func handlerMail(w http.ResponseWriter, r *http.Request) error { r.ParseForm() if r.URL.Path != "/mail" { return handlerNotFound(w, r) } tx, err := mail.DB.Begin() if err != nil { return err } defer tx.Rollback() us, err := getUserSession(r, tx) if err != nil { return err } if us.userID == 0 { // user not logged in, redirect to login page http.Redirect(w, r, serveURL+"/", http.StatusFound) return nil } selectEmailStmt := mail.TxStmt(sqlSelectEmailFromUserID, tx) defer selectEmailStmt.Close() var email string err = selectEmailStmt.QueryRow(us.userID).Scan(&email) if err != nil { return err } mailApp := &MailApp{email, &Skeleton{}} return tMail.Execute(newWSCollapser(&w), mailApp) }
func loginUser( w http.ResponseWriter, r *http.Request, tx *sql.Tx, userID int, ) error { cookie := newCookie() insertCookieStmt := mail.TxStmt(sqlInsertCookie, tx) defer insertCookieStmt.Close() _, err := insertCookieStmt.Exec(userID, cookie, r.RemoteAddr, r.Header.Get("User-Agent")) if err != nil { return err } // set cookie header header := w.Header() cookieHeader := "CID=" + cookie + ";HttpOnly" if mail.HTTPSMode { cookieHeader += ";Secure" } header.Add("Set-Cookie", cookieHeader) // redirect to application http.Redirect(w, r, serveURL+"/mail", http.StatusFound) return nil }
func getUserInfo( tx *sql.Tx, email string, ) ( userID int, passwordHash string, err error, ) { selectEmailStmt := mail.TxStmt(sqlSelectEmail, tx) defer selectEmailStmt.Close() err = selectEmailStmt.QueryRow(email).Scan(&userID, &passwordHash) return }
func handlerLogout(w http.ResponseWriter, r *http.Request) error { r.ParseForm() if r.URL.Path != "/logout" { return handlerNotFound(w, r) } tx, err := mail.DB.Begin() if err != nil { return err } defer tx.Rollback() us, err := getUserSession(r, tx) if err != nil { return err } if us.userID != 0 { deleteCookieStmt := mail.TxStmt(sqlDeleteCookie, tx) defer deleteCookieStmt.Close() _, err = deleteCookieStmt.Exec(getCookie(r)) if err != nil { return err } err = tx.Commit() if err != nil { return err } } // clear cookie header header := w.Header() cookieHeader := "CID=;HttpOnly" if mail.HTTPSMode { cookieHeader += ";Secure" } header.Add("Set-Cookie", cookieHeader) // redirect to login page http.Redirect(w, r, serveURL+"/", http.StatusFound) return nil }
func getUserSession(r *http.Request, tx *sql.Tx) (userSession, error) { cookie := getCookie(r) if cookie == "" { // user not logged in return userSession{}, nil } var userID int var isAdmin bool selectCookieStmt := mail.TxStmt(sqlSelectCookie, tx) defer selectCookieStmt.Close() err := selectCookieStmt.QueryRow(cookie).Scan(&userID, &isAdmin) switch { case err == sql.ErrNoRows: return userSession{}, nil case err != nil: return userSession{}, err } return userSession{userID, isAdmin}, nil }
func processRegister( w http.ResponseWriter, r *http.Request, tx *sql.Tx, register *Register, ) (bool, error) { cFirst := strings.TrimSpace(r.Form.Get("first")) cLast := strings.TrimSpace(r.Form.Get("last")) cEmail := canonEmail(r.Form.Get("email")) cPassword := strings.TrimSpace(r.Form.Get("password")) cPasswordConfirm := strings.TrimSpace(r.Form.Get("password_confirm")) register.First = cFirst register.Last = cLast register.Email = cEmail error := false if cFirst == "" || cLast == "" { error = true register.NameError = errEmpty } if cEmail == "" { error = true register.EmailError = errEmpty } else if !validEmailFormat(cEmail) { error = true register.EmailError = errFullEmail } if cPassword == "" { error = true register.PasswordError = errEmpty } else if !validPasswordFormat(cPassword) { error = true register.PasswordError = errShortPassword } if cPasswordConfirm == "" { error = true register.PasswordConfirmError = errEmpty } else if cPassword != cPasswordConfirm { error = true register.PasswordConfirmError = errPasswordsDoNotMatch } if error { return false, nil } emailExists := true userID, passwordHash, err := getUserInfo(tx, cEmail) switch { case err == sql.ErrNoRows: emailExists = false case err != nil: return false, err } if emailExists { if checkPasswordHash(cPassword, passwordHash) { err = loginUser(w, r, tx, userID) if err != nil { return false, err } err = tx.Commit() if err != nil { return false, err } return true, nil } // Email is already registered, but passwords do not match register.EmailError = errEmailInUse return false, err } cPasswordHash, err := hashPassword(cPassword) if err != nil { return false, err } insertUserStmt := mail.TxStmt(sqlInsertUser, tx) defer insertUserStmt.Close() err = insertUserStmt.QueryRow(cEmail, cPasswordHash).Scan(&userID) if err != nil { return false, err } if userID == 1 { // make userID 1 an admin by default defaultAdminStmt := mail.TxStmt(sqlDefaultAdmin, tx) defer defaultAdminStmt.Close() _, err = defaultAdminStmt.Exec() if err != nil { return false, err } } // TODO(hochhaus): Send email err = loginUser(w, r, tx, userID) if err != nil { return false, err } err = tx.Commit() if err != nil { return false, err } return true, nil }
func handlerErrors(w http.ResponseWriter, r *http.Request) error { r.ParseForm() if r.URL.Path != "/debug/errors" { return handlerNotFound(w, r) } tx, err := mail.DB.Begin() if err != nil { return err } defer tx.Rollback() us, err := getUserSession(r, tx) if err != nil { return err } if r.Method == "POST" { // User may or may not be logged in (eg: outside of site). var nullableUserID, nullableCookieID sql.NullInt64 if us.userID != 0 { nullableUserID.Int64 = int64(us.userID) nullableUserID.Valid = true selectCookieIDStmt := mail.TxStmt(sqlSelectCookieID, tx) defer selectCookieIDStmt.Close() err := selectCookieIDStmt.QueryRow(getCookie(r)).Scan(&nullableCookieID) if err != nil { return err } } postError, err := getBody(r) if err != nil { return err } insertErrorStmt := mail.TxStmt(sqlInsertError, tx) defer insertErrorStmt.Close() _, err = insertErrorStmt.Exec(nullableUserID, nullableCookieID, r.RequestURI, postError, r.Header.Get("Referer"), r.Header.Get("User-Agent")) if err != nil { return err } err = tx.Commit() if err != nil { return err } errorsPage := ErrorsPage{} errorsPage.ErrorLogged = true return tErrors.Execute(w, errorsPage) } if !us.isAdmin { errorsPage := ErrorsPage{} errorsPage.NoAccess = true return tErrors.Execute(newWSCollapser(&w), errorsPage) } selectErrorsStmt := mail.TxStmt(sqlSelectErrors, tx) defer selectErrorsStmt.Close() rows, err := selectErrorsStmt.Query() if err != nil { return err } defer rows.Close() errorsPage := ErrorsPage{} for rows.Next() { var email sql.NullString var url, e, referrer, userAgent string var t time.Time err = rows.Scan(&email, &url, &e, &referrer, &userAgent, &t) if err != nil { return err } errorsPage.Errors = append(errorsPage.Errors, ErrorItem{ email.String, url, e, referrer, userAgent, t.UTC().String()}) } err = rows.Err() // get any error encountered during iteration if err != nil { return err } return tErrors.Execute(newWSCollapser(&w), errorsPage) }