anastasis

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

anastasis-cli-redux.c (10165B)


      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 Lesser 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 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.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file cli/anastasis-cli-redux.c
     18  * @brief command line tool for our reducer
     19  * @author Christian Grothoff
     20  * @author Dennis Neufeld
     21  * @author Dominik Meister
     22  */
     23 
     24 #include "platform.h"
     25 #include <gnunet/gnunet_util_lib.h>
     26 #include <gnunet/gnunet_curl_lib.h>
     27 #include "anastasis_redux.h"
     28 #include <taler/taler_util.h>
     29 #include <taler/taler_error_codes.h>
     30 #include <taler/taler_json_lib.h>
     31 #include "anastasis_util_lib.h"
     32 
     33 /**
     34  * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
     35  */
     36 static struct GNUNET_CURL_RescheduleContext *rc;
     37 
     38 /**
     39  * Curl context for communication with anastasis backend
     40  */
     41 static struct GNUNET_CURL_Context *ctx;
     42 
     43 /**
     44  * Application ID to include in the user attributes.
     45  * (-a option).
     46  */
     47 char *application_id;
     48 
     49 /**
     50  * -b option given.
     51  */
     52 static int b_flag;
     53 
     54 /**
     55  * -r option given.
     56  */
     57 static int r_flag;
     58 
     59 /**
     60  * Input to -a option given.
     61  */
     62 static char *input;
     63 
     64 /**
     65  * Output filename, if given.
     66  */
     67 static char *output_filename;
     68 
     69 /**
     70  * JSON containing previous state
     71  */
     72 static json_t *prev_state;
     73 
     74 /**
     75  * JSON containing arguments for action
     76  */
     77 static json_t *arguments;
     78 
     79 /**
     80  * Handle to an ongoing action.
     81  */
     82 static struct ANASTASIS_ReduxAction *ra;
     83 
     84 /**
     85  * Return value from main.
     86  */
     87 static int global_ret;
     88 
     89 
     90 /**
     91  * Persist a json state, report errors.
     92  *
     93  * @param state to persist
     94  * @param filename where to write the state to, NULL for stdout
     95  */
     96 static void
     97 persist_new_state (json_t *state,
     98                    const char *filename)
     99 {
    100   if (NULL != filename)
    101   {
    102     if (0 !=
    103         json_dump_file (state,
    104                         filename,
    105                         JSON_COMPACT))
    106     {
    107       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    108                   "Could not dump state to `%s'\n",
    109                   filename);
    110       return;
    111     }
    112     return;
    113   }
    114   {
    115     char *state_str = json_dumps (state,
    116                                   JSON_COMPACT);
    117     if (-1 >=
    118         fprintf (stdout,
    119                  "%s",
    120                  state_str))
    121     {
    122       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    123                   "Could not dump state to stdout\n");
    124       GNUNET_free (state_str);
    125       return;
    126     }
    127     GNUNET_free (state_str);
    128   }
    129 }
    130 
    131 
    132 /**
    133  * Function called with the results of #ANASTASIS_redux_action().
    134  *
    135  * @param cls closure
    136  * @param error_code Error code
    137  * @param result_state new state as result
    138  */
    139 static void
    140 action_cb (void *cls,
    141            enum TALER_ErrorCode error_code,
    142            json_t *result_state)
    143 {
    144   (void) cls;
    145   ra = NULL;
    146   if (NULL != result_state)
    147     persist_new_state (result_state,
    148                        output_filename);
    149   if (TALER_EC_NONE != error_code)
    150   {
    151     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    152                 "Redux failed with error %d: %s\n",
    153                 error_code,
    154                 TALER_ErrorCode_get_hint (error_code));
    155     json_dumpf (result_state,
    156                 stderr,
    157                 JSON_INDENT (2));
    158   }
    159   GNUNET_SCHEDULER_shutdown ();
    160   global_ret = (TALER_EC_NONE != error_code) ? 1 : 0;
    161 }
    162 
    163 
    164 /**
    165  * @brief Shutdown the application.
    166  *
    167  * @param cls closure
    168  */
    169 static void
    170 shutdown_task (void *cls)
    171 {
    172   (void) cls;
    173 
    174   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    175               "Shutdown initiated\n");
    176   if (NULL != ra)
    177   {
    178     ANASTASIS_redux_action_cancel (ra);
    179     ra = NULL;
    180   }
    181   ANASTASIS_redux_done ();
    182   if (NULL != ctx)
    183   {
    184     GNUNET_CURL_fini (ctx);
    185     ctx = NULL;
    186   }
    187   if (NULL != rc)
    188   {
    189     GNUNET_CURL_gnunet_rc_destroy (rc);
    190     rc = NULL;
    191   }
    192   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    193               "Shutdown complete\n");
    194 }
    195 
    196 
    197 /**
    198  * @brief Start the application
    199  *
    200  * @param cls closure
    201  * @param args arguments left
    202  * @param cfgfile config file name
    203  * @param cfg handle for the configuration file
    204  */
    205 static void
    206 run (void *cls,
    207      char *const *args,
    208      const char *cfgfile,
    209      const struct GNUNET_CONFIGURATION_Handle *cfg)
    210 {
    211   json_error_t error;
    212 
    213   (void) cls;
    214   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    215               "Starting anastasis-reducer\n");
    216   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
    217                                  NULL);
    218   if (b_flag && r_flag)
    219   {
    220     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    221                 "We cannot start backup and recovery at the same time!\n");
    222     GNUNET_SCHEDULER_shutdown ();
    223     return;
    224   }
    225   if (r_flag)
    226   {
    227     json_t *init_state;
    228 
    229     init_state = ANASTASIS_recovery_start (cfg);
    230     if (NULL == init_state)
    231     {
    232       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    233                   "Failed to create an initial recovery state!\n");
    234       GNUNET_SCHEDULER_shutdown ();
    235       return;
    236     }
    237     persist_new_state (init_state,
    238                        args[0]);
    239     json_decref (init_state);
    240     GNUNET_SCHEDULER_shutdown ();
    241     return;
    242   }
    243   if (b_flag)
    244   {
    245     json_t *init_state;
    246 
    247     init_state = ANASTASIS_backup_start (cfg);
    248     if (NULL == init_state)
    249     {
    250       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    251                   "Failed to create an initial backup state!\n");
    252       GNUNET_SCHEDULER_shutdown ();
    253       return;
    254     }
    255     persist_new_state (init_state,
    256                        args[0]);
    257     json_decref (init_state);
    258     GNUNET_SCHEDULER_shutdown ();
    259     return;
    260   }
    261 
    262   /* action processing */
    263   {
    264     const char *action = args[0];
    265 
    266     if (NULL == action)
    267     {
    268       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    269                   "You must specify an action as the first argument (or `-b' or `-r')\n");
    270       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    271                   "Example: anastasis-reducer back\n");
    272       GNUNET_SCHEDULER_shutdown ();
    273       return;
    274     }
    275     args++;
    276     if (NULL != input)
    277     {
    278       arguments = json_loads (input,
    279                               JSON_DECODE_ANY,
    280                               &error);
    281       if (NULL == arguments)
    282       {
    283         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    284                     "Failed to parse arguments on line %u:%u: %s!\n",
    285                     error.line,
    286                     error.column,
    287                     error.text);
    288         GNUNET_SCHEDULER_shutdown ();
    289         return;
    290       }
    291     }
    292     if (NULL != args[0])
    293     {
    294       prev_state = json_load_file (args[0],
    295                                    JSON_DECODE_ANY,
    296                                    &error);
    297       args++;
    298     }
    299     else
    300     {
    301       prev_state = json_loadf (stdin,
    302                                JSON_DECODE_ANY,
    303                                &error);
    304     }
    305     if (NULL == prev_state)
    306     {
    307       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    308                   "Failed to parse initial state on line %u:%u: %s!\n",
    309                   error.line,
    310                   error.column,
    311                   error.text);
    312       GNUNET_SCHEDULER_shutdown ();
    313       return;
    314     }
    315     output_filename = args[0];
    316     /* initialize HTTP client event loop */
    317     ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    318                             &rc);
    319     rc = GNUNET_CURL_gnunet_rc_create (ctx);
    320     ANASTASIS_redux_init (ctx);
    321     /* Expand identity_attributes if -a is given explicitly and we
    322        are at the respective step of the reduction */
    323     if ( (0 == strcasecmp (action,
    324                            "enter_user_attributes")) &&
    325          (NULL != application_id) &&
    326          (NULL != arguments) )
    327     {
    328       json_t *attr = json_object_get (arguments,
    329                                       "identity_attributes");
    330       if (NULL != attr)
    331         GNUNET_assert (0 ==
    332                        json_object_set_new (attr,
    333                                             "application-id",
    334                                             json_string (application_id)));
    335     }
    336     ra = ANASTASIS_redux_action (prev_state,
    337                                  action,
    338                                  arguments,
    339                                  &action_cb,
    340                                  cls);
    341   }
    342 }
    343 
    344 
    345 int
    346 main (int argc,
    347       char *const *argv)
    348 {
    349   /* the available command line options */
    350   struct GNUNET_GETOPT_CommandLineOption options[] = {
    351     GNUNET_GETOPT_option_string ('A',
    352                                  "application",
    353                                  "ID",
    354                                  "set the application ID",
    355                                  &application_id),
    356     GNUNET_GETOPT_option_string ('a',
    357                                  "arguments",
    358                                  "JSON",
    359                                  "pass a JSON string containing arguments to reducer",
    360                                  &input),
    361     GNUNET_GETOPT_option_flag ('b',
    362                                "backup",
    363                                "use reducer to handle states for backup process",
    364                                &b_flag),
    365     GNUNET_GETOPT_option_flag ('r',
    366                                "restore",
    367                                "use reducer to handle states for restore process",
    368                                &r_flag),
    369     GNUNET_GETOPT_OPTION_END
    370   };
    371   enum GNUNET_GenericReturnValue ret;
    372 
    373   ret = GNUNET_PROGRAM_run (ANASTASIS_project_data (),
    374                             argc,
    375                             argv,
    376                             "anastasis-reducer",
    377                             "This is an application for using Anastasis to handle the states.\n",
    378                             options,
    379                             &run,
    380                             NULL);
    381   GNUNET_free (application_id);
    382   if (GNUNET_SYSERR == ret)
    383     return 3;
    384   if (GNUNET_NO == ret)
    385     return 0;
    386   return global_ret;
    387 }
    388 
    389 
    390 /* end of anastasis-cli-redux.c */