snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
59
courier/template/sms/authenticator_key_added.go
Normal file
59
courier/template/sms/authenticator_key_added.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright © 2026 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/ory/kratos/courier/template"
|
||||
)
|
||||
|
||||
type (
|
||||
AuthenticatorKeyAdded struct {
|
||||
deps template.Dependencies
|
||||
model *AuthenticatorKeyAddedModel
|
||||
}
|
||||
AuthenticatorKeyAddedModel struct {
|
||||
To string `json:"to"`
|
||||
Identity map[string]any `json:"identity"`
|
||||
AddedAt string `json:"added_at"`
|
||||
TransientPayload map[string]any `json:"transient_payload"`
|
||||
UserRequestHeaders http.Header `json:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewAuthenticatorKeyAdded(d template.Dependencies, m *AuthenticatorKeyAddedModel) *AuthenticatorKeyAdded {
|
||||
return &AuthenticatorKeyAdded{deps: d, model: m}
|
||||
}
|
||||
|
||||
func (t *AuthenticatorKeyAdded) PhoneNumber() (string, error) {
|
||||
return t.model.To, nil
|
||||
}
|
||||
|
||||
func (t *AuthenticatorKeyAdded) SMSBody(ctx context.Context) (string, error) {
|
||||
return template.LoadText(
|
||||
ctx,
|
||||
t.deps,
|
||||
os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)),
|
||||
"authenticator_key_added/sms.body.gotmpl",
|
||||
"authenticator_key_added/sms.body*",
|
||||
t.model,
|
||||
t.deps.CourierConfig().CourierSMSTemplatesAuthenticatorKeyAdded(ctx).Body.PlainText,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *AuthenticatorKeyAdded) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.model)
|
||||
}
|
||||
|
||||
func (t *AuthenticatorKeyAdded) TemplateType() template.TemplateType {
|
||||
return template.TypeAuthenticatorKeyAdded
|
||||
}
|
||||
|
||||
func (t *AuthenticatorKeyAdded) RequestHeaders() http.Header {
|
||||
return t.model.UserRequestHeaders
|
||||
}
|
||||
36
courier/template/sms/authenticator_key_added_test.go
Normal file
36
courier/template/sms/authenticator_key_added_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright © 2026 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ory/kratos/courier/template/sms"
|
||||
"github.com/ory/kratos/pkg"
|
||||
)
|
||||
|
||||
func TestAuthenticatorKeyAddedSMS(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
_, reg := pkg.NewFastRegistryWithMocks(t)
|
||||
|
||||
tpl := sms.NewAuthenticatorKeyAdded(reg, &sms.AuthenticatorKeyAddedModel{
|
||||
To: "+15551234567",
|
||||
AddedAt: "2026-04-21T12:00:00Z",
|
||||
Identity: map[string]any{"ID": "00000000-0000-0000-0000-000000000001"},
|
||||
})
|
||||
|
||||
phone, err := tpl.PhoneNumber()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "+15551234567", phone)
|
||||
|
||||
body, err := tpl.SMSBody(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Must stay under 160 chars so we do not fragment SMS billing.
|
||||
assert.LessOrEqual(t, len(body), 160, "SMS body too long: %q", body)
|
||||
assert.Contains(t, body, "sign-in method")
|
||||
}
|
||||
63
courier/template/sms/login_code_valid.go
Normal file
63
courier/template/sms/login_code_valid.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/ory/kratos/courier/template"
|
||||
)
|
||||
|
||||
type (
|
||||
LoginCodeValid struct {
|
||||
deps template.Dependencies
|
||||
model *LoginCodeValidModel
|
||||
}
|
||||
LoginCodeValidModel struct {
|
||||
To string `json:"to"`
|
||||
LoginCode string `json:"login_code"`
|
||||
Identity map[string]any `json:"identity"`
|
||||
RequestURL string `json:"request_url"`
|
||||
RequestURLDomain string `json:"request_url_domain"`
|
||||
TransientPayload map[string]any `json:"transient_payload"`
|
||||
ExpiresInMinutes int `json:"expires_in_minutes"`
|
||||
OAuth2LoginRequest *template.OAuth2LoginRequest `json:"oauth2_login_request,omitempty"`
|
||||
UserRequestHeaders http.Header `json:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewLoginCodeValid(d template.Dependencies, m *LoginCodeValidModel) *LoginCodeValid {
|
||||
return &LoginCodeValid{deps: d, model: m}
|
||||
}
|
||||
|
||||
func (t *LoginCodeValid) PhoneNumber() (string, error) {
|
||||
return t.model.To, nil
|
||||
}
|
||||
|
||||
func (t *LoginCodeValid) SMSBody(ctx context.Context) (string, error) {
|
||||
return template.LoadText(
|
||||
ctx,
|
||||
t.deps,
|
||||
os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)),
|
||||
"login_code/valid/sms.body.gotmpl",
|
||||
"login_code/valid/sms.body*",
|
||||
t.model,
|
||||
t.deps.CourierConfig().CourierSMSTemplatesLoginCodeValid(ctx).Body.PlainText,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *LoginCodeValid) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.model)
|
||||
}
|
||||
|
||||
func (t *LoginCodeValid) TemplateType() template.TemplateType {
|
||||
return template.TypeLoginCodeValid
|
||||
}
|
||||
|
||||
func (t *LoginCodeValid) RequestHeaders() http.Header {
|
||||
return t.model.UserRequestHeaders
|
||||
}
|
||||
36
courier/template/sms/login_code_valid_test.go
Normal file
36
courier/template/sms/login_code_valid_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ory/kratos/courier/template/sms"
|
||||
"github.com/ory/kratos/pkg"
|
||||
)
|
||||
|
||||
func TestNewLoginCodeValid(t *testing.T) {
|
||||
_, reg := pkg.NewFastRegistryWithMocks(t)
|
||||
|
||||
const (
|
||||
expectedPhone = "+12345678901"
|
||||
otp = "012345"
|
||||
)
|
||||
|
||||
tpl := sms.NewLoginCodeValid(reg, &sms.LoginCodeValidModel{To: expectedPhone, LoginCode: otp})
|
||||
|
||||
expectedBody := "Your login code is: 012345\n\nIt expires in 0 minutes.\n"
|
||||
|
||||
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)
|
||||
}
|
||||
43
courier/template/sms/origin_bound_test.go
Normal file
43
courier/template/sms/origin_bound_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright © 2026 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ory/kratos/courier/template/sms"
|
||||
"github.com/ory/kratos/pkg"
|
||||
)
|
||||
|
||||
// TestOriginBoundSMSBodies asserts that the login, registration, and
|
||||
// verification code SMS bodies include the Web OTP origin-bound last line
|
||||
// `@<domain> #<code>`, mirroring the recovery code template.
|
||||
func TestOriginBoundSMSBodies(t *testing.T) {
|
||||
_, reg := pkg.NewFastRegistryWithMocks(t)
|
||||
|
||||
t.Run("template=login_code", func(t *testing.T) {
|
||||
body, err := sms.NewLoginCodeValid(reg, &sms.LoginCodeValidModel{LoginCode: "012345", RequestURLDomain: "auth.example.com"}).SMSBody(t.Context())
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasSuffix(strings.TrimRight(body, "\n"), "@auth.example.com #012345"),
|
||||
"body must end with the origin-bound line, got: %q", body)
|
||||
})
|
||||
|
||||
t.Run("template=registration_code", func(t *testing.T) {
|
||||
body, err := sms.NewRegistrationCodeValid(reg, &sms.RegistrationCodeValidModel{RegistrationCode: "012345", RequestURLDomain: "auth.example.com"}).SMSBody(t.Context())
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasSuffix(strings.TrimRight(body, "\n"), "@auth.example.com #012345"),
|
||||
"body must end with the origin-bound line, got: %q", body)
|
||||
})
|
||||
|
||||
t.Run("template=verification_code", func(t *testing.T) {
|
||||
body, err := sms.NewVerificationCodeValid(reg, &sms.VerificationCodeValidModel{VerificationCode: "012345", RequestURLDomain: "auth.example.com"}).SMSBody(t.Context())
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasSuffix(strings.TrimRight(body, "\n"), "@auth.example.com #012345"),
|
||||
"body must end with the origin-bound line, got: %q", body)
|
||||
})
|
||||
}
|
||||
62
courier/template/sms/recovery_code.go
Normal file
62
courier/template/sms/recovery_code.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright © 2025 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/ory/kratos/courier/template"
|
||||
)
|
||||
|
||||
type (
|
||||
RecoveryCodeValid struct {
|
||||
deps template.Dependencies
|
||||
model *RecoveryCodeValidModel
|
||||
}
|
||||
|
||||
RecoveryCodeValidModel struct {
|
||||
To string `json:"to"`
|
||||
RecoveryCode string `json:"verification_code"`
|
||||
Identity map[string]any `json:"identity"`
|
||||
RequestURL string `json:"request_url"`
|
||||
RequestURLDomain string `json:"request_url_domain"`
|
||||
TransientPayload map[string]any `json:"transient_payload"`
|
||||
ExpiresInMinutes int `json:"expires_in_minutes"`
|
||||
UserRequestHeaders http.Header `json:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewRecoveryCodeValid(d template.Dependencies, m *RecoveryCodeValidModel) *RecoveryCodeValid {
|
||||
return &RecoveryCodeValid{deps: d, model: m}
|
||||
}
|
||||
|
||||
func (t *RecoveryCodeValid) PhoneNumber() (string, error) {
|
||||
return t.model.To, nil
|
||||
}
|
||||
|
||||
func (t *RecoveryCodeValid) SMSBody(ctx context.Context) (string, error) {
|
||||
return template.LoadText(
|
||||
ctx,
|
||||
t.deps,
|
||||
os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)),
|
||||
"recovery_code/valid/sms.body.gotmpl",
|
||||
"recovery_code/valid/sms.body*",
|
||||
t.model,
|
||||
t.deps.CourierConfig().CourierSMSTemplatesRecoveryCodeValid(ctx).Body.PlainText,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *RecoveryCodeValid) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.model)
|
||||
}
|
||||
func (t *RecoveryCodeValid) TemplateType() template.TemplateType {
|
||||
return template.TypeRecoveryCodeValid
|
||||
}
|
||||
func (t *RecoveryCodeValid) RequestHeaders() http.Header {
|
||||
return t.model.UserRequestHeaders
|
||||
|
||||
}
|
||||
63
courier/template/sms/registration_code_valid.go
Normal file
63
courier/template/sms/registration_code_valid.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"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]any `json:"identity"`
|
||||
RequestURL string `json:"request_url"`
|
||||
RequestURLDomain string `json:"request_url_domain"`
|
||||
TransientPayload map[string]any `json:"transient_payload"`
|
||||
ExpiresInMinutes int `json:"expires_in_minutes"`
|
||||
OAuth2LoginRequest *template.OAuth2LoginRequest `json:"oauth2_login_request,omitempty"`
|
||||
UserRequestHeaders http.Header `json:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (t *RegistrationCodeValid) RequestHeaders() http.Header {
|
||||
return t.model.UserRequestHeaders
|
||||
}
|
||||
36
courier/template/sms/registration_code_valid_test.go
Normal file
36
courier/template/sms/registration_code_valid_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ory/kratos/courier/template/sms"
|
||||
"github.com/ory/kratos/pkg"
|
||||
)
|
||||
|
||||
func TestNewRegistrationCodeValid(t *testing.T) {
|
||||
_, reg := pkg.NewFastRegistryWithMocks(t)
|
||||
|
||||
const (
|
||||
expectedPhone = "+12345678901"
|
||||
otp = "012345"
|
||||
)
|
||||
|
||||
tpl := sms.NewRegistrationCodeValid(reg, &sms.RegistrationCodeValidModel{To: expectedPhone, RegistrationCode: otp})
|
||||
|
||||
expectedBody := "Your registration code is: 012345\n\nIt expires in 0 minutes.\n"
|
||||
|
||||
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)
|
||||
}
|
||||
27
courier/template/sms/stub.go
Normal file
27
courier/template/sms/stub.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ory/kratos/courier/template"
|
||||
)
|
||||
|
||||
type (
|
||||
TestStub struct{ m *TestStubModel }
|
||||
|
||||
TestStubModel struct {
|
||||
To string `json:"to"`
|
||||
Body string `json:"body"`
|
||||
Identity map[string]interface{} `json:"identity"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewTestStub(m *TestStubModel) *TestStub { return &TestStub{m: m} }
|
||||
func (t *TestStub) PhoneNumber() (string, error) { return t.m.To, nil }
|
||||
func (t *TestStub) SMSBody(context.Context) (string, error) { return t.m.Body, nil }
|
||||
func (t *TestStub) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) }
|
||||
func (t *TestStub) TemplateType() template.TemplateType { return template.TypeTestStub }
|
||||
59
courier/template/sms/verifiable_address_changed.go
Normal file
59
courier/template/sms/verifiable_address_changed.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright © 2026 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/ory/kratos/courier/template"
|
||||
)
|
||||
|
||||
type (
|
||||
VerifiableAddressChanged struct {
|
||||
deps template.Dependencies
|
||||
model *VerifiableAddressChangedModel
|
||||
}
|
||||
VerifiableAddressChangedModel struct {
|
||||
To string `json:"to"`
|
||||
Identity map[string]any `json:"identity"`
|
||||
ChangedAt string `json:"changed_at"`
|
||||
TransientPayload map[string]any `json:"transient_payload"`
|
||||
UserRequestHeaders http.Header `json:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewVerifiableAddressChanged(d template.Dependencies, m *VerifiableAddressChangedModel) *VerifiableAddressChanged {
|
||||
return &VerifiableAddressChanged{deps: d, model: m}
|
||||
}
|
||||
|
||||
func (t *VerifiableAddressChanged) PhoneNumber() (string, error) {
|
||||
return t.model.To, nil
|
||||
}
|
||||
|
||||
func (t *VerifiableAddressChanged) SMSBody(ctx context.Context) (string, error) {
|
||||
return template.LoadText(
|
||||
ctx,
|
||||
t.deps,
|
||||
os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)),
|
||||
"verifiable_address_changed/sms.body.gotmpl",
|
||||
"verifiable_address_changed/sms.body*",
|
||||
t.model,
|
||||
t.deps.CourierConfig().CourierSMSTemplatesVerifiableAddressChanged(ctx).Body.PlainText,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *VerifiableAddressChanged) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.model)
|
||||
}
|
||||
|
||||
func (t *VerifiableAddressChanged) TemplateType() template.TemplateType {
|
||||
return template.TypeVerifiableAddressChanged
|
||||
}
|
||||
|
||||
func (t *VerifiableAddressChanged) RequestHeaders() http.Header {
|
||||
return t.model.UserRequestHeaders
|
||||
}
|
||||
37
courier/template/sms/verifiable_address_changed_test.go
Normal file
37
courier/template/sms/verifiable_address_changed_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright © 2026 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ory/kratos/courier/template/sms"
|
||||
"github.com/ory/kratos/pkg"
|
||||
)
|
||||
|
||||
func TestVerifiableAddressChangedSMS(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
_, reg := pkg.NewFastRegistryWithMocks(t)
|
||||
|
||||
tpl := sms.NewVerifiableAddressChanged(reg, &sms.VerifiableAddressChangedModel{
|
||||
To: "+15551234567",
|
||||
ChangedAt: "2026-04-21T12:00:00Z",
|
||||
Identity: map[string]any{"ID": "00000000-0000-0000-0000-000000000001"},
|
||||
})
|
||||
|
||||
phone, err := tpl.PhoneNumber()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "+15551234567", phone)
|
||||
|
||||
body, err := tpl.SMSBody(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Must stay under 160 chars so we do not fragment SMS billing.
|
||||
assert.LessOrEqual(t, len(body), 160, "SMS body too long: %q", body)
|
||||
assert.Contains(t, body, "changed")
|
||||
}
|
||||
58
courier/template/sms/verification_code.go
Normal file
58
courier/template/sms/verification_code.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/ory/kratos/courier/template"
|
||||
)
|
||||
|
||||
type (
|
||||
VerificationCodeValid struct {
|
||||
deps template.Dependencies
|
||||
model *VerificationCodeValidModel
|
||||
}
|
||||
|
||||
VerificationCodeValidModel struct {
|
||||
To string `json:"to"`
|
||||
VerificationCode string `json:"verification_code"`
|
||||
Identity map[string]any `json:"identity"`
|
||||
RequestURL string `json:"request_url"`
|
||||
RequestURLDomain string `json:"request_url_domain"`
|
||||
TransientPayload map[string]any `json:"transient_payload"`
|
||||
ExpiresInMinutes int `json:"expires_in_minutes"`
|
||||
OAuth2LoginRequest *template.OAuth2LoginRequest `json:"oauth2_login_request,omitempty"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewVerificationCodeValid(d template.Dependencies, m *VerificationCodeValidModel) *VerificationCodeValid {
|
||||
return &VerificationCodeValid{deps: d, model: m}
|
||||
}
|
||||
|
||||
func (t *VerificationCodeValid) PhoneNumber() (string, error) {
|
||||
return t.model.To, nil
|
||||
}
|
||||
|
||||
func (t *VerificationCodeValid) SMSBody(ctx context.Context) (string, error) {
|
||||
return template.LoadText(
|
||||
ctx,
|
||||
t.deps,
|
||||
os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)),
|
||||
"verification_code/valid/sms.body.gotmpl",
|
||||
"verification_code/valid/sms.body*",
|
||||
t.model,
|
||||
t.deps.CourierConfig().CourierSMSTemplatesVerificationCodeValid(ctx).Body.PlainText,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *VerificationCodeValid) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.model)
|
||||
}
|
||||
|
||||
func (t *VerificationCodeValid) TemplateType() template.TemplateType {
|
||||
return template.TypeVerificationCodeValid
|
||||
}
|
||||
36
courier/template/sms/verification_code_test.go
Normal file
36
courier/template/sms/verification_code_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sms_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ory/kratos/courier/template/sms"
|
||||
"github.com/ory/kratos/pkg"
|
||||
)
|
||||
|
||||
func TestNewOTPMessage(t *testing.T) {
|
||||
_, reg := pkg.NewFastRegistryWithMocks(t)
|
||||
|
||||
const (
|
||||
expectedPhone = "+12345678901"
|
||||
otp = "012345"
|
||||
)
|
||||
|
||||
tpl := sms.NewVerificationCodeValid(reg, &sms.VerificationCodeValidModel{To: expectedPhone, VerificationCode: otp})
|
||||
|
||||
expectedBody := "Your verification code is: 012345\n\nIf this was not you, do nothing. It expires in 0 minutes.\n"
|
||||
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user