summaryrefslogtreecommitdiffstats
path: root/routers/user
diff options
context:
space:
mode:
authorAJ ONeal <coolaj86@gmail.com>2019-04-18 01:23:59 -0600
committerLauris BH <lauris@nix.lv>2019-04-18 10:23:59 +0300
commit6dbd26185203d464c4a4e32e7af04a34f37ae4f2 (patch)
treea637798c309f188ffb8abed5716b2fa03e5cb937 /routers/user
parentfdb933cd67c10c6860ba39402f4b266a9f198f72 (diff)
downloadgitea-6dbd26185203d464c4a4e32e7af04a34f37ae4f2.tar.gz
gitea-6dbd26185203d464c4a4e32e7af04a34f37ae4f2.zip
UX + Security current user password reset (#5042)
* allow current user to reset their own password * handle reset password edge cases properly and consistently * remove dangling assignment * properly label account recovery instead of reset password * remove 'Click here' from button * update English-only account-recovery templates
Diffstat (limited to 'routers/user')
-rw-r--r--routers/user/auth.go111
1 files changed, 68 insertions, 43 deletions
diff --git a/routers/user/auth.go b/routers/user/auth.go
index 7e8ac94e4b..433a4a87dc 100644
--- a/routers/user/auth.go
+++ b/routers/user/auth.go
@@ -893,8 +893,7 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
ctx.Redirect(setting.AppSubURL + "/user/login")
}
-// SignOut sign out from login status
-func SignOut(ctx *context.Context) {
+func handleSignOut(ctx *context.Context) {
ctx.Session.Delete("uid")
ctx.Session.Delete("uname")
ctx.Session.Delete("socialId")
@@ -904,6 +903,11 @@ func SignOut(ctx *context.Context) {
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
ctx.SetCookie("lang", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) // Setting the lang cookie will trigger the middleware to reset the language ot previous state.
+}
+
+// SignOut sign out from login status
+func SignOut(ctx *context.Context) {
+ handleSignOut(ctx)
ctx.Redirect(setting.AppSubURL + "/")
}
@@ -1174,68 +1178,89 @@ func ForgotPasswdPost(ctx *context.Context) {
ctx.HTML(200, tplForgotPassword)
}
-// ResetPasswd render the reset password page
-func ResetPasswd(ctx *context.Context) {
+func commonResetPassword(ctx *context.Context) *models.User {
+ code := ctx.Query("code")
+
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
+ ctx.Data["Code"] = code
+
+ if nil != ctx.User {
+ ctx.Data["user_signed_in"] = true
+ }
- code := ctx.Query("code")
if len(code) == 0 {
- ctx.Error(404)
- return
+ ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
+ return nil
}
- ctx.Data["Code"] = code
- if u := models.VerifyUserActiveCode(code); u != nil {
- ctx.Data["IsResetForm"] = true
+ // Fail early, don't frustrate the user
+ u := models.VerifyUserActiveCode(code)
+ if u == nil {
+ ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
+ return nil
+ }
+
+ // Show the user that they are affecting the account that they intended to
+ ctx.Data["user_email"] = u.Email
+
+ if nil != ctx.User && u.ID != ctx.User.ID {
+ ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email))
+ return nil
}
+ return u
+}
+
+// ResetPasswd render the account recovery page
+func ResetPasswd(ctx *context.Context) {
+ ctx.Data["IsResetForm"] = true
+
+ commonResetPassword(ctx)
+
ctx.HTML(200, tplResetPassword)
}
-// ResetPasswdPost response from reset password request
+// ResetPasswdPost response from account recovery request
func ResetPasswdPost(ctx *context.Context) {
- ctx.Data["Title"] = ctx.Tr("auth.reset_password")
+ u := commonResetPassword(ctx)
- code := ctx.Query("code")
- if len(code) == 0 {
- ctx.Error(404)
+ if u == nil {
+ // Flash error has been set
+ ctx.HTML(200, tplResetPassword)
return
}
- ctx.Data["Code"] = code
- if u := models.VerifyUserActiveCode(code); u != nil {
- // Validate password length.
- passwd := ctx.Query("password")
- if len(passwd) < setting.MinPasswordLength {
- ctx.Data["IsResetForm"] = true
- ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplResetPassword, nil)
- return
- }
+ // Validate password length.
+ passwd := ctx.Query("password")
+ if len(passwd) < setting.MinPasswordLength {
+ ctx.Data["IsResetForm"] = true
+ ctx.Data["Err_Password"] = true
+ ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplResetPassword, nil)
+ return
+ }
- var err error
- if u.Rands, err = models.GetUserSalt(); err != nil {
- ctx.ServerError("UpdateUser", err)
- return
- }
- if u.Salt, err = models.GetUserSalt(); err != nil {
- ctx.ServerError("UpdateUser", err)
- return
- }
- u.HashPassword(passwd)
- u.MustChangePassword = false
- if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil {
- ctx.ServerError("UpdateUser", err)
- return
- }
+ var err error
+ if u.Rands, err = models.GetUserSalt(); err != nil {
+ ctx.ServerError("UpdateUser", err)
+ return
+ }
+ if u.Salt, err = models.GetUserSalt(); err != nil {
+ ctx.ServerError("UpdateUser", err)
+ return
+ }
- log.Trace("User password reset: %s", u.Name)
- ctx.Redirect(setting.AppSubURL + "/user/login")
+ u.HashPassword(passwd)
+ u.MustChangePassword = false
+ if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil {
+ ctx.ServerError("UpdateUser", err)
return
}
+ log.Trace("User password reset: %s", u.Name)
+
ctx.Data["IsResetFailed"] = true
- ctx.HTML(200, tplResetPassword)
+ remember := len(ctx.Query("remember")) != 0
+ handleSignInFull(ctx, u, remember, true)
}
// MustChangePassword renders the page to change a user's password