anastasis

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

anastasis_api_providers.c (8089B)


      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_providers.c
     18  * @brief anastasis provider synchronization logic
     19  * @author Christian Grothoff
     20  */
     21 
     22 #include <platform.h>
     23 #include <jansson.h>
     24 #include "anastasis_redux.h"
     25 #include "anastasis_error_codes.h"
     26 #include "anastasis_api_redux.h"
     27 
     28 
     29 /**
     30  * Main data structure for sync_providers().
     31  */
     32 struct MasterSync;
     33 
     34 
     35 /**
     36  * Data structure for one provider we are syncing /config with.
     37  */
     38 struct SyncEntry
     39 {
     40   /**
     41    * Kept in a DLL.
     42    */
     43   struct SyncEntry *next;
     44 
     45   /**
     46    * Kept in a DLL.
     47    */
     48   struct SyncEntry *prev;
     49 
     50   /**
     51    * Sync operation we are part of.
     52    */
     53   struct MasterSync *ms;
     54 
     55   /**
     56    * Redux action for this provider.
     57    */
     58   struct ANASTASIS_ReduxAction *ra;
     59 };
     60 
     61 
     62 /**
     63  * Main data structure for sync_providers().
     64  */
     65 struct MasterSync
     66 {
     67   /**
     68    * Our own sync action we expose externally.
     69    */
     70   struct ANASTASIS_ReduxAction ra;
     71   /**
     72    * Head of DLL with entries per provider.
     73    */
     74   struct SyncEntry *se_head;
     75   /**
     76    * Tail of DLL with entries per provider.
     77    */
     78   struct SyncEntry *se_tail;
     79 
     80   /**
     81    * Function to call with the result.
     82    */
     83   ANASTASIS_ActionCallback cb;
     84 
     85   /**
     86    * Closure for @e cb.
     87    */
     88   void *cb_cls;
     89 
     90 };
     91 
     92 
     93 /**
     94  * Free @a cls data structure.
     95  *
     96  * @param[in] cls data structure to free, must be a `struct MasterSync *`
     97  */
     98 static void
     99 clean_sync (void *cls)
    100 {
    101   struct MasterSync *ms = cls;
    102   struct SyncEntry *se;
    103 
    104   while (NULL != (se = ms->se_head))
    105   {
    106     GNUNET_CONTAINER_DLL_remove (ms->se_head,
    107                                  ms->se_tail,
    108                                  se);
    109     se->ra->cleanup (se->ra->cleanup_cls);
    110     GNUNET_free (se);
    111   }
    112   GNUNET_free (ms);
    113 }
    114 
    115 
    116 /**
    117  * Function called when we have made progress on any of the
    118  * providers we are trying to sync with.
    119  *
    120  * @param cls closure
    121  * @param error error code, #TALER_EC_NONE if @a new_bs is the new successful state
    122  * @param new_state the new state of the operation (client should json_incref() to keep an alias)
    123  */
    124 static void
    125 sync_progress (void *cls,
    126                enum TALER_ErrorCode error,
    127                json_t *new_state)
    128 {
    129   struct SyncEntry *se = cls;
    130   struct MasterSync *ms = se->ms;
    131 
    132   GNUNET_CONTAINER_DLL_remove (ms->se_head,
    133                                ms->se_tail,
    134                                se);
    135   GNUNET_free (se);
    136   ms->cb (ms->cb_cls,
    137           error,
    138           new_state);
    139   clean_sync (ms);
    140 }
    141 
    142 
    143 struct ANASTASIS_ReduxAction *
    144 ANASTASIS_REDUX_sync_providers_ (json_t *state,
    145                                  const json_t *arguments,
    146                                  ANASTASIS_ActionCallback cb,
    147                                  void *cb_cls)
    148 {
    149   json_t *rd;
    150   json_t *cs_arr;
    151   struct MasterSync *ms;
    152 
    153   rd = json_object_get (state,
    154                         "recovery_document");
    155   if (NULL == rd)
    156   {
    157     GNUNET_break (0);
    158     ANASTASIS_redux_fail_ (cb,
    159                            cb_cls,
    160                            TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
    161                            "'recovery_document' missing");
    162     return NULL;
    163   }
    164   cs_arr = json_object_get (rd,
    165                             "challenges");
    166   if (! json_is_array (cs_arr))
    167   {
    168     GNUNET_break_op (0);
    169     ANASTASIS_redux_fail_ (cb,
    170                            cb_cls,
    171                            TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
    172                            "'recovery_document' must be an array");
    173     return NULL;
    174   }
    175   ms = GNUNET_new (struct MasterSync);
    176   ms->cb = cb;
    177   ms->cb_cls = cb_cls;
    178   {
    179     json_t *cs;
    180     unsigned int n_index;
    181 
    182     json_array_foreach (cs_arr, n_index, cs)
    183     {
    184       const char *provider_url;
    185       struct GNUNET_JSON_Specification spec[] = {
    186         GNUNET_JSON_spec_string ("url",
    187                                  &provider_url),
    188         GNUNET_JSON_spec_end ()
    189       };
    190       struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
    191       struct SyncEntry *se;
    192 
    193       if (GNUNET_OK !=
    194           GNUNET_JSON_parse (cs,
    195                              spec,
    196                              NULL, NULL))
    197       {
    198         GNUNET_break_op (0);
    199         ANASTASIS_redux_fail_ (cb,
    200                                cb_cls,
    201                                TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
    202                                "'recovery_document' missing");
    203         clean_sync (ms);
    204         return NULL;
    205       }
    206       if (GNUNET_OK ==
    207           ANASTASIS_reducer_lookup_salt (state,
    208                                          provider_url,
    209                                          &provider_salt))
    210         continue; /* provider already ready */
    211       se = GNUNET_new (struct SyncEntry);
    212       se->ms = ms;
    213       GNUNET_CONTAINER_DLL_insert (ms->se_head,
    214                                    ms->se_tail,
    215                                    se);
    216       se->ra = ANASTASIS_REDUX_add_provider_to_state_ (provider_url,
    217                                                        state,
    218                                                        &sync_progress,
    219                                                        se);
    220     }
    221   }
    222   if (NULL == ms->se_head)
    223   {
    224     /* everything already synced */
    225     clean_sync (ms);
    226     ANASTASIS_redux_fail_ (cb,
    227                            cb_cls,
    228                            TALER_EC_ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED,
    229                            "already in sync");
    230     return NULL;
    231   }
    232   ms->ra.cleanup = &clean_sync;
    233   ms->ra.cleanup_cls = ms;
    234   return &ms->ra;
    235 }
    236 
    237 
    238 struct ANASTASIS_ReduxAction *
    239 ANASTASIS_REDUX_poll_providers_ (json_t *state,
    240                                  const json_t *arguments,
    241                                  ANASTASIS_ActionCallback cb,
    242                                  void *cb_cls)
    243 {
    244   json_t *ap;
    245   const char *url;
    246   json_t *obj;
    247   struct MasterSync *ms;
    248 
    249   ap = json_object_get (state,
    250                         "authentication_providers");
    251   if (NULL == ap)
    252   {
    253     GNUNET_break (0);
    254     ANASTASIS_redux_fail_ (cb,
    255                            cb_cls,
    256                            TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
    257                            "'authentication_providers' missing");
    258     return NULL;
    259   }
    260   ms = GNUNET_new (struct MasterSync);
    261   ms->cb = cb;
    262   ms->cb_cls = cb_cls;
    263   json_object_foreach (ap, url, obj)
    264   {
    265     struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
    266     struct SyncEntry *se;
    267     struct ANASTASIS_ReduxAction *ra;
    268 
    269     if (GNUNET_OK ==
    270         ANASTASIS_reducer_lookup_salt (state,
    271                                        url,
    272                                        &provider_salt))
    273       continue;
    274     se = GNUNET_new (struct SyncEntry);
    275     se->ms = ms;
    276     GNUNET_CONTAINER_DLL_insert (ms->se_head,
    277                                  ms->se_tail,
    278                                  se);
    279     ra = ANASTASIS_REDUX_add_provider_to_state_ (url,
    280                                                  state,
    281                                                  &sync_progress,
    282                                                  se);
    283     if (NULL == ra)
    284       return NULL; /* sync_progress already called! */
    285     se->ra = ra;
    286   }
    287   if (NULL == ms->se_head)
    288   {
    289     /* everything already synced */
    290     clean_sync (ms);
    291     ANASTASIS_redux_fail_ (cb,
    292                            cb_cls,
    293                            TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
    294                            "already in sync");
    295     return NULL;
    296   }
    297   ms->ra.cleanup = &clean_sync;
    298   ms->ra.cleanup_cls = ms;
    299   return &ms->ra;
    300 }