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,55 @@
// Copyright © 2026 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
AuthenticatorKeyAdded struct {
d template.Dependencies
m *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"`
}
)
func NewAuthenticatorKeyAdded(d template.Dependencies, m *AuthenticatorKeyAddedModel) *AuthenticatorKeyAdded {
return &AuthenticatorKeyAdded{d: d, m: m}
}
func (t *AuthenticatorKeyAdded) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *AuthenticatorKeyAdded) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "authenticator_key_added/email.subject.gotmpl", "authenticator_key_added/email.subject*", t.m, t.d.CourierConfig().CourierTemplatesAuthenticatorKeyAdded(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *AuthenticatorKeyAdded) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "authenticator_key_added/email.body.gotmpl", "authenticator_key_added/email.body*", t.m, t.d.CourierConfig().CourierTemplatesAuthenticatorKeyAdded(ctx).Body.HTML)
}
func (t *AuthenticatorKeyAdded) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "authenticator_key_added/email.body.plaintext.gotmpl", "authenticator_key_added/email.body.plaintext*", t.m, t.d.CourierConfig().CourierTemplatesAuthenticatorKeyAdded(ctx).Body.PlainText)
}
func (t *AuthenticatorKeyAdded) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *AuthenticatorKeyAdded) TemplateType() template.TemplateType {
return template.TypeAuthenticatorKeyAdded
}

View File

@@ -0,0 +1,55 @@
// Copyright © 2026 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"strings"
"testing"
"github.com/gofrs/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/identity"
"github.com/ory/kratos/pkg"
"github.com/ory/kratos/x"
)
func TestAuthenticatorKeyAdded(t *testing.T) {
ctx := t.Context()
_, reg := pkg.NewFastRegistryWithMocks(t)
// Build the Identity map exactly as the courier does in production
// (identity.Manager.sendIdentityNotifications uses x.StructToMap), so the
// template's key lookup is tested against the real key casing instead of a
// hand-crafted map. StructToMap marshals via JSON tags, so the ID lands under
// the lowercase "id" key.
id := &identity.Identity{ID: uuid.Must(uuid.FromString("00000000-0000-0000-0000-000000000001"))}
idMap, err := x.StructToMap(id)
require.NoError(t, err)
tpl := email.NewAuthenticatorKeyAdded(reg, &email.AuthenticatorKeyAddedModel{
To: "owner@example.com",
AddedAt: "2026-04-21T12:00:00Z",
Identity: idMap,
})
recipient, err := tpl.EmailRecipient()
require.NoError(t, err)
assert.Equal(t, "owner@example.com", recipient)
subject, err := tpl.EmailSubject(ctx)
require.NoError(t, err)
assert.Contains(t, strings.ToLower(subject), "sign-in method")
body, err := tpl.EmailBody(ctx)
require.NoError(t, err)
assert.Contains(t, body, "00000000-0000-0000-0000-000000000001", "the account ID must render in the email body")
plain, err := tpl.EmailBodyPlaintext(ctx)
require.NoError(t, err)
assert.Contains(t, plain, "00000000-0000-0000-0000-000000000001", "the account ID must render in the plaintext body")
assert.Contains(t, plain, "2026-04-21T12:00:00Z")
}

View File

@@ -0,0 +1,65 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"net/http"
"os"
"strings"
"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"`
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) EmailRecipient() (string, error) {
return t.model.To, nil
}
func (t *LoginCodeValid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "login_code/valid/email.subject.gotmpl", "login_code/valid/email.subject*", t.model, t.deps.CourierConfig().CourierTemplatesLoginCodeValid(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *LoginCodeValid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "login_code/valid/email.body.gotmpl", "login_code/valid/email.body*", t.model, t.deps.CourierConfig().CourierTemplatesLoginCodeValid(ctx).Body.HTML)
}
func (t *LoginCodeValid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "login_code/valid/email.body.plaintext.gotmpl", "login_code/valid/email.body.plaintext*", t.model, t.deps.CourierConfig().CourierTemplatesLoginCodeValid(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,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestLoginCodeValid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewLoginCodeValid(reg, &email.LoginCodeValidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/login_code/valid", template.TypeLoginCodeValid)
})
}

View File

@@ -0,0 +1,58 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
RecoveryCodeInvalid struct {
deps template.Dependencies
model *RecoveryCodeInvalidModel
}
RecoveryCodeInvalidModel struct {
To string `json:"to"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
}
)
func NewRecoveryCodeInvalid(d template.Dependencies, m *RecoveryCodeInvalidModel) *RecoveryCodeInvalid {
return &RecoveryCodeInvalid{deps: d, model: m}
}
func (t *RecoveryCodeInvalid) EmailRecipient() (string, error) {
return t.model.To, nil
}
func (t *RecoveryCodeInvalid) EmailSubject(ctx context.Context) (string, error) {
filesystem := os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx))
remoteURL := t.deps.CourierConfig().CourierTemplatesRecoveryCodeInvalid(ctx).Subject
subject, err := template.LoadText(ctx, t.deps, filesystem, "recovery_code/invalid/email.subject.gotmpl", "recovery_code/invalid/email.subject*", t.model, remoteURL)
return strings.TrimSpace(subject), err
}
func (t *RecoveryCodeInvalid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "recovery_code/invalid/email.body.gotmpl", "recovery_code/invalid/email.body*", t.model, t.deps.CourierConfig().CourierTemplatesRecoveryCodeInvalid(ctx).Body.HTML)
}
func (t *RecoveryCodeInvalid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "recovery_code/invalid/email.body.plaintext.gotmpl", "recovery_code/invalid/email.body.plaintext*", t.model, t.deps.CourierConfig().CourierTemplatesRecoveryCodeInvalid(ctx).Body.PlainText)
}
func (t *RecoveryCodeInvalid) MarshalJSON() ([]byte, error) {
return json.Marshal(t.model)
}
func (t *RecoveryCodeInvalid) TemplateType() template.TemplateType {
return template.TypeRecoveryCodeInvalid
}

View File

@@ -0,0 +1,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestRecoveryCodeInvalid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewRecoveryCodeInvalid(reg, &email.RecoveryCodeInvalidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("case=test remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery_code/invalid", template.TypeRecoveryCodeInvalid)
})
}

View File

@@ -0,0 +1,63 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"net/http"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
RecoveryCodeValid struct {
deps template.Dependencies
model *RecoveryCodeValidModel
}
RecoveryCodeValidModel struct {
To string `json:"to"`
RecoveryCode string `json:"recovery_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"`
UserRequestHeaders http.Header `json:"-"`
}
)
func NewRecoveryCodeValid(d template.Dependencies, m *RecoveryCodeValidModel) *RecoveryCodeValid {
return &RecoveryCodeValid{deps: d, model: m}
}
func (t *RecoveryCodeValid) EmailRecipient() (string, error) {
return t.model.To, nil
}
func (t *RecoveryCodeValid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "recovery_code/valid/email.subject.gotmpl", "recovery_code/valid/email.subject*", t.model, t.deps.CourierConfig().CourierTemplatesRecoveryCodeValid(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *RecoveryCodeValid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "recovery_code/valid/email.body.gotmpl", "recovery_code/valid/email.body*", t.model, t.deps.CourierConfig().CourierTemplatesRecoveryCodeValid(ctx).Body.HTML)
}
func (t *RecoveryCodeValid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "recovery_code/valid/email.body.plaintext.gotmpl", "recovery_code/valid/email.body.plaintext*", t.model, t.deps.CourierConfig().CourierTemplatesRecoveryCodeValid(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,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestRecoveryCodeValid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewRecoveryCodeValid(reg, &email.RecoveryCodeValidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery_code/valid", template.TypeRecoveryCodeValid)
})
}

View File

@@ -0,0 +1,55 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
RecoveryInvalid struct {
d template.Dependencies
m *RecoveryInvalidModel
}
RecoveryInvalidModel struct {
To string `json:"to"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
}
)
func NewRecoveryInvalid(d template.Dependencies, m *RecoveryInvalidModel) *RecoveryInvalid {
return &RecoveryInvalid{d: d, m: m}
}
func (t *RecoveryInvalid) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *RecoveryInvalid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "recovery/invalid/email.subject.gotmpl", "recovery/invalid/email.subject*", t.m, t.d.CourierConfig().CourierTemplatesRecoveryInvalid(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *RecoveryInvalid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "recovery/invalid/email.body.gotmpl", "recovery/invalid/email.body*", t.m, t.d.CourierConfig().CourierTemplatesRecoveryInvalid(ctx).Body.HTML)
}
func (t *RecoveryInvalid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "recovery/invalid/email.body.plaintext.gotmpl", "recovery/invalid/email.body.plaintext*", t.m, t.d.CourierConfig().CourierTemplatesRecoveryInvalid(ctx).Body.PlainText)
}
func (t *RecoveryInvalid) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *RecoveryInvalid) TemplateType() template.TemplateType {
return template.TypeRecoveryInvalid
}

View File

@@ -0,0 +1,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestRecoverInvalid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewRecoveryInvalid(reg, &email.RecoveryInvalidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("case=test remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery/invalid", template.TypeRecoveryInvalid)
})
}

View File

@@ -0,0 +1,58 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
RecoveryValid struct {
d template.Dependencies
m *RecoveryValidModel
}
RecoveryValidModel struct {
To string `json:"to"`
RecoveryURL string `json:"recovery_url"`
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 NewRecoveryValid(d template.Dependencies, m *RecoveryValidModel) *RecoveryValid {
return &RecoveryValid{d: d, m: m}
}
func (t *RecoveryValid) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *RecoveryValid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "recovery/valid/email.subject.gotmpl", "recovery/valid/email.subject*", t.m, t.d.CourierConfig().CourierTemplatesRecoveryValid(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *RecoveryValid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "recovery/valid/email.body.gotmpl", "recovery/valid/email.body*", t.m, t.d.CourierConfig().CourierTemplatesRecoveryValid(ctx).Body.HTML)
}
func (t *RecoveryValid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "recovery/valid/email.body.plaintext.gotmpl", "recovery/valid/email.body.plaintext*", t.m, t.d.CourierConfig().CourierTemplatesRecoveryValid(ctx).Body.PlainText)
}
func (t *RecoveryValid) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *RecoveryValid) TemplateType() template.TemplateType {
return template.TypeRecoveryValid
}

View File

@@ -0,0 +1,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestRecoverValid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewRecoveryValid(reg, &email.RecoveryValidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery/valid", template.TypeRecoveryValid)
})
}

View File

@@ -0,0 +1,65 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"net/http"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
RegistrationCodeValid struct {
deps template.Dependencies
model *RegistrationCodeValidModel
}
RegistrationCodeValidModel struct {
To string `json:"to"`
Traits map[string]any `json:"traits"`
RegistrationCode string `json:"registration_code"`
RequestURL string `json:"request_url"`
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) EmailRecipient() (string, error) {
return t.model.To, nil
}
func (t *RegistrationCodeValid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "registration_code/valid/email.subject.gotmpl", "registration_code/valid/email.subject*", t.model, t.deps.CourierConfig().CourierTemplatesRegistrationCodeValid(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *RegistrationCodeValid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "registration_code/valid/email.body.gotmpl", "registration_code/valid/email.body*", t.model, t.deps.CourierConfig().CourierTemplatesRegistrationCodeValid(ctx).Body.HTML)
}
func (t *RegistrationCodeValid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "registration_code/valid/email.body.plaintext.gotmpl", "registration_code/valid/email.body.plaintext*", t.model, t.deps.CourierConfig().CourierTemplatesRegistrationCodeValid(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,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestRegistrationCodeValid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewRegistrationCodeValid(reg, &email.RegistrationCodeValidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/registration_code/valid", template.TypeRegistrationCodeValid)
})
}

View File

@@ -0,0 +1,41 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"github.com/ory/kratos/courier/template"
)
type (
TestStub struct {
m *TestStubModel
}
TestStubModel struct {
To string `json:"to"`
Subject string `json:"subject"`
Body string `json:"body"`
HTMLBody string `json:"html_body,omitempty"`
}
)
func NewTestStub(m *TestStubModel) *TestStub {
return &TestStub{m: m}
}
func (t *TestStub) EmailRecipient() (string, error) { return t.m.To, nil }
func (t *TestStub) EmailSubject(context.Context) (string, error) { return t.m.Subject, nil }
func (t *TestStub) EmailBody(ctx context.Context) (string, error) {
if t.m.HTMLBody != "" {
return t.m.HTMLBody, nil
}
return t.EmailBodyPlaintext(ctx)
}
func (t *TestStub) EmailBodyPlaintext(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,55 @@
// Copyright © 2026 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
VerifiableAddressChanged struct {
d template.Dependencies
m *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"`
}
)
func NewVerifiableAddressChanged(d template.Dependencies, m *VerifiableAddressChangedModel) *VerifiableAddressChanged {
return &VerifiableAddressChanged{d: d, m: m}
}
func (t *VerifiableAddressChanged) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *VerifiableAddressChanged) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verifiable_address_changed/email.subject.gotmpl", "verifiable_address_changed/email.subject*", t.m, t.d.CourierConfig().CourierTemplatesVerifiableAddressChanged(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *VerifiableAddressChanged) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verifiable_address_changed/email.body.gotmpl", "verifiable_address_changed/email.body*", t.m, t.d.CourierConfig().CourierTemplatesVerifiableAddressChanged(ctx).Body.HTML)
}
func (t *VerifiableAddressChanged) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verifiable_address_changed/email.body.plaintext.gotmpl", "verifiable_address_changed/email.body.plaintext*", t.m, t.d.CourierConfig().CourierTemplatesVerifiableAddressChanged(ctx).Body.PlainText)
}
func (t *VerifiableAddressChanged) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *VerifiableAddressChanged) TemplateType() template.TemplateType {
return template.TypeVerifiableAddressChanged
}

View File

@@ -0,0 +1,44 @@
// Copyright © 2026 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/pkg"
)
func TestVerifiableAddressChanged(t *testing.T) {
ctx := context.Background()
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewVerifiableAddressChanged(reg, &email.VerifiableAddressChangedModel{
To: "old@example.com",
ChangedAt: "2026-04-21T12:00:00Z",
Identity: map[string]any{"ID": "00000000-0000-0000-0000-000000000001", "Traits": map[string]any{"email": "new@example.com"}},
})
recipient, err := tpl.EmailRecipient()
require.NoError(t, err)
assert.Equal(t, "old@example.com", recipient)
subject, err := tpl.EmailSubject(ctx)
require.NoError(t, err)
assert.Contains(t, strings.ToLower(subject), "address")
body, err := tpl.EmailBody(ctx)
require.NoError(t, err)
assert.Contains(t, body, "00000000-0000-0000-0000-000000000001")
plain, err := tpl.EmailBodyPlaintext(ctx)
require.NoError(t, err)
assert.Contains(t, plain, "00000000-0000-0000-0000-000000000001")
assert.Contains(t, plain, "2026-04-21T12:00:00Z")
}

View File

@@ -0,0 +1,79 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
VerificationCodeInvalid struct {
d template.Dependencies
m *VerificationCodeInvalidModel
}
VerificationCodeInvalidModel struct {
To string `json:"to"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
}
)
func NewVerificationCodeInvalid(d template.Dependencies, m *VerificationCodeInvalidModel) *VerificationCodeInvalid {
return &VerificationCodeInvalid{d: d, m: m}
}
func (t *VerificationCodeInvalid) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *VerificationCodeInvalid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(
ctx,
t.d,
os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)),
"verification_code/invalid/email.subject.gotmpl",
"verification_code/invalid/email.subject*",
t.m,
t.d.CourierConfig().CourierTemplatesVerificationCodeInvalid(ctx).Subject,
)
return strings.TrimSpace(subject), err
}
func (t *VerificationCodeInvalid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(
ctx,
t.d,
os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)),
"verification_code/invalid/email.body.gotmpl",
"verification_code/invalid/email.body*",
t.m,
t.d.CourierConfig().CourierTemplatesVerificationCodeInvalid(ctx).Body.HTML,
)
}
func (t *VerificationCodeInvalid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(
ctx,
t.d,
os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)),
"verification_code/invalid/email.body.plaintext.gotmpl",
"verification_code/invalid/email.body.plaintext*",
t.m,
t.d.CourierConfig().CourierTemplatesVerificationCodeInvalid(ctx).Body.PlainText,
)
}
func (t *VerificationCodeInvalid) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *VerificationCodeInvalid) TemplateType() template.TemplateType {
return template.TypeVerificationCodeInvalid
}

View File

@@ -0,0 +1,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestVerifyCodeInvalid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewVerificationCodeInvalid(reg, &email.VerificationCodeInvalidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification_code/invalid", template.TypeVerificationCodeInvalid)
})
}

View File

@@ -0,0 +1,82 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
VerificationCodeValid struct {
d template.Dependencies
m *VerificationCodeValidModel
}
VerificationCodeValidModel struct {
To string `json:"to"`
VerificationURL string `json:"verification_url"`
VerificationCode string `json:"verification_code"`
Identity map[string]any `json:"identity"`
RequestURL string `json:"request_url"`
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{d: d, m: m}
}
func (t *VerificationCodeValid) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *VerificationCodeValid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(
ctx,
t.d,
os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)),
"verification_code/valid/email.subject.gotmpl",
"verification_code/valid/email.subject*",
t.m,
t.d.CourierConfig().CourierTemplatesVerificationCodeValid(ctx).Subject,
)
return strings.TrimSpace(subject), err
}
func (t *VerificationCodeValid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx,
t.d,
os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)),
"verification_code/valid/email.body.gotmpl",
"verification_code/valid/email.body*",
t.m,
t.d.CourierConfig().CourierTemplatesVerificationCodeValid(ctx).Body.HTML,
)
}
func (t *VerificationCodeValid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx,
t.d,
os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)),
"verification_code/valid/email.body.plaintext.gotmpl",
"verification_code/valid/email.body.plaintext*",
t.m,
t.d.CourierConfig().CourierTemplatesVerificationCodeValid(ctx).Body.PlainText,
)
}
func (t *VerificationCodeValid) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *VerificationCodeValid) TemplateType() template.TemplateType {
return template.TypeVerificationCodeValid
}

View File

@@ -0,0 +1,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestVerifyCodeValid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewVerificationCodeValid(reg, &email.VerificationCodeValidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification_code/valid", template.TypeVerificationCodeValid)
})
}

View File

@@ -0,0 +1,55 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
VerificationInvalid struct {
d template.Dependencies
m *VerificationInvalidModel
}
VerificationInvalidModel struct {
To string `json:"to"`
RequestURL string `json:"request_url"`
TransientPayload map[string]interface{} `json:"transient_payload"`
}
)
func NewVerificationInvalid(d template.Dependencies, m *VerificationInvalidModel) *VerificationInvalid {
return &VerificationInvalid{d: d, m: m}
}
func (t *VerificationInvalid) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *VerificationInvalid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verification/invalid/email.subject.gotmpl", "verification/invalid/email.subject*", t.m, t.d.CourierConfig().CourierTemplatesVerificationInvalid(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *VerificationInvalid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verification/invalid/email.body.gotmpl", "verification/invalid/email.body*", t.m, t.d.CourierConfig().CourierTemplatesVerificationInvalid(ctx).Body.HTML)
}
func (t *VerificationInvalid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verification/invalid/email.body.plaintext.gotmpl", "verification/invalid/email.body.plaintext*", t.m, t.d.CourierConfig().CourierTemplatesVerificationInvalid(ctx).Body.PlainText)
}
func (t *VerificationInvalid) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *VerificationInvalid) TemplateType() template.TemplateType {
return template.TypeVerificationInvalid
}

View File

@@ -0,0 +1,32 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestVerifyInvalid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewVerificationInvalid(reg, &email.VerificationInvalidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification/invalid", template.TypeVerificationInvalid)
})
})
}

View File

@@ -0,0 +1,59 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email
import (
"context"
"encoding/json"
"os"
"strings"
"github.com/ory/kratos/courier/template"
)
type (
VerificationValid struct {
d template.Dependencies
m *VerificationValidModel
}
VerificationValidModel struct {
To string `json:"to"`
VerificationURL string `json:"verification_url"`
Identity map[string]any `json:"identity"`
RequestURL string `json:"request_url"`
TransientPayload map[string]any `json:"transient_payload"`
ExpiresInMinutes int `json:"expires_in_minutes"`
OAuth2LoginRequest *template.OAuth2LoginRequest `json:"oauth2_login_request,omitempty"`
}
)
func NewVerificationValid(d template.Dependencies, m *VerificationValidModel) *VerificationValid {
return &VerificationValid{d: d, m: m}
}
func (t *VerificationValid) EmailRecipient() (string, error) {
return t.m.To, nil
}
func (t *VerificationValid) EmailSubject(ctx context.Context) (string, error) {
subject, err := template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verification/valid/email.subject.gotmpl", "verification/valid/email.subject*", t.m, t.d.CourierConfig().CourierTemplatesVerificationValid(ctx).Subject)
return strings.TrimSpace(subject), err
}
func (t *VerificationValid) EmailBody(ctx context.Context) (string, error) {
return template.LoadHTML(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verification/valid/email.body.gotmpl", "verification/valid/email.body*", t.m, t.d.CourierConfig().CourierTemplatesVerificationValid(ctx).Body.HTML)
}
func (t *VerificationValid) EmailBodyPlaintext(ctx context.Context) (string, error) {
return template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "verification/valid/email.body.plaintext.gotmpl", "verification/valid/email.body.plaintext*", t.m, t.d.CourierConfig().CourierTemplatesVerificationValid(ctx).Body.PlainText)
}
func (t *VerificationValid) MarshalJSON() ([]byte, error) {
return json.Marshal(t.m)
}
func (t *VerificationValid) TemplateType() template.TemplateType {
return template.TypeVerificationValid
}

View File

@@ -0,0 +1,30 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package email_test
import (
"context"
"testing"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/testhelpers"
"github.com/ory/kratos/pkg"
)
func TestVerifyValid(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
t.Run("test=with courier templates directory", func(t *testing.T) {
_, reg := pkg.NewFastRegistryWithMocks(t)
tpl := email.NewVerificationValid(reg, &email.VerificationValidModel{})
testhelpers.TestRendered(t, ctx, tpl)
})
t.Run("test=with remote resources", func(t *testing.T) {
testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification/valid", template.TypeVerificationValid)
})
}