anastasis

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

anastasis_api_redux_serialize.c (28861B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2020, 2021, 2022 Anastasis SARL
      4 
      5   Anastasis is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, 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 General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file reducer/anastasis_api_redux_serialize.c
     18  * @brief write a reducer state back out as JSON
     19  * @author Christian Grothoff
     20  *
     21  * The inverse of anastasis_api_redux_parse.c.  Fields that are not set are
     22  * omitted rather than serialized as null, matching what the JSON-based
     23  * implementation this replaced produced.
     24  */
     25 #include "platform.h"
     26 #include "anastasis_redux.h"
     27 #include "anastasis_api_redux.h"
     28 #include "anastasis_api_redux_state.h"
     29 #include <taler/taler_json_lib.h>
     30 
     31 
     32 /**
     33  * Add @a val to @a obj under @a key, unless @a val is NULL.
     34  *
     35  * @param[in,out] obj object to extend
     36  * @param key field name
     37  * @param[in] val value to add, reference is consumed
     38  */
     39 static void
     40 set_opt (json_t *obj,
     41          const char *key,
     42          json_t *val)
     43 {
     44   if (NULL == val)
     45     return;
     46   GNUNET_assert (0 ==
     47                  json_object_set_new (obj,
     48                                       key,
     49                                       val));
     50 }
     51 
     52 
     53 /**
     54  * Serialize the `continents` array.
     55  *
     56  * @param common state to serialize
     57  * @return JSON array
     58  */
     59 static json_t *
     60 serialize_continents (const struct ANASTASIS_ReduxCommon *common)
     61 {
     62   json_t *arr;
     63 
     64   arr = json_array ();
     65   GNUNET_assert (NULL != arr);
     66   for (unsigned int i = 0; i < common->continents_len; i++)
     67   {
     68     const struct ANASTASIS_ReduxContinent *c = &common->continents[i];
     69     json_t *co;
     70 
     71     if (c->bare)
     72     {
     73       GNUNET_assert (0 ==
     74                      json_array_append_new (arr,
     75                                             json_string (c->name)));
     76       continue;
     77     }
     78     co = GNUNET_JSON_PACK (
     79       GNUNET_JSON_pack_string ("name",
     80                                c->name));
     81     set_opt (co,
     82              "name_i18n",
     83              json_incref (c->name_i18n));
     84     GNUNET_assert (0 ==
     85                    json_array_append_new (arr,
     86                                           co));
     87   }
     88   return arr;
     89 }
     90 
     91 
     92 /**
     93  * Serialize the `countries` array.
     94  *
     95  * @param common state to serialize
     96  * @return JSON array
     97  */
     98 static json_t *
     99 serialize_countries (const struct ANASTASIS_ReduxCommon *common)
    100 {
    101   json_t *arr;
    102 
    103   arr = json_array ();
    104   GNUNET_assert (NULL != arr);
    105   for (unsigned int i = 0; i < common->countries_len; i++)
    106   {
    107     const struct ANASTASIS_ReduxCountry *c = &common->countries[i];
    108     json_t *co;
    109 
    110     co = GNUNET_JSON_PACK (
    111       GNUNET_JSON_pack_string ("code",
    112                                c->code),
    113       GNUNET_JSON_pack_string ("name",
    114                                c->name),
    115       GNUNET_JSON_pack_string ("continent",
    116                                c->continent),
    117       GNUNET_JSON_pack_conditional (
    118         NULL != c->call_code,
    119         GNUNET_JSON_pack_string ("call_code",
    120                                  c->call_code)));
    121     set_opt (co,
    122              "name_i18n",
    123              json_incref (c->name_i18n));
    124     set_opt (co,
    125              "continent_i18n",
    126              json_incref (c->continent_i18n));
    127     if (NULL != c->currency)
    128       set_opt (co,
    129                "currency",
    130                json_string (c->currency));
    131     GNUNET_assert (0 ==
    132                    json_array_append_new (arr,
    133                                           co));
    134   }
    135   return arr;
    136 }
    137 
    138 
    139 /**
    140  * Serialize the `required_attributes` array.
    141  *
    142  * @param common state to serialize
    143  * @return JSON array
    144  */
    145 static json_t *
    146 serialize_required_attributes (const struct ANASTASIS_ReduxCommon *common)
    147 {
    148   json_t *arr;
    149 
    150   arr = json_array ();
    151   GNUNET_assert (NULL != arr);
    152   for (unsigned int i = 0; i < common->required_attributes_len; i++)
    153   {
    154     const struct ANASTASIS_ReduxAttributeSpec *a
    155       = &common->required_attributes[i];
    156     json_t *ao;
    157 
    158     ao = GNUNET_JSON_PACK (
    159       GNUNET_JSON_pack_string ("type",
    160                                a->type),
    161       GNUNET_JSON_pack_string ("name",
    162                                a->name),
    163       GNUNET_JSON_pack_string ("label",
    164                                a->label),
    165       GNUNET_JSON_pack_string ("widget",
    166                                a->widget),
    167       GNUNET_JSON_pack_conditional (
    168         NULL != a->uuid,
    169         GNUNET_JSON_pack_string ("uuid",
    170                                  a->uuid)),
    171       GNUNET_JSON_pack_conditional (
    172         NULL != a->tooltip,
    173         GNUNET_JSON_pack_string ("tooltip",
    174                                  a->tooltip)),
    175       GNUNET_JSON_pack_conditional (
    176         NULL != a->validation_regex,
    177         GNUNET_JSON_pack_string ("validation-regex",
    178                                  a->validation_regex)),
    179       GNUNET_JSON_pack_conditional (
    180         NULL != a->validation_logic,
    181         GNUNET_JSON_pack_string ("validation-logic",
    182                                  a->validation_logic)),
    183       GNUNET_JSON_pack_conditional (
    184         NULL != a->autocomplete,
    185         GNUNET_JSON_pack_string ("autocomplete",
    186                                  a->autocomplete)),
    187       GNUNET_JSON_pack_conditional (
    188         a->have_optional,
    189         GNUNET_JSON_pack_bool ("optional",
    190                                a->optional)));
    191     set_opt (ao,
    192              "label_i18n",
    193              json_incref (a->label_i18n));
    194     GNUNET_assert (0 ==
    195                    json_array_append_new (arr,
    196                                           ao));
    197   }
    198   return arr;
    199 }
    200 
    201 
    202 /**
    203  * Serialize the `authentication_providers` object.
    204  *
    205  * @param common state to serialize
    206  * @return JSON object
    207  */
    208 static json_t *
    209 serialize_providers (const struct ANASTASIS_ReduxCommon *common)
    210 {
    211   json_t *obj;
    212 
    213   obj = json_object ();
    214   GNUNET_assert (NULL != obj);
    215   for (unsigned int i = 0; i < common->providers_len; i++)
    216   {
    217     const struct ANASTASIS_ReduxProvider *p = &common->providers[i];
    218     const char *status;
    219     json_t *po;
    220 
    221     switch (p->status)
    222     {
    223     case ANASTASIS_RPS_NOT_CONTACTED:
    224       status = "not-contacted";
    225       break;
    226     case ANASTASIS_RPS_OK:
    227       status = "ok";
    228       break;
    229     case ANASTASIS_RPS_DISABLED:
    230       status = "disabled";
    231       break;
    232     case ANASTASIS_RPS_ERROR:
    233       status = "error";
    234       break;
    235     default:
    236       GNUNET_assert (0);
    237     }
    238     if (ANASTASIS_RPS_ERROR == p->status)
    239     {
    240       po = GNUNET_JSON_PACK (
    241         GNUNET_JSON_pack_string ("status",
    242                                  status),
    243         GNUNET_JSON_pack_uint64 ("error_code",
    244                                  p->error.ec),
    245         GNUNET_JSON_pack_uint64 ("http_status",
    246                                  p->error.http_status));
    247     }
    248     else if (! p->have_config)
    249     {
    250       po = GNUNET_JSON_PACK (
    251         GNUNET_JSON_pack_string ("status",
    252                                  status));
    253     }
    254     else
    255     {
    256       const struct ANASTASIS_ReduxProviderConfig *cfg = &p->config;
    257       json_t *methods;
    258 
    259       methods = json_array ();
    260       GNUNET_assert (NULL != methods);
    261       for (unsigned int j = 0; j < cfg->methods_len; j++)
    262       {
    263         const struct ANASTASIS_ReduxMethodSpec *ms = &cfg->methods[j];
    264 
    265         GNUNET_assert (0 ==
    266                        json_array_append_new (
    267                          methods,
    268                          GNUNET_JSON_PACK (
    269                            GNUNET_JSON_pack_string ("type",
    270                                                     ms->type),
    271                            TALER_JSON_pack_amount ("usage_fee",
    272                                                    &ms->usage_fee))));
    273       }
    274       po = GNUNET_JSON_PACK (
    275         GNUNET_JSON_pack_string ("status",
    276                                  status),
    277         GNUNET_JSON_pack_array_steal ("methods",
    278                                       methods),
    279         TALER_JSON_pack_amount ("annual_fee",
    280                                 &cfg->annual_fee),
    281         TALER_JSON_pack_amount ("truth_upload_fee",
    282                                 &cfg->truth_upload_fee),
    283         TALER_JSON_pack_amount ("liability_limit",
    284                                 &cfg->liability_limit),
    285         GNUNET_JSON_pack_string ("business_name",
    286                                  cfg->business_name),
    287         GNUNET_JSON_pack_uint64 ("storage_limit_in_megabytes",
    288                                  cfg->storage_limit_in_megabytes),
    289         GNUNET_JSON_pack_data_auto ("provider_salt",
    290                                     &cfg->provider_salt),
    291         GNUNET_JSON_pack_uint64 ("http_status",
    292                                  cfg->http_status),
    293         GNUNET_JSON_pack_conditional (
    294           NULL != cfg->currency,
    295           GNUNET_JSON_pack_string ("currency",
    296                                    cfg->currency)));
    297     }
    298     GNUNET_assert (0 ==
    299                    json_object_set_new (obj,
    300                                         p->url.url,
    301                                         po));
    302   }
    303   return obj;
    304 }
    305 
    306 
    307 /**
    308  * Add the fields shared by the backup and recovery variants to @a obj.
    309  *
    310  * @param[in,out] obj object to extend
    311  * @param common state to serialize
    312  */
    313 static void
    314 serialize_common (json_t *obj,
    315                   const struct ANASTASIS_ReduxCommon *common)
    316 {
    317   if (common->have_continents)
    318     set_opt (obj,
    319              "continents",
    320              serialize_continents (common));
    321   if (common->have_countries)
    322     set_opt (obj,
    323              "countries",
    324              serialize_countries (common));
    325   if (common->have_required_attributes)
    326     set_opt (obj,
    327              "required_attributes",
    328              serialize_required_attributes (common));
    329   if (common->have_providers)
    330     set_opt (obj,
    331              "authentication_providers",
    332              serialize_providers (common));
    333   if (NULL != common->identity_attributes)
    334     set_opt (obj,
    335              "identity_attributes",
    336              json_incref (common->identity_attributes));
    337   if (common->have_currencies)
    338   {
    339     json_t *arr;
    340 
    341     arr = json_array ();
    342     GNUNET_assert (NULL != arr);
    343     for (unsigned int i = 0; i < common->currencies_len; i++)
    344       GNUNET_assert (0 ==
    345                      json_array_append_new (
    346                        arr,
    347                        json_string (common->currencies[i])));
    348     set_opt (obj,
    349              "currencies",
    350              arr);
    351   }
    352   if (NULL != common->selected_continent)
    353     set_opt (obj,
    354              "selected_continent",
    355              json_string (common->selected_continent));
    356   if (NULL != common->selected_country)
    357     set_opt (obj,
    358              "selected_country",
    359              json_string (common->selected_country));
    360 }
    361 
    362 
    363 /**
    364  * Serialize the backup-specific fields into @a obj.
    365  *
    366  * @param[in,out] obj object to extend
    367  * @param b backup state to serialize
    368  */
    369 static void
    370 serialize_backup (json_t *obj,
    371                   const struct ANASTASIS_ReduxBackup *b)
    372 {
    373   if (b->have_authentication_methods)
    374   {
    375     json_t *arr;
    376 
    377     arr = json_array ();
    378     GNUNET_assert (NULL != arr);
    379     for (unsigned int i = 0; i < b->authentication_methods_len; i++)
    380     {
    381       const struct ANASTASIS_ReduxAuthMethod *am
    382         = &b->authentication_methods[i];
    383 
    384       GNUNET_assert (0 ==
    385                      json_array_append_new (
    386                        arr,
    387                        GNUNET_JSON_PACK (
    388                          GNUNET_JSON_pack_string ("type",
    389                                                   am->type),
    390                          GNUNET_JSON_pack_string ("instructions",
    391                                                   am->instructions),
    392                          GNUNET_JSON_pack_data_varsize ("challenge",
    393                                                         am->challenge,
    394                                                         am->challenge_size),
    395                          GNUNET_JSON_pack_conditional (
    396                            NULL != am->mime_type,
    397                            GNUNET_JSON_pack_string ("mime_type",
    398                                                     am->mime_type)))));
    399     }
    400     set_opt (obj,
    401              "authentication_methods",
    402              arr);
    403   }
    404   if (b->have_policies)
    405   {
    406     json_t *arr;
    407 
    408     arr = json_array ();
    409     GNUNET_assert (NULL != arr);
    410     for (unsigned int i = 0; i < b->policies_len; i++)
    411     {
    412       const struct ANASTASIS_ReduxPolicy *p = &b->policies[i];
    413       json_t *methods;
    414 
    415       methods = json_array ();
    416       GNUNET_assert (NULL != methods);
    417       for (unsigned int j = 0; j < p->methods_len; j++)
    418       {
    419         const struct ANASTASIS_ReduxPolicyMethod *pm = &p->methods[j];
    420         json_t *mo;
    421 
    422         mo = GNUNET_JSON_PACK (
    423           GNUNET_JSON_pack_uint64 ("authentication_method",
    424                                    pm->authentication_method.idx),
    425           GNUNET_JSON_pack_string ("provider",
    426                                    pm->provider.url));
    427         if (NULL != pm->truth)
    428         {
    429           json_t *truth = ANASTASIS_truth_to_json (pm->truth);
    430 
    431           GNUNET_assert (NULL != truth);
    432           GNUNET_assert (0 ==
    433                          json_object_set_new (truth,
    434                                               "upload_status",
    435                                               json_integer (
    436                                                 pm->upload_status)));
    437           GNUNET_assert (0 ==
    438                          json_object_set_new (mo,
    439                                               "truth",
    440                                               truth));
    441         }
    442         GNUNET_assert (0 ==
    443                        json_array_append_new (methods,
    444                                               mo));
    445       }
    446       GNUNET_assert (0 ==
    447                      json_array_append_new (
    448                        arr,
    449                        GNUNET_JSON_PACK (
    450                          GNUNET_JSON_pack_conditional (
    451                            p->have_recovery_cost,
    452                            TALER_JSON_pack_amount ("recovery_cost",
    453                                                    &p->recovery_cost)),
    454                          GNUNET_JSON_pack_array_steal ("methods",
    455                                                        methods))));
    456     }
    457     set_opt (obj,
    458              "policies",
    459              arr);
    460   }
    461   if (b->have_policy_providers)
    462   {
    463     json_t *arr;
    464 
    465     arr = json_array ();
    466     GNUNET_assert (NULL != arr);
    467     for (unsigned int i = 0; i < b->policy_providers_len; i++)
    468     {
    469       const struct ANASTASIS_ReduxPolicyProvider *pp
    470         = &b->policy_providers[i];
    471 
    472       GNUNET_assert (0 ==
    473                      json_array_append_new (
    474                        arr,
    475                        GNUNET_JSON_PACK (
    476                          GNUNET_JSON_pack_string ("provider_url",
    477                                                   pp->provider_url.url),
    478                          GNUNET_JSON_pack_conditional (
    479                            pp->have_payment_secret,
    480                            GNUNET_JSON_pack_data_auto (
    481                              "payment_secret",
    482                              &pp->payment_secret)))));
    483     }
    484     set_opt (obj,
    485              "policy_providers",
    486              arr);
    487   }
    488   if (b->have_upload_fees)
    489   {
    490     json_t *arr;
    491 
    492     arr = json_array ();
    493     GNUNET_assert (NULL != arr);
    494     for (unsigned int i = 0; i < b->upload_fees_len; i++)
    495       GNUNET_assert (0 ==
    496                      json_array_append_new (
    497                        arr,
    498                        GNUNET_JSON_PACK (
    499                          TALER_JSON_pack_amount ("fee",
    500                                                  &b->upload_fees[i]))));
    501     set_opt (obj,
    502              "upload_fees",
    503              arr);
    504   }
    505   if (b->have_payments)
    506   {
    507     json_t *arr;
    508 
    509     arr = json_array ();
    510     GNUNET_assert (NULL != arr);
    511     for (unsigned int i = 0; i < b->payments_len; i++)
    512       GNUNET_assert (0 ==
    513                      json_array_append_new (arr,
    514                                             json_string (b->payments[i])));
    515     set_opt (obj,
    516              "payments",
    517              arr);
    518   }
    519   if (b->have_policy_payment_requests)
    520   {
    521     json_t *arr;
    522 
    523     arr = json_array ();
    524     GNUNET_assert (NULL != arr);
    525     for (unsigned int i = 0; i < b->policy_payment_requests_len; i++)
    526     {
    527       const struct ANASTASIS_ReduxPolicyPaymentRequest *ppr
    528         = &b->policy_payment_requests[i];
    529 
    530       GNUNET_assert (0 ==
    531                      json_array_append_new (
    532                        arr,
    533                        GNUNET_JSON_PACK (
    534                          GNUNET_JSON_pack_string ("payto",
    535                                                   ppr->payto),
    536                          GNUNET_JSON_pack_string ("provider",
    537                                                   ppr->provider.url))));
    538     }
    539     set_opt (obj,
    540              "policy_payment_requests",
    541              arr);
    542   }
    543   if (b->have_success_details)
    544   {
    545     json_t *sd;
    546 
    547     sd = json_object ();
    548     GNUNET_assert (NULL != sd);
    549     for (unsigned int i = 0; i < b->success_details_len; i++)
    550     {
    551       const struct ANASTASIS_ReduxSuccessDetail *d = &b->success_details[i];
    552 
    553       GNUNET_assert (0 ==
    554                      json_object_set_new (
    555                        sd,
    556                        d->provider_url.url,
    557                        GNUNET_JSON_PACK (
    558                          GNUNET_JSON_pack_uint64 ("policy_version",
    559                                                   d->policy_version),
    560                          GNUNET_JSON_pack_timestamp ("policy_expiration",
    561                                                      d->policy_expiration))));
    562     }
    563     set_opt (obj,
    564              "success_details",
    565              sd);
    566   }
    567   if (NULL != b->core_secret)
    568     set_opt (obj,
    569              "core_secret",
    570              json_incref (b->core_secret));
    571   if (NULL != b->secret_name)
    572     set_opt (obj,
    573              "secret_name",
    574              json_string (b->secret_name));
    575   if (b->have_expiration)
    576     set_opt (obj,
    577              "expiration",
    578              GNUNET_JSON_from_timestamp (b->expiration));
    579   if (b->have_pay_arguments)
    580   {
    581     json_t *pa;
    582 
    583     pa = json_object ();
    584     GNUNET_assert (NULL != pa);
    585     if (b->pay_arguments.have_timeout)
    586       set_opt (pa,
    587                "timeout",
    588                GNUNET_JSON_from_time_rel (b->pay_arguments.timeout));
    589     set_opt (obj,
    590              "pay_arguments",
    591              pa);
    592   }
    593 }
    594 
    595 
    596 /**
    597  * Serialize the recovery information @a ri.
    598  *
    599  * @param ri recovery information to serialize
    600  * @return JSON object
    601  */
    602 static json_t *
    603 serialize_recovery_info (const struct ANASTASIS_ReduxRecoveryInfo *ri)
    604 {
    605   json_t *challenges;
    606   json_t *policies;
    607 
    608   challenges = json_array ();
    609   GNUNET_assert (NULL != challenges);
    610   for (unsigned int i = 0; i < ri->challenges_len; i++)
    611   {
    612     const struct ANASTASIS_ReduxChallengeInfo *ci = &ri->challenges[i];
    613 
    614     GNUNET_assert (0 ==
    615                    json_array_append_new (
    616                      challenges,
    617                      GNUNET_JSON_PACK (
    618                        GNUNET_JSON_pack_data_auto ("uuid",
    619                                                    &ci->uuid),
    620                        GNUNET_JSON_pack_string ("type",
    621                                                 ci->type),
    622                        GNUNET_JSON_pack_string ("uuid-display",
    623                                                 ANASTASIS_CRYPTO_uuid2s (
    624                                                   &ci->uuid)),
    625                        GNUNET_JSON_pack_string ("instructions",
    626                                                 ci->instructions),
    627                        GNUNET_JSON_pack_conditional (
    628                          NULL != ci->answer,
    629                          GNUNET_JSON_pack_string ("answer",
    630                                                   ci->answer)),
    631                        GNUNET_JSON_pack_conditional (
    632                          ci->have_payment_secret,
    633                          GNUNET_JSON_pack_data_auto ("payment_secret",
    634                                                      &ci->payment_secret)))));
    635   }
    636   policies = json_array ();
    637   GNUNET_assert (NULL != policies);
    638   for (unsigned int i = 0; i < ri->policies_len; i++)
    639   {
    640     const struct ANASTASIS_ReduxRecoveryPolicy *p = &ri->policies[i];
    641     json_t *pa;
    642 
    643     pa = json_array ();
    644     GNUNET_assert (NULL != pa);
    645     for (unsigned int j = 0; j < p->uuids_len; j++)
    646       GNUNET_assert (0 ==
    647                      json_array_append_new (
    648                        pa,
    649                        GNUNET_JSON_PACK (
    650                          GNUNET_JSON_pack_data_auto ("uuid",
    651                                                      &p->uuids[j]))));
    652     GNUNET_assert (0 ==
    653                    json_array_append_new (policies,
    654                                           pa));
    655   }
    656   return GNUNET_JSON_PACK (
    657     GNUNET_JSON_pack_array_steal ("challenges",
    658                                   challenges),
    659     GNUNET_JSON_pack_array_steal ("policies",
    660                                   policies),
    661     GNUNET_JSON_pack_allow_null (
    662       GNUNET_JSON_pack_string ("secret_name",
    663                                ri->secret_name)),
    664     GNUNET_JSON_pack_string ("provider_url",
    665                              ri->provider_url.url),
    666     GNUNET_JSON_pack_uint64 ("version",
    667                              ri->version));
    668 }
    669 
    670 
    671 /**
    672  * Serialize one challenge feedback entry.
    673  *
    674  * @param fb feedback to serialize
    675  * @return JSON object
    676  */
    677 static json_t *
    678 serialize_feedback (const struct ANASTASIS_ReduxFeedback *fb)
    679 {
    680   json_t *fo;
    681 
    682   switch (fb->status)
    683   {
    684   case ANASTASIS_RFS_CODE_IN_FILE:
    685     fo = GNUNET_JSON_PACK (
    686       GNUNET_JSON_pack_string ("state",
    687                                "code-in-file"),
    688       GNUNET_JSON_pack_string ("filename",
    689                                fb->details.code_in_file.filename));
    690     break;
    691   case ANASTASIS_RFS_SEND_TO_ADDRESS:
    692     fo = GNUNET_JSON_PACK (
    693       GNUNET_JSON_pack_string ("state",
    694                                "send-to-address"),
    695       GNUNET_JSON_pack_conditional (
    696         NULL != fb->details.send_to_address.address_hint,
    697         GNUNET_JSON_pack_string ("address_hint",
    698                                  fb->details.send_to_address.address_hint)));
    699     break;
    700   case ANASTASIS_RFS_TALER_PAYMENT:
    701     fo = GNUNET_JSON_PACK (
    702       GNUNET_JSON_pack_string ("state",
    703                                "taler-payment"),
    704       GNUNET_JSON_pack_string ("taler_pay_uri",
    705                                fb->details.taler_payment.taler_pay_uri),
    706       GNUNET_JSON_pack_string ("provider",
    707                                fb->details.taler_payment.provider.url),
    708       GNUNET_JSON_pack_data_auto ("payment_secret",
    709                                   &fb->details.taler_payment.payment_secret));
    710     break;
    711   case ANASTASIS_RFS_SERVER_FAILURE:
    712     fo = GNUNET_JSON_PACK (
    713       GNUNET_JSON_pack_string ("state",
    714                                "server-failure"),
    715       GNUNET_JSON_pack_uint64 ("http_status",
    716                                fb->details.server_failure.http_status),
    717       GNUNET_JSON_pack_uint64 ("error_code",
    718                                fb->details.server_failure.ec));
    719     break;
    720   case ANASTASIS_RFS_TRUTH_UNKNOWN:
    721     fo = GNUNET_JSON_PACK (
    722       GNUNET_JSON_pack_string ("state",
    723                                "truth-unknown"),
    724       GNUNET_JSON_pack_uint64 ("http_status",
    725                                fb->details.server_failure.http_status),
    726       GNUNET_JSON_pack_uint64 ("error_code",
    727                                fb->details.server_failure.ec));
    728     break;
    729   case ANASTASIS_RFS_IBAN_INSTRUCTIONS:
    730     fo = GNUNET_JSON_PACK (
    731       GNUNET_JSON_pack_string ("state",
    732                                "iban-instructions"),
    733       GNUNET_JSON_pack_string ("target_iban",
    734                                fb->details.iban_instructions.target_iban),
    735       GNUNET_JSON_pack_string (
    736         "target_business_name",
    737         fb->details.iban_instructions.target_business_name),
    738       GNUNET_JSON_pack_string (
    739         "wire_transfer_subject",
    740         fb->details.iban_instructions.wire_transfer_subject),
    741       TALER_JSON_pack_amount ("challenge_amount",
    742                               &fb->details.iban_instructions.amount));
    743     break;
    744   case ANASTASIS_RFS_SOLVED:
    745     fo = GNUNET_JSON_PACK (
    746       GNUNET_JSON_pack_string ("state",
    747                                "solved"));
    748     break;
    749   case ANASTASIS_RFS_INCORRECT_ANSWER:
    750     fo = GNUNET_JSON_PACK (
    751       GNUNET_JSON_pack_string ("state",
    752                                "incorrect-answer"),
    753       GNUNET_JSON_pack_uint64 ("error_code",
    754                                fb->details.incorrect_answer.ec));
    755     break;
    756   case ANASTASIS_RFS_RATE_LIMIT_EXCEEDED:
    757     fo = GNUNET_JSON_PACK (
    758       GNUNET_JSON_pack_string ("state",
    759                                "rate-limit-exceeded"),
    760       GNUNET_JSON_pack_uint64 (
    761         "request_limit",
    762         fb->details.rate_limit_exceeded.request_limit),
    763       GNUNET_JSON_pack_time_rel (
    764         "request_frequency",
    765         fb->details.rate_limit_exceeded.request_frequency),
    766       GNUNET_JSON_pack_uint64 ("error_code",
    767                                fb->details.rate_limit_exceeded.ec));
    768     break;
    769   default:
    770     GNUNET_assert (0);
    771   }
    772   if (NULL != fb->display_hint)
    773     set_opt (fo,
    774              "display_hint",
    775              json_string (fb->display_hint));
    776   return fo;
    777 }
    778 
    779 
    780 /**
    781  * Serialize the recovery-specific fields into @a obj.
    782  *
    783  * @param[in,out] obj object to extend
    784  * @param rr recovery state to serialize
    785  */
    786 static void
    787 serialize_recovery (json_t *obj,
    788                     const struct ANASTASIS_ReduxRecovery *rr)
    789 {
    790   if (NULL != rr->ri)
    791     set_opt (obj,
    792              "recovery_information",
    793              serialize_recovery_info (rr->ri));
    794   if (NULL != rr->r)
    795     set_opt (obj,
    796              "recovery_document",
    797              ANASTASIS_recovery_serialize (rr->r));
    798   if (rr->have_challenge_feedback)
    799   {
    800     json_t *cf;
    801 
    802     cf = json_object ();
    803     GNUNET_assert (NULL != cf);
    804     for (unsigned int i = 0; i < rr->challenge_feedback_len; i++)
    805     {
    806       const struct ANASTASIS_ReduxFeedback *fb = &rr->challenge_feedback[i];
    807       char uuid[sizeof (fb->uuid) * 2];
    808       char *end;
    809 
    810       end = GNUNET_STRINGS_data_to_string (&fb->uuid,
    811                                            sizeof (fb->uuid),
    812                                            uuid,
    813                                            sizeof (uuid));
    814       GNUNET_assert (NULL != end);
    815       *end = '\0';
    816       GNUNET_assert (0 ==
    817                      json_object_set_new (cf,
    818                                           uuid,
    819                                           serialize_feedback (fb)));
    820     }
    821     set_opt (obj,
    822              "challenge_feedback",
    823              cf);
    824   }
    825   if (rr->have_selected_challenge)
    826     set_opt (obj,
    827              "selected_challenge_uuid",
    828              GNUNET_JSON_from_data_auto (&rr->selected_challenge));
    829   if (NULL != rr->core_secret)
    830     set_opt (obj,
    831              "core_secret",
    832              json_incref (rr->core_secret));
    833 }
    834 
    835 
    836 json_t *
    837 ANASTASIS_REDUX_state_serialize_ (const struct ANASTASIS_ReduxState *rs)
    838 {
    839   json_t *obj;
    840 
    841   switch (rs->type)
    842   {
    843   case ANASTASIS_RT_BACKUP:
    844     obj = GNUNET_JSON_PACK (
    845       GNUNET_JSON_pack_string ("reducer_type",
    846                                "backup"),
    847       GNUNET_JSON_pack_string ("backup_state",
    848                                ANASTASIS_backup_state_to_string_ (
    849                                  rs->details.backup.state)));
    850     serialize_common (obj,
    851                       &rs->common);
    852     serialize_backup (obj,
    853                       &rs->details.backup);
    854     return obj;
    855   case ANASTASIS_RT_RECOVERY:
    856     obj = GNUNET_JSON_PACK (
    857       GNUNET_JSON_pack_string ("reducer_type",
    858                                "recovery"),
    859       GNUNET_JSON_pack_string ("recovery_state",
    860                                ANASTASIS_recovery_state_to_string_ (
    861                                  rs->details.recovery.state)));
    862     serialize_common (obj,
    863                       &rs->common);
    864     serialize_recovery (obj,
    865                         &rs->details.recovery);
    866     return obj;
    867   case ANASTASIS_RT_ERROR:
    868     return GNUNET_JSON_PACK (
    869       GNUNET_JSON_pack_string ("reducer_type",
    870                                "error"),
    871       GNUNET_JSON_pack_uint64 ("code",
    872                                rs->details.error.code),
    873       GNUNET_JSON_pack_allow_null (
    874         GNUNET_JSON_pack_string ("hint",
    875                                  rs->details.error.hint)),
    876       GNUNET_JSON_pack_allow_null (
    877         GNUNET_JSON_pack_string ("detail",
    878                                  rs->details.error.detail)));
    879   }
    880   GNUNET_assert (0);
    881   return NULL;
    882 }
    883 
    884 
    885 /* end of anastasis_api_redux_serialize.c */