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 */