Invalidate password recovery tokens on eMail change (#10302)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ab812207ab
Коммит
26d3362eca
36
app/user.go
36
app/user.go
@@ -1161,11 +1161,25 @@ func (a *App) ResetPasswordFromToken(userSuppliedTokenString, newPassword string
|
|||||||
return model.NewAppError("resetPassword", "api.user.reset_password.link_expired.app_error", nil, "", http.StatusBadRequest)
|
return model.NewAppError("resetPassword", "api.user.reset_password.link_expired.app_error", nil, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := a.GetUser(token.Extra)
|
tokenData := struct {
|
||||||
|
UserId string
|
||||||
|
Email string
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err2 := json.Unmarshal([]byte(token.Extra), &tokenData)
|
||||||
|
if err2 != nil {
|
||||||
|
return model.NewAppError("resetPassword", "api.user.reset_password.token_parse.error", nil, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := a.GetUser(tokenData.UserId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.Email != tokenData.Email {
|
||||||
|
return model.NewAppError("resetPassword", "api.user.reset_password.link_expired.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
if user.IsSSOUser() {
|
if user.IsSSOUser() {
|
||||||
return model.NewAppError("ResetPasswordFromCode", "api.user.reset_password.sso.app_error", nil, "userId="+user.Id, http.StatusBadRequest)
|
return model.NewAppError("ResetPasswordFromCode", "api.user.reset_password.sso.app_error", nil, "userId="+user.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
@@ -1193,7 +1207,7 @@ func (a *App) SendPasswordReset(email string, siteURL string) (bool, *model.AppE
|
|||||||
return false, model.NewAppError("SendPasswordReset", "api.user.send_password_reset.sso.app_error", nil, "userId="+user.Id, http.StatusBadRequest)
|
return false, model.NewAppError("SendPasswordReset", "api.user.send_password_reset.sso.app_error", nil, "userId="+user.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := a.CreatePasswordRecoveryToken(user.Id)
|
token, err := a.CreatePasswordRecoveryToken(user.Id, user.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -1201,8 +1215,22 @@ func (a *App) SendPasswordReset(email string, siteURL string) (bool, *model.AppE
|
|||||||
return a.SendPasswordResetEmail(user.Email, token, user.Locale, siteURL)
|
return a.SendPasswordResetEmail(user.Email, token, user.Locale, siteURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) CreatePasswordRecoveryToken(userId string) (*model.Token, *model.AppError) {
|
func (a *App) CreatePasswordRecoveryToken(userId, email string) (*model.Token, *model.AppError) {
|
||||||
token := model.NewToken(TOKEN_TYPE_PASSWORD_RECOVERY, userId)
|
|
||||||
|
tokenExtra := struct {
|
||||||
|
UserId string
|
||||||
|
Email string
|
||||||
|
}{
|
||||||
|
userId,
|
||||||
|
email,
|
||||||
|
}
|
||||||
|
jsonData, err := json.Marshal(tokenExtra)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("CreatePasswordRecoveryToken", "api.user.create_password_token.error", nil, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := model.NewToken(TOKEN_TYPE_PASSWORD_RECOVERY, string(jsonData))
|
||||||
|
|
||||||
if result := <-a.Srv.Store.Token().Save(token); result.Err != nil {
|
if result := <-a.Srv.Store.Token().Save(token); result.Err != nil {
|
||||||
return nil, result.Err
|
return nil, result.Err
|
||||||
|
|||||||
@@ -622,3 +622,41 @@ func TestPermanentDeleteUser(t *testing.T) {
|
|||||||
t.Fatal("GetFileInfo after DeleteUser is nil")
|
t.Fatal("GetFileInfo after DeleteUser is nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPasswordRecovery(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
token, err := th.App.CreatePasswordRecoveryToken(th.BasicUser.Id, th.BasicUser.Email)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
tokenData := struct {
|
||||||
|
UserId string
|
||||||
|
Email string
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err2 := json.Unmarshal([]byte(token.Extra), &tokenData)
|
||||||
|
assert.Nil(t, err2)
|
||||||
|
assert.Equal(t, th.BasicUser.Id, tokenData.UserId)
|
||||||
|
assert.Equal(t, th.BasicUser.Email, tokenData.Email)
|
||||||
|
|
||||||
|
// Password token with same eMail as during creation
|
||||||
|
err = th.App.ResetPasswordFromToken(token.Token, "abcdefgh")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// Password token with modified eMail after creation
|
||||||
|
token, err = th.App.CreatePasswordRecoveryToken(th.BasicUser.Id, th.BasicUser.Email)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
th.App.UpdateConfig(func (c *model.Config){
|
||||||
|
*c.EmailSettings.RequireEmailVerification = false
|
||||||
|
})
|
||||||
|
|
||||||
|
th.BasicUser.Email = th.MakeEmail()
|
||||||
|
_, err = th.App.UpdateUser(th.BasicUser, false)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
err = th.App.ResetPasswordFromToken(token.Token, "abcdefgh")
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user