diff options
author | AJ ONeal <coolaj86@gmail.com> | 2019-04-18 01:23:59 -0600 |
---|---|---|
committer | Lauris BH <lauris@nix.lv> | 2019-04-18 10:23:59 +0300 |
commit | 6dbd26185203d464c4a4e32e7af04a34f37ae4f2 (patch) | |
tree | a637798c309f188ffb8abed5716b2fa03e5cb937 /routers/user | |
parent | fdb933cd67c10c6860ba39402f4b266a9f198f72 (diff) | |
download | gitea-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.go | 111 |
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 |