//Handle the root request func handleRootRequest(rw http.ResponseWriter, rq *http.Request) { //Detect if the user is authenticated with Siil authenticated := false token := "" if tokenCookie, err := rq.Cookie("token"); err == nil { token = tokenCookie.Value if sess, err := session.GetSession(token); err == nil { authenticated = sess.SiteId == site.SIIL_SITE_ID } } if authenticated { owner, err := getOwnerFromSession(rq) if err != nil { log.Println(err) http.Redirect(rw, rq, "/signin/"+site.SIIL_SITE_ID, http.StatusFound) return } usr, err := user.FindById(int(owner)) if err != nil { log.Println(err) http.Error(rw, "Invalid user", http.StatusInternalServerError) return } var sections string = "" sites, err := site.GetUsersSites(owner) if err != nil { log.Println(err) return } else { for _, s := range sites { titleArea := surroundWithRow(title(s.Name) + button(s.ClientId)) descriptionListArea := surroundWithRow(surroundWithColumn(getDescriptionList(&s), "twelve")) sections += surroundWithSection(titleArea + descriptionListArea) } } response, err := templates["index.hbs"].Exec(map[string]interface{}{ "Sections": sections, "authed": authenticated, "first_name": usr.FirstName, "last_name": usr.LastName, "site_id": site.SIIL_SITE_ID, "token": token, }) if err != nil { http.Error(rw, "Something broke", http.StatusInternalServerError) } else { rw.Write([]byte(response)) } } else { if t, err := templates["index.hbs"].Exec(map[string]interface{}{"authed": authenticated, "site_id": site.SIIL_SITE_ID, "token": token}); err != nil { http.Error(rw, "Something broke", http.StatusInternalServerError) } else { rw.Write([]byte(t)) } } }
func getOwnerFromSession(rq *http.Request) (uint, error) { cookie, err := rq.Cookie("token") if err != nil { return 0, err } session, err := session.GetSession(cookie.Value) if err != nil { return 0, err } return uint(session.UserId), nil }
func handleSuccessRequest(rw http.ResponseWriter, rq *http.Request) { if rq.Method != "POST" { http.Error(rw, "Method not allowed", http.StatusMethodNotAllowed) } else { switch rq.FormValue("siil_action") { case "signin": if token := rq.FormValue("token"); len(token) != session.TOKEN_LENGTH { http.Error(rw, "Invalid token provided", http.StatusBadRequest) } else { if _, err := session.GetSession(token); err != nil { log.Fatal(err) http.Error(rw, "No session", http.StatusUnauthorized) } else { cookie := http.Cookie{ Name: "token", Value: token, } http.SetCookie(rw, &cookie) http.Redirect(rw, rq, "/", http.StatusFound) } } case "signout": //Just clear the token cookie cookie := http.Cookie{ Name: "token", Value: "lel", Expires: time.Now().UTC().Add(time.Minute * -2), } http.SetCookie(rw, &cookie) http.Redirect(rw, rq, "/", http.StatusFound) default: http.Error(rw, "Invalid action provided", http.StatusBadRequest) } } }
//Invalidate the session func handleSignoutRequest(rw http.ResponseWriter, rq *http.Request) { if rq.Method != "POST" { http.Error(rw, "Invalid method", http.StatusMethodNotAllowed) } else { reqVars := mux.Vars(rq) if token, ok := reqVars["token"]; !ok || len(token) != session.TOKEN_LENGTH { http.Error(rw, "Bad token provided", http.StatusBadRequest) } else { if sess, err := session.GetSession(token); err != nil { http.Error(rw, "Session not found", http.StatusUnauthorized) } else { if !cert.ClientVerified(rq) { http.Error(rw, "Cert not provided", http.StatusBadRequest) } else { if userCert, err := cert.NewCertFromRequest(rq); err != nil { log.Println(err) http.Error(rw, "Failed to parse your client cert", http.StatusBadRequest) } else { if usr, err := user.Find(userCert); err != nil { log.Println(err) http.Error(rw, "We don't know you", http.StatusUnauthorized) } else { if usr.Id == sess.UserId { if err := sess.Delete(); err != nil { http.Error(rw, "Failed to end session", http.StatusInternalServerError) } else { wanted := site.Entity{ClientId: sess.SiteId} if err := wanted.Load(); err != nil { log.Println(err) if strings.Contains(err.Error(), "no rows") { http.Error(rw, "Site not found", http.StatusNotFound) } else { http.Error(rw, "Something broke", http.StatusInternalServerError) } return } if callback, err := url.Parse(wanted.CallbackURL); err != nil { http.Error(rw, "Invalid callback URL provided", http.StatusInternalServerError) } else { //Indicate signin action with GET parameter q := callback.Query() q.Set("siil_action", "signout") callback.RawQuery = q.Encode() if t, err := templates["success.hbs"].Exec(map[string]string{"token": sess.Token, "callback": callback.String()}); err != nil { log.Println(err) http.Error(rw, "Something broke", http.StatusInternalServerError) } else { rw.Write([]byte(t)) } } } } else { http.Error(rw, "Session and user don't match", http.StatusBadRequest) } } } } } } } }
//Provide JSON encoded information about the user related to this session func handleAPISessionRequest(rw http.ResponseWriter, rq *http.Request) { if rq.Method != "GET" { http.Error(rw, "Method not allowed", http.StatusMethodNotAllowed) } else { if token, clientId := rq.FormValue("token"), rq.FormValue("client_id"); len(token) != session.TOKEN_LENGTH || len(clientId) != site.CLIENT_ID_LENGTH { http.Error(rw, "Invalid request", http.StatusBadRequest) } else { if sess, err := session.GetSession(token); err != nil { log.Println(err) http.Error(rw, "Not found", http.StatusNotFound) } else { //Check the client id's if sess.SiteId != clientId { http.Error(rw, "Unauthorized", http.StatusUnauthorized) return } s := site.Entity{ClientId: sess.SiteId} if err := s.Load(); err != nil { log.Println(err) http.Error(rw, "Not found", http.StatusNotFound) return } //Lets check the X-Authorization header if sig := rq.Header.Get("X-Authorization"); len(sig) == 0 { http.Error(rw, "Unauthorized (Missing signature in X-Authorization)", http.StatusUnauthorized) } else { sigHMAC, err := base64.StdEncoding.DecodeString(sig) if err != nil { log.Println(err) http.Error(rw, "Invalid signature provided", http.StatusUnauthorized) return } ourMAC := hmac.New(sha512.New, []byte(s.PrivateKey)) ourMAC.Write([]byte(fmt.Sprintf("%s\t%s", clientId, token))) if !hmac.Equal(sigHMAC, ourMAC.Sum(nil)) { http.Error(rw, "Invalid signature provided", http.StatusUnauthorized) } else { if usr, err := user.FindById(sess.UserId); err != nil { log.Println(err) http.Error(rw, "Not found", http.StatusNotFound) } else { response := apiResponse{ Token: token, ExpiresAt: sess.ExpiresAt.Format(time.RFC3339), CreatedAt: sess.CreatedAt.Format(time.RFC3339), User: usr, Site: clientId, } //Generate verification HMAC verHMAC := hmac.New(sha512.New, []byte(s.PrivateKey)) if m, err := json.Marshal(response); err != nil { log.Println(err) http.Error(rw, "Failed to sign response", http.StatusInternalServerError) } else { verHMAC.Write(m) } response.Verification = base64.StdEncoding.EncodeToString(verHMAC.Sum(nil)) enc := json.NewEncoder(rw) rw.Header().Set("Content-Type", "application/json") if err := enc.Encode(response); err != nil { log.Println(err) http.Error(rw, "Failed to compose response", http.StatusInternalServerError) } } } } } } } }