anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

reducer.rst (59276B)


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