package flow import ( "context" customer "git.sendico.io/tech/sxchnge/product/customers/model" "git.sendico.io/tech/sxchnge/product/notifications" verification "git.sendico.io/tech/sxchnge/product/verification/store" merrors "git.sendico.io/tech/sxchnge/shared/errors" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/v2/bson" "strings" "testing" "time" ) type tokenStub struct { verification.DB request *verification.Request result verification.CreateResult err error } func (s *tokenStub) CreateWithResult(_ context.Context, r *verification.Request) (verification.CreateResult, error) { s.request = r return s.result, s.err } type senderStub struct { messages []notifications.Message err error } func (s *senderStub) Send(_ context.Context, m notifications.Message) error { s.messages = append(s.messages, m) return s.err } func TestIssueRetriesSamePayloadAndBindsServerSecret(t *testing.T) { expiry := time.Now().UTC().Add(time.Minute) tokens := &tokenStub{result: verification.CreateResult{VerificationToken: "123456", ExpiresAt: expiry}} sender := &senderStub{err: merrors.ServiceUnavailable("queue")} service := &Service{Tokens: tokens, Sender: sender, Secret: []byte(strings.Repeat("s", 32)), ActivationURL: "https://app.example/verify-email"} a := &customer.Account{} a.ID = bson.NewObjectID() a.Login = "user@example.com" a.Locale = "ru-RU" _, err := service.sendActivation(context.Background(), a, "client-key") require.Error(t, err) key := *tokens.request.IdempotencyKey require.NotEqual(t, "client-key", key) require.Equal(t, verification.TokenKindLink, tokens.request.Kind) require.Equal(t, 24*time.Hour, tokens.request.Ttl) sender.err = nil _, err = service.sendActivation(context.Background(), a, "client-key") require.NoError(t, err) require.Equal(t, sender.messages[0], sender.messages[1]) require.Equal(t, "ru", sender.messages[0].Locale) service.Secret = []byte(strings.Repeat("b", 32)) require.NotEqual(t, key, service.key(a.ID.Hex(), "account_activation", "client-key")) tokens.result.ExpiresAt = time.Now().Add(-time.Minute) _, err = service.sendActivation(context.Background(), a, "expired") require.ErrorIs(t, err, verification.ErrTokenExpired) require.Len(t, sender.messages, 2) } func TestValidateActivationDestination(t *testing.T) { for _, destination := range []string{"https://app.example/verify-email", "http://localhost:5126/verify-email"} { s := &Service{Secret: []byte(strings.Repeat("s", 32)), ActivationURL: destination} require.NoError(t, s.Validate()) } for _, destination := range []string{"http://app.example/verify-email", "//app.example", "https://user:pass@app.example/verify-email", "https://app.example/#/verify"} { s := &Service{Secret: []byte(strings.Repeat("s", 32)), ActivationURL: destination} require.Error(t, s.Validate()) } }