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