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

This commit is contained in:
upstream-mirror
2026-09-15 21:19:12 +05:00
commit c60cc7ca75
8092 changed files with 394160 additions and 0 deletions

View 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
}

View 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")
}

View 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
}

View 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)
}

View 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)
})
}

View 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
}

View 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
}

View 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)
}

View 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 }

View 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
}

View 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")
}

View 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
}

View 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)
}