MM-52477 - remove recovery tokens when creating a new one (#23171)
* remove recovery tokens when creating a new one * add app layers, unit test, i18 extract * lint fixes * fix unit test
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
e4075dae18
Коммит
355bc6502c
@@ -887,6 +887,7 @@ type AppIface interface {
|
||||
InvalidateAllEmailInvites() *model.AppError
|
||||
InvalidateAllResendInviteEmailJobs() *model.AppError
|
||||
InvalidateCacheForUser(userID string)
|
||||
InvalidatePasswordRecoveryTokensForUser(userID string) *model.AppError
|
||||
InviteGuestsToChannels(teamID string, guestsInvite *model.GuestsInvite, senderId string) *model.AppError
|
||||
InviteGuestsToChannelsGracefully(teamID string, guestsInvite *model.GuestsInvite, senderId string) ([]*model.EmailInviteWithError, *model.AppError)
|
||||
InviteNewUsersToTeam(emailList []string, teamID, senderId string) *model.AppError
|
||||
|
||||
@@ -11904,6 +11904,28 @@ func (a *OpenTracingAppLayer) InvalidateCacheForUser(userID string) {
|
||||
a.app.InvalidateCacheForUser(userID)
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) InvalidatePasswordRecoveryTokensForUser(userID string) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.InvalidatePasswordRecoveryTokensForUser")
|
||||
|
||||
a.ctx = newCtx
|
||||
a.app.Srv().Store().SetContext(newCtx)
|
||||
defer func() {
|
||||
a.app.Srv().Store().SetContext(origCtx)
|
||||
a.ctx = origCtx
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0 := a.app.InvalidatePasswordRecoveryTokensForUser(userID)
|
||||
|
||||
if resultVar0 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar0))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) InviteGuestsToChannels(teamID string, guestsInvite *model.GuestsInvite, senderId string) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.InviteGuestsToChannels")
|
||||
|
||||
@@ -1487,8 +1487,13 @@ func (a *App) CreatePasswordRecoveryToken(userID, email string) (*model.Token, *
|
||||
return nil, model.NewAppError("CreatePasswordRecoveryToken", "api.user.create_password_token.error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
token := model.NewToken(TokenTypePasswordRecovery, string(jsonData))
|
||||
// remove any previously created tokens for user
|
||||
appErr := a.InvalidatePasswordRecoveryTokensForUser(userID)
|
||||
if appErr != nil {
|
||||
mlog.Warn("Error while deleting additional user tokens.", mlog.Err(err))
|
||||
}
|
||||
|
||||
token := model.NewToken(TokenTypePasswordRecovery, string(jsonData))
|
||||
if err := a.Srv().Store().Token().Save(token); err != nil {
|
||||
var appErr *model.AppError
|
||||
switch {
|
||||
@@ -1502,6 +1507,34 @@ func (a *App) CreatePasswordRecoveryToken(userID, email string) (*model.Token, *
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (a *App) InvalidatePasswordRecoveryTokensForUser(userID string) *model.AppError {
|
||||
tokens, err := a.Srv().Store().Token().GetAllTokensByType(TokenTypePasswordRecovery)
|
||||
if err != nil {
|
||||
return model.NewAppError("InvalidatePasswordRecoveryTokensForUser", "api.user.invalidate_password_recovery_tokens.error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
var appErr *model.AppError = nil
|
||||
for _, token := range tokens {
|
||||
tokenExtra := struct {
|
||||
UserId string
|
||||
Email string
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(token.Extra), &tokenExtra); err != nil {
|
||||
appErr = model.NewAppError("InvalidatePasswordRecoveryTokensForUser", "api.user.invalidate_password_recovery_tokens_parse.error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if tokenExtra.UserId != userID {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := a.Srv().Store().Token().Delete(token.Token); err != nil {
|
||||
appErr = model.NewAppError("InvalidatePasswordRecoveryTokensForUser", "api.user.invalidate_password_recovery_tokens_delete.error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
}
|
||||
return appErr
|
||||
}
|
||||
|
||||
func (a *App) GetPasswordRecoveryToken(token string) (*model.Token, *model.AppError) {
|
||||
rtoken, err := a.Srv().Store().Token().GetByToken(token)
|
||||
if err != nil {
|
||||
|
||||
@@ -1173,6 +1173,44 @@ func TestPasswordRecovery(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestInvalidatePasswordRecoveryTokens(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
t.Run("remove manually added tokens", func(t *testing.T) {
|
||||
for i := 0; i < 5; i++ {
|
||||
token := model.NewToken(
|
||||
TokenTypePasswordRecovery,
|
||||
model.MapToJSON(map[string]string{"UserId": th.BasicUser.Id, "email": th.BasicUser.Email}),
|
||||
)
|
||||
require.NoError(t, th.App.Srv().Store().Token().Save(token))
|
||||
}
|
||||
tokens, err := th.App.Srv().Store().Token().GetAllTokensByType(TokenTypePasswordRecovery)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 5, len(tokens))
|
||||
|
||||
appErr := th.App.InvalidatePasswordRecoveryTokensForUser(th.BasicUser.Id)
|
||||
assert.Nil(t, appErr)
|
||||
|
||||
tokens, err = th.App.Srv().Store().Token().GetAllTokensByType(TokenTypePasswordRecovery)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(tokens))
|
||||
})
|
||||
|
||||
t.Run("add multiple tokens, should only be one valid", func(t *testing.T) {
|
||||
_, appErr := th.App.CreatePasswordRecoveryToken(th.BasicUser.Id, th.BasicUser.Email)
|
||||
assert.Nil(t, appErr)
|
||||
|
||||
token, appErr := th.App.CreatePasswordRecoveryToken(th.BasicUser.Id, th.BasicUser.Email)
|
||||
assert.Nil(t, appErr)
|
||||
|
||||
tokens, err := th.App.Srv().Store().Token().GetAllTokensByType(TokenTypePasswordRecovery)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(tokens))
|
||||
assert.Equal(t, token.Token, tokens[0].Token)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetViewUsersRestrictions(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
@@ -4163,6 +4163,18 @@
|
||||
"id": "api.user.get_users.validation.app_error",
|
||||
"translation": "Error fetching roles during validation."
|
||||
},
|
||||
{
|
||||
"id": "api.user.invalidate_password_recovery_tokens.error",
|
||||
"translation": "Unable to get tokens by type when invalidating password recovery tokens"
|
||||
},
|
||||
{
|
||||
"id": "api.user.invalidate_password_recovery_tokens_delete.error",
|
||||
"translation": "Unable to remove token when invalidating password recovery tokens"
|
||||
},
|
||||
{
|
||||
"id": "api.user.invalidate_password_recovery_tokens_parse.error",
|
||||
"translation": "Unable to parse token when invalidating password recovery tokens"
|
||||
},
|
||||
{
|
||||
"id": "api.user.invalidate_verify_email_tokens.error",
|
||||
"translation": "Unable to get tokens by type when invalidating email verification tokens"
|
||||
|
||||
Ссылка в новой задаче
Block a user