From b0f433d4cb65d79acba789394d828663e873a833 Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Thu, 27 Aug 2020 14:07:42 +0200 Subject: [PATCH] refactor: rename recovery request to recovery flow As part of this change, fetching a login flow over the public API no longer requires Anti-CSRF cookies to be sent. Partially closes #635 BREAKING CHANGE: Wording has changed from "Self-Service Recovery Request" to "Self-Service Recovery Flow" to follow community feedback and practice already applied in the documentation. Additionally, fetching a recovery flow over the public API no longer requires Anti-CSRF cookies to be sent. This patch renames several important recovery flow endpoints: - `/self-service/browser/flows/recovery` is now `/self-service/recovery/browser` without functional changes. - `/self-service/browser/flows/requests/recovery?request=abcd` is now `/self-service/recovery/flows?id=abcd` and no longer needs anti-CSRF cookies to be available. Additionally, the URL for completing the password and oidc recovery method has been moved. Given that this endpoint is typically not manually called, you can probably ignore this change: - `/self-service/browser/flows/recovery/link?request=abcd` is now `/self-service/recovery/methods/link?flow=abcd` without functional changes. The Recovery UI Endpoint no longer receives a `?request=abcde` query parameter but instead a `?flow=abcde` query parameter. Functionality did not change however. As part of this change SDK methods have been renamed: ``` const kratos = new CommonApi(config.kratos.public) // ... - kratos.completeSelfServiceBrowserRecoveryLinkStrategyFlow(req.query.request) + kratos.completeSelfServiceRecoveryFlowWithLinkMethod(req.query.flow) ``` This patch requires you to run SQL migrations. --- .schema/api.swagger.json | 365 +++++++++--------- driver/registry_default.go | 2 +- driver/registry_default_recovery.go | 2 +- internal/faker.go | 2 +- .../admin/create_recovery_link_responses.go | 8 +- .../httpclient/client/common/common_client.go | 80 ++-- ...ice_browser_recovery_request_parameters.go | 142 ------- ...vice_browser_recovery_request_responses.go | 225 ----------- ...t_self_service_recovery_flow_parameters.go | 142 +++++++ ...et_self_service_recovery_flow_responses.go | 186 +++++++++ ..._recovery_link_strategy_flow_parameters.go | 205 ---------- ...r_recovery_link_strategy_flow_responses.go | 97 ----- ...covery_flow_with_link_method_parameters.go | 205 ++++++++++ ...ecovery_flow_with_link_method_responses.go | 97 +++++ ...e_self_service_recovery_flow_parameters.go | 112 ------ ...ze_self_service_recovery_flow_responses.go | 97 ----- ...ervice_recovery_via_api_flow_parameters.go | 112 ++++++ ...service_recovery_via_api_flow_responses.go | 147 +++++++ ...ce_recovery_via_browser_flow_parameters.go | 112 ++++++ ...ice_recovery_via_browser_flow_responses.go | 97 +++++ .../httpclient/client/public/public_client.go | 141 ++++--- internal/httpclient/models/recovery_flow.go | 23 ++ .../httpclient/models/recovery_flow_method.go | 2 +- ...very_link_response.go => recovery_link.go} | 20 +- .../models/request_method_config.go | 128 ------ internal/testhelpers/selfservice_recovery.go | 33 +- persistence/reference.go | 2 +- persistence/sql/migratest/migration_test.go | 2 +- persistence/sql/persister_recovery.go | 10 +- selfservice/flow/recovery/error.go | 115 ++++-- selfservice/flow/recovery/error_test.go | 250 ++++++++++++ .../flow/recovery/{request.go => flow.go} | 72 ++-- .../{request_method.go => flow_method.go} | 30 +- .../{request_test.go => flow_test.go} | 7 +- selfservice/flow/recovery/handler.go | 153 +++++--- selfservice/flow/recovery/handler_test.go | 202 ++++++---- selfservice/flow/recovery/persistence.go | 91 +++-- selfservice/hook/session_issuer_test.go | 3 +- .../strategy/oidc/strategy_settings_test.go | 2 +- .../recoverytoken/persister_conformity.go | 4 +- .../strategy/recoverytoken/strategy.go | 44 +-- text/message_recovery.go | 14 +- 42 files changed, 2184 insertions(+), 1599 deletions(-) delete mode 100644 internal/httpclient/client/common/get_self_service_browser_recovery_request_parameters.go delete mode 100644 internal/httpclient/client/common/get_self_service_browser_recovery_request_responses.go create mode 100644 internal/httpclient/client/common/get_self_service_recovery_flow_parameters.go create mode 100644 internal/httpclient/client/common/get_self_service_recovery_flow_responses.go delete mode 100644 internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_parameters.go delete mode 100644 internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_responses.go create mode 100644 internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_parameters.go create mode 100644 internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_responses.go delete mode 100644 internal/httpclient/client/public/initialize_self_service_recovery_flow_parameters.go delete mode 100644 internal/httpclient/client/public/initialize_self_service_recovery_flow_responses.go create mode 100644 internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_parameters.go create mode 100644 internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_responses.go create mode 100644 internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_parameters.go create mode 100644 internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_responses.go rename internal/httpclient/models/{create_recovery_link_response.go => recovery_link.go} (69%) delete mode 100644 internal/httpclient/models/request_method_config.go create mode 100644 selfservice/flow/recovery/error_test.go rename selfservice/flow/recovery/{request.go => flow.go} (71%) rename selfservice/flow/recovery/{request_method.go => flow_method.go} (71%) rename selfservice/flow/recovery/{request_test.go => flow_test.go} (73%) diff --git a/.schema/api.swagger.json b/.schema/api.swagger.json index c68225f3339..7eef254d47e 100755 --- a/.schema/api.swagger.json +++ b/.schema/api.swagger.json @@ -362,9 +362,9 @@ ], "responses": { "200": { - "description": "createRecoveryLinkResponse", + "description": "recoveryLink", "schema": { - "$ref": "#/definitions/createRecoveryLinkResponse" + "$ref": "#/definitions/recoveryLink" } }, "400": { @@ -460,81 +460,6 @@ } } }, - "/self-service/browser/flows/recovery": { - "get": { - "description": "This endpoint initializes a browser-based account recovery flow. Once initialized, the browser will be redirected to\n`selfservice.flows.recovery.ui_url` with the request ID set as a query parameter. If a valid user session exists, the request\nis aborted.\n\n\u003e This endpoint is NOT INTENDED for API clients and only works\nwith browsers (Chrome, Firefox, ...).\n\nMore information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery).", - "schemes": [ - "http", - "https" - ], - "tags": [ - "public" - ], - "summary": "Initialize browser-based account recovery flow", - "operationId": "initializeSelfServiceRecoveryFlow", - "responses": { - "302": { - "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." - }, - "500": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - } - } - } - }, - "/self-service/browser/flows/recovery/link": { - "post": { - "description": "\u003e This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...) and HTML Forms.\n\nMore information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery).", - "consumes": [ - "application/x-www-form-urlencoded" - ], - "schemes": [ - "http", - "https" - ], - "tags": [ - "public" - ], - "summary": "Complete the browser-based recovery flow using a recovery link", - "operationId": "completeSelfServiceBrowserRecoveryLinkStrategyFlow", - "parameters": [ - { - "description": "Email to Recover\n\nNeeds to be set when initiating the flow. If the email is a registered\nrecovery email, a recovery link will be sent. If the email is not known,\na email with details on what happened will be sent instead.", - "name": "email", - "in": "body", - "schema": { - "type": "string" - } - }, - { - "type": "string", - "description": "Recovery Token\n\nThe recovery token which completes the recovery request. If the token\nis invalid (e.g. expired) an error will be shown to the end-user.", - "name": "token", - "in": "query" - }, - { - "type": "string", - "description": "Recovery Request ID", - "name": "request", - "in": "query" - } - ], - "responses": { - "302": { - "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." - }, - "500": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - } - } - } - }, "/self-service/browser/flows/registration/strategies/oidc/settings/connections": { "post": { "description": "This endpoint completes a browser-based settings flow. This is usually achieved by POSTing data to this\nendpoint.\n\n\u003e This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...) and HTML Forms.\n\nMore information can be found at [ORY Kratos User Settings \u0026 Profile Management Documentation](../self-service/flows/user-settings).", @@ -564,66 +489,6 @@ } } }, - "/self-service/browser/flows/requests/recovery": { - "get": { - "description": "When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required\nfor checking the auth session. To prevent scanning attacks, the public endpoint does not return 404 status codes\nbut instead 403 or 500.\n\nMore information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery).", - "produces": [ - "application/json" - ], - "schemes": [ - "http", - "https" - ], - "tags": [ - "common", - "public", - "admin" - ], - "summary": "Get the request context of browser-based recovery flows", - "operationId": "getSelfServiceBrowserRecoveryRequest", - "parameters": [ - { - "type": "string", - "description": "Request is the Login Request ID\n\nThe value for this parameter comes from `request` URL Query parameter sent to your\napplication (e.g. `/recover?request=abcde`).", - "name": "request", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "recoveryFlow", - "schema": { - "$ref": "#/definitions/recoveryFlow" - } - }, - "403": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - }, - "404": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - }, - "410": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - }, - "500": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - } - } - } - }, "/self-service/browser/flows/requests/verification": { "get": { "description": "When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required\nfor checking the auth session. To prevent scanning attacks, the public endpoint does not return 404 status codes\nbut instead 403 or 500.\n\nMore information can be found at [ORY Kratos Email and Phone Verification Documentation](https://www.ory.sh/docs/kratos/selfservice/flows/verify-email-account-activation).", @@ -1055,6 +920,169 @@ } } }, + "/self-service/recovery/api": { + "get": { + "description": "This endpoint initiates a recovery flow for API clients such as mobile devices, smart TVs, and so on.\n\nIf a valid provided session cookie or session token is provided, a 400 Bad Request error.\n\nTo fetch an existing recovery flow call `/self-service/recovery/flows?flow=\u003cflow_id\u003e`.\n\n:::warning\n\nYou MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server\nPages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make\nyou vulnerable to a variety of CSRF attacks.\n\nThis endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...).\n\n:::\n\nMore information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery).", + "schemes": [ + "http", + "https" + ], + "tags": [ + "public" + ], + "summary": "Initialize Login Flow for API Clients", + "operationId": "initializeSelfServiceRecoveryViaAPIFlow", + "responses": { + "200": { + "description": "loginFlow", + "schema": { + "$ref": "#/definitions/loginFlow" + } + }, + "400": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + }, + "500": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + } + } + } + }, + "/self-service/recovery/browser": { + "get": { + "description": "This endpoint initializes a browser-based account recovery flow. Once initialized, the browser will be redirected to\n`selfservice.flows.recovery.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session\nexists, the browser is returned to the configured return URL.\n\nThis endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...).\n\nMore information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery).", + "schemes": [ + "http", + "https" + ], + "tags": [ + "public" + ], + "summary": "Initialize Recovery Flow for Browser Clients", + "operationId": "initializeSelfServiceRecoveryViaBrowserFlow", + "responses": { + "302": { + "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." + }, + "500": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + } + } + } + }, + "/self-service/recovery/flows": { + "get": { + "description": "This endpoint returns a recovery flow's context with, for example, error details and other information.\n\nMore information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery).", + "produces": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "tags": [ + "common", + "public", + "admin" + ], + "summary": "Get information about a recovery flow", + "operationId": "getSelfServiceRecoveryFlow", + "parameters": [ + { + "type": "string", + "description": "The Flow ID\n\nThe value for this parameter comes from `request` URL Query parameter sent to your\napplication (e.g. `/recovery?flow=abcde`).", + "name": "id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "recoveryFlow", + "schema": { + "$ref": "#/definitions/recoveryFlow" + } + }, + "404": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + }, + "410": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + }, + "500": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + } + } + } + }, + "/self-service/recovery/methods/link": { + "post": { + "description": "\u003e This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...) and HTML Forms.\n\nMore information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery).", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "schemes": [ + "http", + "https" + ], + "tags": [ + "public" + ], + "summary": "Complete the browser-based recovery flow using a recovery link", + "operationId": "completeSelfServiceRecoveryFlowWithLinkMethod", + "parameters": [ + { + "description": "Email to Recover\n\nNeeds to be set when initiating the flow. If the email is a registered\nrecovery email, a recovery link will be sent. If the email is not known,\na email with details on what happened will be sent instead.", + "name": "email", + "in": "body", + "schema": { + "type": "string" + } + }, + { + "type": "string", + "description": "Recovery Token\n\nThe recovery token which completes the recovery request. If the token\nis invalid (e.g. expired) an error will be shown to the end-user.", + "name": "token", + "in": "query" + }, + { + "type": "string", + "description": "The Flow ID", + "name": "flow", + "in": "query" + } + ], + "responses": { + "302": { + "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." + }, + "500": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + } + } + } + }, "/self-service/registration/api": { "get": { "description": "This endpoint initiates a registration flow for API clients such as mobile devices, smart TVs, and so on.\n\nIf a valid provided session cookie or session token is provided, a 400 Bad Request error\nwill be returned unless the URL query parameter `?refresh=true` is set.\n\nTo fetch an existing registration flow call `/self-service/registration/flows?flow=\u003cflow_id\u003e`.\n\n:::warning\n\nYou MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server\nPages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make\nyou vulnerable to a variety of CSRF attacks.\n\nThis endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...).\n\n:::\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", @@ -1660,30 +1688,6 @@ "RecoveryAddressType": { "type": "string" }, - "RequestMethodConfig": { - "type": "object", - "required": [ - "action", - "method", - "fields" - ], - "properties": { - "action": { - "description": "Action should be used as the form action URL `\u003cform action=\"{{ .Action }}\" method=\"post\"\u003e`.", - "type": "string" - }, - "fields": { - "$ref": "#/definitions/formFields" - }, - "messages": { - "$ref": "#/definitions/Messages" - }, - "method": { - "description": "Method is the form method (e.g. POST)", - "type": "string" - } - } - }, "SettingsFlowPayload": { "type": "object", "properties": { @@ -1747,23 +1751,6 @@ "VerifiableAddressType": { "type": "string" }, - "createRecoveryLinkResponse": { - "type": "object", - "required": [ - "recovery_link" - ], - "properties": { - "expires_at": { - "description": "Recovery Link Expires At\n\nThe timestamp when the recovery link expires.", - "type": "string", - "format": "date-time" - }, - "recovery_link": { - "description": "Recovery Link\n\nThis link can be used to recover the account.", - "type": "string" - } - } - }, "errorContainer": { "type": "object", "required": [ @@ -2072,6 +2059,9 @@ }, "state": { "$ref": "#/definitions/State" + }, + "type": { + "$ref": "#/definitions/Type" } } }, @@ -2079,7 +2069,7 @@ "type": "object", "properties": { "config": { - "$ref": "#/definitions/RequestMethodConfig" + "$ref": "#/definitions/loginFlowMethodConfig" }, "method": { "description": "Method contains the request credentials type.", @@ -2087,6 +2077,23 @@ } } }, + "recoveryLink": { + "type": "object", + "required": [ + "recovery_link" + ], + "properties": { + "expires_at": { + "description": "Recovery Link Expires At\n\nThe timestamp when the recovery link expires.", + "type": "string", + "format": "date-time" + }, + "recovery_link": { + "description": "Recovery Link\n\nThis link can be used to recover the account.", + "type": "string" + } + } + }, "registrationFlow": { "type": "object", "required": [ diff --git a/driver/registry_default.go b/driver/registry_default.go index 395ca6719db..38674781714 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -486,7 +486,7 @@ func (m *RegistryDefault) RegistrationFlowPersister() registration.FlowPersister return m.persister } -func (m *RegistryDefault) RecoveryRequestPersister() recovery.RequestPersister { +func (m *RegistryDefault) RecoveryFlowPersister() recovery.FlowPersister { return m.persister } diff --git a/driver/registry_default_recovery.go b/driver/registry_default_recovery.go index 56a93035669..234afea741c 100644 --- a/driver/registry_default_recovery.go +++ b/driver/registry_default_recovery.go @@ -4,7 +4,7 @@ import ( "github.com/ory/kratos/selfservice/flow/recovery" ) -func (m *RegistryDefault) RecoveryRequestErrorHandler() *recovery.ErrorHandler { +func (m *RegistryDefault) RecoveryFlowErrorHandler() *recovery.ErrorHandler { if m.selfserviceRecoveryErrorHandler == nil { m.selfserviceRecoveryErrorHandler = recovery.NewErrorHandler(m, m.c) } diff --git a/internal/faker.go b/internal/faker.go index c951c91b93c..a51c5db53fa 100644 --- a/internal/faker.go +++ b/internal/faker.go @@ -142,7 +142,7 @@ func RegisterFakes() { } methods[ct] = &recovery.FlowMethod{ Method: ct, - Config: &recovery.RequestMethodConfig{RequestMethodConfigurator: &f}, + Config: &recovery.FlowMethodConfig{FlowMethodConfigurator: &f}, } } return methods, nil diff --git a/internal/httpclient/client/admin/create_recovery_link_responses.go b/internal/httpclient/client/admin/create_recovery_link_responses.go index eb651d02aba..faad88b6149 100644 --- a/internal/httpclient/client/admin/create_recovery_link_responses.go +++ b/internal/httpclient/client/admin/create_recovery_link_responses.go @@ -63,23 +63,23 @@ func NewCreateRecoveryLinkOK() *CreateRecoveryLinkOK { /*CreateRecoveryLinkOK handles this case with default header values. -createRecoveryLinkResponse +recoveryLink */ type CreateRecoveryLinkOK struct { - Payload *models.CreateRecoveryLinkResponse + Payload *models.RecoveryLink } func (o *CreateRecoveryLinkOK) Error() string { return fmt.Sprintf("[POST /recovery/link][%d] createRecoveryLinkOK %+v", 200, o.Payload) } -func (o *CreateRecoveryLinkOK) GetPayload() *models.CreateRecoveryLinkResponse { +func (o *CreateRecoveryLinkOK) GetPayload() *models.RecoveryLink { return o.Payload } func (o *CreateRecoveryLinkOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - o.Payload = new(models.CreateRecoveryLinkResponse) + o.Payload = new(models.RecoveryLink) // response payload if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { diff --git a/internal/httpclient/client/common/common_client.go b/internal/httpclient/client/common/common_client.go index 7c6a41b2128..336d4462ef6 100644 --- a/internal/httpclient/client/common/common_client.go +++ b/internal/httpclient/client/common/common_client.go @@ -29,12 +29,12 @@ type Client struct { type ClientService interface { GetSchema(params *GetSchemaParams) (*GetSchemaOK, error) - GetSelfServiceBrowserRecoveryRequest(params *GetSelfServiceBrowserRecoveryRequestParams) (*GetSelfServiceBrowserRecoveryRequestOK, error) - GetSelfServiceError(params *GetSelfServiceErrorParams) (*GetSelfServiceErrorOK, error) GetSelfServiceLoginFlow(params *GetSelfServiceLoginFlowParams) (*GetSelfServiceLoginFlowOK, error) + GetSelfServiceRecoveryFlow(params *GetSelfServiceRecoveryFlowParams) (*GetSelfServiceRecoveryFlowOK, error) + GetSelfServiceRegistrationFlow(params *GetSelfServiceRegistrationFlowParams) (*GetSelfServiceRegistrationFlowOK, error) GetSelfServiceSettingsFlow(params *GetSelfServiceSettingsFlowParams) (*GetSelfServiceSettingsFlowOK, error) @@ -85,125 +85,123 @@ func (a *Client) GetSchema(params *GetSchemaParams) (*GetSchemaOK, error) { } /* - GetSelfServiceBrowserRecoveryRequest gets the request context of browser based recovery flows + GetSelfServiceError gets user facing self service errors - When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required -for checking the auth session. To prevent scanning attacks, the public endpoint does not return 404 status codes -but instead 403 or 500. + This endpoint returns the error associated with a user-facing self service errors. -More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). +When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required for CSRF to work. To prevent +token scanning attacks, the public endpoint does not return 404 status codes. + +This endpoint supports stub values to help you implement the error UI: + +`?error=stub:500` - returns a stub 500 (Internal Server Error) error. + +More information can be found at [ORY Kratos User User Facing Error Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-facing-errors). */ -func (a *Client) GetSelfServiceBrowserRecoveryRequest(params *GetSelfServiceBrowserRecoveryRequestParams) (*GetSelfServiceBrowserRecoveryRequestOK, error) { +func (a *Client) GetSelfServiceError(params *GetSelfServiceErrorParams) (*GetSelfServiceErrorOK, error) { // TODO: Validate the params before sending if params == nil { - params = NewGetSelfServiceBrowserRecoveryRequestParams() + params = NewGetSelfServiceErrorParams() } result, err := a.transport.Submit(&runtime.ClientOperation{ - ID: "getSelfServiceBrowserRecoveryRequest", + ID: "getSelfServiceError", Method: "GET", - PathPattern: "/self-service/browser/flows/requests/recovery", + PathPattern: "/self-service/errors", ProducesMediaTypes: []string{"application/json"}, ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, Schemes: []string{"http", "https"}, Params: params, - Reader: &GetSelfServiceBrowserRecoveryRequestReader{formats: a.formats}, + Reader: &GetSelfServiceErrorReader{formats: a.formats}, Context: params.Context, Client: params.HTTPClient, }) if err != nil { return nil, err } - success, ok := result.(*GetSelfServiceBrowserRecoveryRequestOK) + success, ok := result.(*GetSelfServiceErrorOK) if ok { return success, nil } // unexpected success response // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue - msg := fmt.Sprintf("unexpected success response for getSelfServiceBrowserRecoveryRequest: API contract not enforced by server. Client expected to get an error, but got: %T", result) + msg := fmt.Sprintf("unexpected success response for getSelfServiceError: API contract not enforced by server. Client expected to get an error, but got: %T", result) panic(msg) } /* - GetSelfServiceError gets user facing self service errors - - This endpoint returns the error associated with a user-facing self service errors. - -When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required for CSRF to work. To prevent -token scanning attacks, the public endpoint does not return 404 status codes. - -This endpoint supports stub values to help you implement the error UI: + GetSelfServiceLoginFlow gets information about a login flow -`?error=stub:500` - returns a stub 500 (Internal Server Error) error. + This endpoint returns a login flow's context with, for example, error details and other information. -More information can be found at [ORY Kratos User User Facing Error Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-facing-errors). +More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). */ -func (a *Client) GetSelfServiceError(params *GetSelfServiceErrorParams) (*GetSelfServiceErrorOK, error) { +func (a *Client) GetSelfServiceLoginFlow(params *GetSelfServiceLoginFlowParams) (*GetSelfServiceLoginFlowOK, error) { // TODO: Validate the params before sending if params == nil { - params = NewGetSelfServiceErrorParams() + params = NewGetSelfServiceLoginFlowParams() } result, err := a.transport.Submit(&runtime.ClientOperation{ - ID: "getSelfServiceError", + ID: "getSelfServiceLoginFlow", Method: "GET", - PathPattern: "/self-service/errors", + PathPattern: "/self-service/login/flows", ProducesMediaTypes: []string{"application/json"}, ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, Schemes: []string{"http", "https"}, Params: params, - Reader: &GetSelfServiceErrorReader{formats: a.formats}, + Reader: &GetSelfServiceLoginFlowReader{formats: a.formats}, Context: params.Context, Client: params.HTTPClient, }) if err != nil { return nil, err } - success, ok := result.(*GetSelfServiceErrorOK) + success, ok := result.(*GetSelfServiceLoginFlowOK) if ok { return success, nil } // unexpected success response // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue - msg := fmt.Sprintf("unexpected success response for getSelfServiceError: API contract not enforced by server. Client expected to get an error, but got: %T", result) + msg := fmt.Sprintf("unexpected success response for getSelfServiceLoginFlow: API contract not enforced by server. Client expected to get an error, but got: %T", result) panic(msg) } /* - GetSelfServiceLoginFlow gets information about a login flow + GetSelfServiceRecoveryFlow gets information about a recovery flow - This endpoint returns a login flow's context with, for example, error details and other information. + This endpoint returns a recovery flow's context with, for example, error details and other information. -More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). +More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). */ -func (a *Client) GetSelfServiceLoginFlow(params *GetSelfServiceLoginFlowParams) (*GetSelfServiceLoginFlowOK, error) { +func (a *Client) GetSelfServiceRecoveryFlow(params *GetSelfServiceRecoveryFlowParams) (*GetSelfServiceRecoveryFlowOK, error) { // TODO: Validate the params before sending if params == nil { - params = NewGetSelfServiceLoginFlowParams() + params = NewGetSelfServiceRecoveryFlowParams() } result, err := a.transport.Submit(&runtime.ClientOperation{ - ID: "getSelfServiceLoginFlow", + ID: "getSelfServiceRecoveryFlow", Method: "GET", - PathPattern: "/self-service/login/flows", + PathPattern: "/self-service/recovery/flows", ProducesMediaTypes: []string{"application/json"}, ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, Schemes: []string{"http", "https"}, Params: params, - Reader: &GetSelfServiceLoginFlowReader{formats: a.formats}, + Reader: &GetSelfServiceRecoveryFlowReader{formats: a.formats}, Context: params.Context, Client: params.HTTPClient, }) if err != nil { return nil, err } - success, ok := result.(*GetSelfServiceLoginFlowOK) + success, ok := result.(*GetSelfServiceRecoveryFlowOK) if ok { return success, nil } // unexpected success response // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue - msg := fmt.Sprintf("unexpected success response for getSelfServiceLoginFlow: API contract not enforced by server. Client expected to get an error, but got: %T", result) + msg := fmt.Sprintf("unexpected success response for getSelfServiceRecoveryFlow: API contract not enforced by server. Client expected to get an error, but got: %T", result) panic(msg) } diff --git a/internal/httpclient/client/common/get_self_service_browser_recovery_request_parameters.go b/internal/httpclient/client/common/get_self_service_browser_recovery_request_parameters.go deleted file mode 100644 index 0c376eb2828..00000000000 --- a/internal/httpclient/client/common/get_self_service_browser_recovery_request_parameters.go +++ /dev/null @@ -1,142 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package common - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "context" - "net/http" - "time" - - "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" - cr "github.com/go-openapi/runtime/client" - "github.com/go-openapi/strfmt" -) - -// NewGetSelfServiceBrowserRecoveryRequestParams creates a new GetSelfServiceBrowserRecoveryRequestParams object -// with the default values initialized. -func NewGetSelfServiceBrowserRecoveryRequestParams() *GetSelfServiceBrowserRecoveryRequestParams { - var () - return &GetSelfServiceBrowserRecoveryRequestParams{ - - timeout: cr.DefaultTimeout, - } -} - -// NewGetSelfServiceBrowserRecoveryRequestParamsWithTimeout creates a new GetSelfServiceBrowserRecoveryRequestParams object -// with the default values initialized, and the ability to set a timeout on a request -func NewGetSelfServiceBrowserRecoveryRequestParamsWithTimeout(timeout time.Duration) *GetSelfServiceBrowserRecoveryRequestParams { - var () - return &GetSelfServiceBrowserRecoveryRequestParams{ - - timeout: timeout, - } -} - -// NewGetSelfServiceBrowserRecoveryRequestParamsWithContext creates a new GetSelfServiceBrowserRecoveryRequestParams object -// with the default values initialized, and the ability to set a context for a request -func NewGetSelfServiceBrowserRecoveryRequestParamsWithContext(ctx context.Context) *GetSelfServiceBrowserRecoveryRequestParams { - var () - return &GetSelfServiceBrowserRecoveryRequestParams{ - - Context: ctx, - } -} - -// NewGetSelfServiceBrowserRecoveryRequestParamsWithHTTPClient creates a new GetSelfServiceBrowserRecoveryRequestParams object -// with the default values initialized, and the ability to set a custom HTTPClient for a request -func NewGetSelfServiceBrowserRecoveryRequestParamsWithHTTPClient(client *http.Client) *GetSelfServiceBrowserRecoveryRequestParams { - var () - return &GetSelfServiceBrowserRecoveryRequestParams{ - HTTPClient: client, - } -} - -/*GetSelfServiceBrowserRecoveryRequestParams contains all the parameters to send to the API endpoint -for the get self service browser recovery request operation typically these are written to a http.Request -*/ -type GetSelfServiceBrowserRecoveryRequestParams struct { - - /*Request - Request is the Login Request ID - - The value for this parameter comes from `request` URL Query parameter sent to your - application (e.g. `/recover?request=abcde`). - - */ - Request string - - timeout time.Duration - Context context.Context - HTTPClient *http.Client -} - -// WithTimeout adds the timeout to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) WithTimeout(timeout time.Duration) *GetSelfServiceBrowserRecoveryRequestParams { - o.SetTimeout(timeout) - return o -} - -// SetTimeout adds the timeout to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) SetTimeout(timeout time.Duration) { - o.timeout = timeout -} - -// WithContext adds the context to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) WithContext(ctx context.Context) *GetSelfServiceBrowserRecoveryRequestParams { - o.SetContext(ctx) - return o -} - -// SetContext adds the context to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) SetContext(ctx context.Context) { - o.Context = ctx -} - -// WithHTTPClient adds the HTTPClient to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) WithHTTPClient(client *http.Client) *GetSelfServiceBrowserRecoveryRequestParams { - o.SetHTTPClient(client) - return o -} - -// SetHTTPClient adds the HTTPClient to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) SetHTTPClient(client *http.Client) { - o.HTTPClient = client -} - -// WithRequest adds the request to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) WithRequest(request string) *GetSelfServiceBrowserRecoveryRequestParams { - o.SetRequest(request) - return o -} - -// SetRequest adds the request to the get self service browser recovery request params -func (o *GetSelfServiceBrowserRecoveryRequestParams) SetRequest(request string) { - o.Request = request -} - -// WriteToRequest writes these params to a swagger request -func (o *GetSelfServiceBrowserRecoveryRequestParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { - - if err := r.SetTimeout(o.timeout); err != nil { - return err - } - var res []error - - // query param request - qrRequest := o.Request - qRequest := qrRequest - if qRequest != "" { - if err := r.SetQueryParam("request", qRequest); err != nil { - return err - } - } - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} diff --git a/internal/httpclient/client/common/get_self_service_browser_recovery_request_responses.go b/internal/httpclient/client/common/get_self_service_browser_recovery_request_responses.go deleted file mode 100644 index 6f9cd0b6d3a..00000000000 --- a/internal/httpclient/client/common/get_self_service_browser_recovery_request_responses.go +++ /dev/null @@ -1,225 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package common - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "fmt" - "io" - - "github.com/go-openapi/runtime" - "github.com/go-openapi/strfmt" - - "github.com/ory/kratos/internal/httpclient/models" -) - -// GetSelfServiceBrowserRecoveryRequestReader is a Reader for the GetSelfServiceBrowserRecoveryRequest structure. -type GetSelfServiceBrowserRecoveryRequestReader struct { - formats strfmt.Registry -} - -// ReadResponse reads a server response into the received o. -func (o *GetSelfServiceBrowserRecoveryRequestReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { - switch response.Code() { - case 200: - result := NewGetSelfServiceBrowserRecoveryRequestOK() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return result, nil - case 403: - result := NewGetSelfServiceBrowserRecoveryRequestForbidden() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 404: - result := NewGetSelfServiceBrowserRecoveryRequestNotFound() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 410: - result := NewGetSelfServiceBrowserRecoveryRequestGone() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 500: - result := NewGetSelfServiceBrowserRecoveryRequestInternalServerError() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - - default: - return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) - } -} - -// NewGetSelfServiceBrowserRecoveryRequestOK creates a GetSelfServiceBrowserRecoveryRequestOK with default headers values -func NewGetSelfServiceBrowserRecoveryRequestOK() *GetSelfServiceBrowserRecoveryRequestOK { - return &GetSelfServiceBrowserRecoveryRequestOK{} -} - -/*GetSelfServiceBrowserRecoveryRequestOK handles this case with default header values. - -recoveryFlow -*/ -type GetSelfServiceBrowserRecoveryRequestOK struct { - Payload *models.RecoveryFlow -} - -func (o *GetSelfServiceBrowserRecoveryRequestOK) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/recovery][%d] getSelfServiceBrowserRecoveryRequestOK %+v", 200, o.Payload) -} - -func (o *GetSelfServiceBrowserRecoveryRequestOK) GetPayload() *models.RecoveryFlow { - return o.Payload -} - -func (o *GetSelfServiceBrowserRecoveryRequestOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.RecoveryFlow) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRecoveryRequestForbidden creates a GetSelfServiceBrowserRecoveryRequestForbidden with default headers values -func NewGetSelfServiceBrowserRecoveryRequestForbidden() *GetSelfServiceBrowserRecoveryRequestForbidden { - return &GetSelfServiceBrowserRecoveryRequestForbidden{} -} - -/*GetSelfServiceBrowserRecoveryRequestForbidden handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRecoveryRequestForbidden struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRecoveryRequestForbidden) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/recovery][%d] getSelfServiceBrowserRecoveryRequestForbidden %+v", 403, o.Payload) -} - -func (o *GetSelfServiceBrowserRecoveryRequestForbidden) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRecoveryRequestForbidden) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRecoveryRequestNotFound creates a GetSelfServiceBrowserRecoveryRequestNotFound with default headers values -func NewGetSelfServiceBrowserRecoveryRequestNotFound() *GetSelfServiceBrowserRecoveryRequestNotFound { - return &GetSelfServiceBrowserRecoveryRequestNotFound{} -} - -/*GetSelfServiceBrowserRecoveryRequestNotFound handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRecoveryRequestNotFound struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRecoveryRequestNotFound) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/recovery][%d] getSelfServiceBrowserRecoveryRequestNotFound %+v", 404, o.Payload) -} - -func (o *GetSelfServiceBrowserRecoveryRequestNotFound) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRecoveryRequestNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRecoveryRequestGone creates a GetSelfServiceBrowserRecoveryRequestGone with default headers values -func NewGetSelfServiceBrowserRecoveryRequestGone() *GetSelfServiceBrowserRecoveryRequestGone { - return &GetSelfServiceBrowserRecoveryRequestGone{} -} - -/*GetSelfServiceBrowserRecoveryRequestGone handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRecoveryRequestGone struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRecoveryRequestGone) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/recovery][%d] getSelfServiceBrowserRecoveryRequestGone %+v", 410, o.Payload) -} - -func (o *GetSelfServiceBrowserRecoveryRequestGone) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRecoveryRequestGone) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRecoveryRequestInternalServerError creates a GetSelfServiceBrowserRecoveryRequestInternalServerError with default headers values -func NewGetSelfServiceBrowserRecoveryRequestInternalServerError() *GetSelfServiceBrowserRecoveryRequestInternalServerError { - return &GetSelfServiceBrowserRecoveryRequestInternalServerError{} -} - -/*GetSelfServiceBrowserRecoveryRequestInternalServerError handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRecoveryRequestInternalServerError struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRecoveryRequestInternalServerError) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/recovery][%d] getSelfServiceBrowserRecoveryRequestInternalServerError %+v", 500, o.Payload) -} - -func (o *GetSelfServiceBrowserRecoveryRequestInternalServerError) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRecoveryRequestInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} diff --git a/internal/httpclient/client/common/get_self_service_recovery_flow_parameters.go b/internal/httpclient/client/common/get_self_service_recovery_flow_parameters.go new file mode 100644 index 00000000000..134b6cfa7ac --- /dev/null +++ b/internal/httpclient/client/common/get_self_service_recovery_flow_parameters.go @@ -0,0 +1,142 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package common + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewGetSelfServiceRecoveryFlowParams creates a new GetSelfServiceRecoveryFlowParams object +// with the default values initialized. +func NewGetSelfServiceRecoveryFlowParams() *GetSelfServiceRecoveryFlowParams { + var () + return &GetSelfServiceRecoveryFlowParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewGetSelfServiceRecoveryFlowParamsWithTimeout creates a new GetSelfServiceRecoveryFlowParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewGetSelfServiceRecoveryFlowParamsWithTimeout(timeout time.Duration) *GetSelfServiceRecoveryFlowParams { + var () + return &GetSelfServiceRecoveryFlowParams{ + + timeout: timeout, + } +} + +// NewGetSelfServiceRecoveryFlowParamsWithContext creates a new GetSelfServiceRecoveryFlowParams object +// with the default values initialized, and the ability to set a context for a request +func NewGetSelfServiceRecoveryFlowParamsWithContext(ctx context.Context) *GetSelfServiceRecoveryFlowParams { + var () + return &GetSelfServiceRecoveryFlowParams{ + + Context: ctx, + } +} + +// NewGetSelfServiceRecoveryFlowParamsWithHTTPClient creates a new GetSelfServiceRecoveryFlowParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewGetSelfServiceRecoveryFlowParamsWithHTTPClient(client *http.Client) *GetSelfServiceRecoveryFlowParams { + var () + return &GetSelfServiceRecoveryFlowParams{ + HTTPClient: client, + } +} + +/*GetSelfServiceRecoveryFlowParams contains all the parameters to send to the API endpoint +for the get self service recovery flow operation typically these are written to a http.Request +*/ +type GetSelfServiceRecoveryFlowParams struct { + + /*ID + The Flow ID + + The value for this parameter comes from `request` URL Query parameter sent to your + application (e.g. `/recovery?flow=abcde`). + + */ + ID string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) WithTimeout(timeout time.Duration) *GetSelfServiceRecoveryFlowParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) WithContext(ctx context.Context) *GetSelfServiceRecoveryFlowParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) WithHTTPClient(client *http.Client) *GetSelfServiceRecoveryFlowParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithID adds the id to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) WithID(id string) *GetSelfServiceRecoveryFlowParams { + o.SetID(id) + return o +} + +// SetID adds the id to the get self service recovery flow params +func (o *GetSelfServiceRecoveryFlowParams) SetID(id string) { + o.ID = id +} + +// WriteToRequest writes these params to a swagger request +func (o *GetSelfServiceRecoveryFlowParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // query param id + qrID := o.ID + qID := qrID + if qID != "" { + if err := r.SetQueryParam("id", qID); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/internal/httpclient/client/common/get_self_service_recovery_flow_responses.go b/internal/httpclient/client/common/get_self_service_recovery_flow_responses.go new file mode 100644 index 00000000000..9de727e2ba8 --- /dev/null +++ b/internal/httpclient/client/common/get_self_service_recovery_flow_responses.go @@ -0,0 +1,186 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package common + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ory/kratos/internal/httpclient/models" +) + +// GetSelfServiceRecoveryFlowReader is a Reader for the GetSelfServiceRecoveryFlow structure. +type GetSelfServiceRecoveryFlowReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetSelfServiceRecoveryFlowReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewGetSelfServiceRecoveryFlowOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + case 404: + result := NewGetSelfServiceRecoveryFlowNotFound() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + case 410: + result := NewGetSelfServiceRecoveryFlowGone() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + case 500: + result := NewGetSelfServiceRecoveryFlowInternalServerError() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + + default: + return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) + } +} + +// NewGetSelfServiceRecoveryFlowOK creates a GetSelfServiceRecoveryFlowOK with default headers values +func NewGetSelfServiceRecoveryFlowOK() *GetSelfServiceRecoveryFlowOK { + return &GetSelfServiceRecoveryFlowOK{} +} + +/*GetSelfServiceRecoveryFlowOK handles this case with default header values. + +recoveryFlow +*/ +type GetSelfServiceRecoveryFlowOK struct { + Payload *models.RecoveryFlow +} + +func (o *GetSelfServiceRecoveryFlowOK) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/flows][%d] getSelfServiceRecoveryFlowOK %+v", 200, o.Payload) +} + +func (o *GetSelfServiceRecoveryFlowOK) GetPayload() *models.RecoveryFlow { + return o.Payload +} + +func (o *GetSelfServiceRecoveryFlowOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.RecoveryFlow) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewGetSelfServiceRecoveryFlowNotFound creates a GetSelfServiceRecoveryFlowNotFound with default headers values +func NewGetSelfServiceRecoveryFlowNotFound() *GetSelfServiceRecoveryFlowNotFound { + return &GetSelfServiceRecoveryFlowNotFound{} +} + +/*GetSelfServiceRecoveryFlowNotFound handles this case with default header values. + +genericError +*/ +type GetSelfServiceRecoveryFlowNotFound struct { + Payload *models.GenericError +} + +func (o *GetSelfServiceRecoveryFlowNotFound) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/flows][%d] getSelfServiceRecoveryFlowNotFound %+v", 404, o.Payload) +} + +func (o *GetSelfServiceRecoveryFlowNotFound) GetPayload() *models.GenericError { + return o.Payload +} + +func (o *GetSelfServiceRecoveryFlowNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.GenericError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewGetSelfServiceRecoveryFlowGone creates a GetSelfServiceRecoveryFlowGone with default headers values +func NewGetSelfServiceRecoveryFlowGone() *GetSelfServiceRecoveryFlowGone { + return &GetSelfServiceRecoveryFlowGone{} +} + +/*GetSelfServiceRecoveryFlowGone handles this case with default header values. + +genericError +*/ +type GetSelfServiceRecoveryFlowGone struct { + Payload *models.GenericError +} + +func (o *GetSelfServiceRecoveryFlowGone) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/flows][%d] getSelfServiceRecoveryFlowGone %+v", 410, o.Payload) +} + +func (o *GetSelfServiceRecoveryFlowGone) GetPayload() *models.GenericError { + return o.Payload +} + +func (o *GetSelfServiceRecoveryFlowGone) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.GenericError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewGetSelfServiceRecoveryFlowInternalServerError creates a GetSelfServiceRecoveryFlowInternalServerError with default headers values +func NewGetSelfServiceRecoveryFlowInternalServerError() *GetSelfServiceRecoveryFlowInternalServerError { + return &GetSelfServiceRecoveryFlowInternalServerError{} +} + +/*GetSelfServiceRecoveryFlowInternalServerError handles this case with default header values. + +genericError +*/ +type GetSelfServiceRecoveryFlowInternalServerError struct { + Payload *models.GenericError +} + +func (o *GetSelfServiceRecoveryFlowInternalServerError) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/flows][%d] getSelfServiceRecoveryFlowInternalServerError %+v", 500, o.Payload) +} + +func (o *GetSelfServiceRecoveryFlowInternalServerError) GetPayload() *models.GenericError { + return o.Payload +} + +func (o *GetSelfServiceRecoveryFlowInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.GenericError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_parameters.go b/internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_parameters.go deleted file mode 100644 index 88d4a51d76e..00000000000 --- a/internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_parameters.go +++ /dev/null @@ -1,205 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package public - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "context" - "net/http" - "time" - - "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" - cr "github.com/go-openapi/runtime/client" - "github.com/go-openapi/strfmt" -) - -// NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams creates a new CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams object -// with the default values initialized. -func NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams() *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - var () - return &CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams{ - - timeout: cr.DefaultTimeout, - } -} - -// NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParamsWithTimeout creates a new CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams object -// with the default values initialized, and the ability to set a timeout on a request -func NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParamsWithTimeout(timeout time.Duration) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - var () - return &CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams{ - - timeout: timeout, - } -} - -// NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParamsWithContext creates a new CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams object -// with the default values initialized, and the ability to set a context for a request -func NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParamsWithContext(ctx context.Context) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - var () - return &CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams{ - - Context: ctx, - } -} - -// NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParamsWithHTTPClient creates a new CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams object -// with the default values initialized, and the ability to set a custom HTTPClient for a request -func NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParamsWithHTTPClient(client *http.Client) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - var () - return &CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams{ - HTTPClient: client, - } -} - -/*CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams contains all the parameters to send to the API endpoint -for the complete self service browser recovery link strategy flow operation typically these are written to a http.Request -*/ -type CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams struct { - - /*Email - Email to Recover - - Needs to be set when initiating the flow. If the email is a registered - recovery email, a recovery link will be sent. If the email is not known, - a email with details on what happened will be sent instead. - - */ - Email string - /*Request - Recovery Request ID - - */ - Request *string - /*Token - Recovery Token - - The recovery token which completes the recovery request. If the token - is invalid (e.g. expired) an error will be shown to the end-user. - - */ - Token *string - - timeout time.Duration - Context context.Context - HTTPClient *http.Client -} - -// WithTimeout adds the timeout to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) WithTimeout(timeout time.Duration) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - o.SetTimeout(timeout) - return o -} - -// SetTimeout adds the timeout to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) SetTimeout(timeout time.Duration) { - o.timeout = timeout -} - -// WithContext adds the context to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) WithContext(ctx context.Context) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - o.SetContext(ctx) - return o -} - -// SetContext adds the context to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) SetContext(ctx context.Context) { - o.Context = ctx -} - -// WithHTTPClient adds the HTTPClient to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) WithHTTPClient(client *http.Client) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - o.SetHTTPClient(client) - return o -} - -// SetHTTPClient adds the HTTPClient to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) SetHTTPClient(client *http.Client) { - o.HTTPClient = client -} - -// WithEmail adds the email to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) WithEmail(email string) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - o.SetEmail(email) - return o -} - -// SetEmail adds the email to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) SetEmail(email string) { - o.Email = email -} - -// WithRequest adds the request to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) WithRequest(request *string) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - o.SetRequest(request) - return o -} - -// SetRequest adds the request to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) SetRequest(request *string) { - o.Request = request -} - -// WithToken adds the token to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) WithToken(token *string) *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams { - o.SetToken(token) - return o -} - -// SetToken adds the token to the complete self service browser recovery link strategy flow params -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) SetToken(token *string) { - o.Token = token -} - -// WriteToRequest writes these params to a swagger request -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { - - if err := r.SetTimeout(o.timeout); err != nil { - return err - } - var res []error - - if err := r.SetBodyParam(o.Email); err != nil { - return err - } - - if o.Request != nil { - - // query param request - var qrRequest string - if o.Request != nil { - qrRequest = *o.Request - } - qRequest := qrRequest - if qRequest != "" { - if err := r.SetQueryParam("request", qRequest); err != nil { - return err - } - } - - } - - if o.Token != nil { - - // query param token - var qrToken string - if o.Token != nil { - qrToken = *o.Token - } - qToken := qrToken - if qToken != "" { - if err := r.SetQueryParam("token", qToken); err != nil { - return err - } - } - - } - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} diff --git a/internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_responses.go b/internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_responses.go deleted file mode 100644 index e5d0f8bf97f..00000000000 --- a/internal/httpclient/client/public/complete_self_service_browser_recovery_link_strategy_flow_responses.go +++ /dev/null @@ -1,97 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package public - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "fmt" - "io" - - "github.com/go-openapi/runtime" - "github.com/go-openapi/strfmt" - - "github.com/ory/kratos/internal/httpclient/models" -) - -// CompleteSelfServiceBrowserRecoveryLinkStrategyFlowReader is a Reader for the CompleteSelfServiceBrowserRecoveryLinkStrategyFlow structure. -type CompleteSelfServiceBrowserRecoveryLinkStrategyFlowReader struct { - formats strfmt.Registry -} - -// ReadResponse reads a server response into the received o. -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { - switch response.Code() { - case 302: - result := NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 500: - result := NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - - default: - return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) - } -} - -// NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound creates a CompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound with default headers values -func NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound() *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound { - return &CompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound{} -} - -/*CompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound handles this case with default header values. - -Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is -typically 201. -*/ -type CompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound struct { -} - -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound) Error() string { - return fmt.Sprintf("[POST /self-service/browser/flows/recovery/link][%d] completeSelfServiceBrowserRecoveryLinkStrategyFlowFound ", 302) -} - -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - return nil -} - -// NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError creates a CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError with default headers values -func NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError() *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError { - return &CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError{} -} - -/*CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError handles this case with default header values. - -genericError -*/ -type CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError struct { - Payload *models.GenericError -} - -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError) Error() string { - return fmt.Sprintf("[POST /self-service/browser/flows/recovery/link][%d] completeSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError %+v", 500, o.Payload) -} - -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} diff --git a/internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_parameters.go b/internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_parameters.go new file mode 100644 index 00000000000..3981112e6f3 --- /dev/null +++ b/internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_parameters.go @@ -0,0 +1,205 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package public + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewCompleteSelfServiceRecoveryFlowWithLinkMethodParams creates a new CompleteSelfServiceRecoveryFlowWithLinkMethodParams object +// with the default values initialized. +func NewCompleteSelfServiceRecoveryFlowWithLinkMethodParams() *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + var () + return &CompleteSelfServiceRecoveryFlowWithLinkMethodParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewCompleteSelfServiceRecoveryFlowWithLinkMethodParamsWithTimeout creates a new CompleteSelfServiceRecoveryFlowWithLinkMethodParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewCompleteSelfServiceRecoveryFlowWithLinkMethodParamsWithTimeout(timeout time.Duration) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + var () + return &CompleteSelfServiceRecoveryFlowWithLinkMethodParams{ + + timeout: timeout, + } +} + +// NewCompleteSelfServiceRecoveryFlowWithLinkMethodParamsWithContext creates a new CompleteSelfServiceRecoveryFlowWithLinkMethodParams object +// with the default values initialized, and the ability to set a context for a request +func NewCompleteSelfServiceRecoveryFlowWithLinkMethodParamsWithContext(ctx context.Context) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + var () + return &CompleteSelfServiceRecoveryFlowWithLinkMethodParams{ + + Context: ctx, + } +} + +// NewCompleteSelfServiceRecoveryFlowWithLinkMethodParamsWithHTTPClient creates a new CompleteSelfServiceRecoveryFlowWithLinkMethodParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewCompleteSelfServiceRecoveryFlowWithLinkMethodParamsWithHTTPClient(client *http.Client) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + var () + return &CompleteSelfServiceRecoveryFlowWithLinkMethodParams{ + HTTPClient: client, + } +} + +/*CompleteSelfServiceRecoveryFlowWithLinkMethodParams contains all the parameters to send to the API endpoint +for the complete self service recovery flow with link method operation typically these are written to a http.Request +*/ +type CompleteSelfServiceRecoveryFlowWithLinkMethodParams struct { + + /*Email + Email to Recover + + Needs to be set when initiating the flow. If the email is a registered + recovery email, a recovery link will be sent. If the email is not known, + a email with details on what happened will be sent instead. + + */ + Email string + /*Flow + The Flow ID + + */ + Flow *string + /*Token + Recovery Token + + The recovery token which completes the recovery request. If the token + is invalid (e.g. expired) an error will be shown to the end-user. + + */ + Token *string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) WithTimeout(timeout time.Duration) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) WithContext(ctx context.Context) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) WithHTTPClient(client *http.Client) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithEmail adds the email to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) WithEmail(email string) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + o.SetEmail(email) + return o +} + +// SetEmail adds the email to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) SetEmail(email string) { + o.Email = email +} + +// WithFlow adds the flow to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) WithFlow(flow *string) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + o.SetFlow(flow) + return o +} + +// SetFlow adds the flow to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) SetFlow(flow *string) { + o.Flow = flow +} + +// WithToken adds the token to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) WithToken(token *string) *CompleteSelfServiceRecoveryFlowWithLinkMethodParams { + o.SetToken(token) + return o +} + +// SetToken adds the token to the complete self service recovery flow with link method params +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) SetToken(token *string) { + o.Token = token +} + +// WriteToRequest writes these params to a swagger request +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if err := r.SetBodyParam(o.Email); err != nil { + return err + } + + if o.Flow != nil { + + // query param flow + var qrFlow string + if o.Flow != nil { + qrFlow = *o.Flow + } + qFlow := qrFlow + if qFlow != "" { + if err := r.SetQueryParam("flow", qFlow); err != nil { + return err + } + } + + } + + if o.Token != nil { + + // query param token + var qrToken string + if o.Token != nil { + qrToken = *o.Token + } + qToken := qrToken + if qToken != "" { + if err := r.SetQueryParam("token", qToken); err != nil { + return err + } + } + + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_responses.go b/internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_responses.go new file mode 100644 index 00000000000..17322d5961e --- /dev/null +++ b/internal/httpclient/client/public/complete_self_service_recovery_flow_with_link_method_responses.go @@ -0,0 +1,97 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package public + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ory/kratos/internal/httpclient/models" +) + +// CompleteSelfServiceRecoveryFlowWithLinkMethodReader is a Reader for the CompleteSelfServiceRecoveryFlowWithLinkMethod structure. +type CompleteSelfServiceRecoveryFlowWithLinkMethodReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 302: + result := NewCompleteSelfServiceRecoveryFlowWithLinkMethodFound() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + case 500: + result := NewCompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + + default: + return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) + } +} + +// NewCompleteSelfServiceRecoveryFlowWithLinkMethodFound creates a CompleteSelfServiceRecoveryFlowWithLinkMethodFound with default headers values +func NewCompleteSelfServiceRecoveryFlowWithLinkMethodFound() *CompleteSelfServiceRecoveryFlowWithLinkMethodFound { + return &CompleteSelfServiceRecoveryFlowWithLinkMethodFound{} +} + +/*CompleteSelfServiceRecoveryFlowWithLinkMethodFound handles this case with default header values. + +Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is +typically 201. +*/ +type CompleteSelfServiceRecoveryFlowWithLinkMethodFound struct { +} + +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodFound) Error() string { + return fmt.Sprintf("[POST /self-service/recovery/methods/link][%d] completeSelfServiceRecoveryFlowWithLinkMethodFound ", 302) +} + +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + return nil +} + +// NewCompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError creates a CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError with default headers values +func NewCompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError() *CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError { + return &CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError{} +} + +/*CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError handles this case with default header values. + +genericError +*/ +type CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError struct { + Payload *models.GenericError +} + +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError) Error() string { + return fmt.Sprintf("[POST /self-service/recovery/methods/link][%d] completeSelfServiceRecoveryFlowWithLinkMethodInternalServerError %+v", 500, o.Payload) +} + +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError) GetPayload() *models.GenericError { + return o.Payload +} + +func (o *CompleteSelfServiceRecoveryFlowWithLinkMethodInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.GenericError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/internal/httpclient/client/public/initialize_self_service_recovery_flow_parameters.go b/internal/httpclient/client/public/initialize_self_service_recovery_flow_parameters.go deleted file mode 100644 index 0a5b3b892f5..00000000000 --- a/internal/httpclient/client/public/initialize_self_service_recovery_flow_parameters.go +++ /dev/null @@ -1,112 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package public - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "context" - "net/http" - "time" - - "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" - cr "github.com/go-openapi/runtime/client" - "github.com/go-openapi/strfmt" -) - -// NewInitializeSelfServiceRecoveryFlowParams creates a new InitializeSelfServiceRecoveryFlowParams object -// with the default values initialized. -func NewInitializeSelfServiceRecoveryFlowParams() *InitializeSelfServiceRecoveryFlowParams { - - return &InitializeSelfServiceRecoveryFlowParams{ - - timeout: cr.DefaultTimeout, - } -} - -// NewInitializeSelfServiceRecoveryFlowParamsWithTimeout creates a new InitializeSelfServiceRecoveryFlowParams object -// with the default values initialized, and the ability to set a timeout on a request -func NewInitializeSelfServiceRecoveryFlowParamsWithTimeout(timeout time.Duration) *InitializeSelfServiceRecoveryFlowParams { - - return &InitializeSelfServiceRecoveryFlowParams{ - - timeout: timeout, - } -} - -// NewInitializeSelfServiceRecoveryFlowParamsWithContext creates a new InitializeSelfServiceRecoveryFlowParams object -// with the default values initialized, and the ability to set a context for a request -func NewInitializeSelfServiceRecoveryFlowParamsWithContext(ctx context.Context) *InitializeSelfServiceRecoveryFlowParams { - - return &InitializeSelfServiceRecoveryFlowParams{ - - Context: ctx, - } -} - -// NewInitializeSelfServiceRecoveryFlowParamsWithHTTPClient creates a new InitializeSelfServiceRecoveryFlowParams object -// with the default values initialized, and the ability to set a custom HTTPClient for a request -func NewInitializeSelfServiceRecoveryFlowParamsWithHTTPClient(client *http.Client) *InitializeSelfServiceRecoveryFlowParams { - - return &InitializeSelfServiceRecoveryFlowParams{ - HTTPClient: client, - } -} - -/*InitializeSelfServiceRecoveryFlowParams contains all the parameters to send to the API endpoint -for the initialize self service recovery flow operation typically these are written to a http.Request -*/ -type InitializeSelfServiceRecoveryFlowParams struct { - timeout time.Duration - Context context.Context - HTTPClient *http.Client -} - -// WithTimeout adds the timeout to the initialize self service recovery flow params -func (o *InitializeSelfServiceRecoveryFlowParams) WithTimeout(timeout time.Duration) *InitializeSelfServiceRecoveryFlowParams { - o.SetTimeout(timeout) - return o -} - -// SetTimeout adds the timeout to the initialize self service recovery flow params -func (o *InitializeSelfServiceRecoveryFlowParams) SetTimeout(timeout time.Duration) { - o.timeout = timeout -} - -// WithContext adds the context to the initialize self service recovery flow params -func (o *InitializeSelfServiceRecoveryFlowParams) WithContext(ctx context.Context) *InitializeSelfServiceRecoveryFlowParams { - o.SetContext(ctx) - return o -} - -// SetContext adds the context to the initialize self service recovery flow params -func (o *InitializeSelfServiceRecoveryFlowParams) SetContext(ctx context.Context) { - o.Context = ctx -} - -// WithHTTPClient adds the HTTPClient to the initialize self service recovery flow params -func (o *InitializeSelfServiceRecoveryFlowParams) WithHTTPClient(client *http.Client) *InitializeSelfServiceRecoveryFlowParams { - o.SetHTTPClient(client) - return o -} - -// SetHTTPClient adds the HTTPClient to the initialize self service recovery flow params -func (o *InitializeSelfServiceRecoveryFlowParams) SetHTTPClient(client *http.Client) { - o.HTTPClient = client -} - -// WriteToRequest writes these params to a swagger request -func (o *InitializeSelfServiceRecoveryFlowParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { - - if err := r.SetTimeout(o.timeout); err != nil { - return err - } - var res []error - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} diff --git a/internal/httpclient/client/public/initialize_self_service_recovery_flow_responses.go b/internal/httpclient/client/public/initialize_self_service_recovery_flow_responses.go deleted file mode 100644 index 1995abf0e26..00000000000 --- a/internal/httpclient/client/public/initialize_self_service_recovery_flow_responses.go +++ /dev/null @@ -1,97 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package public - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "fmt" - "io" - - "github.com/go-openapi/runtime" - "github.com/go-openapi/strfmt" - - "github.com/ory/kratos/internal/httpclient/models" -) - -// InitializeSelfServiceRecoveryFlowReader is a Reader for the InitializeSelfServiceRecoveryFlow structure. -type InitializeSelfServiceRecoveryFlowReader struct { - formats strfmt.Registry -} - -// ReadResponse reads a server response into the received o. -func (o *InitializeSelfServiceRecoveryFlowReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { - switch response.Code() { - case 302: - result := NewInitializeSelfServiceRecoveryFlowFound() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 500: - result := NewInitializeSelfServiceRecoveryFlowInternalServerError() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - - default: - return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) - } -} - -// NewInitializeSelfServiceRecoveryFlowFound creates a InitializeSelfServiceRecoveryFlowFound with default headers values -func NewInitializeSelfServiceRecoveryFlowFound() *InitializeSelfServiceRecoveryFlowFound { - return &InitializeSelfServiceRecoveryFlowFound{} -} - -/*InitializeSelfServiceRecoveryFlowFound handles this case with default header values. - -Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is -typically 201. -*/ -type InitializeSelfServiceRecoveryFlowFound struct { -} - -func (o *InitializeSelfServiceRecoveryFlowFound) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/recovery][%d] initializeSelfServiceRecoveryFlowFound ", 302) -} - -func (o *InitializeSelfServiceRecoveryFlowFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - return nil -} - -// NewInitializeSelfServiceRecoveryFlowInternalServerError creates a InitializeSelfServiceRecoveryFlowInternalServerError with default headers values -func NewInitializeSelfServiceRecoveryFlowInternalServerError() *InitializeSelfServiceRecoveryFlowInternalServerError { - return &InitializeSelfServiceRecoveryFlowInternalServerError{} -} - -/*InitializeSelfServiceRecoveryFlowInternalServerError handles this case with default header values. - -genericError -*/ -type InitializeSelfServiceRecoveryFlowInternalServerError struct { - Payload *models.GenericError -} - -func (o *InitializeSelfServiceRecoveryFlowInternalServerError) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/recovery][%d] initializeSelfServiceRecoveryFlowInternalServerError %+v", 500, o.Payload) -} - -func (o *InitializeSelfServiceRecoveryFlowInternalServerError) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *InitializeSelfServiceRecoveryFlowInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} diff --git a/internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_parameters.go b/internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_parameters.go new file mode 100644 index 00000000000..3a44eb772fe --- /dev/null +++ b/internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_parameters.go @@ -0,0 +1,112 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package public + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewInitializeSelfServiceRecoveryViaAPIFlowParams creates a new InitializeSelfServiceRecoveryViaAPIFlowParams object +// with the default values initialized. +func NewInitializeSelfServiceRecoveryViaAPIFlowParams() *InitializeSelfServiceRecoveryViaAPIFlowParams { + + return &InitializeSelfServiceRecoveryViaAPIFlowParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewInitializeSelfServiceRecoveryViaAPIFlowParamsWithTimeout creates a new InitializeSelfServiceRecoveryViaAPIFlowParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewInitializeSelfServiceRecoveryViaAPIFlowParamsWithTimeout(timeout time.Duration) *InitializeSelfServiceRecoveryViaAPIFlowParams { + + return &InitializeSelfServiceRecoveryViaAPIFlowParams{ + + timeout: timeout, + } +} + +// NewInitializeSelfServiceRecoveryViaAPIFlowParamsWithContext creates a new InitializeSelfServiceRecoveryViaAPIFlowParams object +// with the default values initialized, and the ability to set a context for a request +func NewInitializeSelfServiceRecoveryViaAPIFlowParamsWithContext(ctx context.Context) *InitializeSelfServiceRecoveryViaAPIFlowParams { + + return &InitializeSelfServiceRecoveryViaAPIFlowParams{ + + Context: ctx, + } +} + +// NewInitializeSelfServiceRecoveryViaAPIFlowParamsWithHTTPClient creates a new InitializeSelfServiceRecoveryViaAPIFlowParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewInitializeSelfServiceRecoveryViaAPIFlowParamsWithHTTPClient(client *http.Client) *InitializeSelfServiceRecoveryViaAPIFlowParams { + + return &InitializeSelfServiceRecoveryViaAPIFlowParams{ + HTTPClient: client, + } +} + +/*InitializeSelfServiceRecoveryViaAPIFlowParams contains all the parameters to send to the API endpoint +for the initialize self service recovery via API flow operation typically these are written to a http.Request +*/ +type InitializeSelfServiceRecoveryViaAPIFlowParams struct { + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the initialize self service recovery via API flow params +func (o *InitializeSelfServiceRecoveryViaAPIFlowParams) WithTimeout(timeout time.Duration) *InitializeSelfServiceRecoveryViaAPIFlowParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the initialize self service recovery via API flow params +func (o *InitializeSelfServiceRecoveryViaAPIFlowParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the initialize self service recovery via API flow params +func (o *InitializeSelfServiceRecoveryViaAPIFlowParams) WithContext(ctx context.Context) *InitializeSelfServiceRecoveryViaAPIFlowParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the initialize self service recovery via API flow params +func (o *InitializeSelfServiceRecoveryViaAPIFlowParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the initialize self service recovery via API flow params +func (o *InitializeSelfServiceRecoveryViaAPIFlowParams) WithHTTPClient(client *http.Client) *InitializeSelfServiceRecoveryViaAPIFlowParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the initialize self service recovery via API flow params +func (o *InitializeSelfServiceRecoveryViaAPIFlowParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WriteToRequest writes these params to a swagger request +func (o *InitializeSelfServiceRecoveryViaAPIFlowParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_responses.go b/internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_responses.go new file mode 100644 index 00000000000..67dddfdb61b --- /dev/null +++ b/internal/httpclient/client/public/initialize_self_service_recovery_via_api_flow_responses.go @@ -0,0 +1,147 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package public + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ory/kratos/internal/httpclient/models" +) + +// InitializeSelfServiceRecoveryViaAPIFlowReader is a Reader for the InitializeSelfServiceRecoveryViaAPIFlow structure. +type InitializeSelfServiceRecoveryViaAPIFlowReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *InitializeSelfServiceRecoveryViaAPIFlowReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewInitializeSelfServiceRecoveryViaAPIFlowOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + case 400: + result := NewInitializeSelfServiceRecoveryViaAPIFlowBadRequest() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + case 500: + result := NewInitializeSelfServiceRecoveryViaAPIFlowInternalServerError() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + + default: + return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) + } +} + +// NewInitializeSelfServiceRecoveryViaAPIFlowOK creates a InitializeSelfServiceRecoveryViaAPIFlowOK with default headers values +func NewInitializeSelfServiceRecoveryViaAPIFlowOK() *InitializeSelfServiceRecoveryViaAPIFlowOK { + return &InitializeSelfServiceRecoveryViaAPIFlowOK{} +} + +/*InitializeSelfServiceRecoveryViaAPIFlowOK handles this case with default header values. + +loginFlow +*/ +type InitializeSelfServiceRecoveryViaAPIFlowOK struct { + Payload *models.LoginFlow +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowOK) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/api][%d] initializeSelfServiceRecoveryViaApiFlowOK %+v", 200, o.Payload) +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowOK) GetPayload() *models.LoginFlow { + return o.Payload +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.LoginFlow) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewInitializeSelfServiceRecoveryViaAPIFlowBadRequest creates a InitializeSelfServiceRecoveryViaAPIFlowBadRequest with default headers values +func NewInitializeSelfServiceRecoveryViaAPIFlowBadRequest() *InitializeSelfServiceRecoveryViaAPIFlowBadRequest { + return &InitializeSelfServiceRecoveryViaAPIFlowBadRequest{} +} + +/*InitializeSelfServiceRecoveryViaAPIFlowBadRequest handles this case with default header values. + +genericError +*/ +type InitializeSelfServiceRecoveryViaAPIFlowBadRequest struct { + Payload *models.GenericError +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowBadRequest) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/api][%d] initializeSelfServiceRecoveryViaApiFlowBadRequest %+v", 400, o.Payload) +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowBadRequest) GetPayload() *models.GenericError { + return o.Payload +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.GenericError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewInitializeSelfServiceRecoveryViaAPIFlowInternalServerError creates a InitializeSelfServiceRecoveryViaAPIFlowInternalServerError with default headers values +func NewInitializeSelfServiceRecoveryViaAPIFlowInternalServerError() *InitializeSelfServiceRecoveryViaAPIFlowInternalServerError { + return &InitializeSelfServiceRecoveryViaAPIFlowInternalServerError{} +} + +/*InitializeSelfServiceRecoveryViaAPIFlowInternalServerError handles this case with default header values. + +genericError +*/ +type InitializeSelfServiceRecoveryViaAPIFlowInternalServerError struct { + Payload *models.GenericError +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowInternalServerError) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/api][%d] initializeSelfServiceRecoveryViaApiFlowInternalServerError %+v", 500, o.Payload) +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowInternalServerError) GetPayload() *models.GenericError { + return o.Payload +} + +func (o *InitializeSelfServiceRecoveryViaAPIFlowInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.GenericError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_parameters.go b/internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_parameters.go new file mode 100644 index 00000000000..68c6b72f842 --- /dev/null +++ b/internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_parameters.go @@ -0,0 +1,112 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package public + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewInitializeSelfServiceRecoveryViaBrowserFlowParams creates a new InitializeSelfServiceRecoveryViaBrowserFlowParams object +// with the default values initialized. +func NewInitializeSelfServiceRecoveryViaBrowserFlowParams() *InitializeSelfServiceRecoveryViaBrowserFlowParams { + + return &InitializeSelfServiceRecoveryViaBrowserFlowParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewInitializeSelfServiceRecoveryViaBrowserFlowParamsWithTimeout creates a new InitializeSelfServiceRecoveryViaBrowserFlowParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewInitializeSelfServiceRecoveryViaBrowserFlowParamsWithTimeout(timeout time.Duration) *InitializeSelfServiceRecoveryViaBrowserFlowParams { + + return &InitializeSelfServiceRecoveryViaBrowserFlowParams{ + + timeout: timeout, + } +} + +// NewInitializeSelfServiceRecoveryViaBrowserFlowParamsWithContext creates a new InitializeSelfServiceRecoveryViaBrowserFlowParams object +// with the default values initialized, and the ability to set a context for a request +func NewInitializeSelfServiceRecoveryViaBrowserFlowParamsWithContext(ctx context.Context) *InitializeSelfServiceRecoveryViaBrowserFlowParams { + + return &InitializeSelfServiceRecoveryViaBrowserFlowParams{ + + Context: ctx, + } +} + +// NewInitializeSelfServiceRecoveryViaBrowserFlowParamsWithHTTPClient creates a new InitializeSelfServiceRecoveryViaBrowserFlowParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewInitializeSelfServiceRecoveryViaBrowserFlowParamsWithHTTPClient(client *http.Client) *InitializeSelfServiceRecoveryViaBrowserFlowParams { + + return &InitializeSelfServiceRecoveryViaBrowserFlowParams{ + HTTPClient: client, + } +} + +/*InitializeSelfServiceRecoveryViaBrowserFlowParams contains all the parameters to send to the API endpoint +for the initialize self service recovery via browser flow operation typically these are written to a http.Request +*/ +type InitializeSelfServiceRecoveryViaBrowserFlowParams struct { + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the initialize self service recovery via browser flow params +func (o *InitializeSelfServiceRecoveryViaBrowserFlowParams) WithTimeout(timeout time.Duration) *InitializeSelfServiceRecoveryViaBrowserFlowParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the initialize self service recovery via browser flow params +func (o *InitializeSelfServiceRecoveryViaBrowserFlowParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the initialize self service recovery via browser flow params +func (o *InitializeSelfServiceRecoveryViaBrowserFlowParams) WithContext(ctx context.Context) *InitializeSelfServiceRecoveryViaBrowserFlowParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the initialize self service recovery via browser flow params +func (o *InitializeSelfServiceRecoveryViaBrowserFlowParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the initialize self service recovery via browser flow params +func (o *InitializeSelfServiceRecoveryViaBrowserFlowParams) WithHTTPClient(client *http.Client) *InitializeSelfServiceRecoveryViaBrowserFlowParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the initialize self service recovery via browser flow params +func (o *InitializeSelfServiceRecoveryViaBrowserFlowParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WriteToRequest writes these params to a swagger request +func (o *InitializeSelfServiceRecoveryViaBrowserFlowParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_responses.go b/internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_responses.go new file mode 100644 index 00000000000..903373f4647 --- /dev/null +++ b/internal/httpclient/client/public/initialize_self_service_recovery_via_browser_flow_responses.go @@ -0,0 +1,97 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package public + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + + "github.com/ory/kratos/internal/httpclient/models" +) + +// InitializeSelfServiceRecoveryViaBrowserFlowReader is a Reader for the InitializeSelfServiceRecoveryViaBrowserFlow structure. +type InitializeSelfServiceRecoveryViaBrowserFlowReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *InitializeSelfServiceRecoveryViaBrowserFlowReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 302: + result := NewInitializeSelfServiceRecoveryViaBrowserFlowFound() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + case 500: + result := NewInitializeSelfServiceRecoveryViaBrowserFlowInternalServerError() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + + default: + return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) + } +} + +// NewInitializeSelfServiceRecoveryViaBrowserFlowFound creates a InitializeSelfServiceRecoveryViaBrowserFlowFound with default headers values +func NewInitializeSelfServiceRecoveryViaBrowserFlowFound() *InitializeSelfServiceRecoveryViaBrowserFlowFound { + return &InitializeSelfServiceRecoveryViaBrowserFlowFound{} +} + +/*InitializeSelfServiceRecoveryViaBrowserFlowFound handles this case with default header values. + +Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is +typically 201. +*/ +type InitializeSelfServiceRecoveryViaBrowserFlowFound struct { +} + +func (o *InitializeSelfServiceRecoveryViaBrowserFlowFound) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/browser][%d] initializeSelfServiceRecoveryViaBrowserFlowFound ", 302) +} + +func (o *InitializeSelfServiceRecoveryViaBrowserFlowFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + return nil +} + +// NewInitializeSelfServiceRecoveryViaBrowserFlowInternalServerError creates a InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError with default headers values +func NewInitializeSelfServiceRecoveryViaBrowserFlowInternalServerError() *InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError { + return &InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError{} +} + +/*InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError handles this case with default header values. + +genericError +*/ +type InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError struct { + Payload *models.GenericError +} + +func (o *InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError) Error() string { + return fmt.Sprintf("[GET /self-service/recovery/browser][%d] initializeSelfServiceRecoveryViaBrowserFlowInternalServerError %+v", 500, o.Payload) +} + +func (o *InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError) GetPayload() *models.GenericError { + return o.Payload +} + +func (o *InitializeSelfServiceRecoveryViaBrowserFlowInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.GenericError) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/internal/httpclient/client/public/public_client.go b/internal/httpclient/client/public/public_client.go index 29ae8c651f4..39282c9955a 100644 --- a/internal/httpclient/client/public/public_client.go +++ b/internal/httpclient/client/public/public_client.go @@ -27,14 +27,14 @@ type Client struct { // ClientService is the interface for Client methods type ClientService interface { - CompleteSelfServiceBrowserRecoveryLinkStrategyFlow(params *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) error - CompleteSelfServiceBrowserSettingsOIDCSettingsFlow(params *CompleteSelfServiceBrowserSettingsOIDCSettingsFlowParams) error CompleteSelfServiceBrowserVerificationFlow(params *CompleteSelfServiceBrowserVerificationFlowParams) error CompleteSelfServiceLoginFlowWithPasswordMethod(params *CompleteSelfServiceLoginFlowWithPasswordMethodParams) (*CompleteSelfServiceLoginFlowWithPasswordMethodOK, error) + CompleteSelfServiceRecoveryFlowWithLinkMethod(params *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) error + CompleteSelfServiceRegistrationFlowWithPasswordMethod(params *CompleteSelfServiceRegistrationFlowWithPasswordMethodParams) (*CompleteSelfServiceRegistrationFlowWithPasswordMethodOK, error) CompleteSelfServiceSettingsFlowWithPasswordMethod(params *CompleteSelfServiceSettingsFlowWithPasswordMethodParams) error @@ -47,7 +47,9 @@ type ClientService interface { InitializeSelfServiceLoginViaBrowserFlow(params *InitializeSelfServiceLoginViaBrowserFlowParams) error - InitializeSelfServiceRecoveryFlow(params *InitializeSelfServiceRecoveryFlowParams) error + InitializeSelfServiceRecoveryViaAPIFlow(params *InitializeSelfServiceRecoveryViaAPIFlowParams) (*InitializeSelfServiceRecoveryViaAPIFlowOK, error) + + InitializeSelfServiceRecoveryViaBrowserFlow(params *InitializeSelfServiceRecoveryViaBrowserFlowParams) error InitializeSelfServiceRegistrationViaBrowserFlow(params *InitializeSelfServiceRegistrationViaBrowserFlowParams) error @@ -62,37 +64,6 @@ type ClientService interface { SetTransport(transport runtime.ClientTransport) } -/* - CompleteSelfServiceBrowserRecoveryLinkStrategyFlow completes the browser based recovery flow using a recovery link - - > This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...) and HTML Forms. - -More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). -*/ -func (a *Client) CompleteSelfServiceBrowserRecoveryLinkStrategyFlow(params *CompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams) error { - // TODO: Validate the params before sending - if params == nil { - params = NewCompleteSelfServiceBrowserRecoveryLinkStrategyFlowParams() - } - - _, err := a.transport.Submit(&runtime.ClientOperation{ - ID: "completeSelfServiceBrowserRecoveryLinkStrategyFlow", - Method: "POST", - PathPattern: "/self-service/browser/flows/recovery/link", - ProducesMediaTypes: []string{"application/json"}, - ConsumesMediaTypes: []string{"application/x-www-form-urlencoded"}, - Schemes: []string{"http", "https"}, - Params: params, - Reader: &CompleteSelfServiceBrowserRecoveryLinkStrategyFlowReader{formats: a.formats}, - Context: params.Context, - Client: params.HTTPClient, - }) - if err != nil { - return err - } - return nil -} - /* CompleteSelfServiceBrowserSettingsOIDCSettingsFlow completes the browser based settings flow for the open ID connect strategy @@ -212,6 +183,37 @@ func (a *Client) CompleteSelfServiceLoginFlowWithPasswordMethod(params *Complete panic(msg) } +/* + CompleteSelfServiceRecoveryFlowWithLinkMethod completes the browser based recovery flow using a recovery link + + > This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...) and HTML Forms. + +More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). +*/ +func (a *Client) CompleteSelfServiceRecoveryFlowWithLinkMethod(params *CompleteSelfServiceRecoveryFlowWithLinkMethodParams) error { + // TODO: Validate the params before sending + if params == nil { + params = NewCompleteSelfServiceRecoveryFlowWithLinkMethodParams() + } + + _, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "completeSelfServiceRecoveryFlowWithLinkMethod", + Method: "POST", + PathPattern: "/self-service/recovery/methods/link", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/x-www-form-urlencoded"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &CompleteSelfServiceRecoveryFlowWithLinkMethodReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return err + } + return nil +} + /* CompleteSelfServiceRegistrationFlowWithPasswordMethod completes registration flow with username email password method @@ -448,32 +450,83 @@ func (a *Client) InitializeSelfServiceLoginViaBrowserFlow(params *InitializeSelf } /* - InitializeSelfServiceRecoveryFlow initializes browser based account recovery flow + InitializeSelfServiceRecoveryViaAPIFlow initializes login flow for API clients + + This endpoint initiates a recovery flow for API clients such as mobile devices, smart TVs, and so on. + +If a valid provided session cookie or session token is provided, a 400 Bad Request error. + +To fetch an existing recovery flow call `/self-service/recovery/flows?flow=`. + +:::warning + +You MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server +Pages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make +you vulnerable to a variety of CSRF attacks. + +This endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...). + +::: + +More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). +*/ +func (a *Client) InitializeSelfServiceRecoveryViaAPIFlow(params *InitializeSelfServiceRecoveryViaAPIFlowParams) (*InitializeSelfServiceRecoveryViaAPIFlowOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewInitializeSelfServiceRecoveryViaAPIFlowParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "initializeSelfServiceRecoveryViaAPIFlow", + Method: "GET", + PathPattern: "/self-service/recovery/api", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &InitializeSelfServiceRecoveryViaAPIFlowReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + success, ok := result.(*InitializeSelfServiceRecoveryViaAPIFlowOK) + if ok { + return success, nil + } + // unexpected success response + // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + msg := fmt.Sprintf("unexpected success response for initializeSelfServiceRecoveryViaAPIFlow: API contract not enforced by server. Client expected to get an error, but got: %T", result) + panic(msg) +} + +/* + InitializeSelfServiceRecoveryViaBrowserFlow initializes recovery flow for browser clients This endpoint initializes a browser-based account recovery flow. Once initialized, the browser will be redirected to -`selfservice.flows.recovery.ui_url` with the request ID set as a query parameter. If a valid user session exists, the request -is aborted. +`selfservice.flows.recovery.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session +exists, the browser is returned to the configured return URL. -> This endpoint is NOT INTENDED for API clients and only works -with browsers (Chrome, Firefox, ...). +This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...). More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). */ -func (a *Client) InitializeSelfServiceRecoveryFlow(params *InitializeSelfServiceRecoveryFlowParams) error { +func (a *Client) InitializeSelfServiceRecoveryViaBrowserFlow(params *InitializeSelfServiceRecoveryViaBrowserFlowParams) error { // TODO: Validate the params before sending if params == nil { - params = NewInitializeSelfServiceRecoveryFlowParams() + params = NewInitializeSelfServiceRecoveryViaBrowserFlowParams() } _, err := a.transport.Submit(&runtime.ClientOperation{ - ID: "initializeSelfServiceRecoveryFlow", + ID: "initializeSelfServiceRecoveryViaBrowserFlow", Method: "GET", - PathPattern: "/self-service/browser/flows/recovery", + PathPattern: "/self-service/recovery/browser", ProducesMediaTypes: []string{"application/json"}, ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, Schemes: []string{"http", "https"}, Params: params, - Reader: &InitializeSelfServiceRecoveryFlowReader{formats: a.formats}, + Reader: &InitializeSelfServiceRecoveryViaBrowserFlowReader{formats: a.formats}, Context: params.Context, Client: params.HTTPClient, }) diff --git a/internal/httpclient/models/recovery_flow.go b/internal/httpclient/models/recovery_flow.go index 5503ca71bcf..8c75ef44f9f 100644 --- a/internal/httpclient/models/recovery_flow.go +++ b/internal/httpclient/models/recovery_flow.go @@ -57,6 +57,9 @@ type RecoveryFlow struct { // state // Required: true State State `json:"state"` + + // type + Type Type `json:"type,omitempty"` } // Validate validates this recovery flow @@ -91,6 +94,10 @@ func (m *RecoveryFlow) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateType(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -190,6 +197,22 @@ func (m *RecoveryFlow) validateState(formats strfmt.Registry) error { return nil } +func (m *RecoveryFlow) validateType(formats strfmt.Registry) error { + + if swag.IsZero(m.Type) { // not required + return nil + } + + if err := m.Type.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("type") + } + return err + } + + return nil +} + // MarshalBinary interface implementation func (m *RecoveryFlow) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/internal/httpclient/models/recovery_flow_method.go b/internal/httpclient/models/recovery_flow_method.go index c0f964aec01..35a0464ff0f 100644 --- a/internal/httpclient/models/recovery_flow_method.go +++ b/internal/httpclient/models/recovery_flow_method.go @@ -17,7 +17,7 @@ import ( type RecoveryFlowMethod struct { // config - Config *RequestMethodConfig `json:"config,omitempty"` + Config *LoginFlowMethodConfig `json:"config,omitempty"` // Method contains the request credentials type. Method string `json:"method,omitempty"` diff --git a/internal/httpclient/models/create_recovery_link_response.go b/internal/httpclient/models/recovery_link.go similarity index 69% rename from internal/httpclient/models/create_recovery_link_response.go rename to internal/httpclient/models/recovery_link.go index 2f7a4c6db95..5991ffc5fbb 100644 --- a/internal/httpclient/models/create_recovery_link_response.go +++ b/internal/httpclient/models/recovery_link.go @@ -12,10 +12,10 @@ import ( "github.com/go-openapi/validate" ) -// CreateRecoveryLinkResponse create recovery link response +// RecoveryLink recovery link // -// swagger:model createRecoveryLinkResponse -type CreateRecoveryLinkResponse struct { +// swagger:model recoveryLink +type RecoveryLink struct { // Recovery Link Expires At // @@ -30,8 +30,8 @@ type CreateRecoveryLinkResponse struct { RecoveryLink *string `json:"recovery_link"` } -// Validate validates this create recovery link response -func (m *CreateRecoveryLinkResponse) Validate(formats strfmt.Registry) error { +// Validate validates this recovery link +func (m *RecoveryLink) Validate(formats strfmt.Registry) error { var res []error if err := m.validateExpiresAt(formats); err != nil { @@ -48,7 +48,7 @@ func (m *CreateRecoveryLinkResponse) Validate(formats strfmt.Registry) error { return nil } -func (m *CreateRecoveryLinkResponse) validateExpiresAt(formats strfmt.Registry) error { +func (m *RecoveryLink) validateExpiresAt(formats strfmt.Registry) error { if swag.IsZero(m.ExpiresAt) { // not required return nil @@ -61,7 +61,7 @@ func (m *CreateRecoveryLinkResponse) validateExpiresAt(formats strfmt.Registry) return nil } -func (m *CreateRecoveryLinkResponse) validateRecoveryLink(formats strfmt.Registry) error { +func (m *RecoveryLink) validateRecoveryLink(formats strfmt.Registry) error { if err := validate.Required("recovery_link", "body", m.RecoveryLink); err != nil { return err @@ -71,7 +71,7 @@ func (m *CreateRecoveryLinkResponse) validateRecoveryLink(formats strfmt.Registr } // MarshalBinary interface implementation -func (m *CreateRecoveryLinkResponse) MarshalBinary() ([]byte, error) { +func (m *RecoveryLink) MarshalBinary() ([]byte, error) { if m == nil { return nil, nil } @@ -79,8 +79,8 @@ func (m *CreateRecoveryLinkResponse) MarshalBinary() ([]byte, error) { } // UnmarshalBinary interface implementation -func (m *CreateRecoveryLinkResponse) UnmarshalBinary(b []byte) error { - var res CreateRecoveryLinkResponse +func (m *RecoveryLink) UnmarshalBinary(b []byte) error { + var res RecoveryLink if err := swag.ReadJSON(b, &res); err != nil { return err } diff --git a/internal/httpclient/models/request_method_config.go b/internal/httpclient/models/request_method_config.go deleted file mode 100644 index 0df596f6c09..00000000000 --- a/internal/httpclient/models/request_method_config.go +++ /dev/null @@ -1,128 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package models - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "github.com/go-openapi/errors" - "github.com/go-openapi/strfmt" - "github.com/go-openapi/swag" - "github.com/go-openapi/validate" -) - -// RequestMethodConfig request method config -// -// swagger:model RequestMethodConfig -type RequestMethodConfig struct { - - // Action should be used as the form action URL `
`. - // Required: true - Action *string `json:"action"` - - // fields - // Required: true - Fields FormFields `json:"fields"` - - // messages - Messages Messages `json:"messages,omitempty"` - - // Method is the form method (e.g. POST) - // Required: true - Method *string `json:"method"` -} - -// Validate validates this request method config -func (m *RequestMethodConfig) Validate(formats strfmt.Registry) error { - var res []error - - if err := m.validateAction(formats); err != nil { - res = append(res, err) - } - - if err := m.validateFields(formats); err != nil { - res = append(res, err) - } - - if err := m.validateMessages(formats); err != nil { - res = append(res, err) - } - - if err := m.validateMethod(formats); err != nil { - res = append(res, err) - } - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} - -func (m *RequestMethodConfig) validateAction(formats strfmt.Registry) error { - - if err := validate.Required("action", "body", m.Action); err != nil { - return err - } - - return nil -} - -func (m *RequestMethodConfig) validateFields(formats strfmt.Registry) error { - - if err := validate.Required("fields", "body", m.Fields); err != nil { - return err - } - - if err := m.Fields.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("fields") - } - return err - } - - return nil -} - -func (m *RequestMethodConfig) validateMessages(formats strfmt.Registry) error { - - if swag.IsZero(m.Messages) { // not required - return nil - } - - if err := m.Messages.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("messages") - } - return err - } - - return nil -} - -func (m *RequestMethodConfig) validateMethod(formats strfmt.Registry) error { - - if err := validate.Required("method", "body", m.Method); err != nil { - return err - } - - return nil -} - -// MarshalBinary interface implementation -func (m *RequestMethodConfig) MarshalBinary() ([]byte, error) { - if m == nil { - return nil, nil - } - return swag.WriteJSON(m) -} - -// UnmarshalBinary interface implementation -func (m *RequestMethodConfig) UnmarshalBinary(b []byte) error { - var res RequestMethodConfig - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *m = res - return nil -} diff --git a/internal/testhelpers/selfservice_recovery.go b/internal/testhelpers/selfservice_recovery.go index 62391c649a1..857ea3cc9b6 100644 --- a/internal/testhelpers/selfservice_recovery.go +++ b/internal/testhelpers/selfservice_recovery.go @@ -16,10 +16,12 @@ import ( "github.com/ory/viper" "github.com/ory/x/pointerx" + "github.com/ory/kratos/driver" "github.com/ory/kratos/driver/configuration" "github.com/ory/kratos/internal/httpclient/client/common" "github.com/ory/kratos/internal/httpclient/models" "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/x" ) func NewRecoveryUITestServer(t *testing.T) *httptest.Server { @@ -39,16 +41,27 @@ func NewRecoveryUITestServer(t *testing.T) *httptest.Server { return ts } -func GetRecoveryRequest(t *testing.T, client *http.Client, ts *httptest.Server) *common.GetSelfServiceBrowserRecoveryRequestOK { +func NewRecoveryUIFlowEchoServer(t *testing.T, reg driver.Registry) *httptest.Server { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + e, err := reg.RecoveryFlowPersister().GetRecoveryFlow(r.Context(), x.ParseUUID(r.URL.Query().Get("flow"))) + require.NoError(t, err) + reg.Writer().Write(w, r, e) + })) + viper.Set(configuration.ViperKeySelfServiceRecoveryUI, ts.URL+"/recovery-ts") + t.Cleanup(ts.Close) + return ts +} + +func GetRecoveryRequest(t *testing.T, client *http.Client, ts *httptest.Server) *common.GetSelfServiceRecoveryFlowOK { publicClient := NewSDKClient(ts) - res, err := client.Get(ts.URL + recovery.PublicRecoveryInitPath) + res, err := client.Get(ts.URL + recovery.RouteInitBrowserFlow) require.NoError(t, err) require.NoError(t, res.Body.Close()) - rs, err := publicClient.Common.GetSelfServiceBrowserRecoveryRequest( - common.NewGetSelfServiceBrowserRecoveryRequestParams().WithHTTPClient(client). - WithRequest(res.Request.URL.Query().Get("request")), + rs, err := publicClient.Common.GetSelfServiceRecoveryFlow( + common.NewGetSelfServiceRecoveryFlowParams().WithHTTPClient(client). + WithID(res.Request.URL.Query().Get("flow")), ) require.NoError(t, err, "%s", res.Request.URL.String()) assert.Empty(t, rs.Payload.Active) @@ -58,10 +71,10 @@ func GetRecoveryRequest(t *testing.T, client *http.Client, ts *httptest.Server) func RecoverySubmitForm( t *testing.T, - f *models.RequestMethodConfig, + f *models.FlowMethodConfig, hc *http.Client, values url.Values, -) (string, *common.GetSelfServiceBrowserRecoveryRequestOK) { +) (string, *common.GetSelfServiceRecoveryFlowOK) { require.NotEmpty(t, f.Action) res, err := hc.PostForm(pointerx.StringR(f.Action), values) @@ -74,9 +87,9 @@ func RecoverySubmitForm( assert.Equal(t, viper.GetString(configuration.ViperKeySelfServiceRecoveryUI), res.Request.URL.Scheme+"://"+res.Request.URL.Host+res.Request.URL.Path, "should end up at the settings URL, used: %s", pointerx.StringR(f.Action)) - rs, err := NewSDKClientFromURL(viper.GetString(configuration.ViperKeyPublicBaseURL)).Common.GetSelfServiceBrowserRecoveryRequest( - common.NewGetSelfServiceBrowserRecoveryRequestParams().WithHTTPClient(hc). - WithRequest(res.Request.URL.Query().Get("request")), + rs, err := NewSDKClientFromURL(viper.GetString(configuration.ViperKeyPublicBaseURL)).Common.GetSelfServiceRecoveryFlow( + common.NewGetSelfServiceRecoveryFlowParams().WithHTTPClient(hc). + WithID(res.Request.URL.Query().Get("flow")), ) require.NoError(t, err) body, err := json.Marshal(rs.Payload) diff --git a/persistence/reference.go b/persistence/reference.go index b4319aa925f..25a5c1a96e2 100644 --- a/persistence/reference.go +++ b/persistence/reference.go @@ -33,7 +33,7 @@ type Persister interface { session.Persister errorx.Persister verification.Persister - recovery.RequestPersister + recovery.FlowPersister recoverytoken.Persister Close(context.Context) error diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index 9e6dc0ef0a3..fbfbc1bedf3 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -156,7 +156,7 @@ func TestMigrations(t *testing.T) { require.NoError(t, c.Select("id").All(&ids)) for _, id := range ids { - actual, err := d.Registry().RecoveryRequestPersister().GetRecoveryRequest(context.Background(), id.ID) + actual, err := d.Registry().RecoveryFlowPersister().GetRecoveryFlow(context.Background(), id.ID) require.NoError(t, err) compareWithFixture(t, actual, "recovery_request", id.ID.String()) } diff --git a/persistence/sql/persister_recovery.go b/persistence/sql/persister_recovery.go index 020f74deae6..b5869ce700f 100644 --- a/persistence/sql/persister_recovery.go +++ b/persistence/sql/persister_recovery.go @@ -15,14 +15,14 @@ import ( "github.com/ory/kratos/selfservice/strategy/recoverytoken" ) -var _ recovery.RequestPersister = new(Persister) +var _ recovery.FlowPersister = new(Persister) var _ recoverytoken.Persister = new(Persister) -func (p Persister) CreateRecoveryRequest(ctx context.Context, r *recovery.Flow) error { +func (p Persister) CreateRecoveryFlow(ctx context.Context, r *recovery.Flow) error { return p.GetConnection(ctx).Eager("MethodsRaw").Create(r) } -func (p Persister) GetRecoveryRequest(ctx context.Context, id uuid.UUID) (*recovery.Flow, error) { +func (p Persister) GetRecoveryFlow(ctx context.Context, id uuid.UUID) (*recovery.Flow, error) { var r recovery.Flow if err := p.GetConnection(ctx).Eager().Find(&r, id); err != nil { return nil, sqlcon.HandleError(err) @@ -35,10 +35,10 @@ func (p Persister) GetRecoveryRequest(ctx context.Context, id uuid.UUID) (*recov return &r, nil } -func (p Persister) UpdateRecoveryRequest(ctx context.Context, r *recovery.Flow) error { +func (p Persister) UpdateRecoveryFlow(ctx context.Context, r *recovery.Flow) error { return p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) error { - rr, err := p.GetRecoveryRequest(ctx, r.ID) + rr, err := p.GetRecoveryFlow(ctx, r.ID) if err != nil { return err } diff --git a/selfservice/flow/recovery/error.go b/selfservice/flow/recovery/error.go index 63f5b96f229..be45c2f59f3 100644 --- a/selfservice/flow/recovery/error.go +++ b/selfservice/flow/recovery/error.go @@ -3,37 +3,54 @@ package recovery import ( "net/http" "net/url" + "time" "github.com/pkg/errors" - "github.com/ory/x/sqlxx" - "github.com/ory/herodot" "github.com/ory/x/urlx" "github.com/ory/kratos/driver/configuration" "github.com/ory/kratos/selfservice/errorx" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/text" "github.com/ory/kratos/x" ) var ( - ErrRequestExpired = herodot.ErrBadRequest. - WithError("recovery request expired"). - WithReasonf(`The recovery request has expired. Please restart the flow.`) - ErrHookAbortRequest = errors.New("aborted recovery hook execution") - ErrRequestNeedsReAuthentication = herodot.ErrForbidden.WithReasonf("The login session is too old and thus not allowed to update these fields. Please re-authenticate.") + ErrAlreadyLoggedIn = herodot.ErrBadRequest.WithReason("A valid session was detected and thus recovery is not possible.") ) +type FlowExpiredError struct { + *herodot.DefaultError + ago time.Duration +} + +func NewFlowExpiredError(at time.Time) *FlowExpiredError { + ago := time.Since(at) + return &FlowExpiredError{ + ago: ago, + DefaultError: herodot.ErrBadRequest. + WithError("recovery flow expired"). + WithReasonf(`The recovery flow has expired. Please restart the flow.`). + WithReasonf("The recovery flow expired %.2f minutes ago, please try again.", ago.Minutes()), + } +} + type ( errorHandlerDependencies interface { errorx.ManagementProvider x.WriterProvider x.LoggingProvider + x.CSRFTokenGeneratorProvider + StrategyProvider RequestPersistenceProvider } - ErrorHandlerProvider interface{ RecoveryRequestErrorHandler() *ErrorHandler } + ErrorHandlerProvider interface { + RecoveryFlowErrorHandler() *ErrorHandler + } ErrorHandler struct { d errorHandlerDependencies @@ -48,45 +65,91 @@ func NewErrorHandler(d errorHandlerDependencies, c configuration.Provider) *Erro } } -func (s *ErrorHandler) HandleRecoveryError( +func (s *ErrorHandler) WriteFlowError( w http.ResponseWriter, r *http.Request, - rr *Flow, + methodName string, + f *Flow, err error, - method string, ) { s.d.Audit(). WithError(err). WithRequest(r). - WithField("recovery_request", rr). + WithField("recovery_flow", f). Info("Encountered self-service recovery error.") - if rr == nil { - s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + if f == nil { + s.forward(w, r, nil, err) return - } else if x.IsJSONRequest(r) { - s.d.Writer().WriteError(w, r, err) + } + + if e := new(FlowExpiredError); errors.As(err, &e) { + // create new flow because the old one is not valid + a, err := NewFlow(s.c.SelfServiceFlowRecoveryRequestLifespan(), s.d.GenerateCSRFToken(r), r, s.d.RecoveryStrategies(), f.Type) + if err != nil { + // failed to create a new session and redirect to it, handle that error as a new one + s.WriteFlowError(w, r, methodName, f, err) + return + } + + a.Messages.Add(text.NewErrorValidationRecoveryFlowExpired(e.ago)) + if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), a); err != nil { + s.forward(w, r, a, err) + return + } + + if f.Type == flow.TypeAPI { + http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(s.c.SelfPublicURL(), + RouteGetFlow), url.Values{"id": {a.ID.String()}}).String(), http.StatusFound) + } else { + http.Redirect(w, r, a.AppendTo(s.c.SelfServiceFlowRecoveryUI()).String(), http.StatusFound) + } return } - if _, ok := rr.Methods[method]; !ok { - s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, errors.WithStack(x.PseudoPanic.WithReasonf("Expected recovery method %s to exist.", method))) + method, ok := f.Methods[methodName] + if !ok { + s.forward(w, r, f, errors.WithStack(herodot.ErrInternalServerError. + WithErrorf(`Expected recovery method "%s" to exist in flow. This is a bug in the code and should be reported on GitHub.`, methodName))) return } - rr.Active = sqlxx.NullString(method) - if err := rr.Methods[method].Config.ParseError(err); err != nil { - s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + if err := method.Config.ParseError(err); err != nil { + s.forward(w, r, f, err) return } - if err := s.d.RecoveryRequestPersister().UpdateRecoveryRequest(r.Context(), rr); err != nil { + if err := s.d.RecoveryFlowPersister().UpdateRecoveryFlow(r.Context(), f); err != nil { + s.forward(w, r, f, err) + return + } + + if f.Type == flow.TypeBrowser { + http.Redirect(w, r, f.AppendTo(s.c.SelfServiceFlowRecoveryUI()).String(), http.StatusFound) + return + } + + updatedFlow, innerErr := s.d.RecoveryFlowPersister().GetRecoveryFlow(r.Context(), f.ID) + if innerErr != nil { + s.forward(w, r, updatedFlow, innerErr) + } + + s.d.Writer().WriteCode(w, r, x.RecoverStatusCode(err, http.StatusBadRequest), updatedFlow) +} + +func (s *ErrorHandler) forward(w http.ResponseWriter, r *http.Request, rr *Flow, err error) { + if rr == nil { + if x.IsJSONRequest(r) { + s.d.Writer().WriteError(w, r, err) + return + } s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return } - http.Redirect(w, r, - urlx.CopyWithQuery(s.c.SelfServiceFlowRecoveryUI(), url.Values{"request": {rr.ID.String()}}).String(), - http.StatusFound, - ) + if rr.Type == flow.TypeAPI { + s.d.Writer().WriteErrorCode(w, r, x.RecoverStatusCode(err, http.StatusBadRequest), err) + } else { + s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + } } diff --git a/selfservice/flow/recovery/error_test.go b/selfservice/flow/recovery/error_test.go new file mode 100644 index 00000000000..50567e34e9e --- /dev/null +++ b/selfservice/flow/recovery/error_test.go @@ -0,0 +1,250 @@ +package recovery_test + +import ( + "context" + "io/ioutil" + "net/http" + "testing" + "time" + + "github.com/gobuffalo/httptest" + "github.com/julienschmidt/httprouter" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + "github.com/ory/viper" + + "github.com/ory/x/assertx" + "github.com/ory/x/urlx" + + "github.com/ory/herodot" + + "github.com/ory/kratos/driver/configuration" + "github.com/ory/kratos/internal" + "github.com/ory/kratos/internal/httpclient/client/common" + "github.com/ory/kratos/internal/httpclient/models" + "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/schema" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/text" + "github.com/ory/kratos/x" +) + +func TestHandleError(t *testing.T) { + conf, reg := internal.NewFastRegistryWithMocks(t) + viper.Set(configuration.ViperKeySelfServiceRecoveryEnabled, true) + + public, admin := testhelpers.NewKratosServer(t, reg) + + router := httprouter.New() + ts := httptest.NewServer(router) + t.Cleanup(ts.Close) + + testhelpers.NewRecoveryUIFlowEchoServer(t, reg) + testhelpers.NewErrorTestServer(t, reg) + + h := reg.RecoveryFlowErrorHandler() + sdk := testhelpers.NewSDKClient(admin) + + var recoveryFlow *recovery.Flow + var flowError error + var methodName string + router.GET("/error", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + h.WriteFlowError(w, r, methodName, recoveryFlow, flowError) + }) + + reset := func() { + recoveryFlow = nil + flowError = nil + methodName = "" + } + + newFlow := func(t *testing.T, ttl time.Duration, ft flow.Type) *recovery.Flow { + req := &http.Request{URL: urlx.ParseOrPanic("/")} + f, err := recovery.NewFlow(ttl, x.FakeCSRFToken, req, reg.RecoveryStrategies(), ft) + require.NoError(t, err) + require.NoError(t, reg.RecoveryFlowPersister().CreateRecoveryFlow(context.Background(), f)) + f, err = reg.RecoveryFlowPersister().GetRecoveryFlow(context.Background(), f.ID) + require.NoError(t, err) + return f + } + + expectErrorUI := func(t *testing.T) (interface{}, *http.Response) { + res, err := ts.Client().Get(ts.URL + "/error") + require.NoError(t, err) + defer res.Body.Close() + require.Contains(t, res.Request.URL.String(), conf.SelfServiceFlowErrorURL().String()+"?error=") + + sse, err := sdk.Common.GetSelfServiceError(common.NewGetSelfServiceErrorParams(). + WithError(res.Request.URL.Query().Get("error"))) + require.NoError(t, err) + + return sse.Payload.Errors, nil + } + + anHourAgo := time.Now().Add(-time.Hour) + + t.Run("case=error with nil flow defaults to error ui redirect", func(t *testing.T) { + t.Cleanup(reset) + + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = recovery.StrategyRecoveryTokenName + + sse, _ := expectErrorUI(t) + assertx.EqualAsJSON(t, []interface{}{flowError}, sse) + }) + + t.Run("case=error with nil flow detects application/json", func(t *testing.T) { + t.Cleanup(reset) + + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = recovery.StrategyRecoveryTokenName + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + assert.Contains(t, res.Header.Get("Content-Type"), "application/json") + assert.NotContains(t, res.Request.URL.String(), conf.SelfServiceFlowErrorURL().String()+"?error=") + + body, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + assert.Contains(t, string(body), "system error") + }) + + t.Run("flow=api", func(t *testing.T) { + t.Run("case=expired error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeAPI) + flowError = recovery.NewFlowExpiredError(anHourAgo) + methodName = recovery.StrategyRecoveryTokenName + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + require.Contains(t, res.Request.URL.String(), public.URL+recovery.RouteGetFlow) + require.Equal(t, http.StatusOK, res.StatusCode, "%+v", res.Request) + + body, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + assert.Equal(t, int(text.ErrorValidationRecoveryFlowExpired), int(gjson.GetBytes(body, "messages.0.id").Int())) + assert.NotEqual(t, recoveryFlow.ID.String(), gjson.GetBytes(body, "id").String()) + }) + + t.Run("case=validation error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeAPI) + flowError = schema.NewInvalidCredentialsError() + methodName = recovery.StrategyRecoveryTokenName + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) + + body, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + assert.Equal(t, int(text.ErrorValidationInvalidCredentials), int(gjson.GetBytes(body, "methods.link.config.messages.0.id").Int()), "%s", body) + assert.Equal(t, recoveryFlow.ID.String(), gjson.GetBytes(body, "id").String()) + }) + + t.Run("case=generic error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeAPI) + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = recovery.StrategyRecoveryTokenName + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + + body, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + assert.JSONEq(t, x.MustEncodeJSON(t, flowError), gjson.GetBytes(body, "error").Raw) + }) + + t.Run("case=method is unknown", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeAPI) + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = "invalid-method" + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + + body, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + assert.Contains(t, gjson.GetBytes(body, "error.message").String(), "invalid-method", "%s", body) + }) + }) + + t.Run("flow=browser", func(t *testing.T) { + expectRecoveryUI := func(t *testing.T) (*models.RecoveryFlow, *http.Response) { + res, err := ts.Client().Get(ts.URL + "/error") + require.NoError(t, err) + defer res.Body.Close() + assert.Contains(t, res.Request.URL.String(), conf.SelfServiceFlowRecoveryUI().String()+"?flow=") + + lf, err := sdk.Common.GetSelfServiceRecoveryFlow(common.NewGetSelfServiceRecoveryFlowParams(). + WithID(res.Request.URL.Query().Get("flow"))) + require.NoError(t, err) + return lf.Payload, res + } + + t.Run("case=expired error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = &recovery.Flow{Type: flow.TypeBrowser} + flowError = recovery.NewFlowExpiredError(anHourAgo) + methodName = recovery.StrategyRecoveryTokenName + + lf, _ := expectRecoveryUI(t) + require.Len(t, lf.Messages, 1) + assert.Equal(t, int(text.ErrorValidationRecoveryFlowExpired), int(lf.Messages[0].ID)) + }) + + t.Run("case=validation error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeBrowser) + flowError = schema.NewInvalidCredentialsError() + methodName = recovery.StrategyRecoveryTokenName + + lf, _ := expectRecoveryUI(t) + require.NotEmpty(t, lf.Methods[string(methodName)], x.MustEncodeJSON(t, lf)) + require.Len(t, lf.Methods[string(methodName)].Config.Messages, 1, x.MustEncodeJSON(t, lf)) + assert.Equal(t, int(text.ErrorValidationInvalidCredentials), int(lf.Methods[string(methodName)].Config.Messages[0].ID), x.MustEncodeJSON(t, lf)) + }) + + t.Run("case=generic error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeBrowser) + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = recovery.StrategyRecoveryTokenName + + sse, _ := expectErrorUI(t) + assertx.EqualAsJSON(t, []interface{}{flowError}, sse) + }) + + t.Run("case=method is unknown", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeBrowser) + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = "invalid-method" + + sse, _ := expectErrorUI(t) + body := x.MustEncodeJSON(t, sse) + assert.Contains(t, gjson.Get(body, "0.message").String(), "invalid-method", "%s", body) + }) + }) +} diff --git a/selfservice/flow/recovery/request.go b/selfservice/flow/recovery/flow.go similarity index 71% rename from selfservice/flow/recovery/request.go rename to selfservice/flow/recovery/flow.go index 98503c27eae..932255252c8 100644 --- a/selfservice/flow/recovery/request.go +++ b/selfservice/flow/recovery/flow.go @@ -13,6 +13,7 @@ import ( "github.com/ory/x/sqlxx" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/form" "github.com/ory/kratos/text" "github.com/ory/kratos/x" @@ -34,6 +35,9 @@ type Flow struct { // format: uuid ID uuid.UUID `json:"id" db:"id" faker:"-"` + // Type represents the flow's type which can be either "api" or "browser", depending on the flow interaction. + Type flow.Type `json:"type" db:"type" faker:"flow_type"` + // ExpiresAt is the time (UTC) when the request expires. If the user still wishes to update the setting, // a new request has to be initiated. // @@ -92,15 +96,13 @@ type Flow struct { RecoveredIdentityID uuid.NullUUID `json:"-" faker:"-" db:"recovered_identity_id"` } -func NewRequest(exp time.Duration, csrf string, r *http.Request, strategies Strategies) (*Flow, error) { - req := &Flow{ - ID: x.NewUUID(), - ExpiresAt: time.Now().UTC().Add(exp), - IssuedAt: time.Now().UTC(), +func NewFlow(exp time.Duration, csrf string, r *http.Request, strategies Strategies, ft flow.Type) (*Flow, error) { + now := time.Now().UTC() + req := &Flow{ID: x.NewUUID(), + ExpiresAt: now.Add(exp), IssuedAt: now, RequestURL: x.RequestURL(r).String(), Methods: map[string]*FlowMethod{}, - State: StateChooseMethod, - CSRFToken: csrf, + State: StateChooseMethod, CSRFToken: csrf, Type: ft, } for _, strategy := range strategies { @@ -112,62 +114,64 @@ func NewRequest(exp time.Duration, csrf string, r *http.Request, strategies Stra return req, nil } -func (r Flow) TableName() string { +func (f Flow) TableName() string { return "selfservice_recovery_flows" } -func (r *Flow) URL(recoveryURL *url.URL) *url.URL { - return urlx.CopyWithQuery(recoveryURL, url.Values{"request": {r.ID.String()}}) +func (f *Flow) URL(recoveryURL *url.URL) *url.URL { + return urlx.CopyWithQuery(recoveryURL, url.Values{"request": {f.ID.String()}}) } -func (r *Flow) GetID() uuid.UUID { - return r.ID +func (f *Flow) GetID() uuid.UUID { + return f.ID } -func (r *Flow) Valid() error { - if r.ExpiresAt.Before(time.Now().UTC()) { - return errors.WithStack(ErrRequestExpired. - WithReasonf("The recovery request expired %.2f minutes ago, please try again.", - -time.Since(r.ExpiresAt).Minutes())) +func (f *Flow) Valid() error { + if f.ExpiresAt.Before(time.Now().UTC()) { + return errors.WithStack(NewFlowExpiredError(f.ExpiresAt)) } return nil } -func (r *Flow) BeforeSave(_ *pop.Connection) error { - r.MethodsRaw = make([]FlowMethod, 0, len(r.Methods)) - for _, m := range r.Methods { - r.MethodsRaw = append(r.MethodsRaw, *m) +func (f *Flow) BeforeSave(_ *pop.Connection) error { + f.MethodsRaw = make([]FlowMethod, 0, len(f.Methods)) + for _, m := range f.Methods { + f.MethodsRaw = append(f.MethodsRaw, *m) } - r.Methods = nil + f.Methods = nil return nil } -func (r *Flow) AfterSave(c *pop.Connection) error { - return r.AfterFind(c) +func (f *Flow) AfterSave(c *pop.Connection) error { + return f.AfterFind(c) } -func (r *Flow) AfterFind(_ *pop.Connection) error { - r.Methods = make(RequestMethods) - for key := range r.MethodsRaw { - m := r.MethodsRaw[key] // required for pointer dereference - r.Methods[m.Method] = &m +func (f *Flow) AfterFind(_ *pop.Connection) error { + f.Methods = make(RequestMethods) + for key := range f.MethodsRaw { + m := f.MethodsRaw[key] // required for pointer dereference + f.Methods[m.Method] = &m } - r.MethodsRaw = nil + f.MethodsRaw = nil return nil } -func (r *Flow) MethodToForm(id string) (form.Form, error) { - method, ok := r.Methods[id] +func (f *Flow) MethodToForm(id string) (form.Form, error) { + method, ok := f.Methods[id] if !ok { return nil, errors.WithStack(x.PseudoPanic.WithReasonf("Expected method %s to exist.", id)) } - config, ok := method.Config.RequestMethodConfigurator.(form.Form) + config, ok := method.Config.FlowMethodConfigurator.(form.Form) if !ok { return nil, errors.WithStack(x.PseudoPanic.WithReasonf( "Expected method config %s to be of type *form.HTMLForm but got: %T", id, - method.Config.RequestMethodConfigurator)) + method.Config.FlowMethodConfigurator)) } return config, nil } + +func (f *Flow) AppendTo(src *url.URL) *url.URL { + return urlx.CopyWithQuery(src, url.Values{"flow": {f.ID.String()}}) +} diff --git a/selfservice/flow/recovery/request_method.go b/selfservice/flow/recovery/flow_method.go similarity index 71% rename from selfservice/flow/recovery/request_method.go rename to selfservice/flow/recovery/flow_method.go index 3fc592ffeb1..70d87c175c7 100644 --- a/selfservice/flow/recovery/request_method.go +++ b/selfservice/flow/recovery/flow_method.go @@ -18,7 +18,7 @@ type FlowMethod struct { Method string `json:"method" db:"method"` // Config is the credential type's config. - Config *RequestMethodConfig `json:"config" db:"config"` + Config *FlowMethodConfig `json:"config" db:"config"` // ID is a helper struct field for gobuffalo.pop. ID uuid.UUID `json:"-" db:"id"` @@ -54,7 +54,7 @@ func (u RequestMethodsRaw) TableName() string { } // swagger:ignore -type RequestMethodConfigurator interface { +type FlowMethodConfigurator interface { form.ErrorParser form.FieldSetter form.FieldUnsetter @@ -66,33 +66,33 @@ type RequestMethodConfigurator interface { form.MessageAdder } -// swagger:type recoveryRequestConfigPayload -type RequestMethodConfig struct { +// swagger:model loginFlowMethodConfig +type FlowMethodConfig struct { // swagger:ignore - RequestMethodConfigurator + FlowMethodConfigurator - swaggerRequestMethodConfig + FlowMethodConfigMock } -// swagger:model recoveryRequestConfigPayload -type swaggerRequestMethodConfig struct { +// swagger:model loginFlowMethodConfigPayload +type FlowMethodConfigMock struct { *form.HTMLForm } -func (c *RequestMethodConfig) Scan(value interface{}) error { +func (c *FlowMethodConfig) Scan(value interface{}) error { return sqlxx.JSONScan(c, value) } -func (c *RequestMethodConfig) Value() (driver.Value, error) { +func (c *FlowMethodConfig) Value() (driver.Value, error) { return sqlxx.JSONValue(c) } -func (c *RequestMethodConfig) UnmarshalJSON(data []byte) error { - c.RequestMethodConfigurator = form.NewHTMLForm("") - return json.Unmarshal(data, c.RequestMethodConfigurator) +func (c *FlowMethodConfig) UnmarshalJSON(data []byte) error { + c.FlowMethodConfigurator = form.NewHTMLForm("") + return json.Unmarshal(data, c.FlowMethodConfigurator) } -func (c *RequestMethodConfig) MarshalJSON() ([]byte, error) { - out, err := json.Marshal(c.RequestMethodConfigurator) +func (c *FlowMethodConfig) MarshalJSON() ([]byte, error) { + out, err := json.Marshal(c.FlowMethodConfigurator) return out, err } diff --git a/selfservice/flow/recovery/request_test.go b/selfservice/flow/recovery/flow_test.go similarity index 73% rename from selfservice/flow/recovery/request_test.go rename to selfservice/flow/recovery/flow_test.go index 24d7accf5dd..68152d0d4fa 100644 --- a/selfservice/flow/recovery/request_test.go +++ b/selfservice/flow/recovery/flow_test.go @@ -11,6 +11,7 @@ import ( "github.com/ory/x/urlx" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" ) @@ -25,8 +26,8 @@ func TestRequest(t *testing.T) { r *recovery.Flow expectErr bool }{ - {r: must(recovery.NewRequest(time.Hour, "", u, nil))}, - {r: must(recovery.NewRequest(-time.Hour, "", u, nil)), expectErr: true}, + {r: must(recovery.NewFlow(time.Hour, "", u, nil, flow.TypeBrowser))}, + {r: must(recovery.NewFlow(-time.Hour, "", u, nil, flow.TypeBrowser)), expectErr: true}, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { err := tc.r.Valid() @@ -40,5 +41,5 @@ func TestRequest(t *testing.T) { } assert.EqualValues(t, recovery.StateChooseMethod, - must(recovery.NewRequest(time.Hour, "", u, nil)).State) + must(recovery.NewFlow(time.Hour, "", u, nil, flow.TypeBrowser)).State) } diff --git a/selfservice/flow/recovery/handler.go b/selfservice/flow/recovery/handler.go index e05e0d18f00..b801e327179 100644 --- a/selfservice/flow/recovery/handler.go +++ b/selfservice/flow/recovery/handler.go @@ -2,11 +2,9 @@ package recovery import ( "net/http" - "net/url" "time" "github.com/julienschmidt/httprouter" - "github.com/justinas/nosurf" "github.com/pkg/errors" "github.com/ory/x/urlx" @@ -14,13 +12,15 @@ import ( "github.com/ory/kratos/driver/configuration" "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/errorx" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/session" "github.com/ory/kratos/x" ) const ( - PublicRecoveryInitPath = "/self-service/browser/flows/recovery" - PublicRecoveryRequestPath = "/self-service/browser/flows/requests/recovery" + RouteInitBrowserFlow = "/self-service/recovery/browser" + RouteInitAPIFlow = "/self-service/recovery/api" + RouteGetFlow = "/self-service/recovery/flows" ) type ( @@ -49,70 +49,115 @@ func NewHandler(d handlerDependencies, c configuration.Provider) *Handler { func (h *Handler) RegisterPublicRoutes(public *x.RouterPublic) { redirect := session.RedirectOnAuthenticated(h.c) - public.GET(PublicRecoveryInitPath, h.d.SessionHandler().IsNotAuthenticated(h.init, redirect)) - public.GET(PublicRecoveryRequestPath, h.publicFetch) + public.GET(RouteInitBrowserFlow, h.d.SessionHandler().IsNotAuthenticated(h.initBrowserFlow, redirect)) + public.GET(RouteInitAPIFlow, h.d.SessionHandler().IsNotAuthenticated(h.initAPIFlow, + session.RespondWithJSONErrorOnAuthenticated(h.d.Writer(), ErrAlreadyLoggedIn))) + public.GET(RouteGetFlow, h.fetchRequest) } func (h *Handler) RegisterAdminRoutes(admin *x.RouterAdmin) { - admin.GET(PublicRecoveryRequestPath, h.adminFetch) + admin.GET(RouteGetFlow, h.fetchRequest) } -// swagger:route GET /self-service/browser/flows/recovery public initializeSelfServiceRecoveryFlow +// swagger:route GET /self-service/recovery/api public initializeSelfServiceRecoveryViaAPIFlow // -// Initialize browser-based account recovery flow +// Initialize Login Flow for API Clients +// +// This endpoint initiates a recovery flow for API clients such as mobile devices, smart TVs, and so on. +// +// If a valid provided session cookie or session token is provided, a 400 Bad Request error. +// +// To fetch an existing recovery flow call `/self-service/recovery/flows?flow=`. +// +// :::warning +// +// You MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server +// Pages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make +// you vulnerable to a variety of CSRF attacks. +// +// This endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...). +// +// ::: +// +// More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). +// +// Schemes: http, https +// +// Security: +// - sessionToken +// +// Responses: +// 200: loginFlow +// 500: genericError +// 400: genericError +func (h *Handler) initAPIFlow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + req, err := NewFlow(h.c.SelfServiceFlowRecoveryRequestLifespan(), h.d.GenerateCSRFToken(r), r, h.d.RecoveryStrategies(), flow.TypeAPI) + if err != nil { + h.d.Writer().WriteError(w, r, err) + return + } + + if err := h.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), req); err != nil { + h.d.Writer().WriteError(w, r, err) + return + } + + h.d.Writer().Write(w, r, req) +} + +// swagger:route GET /self-service/recovery/browser public initializeSelfServiceRecoveryViaBrowserFlow +// +// Initialize Recovery Flow for Browser Clients // // This endpoint initializes a browser-based account recovery flow. Once initialized, the browser will be redirected to -// `selfservice.flows.recovery.ui_url` with the request ID set as a query parameter. If a valid user session exists, the request -// is aborted. +// `selfservice.flows.recovery.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session +// exists, the browser is returned to the configured return URL. // -// > This endpoint is NOT INTENDED for API clients and only works -// with browsers (Chrome, Firefox, ...). +// This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...). // // More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). // // Schemes: http, https // +// Security: +// - sessionToken +// // Responses: // 302: emptyResponse // 500: genericError -func (h *Handler) init(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - req, err := NewRequest(h.c.SelfServiceFlowRecoveryRequestLifespan(), h.d.GenerateCSRFToken(r), r, h.d.RecoveryStrategies()) +func (h *Handler) initBrowserFlow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + req, err := NewFlow(h.c.SelfServiceFlowRecoveryRequestLifespan(), h.d.GenerateCSRFToken(r), r, h.d.RecoveryStrategies(), flow.TypeBrowser) if err != nil { h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return } - if err := h.d.RecoveryRequestPersister().CreateRecoveryRequest(r.Context(), req); err != nil { + if err := h.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), req); err != nil { h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return } - http.Redirect(w, r, - urlx.CopyWithQuery(h.c.SelfServiceFlowRecoveryUI(), url.Values{"request": {req.ID.String()}}).String(), - http.StatusFound, - ) + http.Redirect(w, r, req.AppendTo(h.c.SelfServiceFlowRecoveryUI()).String(), http.StatusFound) } // nolint:deadcode,unused -// swagger:parameters getSelfServiceBrowserRecoveryRequest -type getSelfServiceBrowserRecoveryRequestParameters struct { - // Request is the Login Request ID +// swagger:parameters getSelfServiceRecoveryFlow +type getSelfServiceRecoveryFlow struct { + // The Flow ID // // The value for this parameter comes from `request` URL Query parameter sent to your - // application (e.g. `/recover?request=abcde`). + // application (e.g. `/recovery?flow=abcde`). // // required: true // in: query - Request string `json:"request"` + FlowID string `json:"id"` } -// swagger:route GET /self-service/browser/flows/requests/recovery common public admin getSelfServiceBrowserRecoveryRequest +// swagger:route GET /self-service/recovery/flows common public admin getSelfServiceRecoveryFlow // -// Get the request context of browser-based recovery flows +// Get information about a recovery flow // -// When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required -// for checking the auth session. To prevent scanning attacks, the public endpoint does not return 404 status codes -// but instead 403 or 500. +// This endpoint returns a recovery flow's context with, for example, error details and other information. // // More information can be found at [ORY Kratos Account Recovery Documentation](../self-service/flows/password-reset-account-recovery). // @@ -123,49 +168,29 @@ type getSelfServiceBrowserRecoveryRequestParameters struct { // // Responses: // 200: recoveryFlow -// 403: genericError // 404: genericError // 410: genericError // 500: genericError -func (h *Handler) publicFetch(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if err := h.fetchRequest(w, r, true); err != nil { +func (h *Handler) fetchRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + rid := x.ParseUUID(r.URL.Query().Get("id")) + req, err := h.d.RecoveryFlowPersister().GetRecoveryFlow(r.Context(), rid) + if err != nil { h.d.Writer().WriteError(w, r, err) return } -} - -func (h *Handler) adminFetch(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if err := h.fetchRequest(w, r, false); err != nil { - h.d.Writer().WriteError(w, r, err) - return - } -} - -func (h *Handler) wrapErrorForbidden(err error, shouldWrap bool) error { - if shouldWrap { - return x.ErrInvalidCSRFToken.WithTrace(err).WithDebugf("%s", err) - } - - return err -} - -func (h *Handler) fetchRequest(w http.ResponseWriter, r *http.Request, checkCSRF bool) error { - rid := x.ParseUUID(r.URL.Query().Get("request")) - req, err := h.d.RecoveryRequestPersister().GetRecoveryRequest(r.Context(), rid) - if err != nil { - return h.wrapErrorForbidden(err, checkCSRF) - } - - if checkCSRF && !nosurf.VerifyToken(h.d.GenerateCSRFToken(r), req.CSRFToken) { - return errors.WithStack(x.ErrInvalidCSRFToken) - } if req.ExpiresAt.Before(time.Now().UTC()) { - return errors.WithStack(x.ErrGone. - WithReason("The recovery request has expired. Redirect the user to the login endpoint to initialize a new session."). - WithDetail("redirect_to", urlx.AppendPaths(h.c.SelfPublicURL(), PublicRecoveryInitPath).String())) + if req.Type == flow.TypeBrowser { + h.d.Writer().WriteError(w, r, errors.WithStack(x.ErrGone. + WithReason("The recovery flow has expired. Redirect the user to the recovery flow init endpoint to initialize a new recovery flow."). + WithDetail("redirect_to", urlx.AppendPaths(h.c.SelfPublicURL(), RouteInitBrowserFlow).String()))) + return + } + h.d.Writer().WriteError(w, r, errors.WithStack(x.ErrGone. + WithReason("The recovery flow has expired. Call the recovery flow init API endpoint to initialize a new recovery flow."). + WithDetail("api", urlx.AppendPaths(h.c.SelfPublicURL(), RouteInitAPIFlow).String()))) + return } h.d.Writer().Write(w, r, req) - return nil } diff --git a/selfservice/flow/recovery/handler_test.go b/selfservice/flow/recovery/handler_test.go index 12d68422aba..8283f29c68f 100644 --- a/selfservice/flow/recovery/handler_test.go +++ b/selfservice/flow/recovery/handler_test.go @@ -2,22 +2,26 @@ package recovery_test import ( "context" + "encoding/json" + "io/ioutil" "net/http" - "net/http/cookiejar" "net/http/httptest" "testing" "time" - "github.com/justinas/nosurf" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + "github.com/ory/x/assertx" + "github.com/ory/viper" "github.com/ory/kratos/driver/configuration" + "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/x" ) @@ -28,127 +32,169 @@ func init() { func TestHandlerRedirectOnAuthenticated(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) - testhelpers.RecoveryFlowEnable(true) - - testhelpers.NewRecoveryUITestServer(t) - redirTS := testhelpers.NewRedirTS(t, "already authenticated") - viper.Set(configuration.ViperKeySelfServiceLoginUI, redirTS.URL) + viper.Set(configuration.ViperKeySelfServiceRecoveryEnabled, true) router := x.NewRouterPublic() - testhelpers.NewErrorTestServer(t, reg) - public, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) + ts, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) + redirTS := testhelpers.NewRedirTS(t, "already authenticated") viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") t.Run("does redirect to default on authenticated request", func(t *testing.T) { - body, _ := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", public.URL+recovery.PublicRecoveryInitPath, nil)) + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+recovery.RouteInitBrowserFlow, nil)) + assert.Contains(t, res.Request.URL.String(), redirTS.URL, "%+v", res) assert.EqualValues(t, "already authenticated", string(body)) }) + + t.Run("does redirect to default on authenticated request", func(t *testing.T) { + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+recovery.RouteInitAPIFlow, nil)) + assert.Contains(t, res.Request.URL.String(), recovery.RouteInitAPIFlow) + assertx.EqualAsJSON(t, recovery.ErrAlreadyLoggedIn, json.RawMessage(gjson.GetBytes(body, "error").Raw)) + }) } -func TestRecoveryHandler(t *testing.T) { - _, reg := internal.NewFastRegistryWithMocks(t) - testhelpers.RecoveryFlowEnable(true) +func TestInitFlow(t *testing.T) { + conf, reg := internal.NewFastRegistryWithMocks(t) + viper.Set(configuration.ViperKeySelfServiceRecoveryEnabled, true) + viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+recovery.StrategyRecoveryTokenName, + map[string]interface{}{"enabled": true}) + + router := x.NewRouterPublic() + publicTS, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) + recoveryTS := testhelpers.NewRecoveryUIFlowEchoServer(t, reg) + + viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") + + assertion := func(body []byte, isForced, isApi bool) { + if isApi { + assert.Equal(t, "api", gjson.GetBytes(body, "type").String()) + } else { + assert.Equal(t, "browser", gjson.GetBytes(body, "type").String()) + } + } + + initAuthenticatedFlow := func(t *testing.T, isAPI bool) (*http.Response, []byte) { + route := recovery.RouteInitBrowserFlow + if isAPI { + route = recovery.RouteInitAPIFlow + } + req := x.NewTestHTTPRequest(t, "GET", publicTS.URL+route, nil) + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, req) + return res, body + } + + initFlow := func(t *testing.T, isAPI bool) (*http.Response, []byte) { + route := recovery.RouteInitBrowserFlow + if isAPI { + route = recovery.RouteInitAPIFlow + } + c := publicTS.Client() + res, err := c.Get(publicTS.URL + route) + require.NoError(t, err) + defer res.Body.Close() + body, err := ioutil.ReadAll(res.Body) + require.NoError(t, err) + return res, body + } + + t.Run("flow=api", func(t *testing.T) { + t.Run("case=creates a new flow on unauthenticated request", func(t *testing.T) { + res, body := initFlow(t, true) + assert.Contains(t, res.Request.URL.String(), recovery.RouteInitAPIFlow) + assertion(body, false, true) + }) + + t.Run("case=fails on authenticated request", func(t *testing.T) { + res, body := initAuthenticatedFlow(t, true) + assert.Equal(t, http.StatusBadRequest, res.StatusCode) + assertx.EqualAsJSON(t, recovery.ErrAlreadyLoggedIn, json.RawMessage(gjson.GetBytes(body, "error").Raw), "%s", body) + }) + }) + + t.Run("flow=browser", func(t *testing.T) { + t.Run("case=does not set forced flag on unauthenticated request", func(t *testing.T) { + res, body := initFlow(t, false) + assertion(body, false, false) + assert.Contains(t, res.Request.URL.String(), recoveryTS.URL) + }) + t.Run("case=does not set forced flag on authenticated request with refresh=false", func(t *testing.T) { + res, _ := initAuthenticatedFlow(t, false) + assert.Contains(t, res.Request.URL.String(), "https://www.ory.sh") + }) + }) +} - testhelpers.NewRedirTS(t, "") - testhelpers.NewLoginUIFlowEchoServer(t, reg) - testhelpers.NewErrorTestServer(t, reg) +func TestGetFlow(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + viper.Set(configuration.ViperKeySelfServiceRecoveryEnabled, true) + viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+recovery.StrategyRecoveryTokenName, + map[string]interface{}{"enabled": true}) + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") public, admin := testhelpers.NewKratosServerWithCSRF(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + _ = testhelpers.NewRedirTS(t, "") + newRecoveryTS := func(t *testing.T, upstream string, c *http.Client) *httptest.Server { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if c == nil { c = http.DefaultClient } - _, _ = w.Write(x.EasyGetBody(t, c, upstream+recovery.PublicRecoveryRequestPath+"?request="+r.URL.Query().Get("request"))) + _, err := w.Write(x.EasyGetBody(t, c, upstream+recovery.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + require.NoError(t, err) })) - viper.Set(configuration.ViperKeySelfServiceRecoveryUI, ts.URL) - t.Cleanup(ts.Close) - return ts } - assertRequestPayload := func(t *testing.T, body []byte) { - // assert.Equal(t, "password", gjson.GetBytes(body, "methods.password.method").String(), "%s", body) - // assert.NotEmpty(t, gjson.GetBytes(body, "methods.password.config.fields.#(name==csrf_token).value").String(), "%s", body) + assertFlowPayload := func(t *testing.T, body []byte) { + assert.Equal(t, "password", gjson.GetBytes(body, "methods.password.method").String(), "%s", body) + assert.NotEmpty(t, gjson.GetBytes(body, "methods.password.config.fields.#(name==csrf_token).value").String(), "%s", body) assert.NotEmpty(t, gjson.GetBytes(body, "id").String(), "%s", body) assert.Empty(t, gjson.GetBytes(body, "headers").Value(), "%s", body) - assert.Equal(t, "choose_method", gjson.GetBytes(body, "state").Value(), "%s", body) - // assert.Contains(t, gjson.GetBytes(body, "methods.password.config.action").String(), gjson.GetBytes(body, "id").String(), "%s", body) - // assert.Contains(t, gjson.GetBytes(body, "methods.password.config.action").String(), public.URL, "%s", body) + assert.Contains(t, gjson.GetBytes(body, "methods.password.config.action").String(), gjson.GetBytes(body, "id").String(), "%s", body) + assert.Contains(t, gjson.GetBytes(body, "methods.password.config.action").String(), public.URL, "%s", body) } assertExpiredPayload := func(t *testing.T, res *http.Response, body []byte) { assert.EqualValues(t, http.StatusGone, res.StatusCode) - assert.Equal(t, public.URL+recovery.PublicRecoveryInitPath, gjson.GetBytes(body, "error.details.redirect_to").String(), "%s", body) + assert.Equal(t, public.URL+recovery.RouteInitBrowserFlow, gjson.GetBytes(body, "error.details.redirect_to").String(), "%s", body) } - newExpiredRequest := func() *recovery.Flow { + newExpiredFlow := func() *recovery.Flow { return &recovery.Flow{ ID: x.NewUUID(), ExpiresAt: time.Now().Add(-time.Minute), IssuedAt: time.Now().Add(-time.Minute * 2), - RequestURL: public.URL + recovery.PublicRecoveryInitPath, + RequestURL: public.URL + recovery.RouteInitBrowserFlow, CSRFToken: x.FakeCSRFToken, + Type: flow.TypeBrowser, } } - viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/recovery.schema.json") - - t.Run("daemon=admin", func(t *testing.T) { - regTS := newRecoveryTS(t, admin.URL, nil) - defer regTS.Close() - viper.Set(configuration.ViperKeySelfServiceRecoveryUI, regTS.URL) + run := func(t *testing.T, endpoint *httptest.Server) { + recoveryTS := newRecoveryTS(t, endpoint.URL, nil) + defer recoveryTS.Close() + viper.Set(configuration.ViperKeySelfServiceRecoveryUI, recoveryTS.URL) + viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), + map[string]interface{}{"enabled": true}) t.Run("case=valid", func(t *testing.T) { - assertRequestPayload(t, x.EasyGetBody(t, public.Client(), public.URL+recovery.PublicRecoveryInitPath)) + assertFlowPayload(t, x.EasyGetBody(t, endpoint.Client(), public.URL+recovery.RouteInitBrowserFlow)) }) t.Run("case=expired", func(t *testing.T) { - rr := newExpiredRequest() - require.NoError(t, reg.RecoveryRequestPersister().CreateRecoveryRequest(context.Background(), rr)) - res, body := x.EasyGet(t, admin.Client(), admin.URL+recovery.PublicRecoveryRequestPath+"?request="+rr.ID.String()) + lr := newExpiredFlow() + require.NoError(t, reg.RecoveryFlowPersister().CreateRecoveryFlow(context.Background(), lr)) + res, body := x.EasyGet(t, admin.Client(), endpoint.URL+recovery.RouteGetFlow+"?id="+lr.ID.String()) assertExpiredPayload(t, res, body) }) + } + + t.Run("daemon=admin", func(t *testing.T) { + run(t, admin) }) t.Run("daemon=public", func(t *testing.T) { - t.Run("case=with_csrf", func(t *testing.T) { - j, err := cookiejar.New(nil) - require.NoError(t, err) - hc := &http.Client{Jar: j} - - newRecoveryTS(t, public.URL, hc) - - body := x.EasyGetBody(t, hc, public.URL+recovery.PublicRecoveryInitPath) - assertRequestPayload(t, body) - }) - - t.Run("case=without_csrf", func(t *testing.T) { - newRecoveryTS(t, public.URL, - // using a different client because it doesn't have access to the cookie jar - new(http.Client)) - - body := x.EasyGetBody(t, new(http.Client), public.URL+recovery.PublicRecoveryInitPath) - assert.Contains(t, gjson.GetBytes(body, "error").String(), "csrf_token", "%s", body) - }) - - t.Run("case=expired", func(t *testing.T) { - reg.WithCSRFTokenGenerator(x.FakeCSRFTokenGenerator) - t.Cleanup(func() { - reg.WithCSRFTokenGenerator(nosurf.Token) - }) - - j, err := cookiejar.New(nil) - require.NoError(t, err) - hc := &http.Client{Jar: j} - - regTS := newRecoveryTS(t, public.URL, hc) - defer regTS.Close() - - rr := newExpiredRequest() - require.NoError(t, reg.RecoveryRequestPersister().CreateRecoveryRequest(context.Background(), rr)) - res, body := x.EasyGet(t, admin.Client(), admin.URL+recovery.PublicRecoveryRequestPath+"?request="+rr.ID.String()) - assertExpiredPayload(t, res, body) - }) + run(t, public) }) } diff --git a/selfservice/flow/recovery/persistence.go b/selfservice/flow/recovery/persistence.go index 2a837591ca8..f444502e08b 100644 --- a/selfservice/flow/recovery/persistence.go +++ b/selfservice/flow/recovery/persistence.go @@ -20,18 +20,18 @@ import ( ) type ( - RequestPersister interface { - CreateRecoveryRequest(context.Context, *Flow) error - GetRecoveryRequest(ctx context.Context, id uuid.UUID) (*Flow, error) - UpdateRecoveryRequest(context.Context, *Flow) error + FlowPersister interface { + CreateRecoveryFlow(context.Context, *Flow) error + GetRecoveryFlow(ctx context.Context, id uuid.UUID) (*Flow, error) + UpdateRecoveryFlow(context.Context, *Flow) error } RequestPersistenceProvider interface { - RecoveryRequestPersister() RequestPersister + RecoveryFlowPersister() FlowPersister } ) func TestRequestPersister(p interface { - RequestPersister + FlowPersister identity.PrivilegedPool }) func(t *testing.T) { viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") @@ -42,11 +42,11 @@ func TestRequestPersister(p interface { return func(t *testing.T) { t.Run("case=should error when the recovery request does not exist", func(t *testing.T) { - _, err := p.GetRecoveryRequest(context.Background(), x.NewUUID()) + _, err := p.GetRecoveryFlow(context.Background(), x.NewUUID()) require.Error(t, err) }) - var newRequest = func(t *testing.T) *Flow { + var newFlow = func(t *testing.T) *Flow { var r Flow require.NoError(t, faker.FakeData(&r)) clearids(&r) @@ -54,29 +54,29 @@ func TestRequestPersister(p interface { } t.Run("case=should create a new recovery request", func(t *testing.T) { - r := newRequest(t) - err := p.CreateRecoveryRequest(context.Background(), r) + r := newFlow(t) + err := p.CreateRecoveryFlow(context.Background(), r) require.NoError(t, err, "%#v", err) }) t.Run("case=should create with set ids", func(t *testing.T) { var r Flow require.NoError(t, faker.FakeData(&r)) - require.NoError(t, p.CreateRecoveryRequest(context.Background(), &r)) + require.NoError(t, p.CreateRecoveryFlow(context.Background(), &r)) }) t.Run("case=should create and fetch a recovery request", func(t *testing.T) { - expected := newRequest(t) - err := p.CreateRecoveryRequest(context.Background(), expected) + expected := newFlow(t) + err := p.CreateRecoveryFlow(context.Background(), expected) require.NoError(t, err) - actual, err := p.GetRecoveryRequest(context.Background(), expected.ID) + actual, err := p.GetRecoveryFlow(context.Background(), expected.ID) require.NoError(t, err) fexpected, _ := json.Marshal(expected.Methods[StrategyRecoveryTokenName].Config) factual, _ := json.Marshal(actual.Methods[StrategyRecoveryTokenName].Config) - require.NotEmpty(t, actual.Methods[StrategyRecoveryTokenName].Config.RequestMethodConfigurator.(*form.HTMLForm).Action) + require.NotEmpty(t, actual.Methods[StrategyRecoveryTokenName].Config.FlowMethodConfigurator.(*form.HTMLForm).Action) assert.EqualValues(t, expected.ID, actual.ID) assert.JSONEq(t, string(fexpected), string(factual)) x.AssertEqualTime(t, expected.IssuedAt, actual.IssuedAt) @@ -85,59 +85,56 @@ func TestRequestPersister(p interface { }) t.Run("case=should create and update a recovery request", func(t *testing.T) { - expected := newRequest(t) + expected := newFlow(t) expected.Methods[StrategyRecoveryTokenName] = &FlowMethod{ - Method: StrategyRecoveryTokenName, Config: &RequestMethodConfig{RequestMethodConfigurator: &form.HTMLForm{Fields: []form.Field{{ + Method: StrategyRecoveryTokenName, Config: &FlowMethodConfig{FlowMethodConfigurator: &form.HTMLForm{Fields: []form.Field{{ Name: "zab", Type: "bar", Pattern: "baz"}}}}} expected.Methods["password"] = &FlowMethod{ - Method: "password", Config: &RequestMethodConfig{RequestMethodConfigurator: &form.HTMLForm{Fields: []form.Field{{ + Method: "password", Config: &FlowMethodConfig{FlowMethodConfigurator: &form.HTMLForm{Fields: []form.Field{{ Name: "foo", Type: "bar", Pattern: "baz"}}}}} - err := p.CreateRecoveryRequest(context.Background(), expected) + err := p.CreateRecoveryFlow(context.Background(), expected) require.NoError(t, err) - expected.Methods[StrategyRecoveryTokenName].Config.RequestMethodConfigurator.(*form.HTMLForm).Action = "/new-action" - expected.Methods["password"].Config.RequestMethodConfigurator.(*form.HTMLForm).Fields = []form.Field{{ + expected.Methods[StrategyRecoveryTokenName].Config.FlowMethodConfigurator.(*form.HTMLForm).Action = "/new-action" + expected.Methods["password"].Config.FlowMethodConfigurator.(*form.HTMLForm).Fields = []form.Field{{ Name: "zab", Type: "zab", Pattern: "zab"}} expected.RequestURL = "/new-request-url" expected.Active = StrategyRecoveryTokenName expected.Messages.Add(text.NewRecoveryEmailSent()) - require.NoError(t, p.UpdateRecoveryRequest(context.Background(), expected)) + require.NoError(t, p.UpdateRecoveryFlow(context.Background(), expected)) - actual, err := p.GetRecoveryRequest(context.Background(), expected.ID) + actual, err := p.GetRecoveryFlow(context.Background(), expected.ID) require.NoError(t, err) - assert.Equal(t, "/new-action", actual.Methods[StrategyRecoveryTokenName].Config.RequestMethodConfigurator.(*form.HTMLForm).Action) + assert.Equal(t, "/new-action", actual.Methods[StrategyRecoveryTokenName].Config.FlowMethodConfigurator.(*form.HTMLForm).Action) assert.Equal(t, "/new-request-url", actual.RequestURL) assert.Equal(t, StrategyRecoveryTokenName, actual.Active.String()) assert.Equal(t, expected.Messages, actual.Messages) assert.EqualValues(t, []form.Field{{Name: "zab", Type: "zab", Pattern: "zab"}}, actual. - Methods["password"].Config.RequestMethodConfigurator.(*form.HTMLForm).Fields) + Methods["password"].Config.FlowMethodConfigurator.(*form.HTMLForm).Fields) assert.EqualValues(t, []form.Field{{Name: "zab", Type: "bar", Pattern: "baz"}}, actual. - Methods[StrategyRecoveryTokenName].Config.RequestMethodConfigurator.(*form.HTMLForm).Fields) + Methods[StrategyRecoveryTokenName].Config.FlowMethodConfigurator.(*form.HTMLForm).Fields) }) t.Run("case=should not cause data loss when updating a request without changes", func(t *testing.T) { - t.Logf("Needs implementation") - t.FailNow() - // expected := newFlow(t) - // delete(expected.Methods, identity.CredentialsTypeOIDC) - // err := p.CreateLoginFlow(context.Background(), expected) - // require.NoError(t, err) - // - // actual, err := p.GetLoginFlow(context.Background(), expected.ID) - // require.NoError(t, err) - // assert.Len(t, actual.Methods, 1) - // - // require.NoError(t, p.UpdateLoginFlow(context.Background(), actual)) - // - // actual, err = p.GetLoginFlow(context.Background(), expected.ID) - // require.NoError(t, err) - // require.Len(t, actual.Methods, 2) - // assert.EqualValues(t, identity.CredentialsTypePassword, actual.Active) - // - // js, _ := json.Marshal(actual.Methods) - // assert.Equal(t, string(identity.CredentialsTypePassword), actual.Methods[identity.CredentialsTypePassword].Config.FlowMethodConfigurator.(*form.HTMLForm).Action, "%s", js) - // assert.Equal(t, string(identity.CredentialsTypeOIDC), actual.Methods[identity.CredentialsTypeOIDC].Config.FlowMethodConfigurator.(*form.HTMLForm).Action) + expected := newFlow(t) + err := p.CreateRecoveryFlow(context.Background(), expected) + require.NoError(t, err) + + actual, err := p.GetRecoveryFlow(context.Background(), expected.ID) + require.NoError(t, err) + assert.Len(t, actual.Methods, 1) + + require.NoError(t, p.UpdateRecoveryFlow(context.Background(), actual)) + + actual, err = p.GetRecoveryFlow(context.Background(), expected.ID) + require.NoError(t, err) + require.Len(t, actual.Methods, 1) + assert.EqualValues(t, StrategyRecoveryTokenName, actual.Active) + + js, _ := json.Marshal(actual.Methods) + assert.Equal(t, expected.Methods[StrategyRecoveryTokenName].Config.FlowMethodConfigurator.(*form.HTMLForm).Action, + actual.Methods[StrategyRecoveryTokenName].Config.FlowMethodConfigurator.(*form.HTMLForm).Action, "%s", js) }) } } diff --git a/selfservice/hook/session_issuer_test.go b/selfservice/hook/session_issuer_test.go index d9addf9fbe6..d28e0f584f5 100644 --- a/selfservice/hook/session_issuer_test.go +++ b/selfservice/hook/session_issuer_test.go @@ -8,11 +8,12 @@ import ( "testing" "time" - "github.com/ory/x/randx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + "github.com/ory/x/randx" + "github.com/ory/viper" "github.com/ory/kratos/driver/configuration" diff --git a/selfservice/strategy/oidc/strategy_settings_test.go b/selfservice/strategy/oidc/strategy_settings_test.go index 9382dd895fa..7b47e24a9f1 100644 --- a/selfservice/strategy/oidc/strategy_settings_test.go +++ b/selfservice/strategy/oidc/strategy_settings_test.go @@ -569,7 +569,7 @@ func TestPopulateSettingsMethod(t *testing.T) { reg := nreg(t, &oidc.ConfigurationCollection{Providers: []oidc.Configuration{{Provider: "generic", ID: "github"}}}) i := &identity.Identity{Traits: []byte(`{"subject":"foo@bar.com"}`)} require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) - req := &settings.Flow{Type: flow.TypeAPI, ID: x.NewUUID(), Methods: map[string]*settings.FlowMethod{}} + req := &settings.Flow{Type: flow.TypeAPI, ID: x.NewUUID(), Methods: map[string]*settings.FlowMethod{}} require.NoError(t, ns(t, reg).PopulateSettingsMethod(new(http.Request), i, req)) require.Nil(t, req.Methods[identity.CredentialsTypeOIDC.String()]) }) diff --git a/selfservice/strategy/recoverytoken/persister_conformity.go b/selfservice/strategy/recoverytoken/persister_conformity.go index 48ce68090b4..4df862736b1 100644 --- a/selfservice/strategy/recoverytoken/persister_conformity.go +++ b/selfservice/strategy/recoverytoken/persister_conformity.go @@ -19,7 +19,7 @@ import ( func TestPersister(p interface { Persister - recovery.RequestPersister + recovery.FlowPersister identity.PrivilegedPool }) func(t *testing.T) { viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") @@ -33,7 +33,7 @@ func TestPersister(p interface { newRecoveryToken := func(t *testing.T, email string) *Token { var req recovery.Flow require.NoError(t, faker.FakeData(&req)) - require.NoError(t, p.CreateRecoveryRequest(context.Background(), &req)) + require.NoError(t, p.CreateRecoveryFlow(context.Background(), &req)) var i identity.Identity require.NoError(t, faker.FakeData(&i)) diff --git a/selfservice/strategy/recoverytoken/strategy.go b/selfservice/strategy/recoverytoken/strategy.go index 3fcd93316a1..39b1a6156cb 100644 --- a/selfservice/strategy/recoverytoken/strategy.go +++ b/selfservice/strategy/recoverytoken/strategy.go @@ -34,7 +34,7 @@ import ( ) const ( - PublicPath = "/self-service/browser/flows/recovery/link" // #nosec G101 + PublicPath = "/self-service/recovery/methods/link" // #nosec G101 AdminPath = "/recovery/link" ) @@ -110,7 +110,7 @@ func (s *Strategy) PopulateRecoveryMethod(r *http.Request, req *recovery.Flow) e req.Methods[s.RecoveryStrategyID()] = &recovery.FlowMethod{ Method: s.RecoveryStrategyID(), - Config: &recovery.RequestMethodConfig{RequestMethodConfigurator: &StrategyMethodConfig{HTMLForm: f}}, + Config: &recovery.FlowMethodConfig{FlowMethodConfigurator: &StrategyMethodConfig{HTMLForm: f}}, } return nil } @@ -143,10 +143,10 @@ type createRecoveryLinkParams struct { } } -// swagger:model createRecoveryLinkResponse +// swagger:model recoveryLink // // nolint -type createRecoveryLinkResponse struct { +type recoveryLink struct { // Recovery Link // // This link can be used to recover the account. @@ -177,7 +177,7 @@ type createRecoveryLinkResponse struct { // Schemes: http, https // // Responses: -// 200: createRecoveryLinkResponse +// 200: recoveryLink // 404: genericError // 400: genericError // 500: genericError @@ -203,13 +203,13 @@ func (s *Strategy) createRecoveryLink(w http.ResponseWriter, r *http.Request, _ return } - req, err := recovery.NewRequest(expiresIn, "", r, nil) + req, err := recovery.NewFlow(expiresIn, "", r, nil, flow.TypeBrowser) if err != nil { s.d.Writer().WriteError(w, r, err) return } - if err := s.d.RecoveryRequestPersister().CreateRecoveryRequest(r.Context(), req); err != nil { + if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), req); err != nil { s.d.Writer().WriteError(w, r, err) return } @@ -239,7 +239,7 @@ func (s *Strategy) createRecoveryLink(w http.ResponseWriter, r *http.Request, _ WithSensitiveField("recovery_link_token", token). Info("A recovery link has been created.") - s.d.Writer().Write(w, r, &createRecoveryLinkResponse{ + s.d.Writer().Write(w, r, &recoveryLink{ ExpiresAt: req.ExpiresAt.UTC(), RecoveryLink: urlx.CopyWithQuery( urlx.AppendPaths(s.c.SelfPublicURL(), PublicPath), @@ -249,10 +249,10 @@ func (s *Strategy) createRecoveryLink(w http.ResponseWriter, r *http.Request, _ }).String()}) } -// swagger:parameters completeSelfServiceBrowserRecoveryLinkStrategyFlow +// swagger:parameters completeSelfServiceRecoveryFlowWithLinkMethod // // nolint -type completeSelfServiceBrowserRecoveryLinkStrategyFlowParams struct { +type completeSelfServiceRecoveryFlowWithLinkMethod struct { // Email to Recover // // Needs to be set when initiating the flow. If the email is a registered @@ -270,13 +270,13 @@ type completeSelfServiceBrowserRecoveryLinkStrategyFlowParams struct { // in: query Token string `json:"token"` - // Recovery Request ID + // The Flow ID // // in: query - Request string `json:"request"` + Flow string `json:"flow"` } -// swagger:route POST /self-service/browser/flows/recovery/link public completeSelfServiceBrowserRecoveryLinkStrategyFlow +// swagger:route POST /self-service/recovery/methods/link public completeSelfServiceRecoveryFlowWithLinkMethod // // Complete the browser-based recovery flow using a recovery link // @@ -304,7 +304,7 @@ func (s *Strategy) handleSubmit(w http.ResponseWriter, r *http.Request, ps httpr } rid := r.URL.Query().Get("request") - req, err := s.d.RecoveryRequestPersister().GetRecoveryRequest(r.Context(), x.ParseUUID(rid)) + req, err := s.d.RecoveryFlowPersister().GetRecoveryFlow(r.Context(), x.ParseUUID(rid)) if err != nil { s.handleError(w, r, req, err) return @@ -333,7 +333,7 @@ func (s *Strategy) handleSubmit(w http.ResponseWriter, r *http.Request, ps httpr func (s *Strategy) issueSession(w http.ResponseWriter, r *http.Request, req *recovery.Flow) { req.State = recovery.StatePassedChallenge - if err := s.d.RecoveryRequestPersister().UpdateRecoveryRequest(r.Context(), req); err != nil { + if err := s.d.RecoveryFlowPersister().UpdateRecoveryFlow(r.Context(), req); err != nil { s.handleError(w, r, req, err) return } @@ -381,7 +381,7 @@ func (s *Strategy) verifyToken(w http.ResponseWriter, r *http.Request) { req.Messages.Clear() req.State = recovery.StatePassedChallenge req.RecoveredIdentityID = uuid.NullUUID{UUID: token.RecoveryAddress.IdentityID, Valid: true} - if err := s.d.RecoveryRequestPersister().UpdateRecoveryRequest(r.Context(), req); err != nil { + if err := s.d.RecoveryFlowPersister().UpdateRecoveryFlow(r.Context(), req); err != nil { s.handleError(w, r, req, err) return } @@ -392,14 +392,14 @@ func (s *Strategy) verifyToken(w http.ResponseWriter, r *http.Request) { func (s *Strategy) retryFlowWithMessage(w http.ResponseWriter, r *http.Request, message *text.Message) { s.d.Logger().WithRequest(r).WithField("message", message).Debug("A recovery flow is being retried because a validation error occurred.") - req, err := recovery.NewRequest(s.c.SelfServiceFlowRecoveryRequestLifespan(), s.d.GenerateCSRFToken(r), r, s.d.RecoveryStrategies()) + req, err := recovery.NewFlow(s.c.SelfServiceFlowRecoveryRequestLifespan(), s.d.GenerateCSRFToken(r), r, s.d.RecoveryStrategies(), flow.TypeBrowser) if err != nil { s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return } req.Messages.Add(message) - if err := s.d.RecoveryRequestPersister().CreateRecoveryRequest(r.Context(), req); err != nil { + if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), req); err != nil { s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return } @@ -451,7 +451,7 @@ func (s *Strategy) issueAndSendRecoveryToken(w http.ResponseWriter, r *http.Requ req.Active = sqlxx.NullString(s.RecoveryStrategyID()) req.State = recovery.StateEmailSent req.Messages.Set(text.NewRecoveryEmailSent()) - if err := s.d.RecoveryRequestPersister().UpdateRecoveryRequest(r.Context(), req); err != nil { + if err := s.d.RecoveryFlowPersister().UpdateRecoveryFlow(r.Context(), req); err != nil { s.handleError(w, r, req, err) return } @@ -503,7 +503,7 @@ func (s *Strategy) run(via identity.RecoveryAddressType, emailFunc func() error) } func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, req *recovery.Flow, err error) { - if errors.Is(err, recovery.ErrRequestExpired) { + if e := new(recovery.FlowExpiredError); errors.As(err, &e) { s.retryFlowWithMessage(w, r, text.NewErrorValidationRecoveryRecoveryTokenInvalidOrAlreadyUsed()) return } @@ -511,7 +511,7 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, req *reco if req != nil { config, err := req.MethodToForm(s.RecoveryStrategyID()) if err != nil { - s.d.RecoveryRequestErrorHandler().HandleRecoveryError(w, r, req, err, s.RecoveryStrategyID()) + s.d.RecoveryFlowErrorHandler().WriteFlowError(w, r, s.RecoveryStrategyID(), req, err) return } @@ -520,5 +520,5 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, req *reco config.SetField(form.Field{Name: "email", Type: "email", Required: true, Value: r.PostForm.Get("email")}) } - s.d.RecoveryRequestErrorHandler().HandleRecoveryError(w, r, req, err, s.RecoveryStrategyID()) + s.d.RecoveryFlowErrorHandler().WriteFlowError(w, r, s.RecoveryStrategyID(), req, err) } diff --git a/text/message_recovery.go b/text/message_recovery.go index 6fed695b76a..832130dd8ce 100644 --- a/text/message_recovery.go +++ b/text/message_recovery.go @@ -21,14 +21,26 @@ const ( ErrorValidationRecoveryStateFailure // 4060002 ErrorValidationRecoveryMissingRecoveryToken // 4060003 ErrorValidationRecoveryRecoveryTokenInvalidOrAlreadyUsed // 4060004 + ErrorValidationRecoveryFlowExpired // 4060005 ) +func NewErrorValidationRecoveryFlowExpired(ago time.Duration) *Message { + return &Message{ + ID: ErrorValidationRecoveryFlowExpired, + Text: fmt.Sprintf("The recovery flow expired %.2f minutes ago, please try again.", ago.Minutes()), + Type: Error, + Context: context(map[string]interface{}{ + "expired_at": time.Now().Add(ago), + }), + } +} + func NewRecoverySuccessful(privilegedSessionExpiresAt time.Time) *Message { hasLeft := time.Until(privilegedSessionExpiresAt) return &Message{ ID: InfoSelfServiceRecoverySuccessful, Type: Info, - Text: fmt.Sprintf("You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next %.2f minutes.", hasLeft.Minutes()), + Text: fmt.Sprintf("You successfully recovered your account. Please change your password or set up an alternative recovery method (e.g. social sign in) within the next %.2f minutes.", hasLeft.Minutes()), Context: context(map[string]interface{}{ "privilegedSessionExpiresAt": privilegedSessionExpiresAt, }),