anastasis

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

anastasis-cli-discover.c (7611B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 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-discover.c
     18  * @brief command line tool to discover recovery policies
     19  * @author Christian Grothoff
     20  */
     21 
     22 #include "platform.h"
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include <gnunet/gnunet_curl_lib.h>
     25 #include "anastasis_redux.h"
     26 #include <taler/taler_util.h>
     27 #include <taler/taler_error_codes.h>
     28 #include <taler/taler_json_lib.h>
     29 #include "anastasis_util_lib.h"
     30 #include "anastasis-cli-common.h"
     31 
     32 /**
     33  * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
     34  */
     35 static struct GNUNET_CURL_RescheduleContext *rc;
     36 
     37 /**
     38  * Curl context for communication with anastasis backend
     39  */
     40 static struct GNUNET_CURL_Context *ctx;
     41 
     42 /**
     43  * Input to -a option given.
     44  */
     45 static char *input;
     46 
     47 /**
     48  * JSON containing previous state
     49  */
     50 static json_t *prev_state;
     51 
     52 /**
     53  * JSON containing arguments for action
     54  */
     55 static json_t *arguments;
     56 
     57 /**
     58  * Handle to an ongoing action.
     59  */
     60 struct ANASTASIS_PolicyDiscovery *pd;
     61 
     62 /**
     63  * Return value from main.  Defaults to failure so that every path which
     64  * shuts down without discovery having run to completion — a parse error, a
     65  * failed start, or a signal — is reported to the caller's shell.
     66  */
     67 static int global_ret = 1;
     68 
     69 
     70 /**
     71  * Function called on each discovered recovery policy. Called
     72  * with all arguments NULL if we have received all policies that
     73  * we could possibly receive for the current operation.
     74  *
     75  * The client can then start a new policy discovery process, using the
     76  * smallest (also most recent) @a version received per @a provider_url
     77  * in the cursor to resume.  Note that in this case, the application
     78  * logic is responsible for de-duplication using @a hcpd, or it may show
     79  * policies again if they are at different providers under versions not
     80  * queried up to the cursor.
     81  *
     82  * @param cls closure
     83  * @param hcpd hash of the compressed policy document (unique per policy)
     84  * @param provider_url which provider claims to have this policy
     85  * @param version version of the policy at this provider
     86  * @param attribute_mask combination of optional identity attributes
     87  *           present in the state that was used to locate this version
     88  * @param server_time when did the provider receive the upload
     89  * @param secret_name name the user assigned to the backup
     90  */
     91 static void
     92 print_policy_cb (void *cls,
     93                  const struct GNUNET_HashCode *hcpd,
     94                  const char *provider_url,
     95                  uint32_t version,
     96                  json_int_t attribute_mask,
     97                  struct GNUNET_TIME_Timestamp server_time,
     98                  const char *secret_name,
     99                  const json_t *providers)
    100 {
    101   if (NULL == hcpd)
    102   {
    103     fprintf (stderr,
    104              "All results received, terminating\n");
    105     pd = NULL;
    106     global_ret = 0;
    107     GNUNET_SCHEDULER_shutdown ();
    108     return;
    109   }
    110   fprintf (stdout,
    111            "%s %u %u : \"%s\" \"%s\" (%s)\n",
    112            provider_url,
    113            (unsigned int) version,
    114            (unsigned int) attribute_mask,
    115            GNUNET_TIME_timestamp2s (server_time),
    116            secret_name,
    117            GNUNET_h2s (hcpd));
    118 }
    119 
    120 
    121 /**
    122  * @brief Shutdown the application.
    123  *
    124  * @param cls closure
    125  */
    126 static void
    127 shutdown_task (void *cls)
    128 {
    129   (void) cls;
    130 
    131   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    132               "Shutdown initiated\n");
    133   if (NULL != pd)
    134   {
    135     ANASTASIS_policy_discovery_stop (pd);
    136     pd = NULL;
    137   }
    138   ANASTASIS_redux_done ();
    139   if (NULL != ctx)
    140   {
    141     GNUNET_CURL_fini (ctx);
    142     ctx = NULL;
    143   }
    144   if (NULL != rc)
    145   {
    146     GNUNET_CURL_gnunet_rc_destroy (rc);
    147     rc = NULL;
    148   }
    149   json_decref (prev_state);
    150   prev_state = NULL;
    151   json_decref (arguments);
    152   arguments = NULL;
    153   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    154               "Shutdown complete\n");
    155 }
    156 
    157 
    158 /**
    159  * @brief Start the application
    160  *
    161  * @param cls closure
    162  * @param args arguments left
    163  * @param cfgfile config file name
    164  * @param cfg handle for the configuration file
    165  */
    166 static void
    167 run (void *cls,
    168      char *const *args,
    169      const char *cfgfile,
    170      const struct GNUNET_CONFIGURATION_Handle *cfg)
    171 {
    172   json_error_t error;
    173 
    174   (void) cls;
    175   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    176               "Starting anastasis-discover\n");
    177   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
    178                                  NULL);
    179   /* load cursor */
    180   if (NULL != input)
    181   {
    182     arguments = json_loads (input,
    183                             JSON_DECODE_ANY,
    184                             &error);
    185     if (NULL == arguments)
    186     {
    187       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    188                   "Failed to parse arguments on line %u:%u: %s!\n",
    189                   error.line,
    190                   error.column,
    191                   error.text);
    192       GNUNET_SCHEDULER_shutdown ();
    193       return;
    194     }
    195   }
    196   /* load state */
    197   if (NULL != args[0])
    198   {
    199     prev_state = json_load_file (args[0],
    200                                  JSON_DECODE_ANY,
    201                                  &error);
    202     args++;
    203   }
    204   else
    205   {
    206     prev_state = ANASTASIS_CLI_json_load_capped (stdin,
    207                                                  &error);
    208   }
    209   if (NULL == prev_state)
    210   {
    211     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    212                 "Failed to parse initial state on line %u:%u: %s!\n",
    213                 error.line,
    214                 error.column,
    215                 error.text);
    216     GNUNET_SCHEDULER_shutdown ();
    217     return;
    218   }
    219   /* initialize HTTP client event loop */
    220   ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    221                           &rc);
    222   rc = GNUNET_CURL_gnunet_rc_create (ctx);
    223   ANASTASIS_redux_init (ctx);
    224   pd = ANASTASIS_policy_discovery_start (prev_state,
    225                                          arguments,
    226                                          &print_policy_cb,
    227                                          NULL);
    228   if (NULL == pd)
    229   {
    230     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    231                 "Failed to start policy discovery\n");
    232     GNUNET_SCHEDULER_shutdown ();
    233     return;
    234   }
    235 }
    236 
    237 
    238 int
    239 main (int argc,
    240       char *const *argv)
    241 {
    242   /* the available command line options */
    243   struct GNUNET_GETOPT_CommandLineOption options[] = {
    244     GNUNET_GETOPT_option_string ('a',
    245                                  "arguments",
    246                                  "JSON",
    247                                  "pass a JSON string containing cursor to use",
    248                                  &input),
    249 
    250     GNUNET_GETOPT_OPTION_END
    251   };
    252   enum GNUNET_GenericReturnValue ret;
    253 
    254   ret = GNUNET_PROGRAM_run (ANASTASIS_project_data (),
    255                             argc,
    256                             argv,
    257                             "anastasis-discover",
    258                             "This is an application for finding secrets that could be recovered.\n",
    259                             options,
    260                             &run,
    261                             NULL);
    262   if (GNUNET_SYSERR == ret)
    263     return 3;
    264   if (GNUNET_NO == ret)
    265     return 0;
    266   return global_ret;
    267 }
    268 
    269 
    270 /* end of anastasis-cli-discover.c */