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,36 @@
{
"$id": "https://schemas.ory.sh/kratos/selfservice/strategy/code/login.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"method": {
"type": "string"
},
"code": {
"type": "string"
},
"identifier": {
"type": "string"
},
"address": {
"type": "string"
},
"resend": {
"type": "string",
"enum": [
"code"
]
},
"flow": {
"type": "string",
"format": "uuid"
},
"csrf_token": {
"type": "string"
},
"transient_payload": {
"type": "object",
"additionalProperties": true
}
}
}

View File

@@ -0,0 +1,41 @@
{
"$id": "https://schemas.ory.sh/kratos/selfservice/strategy/profile/recovery.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"method": {
"type": "string"
},
"code": {
"type": "string"
},
"email": {
"type": "string",
"format": "email_loose",
"maxLength": 320
},
"recovery_address": {
"type": "string"
},
"recovery_select_address": {
"type": "string"
},
"recovery_confirm_address": {
"type": "string"
},
"screen": {
"type": "string"
},
"flow": {
"type": "string",
"format": "uuid"
},
"csrf_token": {
"type": "string"
},
"transient_payload": {
"type": "object",
"additionalProperties": true
}
}
}

View File

@@ -0,0 +1,29 @@
{
"$id": "https://schemas.ory.sh/kratos/selfservice/strategy/code/registration.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"method": {
"type": "string"
},
"csrf_token": {
"type": "string"
},
"code": {
"type": "string"
},
"resend": {
"type": "string",
"enum": [
"code"
]
},
"traits": {
"description": "This field will be overwritten in registration.go's decoder() method. Do not add anything to this field as it has no effect."
},
"transient_payload": {
"type": "object",
"additionalProperties": true
}
}
}

View File

@@ -0,0 +1,32 @@
{
"$id": "https://schemas.ory.sh/kratos/selfservice/strategy/profile/verification.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"method": {
"type": "string",
"enum": [
"code",
"link"
]
},
"code": {
"type": "string"
},
"email": {
"type": "string",
"maxLength": 320
},
"flow": {
"type": "string",
"format": "uuid"
},
"csrf_token": {
"type": "string"
},
"transient_payload": {
"type": "object",
"additionalProperties": true
}
}
}

View File

@@ -0,0 +1,43 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,8 @@
{
"error": {
"code": 400,
"message": "The request was malformed or contained invalid parameters",
"reason": "Unable to parse \"expires_in\" as a duration string (e.g. \"1h\", \"1m30s\", \"500ms\"): not-a-valid-value",
"status": "Bad Request"
}
}

View File

@@ -0,0 +1,8 @@
{
"error": {
"code": 400,
"message": "The request was malformed or contained invalid parameters",
"reason": "Value from \"expires_in\" must result to a future time: -1h0m0s",
"status": "Bad Request"
}
}

View File

@@ -0,0 +1,8 @@
{
"error": {
"code": 404,
"message": "Unable to locate the resource",
"reason": "could not find identity",
"status": "Not Found"
}
}

View File

@@ -0,0 +1,54 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "identifier",
"type": "text",
"value": "",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070004,
"text": "ID",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010015,
"text": "Send sign in code",
"type": "info"
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,38 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "address",
"type": "submit",
"value": "refresh-1fa-passwordless@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010023,
"text": "Send code to refresh-1fa-passwordless@ory.sh",
"type": "info",
"context": {
"address": "refresh-1fa-passwordless@ory.sh",
"channel": "email"
}
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,21 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010015,
"text": "Send sign in code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,21 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010015,
"text": "Send sign in code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,21 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010015,
"text": "Send sign in code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,54 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "identifier",
"type": "text",
"value": "",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070004,
"text": "ID",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010015,
"text": "Send sign in code",
"type": "info"
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,38 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "address",
"type": "submit",
"value": "foo@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010023,
"text": "Send code to foo@ory.sh",
"type": "info",
"context": {
"address": "foo@ory.sh",
"channel": "email"
}
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,38 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "address",
"type": "submit",
"value": "populateloginmethodsecondfactor-code-mfa-via-2fa@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010023,
"text": "Send code to populateloginmethodsecondfactor-code-mfa-via-2fa@ory.sh",
"type": "info",
"context": {
"address": "populateloginmethodsecondfactor-code-mfa-via-2fa@ory.sh",
"channel": "email"
}
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,84 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "address",
"type": "submit",
"value": "+4917655138291",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010023,
"text": "Send code to +4917655138291",
"type": "info",
"context": {
"address": "+4917655138291",
"channel": "sms"
}
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "address",
"type": "submit",
"value": "populateloginmethodsecondfactor-no-via-2fa-0@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010023,
"text": "Send code to populateloginmethodsecondfactor-no-via-2fa-0@ory.sh",
"type": "info",
"context": {
"address": "populateloginmethodsecondfactor-no-via-2fa-0@ory.sh",
"channel": "email"
}
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "address",
"type": "submit",
"value": "populateloginmethodsecondfactor-no-via-2fa-1@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010023,
"text": "Send code to populateloginmethodsecondfactor-no-via-2fa-1@ory.sh",
"type": "info",
"context": {
"address": "populateloginmethodsecondfactor-no-via-2fa-1@ory.sh",
"channel": "email"
}
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,38 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "address",
"type": "submit",
"value": "fooaewdk@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1010023,
"text": "Send code to fooaewdk@ory.sh",
"type": "info",
"context": {
"address": "fooaewdk@ory.sh",
"channel": "email"
}
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,127 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_test_fast_browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_test_fast_browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_test_fast_browser@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,127 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_fallback_without_ccbrowser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_fallback_without_ccbrowser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_fallback_without_ccbrowser@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,127 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_fallback_with_ccbrowser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_fallback_with_ccbrowser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_fallback_with_ccbrowser@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,94 @@
{
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "choose_method",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010004,
"text": "Please complete the second authentication challenge.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "fixed_mfa_test_browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_test_browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_test_browser@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "totp_code",
"node_type": "input",
"required": true,
"type": "text",
"value": ""
},
"group": "totp",
"messages": [],
"meta": {
"label": {
"id": 1010006,
"text": "Authentication code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "totp"
},
"group": "totp",
"messages": [],
"meta": {
"label": {
"id": 1010009,
"text": "Use Authenticator",
"type": "info"
}
},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213110"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213110",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213110",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1browser@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2browser@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213110"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213110",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213110",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1browser@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2browser@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213110"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213110",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213110",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1browser@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2browser@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2browser@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2browser@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,114 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "api",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_test_fast_api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_test_fast_api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_test_fast_api@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,114 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "api",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_fallback_without_ccapi@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_fallback_without_ccapi@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_fallback_without_ccapi@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,114 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "api",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_fallback_with_ccapi@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_fallback_with_ccapi@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_fallback_with_ccapi@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,94 @@
{
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "choose_method",
"type": "api",
"ui": {
"messages": [
{
"id": 1010004,
"text": "Please complete the second authentication challenge.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "fixed_mfa_test_api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_test_api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_test_api@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "totp_code",
"node_type": "input",
"required": true,
"type": "text",
"value": ""
},
"group": "totp",
"messages": [],
"meta": {
"label": {
"id": 1010006,
"text": "Authentication code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "totp"
},
"group": "totp",
"messages": [],
"meta": {
"label": {
"id": 1010009,
"text": "Use Authenticator",
"type": "info"
}
},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213111"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213111",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213111",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1api@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2api@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213111"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213111",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213111",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1api@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2api@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213111"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213111",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213111",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1api@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2api@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2api@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2api@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,127 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_test_fast_spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_test_fast_spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_test_fast_spa@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,127 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_fallback_without_ccspa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_fallback_without_ccspa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_fallback_without_ccspa@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,127 @@
{
"active": "code",
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "sent_email",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010025,
"text": "A code was sent to your address. If you didn't receive it, please try again.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "identifier",
"node_type": "input",
"type": "hidden",
"value": "fixed_mfa_fallback_with_ccspa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_fallback_with_ccspa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_fallback_with_ccspa@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "hidden",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"autocomplete": "one-time-code",
"disabled": false,
"name": "code",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070013,
"text": "Login code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "resend",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,94 @@
{
"organization_id": null,
"refresh": false,
"requested_aal": "aal2",
"state": "choose_method",
"type": "browser",
"ui": {
"messages": [
{
"id": 1010004,
"text": "Please complete the second authentication challenge.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "fixed_mfa_test_spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "fixed_mfa_test_spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to fixed_mfa_test_spa@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "totp_code",
"node_type": "input",
"required": true,
"type": "text",
"value": ""
},
"group": "totp",
"messages": [],
"meta": {
"label": {
"id": 1010006,
"text": "Authentication code",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "totp"
},
"group": "totp",
"messages": [],
"meta": {
"label": {
"id": 1010009,
"text": "Use Authenticator",
"type": "info"
}
},
"type": "input"
}
]
}
}

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213112"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213112",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213112",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1spa@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2spa@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213112"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213112",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213112",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1spa@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2spa@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,71 @@
[
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "+4917613213112"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "+4917613213112",
"channel": "sms"
},
"id": 1010023,
"text": "Send code to +4917613213112",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-1spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-1spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-1spa@ory.sh",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "address",
"node_type": "input",
"type": "submit",
"value": "code-mfa-2spa@ory.sh"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"context": {
"address": "code-mfa-2spa@ory.sh",
"channel": "email"
},
"id": 1010023,
"text": "Send code to code-mfa-2spa@ory.sh",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,34 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1040006,
"text": "Send sign up code",
"type": "info"
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,34 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1040006,
"text": "Send sign up code",
"type": "info"
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,15 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,15 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,34 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1040006,
"text": "Send sign up code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,15 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,34 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1040006,
"text": "Send sign up code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "email",
"node_type": "input",
"required": true,
"type": "email"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070007,
"text": "Email",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,88 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "email",
"type": "submit",
"value": "test@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address (Email, phone number, etc)",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address (Email, phone number, etc)",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address (Email, phone number, etc)",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,35 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "email",
"value": "",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070007,
"text": "Email",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,35 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "email",
"value": "",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070007,
"text": "Email",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,35 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "email",
"value": "",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070007,
"text": "Email",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,120 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "submit",
"value": "test-api@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "test-api@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "screen",
"type": "submit",
"value": "previous",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1060007,
"text": "Back",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,120 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "submit",
"value": "test-browser@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "test-browser@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "screen",
"type": "submit",
"value": "previous",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1060007,
"text": "Back",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,120 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "submit",
"value": "test-spa@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "test-spa@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "screen",
"type": "submit",
"value": "previous",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1060007,
"text": "Back",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,120 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "submit",
"value": "+491705550177",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "+491705550177",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "screen",
"type": "submit",
"value": "previous",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1060007,
"text": "Back",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,120 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "submit",
"value": "+491705550176",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "+491705550176",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "screen",
"type": "submit",
"value": "previous",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1060007,
"text": "Back",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,120 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_confirm_address",
"type": "submit",
"value": "+491705550178",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "+491705550178",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "screen",
"type": "submit",
"value": "previous",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1060007,
"text": "Back",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "recovery_address",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070016,
"text": "Recovery address",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,79 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_select_address",
"type": "submit",
"value": "MEIbSbZvtBRV9TH7wdFTF5CGyhxaaM2zuLDSIELCIAI=",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070000,
"text": "+49****67",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_select_address",
"type": "submit",
"value": "BgkSG7BOfSWi+9/IRUclTboO0eGGkgnBFQiBv/v2Jw4=",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070000,
"text": "te****@ory.sh",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "+491705550167",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,79 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_select_address",
"type": "submit",
"value": "52McLavwKA6+jlSuOBVOPvkoLn8r1fUhZDMj2eytcac=",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070000,
"text": "+49****66",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_select_address",
"type": "submit",
"value": "9lRwDY12jB69oE1+tGQXV2XFJbgBtjjRwBjH+iHmHjA=",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070000,
"text": "te****@ory.sh",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "+491705550166",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,79 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_select_address",
"type": "submit",
"value": "zx+NolDxaddHeLJ05eafzEcdjhJ0F8h5MAPtmbBSZkE=",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070000,
"text": "+49****68",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_select_address",
"type": "submit",
"value": "pti/PkfHLV3dkx+jIA+yDc8KCLmQ/K872SvKfFQ7C/c=",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070000,
"text": "te****@ory.sh",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "recovery_address",
"type": "hidden",
"value": "+491705550168",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "email",
"node_type": "input",
"required": true,
"type": "email"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070007,
"text": "Email",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "email",
"node_type": "input",
"required": true,
"type": "email"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070007,
"text": "Email",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "email",
"node_type": "input",
"required": true,
"type": "email"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070007,
"text": "Email",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
}
]

View File

@@ -0,0 +1,88 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "email",
"type": "submit",
"value": "test@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,88 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "email",
"type": "submit",
"value": "test@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,88 @@
[
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"pattern": "[0-9]+",
"disabled": false,
"maxlength": 6,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070010,
"text": "Recovery code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "email",
"type": "submit",
"value": "test@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,53 @@
[
{
"attributes": {
"disabled": false,
"name": "email",
"node_type": "input",
"required": true,
"type": "text"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070018,
"text": "Email or phone number",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "method",
"node_type": "input",
"type": "submit",
"value": "code"
},
"group": "code",
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden"
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]

View File

@@ -0,0 +1,86 @@
[
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "hidden",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "code",
"type": "text",
"required": true,
"autocomplete": "one-time-code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070011,
"text": "Verification code",
"type": "info"
}
}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "method",
"type": "submit",
"value": "code",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070009,
"text": "Continue",
"type": "info"
}
}
},
{
"type": "input",
"group": "default",
"attributes": {
"name": "csrf_token",
"type": "hidden",
"required": true,
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {}
},
{
"type": "input",
"group": "code",
"attributes": {
"name": "email",
"type": "submit",
"value": "test@ory.sh",
"disabled": false,
"node_type": "input"
},
"messages": [],
"meta": {
"label": {
"id": 1070008,
"text": "Resend code",
"type": "info"
}
}
}
]

View File

@@ -0,0 +1,117 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package code
import (
"context"
"database/sql"
"time"
"github.com/pkg/errors"
"github.com/gofrs/uuid"
"github.com/ory/kratos/identity"
"github.com/ory/x/clock"
"github.com/ory/x/region"
)
// swagger:ignore
type LoginCode struct {
// ID represents the tokens's unique ID.
//
// required: true
// type: string
// format: uuid
ID uuid.UUID `json:"id" db:"id" faker:"-"`
// Address represents the address that the code was sent to.
// this can be an email address or a phone number.
Address string `json:"-" db:"address"`
// AddressType represents the type of the address
// this can be an email address or a phone number.
AddressType identity.CodeChannel `json:"-" db:"address_type"`
// CodeHMAC represents the HMACed value of the verification code
CodeHMAC string `json:"-" db:"code"`
// UsedAt is the timestamp of when the code was used or null if it wasn't yet
UsedAt sql.NullTime `json:"-" db:"used_at"`
// ExpiresAt is the time (UTC) when the token expires.
// required: true
ExpiresAt time.Time `json:"expires_at" faker:"time_type" db:"expires_at"`
// IssuedAt is the time (UTC) when the token was issued.
// required: true
IssuedAt time.Time `json:"issued_at" faker:"time_type" db:"issued_at"`
// CreatedAt is a helper struct field for gobuffalo.pop.
CreatedAt time.Time `json:"-" faker:"-" db:"created_at"`
// UpdatedAt is a helper struct field for gobuffalo.pop.
UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"`
// FlowID is a helper struct field for gobuffalo.pop.
FlowID uuid.UUID `json:"-" faker:"-" db:"selfservice_login_flow_id"`
NID uuid.UUID `json:"-" faker:"-" db:"nid"`
IdentityID uuid.UUID `json:"identity_id" faker:"-" db:"identity_id"`
}
func (LoginCode) TableName(ctx context.Context) string {
return "identity_login_codes"
}
func (c *LoginCode) Validate(clk clock.Clock) error {
if c == nil {
return errors.WithStack(ErrCodeNotFound())
}
return validateOneTimeCode(c.ExpiresAt, c.UsedAt, clk)
}
func (c *LoginCode) GetHMACCode() string {
return c.CodeHMAC
}
func (c *LoginCode) GetID() uuid.UUID {
return c.ID
}
// swagger:ignore
type CreateLoginCodeParams struct {
// Address is the email address or phone number the code should be sent to.
// required: true
Address string
// AddressType is the type of the address (email or phone number).
// required: true
AddressType identity.CodeChannel
// Code represents the recovery code
// required: true
RawCode string
// ExpiresAt is the time (UTC) when the code expires.
// required: true
ExpiresIn time.Duration
// FlowID is a helper struct field for gobuffalo.pop.
// required: true
FlowID uuid.UUID
// IdentityID is the identity that this code is for
// required: true
IdentityID uuid.UUID
// IdentityRegion optionally carries the already-known region of the
// identity the code is for, so persisters can use it without re-reading
// the identity row.
IdentityRegion region.Region `json:"-" db:"-" faker:"-"`
// InsertExtraColumns appends fixed (key, value) columns to the INSERT
// statement (e.g. crdb_region).
InsertExtraColumns []identity.ExtraColumn `json:"-" db:"-" faker:"-"`
}

View File

@@ -0,0 +1,86 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package code_test
import (
"database/sql"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/ory/kratos/pkg"
"github.com/ory/kratos/selfservice/flow"
"github.com/ory/kratos/selfservice/flow/login"
"github.com/ory/kratos/selfservice/strategy/code"
"github.com/ory/kratos/x"
"github.com/ory/x/urlx"
)
func TestLoginCode(t *testing.T) {
t.Parallel()
_, reg := pkg.NewVeryFastRegistryWithoutDB(t)
newCode := func(expiresIn time.Duration, f *login.Flow) *code.LoginCode {
return &code.LoginCode{
ID: x.NewUUID(),
FlowID: f.ID,
ExpiresAt: time.Now().Add(expiresIn),
}
}
req := &http.Request{URL: urlx.ParseOrPanic("https://www.ory.com/")}
t.Run("method=Validate", func(t *testing.T) {
t.Parallel()
t.Run("case=returns error if code is expired", func(t *testing.T) {
f, err := login.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(-time.Hour)
c := newCode(-time.Hour, f)
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeNotFound())
})
t.Run("case=returns no error if flow is not expired", func(t *testing.T) {
f, err := login.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(time.Hour)
c := newCode(time.Hour, f)
require.NoError(t, c.Validate(reg.Clock()))
})
t.Run("case=returns error if flow has been used", func(t *testing.T) {
f, err := login.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(-time.Hour)
c := newCode(time.Hour, f)
c.UsedAt = sql.NullTime{
Time: time.Now(),
Valid: true,
}
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeAlreadyUsed())
})
t.Run("case=returns no error if flow has not been used", func(t *testing.T) {
f, err := login.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(-time.Hour)
c := newCode(time.Hour, f)
c.UsedAt = sql.NullTime{
Valid: false,
}
require.NoError(t, c.Validate(reg.Clock()))
})
t.Run("case=returns error if flow is nil", func(t *testing.T) {
var c *code.LoginCode
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeNotFound())
})
})
}

View File

@@ -0,0 +1,132 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package code
import (
"context"
"database/sql"
"time"
"github.com/pkg/errors"
"github.com/gofrs/uuid"
"github.com/ory/herodot"
"github.com/ory/kratos/identity"
"github.com/ory/x/clock"
)
type RecoveryCodeType int
const (
RecoveryCodeTypeAdmin RecoveryCodeType = iota + 1
RecoveryCodeTypeSelfService
)
func ErrCodeNotFound() *herodot.DefaultError {
return herodot.ErrNotFound().WithReasonf("unknown code")
}
func ErrCodeAlreadyUsed() *herodot.DefaultError {
return herodot.ErrBadRequest().WithReasonf("The code was already used. Please request another code.")
}
func ErrCodeSubmittedTooOften() *herodot.DefaultError {
return herodot.ErrBadRequest().WithReasonf("The request was submitted too often. Please request another code.")
}
// validateOneTimeCode reports whether a one-time code is still usable. Every
// one-time code type (login, registration, recovery, verification) shares this
// logic: an expired code is reported as not found, and an already-consumed code
// is reported as already used.
func validateOneTimeCode(expiresAt time.Time, usedAt sql.NullTime, clk clock.Clock) error {
if expiresAt.Before(clk.Now().UTC()) {
return errors.WithStack(ErrCodeNotFound())
}
if usedAt.Valid {
return errors.WithStack(ErrCodeAlreadyUsed())
}
return nil
}
type RecoveryCode struct {
// ID represents the code's unique ID.
//
// required: true
// type: string
// format: uuid
ID uuid.UUID `json:"id" db:"id" faker:"-"`
// CodeHMAC represents the HMACed value of the recovery code
CodeHMAC string `json:"-" db:"code"`
// UsedAt is the timestamp of when the code was used or null if it wasn't yet
UsedAt sql.NullTime `json:"-" db:"used_at"`
// RecoveryAddress links this code to a recovery address.
// required: true
RecoveryAddress *identity.RecoveryAddress `json:"recovery_address" belongs_to:"identity_recovery_addresses" fk_id:"RecoveryAddressID"`
// CodeType is the type of the code - either "admin" or "selfservice"
CodeType RecoveryCodeType `json:"-" faker:"-" db:"code_type"`
// ExpiresAt is the time (UTC) when the code expires.
// required: true
ExpiresAt time.Time `json:"expires_at" faker:"time_type" db:"expires_at"`
// IssuedAt is the time (UTC) when the code was issued.
// required: true
IssuedAt time.Time `json:"issued_at" faker:"time_type" db:"issued_at"`
// CreatedAt is a helper struct field for gobuffalo.pop.
CreatedAt time.Time `json:"-" faker:"-" db:"created_at"`
// UpdatedAt is a helper struct field for gobuffalo.pop.
UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"`
// RecoveryAddressID is a helper struct field for gobuffalo.pop.
RecoveryAddressID uuid.NullUUID `json:"-" faker:"-" db:"identity_recovery_address_id"`
// FlowID is a helper struct field for gobuffalo.pop.
FlowID uuid.UUID `json:"-" faker:"-" db:"selfservice_recovery_flow_id"`
NID uuid.UUID `json:"-" faker:"-" db:"nid"`
IdentityID uuid.UUID `json:"identity_id" faker:"-" db:"identity_id"`
}
func (RecoveryCode) TableName(ctx context.Context) string {
return "identity_recovery_codes"
}
func (f *RecoveryCode) Validate(clk clock.Clock) error {
if f == nil {
return errors.WithStack(ErrCodeNotFound())
}
return validateOneTimeCode(f.ExpiresAt, f.UsedAt, clk)
}
func (c *RecoveryCode) GetHMACCode() string {
return c.CodeHMAC
}
func (c *RecoveryCode) GetID() uuid.UUID {
return c.ID
}
type CreateRecoveryCodeParams struct {
// Code represents the recovery code
RawCode string
// CodeType is the type of the code - either "admin" or "selfservice"
CodeType RecoveryCodeType
// ExpiresAt is the time (UTC) when the code expires.
// required: true
ExpiresIn time.Duration
// RecoveryAddressID is a helper struct field for gobuffalo.pop.
RecoveryAddress *identity.RecoveryAddress
// FlowID is a helper struct field for gobuffalo.pop.
FlowID uuid.UUID
IdentityID uuid.UUID
}

View File

@@ -0,0 +1,95 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package code_test
import (
"database/sql"
"errors"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ory/kratos/pkg"
"github.com/ory/kratos/selfservice/flow"
"github.com/ory/kratos/selfservice/flow/recovery"
"github.com/ory/kratos/selfservice/strategy/code"
"github.com/ory/kratos/x"
"github.com/ory/x/urlx"
)
func TestRecoveryCode(t *testing.T) {
_, reg := pkg.NewVeryFastRegistryWithoutDB(t)
newCode := func(expiresIn time.Duration, f *recovery.Flow) *code.RecoveryCode {
return &code.RecoveryCode{
ID: x.NewUUID(),
FlowID: f.ID,
ExpiresAt: time.Now().Add(expiresIn),
}
}
req := &http.Request{URL: urlx.ParseOrPanic("https://www.ory.com/")}
t.Run("method=Validate", func(t *testing.T) {
t.Parallel()
t.Run("case=returns ErrCodeNotFound if code is expired", func(t *testing.T) {
f, err := recovery.NewFlow(reg, -time.Hour, "", req, nil, flow.TypeBrowser)
require.NoError(t, err)
c := newCode(-time.Hour, f)
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeNotFound())
})
t.Run("case=expired code does not return flow.ExpiredError", func(t *testing.T) {
f, err := recovery.NewFlow(reg, -time.Hour, "", req, nil, flow.TypeBrowser)
require.NoError(t, err)
c := newCode(-time.Hour, f)
expired := new(flow.ExpiredError)
require.False(t, errors.As(c.Validate(reg.Clock()), &expired), "expired code should not return flow.ExpiredError")
})
t.Run("case=returns no error if flow is not expired", func(t *testing.T) {
f, err := recovery.NewFlow(reg, time.Hour, "", req, nil, flow.TypeBrowser)
require.NoError(t, err)
c := newCode(time.Hour, f)
require.NoError(t, c.Validate(reg.Clock()))
})
t.Run("case=returns error if flow has been used", func(t *testing.T) {
f, err := recovery.NewFlow(reg, -time.Hour, "", req, nil, flow.TypeBrowser)
require.NoError(t, err)
c := newCode(time.Hour, f)
c.UsedAt = sql.NullTime{
Time: time.Now(),
Valid: true,
}
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeAlreadyUsed())
})
t.Run("case=returns no error if flow has not been used", func(t *testing.T) {
f, err := recovery.NewFlow(reg, -time.Hour, "", req, nil, flow.TypeBrowser)
require.NoError(t, err)
c := newCode(time.Hour, f)
c.UsedAt = sql.NullTime{
Valid: false,
}
require.NoError(t, c.Validate(reg.Clock()))
})
t.Run("case=returns error if flow is nil", func(t *testing.T) {
var c *code.RecoveryCode
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeNotFound())
})
})
}
func TestRecoveryCodeType(t *testing.T) {
assert.Equal(t, 1, int(code.RecoveryCodeTypeAdmin))
assert.Equal(t, 2, int(code.RecoveryCodeTypeSelfService))
}

View File

@@ -0,0 +1,102 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package code
import (
"context"
"database/sql"
"time"
"github.com/pkg/errors"
"github.com/gofrs/uuid"
"github.com/ory/kratos/identity"
"github.com/ory/x/clock"
)
// swagger:ignore
type RegistrationCode struct {
// ID represents the tokens's unique ID.
//
// required: true
// type: string
// format: uuid
ID uuid.UUID `json:"id" db:"id" faker:"-"`
// Address represents the address that the code was sent to.
// this can be an email address or a phone number.
Address string `json:"-" db:"address"`
// AddressType represents the type of the address
// this can be an email address or a phone number.
AddressType identity.CodeChannel `json:"-" db:"address_type"`
// CodeHMAC represents the HMACed value of the verification code
CodeHMAC string `json:"-" db:"code"`
// UsedAt is the timestamp of when the code was used or null if it wasn't yet
UsedAt sql.NullTime `json:"-" db:"used_at"`
// ExpiresAt is the time (UTC) when the token expires.
// required: true
ExpiresAt time.Time `json:"expires_at" faker:"time_type" db:"expires_at"`
// IssuedAt is the time (UTC) when the token was issued.
// required: true
IssuedAt time.Time `json:"issued_at" faker:"time_type" db:"issued_at"`
// CreatedAt is a helper struct field for gobuffalo.pop.
CreatedAt time.Time `json:"-" faker:"-" db:"created_at"`
// UpdatedAt is a helper struct field for gobuffalo.pop.
UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"`
// FlowID is a helper struct field for gobuffalo.pop.
FlowID uuid.UUID `json:"-" faker:"-" db:"selfservice_registration_flow_id"`
NID uuid.UUID `json:"-" faker:"-" db:"nid"`
}
func (RegistrationCode) TableName(context.Context) string {
return "identity_registration_codes"
}
func (c *RegistrationCode) Validate(clk clock.Clock) error {
if c == nil {
return errors.WithStack(ErrCodeNotFound())
}
return validateOneTimeCode(c.ExpiresAt, c.UsedAt, clk)
}
func (c *RegistrationCode) GetHMACCode() string {
return c.CodeHMAC
}
func (c *RegistrationCode) GetID() uuid.UUID {
return c.ID
}
// swagger:ignore
type CreateRegistrationCodeParams struct {
// Address is the email address or phone number the code should be sent to.
// required: true
Address string
// AddressType is the type of the address (email or phone number).
// required: true
AddressType identity.CodeChannel
// Code represents the recovery code
// required: true
RawCode string
// ExpiresAt is the time (UTC) when the code expires.
// required: true
ExpiresIn time.Duration
// FlowID is a helper struct field for gobuffalo.pop.
// required: true
FlowID uuid.UUID
}

View File

@@ -0,0 +1,83 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package code_test
import (
"database/sql"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/ory/kratos/pkg"
"github.com/ory/kratos/selfservice/flow"
"github.com/ory/kratos/selfservice/flow/registration"
"github.com/ory/kratos/selfservice/strategy/code"
"github.com/ory/kratos/x"
"github.com/ory/x/urlx"
)
func TestRegistrationCode(t *testing.T) {
_, reg := pkg.NewVeryFastRegistryWithoutDB(t)
newCode := func(expiresIn time.Duration, f *registration.Flow) *code.RegistrationCode {
return &code.RegistrationCode{
ID: x.NewUUID(),
FlowID: f.ID,
ExpiresAt: time.Now().Add(expiresIn),
}
}
req := &http.Request{URL: urlx.ParseOrPanic("https://www.ory.com/")}
t.Run("method=Validate", func(t *testing.T) {
t.Parallel()
t.Run("case=returns error if code is expired", func(t *testing.T) {
f, err := registration.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(-time.Hour)
c := newCode(-time.Hour, f)
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeNotFound())
})
t.Run("case=returns no error if flow is not expired", func(t *testing.T) {
f, err := registration.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(time.Hour)
c := newCode(time.Hour, f)
require.NoError(t, c.Validate(reg.Clock()))
})
t.Run("case=returns error if flow has been used", func(t *testing.T) {
f, err := registration.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(-time.Hour)
c := newCode(time.Hour, f)
c.UsedAt = sql.NullTime{
Time: time.Now(),
Valid: true,
}
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeAlreadyUsed())
})
t.Run("case=returns no error if flow has not been used", func(t *testing.T) {
f, err := registration.NewFlow(reg, req, flow.TypeBrowser)
require.NoError(t, err)
f.ExpiresAt = f.IssuedAt.Add(-time.Hour)
c := newCode(time.Hour, f)
c.UsedAt = sql.NullTime{
Valid: false,
}
require.NoError(t, c.Validate(reg.Clock()))
})
t.Run("case=returns error if flow is nil", func(t *testing.T) {
var c *code.RegistrationCode
require.ErrorIs(t, c.Validate(reg.Clock()), code.ErrCodeNotFound())
})
})
}

View File

@@ -0,0 +1,539 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package code
import (
"context"
"net/http"
"net/url"
"strings"
"github.com/pkg/errors"
"github.com/ory/herodot"
"github.com/ory/kratos/courier"
"github.com/ory/kratos/courier/template"
"github.com/ory/kratos/courier/template/email"
"github.com/ory/kratos/courier/template/sms"
"github.com/ory/kratos/driver/config"
"github.com/ory/kratos/hydra"
"github.com/ory/kratos/identity"
"github.com/ory/kratos/selfservice/flow"
"github.com/ory/kratos/selfservice/flow/recovery"
"github.com/ory/kratos/selfservice/flow/verification"
"github.com/ory/kratos/selfservice/hook"
"github.com/ory/kratos/x"
"github.com/ory/x/httpx"
"github.com/ory/x/logrusx"
"github.com/ory/x/sqlcon"
"github.com/ory/x/stringsx"
"github.com/ory/x/urlx"
)
type (
senderDependencies interface {
courier.Provider
courier.ConfigProvider
identity.PoolProvider
identity.ManagementProvider
identity.PrivilegedPoolProvider
logrusx.Provider
config.Provider
RecoveryCodePersistenceProvider
VerificationCodePersistenceProvider
RegistrationCodePersistenceProvider
LoginCodePersistenceProvider
hydra.Provider
httpx.ClientProvider
}
SenderProvider interface {
CodeSender() *Sender
}
Sender struct {
deps senderDependencies
}
Address struct {
To string
Via identity.CodeChannel
}
)
func ErrUnknownAddress() *herodot.DefaultError {
return herodot.ErrNotFound().WithReason("recovery requested for unknown address")
}
func NewSender(deps senderDependencies) *Sender {
return &Sender{deps: deps}
}
func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identity, header http.Header, addresses ...Address) error {
s.deps.Logger().
WithSensitiveField("address", addresses).
Debugf("Preparing %s code", f.GetFlowName())
transientPayload, err := x.ParseRawMessageOrEmpty(f.GetTransientPayload())
if err != nil {
return errors.WithStack(err)
}
// If the flow was initiated by an OAuth2 login challenge, expose a scoped
// view of the OAuth2 client to the courier templates so that messages can
// be branded per client.
var oauth2LoginRequest *template.OAuth2LoginRequest
if p, ok := f.(flow.HydraLoginRequestProvider); ok {
oauth2LoginRequest = template.NewOAuth2LoginRequest(p.GetHydraLoginRequest())
}
// send to all addresses
for _, address := range addresses {
// We have to generate a unique code per address, or otherwise it is not possible to link which
// address was used to verify the code.
//
// See also [this discussion](https://github.com/ory/kratos/pull/3456#discussion_r1307560988).
rawCode := GenerateCode()
switch f.GetFlowName() {
case flow.RegistrationFlow:
code, err := s.deps.
RegistrationCodePersister().
CreateRegistrationCode(ctx, &CreateRegistrationCodeParams{
AddressType: address.Via,
RawCode: rawCode,
ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx),
FlowID: f.GetID(),
Address: address.To,
})
if err != nil {
return err
}
model, err := x.StructToMap(id.Traits)
if err != nil {
return err
}
s.deps.Logger().
WithField("registration_flow_id", code.FlowID).
WithField("registration_code_id", code.ID).
WithSensitiveField("registration_code", rawCode).
Info("Sending out registration email with code.")
var t courier.Template
switch address.Via {
case identity.ChannelTypeEmail:
t = email.NewRegistrationCodeValid(s.deps, &email.RegistrationCodeValidModel{
To: address.To,
RegistrationCode: rawCode,
Traits: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
OAuth2LoginRequest: oauth2LoginRequest,
UserRequestHeaders: hook.RemoveDisallowedHeaders(header, s.deps.Config().WebhookHeaderAllowlist(ctx)),
})
case identity.ChannelTypeSMS:
t = sms.NewRegistrationCodeValid(s.deps, &sms.RegistrationCodeValidModel{
To: address.To,
RegistrationCode: rawCode,
Identity: model,
RequestURL: f.GetRequestURL(),
RequestURLDomain: requestURLDomain(f.GetRequestURL()),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
OAuth2LoginRequest: oauth2LoginRequest,
UserRequestHeaders: hook.RemoveDisallowedHeaders(header, s.deps.Config().WebhookHeaderAllowlist(ctx)),
})
}
if err := s.send(ctx, string(address.Via), t); err != nil {
return errors.WithStack(err)
}
case flow.LoginFlow:
code, err := s.deps.
LoginCodePersister().
CreateLoginCode(ctx, &CreateLoginCodeParams{
AddressType: address.Via,
Address: address.To,
RawCode: rawCode,
ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx),
FlowID: f.GetID(),
IdentityID: id.ID,
IdentityRegion: id.Region,
})
if err != nil {
return err
}
model, err := x.StructToMap(id)
if err != nil {
return err
}
s.deps.Logger().
WithField("login_flow_id", code.FlowID).
WithField("login_code_id", code.ID).
WithSensitiveField("login_code", rawCode).
Info("Sending out login email with code.")
var t courier.Template
switch address.Via {
case identity.ChannelTypeEmail:
t = email.NewLoginCodeValid(s.deps, &email.LoginCodeValidModel{
To: address.To,
LoginCode: rawCode,
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
OAuth2LoginRequest: oauth2LoginRequest,
UserRequestHeaders: hook.RemoveDisallowedHeaders(header, s.deps.Config().WebhookHeaderAllowlist(ctx)),
})
case identity.ChannelTypeSMS:
t = sms.NewLoginCodeValid(s.deps, &sms.LoginCodeValidModel{
To: address.To,
LoginCode: rawCode,
Identity: model,
RequestURL: f.GetRequestURL(),
RequestURLDomain: requestURLDomain(f.GetRequestURL()),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
OAuth2LoginRequest: oauth2LoginRequest,
UserRequestHeaders: hook.RemoveDisallowedHeaders(header, s.deps.Config().WebhookHeaderAllowlist(ctx)),
})
}
if err := s.send(ctx, string(address.Via), t); err != nil {
return errors.WithStack(err)
}
default:
return errors.WithStack(errors.New("received unknown flow type"))
}
}
return nil
}
// SendRecoveryCode sends a recovery code to the specified address
//
// 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) SendRecoveryCode(ctx context.Context, f *recovery.Flow, via, to string, requestHeader http.Header) error {
s.deps.Logger().
WithField("via", via).
WithSensitiveField("address", to).
Debug("Preparing recovery code.")
address, err := s.deps.IdentityPool().FindRecoveryAddressByValue(ctx, via, to)
if errors.Is(err, sqlcon.ErrNoRows()) {
notifyUnknownRecipients := s.deps.Config().SelfServiceFlowRecoveryNotifyUnknownRecipients(ctx)
s.deps.Logger().
WithField("via", via).
WithSensitiveField("address", to).
WithField("strategy", "code").
WithField("was_notified", notifyUnknownRecipients).
Info("Account recovery was requested for an unknown address.")
transientPayload, err := x.ParseRawMessageOrEmpty(f.GetTransientPayload())
if err != nil {
return errors.WithStack(err)
}
// We only send a notification if the configuration allows it *and* the channel is email.
// That's because we pay per SMS sent (typically) so we want to avoid that, contrary to email.
shouldNotifyOfUnkownRecipient := notifyUnknownRecipients && via == identity.AddressTypeEmail
if !shouldNotifyOfUnkownRecipient {
// do nothing
} else if err := s.send(ctx, via, email.NewRecoveryCodeInvalid(s.deps, &email.RecoveryCodeInvalidModel{
To: to,
RequestURL: f.RequestURL,
TransientPayload: transientPayload,
})); err != nil {
return err
}
return errors.WithStack(ErrUnknownAddress())
} else if err != nil {
// DB error
return err
}
// Get the identity associated with the recovery address
i, err := s.deps.IdentityPool().GetIdentity(ctx, address.IdentityID, identity.ExpandDefault)
if err != nil {
return err
}
rawCode := GenerateCode()
var code *RecoveryCode
if code, err = s.deps.
RecoveryCodePersister().
CreateRecoveryCode(ctx, &CreateRecoveryCodeParams{
RawCode: rawCode,
CodeType: RecoveryCodeTypeSelfService,
ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx),
RecoveryAddress: address,
FlowID: f.ID,
IdentityID: i.ID,
}); err != nil {
return err
}
return s.SendRecoveryCodeTo(ctx, i, rawCode, code, f, requestHeader)
}
func (s *Sender) SendRecoveryCodeTo(ctx context.Context, i *identity.Identity, codeString string, code *RecoveryCode, f *recovery.Flow, requestHeader http.Header) error {
s.deps.Logger().
WithField("via", code.RecoveryAddress.Via).
WithField("identity_id", code.RecoveryAddress.IdentityID).
WithField("recovery_code_id", code.ID).
WithSensitiveField("address", code.RecoveryAddress.Value).
WithSensitiveField("recovery_code", codeString).
Info("Sending out recovery code.")
model, err := x.StructToMap(i)
if err != nil {
return err
}
transientPayload, err := x.ParseRawMessageOrEmpty(f.GetTransientPayload())
if err != nil {
return errors.WithStack(err)
}
var t courier.Template
switch code.RecoveryAddress.Via {
case identity.AddressTypeEmail:
t = email.NewRecoveryCodeValid(s.deps, &email.RecoveryCodeValidModel{
To: code.RecoveryAddress.Value,
RecoveryCode: codeString,
Identity: model,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
UserRequestHeaders: hook.RemoveDisallowedHeaders(requestHeader, s.deps.Config().WebhookHeaderAllowlist(ctx)),
})
case identity.AddressTypeSMS:
u, err := url.Parse(f.GetRequestURL())
if err != nil {
return err
}
t = sms.NewRecoveryCodeValid(s.deps, &sms.RecoveryCodeValidModel{
To: code.RecoveryAddress.Value,
RecoveryCode: codeString,
Identity: model,
RequestURL: f.GetRequestURL(),
RequestURLDomain: u.Hostname(),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
UserRequestHeaders: hook.RemoveDisallowedHeaders(requestHeader, s.deps.Config().WebhookHeaderAllowlist(ctx)),
})
default:
return errors.WithStack(herodot.ErrInternalServerError().WithReasonf("Expected email or sms but got %s", code.RecoveryAddress.Via))
}
return s.send(ctx, code.RecoveryAddress.Via, t)
}
// SendVerificationCode sends a verification code & link to the specified address
//
// 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 string, to string) error {
s.deps.Logger().
WithField("via", via).
WithSensitiveField("address", to).
Debug("Preparing verification code.")
address, err := s.deps.IdentityPool().FindVerifiableAddressByValue(ctx, via, to)
if errors.Is(err, sqlcon.ErrNoRows()) {
notifyUnknownRecipients := s.deps.Config().SelfServiceFlowVerificationNotifyUnknownRecipients(ctx)
s.deps.Logger().
WithField("via", via).
WithField("strategy", "code").
WithSensitiveField("email_address", to).
WithField("was_notified", notifyUnknownRecipients).
Info("Address verification was requested for an unknown address.")
transientPayload, err := x.ParseRawMessageOrEmpty(f.GetTransientPayload())
if err != nil {
return errors.WithStack(err)
}
if !notifyUnknownRecipients || via != identity.AddressTypeEmail {
// Only send unknown-address notifications via email. SMS costs money per
// message, so we skip notification for unknown phone numbers.
} else if err := s.send(ctx, via, email.NewVerificationCodeInvalid(s.deps, &email.VerificationCodeInvalidModel{
To: to,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
})); err != nil {
return err
}
return errors.WithStack(ErrUnknownAddress())
} else if err != nil {
return err
}
rawCode := GenerateCode()
if _, err = s.deps.VerificationCodePersister().CreateVerificationCode(ctx, &CreateVerificationCodeParams{
RawCode: rawCode,
ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx),
VerifiableAddress: address,
FlowID: f.ID,
}); err != nil {
return err
}
// Get the identity associated with the recovery address
i, err := s.deps.IdentityPool().GetIdentity(ctx, address.IdentityID, identity.ExpandDefault)
if err != nil {
return err
}
if err := s.SendVerificationCodeTo(ctx, f, i, rawCode, address); err != nil {
return err
}
address.Status = identity.VerifiableAddressStatusSent
return s.deps.PrivilegedIdentityPool().UpdateVerifiableAddress(ctx, address, "status")
}
func (s *Sender) constructVerificationLink(ctx context.Context, f *verification.Flow, codeStr string) string {
return urlx.CopyWithQuery(
urlx.AppendPaths(x.CourierBaseURL(f.GetCourierBaseURL(), s.deps.Config().SelfPublicURL(ctx)), verification.RouteSubmitFlow),
url.Values{
"flow": {f.ID.String()},
"code": {codeStr},
}).String()
}
func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flow, i *identity.Identity, codeString string, address identity.VerifiableAddressLike) error {
to, via := address.Address(), address.DeliveryVia()
s.deps.Logger().
WithField("via", via).
WithField("identity_id", i.ID).
WithSensitiveField("email_address", to).
WithSensitiveField("verification_link_token", codeString).
Info("Sending out verification email with verification code.")
model, err := x.StructToMap(i)
if err != nil {
return err
}
transientPayload, err := x.ParseRawMessageOrEmpty(f.GetTransientPayload())
if err != nil {
return errors.WithStack(err)
}
// If the flow was initiated by an OAuth2 login challenge, expose a scoped
// view of the OAuth2 client to the courier templates so that messages can
// be branded per client.
if f.OAuth2LoginChallenge != "" && f.HydraLoginRequest == nil {
hlr, err := s.deps.Hydra().GetLoginRequest(ctx, string(f.OAuth2LoginChallenge))
if err != nil {
return errors.WithStack(err)
}
f.HydraLoginRequest = hlr
}
oauth2LoginRequest := template.NewOAuth2LoginRequest(f.HydraLoginRequest)
var t courier.Template
// TODO: this can likely be abstracted by making templates not specific to the channel they're using
switch via {
case identity.ChannelTypeEmail:
t = email.NewVerificationCodeValid(s.deps, &email.VerificationCodeValidModel{
To: to,
VerificationURL: s.constructVerificationLink(ctx, f, codeString),
Identity: model,
VerificationCode: codeString,
RequestURL: f.GetRequestURL(),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
OAuth2LoginRequest: oauth2LoginRequest,
})
case identity.ChannelTypeSMS:
t = sms.NewVerificationCodeValid(s.deps, &sms.VerificationCodeValidModel{
To: to,
VerificationCode: codeString,
Identity: model,
RequestURL: f.GetRequestURL(),
RequestURLDomain: requestURLDomain(f.GetRequestURL()),
TransientPayload: transientPayload,
ExpiresInMinutes: int(s.deps.Config().SelfServiceCodeMethodLifespan(ctx).Minutes()),
OAuth2LoginRequest: oauth2LoginRequest,
})
default:
return errors.WithStack(herodot.ErrInternalServerError().WithReasonf("Expected email or sms but got %s", via))
}
return s.send(ctx, via, t)
}
func (s *Sender) send(ctx context.Context, via string, t courier.Template) error {
switch f := stringsx.SwitchExact(via); {
case f.AddCase(identity.ChannelTypeEmail):
c, err := s.deps.Courier(ctx)
if err != nil {
return err
}
t, ok := t.(courier.EmailTemplate)
if !ok {
return errors.WithStack(herodot.ErrInternalServerError().WithReasonf("Expected email template but got %T", t))
}
_, err = c.QueueEmail(ctx, t)
return err
case f.AddCase(identity.ChannelTypeSMS):
c, err := s.deps.Courier(ctx)
if err != nil {
return err
}
t, ok := t.(courier.SMSTemplate)
if !ok {
return errors.WithStack(herodot.ErrInternalServerError().WithReasonf("Expected sms template but got %T", t))
}
_, err = c.QueueSMS(ctx, t)
return err
default:
return f.ToUnknownCaseErr()
}
}
// requestURLDomain returns the bare hostname of the flow's request URL. It is
// used to bind the SMS one-time code to its origin for the Web OTP API. The
// result is a best-effort hint: a malformed URL yields an empty string and must
// not block delivery of the code.
func requestURLDomain(rawURL string) string {
u, err := url.Parse(rawURL)
if err != nil {
return ""
}
return u.Hostname()
}
// hackyInferChannel infers the channel (email or sms) based on the address format.
// Once we support arbitrary custom channels, we need to refactor the recovery/verification
// flow to first look up the address, and let the user select the channel if multiple are available.
func hackyInferChannel(addr string) string {
// Inferring the address type like this is a bit hacky, and actually not really necessary.
// That's because `SendRecoveryCode` expects it, but not because it fundamentally is required.
if strings.ContainsRune(addr, '@') {
return identity.AddressTypeEmail
}
return identity.AddressTypeSMS
}

Some files were not shown because too many files have changed in this diff Show More