mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:17:32 +00:00
fix: restructure resend email code to send email code (#9099)
# Which Problems Are Solved There is currently no endpoint to send an email code for verification of the email if you don't change the email itself. # How the Problems Are Solved Endpoint HasEmailCode to get the information that an email code is existing, used by the new login. Endpoint SendEmailCode, if no code is existing to replace ResendEmailCode as there is a check that a code has to be there, before it can be resend. # Additional Changes None # Additional Context Closes #9096 --------- Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com>
This commit is contained in:
@@ -512,6 +512,85 @@ func TestCommands_ResendUserEmailCode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_SendUserEmailCode(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
userID string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "missing permission",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewSecretGeneratorAddedEvent(context.Background(),
|
||||
&instance.NewAggregate("inst1").Aggregate,
|
||||
domain.SecretGeneratorTypeVerifyEmailCode,
|
||||
12, time.Minute, true, true, true, true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanEmailCodeAddedEventV2(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("a"),
|
||||
},
|
||||
time.Hour*1,
|
||||
"", false, "",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
},
|
||||
wantErr: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
_, err := c.SendUserEmailCode(context.Background(), tt.args.userID, crypto.CreateMockEncryptionAlg(gomock.NewController(t)))
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
// successful cases are tested in TestCommands_sendUserEmailCodeWithGeneratorEvents
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_ResendUserEmailCodeURLTemplate(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
@@ -638,7 +717,99 @@ func TestCommands_ResendUserEmailCodeURLTemplate(t *testing.T) {
|
||||
}
|
||||
_, err := c.ResendUserEmailCodeURLTemplate(context.Background(), tt.args.userID, crypto.CreateMockEncryptionAlg(gomock.NewController(t)), tt.args.urlTmpl)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
// successful cases are tested in TestCommands_resendUserEmailCodeWithGenerator
|
||||
// successful cases are tested in TestCommands_sendUserEmailCodeWithGeneratorEvents
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_SendUserEmailCodeURLTemplate(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
userID string
|
||||
urlTmpl string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "invalid template",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
urlTmpl: "{{",
|
||||
},
|
||||
wantErr: zerrors.ThrowInvalidArgument(nil, "DOMAIN-oGh5e", "Errors.User.InvalidURLTemplate"),
|
||||
},
|
||||
{
|
||||
name: "permission missing",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewSecretGeneratorAddedEvent(context.Background(),
|
||||
&instance.NewAggregate("inst1").Aggregate,
|
||||
domain.SecretGeneratorTypeVerifyEmailCode,
|
||||
12, time.Minute, true, true, true, true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanEmailCodeAddedEventV2(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("a"),
|
||||
},
|
||||
time.Hour*1,
|
||||
"", false, "",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
urlTmpl: "https://example.com/email/verify?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}",
|
||||
},
|
||||
wantErr: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
_, err := c.SendUserEmailCodeURLTemplate(context.Background(), tt.args.userID, crypto.CreateMockEncryptionAlg(gomock.NewController(t)), tt.args.urlTmpl)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
// successful cases are tested in TestCommands_sendUserEmailCodeWithGeneratorEvents
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -760,6 +931,85 @@ func TestCommands_ResendUserEmailReturnCode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_SendUserEmailReturnCode(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
userID string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "missing permission",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewSecretGeneratorAddedEvent(context.Background(),
|
||||
&instance.NewAggregate("inst1").Aggregate,
|
||||
domain.SecretGeneratorTypeVerifyEmailCode,
|
||||
12, time.Minute, true, true, true, true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanEmailCodeAddedEventV2(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("a"),
|
||||
},
|
||||
time.Hour*1,
|
||||
"", false, "",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
},
|
||||
wantErr: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
_, err := c.SendUserEmailReturnCode(context.Background(), tt.args.userID, crypto.CreateMockEncryptionAlg(gomock.NewController(t)))
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
// successful cases are tested in TestCommands_sendUserEmailCodeWithGeneratorEvents
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_ChangeUserEmailVerified(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
@@ -1218,15 +1468,16 @@ func TestCommands_changeUserEmailWithGenerator(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
func TestCommands_sendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
userID string
|
||||
returnCode bool
|
||||
urlTmpl string
|
||||
userID string
|
||||
returnCode bool
|
||||
urlTmpl string
|
||||
checkExisting bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1247,37 +1498,6 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
},
|
||||
wantErr: zerrors.ThrowInvalidArgument(nil, "COMMAND-0Gzs3", "Errors.User.Email.IDMissing"),
|
||||
},
|
||||
{
|
||||
name: "resend code, missing code",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
returnCode: false,
|
||||
urlTmpl: "",
|
||||
},
|
||||
wantErr: zerrors.ThrowPreconditionFailed(nil, "EMAIL-5w5ilin4yt", "Errors.User.Code.Empty"),
|
||||
},
|
||||
{
|
||||
name: "missing permission",
|
||||
fields: fields{
|
||||
@@ -1322,6 +1542,58 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
},
|
||||
wantErr: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
{
|
||||
name: "send code",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
user.NewHumanEmailCodeAddedEventV2(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("a"),
|
||||
},
|
||||
time.Hour*1,
|
||||
"", false, "",
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
returnCode: false,
|
||||
urlTmpl: "",
|
||||
checkExisting: false,
|
||||
},
|
||||
want: &domain.Email{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "user1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
EmailAddress: "email@test.ch",
|
||||
IsEmailVerified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "resend code",
|
||||
fields: fields{
|
||||
@@ -1373,9 +1645,10 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
returnCode: false,
|
||||
urlTmpl: "",
|
||||
userID: "user1",
|
||||
returnCode: false,
|
||||
urlTmpl: "",
|
||||
checkExisting: true,
|
||||
},
|
||||
want: &domain.Email{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
@@ -1387,7 +1660,7 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "resend code, return code",
|
||||
name: "resend code, missing code",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
@@ -1406,17 +1679,36 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
returnCode: false,
|
||||
urlTmpl: "",
|
||||
checkExisting: true,
|
||||
},
|
||||
wantErr: zerrors.ThrowPreconditionFailed(nil, "EMAIL-5w5ilin4yt", "Errors.User.Code.Empty"),
|
||||
},
|
||||
{
|
||||
name: "send code, return code",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanEmailCodeAddedEventV2(context.Background(),
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("a"),
|
||||
},
|
||||
time.Hour*1,
|
||||
"", false, "",
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email@test.ch",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1437,9 +1729,10 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
returnCode: true,
|
||||
urlTmpl: "",
|
||||
userID: "user1",
|
||||
returnCode: true,
|
||||
urlTmpl: "",
|
||||
checkExisting: false,
|
||||
},
|
||||
want: &domain.Email{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
@@ -1452,7 +1745,7 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "resend code, URL template",
|
||||
name: "send code, URL template",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
@@ -1471,19 +1764,6 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanEmailCodeAddedEventV2(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("a"),
|
||||
},
|
||||
time.Hour*1,
|
||||
"", false, "",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
user.NewHumanEmailCodeAddedEventV2(context.Background(),
|
||||
@@ -1502,9 +1782,10 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
returnCode: false,
|
||||
urlTmpl: "https://example.com/email/verify?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}",
|
||||
userID: "user1",
|
||||
returnCode: false,
|
||||
urlTmpl: "https://example.com/email/verify?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}",
|
||||
checkExisting: false,
|
||||
},
|
||||
want: &domain.Email{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
@@ -1522,7 +1803,7 @@ func TestCommands_resendUserEmailCodeWithGeneratorEvents(t *testing.T) {
|
||||
eventstore: tt.fields.eventstore,
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := c.resendUserEmailCodeWithGenerator(context.Background(), tt.args.userID, GetMockSecretGenerator(t), tt.args.returnCode, tt.args.urlTmpl)
|
||||
got, err := c.sendUserEmailCodeWithGenerator(context.Background(), tt.args.userID, GetMockSecretGenerator(t), tt.args.returnCode, tt.args.urlTmpl, tt.args.checkExisting)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
|
Reference in New Issue
Block a user