/* This file is part of Anastasis Copyright (C) 2022 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Anastasis; see the file COPYING.GPL. If not, see */ /** * @file cli/anastasis-cli-discover.c * @brief command line tool to discover recovery policies * @author Christian Grothoff */ #include "platform.h" #include #include #include "anastasis_redux.h" #include #include #include #include "anastasis_util_lib.h" /** * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). */ static struct GNUNET_CURL_RescheduleContext *rc; /** * Curl context for communication with anastasis backend */ static struct GNUNET_CURL_Context *ctx; /** * Input to -a option given. */ static char *input; /** * JSON containing previous state */ static json_t *prev_state; /** * JSON containing arguments for action */ static json_t *arguments; /** * Handle to an ongoing action. */ struct ANASTASIS_PolicyDiscovery *pd; /** * Return value from main. */ static int global_ret; /** * Function called on each discovered recovery policy. Called * with all arguments NULL if we have received all policies that * we could possibly receive for the current operation. * * The client can then start a new policy discovery process, using the * smallest (also most recent) @a version received per @a provider_url * in the cursor to resume. Note that in this case, the application * logic is responsible for de-duplication using @a hcpd, or it may show * policies again if they are at different providers under versions not * queried up to the cursor. * * @param cls closure * @param hcpd hash of the compressed policy document (unique per policy) * @param provider_url which provider claims to have this policy * @param version version of the policy at this provider * @param attribute_mask combination of optional identity attributes * present in the state that was used to locate this version * @param server_time when did the provider receive the upload * @param secret_name name the user assigned to the backup */ static void print_policy_cb (void *cls, const struct GNUNET_HashCode *hcpd, const char *provider_url, uint32_t version, json_int_t attribute_mask, struct GNUNET_TIME_Timestamp server_time, const char *secret_name, const json_t *providers) { if (NULL == hcpd) { fprintf (stderr, "All results received, terminating\n"); pd = NULL; global_ret = 0; GNUNET_SCHEDULER_shutdown (); return; } fprintf (stdout, "%s %u %u : \"%s\" \"%s\" (%s)\n", provider_url, (unsigned int) version, (unsigned int) attribute_mask, GNUNET_TIME_timestamp2s (server_time), secret_name, GNUNET_h2s (hcpd)); } /** * @brief Shutdown the application. * * @param cls closure */ static void shutdown_task (void *cls) { (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutdown initiated\n"); if (NULL != pd) { ANASTASIS_policy_discovery_stop (pd); pd = NULL; } ANASTASIS_redux_done (); if (NULL != ctx) { GNUNET_CURL_fini (ctx); ctx = NULL; } if (NULL != rc) { GNUNET_CURL_gnunet_rc_destroy (rc); rc = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutdown complete\n"); } /** * @brief Start the application * * @param cls closure * @param args arguments left * @param cfgfile config file name * @param cfg handle for the configuration file */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { (void) cls; json_error_t error; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting anastasis-discover\n"); GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* load cursor */ if (NULL != input) { arguments = json_loads (input, JSON_DECODE_ANY, &error); if (NULL == arguments) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Failed to parse arguments on line %u:%u: %s!\n", error.line, error.column, error.text); GNUNET_SCHEDULER_shutdown (); return; } } /* load state */ if (NULL != args[0]) { prev_state = json_load_file (args[0], JSON_DECODE_ANY, &error); args++; } else { prev_state = json_loadf (stdin, JSON_DECODE_ANY, &error); } if (NULL == prev_state) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Failed to parse initial state on line %u:%u: %s!\n", error.line, error.column, error.text); GNUNET_SCHEDULER_shutdown (); return; } /* initialize HTTP client event loop */ ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); rc = GNUNET_CURL_gnunet_rc_create (ctx); ANASTASIS_redux_init (ctx); pd = ANASTASIS_policy_discovery_start (prev_state, arguments, &print_policy_cb, NULL); } int main (int argc, char *const *argv) { /* the available command line options */ struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_option_string ('a', "arguments", "JSON", "pass a JSON string containing cursor to use", &input), GNUNET_GETOPT_OPTION_END }; enum GNUNET_GenericReturnValue ret; /* FIRST get the libtalerutil initialization out of the way. Then throw that one away, and force the SYNC defaults to be used! */ (void) TALER_project_data_default (); GNUNET_OS_init (ANASTASIS_project_data_default ()); ret = GNUNET_PROGRAM_run (argc, argv, "anastasis-discover", "This is an application for finding secrets that could be recovered.\n", options, &run, NULL); if (GNUNET_SYSERR == ret) return 3; if (GNUNET_NO == ret) return 0; return global_ret; } /* end of anastasis-cli-discover.c */