feat: support replacing bound primary email
This commit is contained in:
@@ -285,6 +285,148 @@ func TestAuthServiceBindEmailIdentity_RejectsReservedEmail(t *testing.T) {
|
||||
require.Nil(t, updatedUser)
|
||||
}
|
||||
|
||||
func TestAuthServiceBindEmailIdentity_ReplacesBoundEmailAndSkipsFirstBindDefaults(t *testing.T) {
|
||||
assigner := &emailBindDefaultSubAssignerStub{}
|
||||
cache := &emailBindCacheStub{
|
||||
data: &service.VerificationCodeData{
|
||||
Code: "123456",
|
||||
CreatedAt: time.Now().UTC(),
|
||||
ExpiresAt: time.Now().UTC().Add(10 * time.Minute),
|
||||
},
|
||||
}
|
||||
svc, _, client := newAuthServiceForEmailBind(t, map[string]string{
|
||||
service.SettingKeyAuthSourceDefaultEmailBalance: "8.5",
|
||||
service.SettingKeyAuthSourceDefaultEmailConcurrency: "4",
|
||||
service.SettingKeyAuthSourceDefaultEmailSubscriptions: `[{"group_id":11,"validity_days":30}]`,
|
||||
service.SettingKeyAuthSourceDefaultEmailGrantOnFirstBind: "true",
|
||||
}, cache, assigner)
|
||||
|
||||
ctx := context.Background()
|
||||
hashedPassword, err := svc.HashPassword("current-password")
|
||||
require.NoError(t, err)
|
||||
|
||||
user, err := client.User.Create().
|
||||
SetEmail("current@example.com").
|
||||
SetUsername("bound-user").
|
||||
SetPasswordHash(hashedPassword).
|
||||
SetBalance(7.5).
|
||||
SetConcurrency(3).
|
||||
SetRole(service.RoleUser).
|
||||
SetStatus(service.StatusActive).
|
||||
Save(ctx)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.AuthIdentity.Create().
|
||||
SetUserID(user.ID).
|
||||
SetProviderType("email").
|
||||
SetProviderKey("email").
|
||||
SetProviderSubject("current@example.com").
|
||||
SetVerifiedAt(time.Now().UTC()).
|
||||
SetMetadata(map[string]any{"source": "test"}).
|
||||
Exec(ctx))
|
||||
|
||||
updatedUser, err := svc.BindEmailIdentity(ctx, user.ID, "new@example.com", "123456", "current-password")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updatedUser)
|
||||
require.Equal(t, "new@example.com", updatedUser.Email)
|
||||
|
||||
storedUser, err := client.User.Get(ctx, user.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "new@example.com", storedUser.Email)
|
||||
require.Equal(t, 7.5, storedUser.Balance)
|
||||
require.Equal(t, 3, storedUser.Concurrency)
|
||||
require.True(t, svc.CheckPassword("current-password", storedUser.PasswordHash))
|
||||
|
||||
newIdentityCount, err := client.AuthIdentity.Query().
|
||||
Where(
|
||||
authidentity.UserIDEQ(user.ID),
|
||||
authidentity.ProviderTypeEQ("email"),
|
||||
authidentity.ProviderKeyEQ("email"),
|
||||
authidentity.ProviderSubjectEQ("new@example.com"),
|
||||
).
|
||||
Count(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, newIdentityCount)
|
||||
|
||||
oldIdentityCount, err := client.AuthIdentity.Query().
|
||||
Where(
|
||||
authidentity.UserIDEQ(user.ID),
|
||||
authidentity.ProviderTypeEQ("email"),
|
||||
authidentity.ProviderKeyEQ("email"),
|
||||
authidentity.ProviderSubjectEQ("current@example.com"),
|
||||
).
|
||||
Count(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, oldIdentityCount)
|
||||
|
||||
require.Empty(t, assigner.calls)
|
||||
require.Equal(t, 0, countProviderGrantRecords(t, client, user.ID, "email", "first_bind"))
|
||||
}
|
||||
|
||||
func TestAuthServiceBindEmailIdentity_RejectsWrongCurrentPasswordForBoundEmail(t *testing.T) {
|
||||
cache := &emailBindCacheStub{
|
||||
data: &service.VerificationCodeData{
|
||||
Code: "123456",
|
||||
CreatedAt: time.Now().UTC(),
|
||||
ExpiresAt: time.Now().UTC().Add(10 * time.Minute),
|
||||
},
|
||||
}
|
||||
svc, _, client := newAuthServiceForEmailBind(t, nil, cache, nil)
|
||||
|
||||
ctx := context.Background()
|
||||
hashedPassword, err := svc.HashPassword("current-password")
|
||||
require.NoError(t, err)
|
||||
|
||||
user, err := client.User.Create().
|
||||
SetEmail("current@example.com").
|
||||
SetUsername("bound-user").
|
||||
SetPasswordHash(hashedPassword).
|
||||
SetBalance(1).
|
||||
SetConcurrency(1).
|
||||
SetRole(service.RoleUser).
|
||||
SetStatus(service.StatusActive).
|
||||
Save(ctx)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.AuthIdentity.Create().
|
||||
SetUserID(user.ID).
|
||||
SetProviderType("email").
|
||||
SetProviderKey("email").
|
||||
SetProviderSubject("current@example.com").
|
||||
SetVerifiedAt(time.Now().UTC()).
|
||||
SetMetadata(map[string]any{"source": "test"}).
|
||||
Exec(ctx))
|
||||
|
||||
updatedUser, err := svc.BindEmailIdentity(ctx, user.ID, "new@example.com", "123456", "wrong-password")
|
||||
require.ErrorIs(t, err, service.ErrPasswordIncorrect)
|
||||
require.Nil(t, updatedUser)
|
||||
|
||||
storedUser, err := client.User.Get(ctx, user.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "current@example.com", storedUser.Email)
|
||||
require.True(t, svc.CheckPassword("current-password", storedUser.PasswordHash))
|
||||
|
||||
oldIdentityCount, err := client.AuthIdentity.Query().
|
||||
Where(
|
||||
authidentity.UserIDEQ(user.ID),
|
||||
authidentity.ProviderTypeEQ("email"),
|
||||
authidentity.ProviderKeyEQ("email"),
|
||||
authidentity.ProviderSubjectEQ("current@example.com"),
|
||||
).
|
||||
Count(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, oldIdentityCount)
|
||||
|
||||
newIdentityCount, err := client.AuthIdentity.Query().
|
||||
Where(
|
||||
authidentity.UserIDEQ(user.ID),
|
||||
authidentity.ProviderTypeEQ("email"),
|
||||
authidentity.ProviderKeyEQ("email"),
|
||||
authidentity.ProviderSubjectEQ("new@example.com"),
|
||||
).
|
||||
Count(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, newIdentityCount)
|
||||
}
|
||||
|
||||
type emailBindSettingRepoStub struct {
|
||||
values map[string]string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user