Exemple #1
0
// Redirects to LoginURL unless session value "user_id" is a nonzero integer.
//
// If "must_change_password" is set to true, any request for a path other than
// ChangePasswordPath is redirected to that path.
func MustLogin(h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		userID := session.Int(req, "user_id", 0)
		if userID == 0 {
			session.AddFlash(req, session.Flash{
				Severity: "error",
				Msg:      "You must log in to access this resource.",
			})
			RedirectWithReturn(req, 302, LoginURL)
			return
		}

		mustChangePassword := session.Bool(req, "must_change_password", false)
		if mustChangePassword && req.URL.Path != ChangePasswordPath {
			session.AddFlash(req, session.Flash{
				Severity: "success",
				Msg:      "You must change your password before proceeding.",
			})
			RedirectWithReturn(req, 302, ChangePasswordPath)
			return
		}

		h.ServeHTTP(rw, req)
	})
}
Exemple #2
0
func Auth_LostPW_POST(rw http.ResponseWriter, req *http.Request) {
	email := req.PostFormValue("email")
	var userID int64
	var ak []byte
	err := GetBackend(req).GetDatabase().QueryRow("SELECT id, ak FROM \"user\" WHERE email=$1 LIMIT 1", email).Scan(&userID, &ak)
	if err != nil {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "No user with that e. mail address was found.",
		})
		Auth_LostPW_GET(rw, req)
		return
	}

	err = sendVerificationEmail(email, ak, true)
	if err != nil {
		log.Errore(err, "cannot send verification e. mail")
		Auth_LostPW_GET(rw, req)
		return
	}

	session.AddFlash(req, session.Flash{
		Severity: "success",
		Msg:      "A password recovery e. mail has been sent; please follow the instructions therein.",
	})

	Auth_LostPW_GET(rw, req)
}
Exemple #3
0
func Auth_Login_POST(rw http.ResponseWriter, req *http.Request) {
	email := req.PostFormValue("email")
	password := req.PostFormValue("password")
	userID, ak, isAdmin := ValidateUserEmailPassword(req, email, password)
	if userID == 0 {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "Invalid e. mail address or password.",
		})
		Auth_Login_GET(rw, req)
		return
	}

	session.Set(req, "user_id", int(userID))
	session.Set(req, "user_ak", ak)
	session.Set(req, "user_is_admin", isAdmin)

	if req.PostFormValue("remember") != "" {
		session.Set(req, "session_lifetime", 90*24*time.Hour)
	}

	session.Bump(req)

	session.AddFlash(req, session.Flash{
		Severity: "success",
		Msg:      "You have been logged in.",
	})

	authz.ReturnRedirect(req, 302, authz.AfterLoginURL)
}
Exemple #4
0
func Auth_Logout_POST(rw http.ResponseWriter, req *http.Request) {
	session.Delete(req, "user_id")
	session.Delete(req, "user_ak")
	session.Delete(req, "user_is_admin")
	session.Delete(req, "signup_flow")
	session.AddFlash(req, session.Flash{
		Severity: "success",
		Msg:      "You have been logged out.",
	})
	authz.ReturnRedirect(req, 302, "/")
}
Exemple #5
0
func Auth_Verify_GET(rw http.ResponseWriter, req *http.Request) {
	ac := req.FormValue("ac")
	reset_s := req.FormValue("r")
	email := req.FormValue("e")

	var userID int64
	var ak []byte
	var verified bool
	var isAdmin bool
	err := GetBackend(req).GetDatabase().QueryRow("SELECT node_id, ak, is_admin, email_verified FROM \"n_user\" WHERE email=$1 LIMIT 1", email).Scan(&userID, &ak, &isAdmin, &verified)
	log.Panice(err, "find ak for e. mail verify")

	if !webac.VerifyFor("verify-email/"+reset_s+"/"+email, ac, ak) {
		rw.WriteHeader(400)
		tpl.MustShow(req, "front/400", nil)
		return
	}

	if !verified {
		_, err = dbutil.UpdateKV(GetBackend(req).GetDatabase(), "n_user", dbutil.Set{"email_verified": true}, dbutil.Where{"node_id": userID})
		log.Panice(err)
	}

	if reset_s == "1" {
		_, err = rand.Read(ak)
		log.Panice(err)

		_, err = dbutil.UpdateKV(GetBackend(req).GetDatabase(), "n_user", dbutil.Set{"ak": ak}, dbutil.Where{"node_id": userID})
	}

	// log user in
	if reset_s == "0" {
		if verified {
			// non-reset links cannot be used to get a free login to an already-verified account
			rw.WriteHeader(400)
			tpl.MustShow(req, "front/400", nil)
			return
		}

		session.AddFlash(req, session.Flash{
			Severity: "success",
			Msg:      "Your e. mail address has been verified.",
		})
	} else {
		session.Set(req, "must_change_password", true)
	}
	session.Set(req, "user_id", int(userID))
	session.Set(req, "user_ak", ak)
	session.Set(req, "user_is_admin", isAdmin)
	session.Bump(req)

	miscctx.SeeOther(req, "/panel")
}
Exemple #6
0
func Auth_ChangeEmail_POST(rw http.ResponseWriter, req *http.Request) {
	userID := session.Int(req, "user_id", 0)
	curPassword := req.PostFormValue("cur_password")
	email := req.PostFormValue("email")

	addr, err := mail.ParseAddress(email)
	if err != nil || addr.Name != "" {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "Invalid e. mail address.",
		})
		Auth_ChangeEmail_GET(rw, req)
		return
	}

	var passwordPlain string
	var oldEmail string

	tx, err := GetBackend(req).GetDatabase().Begin()
	log.Panice(err)
	defer tx.Rollback()

	err = tx.QueryRow("SELECT password_plain, email FROM \"n_user\" WHERE node_id=$1 LIMIT 1", userID).
		Scan(&passwordPlain, &oldEmail)
	log.Panice(err)

	_, err = passlib.Verify(curPassword, passwordPlain)
	if err != nil {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "Passwords do not match.",
		})
		Auth_ChangeEmail_GET(rw, req)
		return
	}

	//_, err = tx.Exec("INSERT INTO security_log (type,user_id,message) VALUES ($1,$2,$3)", "change_email", userID, fmt.Sprintf("%s -> %s", oldEmail, addr.Address))
	//log.Panice(err)

	_, err = tx.Exec("UPDATE \"n_user\" SET email=$1, email_verified='f' WHERE node_id=$2", addr.Address, userID)
	if err != nil {
		if perr, ok := err.(pgx.PgError); ok && perr.Code == "23505" { // unique constraint violation
			session.AddFlash(req, session.Flash{
				Severity: "error",
				Msg:      "That e. mail address is already in use.",
			})
			Auth_ChangeEmail_GET(rw, req)
			return
		} else {
			log.Panice(err)
		}
	}

	ak, _ := session.Get(req, "user_ak")
	err = sendVerificationEmail(addr.Address, ak.([]byte), false)
	log.Panice(err)

	err = tx.Commit()
	log.Panice(err)

	session.AddFlash(req, session.Flash{
		Severity: "success",
		Msg:      "E. mail address changed.",
	})

	miscctx.SeeOther(req, "/")
}
Exemple #7
0
func Auth_ChangePassword_POST(rw http.ResponseWriter, req *http.Request) {
	userID := session.Int(req, "user_id", 0)
	curPassword := req.PostFormValue("cur_password")
	password := req.PostFormValue("password")
	passwordConfirm := req.PostFormValue("password_confirm")

	if password == passwordConfirm {
		if len(password) >= 8 {
			mustChangePassword := session.Bool(req, "must_change_password", false)

			var err error
			var passwordPlain string
			if !mustChangePassword {
				err = GetBackend(req).GetDatabase().QueryRow("SELECT password_plain FROM \"n_user\" WHERE node_id=$1", userID).Scan(&passwordPlain)
				log.Panice(err)

				_, err = passlib.Verify(curPassword, passwordPlain)
			}

			if err == nil {
				newHash, err := passlib.Hash(password)
				log.Panice(err)

				newAK := make([]byte, 32)
				rand.Read(newAK)

				_, err = GetBackend(req).GetDatabase().Exec("UPDATE \"n_user\" SET password_plain=$1, ak=$2 WHERE node_id=$3", newHash, newAK, userID)
				log.Panice(err)

				session.Set(req, "user_ak", newAK)

				if mustChangePassword {
					session.Set(req, "must_change_password", false)
				}

				session.AddFlash(req, session.Flash{
					Severity: "success",
					Msg:      "Password changed.",
				})
				miscctx.SeeOther(req, "/")
				return
			} else {
				session.AddFlash(req, session.Flash{
					Severity: "error",
					Msg:      "Password incorrect.",
				})
			}
		} else {
			session.AddFlash(req, session.Flash{
				Severity: "error",
				Msg:      "Password must be at least 8 characters long.",
			})
		}
	} else {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "Passwords do not match.",
		})
	}

	Auth_ChangePassword_GET(rw, req)
}
Exemple #8
0
func Auth_Register_POST(rw http.ResponseWriter, req *http.Request) {
	username := strings.TrimSpace(req.PostFormValue("username"))
	email := req.PostFormValue("email")

	password := req.PostFormValue("password")
	passwordConfirm := req.PostFormValue("password_confirm")

	if registerCAPTCHAFlag.Value() {
		ct, ok := session.Get(req, "captchaTime")
		if !ok || !solvedRecently(ct.(time.Time)) {
			captchaValue := req.PostFormValue("captcha")
			captchaKey := req.PostFormValue("captchak")
			captchaInstance, err := GetBackend(req).GetCAPTCHA().DecodeInstance(captchaKey)
			if err != nil || !GetBackend(req).GetCAPTCHA().Verify(captchaInstance, captchaValue) {
				session.AddFlash(req, session.Flash{
					Severity: "error",
					Msg:      "Invalid CAPTCHA.",
				})

				Auth_Register_GET(rw, req)
				return
			}

			session.Set(req, "captchaTime", time.Now())
		}
	}

	username = strings.Trim(username, " \t\r\n")
	if username == "" {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "You must specify a username.",
		})

		Auth_Register_GET(rw, req)
		return
	}

	if !re_validUsername.MatchString(username) {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "Usernames must consist of letters, numbers, underscores and dashes, must begin with a letter and must not exceed 32 characters.",
		})

		Auth_Register_GET(rw, req)
		return
	}

	addr, err := mail.ParseAddress(email)
	if err != nil || addr.Name != "" {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "You must specify a valid e. mail address.",
		})

		Auth_Register_GET(rw, req)
		return
	}

	if len(password) < 8 {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "Password must be at least eight characters long.",
		})

		Auth_Register_GET(rw, req)
		return
	}

	if password != passwordConfirm {
		session.AddFlash(req, session.Flash{
			Severity: "error",
			Msg:      "Passwords do not match.",
		})

		Auth_Register_GET(rw, req)
		return
	}

	tx, err := GetBackend(req).GetDatabase().Begin()
	log.Panice(err)

	defer tx.Rollback()

	ak := make([]byte, 32)
	rand.Read(ak)

	pwhash, err := passlib.Hash(password)
	log.Panice(err)

	sn := shortname(username)

	var userID int64
	err = dbutil.InsertKVR(tx, "node", "node_id",
		"shortname", sn,
		"longname", username,
		"type", "user",
	).Scan(&userID)
	if err != nil {
		log.Debuge(err, "can't insert user node")
		if dbutil.IsUniqueViolation(err) {
			session.AddFlash(req, session.Flash{
				Severity: "error",
				Msg:      "Username already in use.",
			})
		} else {
			log.Panice(err)
		}

		Auth_Register_GET(rw, req)
		return
	}
	_, err = dbutil.InsertKV(tx, "n_user",
		"node_id", userID,
		"email", addr.Address,
		"password_plain", pwhash,
		"ak", ak,
	)
	if err != nil {
		log.Debuge(err, "can't insert user")
		if dbutil.IsUniqueViolation(err) {
			session.AddFlash(req, session.Flash{
				Severity: "error",
				Msg:      "E. mail address already in use.",
			})
		} else {
			log.Panice(err)
		}

		Auth_Register_GET(rw, req)
		return
	}

	err = tx.Commit()
	if err != nil {
		log.Errore(err, "commit registration transaction")
		Auth_Register_GET(rw, req)
		return
	}

	err = sendVerificationEmail(addr.Address, ak, false)
	if err != nil {
		log.Errore(err, "cannot send verification e. mail")
		Auth_Register_GET(rw, req)
		return
	}

	session.Set(req, "user_id", int(userID))
	session.Set(req, "user_ak", ak)
	session.Set(req, "user_is_admin", false)
	session.AddFlash(req, session.Flash{
		Severity: "success",
		Msg:      "You have successfully been signed up.",
	})

	miscctx.SeeOther(req, "/")
	return
}