summaryrefslogtreecommitdiff
path: root/doc/sphinx/reducer.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/sphinx/reducer.rst')
-rw-r--r--doc/sphinx/reducer.rst597
1 files changed, 341 insertions, 256 deletions
diff --git a/doc/sphinx/reducer.rst b/doc/sphinx/reducer.rst
index 320db48..50fec42 100644
--- a/doc/sphinx/reducer.rst
+++ b/doc/sphinx/reducer.rst
@@ -1,6 +1,6 @@
..
This file is part of Anastasis
- Copyright (C) 2019-2021 Anastasis SARL
+ Copyright (C) 2019-2022 Anastasis SARL
Anastasis is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -89,13 +89,23 @@ above would look like following for the transition action_ ``select_continent``:
]
}
+An action may also result into an *error response* instead of a new state.
+Clients should then render this error response to the user and allow the user
+to continue from the old state. An error response looks like this:
+
+.. code-block:: json
+
+ {
+ "code": 123,
+ "hint": "something went wrong",
+ "details": "parameter foo failed to frobnify"
+ }
+
States
^^^^^^
Overall, the reducer knows the following states:
- - **ERROR**: The transition led to an error. No further transitions are possible from
- this state, but the client may want to continue from a previous state.
- **CONTINENT_SELECTING**: The user should specify the continent where they are living,
so that we can show a list of countries to choose from.
- **COUNTRY_SELECTING**: The user should specify the country where they are living,
@@ -358,7 +368,7 @@ providers that accept payments in the selected currency:
},
{
"type": "string",
- "name": "tax_number",
+ "name": "tax_number",
"label": "Taxpayer identification number",
"label_i18n":{
"de_DE": "Steuerliche Identifikationsnummer",
@@ -366,7 +376,7 @@ providers that accept payments in the selected currency:
"en": "German taxpayer identification number"
},
"widget": "anastasis_gtk_ia_tax_de",
- "uuid": "dae48f85-e3ff-47a4-a4a3-ed981ed8c3c6",
+ "uuid": "dae48f85-e3ff-47a4-a4a3-ed981ed8c3c6",
"validation-regex": "^[0-9]{11}$",
"validation-logic": "DE_TIN_check"
},
@@ -381,8 +391,8 @@ providers that accept payments in the selected currency:
"en": "Social security number"
},
"widget": "anastasis_gtk_ia_ssn",
- "validation-regex": "^[0-9]{8}[[:upper:]][0-9]{3}$",
- "validation-logic": "DE_SVN_check"
+ "validation-regex": "^[0-9]{8}[[:upper:]][0-9]{3}$",
+ "validation-logic": "DE_SVN_check"
"optional" : true
}
],
@@ -489,27 +499,29 @@ If contacting the provider failed, the information returned is:
**add_provider**:
-This operation can be performed in state ``USER_ATTRIBUTES_COLLECTING``. It
+This operation can be performed in state ``USER_ATTRIBUTES_COLLECTING``.
+It
adds one or more Anastasis providers to the list of providers the reducer
should henceforth consider. Note that removing providers is not possible at
this time.
-Here, the client must provide an array with the base URLs of the
-providers to add, for example:
+Here, the client must provide an object with the base URLs of the
+providers to add or disable. The object maps the
+URLs to status information about the provider to
+use. For example:
.. code-block:: json
{
- "urls": [
- "http://localhost:8888/",
- "http://localhost:8089/"
- ]
+ "http://localhost:8088/" : { "disabled" : false },
+ "http://localhost:8089/" : { "disabled" : false },
+ "http://localhost:8090/" : { "disabled" : true }
}
-Note that existing providers will remain in the state. The following is an
+Note that existing providers will remain in the state they were in. The following is an
example for an expected new state where the service on port 8089 is
-unreachable, the service on port 8088 was previously known, and service on
-port 8888 was now added:
+unreachable, the services on port 8088 and 8888 were previously known, and service on
+port 8088 was now added, and on 8090 is disabled:
.. code-block:: json
@@ -517,10 +529,15 @@ port 8888 was now added:
"backup_state": "USER_ATTRIBUTES_COLLECTING",
"authentication_providers": {
"http://localhost:8089/": {
+ "disabled": false,
"error_code": 11,
"http_status": 0
},
+ "http://localhost:8090/": {
+ "disabled": true
+ },
"http://localhost:8088/": {
+ "disabled": false,
"http_status": 200,
"methods": [
{ "type" : "question",
@@ -601,16 +618,18 @@ to it:
}
If required attributes are missing, do not match the required regular
-expression, or fail the custom validation logic, the reducer SHOULD transition
-to an error state indicating what was wrong about the input. A reducer that
-does not support some specific validation logic MAY accept the invalid input
-and proceed anyway. The error state will include a Taler error code that
-is specific to the failure, and optional details. Example:
+expression, or fail the custom validation logic, the reducer SHOULD return an
+error response indicating that the transition has failed and what is wrong about
+the input and not transition to a new state. A reducer that does not support
+some specific validation logic MAY accept the invalid input and proceed anyway.
+The error state will include a Taler error code that is specific to the
+failure, and optional details.
+
+Example:
.. code-block:: json
{
- "backup_state": "ERROR",
"code": 8404,
"hint": "An input did not match the regular expression.",
"detail": "social_security_number"
@@ -703,8 +722,8 @@ response:
]
}
-If the index is invalid, the reducer will instead
-transition into an ``ERROR`` state.
+If the index is invalid, the reducer will return an error
+response instead of making a transition.
**next** (from ``AUTHENTICATIONS_EDITING``):
@@ -779,8 +798,8 @@ policy. The ``methods`` array specifies the index of the
``authentication_method`` in the ``authentication_methods`` array, as well as
the provider that was selected to supervise this authentication.
-If no authentication method was provided, the reducer will transition into an
-``ERROR`` state instead of suggesting policies.
+If no authentication method was provided, the reducer will
+return an error response instead of making a transition.
**add_policy**:
@@ -867,7 +886,7 @@ the "policies" array, returning an updated state:
If the new policy is invalid, for example because it adds an unknown
authentication method, or the selected provider does not support the type of
-authentication, the reducer will transition into an ``ERROR`` state instead of
+authentication, the reducer return an error response instead of
adding the new policy.
@@ -898,7 +917,7 @@ An example for a possible argument would thus be:
If the new policy is invalid, for example because it adds an unknown
authentication method, or the selected provider does not support the type of
-authentication, the reducer will transition into an ``ERROR`` state instead of
+authentication, the reducer will return an error response instead of
modifying the policy.
@@ -961,7 +980,7 @@ be:
]
}
-If the index given is invalid, the reducer will transition into an ``ERROR`` state
+If the index given is invalid, the reducer will return an error response
instead of deleting a policy.
@@ -1022,7 +1041,7 @@ be:
]
}
-If the index given is invalid, the reducer will transition into an ``ERROR`` state
+If the index given is invalid, the reducer will return an error response
instead of deleting a challenge.
@@ -1037,7 +1056,7 @@ The reducer will simply transition to the ``SECRET_EDITING`` state:
{
"backup_state": "SECRET_EDITING",
- "upload_fees" : [ "KUDOS:42" ],
+ "upload_fees" : [ { "fee": "KUDOS:42" } ],
"expiration" : { "t_ms" : 1245362362 }
}
@@ -1046,8 +1065,8 @@ given policy expiration time. This is an array because fees could
be in different currencies. The final cost may be lower if the
user already paid for some of the time.
-If the array of ``policies`` is currently empty, the reducer will transition
-into an ``ERROR`` state instead of allowing the user to continue.
+If the array of ``policies`` is currently empty, the reducer will
+return an error response instead of allowing the user to continue.
**enter_secret:**
@@ -1083,7 +1102,7 @@ be updated.
"mime" : "text/plain"
},
"expiration" : { "t_ms" : 1245362362 },
- "upload_fees" : [ "KUDOS:42" ]
+ "upload_fees" : [ { "fee": "KUDOS:42" } ]
}
@@ -1152,8 +1171,8 @@ Using this transition, the user confirms that the secret and expiration
settings in the current state are acceptable. The transition does not take any
arguments.
-If the secret is currently empty, the reducer will transition into an
-``ERROR`` state instead of allowing the user to continue.
+If the secret is currently empty, the reducer will return an
+error response instead of allowing the user to continue.
After adding a secret, the reducer may transition into different states
depending on whether payment(s) are necessary. If payments are needed, the
@@ -1230,14 +1249,13 @@ will wait this long before giving up. If no timeout is given, the check is
done as quickly as possible without additional delays. The reducer will continue
to either an updated state with the remaining payment requests, to the
``BACKUP_FINISHED`` state (if all payments have been completed and the backup
-finished), or into an ``ERROR`` state in case there was an irrecoverable error,
+finished), or return an error response in case there was an irrecoverable error,
indicating the specific provider and how it failed. An example for this
final error state would be:
.. code-block:: json
{
- "backup_state": "ERROR",
"http_status" : 500,
"upload_status" : 52,
"provider_url" : "https://bad.example.com/",
@@ -1276,11 +1294,73 @@ the backup process. Example arguments would thus be:
}
}
-However, in contrast to the backup process, the reducer will attempt to
-retrieve the latest recovery document from all known providers for the
-selected currency given the above inputs. If a recovery document was found
-by any provider, the reducer will attempt to load it and transition to
-a state where the user can choose which challenges to satisfy:
+Afterwards, the reducer transitions into the ``SECRET_SELECTING`` state:
+
+.. code-block:: json
+
+ {
+ "recovery_state": "SECRET_SELECTING",
+ "identity_attributes": {
+ "full_name": "Max Musterman",
+ "social_security_number": "123456789",
+ "birthdate": "2000-01-01",
+ "birthplace": "Earth"
+ }
+ }
+
+Typically, the special policy discovery process (outside of the state
+machine) is expected to be run in this state. The discovery process
+will use the state (and in particular the identity attributes and the
+list of active providers) to discover a set of possible recovery
+documents with their respective provider URLs, policy version and
+identity attribute mask. An identity attribute mask is a bitmask that
+describes which of the optional attributes from the identity
+attributes should be omitted to recover this backup. Once the user
+has selected a backup providing this triplet, it is possible to
+proceed using ``next``.
+
+Especially if the discovered policies are inadequate, it is again
+possible to add providers using ``add_provider``.
+
+
+**add_provider**:
+
+This operation can be performed in state ``SECRET_SELECTING``. It
+adds one additional Anastasis provider to the list of providers that
+the discovery process should henceforth consider. Note that removing
+providers is not possible at this time.
+
+Here, the client must provide an object with the base URL of the
+providers to add, for example:
+
+.. code-block:: json
+
+ {
+ "provider_url" : "http://localhost:8088/"
+ }
+
+
+**select_version**:
+
+Using the ``select_version`` transition in the ``SECRET_SELECTING`` state,
+it is possible to trigger the download and decryption of a recovery
+policy document. Here, the arguments specify which provider, version
+and mask should be used to download the document:
+
+.. code-block:: json
+
+ {
+ "providers" : [ {
+ "url": "https://localhost:8088/",
+ "version": 0
+ } ],
+ "attribute_mask": 0
+ }
+
+The reducer will attempt to retrieve the specified recovery document
+from that provider. If a recovery document was found, the reducer
+will attempt to load it and transition to a state where the user can
+choose which challenges to satisfy:
.. code-block:: json
@@ -1290,13 +1370,13 @@ a state where the user can choose which challenges to satisfy:
"challenges": [
{
"uuid": "MW2R3RCBZPHNC78AW8AKWRCHF9KV3Y82EN62T831ZP54S3K5599G",
- "cost": "TESTKUDOS:0",
+ "uuid-display": "MW2R3RC",
"type": "question",
"instructions": "q1"
},
{
"uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "cost": "TESTKUDOS:0",
+ "uuid-display": "TXYKGE",
"type": "email",
"instructions": "e-mail address m?il@f*.bar"
},
@@ -1330,12 +1410,11 @@ obtained and its ``version`` are also provided. Each challenge comes with
four mandatory fields:
- **uuid**: A unique identifier of the challenge; this is what the
- UUIDs in the policies array refer to, but also this UUID may be
- included in messages sent to the user. They allow the user to
+ UUIDs in the policies array refer to.
+ - **uuid-display**: Shortened idenfier which is included in messages
+ send to the user. Allows the user to
distinguish different PIN/TANs should say the same phone number be
used for SMS-authentication with different providers.
- - **cost**: This is the amount the Anastasis provider will charge
- to allow the user to pass the challenge.
- **type**: This is the type of the challenge, as a string.
- **instructions**: Contains additional important hints for the user
to allow the user to satisfy the challenge. It typically includes
@@ -1353,7 +1432,6 @@ message together with a transition failure:
.. code-block:: json
{
- "recovery_state": "ERROR",
"error_message": "account unknown to Anastasis server",
"error_code": 9,
}
@@ -1367,26 +1445,33 @@ However, in general it should be sufficient to display the slightly
more generic Taler error code that is returned with the new state.
-**change_version:**
+**sync_providers**
-Even if a recovery document was found, it is possible that the user
-intended to recover a different version, or recover a backup where
-the recovery document is stored at a different provider. Thus, the
-reducer allows the user to explicitly switch to a different provider
-or recovery document version using the ``change_version`` transition,
-which takes a provider URL and policy version as arguments:
+The downloaded policy may include secrets from providers for which
+we do not (yet) have the cost structure or even the salt. So here
+an application can use the ``sync_providers`` request to download
+``/config`` from providers that are in the challenge list but not
+yet known with their salt and other attributes in the provider list.
+
+The transition fails if all providers relevant for the selected
+policy are already downloaded. Applications may either internally
+check the state for this, or call ``sync_providers`` until it fails
+with this error:
.. code-block:: json
- {
- "provider_url": "https://localhost:8080/",
- "version": 2
- }
+ {
+ "detail": "already in sync",
+ "code": 8400,
+ "hint": "The given action is invalid for the current state of the reducer."
+ }
-Note that using a version of 0 implies fetching "the latest version". The
-resulting states are the same as those of the ``enter_user_attributes``
-transition, except that the recovery document version is not necessarily the
-latest available version at the provider.
+As providers may fail to respond, this action may need to be called
+repeatedly. The action will block until progress is made on any provider.
+As some providers may never respond, the application should disable
+challenge buttons for challenges where providers are down. However,
+users should be able to solve challenges where the provider is up while
+the reducer is polling for ``/config`` in the background.
**select_challenge:**
@@ -1442,240 +1527,240 @@ information about attempted challenges, with the final state being ``solved``:
Challenges feedback for a challenge can have many different ``state`` values
that applications must all handle. States other than ``solved`` are:
- - **payment**: Here, the user must pay for a challenge. An example would be:
+- **payment**: Here, the user must pay for a challenge. An example would be:
- .. code-block:: json
+ .. code-block:: json
- {
- "backup_state": "CHALLENGE_PAYING",
- "selected_challenge_uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30",
- "challenge_feedback": {
- "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30" : {
- "state" : "payment",
- "taler_pay_uri" : "taler://pay/...",
- "provider" : "https://localhost:8080/",
- "payment_secret" : "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
- }
- }
- }
+ {
+ "backup_state": "CHALLENGE_PAYING",
+ "selected_challenge_uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30",
+ "challenge_feedback": {
+ "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30" : {
+ "state" : "payment",
+ "taler_pay_uri" : "taler://pay/...",
+ "provider" : "https://localhost:8080/",
+ "payment_secret" : "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
+ }
+ }
+ }
- - **body**: Here, the server provided an HTTP reply for
- how to solve the challenge, but the reducer could not parse
- them into a known format. A mime-type may be provided and may
- help parse the details.
+- **body**: Here, the server provided an HTTP reply for
+ how to solve the challenge, but the reducer could not parse
+ them into a known format. A mime-type may be provided and may
+ help parse the details.
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "body",
- "body": "CROCKFORDBASE32ENCODEDBODY",
- "http_status": 403,
- "mime_type" : "anything/possible"
- }
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SOLVING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "body",
+ "body": "CROCKFORDBASE32ENCODEDBODY",
+ "http_status": 403,
+ "mime_type" : "anything/possible"
+ }
+ }
+ }
- - **hint**: Here, the server provided human-readable hint for
- how to solve the challenge. Note that the ``hint`` provided this
- time is from the Anastasis provider and may differ from the ``instructions``
- for the challenge under ``recovery_information``:
+- **hint**: Here, the server provided human-readable hint for
+ how to solve the challenge. Note that the ``hint`` provided this
+ time is from the Anastasis provider and may differ from the ``instructions``
+ for the challenge under ``recovery_information``:
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "hint",
- "hint": "Recovery TAN send to email mail@DOMAIN",
- "http_status": 403
- }
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SOLVING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "hint",
+ "hint": "Recovery TAN send to email mail@DOMAIN",
+ "http_status": 403
+ }
+ }
+ }
- - **details**: Here, the server provided a detailed JSON status response
- related to solving the challenge:
+- **details**: Here, the server provided a detailed JSON status response
+ related to solving the challenge:
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "details",
- "details": {
- "code": 8111,
- "hint": "The client's response to the challenge was invalid.",
- "detail" : null
- },
- "http_status": 403
- }
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SOLVING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "details",
+ "details": {
+ "code": 8111,
+ "hint": "The client's response to the challenge was invalid.",
+ "detail" : null
+ },
+ "http_status": 403
+ }
+ }
+ }
- - **redirect**: To solve the challenge, the user must visit the indicated
- Web site at ``redirect_url``, for example to perform video authentication:
+- **redirect**: To solve the challenge, the user must visit the indicated
+ Web site at ``redirect_url``, for example to perform video authentication:
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "redirect",
- "redirect_url": "https://videoconf.example.com/",
- "http_status": 303
- }
+ {
+ "recovery_state": "CHALLENGE_SOLVING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "redirect",
+ "redirect_url": "https://videoconf.example.com/",
+ "http_status": 303
}
}
+ }
- - **server-failure**: This indicates that the Anastasis provider encountered
- a failure and recovery using this challenge cannot proceed at this time.
- Examples for failures might be that the provider is unable to send SMS
- messages at this time due to an outage. The body includes details about
- the failure. The user may try again later or continue with other challenges.
+- **server-failure**: This indicates that the Anastasis provider encountered
+ a failure and recovery using this challenge cannot proceed at this time.
+ Examples for failures might be that the provider is unable to send SMS
+ messages at this time due to an outage. The body includes details about
+ the failure. The user may try again later or continue with other challenges.
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "server-failure",
- "http_status": "500",
- "error_code": 52
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": {
+ "...": "..."
}
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "server-failure",
+ "http_status": "500",
+ "error_code": 52
+ }
+ }
+ }
- - **truth-unknown**: This indicates that the Anastasis provider is unaware of
- the specified challenge. This is typically a permanent failure, and user
- interfaces should not allow users to re-try this challenge.
+- **truth-unknown**: This indicates that the Anastasis provider is unaware of
+ the specified challenge. This is typically a permanent failure, and user
+ interfaces should not allow users to re-try this challenge.
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "truth-unknown",
- "error_code": 8108
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "truth-unknown",
+ "error_code": 8108
}
+ }
+ }
- - **rate-limit-exceeded**: This indicates that the user has made too many invalid attempts in too short an amount of time.
+- **rate-limit-exceeded**: This indicates that the user has made too many invalid attempts in too short an amount of time.
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "rate-limit-exceeded",
- "error_code": 8121
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "rate-limit-exceeded",
+ "error_code": 8121
}
+ }
+ }
- - **authentication-timeout**: This indicates that the challenge is awaiting for some external authentication process to complete. The application should ``poll`` for it to complete, or proceed with selecting other challenges.
+- **authentication-timeout**: This indicates that the challenge is awaiting for some external authentication process to complete. The application should ``poll`` for it to complete, or proceed with selecting other challenges.
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "authentication-timeout",
- "error_code": 8122
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "authentication-timeout",
+ "error_code": 8122
}
+ }
+ }
- - **authentication-instructions**: This indicates that the challenge requires the user to perform some authentication method-specific actions. Details about what the user should do are provided.
+- **external-instructions**: This indicates that the challenge requires the user to perform some authentication method-specific actions. Details about what the user should do are provided.
- .. code-block:: json
+ .. code-block:: json
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "external-instructions",
- "method": "iban",
- "async": true, // optional
- "answer_code": 987654321, // optional
- "details": {
- "...": "..."
- }
- }
- }
- }
+ {
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": {
+ "...": "..."
+ }
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": {
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+ "state": "external-instructions",
+ "method": "iban",
+ "async": true, // optional
+ "answer_code": 987654321, // optional
+ "details": {
+ "...": "..."
+ }
+ }
+ }
+ }
- If "async" is "true", then the client should
- poll for the challenge being satisfied using
- the "answer_code" that has been provided.
+ If "async" is "true", then the client should
+ poll for the challenge being satisfied using
+ the "answer_code" that has been provided.
- The specific instructions on how to satisfy
- the challenge depend on the ``method``.
- They include:
+ The specific instructions on how to satisfy
+ the challenge depend on the ``method``.
+ They include:
- - **iban**: The user must perform a wire transfer from their account to the Anastasis provider.
+ - **iban**: The user must perform a wire transfer from their account to the Anastasis provider.
- .. code-block:: json
+ .. code-block:: json
- {
- "challenge_amount": "EUR:1",
- "credit_iban": "DE12345789000",
- "business_name": "Data Loss Incorporated",
- "wire_transfer_subject": "Anastasis 987654321"
- }
+ {
+ "challenge_amount": "EUR:1",
+ "credit_iban": "DE12345789000",
+ "business_name": "Data Loss Incorporated",
+ "wire_transfer_subject": "Anastasis 987654321"
+ }
- Note that the actual wire transfer subject must contain both
- the numeric ``answer_code`` as well as
- the string ``Anastasis``.
+ Note that the actual wire transfer subject must contain both
+ the numeric ``answer_code`` as well as
+ the string ``Anastasis``.
**poll:**
-With a ``poll`` transition, the application indicates that it wants to wait longer for one or more of the challenges that are in state ``authentication-timeout`` to possibly complete. While technically optional, the ``timeout`` argument should really be provided to enable long-polling, for example:
+With a ``poll`` transition, the application indicates that it wants to wait longer for one or more of the challenges that are awaiting some external authentication (state ``external-instructions``) or experienced some kind of timeout (state ``authentication-timeout``) to possibly complete. While technically optional, the ``timeout`` argument should really be provided to enable long-polling, for example:
.. code-block:: json