anastasis

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

anastasis_api_redux_serialize.c (30019B)


      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                            TALER_JSON_pack_amount_list ("usage_fees",
    274                                                         &ms->usage_fees))));
    275       }
    276       {
    277         json_t *currencies = json_array ();
    278 
    279         GNUNET_assert (NULL != currencies);
    280         for (unsigned int j = 0; j < cfg->currencies_len; j++)
    281           GNUNET_assert (0 ==
    282                          json_array_append_new (
    283                            currencies,
    284                            json_string (cfg->currencies[j])));
    285         po = GNUNET_JSON_PACK (
    286           GNUNET_JSON_pack_string ("status",
    287                                    status),
    288           GNUNET_JSON_pack_array_steal ("methods",
    289                                         methods),
    290           GNUNET_JSON_pack_array_steal ("currencies",
    291                                         currencies),
    292           TALER_JSON_pack_amount ("annual_fee",
    293                                   &cfg->annual_fee),
    294           TALER_JSON_pack_amount_list ("annual_fees",
    295                                        &cfg->annual_fees),
    296           TALER_JSON_pack_amount ("truth_upload_fee",
    297                                   &cfg->truth_upload_fee),
    298           TALER_JSON_pack_amount_list ("truth_upload_fees",
    299                                        &cfg->truth_upload_fees),
    300           TALER_JSON_pack_amount ("liability_limit",
    301                                   &cfg->liability_limit),
    302           TALER_JSON_pack_amount_list ("liability_limits",
    303                                        &cfg->liability_limits),
    304           GNUNET_JSON_pack_string ("business_name",
    305                                    cfg->business_name),
    306           GNUNET_JSON_pack_uint64 ("storage_limit_in_megabytes",
    307                                    cfg->storage_limit_in_megabytes),
    308           GNUNET_JSON_pack_data_auto ("provider_salt",
    309                                       &cfg->provider_salt),
    310           GNUNET_JSON_pack_uint64 ("http_status",
    311                                    cfg->http_status),
    312           GNUNET_JSON_pack_conditional (
    313             NULL != cfg->currency,
    314             GNUNET_JSON_pack_string ("currency",
    315                                      cfg->currency)));
    316       }
    317     }
    318     GNUNET_assert (0 ==
    319                    json_object_set_new (obj,
    320                                         p->url.url,
    321                                         po));
    322   }
    323   return obj;
    324 }
    325 
    326 
    327 /**
    328  * Add the fields shared by the backup and recovery variants to @a obj.
    329  *
    330  * @param[in,out] obj object to extend
    331  * @param common state to serialize
    332  */
    333 static void
    334 serialize_common (json_t *obj,
    335                   const struct ANASTASIS_ReduxCommon *common)
    336 {
    337   if (common->have_continents)
    338     set_opt (obj,
    339              "continents",
    340              serialize_continents (common));
    341   if (common->have_countries)
    342     set_opt (obj,
    343              "countries",
    344              serialize_countries (common));
    345   if (common->have_required_attributes)
    346     set_opt (obj,
    347              "required_attributes",
    348              serialize_required_attributes (common));
    349   if (common->have_providers)
    350     set_opt (obj,
    351              "authentication_providers",
    352              serialize_providers (common));
    353   if (NULL != common->identity_attributes)
    354     set_opt (obj,
    355              "identity_attributes",
    356              json_incref (common->identity_attributes));
    357   if (common->have_currencies)
    358   {
    359     json_t *arr;
    360 
    361     arr = json_array ();
    362     GNUNET_assert (NULL != arr);
    363     for (unsigned int i = 0; i < common->currencies_len; i++)
    364       GNUNET_assert (0 ==
    365                      json_array_append_new (
    366                        arr,
    367                        json_string (common->currencies[i])));
    368     set_opt (obj,
    369              "currencies",
    370              arr);
    371   }
    372   if (NULL != common->selected_continent)
    373     set_opt (obj,
    374              "selected_continent",
    375              json_string (common->selected_continent));
    376   if (NULL != common->selected_country)
    377     set_opt (obj,
    378              "selected_country",
    379              json_string (common->selected_country));
    380   if (NULL != common->preferred_currency)
    381     set_opt (obj,
    382              "preferred_currency",
    383              json_string (common->preferred_currency));
    384 }
    385 
    386 
    387 /**
    388  * Serialize the backup-specific fields into @a obj.
    389  *
    390  * @param[in,out] obj object to extend
    391  * @param b backup state to serialize
    392  */
    393 static void
    394 serialize_backup (json_t *obj,
    395                   const struct ANASTASIS_ReduxBackup *b)
    396 {
    397   if (b->have_authentication_methods)
    398   {
    399     json_t *arr;
    400 
    401     arr = json_array ();
    402     GNUNET_assert (NULL != arr);
    403     for (unsigned int i = 0; i < b->authentication_methods_len; i++)
    404     {
    405       const struct ANASTASIS_ReduxAuthMethod *am
    406         = &b->authentication_methods[i];
    407 
    408       GNUNET_assert (0 ==
    409                      json_array_append_new (
    410                        arr,
    411                        GNUNET_JSON_PACK (
    412                          GNUNET_JSON_pack_string ("type",
    413                                                   am->type),
    414                          GNUNET_JSON_pack_string ("instructions",
    415                                                   am->instructions),
    416                          GNUNET_JSON_pack_data_varsize ("challenge",
    417                                                         am->challenge,
    418                                                         am->challenge_size),
    419                          GNUNET_JSON_pack_conditional (
    420                            NULL != am->mime_type,
    421                            GNUNET_JSON_pack_string ("mime_type",
    422                                                     am->mime_type)))));
    423     }
    424     set_opt (obj,
    425              "authentication_methods",
    426              arr);
    427   }
    428   if (b->have_policies)
    429   {
    430     json_t *arr;
    431 
    432     arr = json_array ();
    433     GNUNET_assert (NULL != arr);
    434     for (unsigned int i = 0; i < b->policies_len; i++)
    435     {
    436       const struct ANASTASIS_ReduxPolicy *p = &b->policies[i];
    437       json_t *methods;
    438 
    439       methods = json_array ();
    440       GNUNET_assert (NULL != methods);
    441       for (unsigned int j = 0; j < p->methods_len; j++)
    442       {
    443         const struct ANASTASIS_ReduxPolicyMethod *pm = &p->methods[j];
    444         json_t *mo;
    445 
    446         mo = GNUNET_JSON_PACK (
    447           GNUNET_JSON_pack_uint64 ("authentication_method",
    448                                    pm->authentication_method.idx),
    449           GNUNET_JSON_pack_string ("provider",
    450                                    pm->provider.url));
    451         if (NULL != pm->truth)
    452         {
    453           json_t *truth = ANASTASIS_truth_to_json (pm->truth);
    454 
    455           GNUNET_assert (NULL != truth);
    456           GNUNET_assert (0 ==
    457                          json_object_set_new (truth,
    458                                               "upload_status",
    459                                               json_integer (
    460                                                 pm->upload_status)));
    461           GNUNET_assert (0 ==
    462                          json_object_set_new (mo,
    463                                               "truth",
    464                                               truth));
    465         }
    466         GNUNET_assert (0 ==
    467                        json_array_append_new (methods,
    468                                               mo));
    469       }
    470       GNUNET_assert (0 ==
    471                      json_array_append_new (
    472                        arr,
    473                        GNUNET_JSON_PACK (
    474                          GNUNET_JSON_pack_conditional (
    475                            p->have_recovery_cost,
    476                            TALER_JSON_pack_amount ("recovery_cost",
    477                                                    &p->recovery_cost)),
    478                          GNUNET_JSON_pack_array_steal ("methods",
    479                                                        methods))));
    480     }
    481     set_opt (obj,
    482              "policies",
    483              arr);
    484   }
    485   if (b->have_policy_providers)
    486   {
    487     json_t *arr;
    488 
    489     arr = json_array ();
    490     GNUNET_assert (NULL != arr);
    491     for (unsigned int i = 0; i < b->policy_providers_len; i++)
    492     {
    493       const struct ANASTASIS_ReduxPolicyProvider *pp
    494         = &b->policy_providers[i];
    495 
    496       GNUNET_assert (0 ==
    497                      json_array_append_new (
    498                        arr,
    499                        GNUNET_JSON_PACK (
    500                          GNUNET_JSON_pack_string ("provider_url",
    501                                                   pp->provider_url.url),
    502                          GNUNET_JSON_pack_conditional (
    503                            pp->have_payment_secret,
    504                            GNUNET_JSON_pack_data_auto (
    505                              "payment_secret",
    506                              &pp->payment_secret)))));
    507     }
    508     set_opt (obj,
    509              "policy_providers",
    510              arr);
    511   }
    512   if (b->have_upload_fees)
    513   {
    514     json_t *arr;
    515 
    516     arr = json_array ();
    517     GNUNET_assert (NULL != arr);
    518     for (unsigned int i = 0; i < b->upload_fees_len; i++)
    519       GNUNET_assert (0 ==
    520                      json_array_append_new (
    521                        arr,
    522                        GNUNET_JSON_PACK (
    523                          TALER_JSON_pack_amount ("fee",
    524                                                  &b->upload_fees[i]))));
    525     set_opt (obj,
    526              "upload_fees",
    527              arr);
    528   }
    529   if (b->have_payments)
    530   {
    531     json_t *arr;
    532 
    533     arr = json_array ();
    534     GNUNET_assert (NULL != arr);
    535     for (unsigned int i = 0; i < b->payments_len; i++)
    536       GNUNET_assert (0 ==
    537                      json_array_append_new (arr,
    538                                             json_string (b->payments[i])));
    539     set_opt (obj,
    540              "payments",
    541              arr);
    542   }
    543   if (b->have_policy_payment_requests)
    544   {
    545     json_t *arr;
    546 
    547     arr = json_array ();
    548     GNUNET_assert (NULL != arr);
    549     for (unsigned int i = 0; i < b->policy_payment_requests_len; i++)
    550     {
    551       const struct ANASTASIS_ReduxPolicyPaymentRequest *ppr
    552         = &b->policy_payment_requests[i];
    553 
    554       GNUNET_assert (0 ==
    555                      json_array_append_new (
    556                        arr,
    557                        GNUNET_JSON_PACK (
    558                          GNUNET_JSON_pack_string ("payto",
    559                                                   ppr->payto),
    560                          GNUNET_JSON_pack_string ("provider",
    561                                                   ppr->provider.url))));
    562     }
    563     set_opt (obj,
    564              "policy_payment_requests",
    565              arr);
    566   }
    567   if (b->have_success_details)
    568   {
    569     json_t *sd;
    570 
    571     sd = json_object ();
    572     GNUNET_assert (NULL != sd);
    573     for (unsigned int i = 0; i < b->success_details_len; i++)
    574     {
    575       const struct ANASTASIS_ReduxSuccessDetail *d = &b->success_details[i];
    576 
    577       GNUNET_assert (0 ==
    578                      json_object_set_new (
    579                        sd,
    580                        d->provider_url.url,
    581                        GNUNET_JSON_PACK (
    582                          GNUNET_JSON_pack_uint64 ("policy_version",
    583                                                   d->policy_version),
    584                          GNUNET_JSON_pack_timestamp ("policy_expiration",
    585                                                      d->policy_expiration))));
    586     }
    587     set_opt (obj,
    588              "success_details",
    589              sd);
    590   }
    591   if (NULL != b->core_secret)
    592     set_opt (obj,
    593              "core_secret",
    594              json_incref (b->core_secret));
    595   if (NULL != b->secret_name)
    596     set_opt (obj,
    597              "secret_name",
    598              json_string (b->secret_name));
    599   if (b->have_expiration)
    600     set_opt (obj,
    601              "expiration",
    602              GNUNET_JSON_from_timestamp (b->expiration));
    603   if (b->have_pay_arguments)
    604   {
    605     json_t *pa;
    606 
    607     pa = json_object ();
    608     GNUNET_assert (NULL != pa);
    609     if (b->pay_arguments.have_timeout)
    610       set_opt (pa,
    611                "timeout",
    612                GNUNET_JSON_from_time_rel (b->pay_arguments.timeout));
    613     set_opt (obj,
    614              "pay_arguments",
    615              pa);
    616   }
    617 }
    618 
    619 
    620 /**
    621  * Serialize the recovery information @a ri.
    622  *
    623  * @param ri recovery information to serialize
    624  * @return JSON object
    625  */
    626 static json_t *
    627 serialize_recovery_info (const struct ANASTASIS_ReduxRecoveryInfo *ri)
    628 {
    629   json_t *challenges;
    630   json_t *policies;
    631 
    632   challenges = json_array ();
    633   GNUNET_assert (NULL != challenges);
    634   for (unsigned int i = 0; i < ri->challenges_len; i++)
    635   {
    636     const struct ANASTASIS_ReduxChallengeInfo *ci = &ri->challenges[i];
    637 
    638     GNUNET_assert (0 ==
    639                    json_array_append_new (
    640                      challenges,
    641                      GNUNET_JSON_PACK (
    642                        GNUNET_JSON_pack_data_auto ("uuid",
    643                                                    &ci->uuid),
    644                        GNUNET_JSON_pack_string ("type",
    645                                                 ci->type),
    646                        GNUNET_JSON_pack_string ("uuid-display",
    647                                                 ANASTASIS_CRYPTO_uuid2s (
    648                                                   &ci->uuid)),
    649                        GNUNET_JSON_pack_string ("instructions",
    650                                                 ci->instructions),
    651                        GNUNET_JSON_pack_conditional (
    652                          NULL != ci->answer,
    653                          GNUNET_JSON_pack_string ("answer",
    654                                                   ci->answer)),
    655                        GNUNET_JSON_pack_conditional (
    656                          ci->have_payment_secret,
    657                          GNUNET_JSON_pack_data_auto ("payment_secret",
    658                                                      &ci->payment_secret)))));
    659   }
    660   policies = json_array ();
    661   GNUNET_assert (NULL != policies);
    662   for (unsigned int i = 0; i < ri->policies_len; i++)
    663   {
    664     const struct ANASTASIS_ReduxRecoveryPolicy *p = &ri->policies[i];
    665     json_t *pa;
    666 
    667     pa = json_array ();
    668     GNUNET_assert (NULL != pa);
    669     for (unsigned int j = 0; j < p->uuids_len; j++)
    670       GNUNET_assert (0 ==
    671                      json_array_append_new (
    672                        pa,
    673                        GNUNET_JSON_PACK (
    674                          GNUNET_JSON_pack_data_auto ("uuid",
    675                                                      &p->uuids[j]))));
    676     GNUNET_assert (0 ==
    677                    json_array_append_new (policies,
    678                                           pa));
    679   }
    680   return GNUNET_JSON_PACK (
    681     GNUNET_JSON_pack_array_steal ("challenges",
    682                                   challenges),
    683     GNUNET_JSON_pack_array_steal ("policies",
    684                                   policies),
    685     GNUNET_JSON_pack_allow_null (
    686       GNUNET_JSON_pack_string ("secret_name",
    687                                ri->secret_name)),
    688     GNUNET_JSON_pack_string ("provider_url",
    689                              ri->provider_url.url),
    690     GNUNET_JSON_pack_uint64 ("version",
    691                              ri->version));
    692 }
    693 
    694 
    695 /**
    696  * Serialize one challenge feedback entry.
    697  *
    698  * @param fb feedback to serialize
    699  * @return JSON object
    700  */
    701 static json_t *
    702 serialize_feedback (const struct ANASTASIS_ReduxFeedback *fb)
    703 {
    704   json_t *fo;
    705 
    706   switch (fb->status)
    707   {
    708   case ANASTASIS_RFS_CODE_IN_FILE:
    709     fo = GNUNET_JSON_PACK (
    710       GNUNET_JSON_pack_string ("state",
    711                                "code-in-file"),
    712       GNUNET_JSON_pack_string ("filename",
    713                                fb->details.code_in_file.filename));
    714     break;
    715   case ANASTASIS_RFS_SEND_TO_ADDRESS:
    716     fo = GNUNET_JSON_PACK (
    717       GNUNET_JSON_pack_string ("state",
    718                                "send-to-address"),
    719       GNUNET_JSON_pack_conditional (
    720         NULL != fb->details.send_to_address.address_hint,
    721         GNUNET_JSON_pack_string ("address_hint",
    722                                  fb->details.send_to_address.address_hint)));
    723     break;
    724   case ANASTASIS_RFS_TALER_PAYMENT:
    725     fo = GNUNET_JSON_PACK (
    726       GNUNET_JSON_pack_string ("state",
    727                                "taler-payment"),
    728       GNUNET_JSON_pack_string ("taler_pay_uri",
    729                                fb->details.taler_payment.taler_pay_uri),
    730       GNUNET_JSON_pack_string ("provider",
    731                                fb->details.taler_payment.provider.url),
    732       GNUNET_JSON_pack_data_auto ("payment_secret",
    733                                   &fb->details.taler_payment.payment_secret));
    734     break;
    735   case ANASTASIS_RFS_SERVER_FAILURE:
    736     fo = GNUNET_JSON_PACK (
    737       GNUNET_JSON_pack_string ("state",
    738                                "server-failure"),
    739       GNUNET_JSON_pack_uint64 ("http_status",
    740                                fb->details.server_failure.http_status),
    741       GNUNET_JSON_pack_uint64 ("error_code",
    742                                fb->details.server_failure.ec));
    743     break;
    744   case ANASTASIS_RFS_TRUTH_UNKNOWN:
    745     fo = GNUNET_JSON_PACK (
    746       GNUNET_JSON_pack_string ("state",
    747                                "truth-unknown"),
    748       GNUNET_JSON_pack_uint64 ("http_status",
    749                                fb->details.server_failure.http_status),
    750       GNUNET_JSON_pack_uint64 ("error_code",
    751                                fb->details.server_failure.ec));
    752     break;
    753   case ANASTASIS_RFS_IBAN_INSTRUCTIONS:
    754     fo = GNUNET_JSON_PACK (
    755       GNUNET_JSON_pack_string ("state",
    756                                "iban-instructions"),
    757       GNUNET_JSON_pack_string ("target_iban",
    758                                fb->details.iban_instructions.target_iban),
    759       GNUNET_JSON_pack_string (
    760         "target_business_name",
    761         fb->details.iban_instructions.target_business_name),
    762       GNUNET_JSON_pack_string (
    763         "wire_transfer_subject",
    764         fb->details.iban_instructions.wire_transfer_subject),
    765       TALER_JSON_pack_amount ("challenge_amount",
    766                               &fb->details.iban_instructions.amount));
    767     break;
    768   case ANASTASIS_RFS_SOLVED:
    769     fo = GNUNET_JSON_PACK (
    770       GNUNET_JSON_pack_string ("state",
    771                                "solved"));
    772     break;
    773   case ANASTASIS_RFS_INCORRECT_ANSWER:
    774     fo = GNUNET_JSON_PACK (
    775       GNUNET_JSON_pack_string ("state",
    776                                "incorrect-answer"),
    777       GNUNET_JSON_pack_uint64 ("error_code",
    778                                fb->details.incorrect_answer.ec));
    779     break;
    780   case ANASTASIS_RFS_RATE_LIMIT_EXCEEDED:
    781     fo = GNUNET_JSON_PACK (
    782       GNUNET_JSON_pack_string ("state",
    783                                "rate-limit-exceeded"),
    784       GNUNET_JSON_pack_uint64 (
    785         "request_limit",
    786         fb->details.rate_limit_exceeded.request_limit),
    787       GNUNET_JSON_pack_time_rel (
    788         "request_frequency",
    789         fb->details.rate_limit_exceeded.request_frequency),
    790       GNUNET_JSON_pack_uint64 ("error_code",
    791                                fb->details.rate_limit_exceeded.ec));
    792     break;
    793   default:
    794     GNUNET_assert (0);
    795   }
    796   if (NULL != fb->display_hint)
    797     set_opt (fo,
    798              "display_hint",
    799              json_string (fb->display_hint));
    800   return fo;
    801 }
    802 
    803 
    804 /**
    805  * Serialize the recovery-specific fields into @a obj.
    806  *
    807  * @param[in,out] obj object to extend
    808  * @param rr recovery state to serialize
    809  */
    810 static void
    811 serialize_recovery (json_t *obj,
    812                     const struct ANASTASIS_ReduxRecovery *rr)
    813 {
    814   if (NULL != rr->ri)
    815     set_opt (obj,
    816              "recovery_information",
    817              serialize_recovery_info (rr->ri));
    818   if (NULL != rr->r)
    819     set_opt (obj,
    820              "recovery_document",
    821              ANASTASIS_recovery_serialize (rr->r));
    822   if (rr->have_challenge_feedback)
    823   {
    824     json_t *cf;
    825 
    826     cf = json_object ();
    827     GNUNET_assert (NULL != cf);
    828     for (unsigned int i = 0; i < rr->challenge_feedback_len; i++)
    829     {
    830       const struct ANASTASIS_ReduxFeedback *fb = &rr->challenge_feedback[i];
    831       char uuid[sizeof (fb->uuid) * 2];
    832       char *end;
    833 
    834       end = GNUNET_STRINGS_data_to_string (&fb->uuid,
    835                                            sizeof (fb->uuid),
    836                                            uuid,
    837                                            sizeof (uuid));
    838       GNUNET_assert (NULL != end);
    839       *end = '\0';
    840       GNUNET_assert (0 ==
    841                      json_object_set_new (cf,
    842                                           uuid,
    843                                           serialize_feedback (fb)));
    844     }
    845     set_opt (obj,
    846              "challenge_feedback",
    847              cf);
    848   }
    849   if (rr->have_selected_challenge)
    850     set_opt (obj,
    851              "selected_challenge_uuid",
    852              GNUNET_JSON_from_data_auto (&rr->selected_challenge));
    853   if (NULL != rr->core_secret)
    854     set_opt (obj,
    855              "core_secret",
    856              json_incref (rr->core_secret));
    857 }
    858 
    859 
    860 json_t *
    861 ANASTASIS_REDUX_state_serialize_ (const struct ANASTASIS_ReduxState *rs)
    862 {
    863   json_t *obj;
    864 
    865   switch (rs->type)
    866   {
    867   case ANASTASIS_RT_BACKUP:
    868     obj = GNUNET_JSON_PACK (
    869       GNUNET_JSON_pack_string ("reducer_type",
    870                                "backup"),
    871       GNUNET_JSON_pack_string ("backup_state",
    872                                ANASTASIS_backup_state_to_string_ (
    873                                  rs->details.backup.state)));
    874     serialize_common (obj,
    875                       &rs->common);
    876     serialize_backup (obj,
    877                       &rs->details.backup);
    878     return obj;
    879   case ANASTASIS_RT_RECOVERY:
    880     obj = GNUNET_JSON_PACK (
    881       GNUNET_JSON_pack_string ("reducer_type",
    882                                "recovery"),
    883       GNUNET_JSON_pack_string ("recovery_state",
    884                                ANASTASIS_recovery_state_to_string_ (
    885                                  rs->details.recovery.state)));
    886     serialize_common (obj,
    887                       &rs->common);
    888     serialize_recovery (obj,
    889                         &rs->details.recovery);
    890     return obj;
    891   case ANASTASIS_RT_ERROR:
    892     return GNUNET_JSON_PACK (
    893       GNUNET_JSON_pack_string ("reducer_type",
    894                                "error"),
    895       GNUNET_JSON_pack_uint64 ("code",
    896                                rs->details.error.code),
    897       GNUNET_JSON_pack_allow_null (
    898         GNUNET_JSON_pack_string ("hint",
    899                                  rs->details.error.hint)),
    900       GNUNET_JSON_pack_allow_null (
    901         GNUNET_JSON_pack_string ("detail",
    902                                  rs->details.error.detail)));
    903   }
    904   GNUNET_assert (0);
    905   return NULL;
    906 }
    907 
    908 
    909 /* end of anastasis_api_redux_serialize.c */