fix: rename "phone" courier channel to "sms" (#3680)

Co-authored-by: zepatrik <zepatrik@users.noreply.github.com>
This commit is contained in:
Jonas Hungershausen 2024-01-05 14:07:33 +01:00 committed by GitHub
parent 699e5d59a0
commit eb8d1b9abd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 325 additions and 131 deletions

View File

@ -19,7 +19,7 @@
}
},
"verification": {
"via": "phone"
"via": "sms"
}
}
}

View File

@ -96,11 +96,12 @@ identity:
courier:
channels:
- id: phone
- id: sms
type: http
request_config:
url: https://api.twilio.com/2010-04-01/Accounts/AXXXXXXXXXXXXXX/Messages.json
method: POST
body: base64://ZnVuY3Rpb24oY3R4KSB7CkJvZHk6IGN0eC5ib2R5LApUbzogY3R4LnRvLEZyb206IGN0eC5mcm9tCn0=
body: base64://ZnVuY3Rpb24oY3R4KSB7ClRvOiBjdHguUmVjaXBpZW50LApCb2R5OiBjdHguQm9keSwKfQ==
headers:
Content-Type: application/x-www-form-urlencoded
auth:

View File

@ -61,12 +61,12 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) {
builder, err := request.NewBuilder(ctx, c.requestConfig, c.d)
if err != nil {
return err
return errors.WithStack(err)
}
tmpl, err := newTemplate(c.d, msg)
if err != nil {
return err
return errors.WithStack(err)
}
td := httpDataModel{
@ -80,12 +80,12 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) {
req, err := builder.BuildRequest(ctx, td)
if err != nil {
return err
return errors.WithStack(err)
}
res, err := c.d.HTTPClient(ctx).Do(req)
if err != nil {
return err
return errors.WithStack(err)
}
if res.StatusCode >= 200 && res.StatusCode < 300 {
@ -109,7 +109,7 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) {
WithField("message_subject", msg.Subject).
WithError(err).
Error("sending mail via HTTP failed.")
return err
return errors.WithStack(err)
}
func newTemplate(d template.Dependencies, msg Message) (Template, error) {

View File

@ -1112,7 +1112,7 @@ func (p *Config) CourierTemplatesVerificationCodeValid(ctx context.Context) *Cou
}
func (p *Config) CourierSMSTemplatesVerificationCodeValid(ctx context.Context) *CourierSMSTemplate {
return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidEmail)
return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidSMS)
}
func (p *Config) CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate {

View File

@ -1999,7 +1999,13 @@
"title": "Channel id",
"description": "The channel id. Corresponds to the .via property of the identity schema for recovery, verification, etc. Currently only phone is supported.",
"maxLength": 32,
"enum": ["phone"]
"enum": ["sms"]
},
"type": {
"type": "string",
"title": "Channel type",
"description": "The channel type. Currently only http is supported.",
"enum": ["http"]
},
"request_config": {
"$ref": "#/definitions/httpRequestConfig"

View File

@ -5,15 +5,19 @@ package embedx
import (
"context"
"embed"
"io/fs"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
"github.com/ory/jsonschema/v3"
)
func TestAddSchemaResources(t *testing.T) {
for _, tc := range []struct {
description string
dependencies []SchemaType
@ -65,7 +69,38 @@ func TestAddSchemaResources(t *testing.T) {
assert.NoError(t, err)
}
}
})
}
}
//go:embed testdata/identity_meta.*
var identityMetaTestCases embed.FS
func TestIdentityMetaSchema(t *testing.T) {
c := jsonschema.NewCompiler()
err := AddSchemaResources(c, IdentityMeta, IdentityExtension)
require.NoError(t, err)
schema, err := c.Compile(context.Background(), IdentityMeta.GetSchemaID())
require.NoError(t, err)
require.NoError(t, fs.WalkDir(identityMetaTestCases, ".", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
return nil
}
t.Run("case="+path, func(t *testing.T) {
f, err := identityMetaTestCases.Open(path)
require.NoError(t, err)
err = schema.Validate(f)
if strings.HasSuffix(path, "invalid.schema.json") {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
return nil
}))
}

View File

@ -60,7 +60,7 @@
"properties": {
"via": {
"type": "string",
"enum": ["email", "phone"]
"enum": ["email", "sms"]
}
}
},

View File

@ -10,9 +10,7 @@
"properties": {
"properties": {
"type": "object",
"required": [
"traits"
],
"required": ["traits"],
"properties": {
"traits": {
"type": "object",
@ -27,6 +25,32 @@
"patternProperties": {
".*": {
"type": "object",
"if": {
"properties": {
"ory.sh/kratos": {
"type": "object",
"properties": {
"verification": {}
},
"required": ["verification"]
}
},
"required": ["ory.sh/kratos"]
},
"then": {
"properties": {
"format": {
"enum": [
"email",
"tel",
"date",
"time",
"date-time",
"no-validate"
]
}
}
},
"allOf": [
{
"$ref": "ory://identity-extension"
@ -40,9 +64,7 @@
}
}
},
"required": [
"properties"
]
"required": ["properties"]
}
]
}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,23 @@
{
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
"verification": {
"via": "email"
}
}
}
}
}
}
}

View File

@ -0,0 +1,23 @@
{
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "unknown",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
"verification": {
"via": "email"
}
}
}
}
}
}
}

View File

@ -5,5 +5,4 @@ package identity
const (
AddressTypeEmail = "email"
AddressTypePhone = "phone"
)

View File

@ -146,15 +146,6 @@ func ParseCredentialsType(in string) (CredentialsType, bool) {
return "", false
}
// swagger:ignore
type CredentialsIdentifierAddressType string
const (
CredentialsIdentifierAddressTypeEmail CredentialsIdentifierAddressType = AddressTypeEmail
CredentialsIdentifierAddressTypePhone CredentialsIdentifierAddressType = AddressTypePhone
CredentialsIdentifierAddressTypeNone CredentialsIdentifierAddressType = "none"
)
// Credentials represents a specific credential type
//
// swagger:model identityCredentials

View File

@ -11,7 +11,6 @@ type CodeAddressType string
const (
CodeAddressTypeEmail CodeAddressType = AddressTypeEmail
CodeAddressTypePhone CodeAddressType = AddressTypePhone
)
// CredentialsCode represents a one time login/registration code

View File

@ -26,7 +26,7 @@ func NewSchemaExtensionCredentials(i *Identity) *SchemaExtensionCredentials {
return &SchemaExtensionCredentials{i: i}
}
func (r *SchemaExtensionCredentials) setIdentifier(ct CredentialsType, value interface{}, addressType CredentialsIdentifierAddressType) {
func (r *SchemaExtensionCredentials) setIdentifier(ct CredentialsType, value interface{}) {
cred, ok := r.i.GetCredentials(ct)
if !ok {
cred = &Credentials{
@ -49,11 +49,11 @@ func (r *SchemaExtensionCredentials) Run(ctx jsonschema.ValidationContext, s sch
defer r.l.Unlock()
if s.Credentials.Password.Identifier {
r.setIdentifier(CredentialsTypePassword, value, CredentialsIdentifierAddressTypeNone)
r.setIdentifier(CredentialsTypePassword, value)
}
if s.Credentials.WebAuthn.Identifier {
r.setIdentifier(CredentialsTypeWebAuthn, value, CredentialsIdentifierAddressTypeNone)
r.setIdentifier(CredentialsTypeWebAuthn, value)
}
if s.Credentials.Code.Identifier {
@ -63,7 +63,7 @@ func (r *SchemaExtensionCredentials) Run(ctx jsonschema.ValidationContext, s sch
return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via)
}
r.setIdentifier(CredentialsTypeCodeAuth, value, CredentialsIdentifierAddressTypeEmail)
r.setIdentifier(CredentialsTypeCodeAuth, value)
// case f.AddCase(AddressTypePhone):
// if !jsonschema.Formats["tel"](value) {
// return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via)

View File

@ -9,10 +9,18 @@ import (
"sync"
"time"
"golang.org/x/exp/maps"
"github.com/ory/jsonschema/v3"
"github.com/ory/kratos/schema"
)
func init() {
jsonschema.Formats["no-validate"] = func(v interface{}) bool {
return true
}
}
type SchemaExtensionVerification struct {
lifespan time.Duration
l sync.Mutex
@ -24,40 +32,57 @@ func NewSchemaExtensionVerification(i *Identity, lifespan time.Duration) *Schema
return &SchemaExtensionVerification{i: i, lifespan: lifespan}
}
const (
ChannelTypeEmail = "email"
ChannelTypeSMS = "sms"
)
func (r *SchemaExtensionVerification) Run(ctx jsonschema.ValidationContext, s schema.ExtensionConfig, value interface{}) error {
r.l.Lock()
defer r.l.Unlock()
switch s.Verification.Via {
case AddressTypeEmail:
if !jsonschema.Formats["email"](value) {
return ctx.Error("format", "%q is not valid %q", value, "email")
}
address := NewVerifiableEmailAddress(
strings.ToLower(strings.TrimSpace(
fmt.Sprintf("%s", value))), r.i.ID)
r.appendAddress(address)
return nil
case AddressTypePhone:
if !jsonschema.Formats["tel"](value) {
return ctx.Error("format", "%q is not valid %q", value, "phone")
}
address := NewVerifiablePhoneAddress(fmt.Sprintf("%s", value), r.i.ID)
r.appendAddress(address)
return nil
case "":
if s.Verification.Via == "" {
return nil
}
return ctx.Error("", "verification.via has unknown value %q", s.Verification.Via)
format, ok := s.RawSchema["format"]
if !ok {
format = ""
}
formatString, ok := format.(string)
if !ok {
return nil
}
if formatString == "" {
switch s.Verification.Via {
case ChannelTypeEmail:
formatString = "email"
formatter, ok := jsonschema.Formats[formatString]
if !ok {
supportedKeys := maps.Keys(jsonschema.Formats)
return ctx.Error("format", "format %q is not supported. Supported formats are [%s]", formatString, strings.Join(supportedKeys, ", "))
}
if !formatter(value) {
return ctx.Error("format", "%q is not valid %q", value, formatString)
}
default:
return ctx.Error("format", "no format specified. A format is required if verification is enabled. If this was intentional, please set \"format\" to \"no-validate\"")
}
}
var normalized string
switch formatString {
case "email":
normalized = strings.ToLower(strings.TrimSpace(fmt.Sprintf("%s", value)))
default:
normalized = strings.TrimSpace(fmt.Sprintf("%s", value))
}
address := NewVerifiableAddress(normalized, r.i.ID, s.Verification.Via)
r.appendAddress(address)
return nil
}
func (r *SchemaExtensionVerification) Finish() error {

View File

@ -6,12 +6,13 @@ package identity
import (
"bytes"
"context"
"errors"
"fmt"
"net"
"reflect"
"testing"
"time"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -22,13 +23,17 @@ import (
)
const (
emailSchemaPath = "file://./stub/extension/verify/email.schema.json"
phoneSchemaPath = "file://./stub/extension/verify/phone.schema.json"
emailSchemaPath = "file://./stub/extension/verify/email.schema.json"
phoneSchemaPath = "file://./stub/extension/verify/phone.schema.json"
missingFormatSchemaPath = "file://./stub/extension/verify/missing-format.schema.json"
legacyEmailMissingFormatSchemaPath = "file://./stub/extension/verify/legacy-email-missing-format.schema.json"
noValidateSchemaPath = "file://./stub/extension/verify/no-validate.schema.json"
)
var ctx = context.Background()
func TestSchemaExtensionVerification(t *testing.T) {
net.IP{}.IsPrivate()
t.Run("address verification", func(t *testing.T) {
iid := x.NewUUID()
@ -194,7 +199,7 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+18004444444",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -208,7 +213,7 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+442087599036",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -217,7 +222,7 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+18004444444",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -231,14 +236,14 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+442087599036",
Verified: true,
Status: VerifiableAddressStatusCompleted,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
{
Value: "+380634872774",
Verified: true,
Status: VerifiableAddressStatusCompleted,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -247,14 +252,14 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+442087599036",
Verified: true,
Status: VerifiableAddressStatusCompleted,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
{
Value: "+18004444444",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -268,14 +273,14 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+18004444444",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
{
Value: "+380634872774",
Verified: true,
Status: VerifiableAddressStatusCompleted,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -284,14 +289,14 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+18004444444",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
{
Value: "+442087599036",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -305,21 +310,21 @@ func TestSchemaExtensionVerification(t *testing.T) {
Value: "+18004444444",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
{
Value: "+442087599036",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
{
Value: "+380634872774",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
@ -328,7 +333,41 @@ func TestSchemaExtensionVerification(t *testing.T) {
name: "phone:must return error for malformed input",
schema: phoneSchemaPath,
doc: `{"phones":["+18004444444","+18004444444","12112112"], "username": "+380634872774"}`,
expectErr: errors.New("I[#/phones/2] S[#/properties/phones/items/format] \"12112112\" is not valid \"phone\""),
expectErr: errors.New("I[#/phones/2] S[#/properties/phones/items/format] \"12112112\" is not valid \"tel\""),
},
{
name: "missing format returns an error",
schema: missingFormatSchemaPath,
doc: `{"phone": "+380634872774"}`,
expectErr: errors.New("I[#/phone] S[#/properties/phone/format] no format specified. A format is required if verification is enabled. If this was intentional, please set \"format\" to \"no-validate\""),
},
{
name: "missing format works for email if format is missing",
schema: legacyEmailMissingFormatSchemaPath,
doc: `{"email": "user@ory.sh"}`,
expect: []VerifiableAddress{
{
Value: "user@ory.sh",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: ChannelTypeEmail,
IdentityID: iid,
},
},
},
{
name: "format: no-validate works",
schema: noValidateSchemaPath,
doc: `{"phone": "not a phone number"}`,
expect: []VerifiableAddress{
{
Value: "not a phone number",
Verified: false,
Status: VerifiableAddressStatusPending,
Via: ChannelTypeSMS,
IdentityID: iid,
},
},
},
} {
t.Run(fmt.Sprintf("case=%v", tc.name), func(t *testing.T) {
@ -357,7 +396,6 @@ func TestSchemaExtensionVerification(t *testing.T) {
})
}
})
}
func mustContainAddress(t *testing.T, expected, actual []VerifiableAddress) {

View File

@ -15,7 +15,6 @@ import (
const (
VerifiableAddressTypeEmail VerifiableAddressType = AddressTypeEmail
VerifiableAddressTypePhone VerifiableAddressType = AddressTypePhone
VerifiableAddressStatusPending VerifiableAddressStatus = "pending"
VerifiableAddressStatusSent VerifiableAddressStatus = "sent"
@ -25,7 +24,7 @@ const (
// VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema
//
// swagger:model identityVerifiableAddressType
type VerifiableAddressType string
type VerifiableAddressType = string
// VerifiableAddressStatus must not exceed 16 characters as that is the limitation in the SQL Schema
//
@ -54,14 +53,14 @@ type VerifiableAddress struct {
// The delivery method
//
// enum: ["email"]
// enum: email,sms
// example: email
// required: true
Via VerifiableAddressType `json:"via" db:"via"`
Via string `json:"via" db:"via"`
// The verified address status
//
// enum: ["pending","sent","completed"]
// enum: pending,sent,completed
// example: sent
// required: true
Status VerifiableAddressStatus `json:"status" db:"status"`
@ -87,36 +86,20 @@ type VerifiableAddress struct {
NID uuid.UUID `json:"-" faker:"-" db:"nid"`
}
func (v VerifiableAddressType) HTMLFormInputType() string {
switch v {
case VerifiableAddressTypeEmail:
return "email"
case VerifiableAddressTypePhone:
return "phone"
}
return ""
}
func (a VerifiableAddress) TableName(ctx context.Context) string {
return "identity_verifiable_addresses"
}
func NewVerifiableEmailAddress(value string, identity uuid.UUID) *VerifiableAddress {
return &VerifiableAddress{
Value: value,
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypeEmail,
IdentityID: identity,
}
return NewVerifiableAddress(value, identity, VerifiableAddressTypeEmail)
}
func NewVerifiablePhoneAddress(value string, identity uuid.UUID) *VerifiableAddress {
func NewVerifiableAddress(value string, identity uuid.UUID, channel string) *VerifiableAddress {
return &VerifiableAddress{
Value: value,
Verified: false,
Status: VerifiableAddressStatusPending,
Via: VerifiableAddressTypePhone,
Via: channel,
IdentityID: identity,
}
}

View File

@ -39,7 +39,7 @@ type (
GetIdentity(context.Context, uuid.UUID, sqlxx.Expandables) (*Identity, error)
// FindVerifiableAddressByValue returns a matching address or sql.ErrNoRows if no address could be found.
FindVerifiableAddressByValue(ctx context.Context, via VerifiableAddressType, address string) (*VerifiableAddress, error)
FindVerifiableAddressByValue(ctx context.Context, via string, address string) (*VerifiableAddress, error)
// FindRecoveryAddressByValue returns a matching address or sql.ErrNoRows if no address could be found.
FindRecoveryAddressByValue(ctx context.Context, via RecoveryAddressType, address string) (*RecoveryAddress, error)

View File

@ -0,0 +1,13 @@
{
"type": "object",
"properties": {
"email": {
"type": "string",
"ory.sh/kratos": {
"verification": {
"via": "email"
}
}
}
}
}

View File

@ -0,0 +1,13 @@
{
"type": "object",
"properties": {
"phone": {
"type": "string",
"ory.sh/kratos": {
"verification": {
"via": "sms"
}
}
}
}
}

View File

@ -0,0 +1,14 @@
{
"type": "object",
"properties": {
"phone": {
"type": "string",
"format": "noformat",
"ory.sh/kratos": {
"verification": {
"via": "sms"
}
}
}
}
}

View File

@ -5,18 +5,20 @@
"type": "array",
"items": {
"type": "string",
"format": "tel",
"ory.sh/kratos": {
"verification": {
"via": "phone"
"via": "sms"
}
}
}
},
"username": {
"type": "string",
"format": "tel",
"ory.sh/kratos": {
"verification": {
"via": "phone"
"via": "sms"
}
}
}

View File

@ -31,7 +31,7 @@ type VerifiableIdentityAddress struct {
// Indicates if the address has already been verified
Verified bool `json:"verified"`
VerifiedAt *time.Time `json:"verified_at,omitempty"`
// VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema
// The delivery method
Via string `json:"via"`
}

View File

@ -31,7 +31,7 @@ type VerifiableIdentityAddress struct {
// Indicates if the address has already been verified
Verified bool `json:"verified"`
VerifiedAt *time.Time `json:"verified_at,omitempty"`
// VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema
// The delivery method
Via string `json:"via"`
}

View File

@ -957,7 +957,7 @@ func (p *IdentityPersister) GetIdentityConfidential(ctx context.Context, id uuid
return p.GetIdentity(ctx, id, identity.ExpandEverything)
}
func (p *IdentityPersister) FindVerifiableAddressByValue(ctx context.Context, via identity.VerifiableAddressType, value string) (_ *identity.VerifiableAddress, err error) {
func (p *IdentityPersister) FindVerifiableAddressByValue(ctx context.Context, via string, value string) (_ *identity.VerifiableAddress, err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindVerifiableAddressByValue")
otelx.End(span, &err)

View File

@ -163,23 +163,23 @@ func (b *Builder) addURLEncodedBody(ctx context.Context, template *bytes.Buffer,
enc.SetIndent("", "")
if err := enc.Encode(body); err != nil {
return err
return errors.WithStack(err)
}
vm, err := b.deps.JsonnetVM(ctx)
if err != nil {
return err
return errors.WithStack(err)
}
vm.TLACode("ctx", buf.String())
res, err := vm.EvaluateAnonymousSnippet(b.Config.TemplateURI, template.String())
if err != nil {
return err
return errors.WithStack(err)
}
values := map[string]string{}
if err := json.Unmarshal([]byte(res), &values); err != nil {
return err
return errors.WithStack(err)
}
u := url.Values{}

View File

@ -41,6 +41,7 @@ type (
Recovery struct {
Via string `json:"via"`
} `json:"recovery"`
RawSchema map[string]interface{} `json:"-"`
}
ValidateExtension interface {
@ -53,7 +54,7 @@ type (
ExtensionRunner struct {
meta *jsonschema.Schema
compile func(ctx jsonschema.CompilerContext, m map[string]interface{}) (interface{}, error)
compile func(ctx jsonschema.CompilerContext, rawSchema map[string]interface{}) (interface{}, error)
validate func(ctx jsonschema.ValidationContext, s interface{}, v interface{}) error
validateRunners []ValidateExtension
@ -106,6 +107,7 @@ func NewExtensionRunner(ctx context.Context, opts ...ExtensionRunnerOption) (*Ex
return nil, err
}
}
e.RawSchema = m
return &e, nil
}

View File

@ -241,7 +241,7 @@ func (s *Sender) SendRecoveryCodeTo(ctx context.Context, i *identity.Identity, c
// If the address does not exist in the store and dispatching invalid emails is enabled (CourierEnableInvalidDispatch is
// true), an email is still being sent to prevent account enumeration attacks. In that case, this function returns the
// ErrUnknownAddress error.
func (s *Sender) SendVerificationCode(ctx context.Context, f *verification.Flow, via identity.VerifiableAddressType, to string) error {
func (s *Sender) SendVerificationCode(ctx context.Context, f *verification.Flow, via string, to string) error {
s.deps.Logger().
WithField("via", via).
WithSensitiveField("address", to).
@ -317,21 +317,21 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo
// TODO: this can likely be abstracted by making templates not specific to the channel they're using
switch code.VerifiableAddress.Via {
case identity.AddressTypeEmail:
case identity.ChannelTypeEmail:
t = email.NewVerificationCodeValid(s.deps, &email.VerificationCodeValidModel{
To: code.VerifiableAddress.Value,
VerificationURL: s.constructVerificationLink(ctx, f.ID, codeString),
Identity: model,
VerificationCode: codeString,
})
case identity.AddressTypePhone:
case identity.ChannelTypeSMS:
t = sms.NewVerificationCodeValid(s.deps, &sms.VerificationCodeValidModel{
To: code.VerifiableAddress.Value,
VerificationCode: codeString,
Identity: model,
})
default:
return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email or phone but got %s", code.VerifiableAddress.Via))
return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email or sms but got %s", code.VerifiableAddress.Via))
}
if err := s.send(ctx, string(code.VerifiableAddress.Via), t); err != nil {
@ -343,7 +343,7 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo
func (s *Sender) send(ctx context.Context, via string, t courier.Template) error {
switch f := stringsx.SwitchExact(via); {
case f.AddCase(identity.AddressTypeEmail):
case f.AddCase(identity.ChannelTypeEmail):
c, err := s.deps.Courier(ctx)
if err != nil {
return err
@ -356,7 +356,7 @@ func (s *Sender) send(ctx context.Context, via string, t courier.Template) error
_, err = c.QueueEmail(ctx, t)
return err
case f.AddCase(identity.AddressTypePhone):
case f.AddCase(identity.ChannelTypeSMS):
c, err := s.deps.Courier(ctx)
if err != nil {
return err

View File

@ -1156,10 +1156,6 @@
"description": "VerifiableAddressStatus must not exceed 16 characters as that is the limitation in the SQL Schema",
"type": "string"
},
"identityVerifiableAddressType": {
"description": "VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema",
"type": "string"
},
"identityWithCredentials": {
"description": "Create Identity and Import Credentials",
"properties": {
@ -3255,7 +3251,13 @@
"$ref": "#/components/schemas/nullTime"
},
"via": {
"$ref": "#/components/schemas/identityVerifiableAddressType"
"description": "The delivery method",
"enum": [
"email",
"sms"
],
"example": "email",
"type": "string"
}
},
"required": [

View File

@ -4219,10 +4219,6 @@
"description": "VerifiableAddressStatus must not exceed 16 characters as that is the limitation in the SQL Schema",
"type": "string"
},
"identityVerifiableAddressType": {
"description": "VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema",
"type": "string"
},
"identityWithCredentials": {
"description": "Create Identity and Import Credentials",
"type": "object",
@ -6147,7 +6143,13 @@
"$ref": "#/definitions/nullTime"
},
"via": {
"$ref": "#/definitions/identityVerifiableAddressType"
"description": "The delivery method",
"type": "string",
"enum": [
"email",
"sms"
],
"example": "email"
}
}
},