aboutsummaryrefslogtreecommitdiff
path: root/doc/sphinx/reducer.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/sphinx/reducer.rst')
-rw-r--r--doc/sphinx/reducer.rst1656
1 files changed, 1656 insertions, 0 deletions
diff --git a/doc/sphinx/reducer.rst b/doc/sphinx/reducer.rst
new file mode 100644
index 0000000..e5f1699
--- /dev/null
+++ b/doc/sphinx/reducer.rst
@@ -0,0 +1,1656 @@
1..
2 This file is part of Anastasis
3 Copyright (C) 2019-2021 Anastasis SARL
4
5 Anastasis is free software; you can redistribute it and/or modify it under the
6 terms of the GNU Affero General Public License as published by the Free Software
7 Foundation; either version 2.1, or (at your option) any later version.
8
9 Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
12
13 You should have received a copy of the GNU Affero General Public License along with
14 Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15
16 @author Christian Grothoff
17 @author Dominik Meister
18 @author Dennis Neufeld
19
20-----------
21Reducer API
22-----------
23
24This section describes the Anastasis Reducer API which is used by client applications
25to store or load the different states the client application can have.
26The reducer takes a state_ in JSON syntax and returns the new state in JSON syntax.
27
28For example a **state** may take the following structure:
29
30.. code-block:: json
31
32 {
33 "backup_state": "CONTINENT_SELECTING",
34 "continents": [
35 "Europe",
36 "North_America"
37 ]
38 }
39
40The new state depends on the previous one and on the transition action_ with its
41arguments given to the reducer. A **transition argument** also is a statement in JSON syntax:
42
43.. code-block:: json
44
45 {
46 "continent": "Europe"
47 }
48
49The new state returned by the reducer with the state and transition argument defined
50above would look like following for the transition action_ ``select_continent``:
51
52.. code-block:: json
53
54 {
55 "backup_state": "COUNTRY_SELECTING",
56 "continents": [
57 "Europe",
58 "North_America"
59 ],
60 "selected_continent": "Europe",
61 "countries": [
62 {
63 "code": "ch",
64 "name": "Switzerland",
65 "continent": "Europe",
66 "name_i18n": {
67 "de_DE": "Schweiz",
68 "de_CH": "Schwiiz",
69 "fr": "Suisse",
70 "en": "Swiss"
71 },
72 "currency": "CHF"
73 },
74 {
75 "code": "de",
76 "name": "Germany",
77 "continent": "Europe",
78 "continent_i18n": {
79 "de": "Europa"
80 },
81 "name_i18n": {
82 "de_DE": "Deutschland",
83 "de_CH": "Deutschland",
84 "fr": "Allemagne",
85 "en": "Germany"
86 },
87 "currency": "EUR"
88 }
89 ]
90 }
91
92States
93^^^^^^
94
95Overall, the reducer knows the following states:
96
97 - **ERROR**: The transition led to an error. No further transitions are possible from
98 this state, but the client may want to continue from a previous state.
99 - **CONTINENT_SELECTING**: The user should specify the continent where they are living,
100 so that we can show a list of countries to choose from.
101 - **COUNTRY_SELECTING**: The user should specify the country where they are living,
102 so that we can determine appropriate attributes, currencies and Anastasis
103 providers.
104 - **USER_ATTRIBUTES_COLLECTING**: The user should provide the country-specific personal
105 attributes.
106 - **AUTHENTICATIONS_EDITING**: The user should add authentication methods to be used
107 during recovery.
108 - **POLICIES_REVIEWING**: The user should review the recovery policies.
109 - **SECRET_EDITING**: The user should edit the secret to be backed up.
110 - **TRUTHS_PAYING**: The user needs to pay for one or more uploads of data associated
111 with an authentication method.
112 - **POLICIES_PAYING**: The user needs to pay for storing the recovery policy document.
113 - **BACKUP_FINISHED**: A backup has been successfully generated.
114 - **SECRET_SELECTING**: The user needs to select a recovery policy document with
115 the secret that is to be recovered.
116 - **CHALLENGE_SELECTING**: The user needs to select an authorization challenge to
117 proceed with recovery.
118 - **CHALLENGE_PAYING**: The user needs to pay to proceed with the authorization challenge.
119 - **CHALLENGE_SOLVING**: The user needs to solve the authorization challenge.
120 - **RECOVERY_FINISHED**: The secret of the user has been recovered.
121
122State names:
123
124 - In SELECTING-states, the user has to choose one value out of a predefined set of values (for example a continent out of a set of continents).
125 - In COLLECTING-states, the user has to give certain values.
126 - In EDITING-states, the user is free to choose which values he wants to give.
127 - In REVEIWING-states, the user may make a few choices, but primarily is expected to affirm something.
128 - in PAYING-states, the user must make a payment.
129 - in FINISHED-states, the operation has definitively concluded.
130
131
132Backup Reducer
133^^^^^^^^^^^^^^
134.. _state:
135.. _action:
136.. figure:: anastasis_reducer_backup.png
137 :name: fig-anastasis_reducer_backup
138 :alt: fig-anastasis_reducer_backup
139 :scale: 75 %
140 :align: center
141
142 Backup states and their transitions.
143
144
145The illustration above shows the different states the reducer can have during a backup
146process.
147
148
149Recovery Reducer
150^^^^^^^^^^^^^^^^
151.. figure:: anastasis_reducer_recovery.png
152 :name: fig-anastasis_reducer_recovery
153 :alt: fig-anastasis_reducer_recovery
154 :scale: 75 %
155 :align: center
156
157 Recovery states and their transitions.
158
159
160The illustration above shows the different states the reducer can have during a recovery
161process.
162
163
164Reducer transitions
165^^^^^^^^^^^^^^^^^^^
166In the following, the individual transitions will be specified in more detail.
167Note that we only show fields added by the reducer, typically the previous
168state is preserved to enable "back" transitions to function smoothly.
169
170
171Initial state
172-------------
173
174The initial states for backup and recovery processes are:
175
176**Initial backup state:**
177
178.. code-block:: json
179
180 {
181 "backup_state": "CONTINENT_SELECTING",
182 "continents": [
183 "Europe",
184 "North America"
185 ]
186 }
187
188
189**Initial recovery state:**
190
191.. code-block:: json
192
193 {
194 "recovery_state": "CONTINENT_SELECTING",
195 "continents": [
196 "Europe",
197 "North America"
198 ]
199 }
200
201Here, "continents" is an array of English strings with the names of the
202continents which contain countries for which Anastasis could function (based
203on having providers that are known to operate and rules being provided for
204user attributes from those countries).
205
206For internationalization, another field ``continents_i18n`` may be present.
207This field would be a map of language names to arrays of translated
208continent names:
209
210.. code-block:: json
211
212 {
213 "recovery_state": "CONTINENT_SELECTING",
214 "continents": [
215 "Europe",
216 "North America"
217 ]
218 "continents_i18n":
219 {
220 "de_DE" : [
221 "Europa",
222 "Nordamerika"
223 ],
224 "de_CH" : [
225 "Europa",
226 "Nordamerika"
227 ]
228 }
229 }
230
231Translations must be given in the same order as the main English array.
232
233
234Common transitions
235------------------
236
237**select_continent:**
238
239Here the user specifies the continent they live on. Arguments (example):
240
241.. code-block:: json
242
243 {
244 "continent": "Europe"
245 }
246
247The continent must be given using the English name from the ``continents`` array.
248Using a translated continent name is invalid and may result in failure.
249
250The reducer returns an updated state with a list of countries to choose from,
251for example:
252
253.. code-block:: json
254
255 {
256 "backup_state": "COUNTRY_SELECTING",
257 "selected_continent": "Europe",
258 "countries": [
259 {
260 "code": "ch",
261 "name": "Switzerland",
262 "continent": "Europe",
263 "name_i18n": {
264 "de_DE": "Schweiz",
265 "de_CH": "Schwiiz",
266 "fr": "Suisse",
267 "en": "Swiss"
268 },
269 "currency": "CHF"
270 },
271 {
272 "code": "de",
273 "name": "Germany",
274 "continent": "Europe",
275 "continent_i18n": {
276 "de": "Europa"
277 },
278 "name_i18n": {
279 "de_DE": "Deutschland",
280 "de_CH": "Deutschland",
281 "fr": "Allemagne",
282 "en": "Germany"
283 },
284 "currency": "EUR"
285 }
286 ]
287 }
288
289Here ``countries`` is an array of countries on the ``selected_continent``. For
290each country, the ``code`` is the ISO 3166-1 alpha-2 country code. The
291``continent`` is only present because some countries span continents, the
292information is redundant and will always match ``selected_continent``. The
293``name`` is the name of the country in English, internationalizations of the
294name may be provided in ``name_i18n``. The ``currency`` is **an** official
295currency of the country, if a country has multiple currencies, it may appear
296multiple times in the list. In this case, the user should select the entry
297with the currency they intend to pay with. It is also possible for users
298to select a currency that does not match their country, but user interfaces
299should by default try to use currencies that match the user's residence.
300
301
302**select_country:**
303
304Selects the country (via the country code) and specifies the currency.
305The latter is needed as some countries have more than one currency,
306and some use-cases may also involve users insisting on paying with
307foreign currency.
308
309Arguments (example):
310
311.. code-block:: json
312
313 {
314 "country_code": "de",
315 "currency": "EUR"
316 }
317
318The ``country_code`` must be an ISO 3166-1 alpha-2 country code from
319the array of ``countries`` of the reducer's state. The ``currency``
320field must be a valid currency accepted by the Taler payment system.
321
322The reducer returns a new state with the list of attributes the
323user is expected to provide, as well as possible authentication
324providers that accept payments in the selected currency:
325
326.. code-block:: json
327
328 {
329 "backup_state": "USER_ATTRIBUTES_COLLECTING",
330 "selected_country": "de",
331 "currency": "EUR",
332 "required_attributes": [
333 {
334 "type": "string",
335 "name": "full_name",
336 "label": "Full name",
337 "label_i18n": {
338 "de_DE": "Vollstaendiger Name",
339 "de_CH": "Vollstaendiger. Name",
340 "fr": "Nom complet",
341 "en": "Full name"
342 },
343 "widget": "anastasis_gtk_ia_full_name",
344 "uuid" : "9e8f463f-575f-42cb-85f3-759559997331"
345 },
346 {
347 "type": "date",
348 "name": "birthdate",
349 "label": "Birthdate",
350 "label_i18n": {
351 "de_DE": "Geburtsdatum",
352 "de_CH": "Geburtsdatum",
353 "fr": "Date de naissance",
354 "en": "Birthdate"
355 },
356 "uuid" : "83d655c7-bdb6-484d-904e-80c1058c8854"
357 "widget": "anastasis_gtk_ia_birthdate"
358 },
359 {
360 "type": "string",
361 "name": "tax_number",
362 "label": "Taxpayer identification number",
363 "label_i18n":{
364 "de_DE": "Steuerliche Identifikationsnummer",
365 "de_CH": "Steuerliche Identifikationsnummer",
366 "en": "German taxpayer identification number"
367 },
368 "widget": "anastasis_gtk_ia_tax_de",
369 "uuid": "dae48f85-e3ff-47a4-a4a3-ed981ed8c3c6",
370 "validation-regex": "^[0-9]{11}$",
371 "validation-logic": "DE_TIN_check"
372 },
373 {
374 "type": "string",
375 "name": "social_security_number",
376 "label": "Social security number",
377 "label_i18n": {
378 "de_DE": "Sozialversicherungsnummer",
379 "de_CH": "Sozialversicherungsnummer",
380 "fr": "Numéro de sécurité sociale",
381 "en": "Social security number"
382 },
383 "widget": "anastasis_gtk_ia_ssn",
384 "validation-regex": "^[0-9]{8}[[:upper:]][0-9]{3}$",
385 "validation-logic": "DE_SVN_check"
386 "optional" : true
387 }
388 ],
389 "authentication_providers": {
390 "http://localhost:8089/": {
391 "http_status": 200,
392 "methods": [
393 { "type" : "question",
394 "usage_fee" : "EUR:0.0" },
395 { "type" : "sms",
396 "usage_fee" : "EUR:0.5" }
397 ],
398 "annual_fee": "EUR:4.99",
399 "truth_upload_fee": "EUR:4.99",
400 "liability_limit": "EUR:1",
401 "currency": "EUR",
402 "truth_lifetime": { "d_ms" : 50000000 },
403 "storage_limit_in_megabytes": 1,
404 "provider_name": "Anastasis 4",
405 "salt": "CXAPCKSH9D3MYJTS9536RHJHCW"
406 },
407 "http://localhost:8088/": {
408 "http_status": 200,
409 "methods": [
410 { "type" : "question",
411 "usage_fee" : "EUR:0.01" },
412 { "type" : "sms",
413 "usage_fee" : "EUR:0.55" }
414 ],
415 "annual_fee": "EUR:0.99",
416 "truth_upload_fee": "EUR:3.99",
417 "liability_limit": "EUR:1",
418 "currency": "EUR",
419 "truth_lifetime": { "d_ms" : 50000000 },
420 "storage_limit_in_megabytes": 1,
421 "provider_name": "Anastasis 4",
422 "salt": "CXAPCKSH9D3MYJTS9536RHJHCW"
423 }
424 }
425 }
426
427The array of ``required_attributes`` contains attributes about the user
428that must be provided includes:
429
430 - **type**: The type of the attribute, for now only ``string`` and ``date`` are
431 supported.
432 - **name**: The name of the attribute, this is the key under which the
433 attribute value must be provided later. The name must be unique per response.
434 - **label**: A human-readable description of the attribute in English.
435 Translated descriptions may be provided under **label_i18n**.
436 - **uuid**: A UUID that uniquely identifies identical attributes across
437 different countries. Useful to preserve values should the user enter
438 some attributes, and then switch to another country. Note that
439 attributes must not be preserved if they merely have the same **name**,
440 only the **uuid** will be identical if the semantics is identical.
441 - **widget**: An optional name of a widget that is known to nicely render
442 the attribute entry in user interfaces where named widgets are
443 supported.
444 - **validation-regex**: An optional extended POSIX regular expression
445 that is to be used to validate (string) inputs to ensure they are
446 well-formed.
447 - **validation-logic**: Optional name of a function that should be called
448 to validate the input. If the function is not known to the particular
449 client, the respective validation can be skipped (at the expense of
450 typos by users not being detected, possibly rendering secrets
451 irrecoverable).
452 - **optional**: Optional boolean field that, if ``true``, indicates that
453 this attribute is not actually required but optional and users MAY leave
454 it blank in case they do not have the requested information. Used for
455 common fields that apply to some large part of the population but are
456 not sufficiently universal to be actually required.
457
458The authentication providers are listed under a key that is the
459base URL of the service. For each provider, the following
460information is provided if the provider was successfully contacted:
461
462 - **http_status**: HTTP status code, always ``200`` on success.
463 - **methods**: Array of authentication methods supported by this
464 provider. Includes the **type** of the authentication method
465 and the **usage_fee** (how much the user must pay for authorization
466 using this method during recovery).
467 - **annual_fee**: Fee the provider charges to store the recovery
468 policy for one year.
469 - **truth_upload_fee**: Fee the provider charges to store a key share.
470 - **liability_limit**: Amount the provider can be held liable for in
471 case a key share or recovery document cannot be recovered due to
472 provider failures.
473 - **currency**: Currency in which the provider wants to be paid,
474 will match all of the fees.
475 - **storage_limit_in_megabytes**: Maximum size of an upload (for
476 both recovery document and truth data) in megabytes.
477 - **provider_name**: Human-readable name of the provider's business.
478 - **salt**: Salt value used by the provider, used to derive the
479 user's identity at this provider. Should be unique per provider,
480 and must never change for a given provider. The salt is
481 base32 encoded.
482
483If contacting the provider failed, the information returned is:
484
485 - **http_status**: HTTP status code (if available, possibly 0 if
486 we did not even obtain an HTTP response).
487 - **error_code**: Taler error code, never 0.
488
489
490**add_provider**:
491
492This operation can be performed in state ``USER_ATTRIBUTES_COLLECTING``. It
493adds one or more Anastasis providers to the list of providers the reducer
494should henceforth consider. Note that removing providers is not possible at
495this time.
496
497Here, the client must provide an array with the base URLs of the
498providers to add, for example:
499
500.. code-block:: json
501
502 {
503 "urls": [
504 "http://localhost:8888/",
505 "http://localhost:8089/"
506 ]
507 }
508
509Note that existing providers will remain in the state. The following is an
510example for an expected new state where the service on port 8089 is
511unreachable, the service on port 8088 was previously known, and service on
512port 8888 was now added:
513
514.. code-block:: json
515
516 {
517 "backup_state": "USER_ATTRIBUTES_COLLECTING",
518 "authentication_providers": {
519 "http://localhost:8089/": {
520 "error_code": 11,
521 "http_status": 0
522 },
523 "http://localhost:8088/": {
524 "http_status": 200,
525 "methods": [
526 { "type" : "question",
527 "usage_fee" : "EUR:0.01" },
528 { "type" : "sms",
529 "usage_fee" : "EUR:0.55" }
530 ],
531 "annual_fee": "EUR:0.99",
532 "truth_upload_fee": "EUR:3.99",
533 "liability_limit": "EUR:1",
534 "currency": "EUR",
535 "truth_lifetime": { "d_ms" : 50000000 },
536 "storage_limit_in_megabytes": 1,
537 "provider_name": "Anastasis 4",
538 "salt": "CXAPCKSH9D3MYJTS9536RHJHCW"
539 }
540 "http://localhost:8888/": {
541 "methods": [
542 { "type" : "question",
543 "usage_fee" : "EUR:0.01" },
544 { "type" : "sms",
545 "usage_fee" : "EUR:0.55" }
546 ],
547 "annual_fee": "EUR:0.99",
548 "truth_upload_fee": "EUR:3.99",
549 "liability_limit": "EUR:1",
550 "currency": "EUR",
551 "truth_lifetime": { "d_ms" : 50000000 },
552 "storage_limit_in_megabytes": 1,
553 "provider_name": "Anastasis 42",
554 "salt": "BXAPCKSH9D3MYJTS9536RHJHCX"
555 }
556 }
557 }
558
559
560
561Backup transitions
562------------------
563
564**enter_user_attributes:**
565
566This transition provides the user's personal attributes. The specific set of
567attributes required depends on the country of residence of the user. Some
568attributes may be optional, in which case they should be omitted entirely
569(that is, not simply be set to ``null`` or an empty string). Example
570arguments would be:
571
572.. code-block:: json
573
574 {
575 "identity_attributes": {
576 "full_name": "Max Musterman",
577 "social_security_number": "123456789",
578 "birthdate": "2000-01-01",
579 "birthplace": "Earth"
580 }
581 }
582
583Note that at this stage, the state machines between backup and
584recovery diverge and the ``recovery_state`` will begin to look
585very different from the ``backup_state``.
586
587For backups, if all required attributes are present, the reducer will
588transition to an ``AUTHENTICATIONS_EDITING`` state with the attributes added
589to it:
590
591.. code-block:: json
592
593 {
594 "backup_state": "AUTHENTICATIONS_EDITING",
595 "identity_attributes": {
596 "full_name": "Max Musterman",
597 "social_security_number": "123456789",
598 "birthdate": "2000-01-01",
599 "birthplace": "Earth"
600 }
601 }
602
603If required attributes are missing, do not match the required regular
604expression, or fail the custom validation logic, the reducer SHOULD transition
605to an error state indicating what was wrong about the input. A reducer that
606does not support some specific validation logic MAY accept the invalid input
607and proceed anyway. The error state will include a Taler error code that
608is specific to the failure, and optional details. Example:
609
610.. code-block:: json
611
612 {
613 "backup_state": "ERROR",
614 "code": 8404,
615 "hint": "An input did not match the regular expression.",
616 "detail": "social_security_number"
617 }
618
619Clients may safely repeat this transition to validate the user's inputs
620until they satisfy all of the constraints. This way, the user interface
621does not have to perform the input validation directly.
622
623
624**add_authentication**:
625
626This transition adds an authentication method. The method must be supported
627by one or more providers that are included in the current state. Adding an
628authentication method requires specifying the ``type`` and ``instructions`` to
629be given to the user. The ``challenge`` is encrypted and stored at the
630Anastasis provider. The specific semantics of the value depend on the
631``type``. Typical challenges values are a phone number (to send an SMS to),
632an e-mail address (to send a PIN code to) or the answer to a security
633question. Note that these challenge values will still be encrypted (and
634possibly hashed) before being given to the Anastasis providers.
635
636Note that the ``challenge`` must be given in Crockford Base32 encoding, as it
637MAY include binary data (such as a photograph of the user). In the latter
638case, the optional ``mime_type`` field must be provided to give the MIME type
639of the value encoded in ``challenge``.
640
641.. code-block:: json
642
643 {
644 "authentication_method":
645 {
646 "type": "question",
647 "mime_type" : "text/plain",
648 "instructions" : "What is your favorite GNU package?",
649 "challenge" : "E1QPPS8A",
650 }
651 }
652
653If the information provided is valid, the reducer will add the new
654authentication method to the array of authentication methods:
655
656.. code-block:: json
657
658 {
659 "backup_state": "AUTHENTICATIONS_EDITING",
660 "authentication_methods": [
661 {
662 "type": "question",
663 "mime_type" : "text/plain",
664 "instructions" : "What is your favorite GNU package?",
665 "challenge" : "E1QPPS8A",
666 },
667 {
668 "type": "email",
669 "instructions" : "E-mail to user@*le.com",
670 "challenge": "ENSPAWJ0CNW62VBGDHJJWRVFDM50"
671 }
672 ]
673 }
674
675
676**delete_authentication**:
677
678This transition can be used to remove an authentication method from the
679array of authentication methods. It simply requires the index of the
680authentication method to remove. Note that the array is 0-indexed:
681
682.. code-block:: json
683
684 {
685 "authentication_method": 1
686 }
687
688Assuming we begin with the state from the example above, this would
689remove the ``email`` authentication method, resulting in the following
690response:
691
692.. code-block:: json
693
694 {
695 "backup_state": "AUTHENTICATIONS_EDITING",
696 "authentication_methods": [
697 {
698 "type": "question",
699 "mime_type" : "text/plain",
700 "instructions" : "What is your favorite GNU package?",
701 "challenge" : "gdb",
702 }
703 ]
704 }
705
706If the index is invalid, the reducer will instead
707transition into an ``ERROR`` state.
708
709
710**next** (from ``AUTHENTICATIONS_EDITING``):
711
712This transition confirms that the user has finished adding (or removing)
713authentication methods, and that the system should now automatically compute
714a set of reasonable recovery policies.
715
716This transition does not take any mandatory arguments. Optional arguments can
717be provided to upload the recovery document only to a specific subset of the
718providers:
719
720.. code-block:: json
721
722 {
723 "providers": [
724 "http://localhost:8088/",
725 "http://localhost:8089/"
726 ]
727 }
728
729The resulting state provides the suggested recovery policies in a way suitable
730for presentation to the user:
731
732.. code-block:: javascript
733
734 {
735 "backup_state": "POLICIES_REVIEWING",
736 "policy_providers" : [
737 { "provider_url" : "http://localhost:8088/" },
738 { "provider_url" : "http://localhost:8089/" }
739 ],
740 "policies": [
741 {
742 "methods": [
743 {
744 "authentication_method": 0,
745 "provider": "http://localhost:8088/"
746 },
747 {
748 "authentication_method": 1,
749 "provider": "http://localhost:8089/"
750 },
751 {
752 "authentication_method": 2,
753 "provider": "http://localhost:8087/"
754 }
755 ]
756 },
757 {
758 "methods": [
759 {
760 "authentication_method": 0,
761 "provider": "http://localhost:8088/"
762 },
763 {
764 "authentication_method": 1,
765 "provider": "http://localhost:8089/"
766 },
767 {
768 "authentication_method": 3,
769 "provider": "http://localhost:8089/"
770 }
771 ]
772 }
773 ]
774 }
775
776For each recovery policy, the state includes the specific details of which
777authentication ``methods`` must be solved to recovery the secret using this
778policy. The ``methods`` array specifies the index of the
779``authentication_method`` in the ``authentication_methods`` array, as well as
780the provider that was selected to supervise this authentication.
781
782If no authentication method was provided, the reducer will transition into an
783``ERROR`` state instead of suggesting policies.
784
785
786**add_policy**:
787
788Using this transition, the user can add an additional recovery policy to the
789state. The argument format is the same that is used in the existing state.
790An example for a possible argument would thus be:
791
792.. code-block:: javascript
793
794 {
795 "policy": [
796 {
797 "authentication_method": 1,
798 "provider": "http://localhost:8088/"
799 },
800 {
801 "authentication_method": 3,
802 "provider": "http://localhost:8089/"
803 }
804 ]
805 }
806
807Note that the specified providers must already be in the
808``authentication_providers`` of the state. You cannot add new providers at
809this stage. The reducer will simply attempt to append the suggested policy to
810the "policies" array, returning an updated state:
811
812.. code-block:: json
813
814 {
815 "backup_state": "POLICIES_REVIEWING",
816 "policies": [
817 {
818 "methods": [
819 {
820 "authentication_method": 0,
821 "provider": "http://localhost:8089/"
822 },
823 {
824 "authentication_method": 1,
825 "provider": "http://localhost:8088/"
826 }
827 ]
828 },
829 {
830 "methods": [
831 {
832 "authentication_method": 0,
833 "provider": "http://localhost:8089/"
834 },
835 {
836 "authentication_method": 2,
837 "provider": "http://localhost:8088/"
838 }
839 ]
840 },
841 {
842 "methods": [
843 {
844 "authentication_method": 1,
845 "provider": "http://localhost:8089/"
846 },
847 {
848 "authentication_method": 2,
849 "provider": "http://localhost:8088/"
850 }
851 ]
852 },
853 {
854 "methods": [
855 {
856 "authentication_method": 1,
857 "provider": "http://localhost:8088/"
858 },
859 {
860 "authentication_method": 3,
861 "provider": "http://localhost:8089/"
862 }
863 ]
864 }
865 ]
866 }
867
868If the new policy is invalid, for example because it adds an unknown
869authentication method, or the selected provider does not support the type of
870authentication, the reducer will transition into an ``ERROR`` state instead of
871adding the new policy.
872
873
874**update_policy**:
875
876Using this transition, the user can modify an existing recovery policy
877in the state.
878The argument format is the same that is used in **add_policy**,
879except there is an additional key ``policy_index`` which
880identifies the policy to modify.
881An example for a possible argument would thus be:
882
883.. code-block:: javascript
884
885 {
886 "policy_index" : 1,
887 "policy": [
888 {
889 "authentication_method": 1,
890 "provider": "http://localhost:8088/"
891 },
892 {
893 "authentication_method": 3,
894 "provider": "http://localhost:8089/"
895 }
896 ]
897 }
898
899If the new policy is invalid, for example because it adds an unknown
900authentication method, or the selected provider does not support the type of
901authentication, the reducer will transition into an ``ERROR`` state instead of
902modifying the policy.
903
904
905
906**delete_policy:**
907
908This transition allows the deletion of a recovery policy. The argument
909simply specifies the index of the policy to delete, for example:
910
911.. code-block:: json
912
913 {
914 "policy_index": 3
915 }
916
917Given as input the state from the example above, the expected new state would
918be:
919
920.. code-block:: json
921
922 {
923 "backup_state": "POLICIES_REVIEWING",
924 "policies": [
925 {
926 "methods": [
927 {
928 "authentication_method": 0,
929 "provider": "http://localhost:8089/"
930 },
931 {
932 "authentication_method": 1,
933 "provider": "http://localhost:8088/"
934 }
935 ]
936 },
937 {
938 "methods": [
939 {
940 "authentication_method": 0,
941 "provider": "http://localhost:8089/"
942 },
943 {
944 "authentication_method": 2,
945 "provider": "http://localhost:8088/"
946 }
947 ]
948 },
949 {
950 "methods": [
951 {
952 "authentication_method": 1,
953 "provider": "http://localhost:8089/"
954 },
955 {
956 "authentication_method": 2,
957 "provider": "http://localhost:8088/"
958 }
959 ]
960 }
961 ]
962 }
963
964If the index given is invalid, the reducer will transition into an ``ERROR`` state
965instead of deleting a policy.
966
967
968**delete_challenge:**
969
970This transition allows the deletion of an individual
971challenge from a recovery policy. The argument
972simply specifies the index of the policy and challenge
973to delete, for example:
974
975.. code-block:: json
976
977 {
978 "policy_index": 1,
979 "challenge_index" : 1
980 }
981
982Given as input the state from the example above, the expected new state would
983be:
984
985.. code-block:: json
986
987 {
988 "backup_state": "POLICIES_REVIEWING",
989 "policies": [
990 {
991 "methods": [
992 {
993 "authentication_method": 0,
994 "provider": "http://localhost:8089/"
995 },
996 {
997 "authentication_method": 1,
998 "provider": "http://localhost:8088/"
999 }
1000 ]
1001 },
1002 {
1003 "methods": [
1004 {
1005 "authentication_method": 0,
1006 "provider": "http://localhost:8089/"
1007 }
1008 ]
1009 },
1010 {
1011 "methods": [
1012 {
1013 "authentication_method": 1,
1014 "provider": "http://localhost:8089/"
1015 },
1016 {
1017 "authentication_method": 2,
1018 "provider": "http://localhost:8088/"
1019 }
1020 ]
1021 }
1022 ]
1023 }
1024
1025If the index given is invalid, the reducer will transition into an ``ERROR`` state
1026instead of deleting a challenge.
1027
1028
1029**next** (from ``POLICIES_REVIEWING``):
1030
1031Using this transition, the user confirms that the policies in the current
1032state are acceptable. The transition does not take any arguments.
1033
1034The reducer will simply transition to the ``SECRET_EDITING`` state:
1035
1036.. code-block:: json
1037
1038 {
1039 "backup_state": "SECRET_EDITING",
1040 "upload_fees" : [ "KUDOS:42" ],
1041 "expiration" : { "t_ms" : 1245362362 }
1042 }
1043
1044Here, ``upload_fees`` is an array of applicable upload fees for the
1045given policy expiration time. This is an array because fees could
1046be in different currencies. The final cost may be lower if the
1047user already paid for some of the time.
1048
1049If the array of ``policies`` is currently empty, the reducer will transition
1050into an ``ERROR`` state instead of allowing the user to continue.
1051
1052
1053**enter_secret:**
1054
1055This transition provides the reducer with the actual core ``secret`` of the user
1056that Anastasis is supposed to backup (and possibly recover). The argument is
1057simply the Crockford-Base32 encoded ``value`` together with its ``mime`` type, or a ``text`` field with a human-readable secret text.
1058For example:
1059
1060.. code-block:: javascript
1061
1062 {
1063 "secret": {
1064 "value": "EDJP6WK5EG50",
1065 "mime" : "text/plain"
1066 },
1067 "expiration" : { "t_ms" : 1245362362 }
1068 }
1069
1070If the application is unaware of the format, it set the ``mime`` field to ``null``.
1071The ``expiration`` field is optional.
1072
1073The reducer remains in the ``SECRET_EDITING`` state, but now the secret and
1074updated expiration time are part of the state and the cost calculations will
1075be updated.
1076
1077.. code-block:: json
1078
1079 {
1080 "backup_state": "SECRET_EDITING",
1081 "core_secret" : {
1082 "value": "EDJP6WK5EG50",
1083 "mime" : "text/plain"
1084 },
1085 "expiration" : { "t_ms" : 1245362362 },
1086 "upload_fees" : [ "KUDOS:42" ]
1087 }
1088
1089
1090**clear_secret:**
1091
1092This transition removes the core secret from the state. It is simply a
1093convenience function to undo ``enter_secret`` without providing a new value
1094immediately. The transition takes no arguments. The resuting state will no
1095longer have the ``core_secret`` field, and be otherwise unchanged. Calling
1096**clear_secret** on a state without a ``core_secret`` will result in an error.
1097
1098
1099**enter_secret_name:**
1100
1101This transition provides the reducer with a name for the core ``secret`` of the user. This name will be given to the user as a hint when seleting a recovery policy document during recovery, prior to satisfying any of the challenges. The argument simply contains the name for the secret.
1102Applications that have built-in support for Anastasis MUST prefix the
1103secret name with an underscore and an application-specific identifier
1104registered in GANA so that they can use recognize their own backups.
1105An example argument would be:
1106
1107.. code-block:: javascript
1108
1109 {
1110 "name": "_TALERWALLET_MyPinePhone",
1111 }
1112
1113Here, ``MyPinePhone`` might be chosen by the user to identify the
1114device that was being backed up.
1115
1116The reducer remains in the ``SECRET_EDITING`` state, but now the
1117secret name is updated:
1118
1119.. code-block:: json
1120
1121 {
1122 "secret_name" : "_TALERWALLET_MyPinePhone"
1123 }
1124
1125
1126**update_expiration:**
1127
1128This transition asks the reducer to change the desired expiration time
1129and to update the associated cost. For example:
1130
1131.. code-block:: javascript
1132
1133 {
1134 "expiration" : { "t_ms" : 1245362362 }
1135 }
1136
1137The reducer remains in the ``SECRET_EDITING`` state, but the
1138expiration time and cost calculation will be updated.
1139
1140.. code-block:: json
1141
1142 {
1143 "backup_state": "SECRET_EDITING",
1144 "expiration" : { "t_ms" : 1245362362 },
1145 "upload_fees" : [ { "fee": "KUDOS:43" } ]
1146 }
1147
1148
1149**next** (from ``SECRET_EDITING``):
1150
1151Using this transition, the user confirms that the secret and expiration
1152settings in the current state are acceptable. The transition does not take any
1153arguments.
1154
1155If the secret is currently empty, the reducer will transition into an
1156``ERROR`` state instead of allowing the user to continue.
1157
1158After adding a secret, the reducer may transition into different states
1159depending on whether payment(s) are necessary. If payments are needed, the
1160``secret`` will be stored in the state under ``core_secret``. Applications
1161should be careful when persisting the resulting state, as the ``core_secret``
1162is not protected in the ``PAYING`` states. The ``PAYING`` states only differ
1163in terms of what the payments are for (key shares or the recovery document),
1164in all cases the state simply includes an array of Taler URIs that refer to
1165payments that need to be made with the Taler wallet.
1166
1167If all payments are complete, the reducer will transition into the
1168``BACKUP_FINISHED`` state and (if applicable) delete the ``core_secret`` as an
1169additional safety measure.
1170
1171Example results are thus:
1172
1173.. code-block:: json
1174
1175 {
1176 "backup_state": "TRUTHS_PAYING",
1177 "secret_name" : "$NAME",
1178 "core_secret" : { "$anything":"$anything" },
1179 "payments": [
1180 "taler://pay/...",
1181 "taler://pay/..."
1182 ]
1183 }
1184
1185.. code-block:: json
1186
1187 {
1188 "backup_state": "POLICIES_PAYING",
1189 "secret_name" : "$NAME",
1190 "core_secret" : { "$anything":"$anything" },
1191 "payments": [
1192 "taler://pay/...",
1193 "taler://pay/..."
1194 ]
1195 }
1196
1197.. code-block:: json
1198
1199 {
1200 "backup_state": "BACKUP_FINISHED",
1201 "success_details": {
1202 "http://localhost:8080/" : {
1203 "policy_version" : 1,
1204 "policy_expiration" : { "t_ms" : 1245362362000 }
1205 },
1206 "http://localhost:8081/" : {
1207 "policy_version" : 3,
1208 "policy_expiration" : { "t_ms" : 1245362362000 }
1209 }
1210 }
1211 }
1212
1213
1214**pay:**
1215
1216This transition suggests to the reducer that a payment may have been made or
1217is immanent, and that the reducer should check with the Anastasis service
1218provider to see if the operation is now possible. The operation takes one
1219optional argument, which is a ``timeout`` value that specifies how long the
1220reducer may wait (in long polling) for the payment to complete:
1221
1222.. code-block:: json
1223
1224 {
1225 "timeout": { "d_ms" : 5000 },
1226 }
1227
1228The specified timeout is passed on to the Anastasis service provider(s), which
1229will wait this long before giving up. If no timeout is given, the check is
1230done as quickly as possible without additional delays. The reducer will continue
1231to either an updated state with the remaining payment requests, to the
1232``BACKUP_FINISHED`` state (if all payments have been completed and the backup
1233finished), or into an ``ERROR`` state in case there was an irrecoverable error,
1234indicating the specific provider and how it failed. An example for this
1235final error state would be:
1236
1237.. code-block:: json
1238
1239 {
1240 "backup_state": "ERROR",
1241 "http_status" : 500,
1242 "upload_status" : 52,
1243 "provider_url" : "https://bad.example.com/",
1244 }
1245
1246Here, the fields have the following meaning:
1247
1248 - **http_status** is the HTTP status returned by the Anastasis provider.
1249 - **upload_status** is the Taler error code return by the provider.
1250 - **provider_url** is the base URL of the failing provider.
1251
1252In the above example, 52 would thus imply that the Anastasis provider failed to
1253store information into its database.
1254
1255
1256Recovery transitions
1257--------------------
1258
1259**enter_user_attributes:**
1260
1261This transition provides the user's personal attributes. The specific set of
1262attributes required depends on the country of residence of the user. Some
1263attributes may be optional, in which case they should be omitted entirely
1264(that is, not simply be set to ``null`` or an empty string). The
1265arguments are identical to the **enter_user_attributes** transition from
1266the backup process. Example arguments would thus be:
1267
1268.. code-block:: json
1269
1270 {
1271 "identity_attributes": {
1272 "full_name": "Max Musterman",
1273 "social_security_number": "123456789",
1274 "birthdate": "2000-01-01",
1275 "birthplace": "Earth"
1276 }
1277 }
1278
1279However, in contrast to the backup process, the reducer will attempt to
1280retrieve the latest recovery document from all known providers for the
1281selected currency given the above inputs. If a recovery document was found
1282by any provider, the reducer will attempt to load it and transition to
1283a state where the user can choose which challenges to satisfy:
1284
1285.. code-block:: json
1286
1287 {
1288 "recovery_state": "CHALLENGE_SELECTING",
1289 "recovery_information": {
1290 "challenges": [
1291 {
1292 "uuid": "MW2R3RCBZPHNC78AW8AKWRCHF9KV3Y82EN62T831ZP54S3K5599G",
1293 "cost": "TESTKUDOS:0",
1294 "type": "question",
1295 "instructions": "q1"
1296 },
1297 {
1298 "uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1299 "cost": "TESTKUDOS:0",
1300 "type": "email",
1301 "instructions": "e-mail address m?il@f*.bar"
1302 },
1303 ],
1304 "policies": [
1305 [
1306 {
1307 "uuid": "MW2R3RCBZPHNC78AW8AKWRCHF9KV3Y82EN62T831ZP54S3K5599G"
1308 },
1309 {
1310 "uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0"
1311 },
1312 ],
1313 ],
1314 "provider_url": "http://localhost:8088/",
1315 "version": 1,
1316 },
1317 "recovery_document": {
1318 "...": "..."
1319 }
1320 }
1321
1322The ``recovery_document`` is an internal representation of the recovery
1323information and of no concern to the user interface. The pertinent information
1324is in the ``recovery_information``. Here, the ``challenges`` array is a list
1325of possible challenges the user could attempt to solve next, while ``policies``
1326is an array of policies, with each policy being an array of challenges.
1327Satisfying all of the challenges of one of the policies will enable the secret
1328to be recovered. The ``provider_url`` from where the recovery document was
1329obtained and its ``version`` are also provided. Each challenge comes with
1330four mandatory fields:
1331
1332 - **uuid**: A unique identifier of the challenge; this is what the
1333 UUIDs in the policies array refer to, but also this UUID may be
1334 included in messages sent to the user. They allow the user to
1335 distinguish different PIN/TANs should say the same phone number be
1336 used for SMS-authentication with different providers.
1337 - **cost**: This is the amount the Anastasis provider will charge
1338 to allow the user to pass the challenge.
1339 - **type**: This is the type of the challenge, as a string.
1340 - **instructions**: Contains additional important hints for the user
1341 to allow the user to satisfy the challenge. It typically includes
1342 an abbreviated form of the contact information or the security
1343 question. Details depend on ``type``.
1344
1345If a recovery document was not found, either the user never performed
1346a backup, entered incorrect attributes, or used a provider not yet in
1347the list of Anastasis providers. Hence, the user must now either
1348select a different provider, or go ``back`` and update the identity
1349attributes. In the case a recovery document was not found, the
1350transition fails, returning the error code and a human-readable error
1351message together with a transition failure:
1352
1353.. code-block:: json
1354
1355 {
1356 "recovery_state": "ERROR",
1357 "error_message": "account unknown to Anastasis server",
1358 "error_code": 9,
1359 }
1360
1361Here, the ``error_code`` is from the ``enum ANASTASIS_RecoveryStatus``
1362and describes precisely what failed about the download, while the
1363``error_message`` is a human-readable (English) explanation of the code.
1364Applications may want to translate the message using GNU gettext;
1365translations should be available in the ``anastasis`` text domain.
1366However, in general it should be sufficient to display the slightly
1367more generic Taler error code that is returned with the new state.
1368
1369
1370**change_version:**
1371
1372Even if a recovery document was found, it is possible that the user
1373intended to recover a different version, or recover a backup where
1374the recovery document is stored at a different provider. Thus, the
1375reducer allows the user to explicitly switch to a different provider
1376or recovery document version using the ``change_version`` transition,
1377which takes a provider URL and policy version as arguments:
1378
1379.. code-block:: json
1380
1381 {
1382 "provider_url": "https://localhost:8080/",
1383 "version": 2
1384 }
1385
1386Note that using a version of 0 implies fetching "the latest version". The
1387resulting states are the same as those of the ``enter_user_attributes``
1388transition, except that the recovery document version is not necessarily the
1389latest available version at the provider.
1390
1391
1392**select_challenge:**
1393
1394Selecting a challenge takes different, depending on the state of the payment.
1395A comprehensive example for ``select_challenge`` would be:
1396
1397.. code-block:: json
1398
1399 {
1400 "uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30"
1401 "timeout" : { "d_ms" : 5000 },
1402 "payment_secret": "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
1403 }
1404
1405The ``uuid`` field is mandatory and specifies the selected challenge.
1406The other fields are optional, and are needed in case the user has
1407previously been requested to pay for the challenge. In this case,
1408the ``payment_secret`` identifies the previous payment request, and
1409``timeout`` says how long the Anastasis service should wait for the
1410payment to be completed before giving up (long polling).
1411
1412Depending on the type of the challenge and the need for payment, the
1413reducer may transition into ``CHALLENGE_SOLVING`` or ``CHALLENGE_PAYING``
1414states. In ``CHALLENGE_SOLVING``, the new state will primarily specify
1415the selected challenge:
1416
1417.. code-block:: json
1418
1419 {
1420 "backup_state": "CHALLENGE_SOLVING",
1421 "selected_challenge_uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30"
1422 }
1423
1424In ``CHALLENGE_PAYING``, the new state will include instructions for payment
1425in the ``challenge_feedback``. In general, ``challenge_feedback`` includes
1426information about attempted challenges, with the final state being ``solved``:
1427
1428.. code-block:: json
1429
1430 {
1431 "recovery_state": "CHALLENGE_SELECTING",
1432 "recovery_information": {
1433 "...": "..."
1434 }
1435 "challenge_feedback": {
1436 "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30" : {
1437 "state" : "solved"
1438 }
1439 }
1440 }
1441
1442Challenges feedback for a challenge can have many different ``state`` values
1443that applications must all handle. States other than ``solved`` are:
1444
1445 - **payment**: Here, the user must pay for a challenge. An example would be:
1446
1447 .. code-block:: json
1448
1449 {
1450 "backup_state": "CHALLENGE_PAYING",
1451 "selected_challenge_uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30",
1452 "challenge_feedback": {
1453 "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30" : {
1454 "state" : "payment",
1455 "taler_pay_uri" : "taler://pay/...",
1456 "provider" : "https://localhost:8080/",
1457 "payment_secret" : "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
1458 }
1459 }
1460 }
1461
1462 - **body**: Here, the server provided an HTTP reply for
1463 how to solve the challenge, but the reducer could not parse
1464 them into a known format. A mime-type may be provided and may
1465 help parse the details.
1466
1467 .. code-block:: json
1468
1469 {
1470 "recovery_state": "CHALLENGE_SOLVING",
1471 "recovery_information": {
1472 "...": "..."
1473 }
1474 "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1475 "challenge_feedback": {
1476 "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
1477 "state": "body",
1478 "body": "CROCKFORDBASE32ENCODEDBODY",
1479 "http_status": 403,
1480 "mime_type" : "anything/possible"
1481 }
1482 }
1483 }
1484
1485 - **hint**: Here, the server provided human-readable hint for
1486 how to solve the challenge. Note that the ``hint`` provided this
1487 time is from the Anastasis provider and may differ from the ``instructions``
1488 for the challenge under ``recovery_information``:
1489
1490 .. code-block:: json
1491
1492 {
1493 "recovery_state": "CHALLENGE_SOLVING",
1494 "recovery_information": {
1495 "...": "..."
1496 }
1497 "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1498 "challenge_feedback": {
1499 "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
1500 "state": "hint",
1501 "hint": "Recovery TAN send to email mail@DOMAIN",
1502 "http_status": 403
1503 }
1504 }
1505 }
1506
1507 - **details**: Here, the server provided a detailed JSON status response
1508 related to solving the challenge:
1509
1510 .. code-block:: json
1511
1512 {
1513 "recovery_state": "CHALLENGE_SOLVING",
1514 "recovery_information": {
1515 "...": "..."
1516 }
1517 "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1518 "challenge_feedback": {
1519 "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
1520 "state": "details",
1521 "details": {
1522 "code": 8111,
1523 "hint": "The client's response to the challenge was invalid.",
1524 "detail" : null
1525 },
1526 "http_status": 403
1527 }
1528 }
1529 }
1530
1531 - **redirect**: To solve the challenge, the user must visit the indicated
1532 Web site at ``redirect_url``, for example to perform video authentication:
1533
1534 .. code-block:: json
1535
1536 {
1537 "recovery_state": "CHALLENGE_SOLVING",
1538 "recovery_information": {
1539 "...": "..."
1540 }
1541 "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1542 "challenge_feedback": {
1543 "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
1544 "state": "redirect",
1545 "redirect_url": "https://videoconf.example.com/",
1546 "http_status": 303
1547 }
1548 }
1549 }
1550
1551 - **server-failure**: This indicates that the Anastasis provider encountered
1552 a failure and recovery using this challenge cannot proceed at this time.
1553 Examples for failures might be that the provider is unable to send SMS
1554 messages at this time due to an outage. The body includes details about
1555 the failure. The user may try again later or continue with other challenges.
1556
1557 .. code-block:: json
1558
1559 {
1560 "recovery_state": "CHALLENGE_SELECTING",
1561 "recovery_information": {
1562 "...": "..."
1563 }
1564 "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1565 "challenge_feedback": {
1566 "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
1567 "state": "server-failure",
1568 "http_status": "500",
1569 "error_code": 52
1570 }
1571 }
1572 }
1573
1574 - **truth-unknown**: This indicates that the Anastasis provider is unaware of
1575 the specified challenge. This is typically a permanent failure, and user
1576 interfaces should not allow users to re-try this challenge.
1577
1578 .. code-block:: json
1579
1580 {
1581 "recovery_state": "CHALLENGE_SELECTING",
1582 "recovery_information": {
1583 "...": "..."
1584 }
1585 "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1586 "challenge_feedback": {
1587 "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
1588 "state": "truth-unknown",
1589 "error_code": 8108
1590 }
1591 }
1592 }
1593
1594 - **rate-limit-exceeded**:
1595
1596 .. code-block:: json
1597
1598 {
1599 "recovery_state": "CHALLENGE_SELECTING",
1600 "recovery_information": {
1601 "...": "..."
1602 }
1603 "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
1604 "challenge_feedback": {
1605 "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
1606 "state": "rate-limit-exceeded",
1607 "error_code": 8121
1608 }
1609 }
1610 }
1611
1612**pay:**
1613
1614With a ``pay`` transition, the application indicates to the reducer that
1615a payment may have been made. Here, it is again possible to specify an
1616optional ``timeout`` argument for long-polling, for example:
1617
1618.. code-block:: json
1619
1620 {
1621 "payment_secret": "ABCDADF242525AABASD52525235ABABFDABABANALASDAAKASDAS"
1622 "timeout" : { "d_ms" : 5000 },
1623 }
1624
1625Depending on the type of the challenge and the result of the operation, the
1626new state may be ``CHALLENGE_SOLVING`` (if say the SMS was now sent to the
1627user), ``CHALLENGE_SELECTING`` (if the answer to the security question was
1628correct), ``RECOVERY_FINISHED`` (if this was the last challenge that needed to
1629be solved) or still ``CHALLENGE_PAYING`` (if the challenge was not actually
1630paid for). For sample messages, see the different types of
1631``challenge_feedback`` in the section about ``select_challenge``.
1632
1633
1634**solve_challenge:**
1635
1636Solving a challenge takes various formats, depending on the type of the
1637challenge and what is known about the answer. The different supported
1638formats are:
1639
1640.. code-block:: json
1641
1642 {
1643 "answer": "answer to security question"
1644 }
1645
1646.. code-block:: json
1647
1648 {
1649 "pin": 1234
1650 }
1651
1652.. code-block:: json
1653
1654 {
1655 "hash": "SOMEBASE32ENCODEDHASHVALUE"
1656 }