diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go
index f7658bd6e086..a2b1850a87fa 100644
--- a/cmd/clidoc/main.go
+++ b/cmd/clidoc/main.go
@@ -162,7 +162,7 @@ func init() {
"NewInfoSelfServiceLoginContinue": text.NewInfoSelfServiceLoginContinue(),
"NewErrorValidationSuchNoWebAuthnUser": text.NewErrorValidationSuchNoWebAuthnUser(),
"NewRegistrationEmailWithCodeSent": text.NewRegistrationEmailWithCodeSent(),
- "NewLoginEmailWithCodeSent": text.NewLoginEmailWithCodeSent(),
+ "NewLoginCodeSent": text.NewLoginCodeSent(),
"NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed": text.NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed(),
"NewErrorValidationLoginCodeInvalidOrAlreadyUsed": text.NewErrorValidationLoginCodeInvalidOrAlreadyUsed(),
"NewErrorValidationNoCodeUser": text.NewErrorValidationNoCodeUser(),
diff --git a/courier/courier.go b/courier/courier.go
index 231b4007060f..cb5acede6aee 100644
--- a/courier/courier.go
+++ b/courier/courier.go
@@ -47,10 +47,10 @@ type (
}
courier struct {
- courierChannels map[string]Channel
- deps Dependencies
- failOnDispatchError bool
- backoff backoff.BackOff
+ deps Dependencies
+ failOnDispatchError bool
+ backoff backoff.BackOff
+ newEmailTemplateFromMessage func(d template.Dependencies, msg Message) (EmailTemplate, error)
}
)
@@ -58,31 +58,11 @@ func NewCourier(ctx context.Context, deps Dependencies) (Courier, error) {
return NewCourierWithCustomTemplates(ctx, deps, NewEmailTemplateFromMessage)
}
-func NewCourierWithCustomTemplates(ctx context.Context, deps Dependencies, newEmailTemplateFromMessage func(d template.Dependencies, msg Message) (EmailTemplate, error)) (Courier, error) {
- cs, err := deps.CourierConfig().CourierChannels(ctx)
- if err != nil {
- return nil, err
- }
- channels := make(map[string]Channel, len(cs))
- for _, c := range cs {
- switch c.Type {
- case "smtp":
- ch, err := NewSMTPChannelWithCustomTemplates(deps, c.SMTPConfig, newEmailTemplateFromMessage)
- if err != nil {
- return nil, err
- }
- channels[ch.ID()] = ch
- case "http":
- channels[c.ID] = newHttpChannel(c.ID, c.RequestConfig, deps)
- default:
- return nil, errors.Errorf("unknown courier channel type: %s", c.Type)
- }
- }
-
+func NewCourierWithCustomTemplates(_ context.Context, deps Dependencies, newEmailTemplateFromMessage func(d template.Dependencies, msg Message) (EmailTemplate, error)) (Courier, error) {
return &courier{
- deps: deps,
- backoff: backoff.NewExponentialBackOff(),
- courierChannels: channels,
+ deps: deps,
+ backoff: backoff.NewExponentialBackOff(),
+ newEmailTemplateFromMessage: newEmailTemplateFromMessage,
}, nil
}
diff --git a/courier/courier_dispatcher.go b/courier/courier_dispatcher.go
index 47399369c3c3..a0f75954d68e 100644
--- a/courier/courier_dispatcher.go
+++ b/courier/courier_dispatcher.go
@@ -9,6 +9,33 @@ import (
"github.com/pkg/errors"
)
+func (c *courier) channels(ctx context.Context, id string) (Channel, error) {
+ cs, err := c.deps.CourierConfig().CourierChannels(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, channel := range cs {
+ if channel.ID != id {
+ continue
+ }
+ switch channel.Type {
+ case "smtp":
+ courierChannel, err := NewSMTPChannelWithCustomTemplates(c.deps, channel.SMTPConfig, c.newEmailTemplateFromMessage)
+ if err != nil {
+ return nil, err
+ }
+ return courierChannel, nil
+ case "http":
+ return newHttpChannel(channel.ID, channel.RequestConfig, c.deps), nil
+ default:
+ return nil, errors.Errorf("unknown courier channel type: %s", channel.Type)
+ }
+ }
+
+ return nil, errors.Errorf("no courier channels configured")
+}
+
func (c *courier) DispatchMessage(ctx context.Context, msg Message) error {
logger := c.deps.Logger().
WithField("message_id", msg.ID).
@@ -24,9 +51,9 @@ func (c *courier) DispatchMessage(ctx context.Context, msg Message) error {
return err
}
- channel, ok := c.courierChannels[msg.Channel.String()]
- if !ok {
- return errors.Errorf("message %s has unknown channel %q", msg.ID.String(), msg.Channel)
+ channel, err := c.channels(ctx, msg.Channel.String())
+ if err != nil {
+ return err
}
logger = logger.
@@ -80,6 +107,9 @@ func (c *courier) DispatchQueue(ctx context.Context) error {
logger.
Warnf(`Message was abandoned because it did not deliver after %d attempts`, msg.SendCount)
} else if err := c.DispatchMessage(ctx, msg); err != nil {
+ logger.
+ WithError(err).
+ Warn(`Unable to dispatch message.`)
if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusFailed, err); err != nil {
logger.
WithError(err).
diff --git a/courier/sms_templates.go b/courier/sms_templates.go
index b560542d53c9..12c55ceed751 100644
--- a/courier/sms_templates.go
+++ b/courier/sms_templates.go
@@ -40,6 +40,12 @@ func NewSMSTemplateFromMessage(d template.Dependencies, m Message) (SMSTemplate,
return nil, err
}
return sms.NewLoginCodeValid(d, &t), nil
+ case template.TypeRegistrationCodeValid:
+ var t sms.RegistrationCodeValidModel
+ if err := json.Unmarshal(m.TemplateData, &t); err != nil {
+ return nil, err
+ }
+ return sms.NewRegistrationCodeValid(d, &t), nil
default:
return nil, errors.Errorf("received unexpected message template type: %s", m.TemplateType)
diff --git a/courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl
index 505684b9849b..0b1b3abd30b8 100644
--- a/courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl
+++ b/courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl
@@ -1,5 +1,5 @@
-Hi,
-
-please login to your account by entering the following code:
+Login to your account with the following code:
{{ .LoginCode }}
+
+It expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl
index 505684b9849b..0b1b3abd30b8 100644
--- a/courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl
+++ b/courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl
@@ -1,5 +1,5 @@
-Hi,
-
-please login to your account by entering the following code:
+Login to your account with the following code:
{{ .LoginCode }}
+
+It expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl
index 19d7bfd57d49..0015e66086c9 100644
--- a/courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl
+++ b/courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl
@@ -1 +1 @@
-Login to your account
+Use code {{ .LoginCode }} to log in
diff --git a/courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl
index 5b88dde9a382..ca6d35ca9eac 100644
--- a/courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl
+++ b/courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl
@@ -1 +1,3 @@
Your login code is: {{ .LoginCode }}
+
+It expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/recovery/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/recovery/valid/email.body.gotmpl
index 2dbc8d53550b..c4ac7a1d6404 100644
--- a/courier/template/courier/builtin/templates/recovery/valid/email.body.gotmpl
+++ b/courier/template/courier/builtin/templates/recovery/valid/email.body.gotmpl
@@ -1,5 +1,5 @@
-Hi,
-
-please recover access to your account by clicking the following link:
+Recover access to your account by clicking the following link:
{{ .RecoveryURL }}
+
+If this was not you, do nothing. This link expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/recovery/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/recovery/valid/email.body.plaintext.gotmpl
index d41e8963cc50..7bea438ffffa 100644
--- a/courier/template/courier/builtin/templates/recovery/valid/email.body.plaintext.gotmpl
+++ b/courier/template/courier/builtin/templates/recovery/valid/email.body.plaintext.gotmpl
@@ -1,5 +1,6 @@
-Hi,
-
-please recover access to your account by clicking the following link:
+Recover access to your account by clicking the following link:
{{ .RecoveryURL }}
+
+If this was not you, do nothing. This link expires in {{ .ExpiresInMinutes }} minutes.
+
diff --git a/courier/template/courier/builtin/templates/recovery_code/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/recovery_code/valid/email.body.gotmpl
index 5037d753998e..8427467b81c8 100644
--- a/courier/template/courier/builtin/templates/recovery_code/valid/email.body.gotmpl
+++ b/courier/template/courier/builtin/templates/recovery_code/valid/email.body.gotmpl
@@ -1,5 +1,5 @@
-Hi,
-
-please recover access to your account by entering the following code:
+Recover access to your account by entering the following code:
{{ .RecoveryCode }}
+
+If this was not you, do nothing. This code expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/recovery_code/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/recovery_code/valid/email.body.plaintext.gotmpl
index 5037d753998e..8427467b81c8 100644
--- a/courier/template/courier/builtin/templates/recovery_code/valid/email.body.plaintext.gotmpl
+++ b/courier/template/courier/builtin/templates/recovery_code/valid/email.body.plaintext.gotmpl
@@ -1,5 +1,5 @@
-Hi,
-
-please recover access to your account by entering the following code:
+Recover access to your account by entering the following code:
{{ .RecoveryCode }}
+
+If this was not you, do nothing. This code expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/recovery_code/valid/email.subject.gotmpl b/courier/template/courier/builtin/templates/recovery_code/valid/email.subject.gotmpl
index 9a47d5f5814a..0890daa9df87 100644
--- a/courier/template/courier/builtin/templates/recovery_code/valid/email.subject.gotmpl
+++ b/courier/template/courier/builtin/templates/recovery_code/valid/email.subject.gotmpl
@@ -1 +1 @@
-Recover access to your account
+Use code {{ .RecoveryCode }} to recover access to your account
diff --git a/courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl
index 6b9c31799995..b839053d8afb 100644
--- a/courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl
+++ b/courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl
@@ -1,5 +1,5 @@
-Hi,
-
-please complete your account registration by entering the following code:
+Complete your account registration with the following code:
{{ .RegistrationCode }}
+
+This code expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl
index 6b9c31799995..b839053d8afb 100644
--- a/courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl
+++ b/courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl
@@ -1,5 +1,5 @@
-Hi,
-
-please complete your account registration by entering the following code:
+Complete your account registration with the following code:
{{ .RegistrationCode }}
+
+This code expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl b/courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl
index 0f36292619ef..fd48d99a2b19 100644
--- a/courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl
+++ b/courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl
@@ -1 +1 @@
-Complete your account registration
+Use code {{ .RegistrationCode }} to complete your account registration
diff --git a/courier/template/courier/builtin/templates/registration_code/valid/sms.body.gotmpl b/courier/template/courier/builtin/templates/registration_code/valid/sms.body.gotmpl
new file mode 100644
index 000000000000..24b79fff0f8a
--- /dev/null
+++ b/courier/template/courier/builtin/templates/registration_code/valid/sms.body.gotmpl
@@ -0,0 +1,3 @@
+Your registration code is: {{ .RegistrationCode }}
+
+It expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/verification/invalid/email.body.gotmpl b/courier/template/courier/builtin/templates/verification/invalid/email.body.gotmpl
index bb3d3c1b3d90..18565a8de01d 100644
--- a/courier/template/courier/builtin/templates/verification/invalid/email.body.gotmpl
+++ b/courier/template/courier/builtin/templates/verification/invalid/email.body.gotmpl
@@ -1,6 +1,4 @@
-Hi,
-
-someone asked to verify this email address, but we were unable to find an account for this address.
+Someone asked to verify this email address, but we were unable to find an account for this address.
If this was you, check if you signed up using a different address.
diff --git a/courier/template/courier/builtin/templates/verification/invalid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/verification/invalid/email.body.plaintext.gotmpl
index bb3d3c1b3d90..18565a8de01d 100644
--- a/courier/template/courier/builtin/templates/verification/invalid/email.body.plaintext.gotmpl
+++ b/courier/template/courier/builtin/templates/verification/invalid/email.body.plaintext.gotmpl
@@ -1,6 +1,4 @@
-Hi,
-
-someone asked to verify this email address, but we were unable to find an account for this address.
+Someone asked to verify this email address, but we were unable to find an account for this address.
If this was you, check if you signed up using a different address.
diff --git a/courier/template/courier/builtin/templates/verification/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/verification/valid/email.body.gotmpl
index d8e3168e5a78..d111cc47dd32 100644
--- a/courier/template/courier/builtin/templates/verification/valid/email.body.gotmpl
+++ b/courier/template/courier/builtin/templates/verification/valid/email.body.gotmpl
@@ -1,3 +1,5 @@
-Hi, please verify your account by clicking the following link:
+Verify your account by opening the following link:
{{ .VerificationURL }}
+
+If this was not you, do nothing. This link expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/verification/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/verification/valid/email.body.plaintext.gotmpl
index 4d915646c61e..ac28e51a4878 100644
--- a/courier/template/courier/builtin/templates/verification/valid/email.body.plaintext.gotmpl
+++ b/courier/template/courier/builtin/templates/verification/valid/email.body.plaintext.gotmpl
@@ -1,4 +1,5 @@
-Hi, please verify your account by clicking the following link:
+Verify your account by opening the following link:
{{ .VerificationURL }}
+If this was not you, do nothing. This link expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/verification_code/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/verification_code/valid/email.body.gotmpl
index f564f53378af..fc8d55ab5c0a 100644
--- a/courier/template/courier/builtin/templates/verification_code/valid/email.body.gotmpl
+++ b/courier/template/courier/builtin/templates/verification_code/valid/email.body.gotmpl
@@ -1,9 +1,9 @@
-Hi,
-
-please verify your account by entering the following code:
+Verify your account with the following code:
{{ .VerificationCode }}
or clicking the following link:
{{ .VerificationURL }}
+
+If this was not you, do nothing. This code / link expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/verification_code/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/verification_code/valid/email.body.plaintext.gotmpl
index 58a5f39d4410..b6dde063b3c1 100644
--- a/courier/template/courier/builtin/templates/verification_code/valid/email.body.plaintext.gotmpl
+++ b/courier/template/courier/builtin/templates/verification_code/valid/email.body.plaintext.gotmpl
@@ -1,9 +1,9 @@
-Hi,
-
-please verify your account by entering the following code:
+Verify your account with the following code:
{{ .VerificationCode }}
or clicking the following link:
{{ .VerificationURL }}
+
+If this was not you, do nothing. This code / link expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/courier/builtin/templates/verification_code/valid/email.subject.gotmpl b/courier/template/courier/builtin/templates/verification_code/valid/email.subject.gotmpl
index 3f0aceec1a72..b71c78404bde 100644
--- a/courier/template/courier/builtin/templates/verification_code/valid/email.subject.gotmpl
+++ b/courier/template/courier/builtin/templates/verification_code/valid/email.subject.gotmpl
@@ -1 +1 @@
-Please verify your email address
+Use code {{ .VerificationCode }} to verify your account
diff --git a/courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl b/courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl
index 0469598d2d58..60474c5eb57b 100644
--- a/courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl
+++ b/courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl
@@ -1 +1,3 @@
Your verification code is: {{ .VerificationCode }}
+
+If this was not you, do nothing. It expires in {{ .ExpiresInMinutes }} minutes.
diff --git a/courier/template/email/login_code_valid.go b/courier/template/email/login_code_valid.go
index b09f70f8625e..1863ea39fbe6 100644
--- a/courier/template/email/login_code_valid.go
+++ b/courier/template/email/login_code_valid.go
@@ -23,6 +23,7 @@ type (
Identity map[string]interface{} `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/email/recovery_code_valid.go b/courier/template/email/recovery_code_valid.go
index 4e8992da3d1d..313613ab714d 100644
--- a/courier/template/email/recovery_code_valid.go
+++ b/courier/template/email/recovery_code_valid.go
@@ -23,6 +23,7 @@ type (
Identity map[string]interface{} `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/email/recovery_valid.go b/courier/template/email/recovery_valid.go
index f82a40b4f919..ae681b7c875b 100644
--- a/courier/template/email/recovery_valid.go
+++ b/courier/template/email/recovery_valid.go
@@ -23,6 +23,7 @@ type (
Identity map[string]interface{} `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/email/registration_code_valid.go b/courier/template/email/registration_code_valid.go
index ec52362a8990..7994c1484afc 100644
--- a/courier/template/email/registration_code_valid.go
+++ b/courier/template/email/registration_code_valid.go
@@ -23,6 +23,7 @@ type (
RegistrationCode string `json:"registration_code"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/email/verification_code_valid.go b/courier/template/email/verification_code_valid.go
index bd2045a03d25..d9b527901519 100644
--- a/courier/template/email/verification_code_valid.go
+++ b/courier/template/email/verification_code_valid.go
@@ -24,6 +24,7 @@ type (
Identity map[string]interface{} `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/email/verification_valid.go b/courier/template/email/verification_valid.go
index eb9578261d83..c8d24c4372ac 100644
--- a/courier/template/email/verification_valid.go
+++ b/courier/template/email/verification_valid.go
@@ -23,6 +23,7 @@ type (
Identity map[string]interface{} `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/sms/login_code_valid.go b/courier/template/sms/login_code_valid.go
index f365a6ba2800..f19e6e567771 100644
--- a/courier/template/sms/login_code_valid.go
+++ b/courier/template/sms/login_code_valid.go
@@ -22,6 +22,7 @@ type (
Identity map[string]interface{} `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/sms/login_code_valid_test.go b/courier/template/sms/login_code_valid_test.go
index a2915c750c89..48e24475c8d7 100644
--- a/courier/template/sms/login_code_valid_test.go
+++ b/courier/template/sms/login_code_valid_test.go
@@ -25,7 +25,7 @@ func TestNewLoginCodeValid(t *testing.T) {
tpl := sms.NewLoginCodeValid(reg, &sms.LoginCodeValidModel{To: expectedPhone, LoginCode: otp})
- expectedBody := fmt.Sprintf("Your login code is: %s\n", otp)
+ expectedBody := fmt.Sprintf("Your login code is: %s\n\nIt expires in 0 minutes.\n", otp)
actualBody, err := tpl.SMSBody(context.Background())
require.NoError(t, err)
diff --git a/courier/template/sms/registration_code_valid.go b/courier/template/sms/registration_code_valid.go
new file mode 100644
index 000000000000..7413f75a94de
--- /dev/null
+++ b/courier/template/sms/registration_code_valid.go
@@ -0,0 +1,55 @@
+// Copyright © 2023 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+package sms
+
+import (
+ "context"
+ "encoding/json"
+ "os"
+
+ "github.com/ory/kratos/courier/template"
+)
+
+type (
+ RegistrationCodeValid struct {
+ deps template.Dependencies
+ model *RegistrationCodeValidModel
+ }
+ RegistrationCodeValidModel struct {
+ To string `json:"to"`
+ RegistrationCode string `json:"registration_code"`
+ Identity map[string]interface{} `json:"identity"`
+ RequestURL string `json:"request_url"`
+ TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
+ }
+)
+
+func NewRegistrationCodeValid(d template.Dependencies, m *RegistrationCodeValidModel) *RegistrationCodeValid {
+ return &RegistrationCodeValid{deps: d, model: m}
+}
+
+func (t *RegistrationCodeValid) PhoneNumber() (string, error) {
+ return t.model.To, nil
+}
+
+func (t *RegistrationCodeValid) SMSBody(ctx context.Context) (string, error) {
+ return template.LoadText(
+ ctx,
+ t.deps,
+ os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)),
+ "registration_code/valid/sms.body.gotmpl",
+ "registration_code/valid/sms.body*",
+ t.model,
+ t.deps.CourierConfig().CourierSMSTemplatesRegistrationCodeValid(ctx).Body.PlainText,
+ )
+}
+
+func (t *RegistrationCodeValid) MarshalJSON() ([]byte, error) {
+ return json.Marshal(t.model)
+}
+
+func (t *RegistrationCodeValid) TemplateType() template.TemplateType {
+ return template.TypeRegistrationCodeValid
+}
diff --git a/courier/template/sms/registration_code_valid_test.go b/courier/template/sms/registration_code_valid_test.go
new file mode 100644
index 000000000000..1299c113f331
--- /dev/null
+++ b/courier/template/sms/registration_code_valid_test.go
@@ -0,0 +1,37 @@
+// Copyright © 2023 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+package sms_test
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/ory/kratos/courier/template/sms"
+ "github.com/ory/kratos/internal"
+)
+
+func TestNewRegistrationCodeValid(t *testing.T) {
+ _, reg := internal.NewFastRegistryWithMocks(t)
+
+ const (
+ expectedPhone = "+12345678901"
+ otp = "012345"
+ )
+
+ tpl := sms.NewRegistrationCodeValid(reg, &sms.RegistrationCodeValidModel{To: expectedPhone, RegistrationCode: otp})
+
+ expectedBody := fmt.Sprintf("Your registration code is: %s\n\nIt expires in 0 minutes.\n", otp)
+
+ actualBody, err := tpl.SMSBody(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, expectedBody, actualBody)
+
+ actualPhone, err := tpl.PhoneNumber()
+ require.NoError(t, err)
+ assert.Equal(t, expectedPhone, actualPhone)
+}
diff --git a/courier/template/sms/verification_code.go b/courier/template/sms/verification_code.go
index 4204df0ac4c8..13c24be534cd 100644
--- a/courier/template/sms/verification_code.go
+++ b/courier/template/sms/verification_code.go
@@ -23,6 +23,7 @@ type (
Identity map[string]interface{} `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
+ ExpiresInMinutes int `json:"expires_in_minutes"`
}
)
diff --git a/courier/template/sms/verification_code_test.go b/courier/template/sms/verification_code_test.go
index fc2bb892e6b2..4a31ae7f6ce3 100644
--- a/courier/template/sms/verification_code_test.go
+++ b/courier/template/sms/verification_code_test.go
@@ -25,7 +25,7 @@ func TestNewOTPMessage(t *testing.T) {
tpl := sms.NewVerificationCodeValid(reg, &sms.VerificationCodeValidModel{To: expectedPhone, VerificationCode: otp})
- expectedBody := fmt.Sprintf("Your verification code is: %s\n", otp)
+ expectedBody := fmt.Sprintf("Your verification code is: %s\n\nIf this was not you, do nothing. It expires in 0 minutes.\n", otp)
actualBody, err := tpl.SMSBody(context.Background())
require.NoError(t, err)
diff --git a/driver/config/config.go b/driver/config/config.go
index d1e28d166b98..dd7a6a42f00d 100644
--- a/driver/config/config.go
+++ b/driver/config/config.go
@@ -69,6 +69,7 @@ const (
ViperKeyCourierTemplatesVerificationCodeValidEmail = "courier.templates.verification_code.valid.email"
ViperKeyCourierTemplatesVerificationCodeValidSMS = "courier.templates.verification_code.valid.sms"
ViperKeyCourierTemplatesLoginCodeValidSMS = "courier.templates.login_code.valid.sms"
+ ViperKeyCourierTemplatesRegistrationCodeValidSMS = "courier.templates.registration_code.valid.sms"
ViperKeyCourierDeliveryStrategy = "courier.delivery_strategy"
ViperKeyCourierHTTPRequestConfig = "courier.http.request_config"
ViperKeyCourierTemplatesLoginCodeValidEmail = "courier.templates.login_code.valid.email"
@@ -322,6 +323,7 @@ type (
CourierTemplatesRegistrationCodeValid(ctx context.Context) *CourierEmailTemplate
CourierSMSTemplatesVerificationCodeValid(ctx context.Context) *CourierSMSTemplate
CourierSMSTemplatesLoginCodeValid(ctx context.Context) *CourierSMSTemplate
+ CourierSMSTemplatesRegistrationCodeValid(ctx context.Context) *CourierSMSTemplate
CourierMessageRetries(ctx context.Context) int
CourierWorkerPullCount(ctx context.Context) int
CourierWorkerPullWait(ctx context.Context) time.Duration
@@ -1164,6 +1166,10 @@ func (p *Config) CourierSMSTemplatesLoginCodeValid(ctx context.Context) *Courier
return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesLoginCodeValidSMS)
}
+func (p *Config) CourierSMSTemplatesRegistrationCodeValid(ctx context.Context) *CourierSMSTemplate {
+ return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesRegistrationCodeValidSMS)
+}
+
func (p *Config) CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate {
return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesLoginCodeValidEmail)
}
diff --git a/embedx/config.schema.json b/embedx/config.schema.json
index 119ed3766fce..abe5a4e7ac5b 100644
--- a/embedx/config.schema.json
+++ b/embedx/config.schema.json
@@ -2043,6 +2043,9 @@
"properties": {
"email": {
"$ref": "#/definitions/emailCourierTemplate"
+ },
+ "sms": {
+ "$ref": "#/definitions/smsCourierTemplate"
}
},
"required": ["email"]
diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum
index c966c8ddfd0d..6cc3f5911d11 100644
--- a/internal/client-go/go.sum
+++ b/internal/client-go/go.sum
@@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/internal/testhelpers/courier.go b/internal/testhelpers/courier.go
index fcb77f47005d..f4779adcd6d1 100644
--- a/internal/testhelpers/courier.go
+++ b/internal/testhelpers/courier.go
@@ -20,6 +20,7 @@ func CourierExpectMessage(ctx context.Context, t *testing.T, reg interface {
courier.PersistenceProvider
}, recipient, subject string,
) *courier.Message {
+ t.Helper()
messages, total, _, err := reg.CourierPersister().ListMessages(ctx, courier.ListCourierMessagesParameters{
Recipient: recipient,
}, []keysetpagination.Option{})
@@ -31,7 +32,7 @@ func CourierExpectMessage(ctx context.Context, t *testing.T, reg interface {
})
for _, m := range messages {
- if strings.EqualFold(m.Recipient, recipient) && (strings.EqualFold(m.Subject, subject) || strings.Contains(m.Body, subject)) {
+ if strings.EqualFold(m.Recipient, recipient) && (strings.Contains(m.Subject, subject) || strings.Contains(m.Body, subject)) {
return &m
}
}
diff --git a/persistence/sql/migratest/testdata/20200402142539_testdata.sql b/persistence/sql/migratest/testdata/20200402142539_testdata.sql
index 36781f7a493a..6d67a5358c80 100644
--- a/persistence/sql/migratest/testdata/20200402142539_testdata.sql
+++ b/persistence/sql/migratest/testdata/20200402142539_testdata.sql
@@ -3,13 +3,13 @@ INSERT INTO identities (id, traits_schema_id, traits, created_at, updated_at) VA
INSERT INTO continuity_containers (id, identity_id, name, payload, expires_at, created_at, updated_at) VALUES ('50ba09d3-481b-4060-844a-9541a9cec39c', '5ff66179-c240-4703-b0d8-494592cefff5', 'ory_kratos_settings_profile', '{"traits":{"email":"baz@ory.sh"},"request_id":""}', '2013-10-07 08:23:19', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
-INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('98f45a85-0782-49f1-a7b5-8f83d160b4a5', 1, 2, 'Hi, please verify your account by clicking the following link:
+INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('98f45a85-0782-49f1-a7b5-8f83d160b4a5', 1, 2, 'Hi, Verify your account by opening the following link:
http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/swmcFweNFSfvTSTKecmZjO6I8x0hxzZS', 'Please verify your email address', 'foo@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
-INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('7a9d6df4-3b60-4cae-996e-d15d78b0fc36', 1, 2, 'Hi, please verify your account by clicking the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/u9ZcBr5HbRTR8f53Qj2Ng3KR8Mv1Zjdb', 'Please verify your email address', 'foobar@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
-INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('77fdc5e0-2260-49da-8aae-c36ba255d05b', 1, 2, 'Hi, please verify your account by clicking the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/SQcSX0Jx6IVEDKqAuaLZLNEw00J4vlig', 'Please verify your email address', 'foobar@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
-INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('a3ea4c30-0c6e-47b1-99ba-8fa69282e166', 1, 2, 'Hi, please verify your account by clicking the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/AtsREGbtXu0RlIcwv3RPpxHEZNEcq3R9', 'Please verify your email address', 'foo@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
+INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('7a9d6df4-3b60-4cae-996e-d15d78b0fc36', 1, 2, 'Hi, Verify your account by opening the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/u9ZcBr5HbRTR8f53Qj2Ng3KR8Mv1Zjdb', 'Please verify your email address', 'foobar@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
+INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('77fdc5e0-2260-49da-8aae-c36ba255d05b', 1, 2, 'Hi, Verify your account by opening the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/SQcSX0Jx6IVEDKqAuaLZLNEw00J4vlig', 'Please verify your email address', 'foobar@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
+INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('a3ea4c30-0c6e-47b1-99ba-8fa69282e166', 1, 2, 'Hi, Verify your account by opening the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/AtsREGbtXu0RlIcwv3RPpxHEZNEcq3R9', 'Please verify your email address', 'foo@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
INSERT INTO identity_credential_types (id, name) VALUES ('22bff9ae-f5aa-45d7-803b-97ec0b4e7b32', 'password');
INSERT INTO identity_credential_types (id, name) VALUES ('8071b37b-0d54-4c6f-8234-72cffb4ce784', 'totp');
diff --git a/persistence/sql/migratest/testdata/20210307130558_testdata.sql b/persistence/sql/migratest/testdata/20210307130558_testdata.sql
index e92788541f35..b256c62cb945 100644
--- a/persistence/sql/migratest/testdata/20210307130558_testdata.sql
+++ b/persistence/sql/migratest/testdata/20210307130558_testdata.sql
@@ -1 +1 @@
-INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('34948489-31dc-454a-ab3b-b2dcc75a787f', 1, 2, 'Hi, please verify your account by clicking the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/AtsREGbtXu0RlIcwv3RPpxHEZNEcq3R9', 'Please verify your email address', 'foo@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
+INSERT INTO courier_messages (id, type, status, body, subject, recipient, created_at, updated_at) VALUES ('34948489-31dc-454a-ab3b-b2dcc75a787f', 1, 2, 'Hi, Verify your account by opening the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/AtsREGbtXu0RlIcwv3RPpxHEZNEcq3R9', 'Please verify your email address', 'foo@ory.sh', '2013-10-07 08:23:19', '2013-10-07 08:23:19');
diff --git a/persistence/sql/migratest/testdata/20221205095201_testdata.sql b/persistence/sql/migratest/testdata/20221205095201_testdata.sql
index de20fc952a73..fee47fdd5e8d 100644
--- a/persistence/sql/migratest/testdata/20221205095201_testdata.sql
+++ b/persistence/sql/migratest/testdata/20221205095201_testdata.sql
@@ -17,7 +17,7 @@ VALUES
'd9d4401c-08a1-434c-8ab5-4a7edefde351',
1,
2,
- 'Hi, please verify your account by clicking the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/u9ZcBr5HbRTR8f53Qj2Ng3KR8Mv1Zjdb',
+ 'Hi, Verify your account by opening the following link: http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/verification/email/confirm/u9ZcBr5HbRTR8f53Qj2Ng3KR8Mv1Zjdb',
'Please verify your email address',
'foobar@ory.sh',
'2013-10-07 08:23:19',
@@ -38,4 +38,4 @@ VALUES
'884f556e-eb3a-4b9f-bee3-11345642c6c0',
'2013-10-07 08:23:19',
'2013-10-07 08:23:19'
- )
\ No newline at end of file
+ )
diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go
index 02fda31f3d0a..20e392836ce7 100644
--- a/selfservice/strategy/code/code_sender.go
+++ b/selfservice/strategy/code/code_sender.go
@@ -101,21 +101,35 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit
return err
}
- emailModel := email.RegistrationCodeValidModel{
- To: address.To,
- RegistrationCode: rawCode,
- Traits: model,
- RequestURL: f.GetRequestURL(),
- TransientPayload: transientPayload,
- }
-
s.deps.Audit().
WithField("registration_flow_id", code.FlowID).
WithField("registration_code_id", code.ID).
WithSensitiveField("registration_code", rawCode).
Info("Sending out registration email with code.")
- if err := s.send(ctx, string(address.Via), email.NewRegistrationCodeValid(s.deps, &emailModel)); err != nil {
+ var t courier.Template
+ switch address.Via {
+ case identity.ChannelTypeEmail:
+ t = email.NewRegistrationCodeValid(s.deps, &email.RegistrationCodeValidModel{
+ To: address.To,
+ RegistrationCode: rawCode,
+ Traits: model,
+ RequestURL: f.GetRequestURL(),
+ TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
+ })
+ case identity.ChannelTypeSMS:
+ t = sms.NewRegistrationCodeValid(s.deps, &sms.RegistrationCodeValidModel{
+ To: address.To,
+ RegistrationCode: rawCode,
+ Identity: model,
+ RequestURL: f.GetRequestURL(),
+ TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
+ })
+ }
+
+ if err := s.send(ctx, string(address.Via), t); err != nil {
return errors.WithStack(err)
}
@@ -153,6 +167,7 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
})
case identity.ChannelTypeSMS:
t = sms.NewLoginCodeValid(s.deps, &sms.LoginCodeValidModel{
@@ -161,6 +176,7 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
})
}
@@ -266,6 +282,7 @@ func (s *Sender) SendRecoveryCodeTo(ctx context.Context, i *identity.Identity, c
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
}
return s.send(ctx, string(code.RecoveryAddress.Via), email.NewRecoveryCodeValid(s.deps, &emailModel))
@@ -371,6 +388,7 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo
VerificationCode: codeString,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
})
case identity.ChannelTypeSMS:
t = sms.NewVerificationCodeValid(s.deps, &sms.VerificationCodeValidModel{
@@ -379,6 +397,7 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
})
default:
return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email or sms but got %s", code.VerifiableAddress.Via))
diff --git a/selfservice/strategy/code/code_sender_test.go b/selfservice/strategy/code/code_sender_test.go
index e5ba75826eb5..4e306a78cf02 100644
--- a/selfservice/strategy/code/code_sender_test.go
+++ b/selfservice/strategy/code/code_sender_test.go
@@ -66,7 +66,7 @@ func TestSender(t *testing.T) {
require.Len(t, messages, 2)
assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient)
- assert.Contains(t, messages[0].Subject, "Recover access to your account")
+ assert.Contains(t, messages[0].Subject, "Use code")
assert.Regexp(t, testhelpers.CodeRegex, messages[0].Body)
@@ -122,7 +122,7 @@ func TestSender(t *testing.T) {
require.Len(t, messages, 2)
assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient)
- assert.Contains(t, messages[0].Subject, "Please verify your email address")
+ assert.Contains(t, messages[0].Subject, "Use code")
assert.Regexp(t, testhelpers.CodeRegex, messages[0].Body)
diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go
index 1e8fb5cb6af4..aaac228508fd 100644
--- a/selfservice/strategy/code/strategy.go
+++ b/selfservice/strategy/code/strategy.go
@@ -352,7 +352,7 @@ func (s *Strategy) populateEmailSentFlow(ctx context.Context, f flow.Flow) error
case flow.LoginFlow:
route = login.RouteSubmitFlow
codeMetaLabel = text.NewInfoNodeLabelLoginCode()
- message = text.NewLoginEmailWithCodeSent()
+ message = text.NewLoginCodeSent()
// preserve the login identifier that was submitted
// so we can retry the code flow with the same data
diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go
index d93972162852..95952f45d7de 100644
--- a/selfservice/strategy/code/strategy_login_test.go
+++ b/selfservice/strategy/code/strategy_login_test.go
@@ -236,8 +236,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", stringsx.ToUpperInitial(s.identityEmail))
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -257,8 +257,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -284,8 +284,8 @@ func TestLoginCodeStrategy(t *testing.T) {
t.Logf("s.body: %s", s.body)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -450,8 +450,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -478,8 +478,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -505,8 +505,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -564,8 +564,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -616,8 +616,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -652,8 +652,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -663,8 +663,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message = testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message = testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode2 := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode2)
@@ -713,8 +713,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, loginEmail, "Login to your account")
- require.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, loginEmail, "Use code")
+ require.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
require.NotEmpty(t, loginCode)
@@ -795,8 +795,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("identifier", s.identityEmail)
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -837,8 +837,8 @@ func TestLoginCodeStrategy(t *testing.T) {
v.Set("method", "code")
}, false, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, loginCode)
@@ -988,8 +988,8 @@ func TestLoginCodeStrategy(t *testing.T) {
var message *courier.Message
if !strings.HasPrefix(identifier, "+") {
// email
- message = testhelpers.CourierExpectMessage(ctx, t, reg, x.GracefulNormalization(identifier), "Login to your account")
- assert.Contains(t, message.Body, "please login to your account by entering the following code")
+ message = testhelpers.CourierExpectMessage(ctx, t, reg, x.GracefulNormalization(identifier), "Use code")
+ assert.Contains(t, message.Body, "Login to your account with the following code")
} else {
// SMS
message = testhelpers.CourierExpectMessage(ctx, t, reg, x.GracefulNormalization(identifier), "Your login code is:")
diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go
index 483e8dfc6f89..9b55016daebb 100644
--- a/selfservice/strategy/code/strategy_recovery_test.go
+++ b/selfservice/strategy/code/strategy_recovery_test.go
@@ -242,8 +242,8 @@ func TestRecovery(t *testing.T) {
assert.Len(t, gjson.Get(recoverySubmissionResponse, "ui.messages").Array(), 1, "%s", recoverySubmissionResponse)
assertx.EqualAsJSON(t, text.NewRecoveryEmailWithCodeSent(), json.RawMessage(gjson.Get(recoverySubmissionResponse, "ui.messages.0").Raw))
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
- assert.Contains(t, message.Body, "please recover access to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
+ assert.Contains(t, message.Body, "Recover access to your account by entering")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, recoveryCode)
@@ -316,7 +316,7 @@ func TestRecovery(t *testing.T) {
formPayload.Set("transient_payload", templatePayload)
body, _ := testhelpers.RecoveryMakeRequest(t, false, f, client, formPayload.Encode())
- message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Use code")
assert.Equal(t, templatePayload, gjson.GetBytes(message.TemplateData, "transient_payload").String(),
"should pass transient payload to email template")
@@ -607,7 +607,7 @@ func TestRecovery(t *testing.T) {
addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, email)
assert.NoError(t, err)
- emailText := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account")
+ emailText := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, emailText, 1)
// Deactivate the identity
@@ -646,7 +646,7 @@ func TestRecovery(t *testing.T) {
actual := expectSuccessfulRecovery(t, cl, RecoveryClientTypeBrowser, func(v url.Values) {
v.Set("email", email)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
cl.CheckRedirect = func(req *http.Request, via []*http.Request) error {
@@ -707,7 +707,7 @@ func TestRecovery(t *testing.T) {
v.Set("email", recoveryEmail)
}, http.StatusOK)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
form := withCSRFToken(t, testCase.ClientType, actual, url.Values{
@@ -818,8 +818,8 @@ func TestRecovery(t *testing.T) {
initialFlowId := gjson.Get(body, "id")
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
- assert.Contains(t, message.Body, "please recover access to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
+ assert.Contains(t, message.Body, "Recover access to your account by entering")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
@@ -873,7 +873,7 @@ func TestRecovery(t *testing.T) {
assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists())
assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, recoveryCode, http.StatusOK)
@@ -892,14 +892,14 @@ func TestRecovery(t *testing.T) {
require.NotEmpty(t, action)
assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message1 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message1 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode1 := testhelpers.CourierExpectCodeInMessage(t, message1, 1)
body = resendRecoveryCode(t, c, body, RecoveryClientTypeBrowser, http.StatusOK)
assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists())
assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message2 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message2 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode2 := testhelpers.CourierExpectCodeInMessage(t, message2, 1)
body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, recoveryCode1, http.StatusOK)
@@ -943,7 +943,7 @@ func TestRecovery(t *testing.T) {
v.Set("email", recoveryEmail)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
action := gjson.Get(body, "ui.action").String()
@@ -975,7 +975,7 @@ func TestRecovery(t *testing.T) {
v.Set("email", recoveryEmail)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
action := gjson.Get(body, "ui.action").String()
@@ -1117,8 +1117,8 @@ func TestRecovery_WithContinueWith(t *testing.T) {
assert.Len(t, gjson.Get(recoverySubmissionResponse, "ui.messages").Array(), 1, "%s", recoverySubmissionResponse)
assertx.EqualAsJSON(t, text.NewRecoveryEmailWithCodeSent(), json.RawMessage(gjson.Get(recoverySubmissionResponse, "ui.messages.0").Raw))
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
- assert.Contains(t, message.Body, "please recover access to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
+ assert.Contains(t, message.Body, "Recover access to your account by entering")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, recoveryCode)
@@ -1435,7 +1435,7 @@ func TestRecovery_WithContinueWith(t *testing.T) {
addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, email)
assert.NoError(t, err)
- emailText := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account")
+ emailText := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, emailText, 1)
// Deactivate the identity
@@ -1478,7 +1478,7 @@ func TestRecovery_WithContinueWith(t *testing.T) {
actual := submitRecoveryForm(t, cl, testCase.ClientType, func(v url.Values) {
v.Set("email", email)
}, http.StatusOK)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
submitCodeAndExpectRedirectToSettings(t, cl, testCase.ClientType, recoveryCode, actual)
@@ -1555,7 +1555,7 @@ func TestRecovery_WithContinueWith(t *testing.T) {
v.Set("email", recoveryEmail)
}, http.StatusOK)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
form := withCSRFToken(t, testCase.ClientType, actual, url.Values{
@@ -1631,7 +1631,7 @@ func TestRecovery_WithContinueWith(t *testing.T) {
v.Set("email", recoveryEmail)
}, http.StatusOK)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
action := gjson.Get(actual, "ui.action").String()
@@ -1744,8 +1744,8 @@ func TestRecovery_WithContinueWith(t *testing.T) {
initialFlowId := gjson.Get(body, "id")
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
- assert.Contains(t, message.Body, "please recover access to your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
+ assert.Contains(t, message.Body, "Recover access to your account by entering")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
@@ -1812,7 +1812,7 @@ func TestRecovery_WithContinueWith(t *testing.T) {
assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists())
assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
submitCodeAndExpectRedirectToSettings(t, c, testCase.ClientType, recoveryCode, body)
@@ -1835,14 +1835,14 @@ func TestRecovery_WithContinueWith(t *testing.T) {
require.NotEmpty(t, action)
assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message1 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message1 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode1 := testhelpers.CourierExpectCodeInMessage(t, message1, 1)
body = resendRecoveryCode(t, c, body, testCase.ClientType, http.StatusOK)
assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists())
assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message2 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message2 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode2 := testhelpers.CourierExpectCodeInMessage(t, message2, 1)
body = submitRecoveryCode(t, c, body, testCase.ClientType, recoveryCode1, http.StatusOK)
@@ -1892,7 +1892,7 @@ func TestRecovery_WithContinueWith(t *testing.T) {
v.Set("email", recoveryEmail)
}, http.StatusOK)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
action := gjson.Get(body, "ui.action").String()
@@ -1920,7 +1920,7 @@ func TestRecovery_WithContinueWith(t *testing.T) {
v.Set("email", recoveryEmail)
}, http.StatusOK)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Use code")
recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
action := gjson.Get(body, "ui.action").String()
diff --git a/selfservice/strategy/code/strategy_registration_test.go b/selfservice/strategy/code/strategy_registration_test.go
index c5988047d0a3..b5f0d6e02c9f 100644
--- a/selfservice/strategy/code/strategy_registration_test.go
+++ b/selfservice/strategy/code/strategy_registration_test.go
@@ -274,8 +274,8 @@ func TestRegistrationCodeStrategy(t *testing.T) {
// 2. Submit Identifier (email)
state = registerNewUser(ctx, t, state, tc.apiType, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration with the following code")
registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode)
@@ -307,8 +307,8 @@ func TestRegistrationCodeStrategy(t *testing.T) {
// 2. Submit Identifier (email)
state = registerNewUser(ctx, t, state, tc.apiType, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, sourceMail, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, sourceMail, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration with the following code")
registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode)
@@ -351,8 +351,8 @@ func TestRegistrationCodeStrategy(t *testing.T) {
require.Equal(t, "code", val, body)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration with the following code")
registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode)
@@ -372,12 +372,12 @@ func TestRegistrationCodeStrategy(t *testing.T) {
} else {
require.NotEmptyf(t, csrfToken, "expected to find the csrf_token but got %s", body)
}
- require.Containsf(t, gjson.Get(body, "ui.messages").String(), "An email containing a code has been sent to the email address you provided.", "%s", body)
+ require.Containsf(t, gjson.Get(body, "ui.messages").String(), "A code has been sent to the address(es) you provided", "%s", body)
})
// get the new code from email
- message = testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message = testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration with the following code")
registrationCode2 := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode2)
@@ -410,8 +410,8 @@ func TestRegistrationCodeStrategy(t *testing.T) {
// 2. Submit Identifier (email)
s = registerNewUser(ctx, t, s, tc.apiType, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration with the following code")
registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode)
@@ -439,8 +439,8 @@ func TestRegistrationCodeStrategy(t *testing.T) {
// 2. Submit Identifier (email)
s = registerNewUser(ctx, t, s, tc.apiType, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration")
registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode)
@@ -573,8 +573,8 @@ func TestRegistrationCodeStrategy(t *testing.T) {
// 2. Submit Identifier (email)
state = registerNewUser(ctx, t, state, tc.apiType, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration with the following code")
registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode)
@@ -597,8 +597,8 @@ func TestRegistrationCodeStrategy(t *testing.T) {
// 2. Submit Identifier (email)
s = registerNewUser(ctx, t, s, tc.apiType, nil)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration")
- assert.Contains(t, message.Body, "please complete your account registration by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Use code")
+ assert.Contains(t, message.Body, "Complete your account registration with the following code")
registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
assert.NotEmpty(t, registrationCode)
diff --git a/selfservice/strategy/code/strategy_verification_test.go b/selfservice/strategy/code/strategy_verification_test.go
index 322dc56eabd2..5bd8417d180d 100644
--- a/selfservice/strategy/code/strategy_verification_test.go
+++ b/selfservice/strategy/code/strategy_verification_test.go
@@ -285,8 +285,8 @@ func TestVerification(t *testing.T) {
v.Set("email", verificationEmail)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
- assert.Contains(t, message.Body, "please verify your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
+ assert.Contains(t, message.Body, "Verify your account with the following code")
code := testhelpers.CourierExpectCodeInMessage(t, message, 1)
@@ -310,8 +310,8 @@ func TestVerification(t *testing.T) {
assert.EqualValues(t, verificationEmail, gjson.Get(actual, "ui.nodes.#(attributes.name==email).attributes.value").String(), "%s", actual)
assertx.EqualAsJSON(t, text.NewVerificationEmailWithCodeSent(), json.RawMessage(gjson.Get(actual, "ui.messages.0").Raw))
- message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
- assert.Contains(t, message.Body, "please verify your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
+ assert.Contains(t, message.Body, "Verify your account with the following code")
verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1)
@@ -374,7 +374,7 @@ func TestVerification(t *testing.T) {
}
expectSuccess(t, nil, false, false, values)
- message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1)
code := testhelpers.CourierExpectCodeInMessage(t, message, 1)
@@ -442,8 +442,8 @@ func TestVerification(t *testing.T) {
v.Set("email", verificationEmail)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
- assert.Contains(t, message.Body, "please verify your account by entering the following code")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
+ assert.Contains(t, message.Body, "Verify your account with the following code")
verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1)
@@ -507,7 +507,7 @@ func TestVerification(t *testing.T) {
v.Set("email", verificationEmail)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
_ = testhelpers.CourierExpectCodeInMessage(t, message, 1)
c := testhelpers.NewClientWithCookies(t)
@@ -516,7 +516,7 @@ func TestVerification(t *testing.T) {
assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists())
assert.Equal(t, verificationEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
+ message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
verificationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
submitVerificationCode(t, body, c, verificationCode)
@@ -527,7 +527,7 @@ func TestVerification(t *testing.T) {
v.Set("email", verificationEmail)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
firstCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
c := testhelpers.NewClientWithCookies(t)
@@ -536,7 +536,7 @@ func TestVerification(t *testing.T) {
assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists())
assert.Equal(t, verificationEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String())
- message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
+ message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
secondCode := testhelpers.CourierExpectCodeInMessage(t, message, 1)
body, res := submitVerificationCode(t, body, c, firstCode)
@@ -587,7 +587,7 @@ func TestVerification(t *testing.T) {
body := expectSuccess(t, nil, true, false, func(v url.Values) {
v.Set("email", verificationEmail)
})
- message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
+ message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
code := testhelpers.CourierExpectCodeInMessage(t, message, 1)
body, res := submitVerificationCode(t, body, c, code)
@@ -597,7 +597,7 @@ func TestVerification(t *testing.T) {
body = expectSuccess(t, nil, true, false, func(v url.Values) {
v.Set("email", verificationEmail)
})
- message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
+ message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Use code")
code = testhelpers.CourierExpectCodeInMessage(t, message, 1)
body, res = submitVerificationCode(t, body, c, code)
diff --git a/selfservice/strategy/link/sender.go b/selfservice/strategy/link/sender.go
index 41231a721b8b..c289b657e0a1 100644
--- a/selfservice/strategy/link/sender.go
+++ b/selfservice/strategy/link/sender.go
@@ -202,6 +202,7 @@ func (s *Sender) SendRecoveryTokenTo(ctx context.Context, f *recovery.Flow, i *i
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.r.Config().SelfServiceLinkMethodLifespan(ctx).Minutes()),
}))
}
@@ -231,13 +232,14 @@ func (s *Sender) SendVerificationTokenTo(ctx context.Context, f *verification.Fl
"token": {token.Token},
}).String()
- if err := s.send(ctx, string(address.Via), email.NewVerificationValid(s.r,
+ if err := s.send(ctx, address.Via, email.NewVerificationValid(s.r,
&email.VerificationValidModel{
To: address.Value,
VerificationURL: verificationUrl,
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
+ ExpiresInMinutes: int(s.r.Config().SelfServiceLinkMethodLifespan(ctx).Minutes()),
})); err != nil {
return err
}
diff --git a/selfservice/strategy/link/strategy_recovery_test.go b/selfservice/strategy/link/strategy_recovery_test.go
index 5cc6c510d73e..531cb4e77502 100644
--- a/selfservice/strategy/link/strategy_recovery_test.go
+++ b/selfservice/strategy/link/strategy_recovery_test.go
@@ -506,7 +506,7 @@ func TestRecovery(t *testing.T) {
assertx.EqualAsJSON(t, text.NewRecoveryEmailSent(), json.RawMessage(gjson.Get(recoverySubmissionResponse, "ui.messages.0").Raw))
message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
- assert.Contains(t, message.Body, "please recover access to your account by clicking the following link")
+ assert.Contains(t, message.Body, "Recover access to your account by clicking the following link")
recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1)
@@ -788,7 +788,7 @@ func TestRecovery(t *testing.T) {
})
message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account")
- assert.Contains(t, message.Body, "please recover access to your account by clicking the following link")
+ assert.Contains(t, message.Body, "Recover access to your account by clicking the following link")
recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1)
diff --git a/selfservice/strategy/link/strategy_verification_test.go b/selfservice/strategy/link/strategy_verification_test.go
index b2fd7c0f405a..ae0e20021338 100644
--- a/selfservice/strategy/link/strategy_verification_test.go
+++ b/selfservice/strategy/link/strategy_verification_test.go
@@ -248,7 +248,7 @@ func TestVerification(t *testing.T) {
})
message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
- assert.Contains(t, message.Body, "Hi, please verify your account by clicking the following link")
+ assert.Contains(t, message.Body, "Verify your account by opening the following link")
verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1)
@@ -283,7 +283,7 @@ func TestVerification(t *testing.T) {
assertx.EqualAsJSON(t, text.NewVerificationEmailSent(), json.RawMessage(gjson.Get(actual, "ui.messages.0").Raw))
message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address")
- assert.Contains(t, message.Body, "please verify your account by clicking the following link")
+ assert.Contains(t, message.Body, "Verify your account by opening the following link")
verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1)
diff --git a/selfservice/strategy/profile/strategy_test.go b/selfservice/strategy/profile/strategy_test.go
index d34c3f9e94f6..be9b448a0215 100644
--- a/selfservice/strategy/profile/strategy_test.go
+++ b/selfservice/strategy/profile/strategy_test.go
@@ -544,7 +544,7 @@ func TestStrategyTraits(t *testing.T) {
m, err := reg.CourierPersister().LatestQueuedMessage(context.Background())
require.NoError(t, err)
- assert.Contains(t, m.Subject, "verify your email address")
+ assert.Contains(t, m.Subject, "Use code")
}
payload := func(newEmail string) func(v url.Values) {
diff --git a/test/e2e/cypress/helpers/index.ts b/test/e2e/cypress/helpers/index.ts
index 52bcb339ad50..ef61a5546bba 100644
--- a/test/e2e/cypress/helpers/index.ts
+++ b/test/e2e/cypress/helpers/index.ts
@@ -95,7 +95,7 @@ export const appPrefix = (app) => `[data-testid="app-${app}"] `
export const codeRegex = /(\d{6})/
-export function extractRecoveryCode(body: string): string | null {
+export function extractOTPCode(body: string): string | null {
const result = codeRegex.exec(body)
if (result != null && result.length > 0) {
return result[0]
diff --git a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts
index 244d40ab8132..cf929a1df6fb 100644
--- a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts
+++ b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts
@@ -78,10 +78,7 @@ context("Login error messages with code method", () => {
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1010014"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1010014"]').should("exist")
cy.get(Selectors[app]["code"]).type("123456")
cy.submitCodeForm(app)
diff --git a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts
index 4570c1c5cc60..a1e10a196c02 100644
--- a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts
+++ b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts
@@ -69,10 +69,7 @@ context("Registration error messages with code method", () => {
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.get(Selectors[app]["code"]).type("123456")
cy.submitCodeForm(app)
@@ -90,10 +87,7 @@ context("Registration error messages with code method", () => {
cy.get(Selectors[app]["tos"]).click()
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
if (app !== "express") {
// the mobile app doesn't render hidden fields in the DOM
@@ -131,10 +125,7 @@ context("Registration error messages with code method", () => {
cy.get(Selectors[app]["tos"]).click()
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.removeAttribute([Selectors[app]["code"]], "required")
@@ -200,10 +191,7 @@ context("Registration error messages with code method", () => {
cy.get(Selectors[app]["tos"]).click()
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.getRegistrationCodeFromEmail(email).then((code) => {
cy.get(Selectors[app]["code"]).type(code)
diff --git a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts
index c715d80cd86e..91c48b760f1c 100644
--- a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts
+++ b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts
@@ -98,10 +98,7 @@ context("Registration success with code method", () => {
cy.get(Selectors[app]["tos"]).click()
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.getRegistrationCodeFromEmail(email).then((code) =>
cy.wrap(code).as("code1"),
@@ -166,10 +163,7 @@ context("Registration success with code method", () => {
cy.get(Selectors[app]["tos"]).click()
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.getRegistrationCodeFromEmail(email).should((code) => {
cy.get(Selectors[app]["code"]).type(code)
@@ -216,10 +210,7 @@ context("Registration success with code method", () => {
cy.get(Selectors[app]["tos"]).click()
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.getRegistrationCodeFromEmail(email).should((code) => {
cy.get(Selectors[app]["code"]).type(code)
@@ -329,10 +320,7 @@ context("Registration success with code method", () => {
cy.get(Selectors[app]["email2"]).type(email2)
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
// intentionally use email 1 to sign up for the account
cy.getRegistrationCodeFromEmail(email, { expectedCount: 1 }).should(
diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts
index 861cfd0d2a79..d7f73f44872c 100644
--- a/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts
+++ b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts
@@ -218,14 +218,20 @@ context("OpenID Provider - change between flows", () => {
})
it("switch to recovery flow with password reset", () => {
+ cy.updateConfigFile((config) => {
+ config.selfservice.flows.recovery.lifespan = "1m"
+ config.selfservice.methods.link.config.lifespan = "1m"
+ config.selfservice.flows.verification.enabled = false
+ if (!config.selfservice.flows.recovery) {
+ config.selfservice.flows.recovery = {}
+ }
+ config.selfservice.flows.recovery.enabled = true
+ config.selfservice.flows.settings.privileged_session_max_age = "5m"
+ return config
+ })
cy.deleteMail()
- cy.longRecoveryLifespan()
- cy.longLinkLifespan()
- cy.disableVerification()
- cy.enableRecovery()
cy.useRecoveryStrategy("code")
cy.notifyUnknownRecipients("recovery", false)
- cy.longPrivilegedSessionTime()
const identity = gen.identityWithWebsite()
cy.registerApi(identity)
diff --git a/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts b/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts
index 23d877049e6c..8da454cfdfe7 100644
--- a/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts
+++ b/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts
@@ -1,7 +1,7 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
-import { appPrefix, email, extractRecoveryCode, gen } from "../../../../helpers"
+import { appPrefix, email, extractOTPCode, gen } from "../../../../helpers"
import { routes as express } from "../../../../helpers/express"
import { routes as react } from "../../../../helpers/react"
@@ -123,7 +123,7 @@ context("Account Recovery Errors", () => {
expect(message.toAddresses).to.have.length(1)
expect(message.toAddresses[0].trim()).to.equal(email)
- const code = extractRecoveryCode(message.body)
+ const code = extractOTPCode(message.body)
expect(code).to.be.null
})
})
diff --git a/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts b/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts
index bffafb36ee03..41cc98c03eb8 100644
--- a/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts
+++ b/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts
@@ -104,10 +104,7 @@ context("Registration success with code method", () => {
cy.submitProfileForm(app)
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.getRegistrationCodeFromEmail(email).then((code) =>
cy.wrap(code).as("code1"),
@@ -187,10 +184,7 @@ context("Registration success with code method", () => {
cy.submitProfileForm(app)
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.getRegistrationCodeFromEmail(email).should((code) => {
cy.get(Selectors[app]["code"]).type(code)
@@ -234,10 +228,7 @@ context("Registration success with code method", () => {
cy.submitProfileForm(app)
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
cy.getRegistrationCodeFromEmail(email).should((code) => {
cy.get(Selectors[app]["code"]).type(code)
@@ -305,10 +296,7 @@ context("Registration success with code method", () => {
cy.submitProfileForm(app)
cy.submitCodeForm(app)
- cy.get('[data-testid="ui/message/1040005"]').should(
- "contain",
- "An email containing a code has been sent to the email address you provided",
- )
+ cy.get('[data-testid="ui/message/1040005"]').should("be.visible")
// intentionally use email 1 to sign up for the account
cy.getRegistrationCodeFromEmail(email, { expectedCount: 1 }).should(
diff --git a/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts b/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts
index 06a68f4af237..f8436c7eae1a 100644
--- a/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts
+++ b/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts
@@ -66,7 +66,7 @@ context("Account Verification Registration Errors", () => {
it("is unable to verify the email address if the code is incorrect", () => {
cy.getMail({
- subject: "Please verify your email address",
+ body: "Verify your account",
email: identity.email,
}).then((mail) => {
const link = parseHtml(mail.body).querySelector("a")
diff --git a/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts b/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts
index 287f63a931e0..91ae2c5e8259 100644
--- a/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts
+++ b/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts
@@ -72,7 +72,7 @@ context("Account Verification Settings Error", () => {
cy.get('button[value="profile"]').click()
cy.getMail({
- subject: "Please verify your email address",
+ body: "Verify your account",
email,
}).then((mail) => {
const link = parseHtml(mail.body).querySelector("a")
diff --git a/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts b/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts
index 97fd908a2e22..afb8d9730413 100644
--- a/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts
+++ b/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts
@@ -70,12 +70,9 @@ context("Account Verification Error", () => {
cy.getMail({
removeMail: true,
- subject: "Please verify your email address",
+ body: "Verify your account",
email: identity.email,
}).then((message) => {
- expect(message.subject).to.equal(
- "Please verify your email address",
- )
expect(message.toAddresses[0].trim()).to.equal(identity.email)
const link = parseHtml(message.body).querySelector("a")
@@ -136,7 +133,7 @@ context("Account Verification Error", () => {
cy.getMail({
email: identity.email,
- subject: "Please verify your email address",
+ body: "Verify your account",
}).then((mail) => {
const link = parseHtml(mail.body).querySelector("a")
diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts
index 89b5c7cb15c5..2d933360c26e 100644
--- a/test/e2e/cypress/support/commands.ts
+++ b/test/e2e/cypress/support/commands.ts
@@ -4,7 +4,7 @@
import {
APP_URL,
assertVerifiableAddress,
- extractRecoveryCode,
+ extractOTPCode,
gen,
KRATOS_ADMIN,
KRATOS_PUBLIC,
@@ -1112,9 +1112,8 @@ Cypress.Commands.add(
({ expect: { email, redirectTo }, strategy = "code" }) => {
cy.getMail({
email,
- subject: "Please verify your email address",
+ body: "Verify your account",
}).then((message) => {
- expect(message.subject).to.equal("Please verify your email address")
expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh")
expect(message.toAddresses).to.have.length(1)
expect(message.toAddresses[0].trim()).to.equal(email)
@@ -1176,9 +1175,9 @@ Cypress.Commands.add(
cy.getMail({
removeMail: true,
email,
- subject: "Recover access to your account",
+ body: "Recover access to your account",
}).should((message) => {
- const code = extractRecoveryCode(message.body)
+ const code = extractOTPCode(message.body)
expect(code).to.not.be.undefined
expect(code.length).to.equal(6)
cy.wrap(code).as("recoveryCode")
@@ -1221,7 +1220,7 @@ Cypress.Commands.add(
cy.getMail({
removeMail: true,
email,
- subject: "Please verify your email address",
+ body: "Verify your account",
}).should((message) => {
expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh")
expect(message.toAddresses).to.have.length(1)
@@ -1286,6 +1285,7 @@ Cypress.Commands.add(
expectedCount = 1,
email = undefined,
subject = undefined,
+ body = undefined,
}) => {
let tries = 0
const req = () =>
@@ -1313,6 +1313,9 @@ Cypress.Commands.add(
if (subject) {
filters.push((m: MailMessage) => m.subject.includes(subject))
}
+ if (body) {
+ filters.push((m: MailMessage) => m.body.includes(body))
+ }
const filtered = response.body.mailItems.filter((m) => {
return filters.every((f) => f(m))
})
@@ -1525,13 +1528,13 @@ Cypress.Commands.add("getVerificationCodeFromEmail", (email) => {
.getMail({
removeMail: true,
email,
- subject: "Please verify your email address",
+ body: "Verify your account",
})
.should((message) => {
expect(message.toAddresses[0].trim()).to.equal(email)
})
.then((message) => {
- const code = extractRecoveryCode(message.body)
+ const code = extractOTPCode(message.body)
expect(code).to.not.be.undefined
expect(code.length).to.equal(6)
return code
@@ -1543,14 +1546,14 @@ Cypress.Commands.add("getRegistrationCodeFromEmail", (email, opts) => {
.getMail({
removeMail: true,
email,
- subject: "Complete your account registration",
+ body: "Complete your account registration with the following code",
...opts,
})
.should((message) => {
expect(message.toAddresses[0].trim()).to.equal(email)
})
.then((message) => {
- const code = extractRecoveryCode(message.body)
+ const code = extractOTPCode(message.body)
expect(code).to.not.be.undefined
expect(code.length).to.equal(6)
return code
@@ -1562,14 +1565,14 @@ Cypress.Commands.add("getLoginCodeFromEmail", (email, opts) => {
.getMail({
removeMail: true,
email,
- subject: "Login to your account",
+ body: "Login to your account with the following code",
...opts,
})
.should((message) => {
expect(message.toAddresses[0].trim()).to.equal(email)
})
.then((message) => {
- const code = extractRecoveryCode(message.body)
+ const code = extractOTPCode(message.body)
expect(code).to.not.be.undefined
expect(code.length).to.equal(6)
return code
diff --git a/test/e2e/cypress/support/index.d.ts b/test/e2e/cypress/support/index.d.ts
index a6a7120937de..667360b32c66 100644
--- a/test/e2e/cypress/support/index.d.ts
+++ b/test/e2e/cypress/support/index.d.ts
@@ -114,6 +114,7 @@ declare global {
expectedCount?: number
email?: string
subject?: string
+ body?: string
}): Chainable
performEmailVerification(opts?: {
diff --git a/test/e2e/mock/httptarget/go.mod b/test/e2e/mock/httptarget/go.mod
new file mode 100644
index 000000000000..2d66a9ff4f48
--- /dev/null
+++ b/test/e2e/mock/httptarget/go.mod
@@ -0,0 +1,10 @@
+module github.com/ory/mock
+
+go 1.22.1
+
+require (
+ github.com/julienschmidt/httprouter v1.3.0
+ github.com/ory/graceful v0.1.3
+)
+
+require github.com/pkg/errors v0.9.1 // indirect
diff --git a/test/e2e/mock/httptarget/go.sum b/test/e2e/mock/httptarget/go.sum
new file mode 100644
index 000000000000..e44bf27060c1
--- /dev/null
+++ b/test/e2e/mock/httptarget/go.sum
@@ -0,0 +1,16 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/ory/graceful v0.1.3 h1:FaeXcHZh168WzS+bqruqWEw/HgXWLdNv2nJ+fbhxbhc=
+github.com/ory/graceful v0.1.3/go.mod h1:4zFz687IAF7oNHHiB586U4iL+/4aV09o/PYLE34t2bA=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/test/e2e/mock/httptarget/main.go b/test/e2e/mock/httptarget/main.go
new file mode 100644
index 000000000000..c95d0834fb76
--- /dev/null
+++ b/test/e2e/mock/httptarget/main.go
@@ -0,0 +1,79 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+package main
+
+import (
+ "cmp"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "sync"
+
+ "github.com/julienschmidt/httprouter"
+
+ "github.com/ory/graceful"
+)
+
+var (
+ documentsLock sync.RWMutex
+ documents = make(map[string][]byte)
+)
+
+func main() {
+ port := cmp.Or(os.Getenv("PORT"), "4471")
+ server := graceful.WithDefaults(&http.Server{Addr: fmt.Sprintf(":%s", port)})
+ register(server)
+ if err := graceful.Graceful(server.ListenAndServe, server.Shutdown); err != nil {
+ log.Fatalln(err)
+ }
+}
+
+func register(server *http.Server) {
+ router := httprouter.New()
+
+ router.GET("/health", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+ _, _ = w.Write([]byte("OK"))
+ })
+
+ router.GET("/documents/:id", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
+ id := ps.ByName("id")
+
+ documentsLock.RLock()
+ doc, ok := documents[id]
+ documentsLock.RUnlock()
+
+ if ok {
+ _, _ = w.Write(doc)
+ } else {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ })
+
+ router.PUT("/documents/:id", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
+ documentsLock.Lock()
+ defer documentsLock.Unlock()
+ id := ps.ByName("id")
+
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ documents[id] = body
+ })
+
+ router.DELETE("/documents/:id", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
+ documentsLock.Lock()
+ defer documentsLock.Unlock()
+ id := ps.ByName("id")
+
+ delete(documents, id)
+ w.WriteHeader(http.StatusNoContent)
+ })
+
+ server.Handler = router
+}
diff --git a/test/e2e/package-lock.json b/test/e2e/package-lock.json
index f6452591bda9..7dd8c6416648 100644
--- a/test/e2e/package-lock.json
+++ b/test/e2e/package-lock.json
@@ -8,7 +8,8 @@
"name": "@ory/kratos-e2e-suite",
"version": "0.0.1",
"dependencies": {
- "@faker-js/faker": "8.4.1",
+ "@faker-js/faker": "9.0.3",
+ "@types/promise-retry": "^1.1.6",
"async-retry": "1.3.3",
"mailhog": "4.16.0",
"promise-retry": "^2.0.1"
@@ -26,6 +27,7 @@
"got": "11.8.2",
"json-schema-to-typescript": "12.0.0",
"otplib": "12.0.1",
+ "phone-number-generator-js": "^1.2.12",
"process": "0.11.10",
"typescript": "4.7.4",
"wait-on": "7.0.1",
@@ -99,9 +101,9 @@
}
},
"node_modules/@faker-js/faker": {
- "version": "8.4.1",
- "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz",
- "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==",
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.0.3.tgz",
+ "integrity": "sha512-lWrrK4QNlFSU+13PL9jMbMKLJYXDFu3tQfayBsMXX7KL/GiQeqfB1CzHkqD5UHBUtPAuPo6XwGbMFNdVMZObRA==",
"funding": [
{
"type": "opencollective",
@@ -110,8 +112,8 @@
],
"license": "MIT",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0",
- "npm": ">=6.14.13"
+ "node": ">=18.0.0",
+ "npm": ">=9.0.0"
}
},
"node_modules/@hapi/hoek": {
@@ -329,6 +331,15 @@
"integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
"dev": true
},
+ "node_modules/@types/promise-retry": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@types/promise-retry/-/promise-retry-1.1.6.tgz",
+ "integrity": "sha512-EC1+OMXV0PZb0pf+cmyxc43MEP2CDumZe4AfuxWboxxEixztIebknpJPZAX5XlodGF1OY+C1E/RAeNGzxf+bJA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/retry": "*"
+ }
+ },
"node_modules/@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
@@ -341,8 +352,7 @@
"node_modules/@types/retry": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz",
- "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==",
- "dev": true
+ "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow=="
},
"node_modules/@types/sinonjs__fake-timers": {
"version": "8.1.1",
@@ -356,6 +366,13 @@
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
"dev": true
},
+ "node_modules/@types/validator": {
+ "version": "13.12.2",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz",
+ "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/yamljs": {
"version": "0.2.31",
"resolved": "https://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.31.tgz",
@@ -540,9 +557,9 @@
"dev": true
},
"node_modules/axios": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
- "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
+ "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -780,6 +797,25 @@
"integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==",
"dev": true
},
+ "node_modules/class-validator": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz",
+ "integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/validator": "^13.11.8",
+ "libphonenumber-js": "^1.10.53",
+ "validator": "^13.9.0"
+ }
+ },
+ "node_modules/class-validator/node_modules/libphonenumber-js": {
+ "version": "1.11.9",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.9.tgz",
+ "integrity": "sha512-Zs5wf5HaWzW2/inlupe2tstl0I/Tbqo7lH20ZLr6Is58u7Dz2n+gRFGNlj9/gWxFvNfp9+YyDsiegjNhdixB9A==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -1158,14 +1194,16 @@
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="
},
"node_modules/es5-ext": {
- "version": "0.10.62",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
- "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+ "version": "0.10.64",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
+ "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"dev": true,
"hasInstallScript": true,
+ "license": "ISC",
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
+ "esniff": "^2.0.1",
"next-tick": "^1.1.0"
},
"engines": {
@@ -1214,6 +1252,29 @@
"node": ">=0.8.0"
}
},
+ "node_modules/esniff": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
+ "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.62",
+ "event-emitter": "^0.3.5",
+ "type": "^2.7.2"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esniff/node_modules/type": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",
+ "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
@@ -1966,6 +2027,13 @@
"node": "> 0.8"
}
},
+ "node_modules/libphonenumber-js": {
+ "version": "1.10.30",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.30.tgz",
+ "integrity": "sha512-PLGc+xfrQrkya/YK2/5X+bPpxRmyJBHM+xxz9krUdSgk4Vs2ZwxX5/Ow0lv3r9PDlDtNWb4u+it8MY5rZ0IyGw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/listr2": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
@@ -2365,6 +2433,18 @@
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"dev": true
},
+ "node_modules/phone-number-generator-js": {
+ "version": "1.2.12",
+ "resolved": "https://registry.npmjs.org/phone-number-generator-js/-/phone-number-generator-js-1.2.12.tgz",
+ "integrity": "sha512-AtJpQjHFlXqD2ZMZLUlzrNKNTwwyn9gFASeTgfcGqdWUUHsddThKkCbsJ7VyDyj7C2Xo0oce/XOARH8eElas6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "class-validator": "0.14.1",
+ "libphonenumber-js": "1.10.30",
+ "lodash": "4.17.21"
+ }
+ },
"node_modules/pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
@@ -2446,6 +2526,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
"integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+ "license": "MIT",
"dependencies": {
"err-code": "^2.0.2",
"retry": "^0.12.0"
@@ -2964,6 +3045,16 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/validator": {
+ "version": "13.12.0",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
+ "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -3060,10 +3151,11 @@
"dev": true
},
"node_modules/ws": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
- "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8.3.0"
},
@@ -3172,9 +3264,9 @@
}
},
"@faker-js/faker": {
- "version": "8.4.1",
- "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz",
- "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg=="
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.0.3.tgz",
+ "integrity": "sha512-lWrrK4QNlFSU+13PL9jMbMKLJYXDFu3tQfayBsMXX7KL/GiQeqfB1CzHkqD5UHBUtPAuPo6XwGbMFNdVMZObRA=="
},
"@hapi/hoek": {
"version": "9.3.0",
@@ -3374,6 +3466,14 @@
"integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
"dev": true
},
+ "@types/promise-retry": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@types/promise-retry/-/promise-retry-1.1.6.tgz",
+ "integrity": "sha512-EC1+OMXV0PZb0pf+cmyxc43MEP2CDumZe4AfuxWboxxEixztIebknpJPZAX5XlodGF1OY+C1E/RAeNGzxf+bJA==",
+ "requires": {
+ "@types/retry": "*"
+ }
+ },
"@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
@@ -3386,8 +3486,7 @@
"@types/retry": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz",
- "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==",
- "dev": true
+ "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow=="
},
"@types/sinonjs__fake-timers": {
"version": "8.1.1",
@@ -3401,6 +3500,12 @@
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
"dev": true
},
+ "@types/validator": {
+ "version": "13.12.2",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz",
+ "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==",
+ "dev": true
+ },
"@types/yamljs": {
"version": "0.2.31",
"resolved": "https://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.31.tgz",
@@ -3538,9 +3643,9 @@
"dev": true
},
"axios": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
- "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
+ "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dev": true,
"requires": {
"follow-redirects": "^1.15.6",
@@ -3718,6 +3823,25 @@
"integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==",
"dev": true
},
+ "class-validator": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz",
+ "integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==",
+ "dev": true,
+ "requires": {
+ "@types/validator": "^13.11.8",
+ "libphonenumber-js": "^1.10.53",
+ "validator": "^13.9.0"
+ },
+ "dependencies": {
+ "libphonenumber-js": {
+ "version": "1.11.9",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.9.tgz",
+ "integrity": "sha512-Zs5wf5HaWzW2/inlupe2tstl0I/Tbqo7lH20ZLr6Is58u7Dz2n+gRFGNlj9/gWxFvNfp9+YyDsiegjNhdixB9A==",
+ "dev": true
+ }
+ }
+ },
"clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -4020,13 +4144,14 @@
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="
},
"es5-ext": {
- "version": "0.10.62",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
- "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+ "version": "0.10.64",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
+ "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"dev": true,
"requires": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
+ "esniff": "^2.0.1",
"next-tick": "^1.1.0"
}
},
@@ -4069,6 +4194,26 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
+ "esniff": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
+ "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
+ "dev": true,
+ "requires": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.62",
+ "event-emitter": "^0.3.5",
+ "type": "^2.7.2"
+ },
+ "dependencies": {
+ "type": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",
+ "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==",
+ "dev": true
+ }
+ }
+ },
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
@@ -4624,6 +4769,12 @@
"integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=",
"dev": true
},
+ "libphonenumber-js": {
+ "version": "1.10.30",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.30.tgz",
+ "integrity": "sha512-PLGc+xfrQrkya/YK2/5X+bPpxRmyJBHM+xxz9krUdSgk4Vs2ZwxX5/Ow0lv3r9PDlDtNWb4u+it8MY5rZ0IyGw==",
+ "dev": true
+ },
"listr2": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
@@ -4924,6 +5075,17 @@
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"dev": true
},
+ "phone-number-generator-js": {
+ "version": "1.2.12",
+ "resolved": "https://registry.npmjs.org/phone-number-generator-js/-/phone-number-generator-js-1.2.12.tgz",
+ "integrity": "sha512-AtJpQjHFlXqD2ZMZLUlzrNKNTwwyn9gFASeTgfcGqdWUUHsddThKkCbsJ7VyDyj7C2Xo0oce/XOARH8eElas6A==",
+ "dev": true,
+ "requires": {
+ "class-validator": "0.14.1",
+ "libphonenumber-js": "1.10.30",
+ "lodash": "4.17.21"
+ }
+ },
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
@@ -5362,6 +5524,12 @@
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
},
+ "validator": {
+ "version": "13.12.0",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
+ "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
+ "dev": true
+ },
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -5436,9 +5604,9 @@
"dev": true
},
"ws": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
- "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
"requires": {}
},
diff --git a/test/e2e/package.json b/test/e2e/package.json
index 05b04db6880a..a33ac330bf00 100644
--- a/test/e2e/package.json
+++ b/test/e2e/package.json
@@ -11,7 +11,8 @@
"wait-on": "wait-on"
},
"dependencies": {
- "@faker-js/faker": "8.4.1",
+ "@faker-js/faker": "9.0.3",
+ "@types/promise-retry": "^1.1.6",
"async-retry": "1.3.3",
"mailhog": "4.16.0",
"promise-retry": "^2.0.1"
@@ -29,6 +30,7 @@
"got": "11.8.2",
"json-schema-to-typescript": "12.0.0",
"otplib": "12.0.1",
+ "phone-number-generator-js": "^1.2.12",
"process": "0.11.10",
"typescript": "4.7.4",
"wait-on": "7.0.1",
diff --git a/test/e2e/playwright.config.ts b/test/e2e/playwright.config.ts
index a3f81c73060d..2ace64395520 100644
--- a/test/e2e/playwright.config.ts
+++ b/test/e2e/playwright.config.ts
@@ -65,6 +65,12 @@ export default defineConfig({
reuseExistingServer: false,
url: "http://localhost:8025/",
},
+ {
+ command: "go run test/e2e/mock/httptarget/main.go",
+ cwd: "../..",
+ reuseExistingServer: false,
+ url: "http://localhost:4471/health",
+ },
],
})
diff --git a/test/e2e/playwright/actions/identity.ts b/test/e2e/playwright/actions/identity.ts
new file mode 100644
index 000000000000..f05bc2f68a3e
--- /dev/null
+++ b/test/e2e/playwright/actions/identity.ts
@@ -0,0 +1,61 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { faker } from "@faker-js/faker"
+import { APIRequestContext } from "@playwright/test"
+import { CreateIdentityBody } from "@ory/kratos-client"
+import { generatePhoneNumber, CountryNames } from "phone-number-generator-js"
+import { expect } from "../fixtures"
+
+export async function createIdentity(
+ request: APIRequestContext,
+ data: Partial,
+) {
+ const resp = await request.post("http://localhost:4434/admin/identities", {
+ data,
+ })
+ expect(resp.status()).toBe(201)
+ return await resp.json()
+}
+
+export async function createIdentityWithPhoneNumber(
+ request: APIRequestContext,
+) {
+ const phone = generatePhoneNumber({
+ countryName: CountryNames.Germany,
+ withoutCountryCode: false,
+ })
+ return {
+ identity: await createIdentity(request, {
+ schema_id: "sms",
+ traits: {
+ phone,
+ },
+ }),
+ phone,
+ }
+}
+
+export async function createIdentityWithPassword(request: APIRequestContext) {
+ const email = faker.internet.email({ provider: "ory.sh" })
+ const password = faker.internet.password()
+ return {
+ identity: await createIdentity(request, {
+ schema_id: "email",
+ traits: {
+ email,
+ website: faker.internet.url(),
+ },
+
+ credentials: {
+ password: {
+ config: {
+ password,
+ },
+ },
+ },
+ }),
+ email,
+ password,
+ }
+}
diff --git a/test/e2e/playwright/actions/webhook.ts b/test/e2e/playwright/actions/webhook.ts
new file mode 100644
index 000000000000..82b2511d5d90
--- /dev/null
+++ b/test/e2e/playwright/actions/webhook.ts
@@ -0,0 +1,57 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { request } from "@playwright/test"
+import retry from "promise-retry"
+import { retryOptions } from "../lib/config"
+
+export const WEBHOOK_TARGET = "http://127.0.0.1:4471"
+
+const baseUrl = WEBHOOK_TARGET
+
+/**
+ * Fetches a documented (hopefully) created by web hook
+ *
+ * @param key
+ */
+export async function fetchDocument(key: string) {
+ const r = await request.newContext()
+
+ return retry(async (retry) => {
+ const res = await r.get(documentUrl(key))
+ if (res.status() !== 200) {
+ const body = await res.text()
+ const message = `Expected response code 200 but received ${res.status()}: ${body}`
+ return retry(message)
+ }
+ return await res.json()
+ }, retryOptions)
+}
+
+/**
+ * Fetches a documented (hopefully) created by web hook
+ *
+ * @param key
+ */
+export async function deleteDocument(key: string) {
+ const r = await request.newContext()
+
+ return retry(async (retry) => {
+ const res = await r.delete(documentUrl(key))
+ if (res.status() !== 204) {
+ const body = await res.text()
+ const message = `Expected response code 204 but received ${res.status()}: ${body}`
+ return retry(message)
+ }
+ return
+ }, retryOptions)
+}
+
+/**
+ * Returns the URL for a specific document
+ *
+ * @param key
+ */
+export function documentUrl(key: string) {
+ return `${baseUrl}/documents/${key}`
+}
diff --git a/test/e2e/playwright/fixtures/index.ts b/test/e2e/playwright/fixtures/index.ts
index b915dd4d937f..7f227ac7b5ee 100644
--- a/test/e2e/playwright/fixtures/index.ts
+++ b/test/e2e/playwright/fixtures/index.ts
@@ -1,14 +1,13 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
-import { faker } from "@faker-js/faker"
import { Identity } from "@ory/kratos-client"
import {
+ APIRequestContext,
CDPSession,
- test as base,
expect as baseExpect,
- APIRequestContext,
Page,
+ test as base,
} from "@playwright/test"
import { writeFile } from "fs/promises"
import { merge } from "lodash"
@@ -19,6 +18,7 @@ import { SessionWithResponse } from "../types"
import { retryOptions } from "../lib/request"
import promiseRetry from "promise-retry"
import { Protocol } from "playwright-core/types/protocol"
+import { createIdentityWithPassword } from "../actions/identity"
// from https://stackoverflow.com/questions/61132262/typescript-deep-partial
type DeepPartial = T extends object
@@ -104,31 +104,15 @@ export const test = base.extend({
await pageCDPSession.send("WebAuthn.disable")
},
identity: async ({ request }, use, i) => {
- const email = faker.internet.email({ provider: "ory.sh" })
- const password = faker.internet.password()
- const resp = await request.post("http://localhost:4434/admin/identities", {
- data: {
- schema_id: "email",
- traits: {
- email,
- website: faker.internet.url(),
- },
-
- credentials: {
- password: {
- config: {
- password,
- },
- },
- },
- },
- })
- const oryIdentity = await resp.json()
+ const {
+ identity: oryIdentity,
+ password,
+ email,
+ } = await createIdentityWithPassword(request)
i.attach("identity", {
body: JSON.stringify(oryIdentity, null, 2),
contentType: "application/json",
})
- expect(resp.status()).toBe(201)
await use({
oryIdentity,
email,
diff --git a/test/e2e/playwright/fixtures/schemas/sms.ts b/test/e2e/playwright/fixtures/schemas/sms.ts
new file mode 100644
index 000000000000..0e5186633dfb
--- /dev/null
+++ b/test/e2e/playwright/fixtures/schemas/sms.ts
@@ -0,0 +1,35 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+export default {
+ $id: "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json",
+ $schema: "http://json-schema.org/draft-07/schema#",
+ title: "Person",
+ type: "object",
+ properties: {
+ traits: {
+ type: "object",
+ properties: {
+ phone: {
+ type: "string",
+ format: "tel",
+ title: "Your Phone Number",
+ minLength: 3,
+ "ory.sh/kratos": {
+ credentials: {
+ code: {
+ identifier: true,
+ via: "sms",
+ },
+ },
+ verification: {
+ via: "sms",
+ },
+ },
+ },
+ },
+ required: ["phone"],
+ additionalProperties: false,
+ },
+ },
+}
diff --git a/test/e2e/playwright/lib/config.ts b/test/e2e/playwright/lib/config.ts
new file mode 100644
index 000000000000..4584d51f746e
--- /dev/null
+++ b/test/e2e/playwright/lib/config.ts
@@ -0,0 +1,14 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import type { OperationOptions } from "retry"
+
+export type RetryOptions = OperationOptions
+
+export const retryOptions: RetryOptions = {
+ retries: 20,
+ factor: 1,
+ maxTimeout: 500,
+ minTimeout: 250,
+ randomize: false,
+}
diff --git a/test/e2e/playwright/models/elements/registration.ts b/test/e2e/playwright/models/elements/registration.ts
new file mode 100644
index 000000000000..029903f14e49
--- /dev/null
+++ b/test/e2e/playwright/models/elements/registration.ts
@@ -0,0 +1,45 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { expect, Page } from "@playwright/test"
+import { createInputLocator, InputLocator } from "../../selectors/input"
+import { OryKratosConfiguration } from "../../../shared/config"
+
+export class RegistrationPage {
+ public identifier: InputLocator
+
+ constructor(readonly page: Page, readonly config: OryKratosConfiguration) {
+ this.identifier = createInputLocator(page, "identifier")
+ }
+
+ async open() {
+ await Promise.all([
+ this.page.goto(this.config.selfservice.flows.registration.ui_url),
+ this.isReady(),
+ this.page.waitForURL((url) =>
+ url
+ .toString()
+ .includes(this.config.selfservice.flows.registration.ui_url),
+ ),
+ ])
+ await this.isReady()
+ }
+
+ inputField(name: string) {
+ return this.page.locator(`input[name="${name}"]`)
+ }
+
+ submitField(name: string) {
+ return this.page.locator(`[type="submit"][name="method"][value="${name}"]`)
+ }
+
+ async isReady() {
+ await expect(this.inputField("csrf_token").nth(0)).toBeHidden()
+ }
+
+ async triggerRegistrationWithCode(identifier: string) {
+ await this.inputField("traits.phone").fill(identifier)
+ await this.submitField("profile").click()
+ await this.submitField("code").click()
+ }
+}
diff --git a/test/e2e/playwright/tests/desktop/code/sms.spec.ts b/test/e2e/playwright/tests/desktop/code/sms.spec.ts
new file mode 100644
index 000000000000..8d374c2ce1b7
--- /dev/null
+++ b/test/e2e/playwright/tests/desktop/code/sms.spec.ts
@@ -0,0 +1,116 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { test } from "../../../fixtures"
+import { toConfig } from "../../../lib/helper"
+import smsSchema from "../../../fixtures/schemas/sms"
+import { LoginPage } from "../../../models/elements/login"
+import { hasSession } from "../../../actions/session"
+import { createIdentityWithPhoneNumber } from "../../../actions/identity"
+import {
+ deleteDocument,
+ documentUrl,
+ fetchDocument,
+} from "../../../actions/webhook"
+import { RegistrationPage } from "../../../models/elements/registration"
+import { CountryNames, generatePhoneNumber } from "phone-number-generator-js"
+
+const documentId = "doc-" + Math.random().toString(36).substring(7)
+
+test.describe("account enumeration protection off", () => {
+ test.use({
+ configOverride: {
+ security: {
+ account_enumeration: {
+ enabled: false,
+ },
+ },
+ selfservice: {
+ flows: {
+ login: {
+ style: "unified",
+ },
+ registration: {
+ after: {
+ code: {
+ hooks: [
+ {
+ hook: "session",
+ },
+ ],
+ },
+ },
+ },
+ },
+ methods: {
+ code: {
+ passwordless_enabled: true,
+ },
+ password: {
+ enabled: false,
+ },
+ },
+ },
+ courier: {
+ channels: [
+ {
+ id: "sms",
+ type: "http",
+ request_config: {
+ body: "base64://ZnVuY3Rpb24oY3R4KSB7DQpjdHg6IGN0eCwNCn0=",
+ method: "PUT",
+ url: documentUrl(documentId),
+ },
+ },
+ ],
+ },
+ identity: {
+ default_schema_id: "sms",
+ schemas: [
+ {
+ id: "sms",
+ url:
+ "base64://" +
+ Buffer.from(JSON.stringify(smsSchema), "ascii").toString(
+ "base64",
+ ),
+ },
+ ],
+ },
+ },
+ })
+
+ test.afterEach(async () => {
+ await deleteDocument(documentId)
+ })
+
+ test("login succeeds", async ({ page, config, kratosPublicURL }) => {
+ const identity = await createIdentityWithPhoneNumber(page.request)
+
+ const login = new LoginPage(page, config)
+ await login.open()
+ await login.triggerLoginWithCode(identity.phone)
+
+ const result = await fetchDocument(documentId)
+ await login.codeInput.input.fill(result.ctx.template_data.login_code)
+ await login.codeSubmit.getByText("Continue").click()
+ await hasSession(page.request, kratosPublicURL)
+ })
+
+ test("registration succeeds", async ({ page, config, kratosPublicURL }) => {
+ const phone = generatePhoneNumber({
+ countryName: CountryNames.Germany,
+ withoutCountryCode: false,
+ })
+
+ const registration = new RegistrationPage(page, config)
+ await registration.open()
+ await registration.triggerRegistrationWithCode(phone)
+
+ const result = await fetchDocument(documentId)
+ const code = result.ctx.template_data.registration_code
+ await registration.inputField("code").fill(code)
+ await registration.submitField("code").getByText("Continue").click()
+ await hasSession(page.request, kratosPublicURL)
+ })
+})
diff --git a/text/id.go b/text/id.go
index 3d9028af8ed0..c6d26323f5e2 100644
--- a/text/id.go
+++ b/text/id.go
@@ -23,7 +23,7 @@ const (
InfoSelfServiceLoginContinueWebAuthn // 1010011
InfoSelfServiceLoginWebAuthnPasswordless // 1010012
InfoSelfServiceLoginContinue // 1010013
- InfoSelfServiceLoginEmailWithCodeSent // 1010014
+ InfoSelfServiceLoginCodeSent // 1010014
InfoSelfServiceLoginCode // 1010015
InfoSelfServiceLoginLink // 1010016
InfoSelfServiceLoginAndLink // 1010017
diff --git a/text/message_login.go b/text/message_login.go
index f5ebc54d9899..f60761f49e69 100644
--- a/text/message_login.go
+++ b/text/message_login.go
@@ -224,11 +224,11 @@ func NewInfoSelfServiceLoginContinue() *Message {
}
}
-func NewLoginEmailWithCodeSent() *Message {
+func NewLoginCodeSent() *Message {
return &Message{
- ID: InfoSelfServiceLoginEmailWithCodeSent,
+ ID: InfoSelfServiceLoginCodeSent,
Type: Info,
- Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the login.",
+ Text: "A code has been sent to the address you provided. If you have not received an message, check the spelling of the address and retry the login.",
}
}
diff --git a/text/message_registration.go b/text/message_registration.go
index 443d234cfda7..5249f21e3b8b 100644
--- a/text/message_registration.go
+++ b/text/message_registration.go
@@ -84,7 +84,7 @@ func NewRegistrationEmailWithCodeSent() *Message {
return &Message{
ID: InfoSelfServiceRegistrationEmailWithCodeSent,
Type: Info,
- Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the registration.",
+ Text: "A code has been sent to the address(es) you provided. If you have not received a message, check the spelling of the address and retry the registration.",
}
}