Example #1
0
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)
}
Example #2
0
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
}
Example #3
0
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
}
Example #4
0
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
}
Example #5
0
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
}
Example #6
0
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
}
Example #7
0
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)
}