commit 0c2c6ac10d3c5a1f2294fa7f8d7f0f967f7fa793
parent 4fefdf6262bdffa6a4cfedd5fd25e24821787def
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 29 Jul 2026 12:09:18 +0200
use new typed C structs for the reducer
Diffstat:
13 files changed, 3032 insertions(+), 3885 deletions(-)
diff --git a/src/include/anastasis.h b/src/include/anastasis.h
@@ -122,6 +122,20 @@ ANASTASIS_challenge_set_async (struct ANASTASIS_Challenge *challenge,
/**
+ * Remember the @a answer_pin the user supplied for @a challenge without
+ * declaring the challenge asynchronous. Used when an answer was given
+ * up front, so that it is still around if the provider later turns the
+ * challenge into an asynchronous one.
+ *
+ * @param[in,out] challenge the challenge to update
+ * @param answer_pin answer code to remember
+ */
+void
+ANASTASIS_challenge_set_answer_pin (struct ANASTASIS_Challenge *challenge,
+ uint64_t answer_pin);
+
+
+/**
* Possible outcomes of trying to start a challenge operation.
*/
enum ANASTASIS_ChallengeStartStatus
diff --git a/src/lib/anastasis_recovery.c b/src/lib/anastasis_recovery.c
@@ -471,6 +471,15 @@ ANASTASIS_challenge_set_async (struct ANASTASIS_Challenge *challenge,
uint64_t answer_pin)
{
challenge->ci.async = true;
+ ANASTASIS_challenge_set_answer_pin (challenge,
+ answer_pin);
+}
+
+
+void
+ANASTASIS_challenge_set_answer_pin (struct ANASTASIS_Challenge *challenge,
+ uint64_t answer_pin)
+{
challenge->ci.have_answer_pin = true;
challenge->ci.answer_pin = answer_pin;
}
diff --git a/src/reducer/anastasis_api_backup_redux.c b/src/reducer/anastasis_api_backup_redux.c
@@ -24,6 +24,7 @@
#include "platform.h"
#include "anastasis_redux.h"
#include "anastasis_api_redux.h"
+#include "anastasis_api_redux_state.h"
#include <taler/taler_merchant_service.h>
/**
@@ -149,21 +150,17 @@ ANASTASIS_backup_state_to_string_ (enum ANASTASIS_BackupState bs)
/**
- * Update the 'backup_state' field of @a state to @a new_backup_state.
+ * Transition @a rs to @a new_backup_state.
*
- * @param[in,out] state the state to transition
+ * @param[in,out] rs the state to transition
* @param new_backup_state the state to transition to
*/
static void
-set_state (json_t *state,
+set_state (struct ANASTASIS_ReduxState *rs,
enum ANASTASIS_BackupState new_backup_state)
{
- GNUNET_assert (
- 0 ==
- json_object_set_new (
- state,
- "backup_state",
- json_string (ANASTASIS_backup_state_to_string_ (new_backup_state))));
+ GNUNET_assert (ANASTASIS_RT_BACKUP == rs->type);
+ rs->details.backup.state = new_backup_state;
}
@@ -254,8 +251,14 @@ ANASTASIS_backup_start (const struct GNUNET_CONFIGURATION_Handle *cfg)
json_object_set_new (initial_state,
"reducer_type",
json_string ("backup")));
- set_state (initial_state,
- ANASTASIS_BACKUP_STATE_CONTINENT_SELECTING);
+ GNUNET_assert (
+ 0 ==
+ json_object_set_new (
+ initial_state,
+ "backup_state",
+ json_string (
+ ANASTASIS_backup_state_to_string_ (
+ ANASTASIS_BACKUP_STATE_CONTINENT_SELECTING))));
return initial_state;
}
@@ -292,31 +295,38 @@ challenge_size_ok (uint32_t size_limit_in_mb,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-add_authentication (json_t *state,
+add_authentication (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *auth_providers;
- json_t *method;
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
+ const json_t *method;
const char *method_type;
+ const char *instructions;
+ const char *mime_type = NULL;
void *challenge;
size_t challenge_size;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("type",
&method_type),
+ GNUNET_JSON_spec_string ("instructions",
+ &instructions),
GNUNET_JSON_spec_varsize ("challenge",
&challenge,
&challenge_size),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("mime_type",
+ &mime_type),
+ NULL),
GNUNET_JSON_spec_end ()
};
- auth_providers = json_object_get (state,
- "authentication_providers");
- if (NULL == auth_providers)
+ if (! rs->common.have_providers)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_providers' missing");
@@ -328,7 +338,8 @@ add_authentication (json_t *state,
if (NULL == method)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'authentication_method' required");
@@ -340,10 +351,11 @@ add_authentication (json_t *state,
NULL, NULL))
{
GNUNET_break (0);
- json_dumpf (method,
+ json_dumpf ((json_t *) method,
stderr,
JSON_INDENT (2));
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'authentication_method' content malformed");
@@ -353,70 +365,34 @@ add_authentication (json_t *state,
{
bool found = false;
bool too_big = false;
- json_t *details;
- const char *url;
- json_object_foreach (auth_providers, url, details)
+ for (unsigned int i = 0; i < rs->common.providers_len; i++)
{
- const json_t *methods = NULL;
- json_t *imethod;
- size_t index;
- uint32_t size_limit_in_mb = 0;
- const char *status;
- uint32_t http_status = 0;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
- &size_limit_in_mb),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("http_status",
- &http_status),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("methods",
- &methods),
- NULL),
- GNUNET_JSON_spec_end ()
- };
+ const struct ANASTASIS_ReduxProvider *p = &rs->common.providers[i];
+ const struct ANASTASIS_ReduxProviderConfig *cfg = &p->config;
- if (GNUNET_OK !=
- GNUNET_JSON_parse (details,
- ispec,
- NULL, NULL))
+ if (ANASTASIS_RPS_OK != p->status)
+ continue;
+ if (! p->have_config)
{
GNUNET_break (0);
continue;
}
- if (0 != strcmp (status,
- "ok"))
- continue;
- if (MHD_HTTP_OK != http_status)
+ if (MHD_HTTP_OK != cfg->http_status)
continue; /* skip providers that are down */
- if ( (NULL == methods) ||
- (0 == size_limit_in_mb) )
+ if (0 == cfg->storage_limit_in_megabytes)
{
GNUNET_break (0);
continue;
}
- json_array_foreach (methods, index, imethod)
- {
- const char *type;
-
- type = json_string_value (json_object_get (imethod,
- "type"));
- GNUNET_break (NULL != type);
- if ( (NULL != type) &&
- (0 == strcmp (type,
- method_type)) )
+ for (unsigned int j = 0; j < cfg->methods_len; j++)
+ if (0 == strcmp (cfg->methods[j].type,
+ method_type))
{
found = true;
break;
}
- }
- if (! challenge_size_ok (size_limit_in_mb,
+ if (! challenge_size_ok (cfg->storage_limit_in_megabytes,
challenge_size))
{
/* Challenge data too big for this provider. Try to find another one.
@@ -430,55 +406,42 @@ add_authentication (json_t *state,
}
if (! found)
{
- if (too_big)
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_CHALLENGE_DATA_TOO_BIG,
- method_type);
- }
- else
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_AUTHENTICATION_METHOD_NOT_SUPPORTED,
- method_type);
- }
+ enum TALER_ErrorCode ec
+ = too_big
+ ? TALER_EC_ANASTASIS_REDUCER_CHALLENGE_DATA_TOO_BIG
+ : TALER_EC_ANASTASIS_REDUCER_AUTHENTICATION_METHOD_NOT_SUPPORTED;
+
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ ec,
+ method_type);
GNUNET_JSON_parse_free (spec);
return NULL;
}
}
- GNUNET_JSON_parse_free (spec);
/* append provided method to our array */
{
- json_t *auth_method_arr;
+ struct ANASTASIS_ReduxAuthMethod am = {
+ .type = GNUNET_strdup (method_type),
+ .instructions = GNUNET_strdup (instructions),
+ .mime_type = (NULL == mime_type) ? NULL : GNUNET_strdup (mime_type),
+ .challenge = GNUNET_memdup (challenge,
+ challenge_size),
+ .challenge_size = challenge_size
+ };
- auth_method_arr = json_object_get (state,
- "authentication_methods");
- if (NULL == auth_method_arr)
- {
- auth_method_arr = json_array ();
- GNUNET_assert (0 == json_object_set_new (state,
- "authentication_methods",
- auth_method_arr));
- }
- if (! json_is_array (auth_method_arr))
- {
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'authentication_methods' must be an array");
- return NULL;
- }
- GNUNET_assert (0 ==
- json_array_append (auth_method_arr,
- method));
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ GNUNET_array_append (b->authentication_methods,
+ b->authentication_methods_len,
+ am);
+ b->have_authentication_methods = true;
}
+ GNUNET_JSON_parse_free (spec);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -495,19 +458,19 @@ add_authentication (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-del_authentication (json_t *state,
+del_authentication (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *idx;
- json_t *auth_method_arr;
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
+ const json_t *idx;
+ json_int_t index;
- auth_method_arr = json_object_get (state,
- "authentication_methods");
- if (! json_is_array (auth_method_arr))
+ if (! b->have_authentication_methods)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_methods' must be an array");
@@ -515,7 +478,8 @@ del_authentication (json_t *state,
}
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -526,29 +490,41 @@ del_authentication (json_t *state,
if ( (NULL == idx) ||
(! json_is_integer (idx)) )
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'authentication_method' must be a number");
return NULL;
}
-
+ index = json_integer_value (idx);
+ if ( (index < 0) ||
+ (index >= (json_int_t) b->authentication_methods_len) )
{
- size_t index = (size_t) json_integer_value (idx);
-
- if (0 != json_array_remove (auth_method_arr,
- index))
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
- "removal failed");
- return NULL;
- }
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
+ "removal failed");
+ return NULL;
+ }
+ {
+ struct ANASTASIS_ReduxAuthMethod *am
+ = &b->authentication_methods[index];
+
+ GNUNET_free (am->type);
+ GNUNET_free (am->instructions);
+ GNUNET_free (am->challenge);
+ GNUNET_free (am->mime_type);
+ memmove (am,
+ am + 1,
+ sizeof (*am) * (b->authentication_methods_len - index - 1));
+ b->authentication_methods_len--;
}
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -645,14 +621,16 @@ struct Policy
struct PolicyBuilder
{
/**
- * Authentication providers available overall, from our state.
+ * State we are working on; provides the authentication providers
+ * available overall.
*/
- json_t *providers;
+ const struct ANASTASIS_ReduxCommon *common;
/**
- * Authentication methods available overall, from our state.
+ * Backup state we are working on; provides the authentication
+ * methods the user entered, and receives the computed policies.
*/
- const json_t *methods;
+ struct ANASTASIS_ReduxBackup *backup;
/**
* Head of DLL of all possible policies.
@@ -665,11 +643,6 @@ struct PolicyBuilder
struct Policy *p_tail;
/**
- * Array of authentication policies to be computed.
- */
- json_t *policies;
-
- /**
* Array of length @e req_methods.
*/
unsigned int *m_idx;
@@ -781,137 +754,58 @@ equiv_provider (const struct PolicyBuilder *pb,
const char *p1,
const char *p2)
{
- const json_t *j1;
- const json_t *j2;
- const json_t *m1;
- const json_t *m2;
- struct TALER_Amount uc1;
- struct TALER_Amount uc2;
-
- j1 = json_object_get (pb->providers,
- p1);
- j2 = json_object_get (pb->providers,
- p2);
+ const struct ANASTASIS_ReduxProvider *j1;
+ const struct ANASTASIS_ReduxProvider *j2;
+ const struct ANASTASIS_ReduxProviderConfig *c1;
+ const struct ANASTASIS_ReduxProviderConfig *c2;
+
+ j1 = ANASTASIS_REDUX_provider_find_ (pb->common,
+ p1);
+ j2 = ANASTASIS_REDUX_provider_find_ (pb->common,
+ p2);
if ( (NULL == j1) ||
- (NULL == j2) )
+ (NULL == j2) ||
+ (! j1->have_config) ||
+ (! j2->have_config) )
{
GNUNET_break (0);
return false;
}
-
- {
- struct GNUNET_JSON_Specification s1[] = {
- GNUNET_JSON_spec_array_const ("methods",
- &m1),
- TALER_JSON_spec_amount_any ("truth_upload_fee",
- &uc1),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (j1,
- s1,
- NULL, NULL))
- {
- GNUNET_break (0);
- return false;
- }
- }
-
- {
- struct GNUNET_JSON_Specification s2[] = {
- GNUNET_JSON_spec_array_const ("methods",
- &m2),
- TALER_JSON_spec_amount_any ("truth_upload_fee",
- &uc2),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (j2,
- s2,
- NULL, NULL))
- {
- GNUNET_break (0);
- return false;
- }
- }
-
+ c1 = &j1->config;
+ c2 = &j2->config;
if ( (GNUNET_OK !=
- TALER_amount_cmp_currency (&uc1,
- &uc2)) ||
+ TALER_amount_cmp_currency (&c1->truth_upload_fee,
+ &c2->truth_upload_fee)) ||
(0 !=
- TALER_amount_cmp (&uc1,
- &uc2)) )
+ TALER_amount_cmp (&c1->truth_upload_fee,
+ &c2->truth_upload_fee)) )
return false;
- if (json_array_size (m1) != json_array_size (m2))
+ if (c1->methods_len != c2->methods_len)
return false;
+ for (unsigned int i = 0; i < c1->methods_len; i++)
{
- size_t idx1;
- json_t *e1;
+ const struct ANASTASIS_ReduxMethodSpec *m1 = &c1->methods[i];
+ bool matched = false;
- json_array_foreach (m1, idx1, e1)
+ for (unsigned int j = 0; j < c2->methods_len; j++)
{
- const char *type1;
- struct TALER_Amount fee1;
- struct GNUNET_JSON_Specification s1[] = {
- GNUNET_JSON_spec_string ("type",
- &type1),
- TALER_JSON_spec_amount_any ("usage_fee",
- &fee1),
- GNUNET_JSON_spec_end ()
- };
- bool matched = false;
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (e1,
- s1,
- NULL, NULL))
- {
- GNUNET_break (0);
- return false;
- }
+ const struct ANASTASIS_ReduxMethodSpec *m2 = &c2->methods[j];
+
+ if ( (0 == strcmp (m1->type,
+ m2->type)) &&
+ (GNUNET_OK ==
+ TALER_amount_cmp_currency (&m1->usage_fee,
+ &m2->usage_fee)) &&
+ (0 == TALER_amount_cmp (&m1->usage_fee,
+ &m2->usage_fee)) )
{
- size_t idx2;
- json_t *e2;
-
- json_array_foreach (m2, idx2, e2)
- {
- const char *type2;
- struct TALER_Amount fee2;
- struct GNUNET_JSON_Specification s2[] = {
- GNUNET_JSON_spec_string ("type",
- &type2),
- TALER_JSON_spec_amount_any ("usage_fee",
- &fee2),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (e2,
- s2,
- NULL, NULL))
- {
- GNUNET_break (0);
- return false;
- }
- if ( (0 == strcmp (type1,
- type2)) &&
- (GNUNET_OK ==
- TALER_amount_cmp_currency (&fee1,
- &fee2)) &&
- (0 == TALER_amount_cmp (&fee1,
- &fee2)) )
- {
- matched = true;
- break;
- }
- }
+ matched = true;
+ break;
}
- if (! matched)
- return false;
}
+ if (! matched)
+ return false;
}
return true;
}
@@ -936,110 +830,48 @@ eval_provider_selection (struct PolicyBuilder *pb,
sizeof (policy_ent));
for (unsigned int i = 0; i < pb->req_methods; i++)
{
- const json_t *method_obj = json_array_get (pb->methods,
- pb->m_idx[i]);
- const json_t *provider_cfg = json_object_get (pb->providers,
- prov_sel[i]);
- const json_t *provider_methods;
- const char *method_type;
- json_t *md;
- size_t index;
+ const struct ANASTASIS_ReduxAuthMethod *am
+ = &pb->backup->authentication_methods[pb->m_idx[i]];
+ const struct ANASTASIS_ReduxProvider *p;
+ const struct ANASTASIS_ReduxProviderConfig *cfg;
bool found = false;
- uint32_t size_limit_in_mb;
- struct TALER_Amount upload_cost;
- struct GNUNET_JSON_Specification pspec[] = {
- GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
- &size_limit_in_mb),
- GNUNET_JSON_spec_array_const ("methods",
- &provider_methods),
- TALER_JSON_spec_amount_any ("truth_upload_fee",
- &upload_cost),
- GNUNET_JSON_spec_end ()
- };
- void *challenge;
- size_t challenge_size;
- struct GNUNET_JSON_Specification mspec[] = {
- GNUNET_JSON_spec_string ("type",
- &method_type),
- GNUNET_JSON_spec_varsize ("challenge",
- &challenge,
- &challenge_size),
- GNUNET_JSON_spec_end ()
- };
policy_ent[i].provider_name = prov_sel[i];
- if (GNUNET_OK !=
- GNUNET_JSON_parse (method_obj,
- mspec,
- NULL, NULL))
- {
- GNUNET_break (0);
- pb->ec = TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID;
- pb->hint = "'authentication_method' content malformed";
- goto cleanup;
- }
-
- if (MHD_HTTP_OK !=
- json_integer_value (json_object_get (provider_cfg,
- "http_status")))
- {
- GNUNET_JSON_parse_free (mspec);
- goto cleanup;
- }
- if (GNUNET_OK !=
- GNUNET_JSON_parse (provider_cfg,
- pspec,
- NULL, NULL))
+ p = ANASTASIS_REDUX_provider_find_ (pb->common,
+ prov_sel[i]);
+ if ( (NULL == p) ||
+ (! p->have_config) ||
+ (MHD_HTTP_OK != p->config.http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Skipping provider %s: no suitable configuration\n",
prov_sel[i]);
- GNUNET_JSON_parse_free (mspec);
goto cleanup;
}
- json_array_foreach (provider_methods, index, md)
+ cfg = &p->config;
+ for (unsigned int j = 0; j < cfg->methods_len; j++)
{
- const char *type;
- struct TALER_Amount method_cost;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("type",
- &type),
- TALER_JSON_spec_amount_any ("usage_fee",
- &method_cost),
- GNUNET_JSON_spec_end ()
- };
+ const struct ANASTASIS_ReduxMethodSpec *ms = &cfg->methods[j];
- if (GNUNET_OK !=
- GNUNET_JSON_parse (md,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID;
- pb->hint = "'methods' of provider";
- goto cleanup;
- }
- if ( (0 == strcmp (type,
- method_type)) &&
- (challenge_size_ok (size_limit_in_mb,
- challenge_size) ) )
+ if ( (0 == strcmp (ms->type,
+ am->type)) &&
+ (challenge_size_ok (cfg->storage_limit_in_megabytes,
+ am->challenge_size) ) )
{
found = true;
add_cost (&policy_ent[i].usage_fee,
- &method_cost);
+ &ms->usage_fee);
add_cost (&policy_ent[i].usage_fee,
- &upload_cost);
+ &cfg->truth_upload_fee);
}
}
if (! found)
{
/* Provider does not OFFER this method, combination not possible.
Cost is basically 'infinite', but we simply then skip this. */
- GNUNET_JSON_parse_free (mspec);
goto cleanup;
}
- GNUNET_JSON_parse_free (mspec);
}
/* calculate provider diversity by counting number of different
@@ -1159,40 +991,15 @@ provider_candidate (struct PolicyBuilder *pb,
const char *prov_sel[],
unsigned int i)
{
- const char *url;
- json_t *pconfig;
-
- json_object_foreach (pb->providers, url, pconfig)
+ for (unsigned int k = 0; k < pb->common->providers_len; k++)
{
- const char *status;
- uint32_t http_status = 0;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("http_status",
- &http_status),
- NULL),
- GNUNET_JSON_spec_end ()
- };
+ const struct ANASTASIS_ReduxProvider *p = &pb->common->providers[k];
- if (GNUNET_OK !=
- GNUNET_JSON_parse (pconfig,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- continue;
- }
- if ( (MHD_HTTP_OK != http_status) ||
- (0 == strcmp (status,
- "disabled")) )
- {
- GNUNET_JSON_parse_free (spec);
+ if ( (ANASTASIS_RPS_DISABLED == p->status) ||
+ (! p->have_config) ||
+ (MHD_HTTP_OK != p->config.http_status) )
continue;
- }
- GNUNET_JSON_parse_free (spec);
- prov_sel[i] = url;
+ prov_sel[i] = p->url.url;
if (i == pb->req_methods - 1)
{
eval_provider_selection (pb,
@@ -1510,8 +1317,8 @@ find_best_map (struct PolicyBuilder *pb,
/**
- * Select cheapest policy combinations and add them to the JSON ``policies``
- * array in @a pb
+ * Select cheapest policy combinations and store them in the ``policies``
+ * of the backup state @a pb builds.
*
* @param[in,out] pb policy builder with our state
*/
@@ -1545,7 +1352,11 @@ select_policies (struct PolicyBuilder *pb)
p = p->next)
{
struct PolicyMap *pm = &best[off++];
- json_t *method_arr;
+ struct ANASTASIS_ReduxPolicy pol = {
+ .methods_len = pb->req_methods,
+ .methods = GNUNET_new_array (pb->req_methods,
+ struct ANASTASIS_ReduxPolicyMethod)
+ };
#if DEBUG
fprintf (stderr,
@@ -1560,31 +1371,19 @@ select_policies (struct PolicyBuilder *pb)
}
fprintf (stderr, "\n");
#endif
- /* Convert "best" selection into 'policies' array */
- method_arr = json_array ();
- GNUNET_assert (NULL != method_arr);
+ /* Convert "best" selection into the 'policies' array */
for (unsigned int i = 0; i < pb->req_methods; i++)
{
- json_t *policy_method = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_uint64 ("authentication_method",
- p->challenges[i]),
- GNUNET_JSON_pack_string ("provider",
- pm->providers[i].provider_name));
-
- GNUNET_assert (0 ==
- json_array_append_new (method_arr,
- policy_method));
- }
- {
- json_t *policy = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal (
- "methods",
- method_arr));
-
- GNUNET_assert (0 ==
- json_array_append_new (pb->policies,
- policy));
+ struct ANASTASIS_ReduxPolicyMethod *pm2 = &pol.methods[i];
+
+ pm2->authentication_method.idx = p->challenges[i];
+ ANASTASIS_REDUX_provider_url_set_ (&pm2->provider,
+ pm->providers[i].provider_name);
}
+ GNUNET_array_append (pb->backup->policies,
+ pb->backup->policies_len,
+ pol);
+ pb->backup->have_policies = true;
}
}
}
@@ -1637,52 +1436,50 @@ clean_pb (struct PolicyBuilder *pb)
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-done_authentication (json_t *state,
+done_authentication (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
struct PolicyBuilder pb = {
- .ec = TALER_EC_NONE
+ .ec = TALER_EC_NONE,
+ .common = &rs->common,
+ .backup = b
};
- json_t *providers;
- json_t *policy_providers;
+ const json_t *providers;
- pb.providers = json_object_get (state,
- "authentication_providers");
- if ( (NULL == pb.providers) ||
- (! json_is_object (pb.providers) ) )
+ if (! rs->common.have_providers)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_providers' must be provided");
return NULL;
}
- pb.methods = json_object_get (state,
- "authentication_methods");
- if ( (NULL == pb.methods) ||
- (! json_is_array (pb.methods)) ||
- (json_array_size (pb.methods) > UINT_MAX) )
+ if (! b->have_authentication_methods)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_methods' must be provided");
return NULL;
}
- pb.num_methods
- = (unsigned int) json_array_size (pb.methods);
+ pb.num_methods = b->authentication_methods_len;
switch (pb.num_methods)
{
case 0:
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_methods' must not be empty");
return NULL;
case 1:
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"Two factor authentication (2-FA) is required");
@@ -1716,106 +1513,94 @@ done_authentication (json_t *state,
method_candidate (&pb,
0);
}
- pb.policies = json_array ();
+ /* the computed policies replace whatever was there before */
+ ANASTASIS_REDUX_policies_clear_ (b);
+ b->have_policies = true;
select_policies (&pb);
clean_pb (&pb);
if (TALER_EC_NONE != pb.ec)
{
- json_decref (pb.policies);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
pb.ec,
pb.hint);
return NULL;
}
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "policies",
- pb.policies));
+ ANASTASIS_REDUX_policy_providers_clear_ (b);
+ b->have_policy_providers = true;
providers = json_object_get (arguments,
"providers");
if (NULL == providers)
{
/* Setup a providers array from all working providers */
- json_t *available = json_object_get (state,
- "authentication_providers");
- const char *url;
- json_t *details;
-
- policy_providers = json_array ();
- GNUNET_assert (NULL != policy_providers);
- json_object_foreach (available, url, details)
+ for (unsigned int i = 0; i < rs->common.providers_len; i++)
{
- json_t *provider;
+ const char *url = rs->common.providers[i].url.url;
+ struct ANASTASIS_ReduxPolicyProvider pp = { 0 };
struct ANASTASIS_CRYPTO_ProviderSaltP salt;
if (GNUNET_OK !=
- ANASTASIS_reducer_lookup_salt (state,
- url,
- &salt))
+ ANASTASIS_REDUX_lookup_salt_ (&rs->common,
+ url,
+ &salt))
continue; /* skip providers that are down */
- provider = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("provider_url",
- url));
- GNUNET_assert (NULL != provider);
- GNUNET_assert (0 ==
- json_array_append_new (policy_providers,
- provider));
+ ANASTASIS_REDUX_provider_url_set_ (&pp.provider_url,
+ url);
+ GNUNET_array_append (b->policy_providers,
+ b->policy_providers_len,
+ pp);
}
}
else
{
- /* Setup a providers array from all working providers */
+ /* Setup a providers array from the requested providers */
size_t off;
json_t *url;
- policy_providers = json_array ();
json_array_foreach (providers, off, url)
{
- json_t *provider;
+ struct ANASTASIS_ReduxPolicyProvider pp = { 0 };
struct ANASTASIS_CRYPTO_ProviderSaltP salt;
const char *url_str;
url_str = json_string_value (url);
if ( (NULL == url_str) ||
(GNUNET_OK !=
- ANASTASIS_reducer_lookup_salt (state,
- url_str,
- &salt)) )
+ ANASTASIS_REDUX_lookup_salt_ (&rs->common,
+ url_str,
+ &salt)) )
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"unworkable provider requested");
return NULL;
}
- provider = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("provider_url",
- url_str));
- GNUNET_assert (0 ==
- json_array_append_new (policy_providers,
- provider));
+ ANASTASIS_REDUX_provider_url_set_ (&pp.provider_url,
+ url_str);
+ GNUNET_array_append (b->policy_providers,
+ b->policy_providers_len,
+ pp);
}
}
- if (0 == json_array_size (policy_providers))
+ if (0 == b->policy_providers_len)
{
- json_decref (policy_providers);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"no workable providers in state");
return NULL;
}
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "policy_providers",
- policy_providers));
- set_state (state,
+ set_state (rs,
ANASTASIS_BACKUP_STATE_POLICIES_REVIEWING);
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -1834,17 +1619,17 @@ done_authentication (json_t *state,
* @param cb_cls callback closure
*/
static struct ANASTASIS_ReduxAction *
-add_provider (json_t *state,
+add_provider (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- if (ANASTASIS_add_provider_ (state,
+ if (ANASTASIS_add_provider_ (rs,
arguments,
cb,
cb_cls))
return NULL;
- return ANASTASIS_REDUX_backup_begin_ (state,
+ return ANASTASIS_REDUX_backup_begin_ (rs,
NULL,
cb,
cb_cls);
@@ -1865,21 +1650,20 @@ add_provider (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-add_policy (json_t *state,
+add_policy (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
const json_t *arg_array;
- json_t *policies;
- const json_t *auth_providers;
- const json_t *auth_methods;
- json_t *methods;
+ struct ANASTASIS_ReduxPolicy pol = { 0 };
if (NULL == arguments)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -1890,50 +1674,45 @@ add_policy (json_t *state,
if (! json_is_array (arg_array))
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'policy' not an array");
return NULL;
}
- policies = json_object_get (state,
- "policies");
- if (! json_is_array (policies))
+ if (! b->have_policies)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'policies' not an array");
return NULL;
}
- auth_providers = json_object_get (state,
- "authentication_providers");
- if (! json_is_object (auth_providers))
+ if (! rs->common.have_providers)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'auth_providers' not an object");
return NULL;
}
- auth_methods = json_object_get (state,
- "authentication_methods");
- if (! json_is_array (auth_methods))
+ if (! b->have_authentication_methods)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'auth_methods' not an array");
return NULL;
}
- methods = json_array ();
- GNUNET_assert (NULL != methods);
-
- /* Add all methods from 'arg_array' to 'methods' */
+ /* Add all methods from 'arg_array' to the new policy */
{
size_t aindex;
json_t *method;
@@ -1943,7 +1722,8 @@ add_policy (json_t *state,
const char *provider_url;
uint32_t method_idx;
const char *method_type;
- const json_t *prov_methods;
+ const struct ANASTASIS_ReduxProvider *p;
+ const struct ANASTASIS_ReduxProviderConfig *cfg;
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("provider",
&provider_url),
@@ -1958,174 +1738,115 @@ add_policy (json_t *state,
NULL, NULL))
{
GNUNET_break (0);
- json_decref (methods);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_policy_clear_ (&pol);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'method' details malformed");
return NULL;
}
+ p = ANASTASIS_REDUX_provider_find_ (&rs->common,
+ provider_url);
+ if (NULL == p)
{
- const json_t *prov_cfg;
- uint32_t limit;
- const char *status;
- uint32_t http_status = 0;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("http_status",
- &http_status),
- NULL),
- GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
- &limit),
- GNUNET_JSON_spec_array_const ("methods",
- &prov_methods),
- GNUNET_JSON_spec_end ()
- };
-
- prov_cfg = json_object_get (auth_providers,
- provider_url);
- if (NULL == prov_cfg)
- {
- GNUNET_break (0);
- json_decref (methods);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "provider URL unknown");
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_JSON_parse (prov_cfg,
- spec,
- NULL, NULL))
- {
- /* skip provider, likely was down */
- json_decref (methods);
- continue;
- }
- if ( (MHD_HTTP_OK != http_status) ||
- (0 != strcmp (status,
- "ok")) )
- {
- /* skip provider, disabled or down */
- json_decref (methods);
- continue;
- }
+ GNUNET_break (0);
+ ANASTASIS_REDUX_policy_clear_ (&pol);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "provider URL unknown");
+ return NULL;
}
+ if ( (! p->have_config) ||
+ (ANASTASIS_RPS_OK != p->status) ||
+ (MHD_HTTP_OK != p->config.http_status) )
+ continue; /* skip provider, disabled or down */
+ cfg = &p->config;
+ if (method_idx >= b->authentication_methods_len)
{
- const json_t *auth_method;
-
- auth_method = json_array_get (auth_methods,
- method_idx);
- if (NULL == auth_method)
- {
- GNUNET_break (0);
- json_decref (methods);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "authentication method unknown");
- return NULL;
- }
- method_type = json_string_value (json_object_get (auth_method,
- "type"));
- if (NULL == method_type)
- {
- GNUNET_break (0);
- json_decref (methods);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "authentication method must be a string");
- return NULL;
- }
+ GNUNET_break (0);
+ ANASTASIS_REDUX_policy_clear_ (&pol);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "authentication method unknown");
+ return NULL;
}
+ method_type = b->authentication_methods[method_idx].type;
{
bool found = false;
- size_t mindex;
- json_t *pm;
- json_array_foreach (prov_methods, mindex, pm)
- {
- struct TALER_Amount method_cost;
- const char *type;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("type",
- &type),
- TALER_JSON_spec_amount_any ("usage_fee",
- &method_cost),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (pm,
- spec,
- NULL, NULL))
+
+ for (unsigned int j = 0; j < cfg->methods_len; j++)
+ if (0 == strcmp (cfg->methods[j].type,
+ method_type))
{
- GNUNET_break (0);
- json_decref (methods);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "provider authentication method specification invalid");
- return NULL;
+ found = true;
+ break;
}
- if (0 != strcmp (type,
- method_type))
- continue;
- found = true;
- break;
- }
if (! found)
{
GNUNET_break (0);
- json_decref (methods);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "selected provider does not support authentication method");
+ ANASTASIS_REDUX_policy_clear_ (&pol);
+ ANASTASIS_REDUX_fail_ (
+ rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "selected provider does not support authentication method");
return NULL;
}
}
- GNUNET_assert (0 ==
- json_array_append (methods,
- method));
+ {
+ struct ANASTASIS_ReduxPolicyMethod pm = {
+ .authentication_method.idx = method_idx
+ };
+
+ ANASTASIS_REDUX_provider_url_set_ (&pm.provider,
+ provider_url);
+ GNUNET_array_append (pol.methods,
+ pol.methods_len,
+ pm);
+ }
} /* end of json_array_foreach (arg_array, mindex, method) */
}
/* add new policy to array of existing policies */
{
- json_t *policy;
- json_t *idx;
+ const json_t *idx;
+ unsigned int at;
- policy = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("methods",
- methods));
idx = json_object_get (arguments,
"policy_index");
if ( (NULL == idx) ||
(! json_is_integer (idx)) )
- {
- GNUNET_assert (0 ==
- json_array_append_new (policies,
- policy));
- }
+ at = b->policies_len;
else
+ at = GNUNET_MIN ((unsigned int) json_integer_value (idx),
+ b->policies_len);
+ GNUNET_array_append (b->policies,
+ b->policies_len,
+ pol);
+ if (at != b->policies_len - 1)
{
- GNUNET_assert (0 ==
- json_array_insert_new (policies,
- json_integer_value (idx),
- policy));
+ /* shift the tail one to the right and drop the new entry in */
+ memmove (&b->policies[at + 1],
+ &b->policies[at],
+ sizeof (struct ANASTASIS_ReduxPolicy)
+ * (b->policies_len - at - 1));
+ b->policies[at] = pol;
}
}
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -2144,19 +1865,20 @@ add_policy (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-update_policy (json_t *state,
+update_policy (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
const json_t *idx;
- size_t index;
- json_t *policy_arr;
+ json_int_t index;
if (NULL == arguments)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -2167,35 +1889,42 @@ update_policy (json_t *state,
if (! json_is_integer (idx))
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'policy_index' must be an integer");
return NULL;
}
index = json_integer_value (idx);
- policy_arr = json_object_get (state,
- "policies");
- if (! json_is_array (policy_arr))
+ if (! b->have_policies)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'policies' must be an array");
return NULL;
}
- if (0 != json_array_remove (policy_arr,
- index))
+ if ( (index < 0) ||
+ (index >= (json_int_t) b->policies_len) )
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
"removal failed");
return NULL;
}
- return add_policy (state,
+ ANASTASIS_REDUX_policy_clear_ (&b->policies[index]);
+ memmove (&b->policies[index],
+ &b->policies[index + 1],
+ sizeof (struct ANASTASIS_ReduxPolicy)
+ * (b->policies_len - index - 1));
+ b->policies_len--;
+ return add_policy (rs,
arguments,
cb,
cb_cls);
@@ -2216,18 +1945,19 @@ update_policy (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-del_policy (json_t *state,
+del_policy (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
const json_t *idx;
- size_t index;
- json_t *policy_arr;
+ json_int_t index;
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -2237,35 +1967,43 @@ del_policy (json_t *state,
"policy_index");
if (! json_is_integer (idx))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'policy_index' must be an integer");
return NULL;
}
index = json_integer_value (idx);
- policy_arr = json_object_get (state,
- "policies");
- if (! json_is_array (policy_arr))
+ if (! b->have_policies)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'policies' must be an array");
return NULL;
}
- if (0 != json_array_remove (policy_arr,
- index))
+ if ( (index < 0) ||
+ (index >= (json_int_t) b->policies_len) )
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
"removal failed");
return NULL;
}
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_policy_clear_ (&b->policies[index]);
+ memmove (&b->policies[index],
+ &b->policies[index + 1],
+ sizeof (struct ANASTASIS_ReduxPolicy)
+ * (b->policies_len - index - 1));
+ b->policies_len--;
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -2284,21 +2022,21 @@ del_policy (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-del_challenge (json_t *state,
+del_challenge (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
const json_t *pidx;
const json_t *cidx;
- size_t index;
- json_t *policy_arr;
- json_t *policy;
- json_t *method_arr;
+ json_int_t index;
+ struct ANASTASIS_ReduxPolicy *policy;
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -2310,7 +2048,8 @@ del_challenge (json_t *state,
"challenge_index");
if (! json_is_integer (pidx))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'policy_index' must be an integer");
@@ -2318,56 +2057,60 @@ del_challenge (json_t *state,
}
if (! json_is_integer (cidx))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'challenge_index' must be an integer");
return NULL;
}
index = json_integer_value (pidx);
- policy_arr = json_object_get (state,
- "policies");
- if (! json_is_array (policy_arr))
+ if (! b->have_policies)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'policies' must be an array");
return NULL;
}
- policy = json_array_get (policy_arr,
- index);
- if (NULL == policy)
+ if ( (index < 0) ||
+ (index >= (json_int_t) b->policies_len) )
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'policy_index' out of range");
return NULL;
}
- method_arr = json_object_get (policy,
- "methods");
- if (NULL == method_arr)
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
- "methods missing in policy");
- return NULL;
- }
+ policy = &b->policies[index];
index = json_integer_value (cidx);
- if (0 != json_array_remove (method_arr,
- index))
+ if ( (index < 0) ||
+ (index >= (json_int_t) policy->methods_len) )
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
"removal failed");
return NULL;
}
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ {
+ struct ANASTASIS_ReduxPolicyMethod *pm = &policy->methods[index];
+
+ ANASTASIS_REDUX_provider_url_clear_ (&pm->provider);
+ if (NULL != pm->truth)
+ ANASTASIS_truth_free (pm->truth);
+ memmove (pm,
+ pm + 1,
+ sizeof (*pm) * (policy->methods_len - index - 1));
+ policy->methods_len--;
+ }
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -2408,17 +2151,15 @@ expiration_to_years (struct GNUNET_TIME_Timestamp expiration)
* #GNUNET_SYSERR if the state is invalid
*/
static enum GNUNET_GenericReturnValue
-update_expiration_cost (json_t *state,
+update_expiration_cost (struct ANASTASIS_ReduxState *rs,
struct GNUNET_TIME_Timestamp expiration)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
struct Costs *costs = NULL;
unsigned int years;
- json_t *providers;
bool is_free = true;
- providers = json_object_get (state,
- "authentication_providers");
- if (! json_is_object (providers))
+ if (! rs->common.have_providers)
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -2427,51 +2168,26 @@ update_expiration_cost (json_t *state,
years = expiration_to_years (expiration);
/* go over all providers and add up cost */
- {
- const char *url;
- json_t *provider;
-
- json_object_foreach (providers, url, provider)
+ for (unsigned int i = 0; i < rs->common.providers_len; i++)
+ {
+ const struct ANASTASIS_ReduxProvider *p = &rs->common.providers[i];
+ struct TALER_Amount fee;
+
+ if ( (ANASTASIS_RPS_OK != p->status) ||
+ (! p->have_config) ||
+ (MHD_HTTP_OK != p->config.http_status) )
+ continue; /* skip providers that are down or disabled */
+ if (0 >
+ TALER_amount_multiply (&fee,
+ &p->config.annual_fee,
+ years))
{
- struct TALER_Amount annual_fee;
- const char *status;
- uint32_t http_status = 0;
- struct GNUNET_JSON_Specification pspec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("http_status",
- &http_status),
- NULL),
- TALER_JSON_spec_amount_any ("annual_fee",
- &annual_fee),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_Amount fee;
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (provider,
- pspec,
- NULL, NULL))
- {
- /* likely down, skip */
- continue;
- }
- if ( (MHD_HTTP_OK != http_status) ||
- (0 != strcmp (status,
- "ok")) )
- continue; /* skip providers that are down or disabled */
- if (0 >
- TALER_amount_multiply (&fee,
- &annual_fee,
- years))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- add_cost (&costs,
- &fee);
+ GNUNET_break (0);
+ free_costs (costs);
+ return GNUNET_SYSERR;
}
+ add_cost (&costs,
+ &fee);
}
/* go over all truths and add up cost */
@@ -2480,44 +2196,21 @@ update_expiration_cost (json_t *state,
unsigned int len = 0;
struct AlreadySeen
{
- uint32_t method;
+ unsigned int method;
const char *provider_url;
} *seen = NULL;
- json_t *policies;
- size_t pidx;
- json_t *policy;
- policies = json_object_get (state,
- "policies");
- json_array_foreach (policies, pidx, policy)
+ for (unsigned int pidx = 0; pidx < b->policies_len; pidx++)
{
- json_t *methods;
- json_t *method;
- size_t midx;
+ const struct ANASTASIS_ReduxPolicy *policy = &b->policies[pidx];
- methods = json_object_get (policy,
- "methods");
- json_array_foreach (methods, midx, method)
+ for (unsigned int midx = 0; midx < policy->methods_len; midx++)
{
- const char *provider_url;
- uint32_t method_idx;
-
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("provider",
- &provider_url),
- GNUNET_JSON_spec_uint32 ("authentication_method",
- &method_idx),
- GNUNET_JSON_spec_end ()
- };
+ const struct ANASTASIS_ReduxPolicyMethod *pm = &policy->methods[midx];
+ const char *provider_url = pm->provider.url;
+ unsigned int method_idx = pm->authentication_method.idx;
+ const struct ANASTASIS_ReduxProvider *p;
- if (GNUNET_OK !=
- GNUNET_JSON_parse (method,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
/* check if we have seen this one before */
{
bool found = false;
@@ -2539,47 +2232,33 @@ update_expiration_cost (json_t *state,
seen[off].method = method_idx;
seen[off].provider_url = provider_url;
off++;
+ p = ANASTASIS_REDUX_provider_find_ (&rs->common,
+ provider_url);
+ if ( (NULL == p) ||
+ (! p->have_config) ||
+ (ANASTASIS_RPS_OK != p->status) ||
+ (MHD_HTTP_OK != p->config.http_status) )
+ {
+ GNUNET_break (0);
+ GNUNET_array_grow (seen,
+ len,
+ 0);
+ free_costs (costs);
+ return GNUNET_SYSERR;
+ }
{
- struct TALER_Amount upload_cost;
- const char *status;
- uint32_t http_status = 0;
- struct GNUNET_JSON_Specification pspec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("http_status",
- &http_status),
- NULL),
- TALER_JSON_spec_amount_any ("truth_upload_fee",
- &upload_cost),
- GNUNET_JSON_spec_end ()
- };
struct TALER_Amount fee;
- const json_t *provider_cfg
- = json_object_get (providers,
- provider_url);
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (provider_cfg,
- pspec,
- NULL, NULL))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if ( (MHD_HTTP_OK != http_status) ||
- (0 != strcmp (status,
- "ok")) )
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
+
if (0 >
TALER_amount_multiply (&fee,
- &upload_cost,
+ &p->config.truth_upload_fee,
years))
{
GNUNET_break (0);
+ GNUNET_array_grow (seen,
+ len,
+ 0);
+ free_costs (costs);
return GNUNET_SYSERR;
}
add_cost (&costs,
@@ -2593,50 +2272,28 @@ update_expiration_cost (json_t *state,
}
/* convert 'costs' into state */
+ GNUNET_free (b->upload_fees);
+ b->upload_fees_len = 0;
+ b->have_upload_fees = true;
+ while (NULL != costs)
{
- json_t *arr;
+ struct Costs *nxt = costs->next;
- arr = json_array ();
- GNUNET_assert (NULL != arr);
- while (NULL != costs)
+ if (! TALER_amount_is_zero (&costs->cost))
{
- struct Costs *nxt = costs->next;
-
- if (! TALER_amount_is_zero (&costs->cost))
- {
- json_t *ao;
-
- ao = GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("fee",
- &costs->cost));
- GNUNET_assert (0 ==
- json_array_append_new (arr,
- ao));
- is_free = false;
- }
- GNUNET_free (costs);
- costs = nxt;
+ GNUNET_array_append (b->upload_fees,
+ b->upload_fees_len,
+ costs->cost);
+ is_free = false;
}
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "upload_fees",
- arr));
+ GNUNET_free (costs);
+ costs = nxt;
}
if (is_free)
expiration = GNUNET_TIME_relative_to_timestamp (ANASTASIS_FREE_STORAGE);
- /* update 'expiration' in state */
- {
- json_t *eo;
-
- eo = GNUNET_JSON_from_timestamp (expiration);
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "expiration",
- eo));
- }
-
-
+ b->expiration = expiration;
+ b->have_expiration = true;
return GNUNET_OK;
}
@@ -2652,63 +2309,45 @@ update_expiration_cost (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-done_policy_review (json_t *state,
+done_policy_review (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- const json_t *policy_arr;
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
+ struct GNUNET_TIME_Timestamp exp;
- policy_arr = json_object_get (state,
- "policies");
- if (0 == json_array_size (policy_arr))
+ if (0 == b->policies_len)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
"no policies specified");
return NULL;
}
+ exp = b->have_expiration
+ ? b->expiration
+ : GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS);
+ if (GNUNET_TIME_absolute_is_zero (exp.abs_time))
+ exp = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS);
+ if (GNUNET_OK !=
+ update_expiration_cost (rs,
+ exp))
{
- struct GNUNET_TIME_Timestamp exp
- = GNUNET_TIME_UNIT_ZERO_TS;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_timestamp ("expiration",
- &exp),
- NULL),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (state,
- spec,
- NULL, NULL))
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
- "invalid expiration specified");
- return NULL;
- }
- if (GNUNET_TIME_absolute_is_zero (exp.abs_time))
- exp = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS);
- if (GNUNET_OK !=
- update_expiration_cost (state,
- exp))
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
- "could not calculate expiration cost");
- return NULL;
- }
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
+ "could not calculate expiration cost");
+ return NULL;
}
- set_state (state,
+ set_state (rs,
ANASTASIS_BACKUP_STATE_SECRET_EDITING);
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -2830,9 +2469,9 @@ struct UploadContext
void *cb_cls;
/**
- * Our state.
+ * Our state; we own it.
*/
- json_t *state;
+ struct ANASTASIS_ReduxState *rs;
/**
* Master secret sharing operation, NULL if not yet running.
@@ -2898,25 +2537,90 @@ upload_cancel_cb (void *cls)
ANASTASIS_secret_share_cancel (uc->ss);
uc->ss = NULL;
}
- json_decref (uc->state);
+ ANASTASIS_REDUX_state_free_ (uc->rs);
GNUNET_free (uc);
}
/**
- * Take all of the ongoing truth uploads and serialize them into the @a uc
- * state.
+ * Return the state of @a uc to the application and dispose of @a uc.
+ *
+ * @param[in] uc context to finish
+ * @param ec error code to report alongside the state
+ */
+static void
+uc_return (struct UploadContext *uc,
+ enum TALER_ErrorCode ec)
+{
+ struct ANASTASIS_ReduxState *rs = uc->rs;
+ ANASTASIS_ActionCallback cb = uc->cb;
+ void *cb_cls = uc->cb_cls;
+
+ uc->rs = NULL;
+ upload_cancel_cb (uc);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ ec);
+}
+
+
+/**
+ * Report an error to the application and dispose of @a uc.
+ *
+ * @param[in] uc context to finish
+ * @param ec error to report
+ * @param detail human-readable detail, may be NULL
+ */
+static void
+uc_fail (struct UploadContext *uc,
+ enum TALER_ErrorCode ec,
+ const char *detail)
+{
+ ANASTASIS_ActionCallback cb = uc->cb;
+ void *cb_cls = uc->cb_cls;
+
+ upload_cancel_cb (uc);
+ ANASTASIS_redux_fail_ (cb,
+ cb_cls,
+ ec,
+ detail);
+}
+
+
+/**
+ * Duplicate the truth @a t. Truths are shared between the policies
+ * that use them, but each `struct ANASTASIS_Truth` has a single owner,
+ * so the state gets its own copy.
+ *
+ * @param t truth to copy
+ * @return a copy of @a t
+ */
+static struct ANASTASIS_Truth *
+truth_dup (const struct ANASTASIS_Truth *t)
+{
+ json_t *jt = ANASTASIS_truth_to_json (t);
+ struct ANASTASIS_Truth *r;
+
+ GNUNET_assert (NULL != jt);
+ r = ANASTASIS_truth_from_json (jt);
+ GNUNET_assert (NULL != r);
+ json_decref (jt);
+ return r;
+}
+
+
+/**
+ * Take all of the ongoing truth uploads and store them in the @a uc
+ * state, so that they survive a round-trip through the application.
*
* @param[in,out] uc context to take truth uploads from and to update state of
*/
static void
serialize_truth (struct UploadContext *uc)
{
- json_t *policies;
+ struct ANASTASIS_ReduxBackup *b = &uc->rs->details.backup;
- policies = json_object_get (uc->state,
- "policies");
- GNUNET_assert (json_is_array (policies));
for (struct TruthUpload *tue = uc->tues_head;
NULL != tue;
tue = tue->next)
@@ -2926,26 +2630,17 @@ serialize_truth (struct UploadContext *uc)
for (unsigned int i = 0; i<tue->policies_length; i++)
{
const struct PolicyMethodReference *pmr = &tue->policies[i];
- json_t *policy = json_array_get (policies,
- pmr->policy_index);
- json_t *methods = json_object_get (policy,
- "methods");
- json_t *auth_method = json_array_get (methods,
- pmr->method_index);
- json_t *truth = ANASTASIS_truth_to_json (tue->t);
-
- GNUNET_assert (0 ==
- json_object_set_new (truth,
- "upload_status",
- json_integer (tue->us)));
- GNUNET_assert (NULL != policy);
- GNUNET_assert (NULL != methods);
- GNUNET_assert (NULL != auth_method);
- GNUNET_assert (NULL != truth);
- GNUNET_assert (0 ==
- json_object_set_new (auth_method,
- "truth",
- truth));
+ struct ANASTASIS_ReduxPolicy *policy;
+ struct ANASTASIS_ReduxPolicyMethod *pm;
+
+ GNUNET_assert (pmr->policy_index < b->policies_len);
+ policy = &b->policies[pmr->policy_index];
+ GNUNET_assert (pmr->method_index < policy->methods_len);
+ pm = &policy->methods[pmr->method_index];
+ if (NULL != pm->truth)
+ ANASTASIS_truth_free (pm->truth);
+ pm->truth = truth_dup (tue->t);
+ pm->upload_status = tue->us;
}
}
}
@@ -2962,37 +2657,19 @@ serialize_truth (struct UploadContext *uc)
* upload considerations without causing a problem
*/
static bool
-provider_required (const json_t *state,
+provider_required (const struct ANASTASIS_ReduxState *rs,
const char *provider_url)
{
- json_t *policies
- = json_object_get (state,
- "policies");
- size_t pidx;
- json_t *policy;
+ const struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
- json_array_foreach (policies, pidx, policy)
+ for (unsigned int pidx = 0; pidx < b->policies_len; pidx++)
{
- json_t *methods = json_object_get (policy,
- "methods");
- size_t midx;
- json_t *method;
-
- json_array_foreach (methods, midx, method)
- {
- const char *provider
- = json_string_value (json_object_get (method,
- "provider"));
+ const struct ANASTASIS_ReduxPolicy *policy = &b->policies[pidx];
- if (NULL == provider)
- {
- GNUNET_break (0);
- continue;
- }
- if (0 == strcmp (provider,
+ for (unsigned int midx = 0; midx < policy->methods_len; midx++)
+ if (0 == strcmp (policy->methods[midx].provider.url,
provider_url))
return true;
- }
}
return false;
}
@@ -3018,6 +2695,7 @@ secret_share_result_cb (void *cls,
const struct ANASTASIS_ShareResult *sr)
{
struct UploadContext *uc = cls;
+ struct ANASTASIS_ReduxBackup *b = &uc->rs->details.backup;
uc->ss = NULL;
switch (sr->ss)
@@ -3025,147 +2703,103 @@ secret_share_result_cb (void *cls,
case ANASTASIS_SHARE_STATUS_SUCCESS:
/* Just to be safe, delete the "core_secret" so that it is not
accidentally preserved anywhere */
- (void) json_object_del (uc->state,
- "core_secret");
+ json_decref (b->core_secret);
+ b->core_secret = NULL;
+ for (unsigned int i = 0; i < b->success_details_len; i++)
+ ANASTASIS_REDUX_provider_url_clear_ (
+ &b->success_details[i].provider_url);
+ GNUNET_free (b->success_details);
+ b->success_details_len = 0;
+ b->have_success_details = true;
+ for (unsigned int i = 0; i<sr->details.success.num_providers; i++)
{
- json_t *sa = json_object ();
+ const struct ANASTASIS_ProviderSuccessStatus *pssi
+ = &sr->details.success.pss[i];
+ struct ANASTASIS_ReduxSuccessDetail d = {
+ .policy_version = pssi->policy_version,
+ .policy_expiration = pssi->policy_expiration
+ };
- GNUNET_assert (NULL != sa);
- for (unsigned int i = 0; i<sr->details.success.num_providers; i++)
- {
- const struct ANASTASIS_ProviderSuccessStatus *pssi
- = &sr->details.success.pss[i];
- json_t *d;
-
- d = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_uint64 ("policy_version",
- pssi->policy_version),
- GNUNET_JSON_pack_timestamp ("policy_expiration",
- pssi->policy_expiration));
- GNUNET_assert (NULL != d);
- GNUNET_assert (0 ==
- json_object_set_new (sa,
- pssi->provider_url,
- d));
- }
- GNUNET_assert (0 ==
- json_object_set_new (uc->state,
- "success_details",
- sa));
+ ANASTASIS_REDUX_provider_url_set_ (&d.provider_url,
+ pssi->provider_url);
+ GNUNET_array_append (b->success_details,
+ b->success_details_len,
+ d);
}
- set_state (uc->state,
+ set_state (uc->rs,
ANASTASIS_BACKUP_STATE_BACKUP_FINISHED);
- uc->cb (uc->cb_cls,
- TALER_EC_NONE,
- uc->state);
- break;
+ uc_return (uc,
+ TALER_EC_NONE);
+ return;
case ANASTASIS_SHARE_STATUS_PAYMENT_REQUIRED:
+ set_state (uc->rs,
+ ANASTASIS_BACKUP_STATE_POLICIES_PAYING);
+ serialize_truth (uc);
+ ANASTASIS_REDUX_policy_payment_requests_clear_ (b);
+ b->have_policy_payment_requests = true;
+ for (unsigned int i = 0; i<
+ sr->details.payment_required.payment_requests_length; i++)
{
- json_t *ra;
- json_t *providers;
-
- providers = json_object_get (uc->state,
- "policy_providers");
- set_state (uc->state,
- ANASTASIS_BACKUP_STATE_POLICIES_PAYING);
- serialize_truth (uc);
- ra = json_array ();
- GNUNET_assert (NULL != ra);
- for (unsigned int i = 0; i<
- sr->details.payment_required.payment_requests_length; i++)
+ const struct ANASTASIS_SharePaymentRequest *spr;
+ struct ANASTASIS_ReduxPolicyPaymentRequest ppr = { 0 };
+
+ spr = &sr->details.payment_required.payment_requests[i];
+ ppr.payto = GNUNET_strdup (spr->payment_request_url);
+ ANASTASIS_REDUX_provider_url_set_ (&ppr.provider,
+ spr->provider_url);
+ GNUNET_array_append (b->policy_payment_requests,
+ b->policy_payment_requests_len,
+ ppr);
+ for (unsigned int off = 0; off < b->policy_providers_len; off++)
{
- const struct ANASTASIS_SharePaymentRequest *spr;
- json_t *pr;
- size_t off;
- json_t *provider;
-
- spr = &sr->details.payment_required.payment_requests[i];
- pr = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("payto",
- spr->payment_request_url),
- GNUNET_JSON_pack_string ("provider",
- spr->provider_url));
- GNUNET_assert (0 ==
- json_array_append_new (ra,
- pr));
- json_array_foreach (providers, off, provider)
- {
- const char *purl = json_string_value (json_object_get (provider,
- "provider_url")
- );
+ struct ANASTASIS_ReduxPolicyProvider *pp = &b->policy_providers[off];
- if (NULL == purl)
- {
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "policy_providers array contents are invalid");
- json_decref (ra);
- return;
- }
- if (0 == strcmp (purl,
- spr->provider_url))
- {
- json_t *psj;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Remembering payment secret for provider `%s'\n",
- spr->provider_url);
- psj = GNUNET_JSON_from_data_auto (&spr->payment_secret);
- GNUNET_assert (0 ==
- json_object_set_new (provider,
- "payment_secret",
- psj));
- }
+ if (0 == strcmp (pp->provider_url.url,
+ spr->provider_url))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Remembering payment secret for provider `%s'\n",
+ spr->provider_url);
+ pp->payment_secret = spr->payment_secret;
+ pp->have_payment_secret = true;
}
}
- GNUNET_assert (0 ==
- json_object_set_new (uc->state,
- "policy_payment_requests",
- ra));
}
- uc->cb (uc->cb_cls,
- TALER_EC_NONE,
- uc->state);
- break;
+ uc_return (uc,
+ TALER_EC_NONE);
+ return;
case ANASTASIS_SHARE_STATUS_PROVIDER_FAILED:
{
json_t *details;
+ ANASTASIS_ActionCallback cb;
+ void *cb_cls;
- if (! provider_required (uc->state,
+ if (! provider_required (uc->rs,
sr->details.provider_failure.provider_url))
{
/* try again without that provider */
- json_t *provider;
- json_t *providers;
- size_t idx;
-
- provider
- = json_object_get (
- json_object_get (uc->state,
- "authentication_providers"),
- sr->details.provider_failure.provider_url);
- GNUNET_break (0 ==
- json_object_set_new (provider,
- "status",
- json_string ("disabled")));
- providers
- = json_object_get (uc->state,
- "policy_providers");
- json_array_foreach (providers, idx, provider)
+ struct ANASTASIS_ReduxProvider *p;
+
+ p = ANASTASIS_REDUX_provider_find_ (
+ &uc->rs->common,
+ sr->details.provider_failure.provider_url);
+ if (NULL == p)
+ GNUNET_break (0);
+ else
+ p->status = ANASTASIS_RPS_DISABLED;
+ for (unsigned int idx = 0; idx < b->policy_providers_len; idx++)
{
- const char *url
- = json_string_value (json_object_get (provider,
- "provider_url"));
+ struct ANASTASIS_ReduxPolicyProvider *pp
+ = &b->policy_providers[idx];
- if ( (NULL != url) &&
- (0 == strcmp (sr->details.provider_failure.provider_url,
- url)) )
+ if (0 == strcmp (sr->details.provider_failure.provider_url,
+ pp->provider_url.url))
{
- GNUNET_break (0 ==
- json_array_remove (providers,
- idx));
+ ANASTASIS_REDUX_provider_url_clear_ (&pp->provider_url);
+ memmove (pp,
+ pp + 1,
+ sizeof (*pp) * (b->policy_providers_len - idx - 1));
+ b->policy_providers_len--;
break;
}
}
@@ -3182,21 +2816,22 @@ secret_share_result_cb (void *cls,
sr->details.provider_failure.ec)),
GNUNET_JSON_pack_string ("provider_url",
sr->details.provider_failure.provider_url));
- uc->cb (uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_BACKUP_PROVIDER_FAILED,
- details);
+ cb = uc->cb;
+ cb_cls = uc->cb_cls;
+ upload_cancel_cb (uc);
+ cb (cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_BACKUP_PROVIDER_FAILED,
+ details);
json_decref (details);
}
- break;
+ return;
default:
GNUNET_break (0);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "unexpected share result");
- break;
+ uc_fail (uc,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "unexpected share result");
+ return;
}
- upload_cancel_cb (uc);
}
@@ -3208,106 +2843,35 @@ secret_share_result_cb (void *cls,
static void
share_secret (struct UploadContext *uc)
{
- const json_t *user_id;
- const json_t *core_secret;
- const json_t *jpolicies;
- const json_t *providers = NULL;
- size_t policies_len;
- const char *secret_name = NULL;
- unsigned int pds_len;
+ struct ANASTASIS_ReduxBackup *b = &uc->rs->details.backup;
+ unsigned int policies_len = b->policies_len;
+ unsigned int pds_len = b->policy_providers_len;
struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_object_const ("identity_attributes",
- &user_id),
- GNUNET_JSON_spec_array_const ("policies",
- &jpolicies),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("policy_providers",
- &providers),
- NULL),
- GNUNET_JSON_spec_object_const ("core_secret",
- &core_secret),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("secret_name",
- &secret_name),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- if (GNUNET_OK !=
- GNUNET_JSON_parse (uc->state,
- spec,
- NULL, NULL))
+ if ( (NULL == uc->rs->common.identity_attributes) ||
+ (NULL == b->core_secret) ||
+ (! b->have_policies) )
{
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "State parsing failed when preparing to share secret");
- upload_cancel_cb (uc);
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "State parsing failed when preparing to share secret");
return;
}
-
- {
- json_t *args;
- struct GNUNET_JSON_Specification pspec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_relative_time ("timeout",
- &timeout),
- NULL),
- GNUNET_JSON_spec_end ()
- };
-
- args = json_object_get (uc->state,
- "pay_arguments");
- if ( (NULL != args) &&
- (GNUNET_OK !=
- GNUNET_JSON_parse (args,
- pspec,
- NULL, NULL)) )
- {
- json_dumpf (args,
- stderr,
- JSON_INDENT (2));
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- NULL);
- upload_cancel_cb (uc);
- return;
- }
- }
-
- policies_len = json_array_size (jpolicies);
+ if (b->have_pay_arguments &&
+ b->pay_arguments.have_timeout)
+ timeout = b->pay_arguments.timeout;
if (0 == policies_len)
{
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "State parsing failed checks when preparing to share secret");
- upload_cancel_cb (uc);
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "State parsing failed checks when preparing to share secret");
return;
}
-
- if (json_array_size (providers) > UINT_MAX)
- {
- GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "provider array excessively long");
- upload_cancel_cb (uc);
- return;
- }
- pds_len
- = (unsigned int) json_array_size (providers);
if (0 == pds_len)
{
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "no workable providers in state");
- upload_cancel_cb (uc);
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "no workable providers in state");
return;
}
@@ -3320,28 +2884,21 @@ share_secret (struct UploadContext *uc)
memset (pds,
0,
sizeof (pds));
- for (size_t i = 0; i<policies_len; i++)
+ for (unsigned int i = 0; i<policies_len; i++)
{
- const json_t *policy = json_array_get (jpolicies,
- i);
- const json_t *jmethods = json_object_get (policy,
- "methods");
- unsigned int methods_len;
-
- if ( (! json_is_array (jmethods)) ||
- (0 == json_array_size (jmethods)) ||
- (json_array_size (jmethods) > UINT_MAX) )
+ const struct ANASTASIS_ReduxPolicy *policy = &b->policies[i];
+ unsigned int methods_len = policy->methods_len;
+
+ if (0 == methods_len)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'methods' must be an array of sane length");
- upload_cancel_cb (uc);
+ for (unsigned int k = 0; k<i; k++)
+ ANASTASIS_policy_destroy (vpolicies[k]);
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'methods' must be an array of sane length");
return;
}
- methods_len
- = (unsigned int) json_array_size (jmethods);
{
struct ANASTASIS_Policy *p;
struct ANASTASIS_Truth *truths[methods_len];
@@ -3349,76 +2906,27 @@ share_secret (struct UploadContext *uc)
for (unsigned int j = 0; j<methods_len; j++)
{
- const json_t *jmethod = json_array_get (jmethods,
- j);
- const json_t *jtruth = NULL;
- uint32_t truth_index;
- const char *provider_url;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_const ("truth",
- &jtruth),
- NULL),
- GNUNET_JSON_spec_string ("provider",
- &provider_url),
- GNUNET_JSON_spec_uint32 ("authentication_method",
- &truth_index),
- GNUNET_JSON_spec_end ()
- };
-
- GNUNET_break (NULL != jmethod);
- if (GNUNET_OK !=
- GNUNET_JSON_parse (jmethod,
- ispec,
- NULL, NULL))
- {
- GNUNET_break (0);
- for (unsigned int k = 0; k<j; k++)
- ANASTASIS_truth_free (truths[k]);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'truth' failed to decode");
- upload_cancel_cb (uc);
- return;
- }
- if (NULL != jtruth)
+ const struct ANASTASIS_ReduxPolicyMethod *pm = &policy->methods[j];
+
+ if (NULL != pm->truth)
{
- /* Get truth by deserializing from state */
- truths[j] = ANASTASIS_truth_from_json (jtruth);
- if (NULL == truths[j])
- {
- GNUNET_break (0);
- for (unsigned int k = 0; k<j; k++)
- ANASTASIS_truth_free (truths[k]);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'truth' failed to decode");
- upload_cancel_cb (uc);
- return;
- }
+ /* Truth we already have in the state */
+ truths[j] = truth_dup (pm->truth);
}
else
{
bool found = false;
- /* Maybe we never serialized the truth; find it in our DLL */
+ /* Maybe we never stored the truth; find it in our DLL */
for (struct TruthUpload *tue = uc->tues_head;
NULL != tue;
tue = tue->next)
{
GNUNET_break (NULL != tue->t);
- if ( (tue->am_idx == truth_index) &&
- (0 == strcmp (provider_url,
+ if ( (tue->am_idx == pm->authentication_method.idx) &&
+ (0 == strcmp (pm->provider.url,
tue->provider_url)) )
{
- /* Duplicate truth object */
- json_t *jt = ANASTASIS_truth_to_json (tue->t);
-
- GNUNET_assert (NULL != jt);
- truths[j] = ANASTASIS_truth_from_json (jt);
- GNUNET_assert (NULL != truths[j]);
- json_decref (jt);
+ truths[j] = truth_dup (tue->t);
found = true;
break;
}
@@ -3428,11 +2936,11 @@ share_secret (struct UploadContext *uc)
GNUNET_break (0);
for (unsigned int k = 0; k<j; k++)
ANASTASIS_truth_free (truths[k]);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'truth' failed to decode");
- upload_cancel_cb (uc);
+ for (unsigned int k = 0; k<i; k++)
+ ANASTASIS_policy_destroy (vpolicies[k]);
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'truth' failed to decode");
return;
}
}
@@ -3450,35 +2958,23 @@ share_secret (struct UploadContext *uc)
/* initialize 'pds' array */
for (unsigned int i = 0; i<pds_len; i++)
{
- json_t *pdj = json_array_get (providers,
- i);
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto ("payment_secret",
- &pds[i].payment_secret),
- NULL),
- GNUNET_JSON_spec_string ("provider_url",
- &pds[i].provider_url),
- GNUNET_JSON_spec_end ()
- };
+ const struct ANASTASIS_ReduxPolicyProvider *pp
+ = &b->policy_providers[i];
- if ( (GNUNET_OK !=
- GNUNET_JSON_parse (pdj,
- ispec,
- NULL, NULL)) ||
- (GNUNET_OK !=
- ANASTASIS_reducer_lookup_salt (uc->state,
- pds[i].provider_url,
- &pds[i].provider_salt)) )
+ pds[i].provider_url = pp->provider_url.url;
+ if (pp->have_payment_secret)
+ pds[i].payment_secret = pp->payment_secret;
+ if (GNUNET_OK !=
+ ANASTASIS_REDUX_lookup_salt_ (&uc->rs->common,
+ pds[i].provider_url,
+ &pds[i].provider_salt))
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'providers' entry malformed");
for (unsigned int p = 0; p<policies_len; p++)
ANASTASIS_policy_destroy (vpolicies[p]);
- upload_cancel_cb (uc);
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'providers' entry malformed");
return;
}
}
@@ -3487,12 +2983,12 @@ share_secret (struct UploadContext *uc)
char *secret;
size_t secret_size;
- secret = json_dumps (core_secret,
+ secret = json_dumps (b->core_secret,
JSON_COMPACT | JSON_SORT_KEYS);
GNUNET_assert (NULL != secret);
secret_size = strlen (secret);
uc->ss = ANASTASIS_secret_share (ANASTASIS_REDUX_ctx_,
- user_id,
+ uc->rs->common.identity_attributes,
pds,
pds_len,
policies,
@@ -3501,7 +2997,7 @@ share_secret (struct UploadContext *uc)
timeout,
&secret_share_result_cb,
uc,
- secret_name,
+ b->secret_name,
secret,
secret_size);
GNUNET_free (secret);
@@ -3512,11 +3008,9 @@ share_secret (struct UploadContext *uc)
if (NULL == uc->ss)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (uc->cb,
- uc->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "Failed to begin secret sharing");
- upload_cancel_cb (uc);
+ uc_fail (uc,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "Failed to begin secret sharing");
return;
}
}
@@ -3531,33 +3025,28 @@ share_secret (struct UploadContext *uc)
static void
request_truth_payment (struct UploadContext *uc)
{
- json_t *payments;
+ struct ANASTASIS_ReduxBackup *b = &uc->rs->details.backup;
- payments = json_array ();
- GNUNET_assert (NULL != payments);
serialize_truth (uc);
+ ANASTASIS_REDUX_payments_clear_ (b);
+ b->have_payments = true;
for (struct TruthUpload *tue = uc->tues_head;
NULL != tue;
tue = tue->next)
{
+ char *pr;
+
if (NULL == tue->payment_request)
continue;
- GNUNET_assert (
- 0 ==
- json_array_append_new (payments,
- json_string (
- tue->payment_request)));
+ pr = GNUNET_strdup (tue->payment_request);
+ GNUNET_array_append (b->payments,
+ b->payments_len,
+ pr);
}
- GNUNET_assert (0 ==
- json_object_set_new (uc->state,
- "payments",
- payments));
- set_state (uc->state,
+ set_state (uc->rs,
ANASTASIS_BACKUP_STATE_TRUTHS_PAYING);
- uc->cb (uc->cb_cls,
- TALER_EC_NONE,
- uc->state);
- upload_cancel_cb (uc);
+ uc_return (uc,
+ TALER_EC_NONE);
}
@@ -3579,13 +3068,17 @@ check_upload_finished (struct UploadContext *uc)
{
if (TALER_EC_NONE != tue->ec)
{
+ ANASTASIS_ActionCallback cb = uc->cb;
+ void *cb_cls = uc->cb_cls;
+ enum TALER_ErrorCode ec = tue->ec;
+
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Truth upload failed with error %d\n",
- (int) tue->ec);
- uc->cb (uc->cb_cls,
- tue->ec,
- NULL);
+ (int) ec);
upload_cancel_cb (uc);
+ cb (cb_cls,
+ ec,
+ NULL);
return;
}
if (NULL != tue->tu)
@@ -3657,13 +3150,13 @@ add_truth_object (struct UploadContext *uc,
const struct PolicyMethodReference *pmr,
const char *provider_url,
uint32_t am_idx,
- json_t *truth,
+ const struct ANASTASIS_ReduxPolicyMethod *pm,
unsigned int *async_truth,
- json_t *auth_method)
+ const struct ANASTASIS_ReduxAuthMethod *auth_method)
{
/* check if we are already uploading this truth */
struct TruthUpload *tue;
- bool must_upload = true;
+ bool must_upload;
for (tue = uc->tues_head;
NULL != tue;
@@ -3696,36 +3189,10 @@ add_truth_object (struct UploadContext *uc,
tue->policies_length = 1;
}
- {
- uint32_t status = UINT32_MAX;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("upload_status",
- &status),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- if (GNUNET_OK !=
- GNUNET_JSON_parse (truth,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- must_upload = (ANASTASIS_US_SUCCESS != status);
- }
+ must_upload = (ANASTASIS_US_SUCCESS != pm->upload_status);
if (NULL == tue->t)
- {
- tue->t = ANASTASIS_truth_from_json (truth);
- if (NULL == tue->t)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- }
+ tue->t = truth_dup (pm->truth);
if ( (NULL != tue->tu) &&
(! must_upload) )
@@ -3741,58 +3208,33 @@ add_truth_object (struct UploadContext *uc,
{
struct ANASTASIS_CRYPTO_ProviderSaltP salt;
struct ANASTASIS_CRYPTO_UserIdentifierP id;
- void *truth_data;
- size_t truth_data_size;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_varsize ("challenge",
- &truth_data,
- &truth_data_size),
- GNUNET_JSON_spec_end ()
- };
if (GNUNET_OK !=
- ANASTASIS_reducer_lookup_salt (uc->state,
- provider_url,
- &salt))
+ ANASTASIS_REDUX_lookup_salt_ (&uc->rs->common,
+ provider_url,
+ &salt))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
- if (GNUNET_OK !=
- GNUNET_JSON_parse (auth_method,
- spec,
- NULL, NULL))
+ if (NULL == uc->rs->common.identity_attributes)
{
- json_dumpf (auth_method,
- stderr,
- JSON_INDENT (2));
GNUNET_break (0);
return GNUNET_SYSERR;
}
- {
- json_t *user_id;
-
- user_id = json_object_get (uc->state,
- "identity_attributes");
- if (! json_is_object (user_id))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- ANASTASIS_CRYPTO_user_identifier_derive (user_id,
- &salt,
- &id);
- }
+ ANASTASIS_CRYPTO_user_identifier_derive (
+ uc->rs->common.identity_attributes,
+ &salt,
+ &id);
tue->tu = ANASTASIS_truth_upload3 (ANASTASIS_REDUX_ctx_,
&id,
tue->t,
- truth_data,
- truth_data_size,
+ auth_method->challenge,
+ auth_method->challenge_size,
uc->years,
uc->timeout,
&truth_upload_cb,
tue);
- GNUNET_JSON_parse_free (spec);
tue->t = NULL;
(*async_truth)++;
}
@@ -3820,7 +3262,8 @@ add_truth_object (struct UploadContext *uc,
* the truth to, used to check for existing entries
* @param am_idx index of the authentication method, used to check for existing entries
* @param auth_method object with the challenge details, to generate the truth
- * @return #GNUNET_SYSERR on error requiring abort,
+ * @return #GNUNET_SYSERR on error requiring abort, in which case @a uc
+ * has already been disposed of,
* #GNUNET_NO if no new truth upload was generated (@a pmr was appended)
* #GNUNET_OK if a new truth upload was initiated
*/
@@ -3829,17 +3272,15 @@ check_truth_upload (struct UploadContext *uc,
const struct PolicyMethodReference *pmr,
const char *provider_url,
uint32_t am_idx,
- json_t *auth_method)
+ const struct ANASTASIS_ReduxAuthMethod *auth_method)
{
- json_t *user_id;
- json_t *jtruth;
+ const json_t *user_id = uc->rs->common.identity_attributes;
struct TruthUpload *tue;
- user_id = json_object_get (uc->state,
- "identity_attributes");
- if (! json_is_object (user_id))
+ if (NULL == user_id)
{
GNUNET_break (0);
+ upload_cancel_cb (uc);
return GNUNET_SYSERR;
}
@@ -3862,56 +3303,9 @@ check_truth_upload (struct UploadContext *uc,
/* need new upload */
tue = GNUNET_new (struct TruthUpload);
{
- json_t *policies = json_object_get (uc->state,
- "policies");
- json_t *policy = json_array_get (policies,
- pmr->policy_index);
- json_t *methods = json_object_get (policy,
- "methods");
- json_t *method = json_array_get (methods,
- pmr->method_index);
-
- jtruth = json_object_get (method,
- "truth");
- }
-
- {
- const char *type;
- const char *mime_type = NULL;
- const char *instructions = NULL;
- void *truth_data;
- size_t truth_data_size;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("type",
- &type),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("mime_type",
- &mime_type),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("instructions",
- &instructions),
- NULL),
- GNUNET_JSON_spec_varsize ("challenge",
- &truth_data,
- &truth_data_size),
- GNUNET_JSON_spec_end ()
- };
struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
struct ANASTASIS_CRYPTO_UserIdentifierP id;
- if (GNUNET_OK !=
- GNUNET_JSON_parse (auth_method,
- spec,
- NULL, NULL))
- {
- json_dumpf (auth_method,
- stderr,
- JSON_INDENT (2));
- GNUNET_break (0);
- GNUNET_free (tue);
- return GNUNET_SYSERR;
- }
GNUNET_CONTAINER_DLL_insert (uc->tues_head,
uc->tues_tail,
tue);
@@ -3922,87 +3316,36 @@ check_truth_upload (struct UploadContext *uc,
tue->am_idx = am_idx;
tue->policies_length = 1;
if (GNUNET_OK !=
- ANASTASIS_reducer_lookup_salt (uc->state,
- provider_url,
- &provider_salt))
+ ANASTASIS_REDUX_lookup_salt_ (&uc->rs->common,
+ provider_url,
+ &provider_salt))
{
GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
upload_cancel_cb (uc);
return GNUNET_SYSERR;
}
ANASTASIS_CRYPTO_user_identifier_derive (user_id,
&provider_salt,
&id);
- {
- struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
- struct ANASTASIS_CRYPTO_QuestionSaltP question_salt;
- struct ANASTASIS_CRYPTO_TruthKeyP truth_key;
- struct ANASTASIS_CRYPTO_KeyShareP key_share;
- struct ANASTASIS_CRYPTO_NonceP nonce;
- struct GNUNET_JSON_Specification jspec[] = {
- GNUNET_JSON_spec_fixed_auto ("salt",
- &question_salt),
- GNUNET_JSON_spec_fixed_auto ("truth_key",
- &truth_key),
- GNUNET_JSON_spec_fixed_auto ("nonce",
- &nonce),
- GNUNET_JSON_spec_fixed_auto ("uuid",
- &uuid),
- GNUNET_JSON_spec_fixed_auto ("key_share",
- &key_share),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (jtruth,
- jspec,
- NULL, NULL))
- {
- tue->tu = ANASTASIS_truth_upload (ANASTASIS_REDUX_ctx_,
- &id,
- provider_url,
- type,
- instructions,
- mime_type,
- &provider_salt,
- truth_data,
- truth_data_size,
- uc->years,
- uc->timeout,
- &truth_upload_cb,
- tue);
- }
- else
- {
- tue->tu = ANASTASIS_truth_upload2 (ANASTASIS_REDUX_ctx_,
- &id,
- provider_url,
- type,
- instructions,
- mime_type,
- &provider_salt,
- truth_data,
- truth_data_size,
- uc->years,
- uc->timeout,
- &nonce,
- &uuid,
- &question_salt,
- &truth_key,
- &key_share,
- &truth_upload_cb,
- tue);
- }
- }
+ tue->tu = ANASTASIS_truth_upload (ANASTASIS_REDUX_ctx_,
+ &id,
+ provider_url,
+ auth_method->type,
+ auth_method->instructions,
+ auth_method->mime_type,
+ &provider_salt,
+ auth_method->challenge,
+ auth_method->challenge_size,
+ uc->years,
+ uc->timeout,
+ &truth_upload_cb,
+ tue);
if (NULL == tue->tu)
{
GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
upload_cancel_cb (uc);
return GNUNET_SYSERR;
}
- GNUNET_JSON_parse_free (spec);
return GNUNET_OK;
}
}
@@ -4018,48 +3361,35 @@ check_truth_upload (struct UploadContext *uc,
* @param cb_cls callback closure
*/
static struct ANASTASIS_ReduxAction *
-upload (json_t *state,
+upload (struct ANASTASIS_ReduxState *rs,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
struct UploadContext *uc;
- json_t *auth_methods;
- json_t *policies;
- struct GNUNET_TIME_Timestamp expiration;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_timestamp ("expiration",
- &expiration),
- GNUNET_JSON_spec_end ()
- };
- if (GNUNET_OK !=
- GNUNET_JSON_parse (state,
- spec,
- NULL, NULL))
+ if (! b->have_expiration)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'expiration' missing");
return NULL;
}
- auth_methods = json_object_get (state,
- "authentication_methods");
- if ( (! json_is_array (auth_methods)) ||
- (0 == json_array_size (auth_methods)) )
+ if (0 == b->authentication_methods_len)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_methods' must be non-empty array");
return NULL;
}
- policies = json_object_get (state,
- "policies");
- if ( (! json_is_array (policies)) ||
- (0 == json_array_size (policies)) )
+ if (0 == b->policies_len)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'policies' must be non-empty array");
@@ -4071,154 +3401,83 @@ upload (json_t *state,
uc->ra.cleanup_cls = uc;
uc->cb = cb;
uc->cb_cls = cb_cls;
- uc->state = json_incref (state);
- uc->years = expiration_to_years (expiration);
-
- {
- json_t *args;
- struct GNUNET_JSON_Specification pspec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_relative_time ("timeout",
- &uc->timeout),
- NULL),
- GNUNET_JSON_spec_end ()
- };
-
- args = json_object_get (uc->state,
- "pay_arguments");
- if ( (NULL != args) &&
- (GNUNET_OK !=
- GNUNET_JSON_parse (args,
- pspec,
- NULL, NULL)) )
- {
- json_dumpf (args,
- stderr,
- JSON_INDENT (2));
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'timeout' must be valid delay");
-
- return NULL;
- }
- }
+ uc->rs = rs;
+ uc->years = expiration_to_years (b->expiration);
+ if (b->have_pay_arguments &&
+ b->pay_arguments.have_timeout)
+ uc->timeout = b->pay_arguments.timeout;
{
- json_t *policy;
- size_t pindex;
unsigned int async_truth = 0;
- json_array_foreach (policies, pindex, policy)
+ for (unsigned int pindex = 0; pindex < b->policies_len; pindex++)
{
- json_t *methods = json_object_get (policy,
- "methods");
- json_t *auth_method;
- size_t mindex;
+ const struct ANASTASIS_ReduxPolicy *policy = &b->policies[pindex];
- if ( (! json_is_array (methods)) ||
- (0 == json_array_size (policies)) )
+ if (0 == policy->methods_len)
{
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'policies' must be non-empty array");
- upload_cancel_cb (uc);
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'policies' must be non-empty array");
return NULL;
}
- json_array_foreach (methods, mindex, auth_method)
+ for (unsigned int mindex = 0; mindex < policy->methods_len; mindex++)
{
- uint32_t am_idx;
- const char *provider_url;
- json_t *truth = NULL;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("provider",
- &provider_url),
- GNUNET_JSON_spec_uint32 ("authentication_method",
- &am_idx),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_json ("truth",
- &truth),
- NULL),
- GNUNET_JSON_spec_end ()
+ const struct ANASTASIS_ReduxPolicyMethod *pm
+ = &policy->methods[mindex];
+ unsigned int am_idx = pm->authentication_method.idx;
+ struct PolicyMethodReference pmr = {
+ .policy_index = pindex,
+ .method_index = mindex
};
+ const struct ANASTASIS_ReduxAuthMethod *amj;
+ int ret;
- if (GNUNET_OK !=
- GNUNET_JSON_parse (auth_method,
- ispec,
- NULL, NULL))
+ if (am_idx >= b->authentication_methods_len)
{
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'method' data malformed");
- upload_cancel_cb (uc);
+ uc_fail (
+ uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'authentication_method' refers to invalid authorization index malformed");
return NULL;
}
+ amj = &b->authentication_methods[am_idx];
+ if (NULL == pm->truth)
{
- struct PolicyMethodReference pmr = {
- .policy_index = pindex,
- .method_index = mindex
- };
- json_t *amj;
-
- amj = json_array_get (auth_methods,
- am_idx);
- if (NULL == amj)
+ ret = check_truth_upload (uc,
+ &pmr,
+ pm->provider.url,
+ am_idx,
+ amj);
+ if (GNUNET_SYSERR == ret)
{
+ /* check_truth_upload() already disposed of @a uc */
ANASTASIS_redux_fail_ (cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'authentication_method' refers to invalid authorization index malformed");
- upload_cancel_cb (uc);
- GNUNET_JSON_parse_free (spec);
+ NULL);
return NULL;
}
- if (NULL == truth)
- {
- int ret;
-
- ret = check_truth_upload (uc,
- &pmr,
- provider_url,
- am_idx,
- amj);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_JSON_parse_free (spec);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- NULL);
- return NULL;
- }
- if (GNUNET_OK == ret)
- async_truth++;
- }
- else
+ if (GNUNET_OK == ret)
+ async_truth++;
+ }
+ else
+ {
+ ret = add_truth_object (uc,
+ &pmr,
+ pm->provider.url,
+ am_idx,
+ pm,
+ &async_truth,
+ amj);
+ if (GNUNET_SYSERR == ret)
{
- int ret;
-
- ret = add_truth_object (uc,
- &pmr,
- provider_url,
- am_idx,
- truth,
- &async_truth,
- amj);
- if (GNUNET_SYSERR == ret)
- {
- GNUNET_JSON_parse_free (spec);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- NULL);
- return NULL;
- }
+ uc_fail (uc,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ NULL);
+ return NULL;
}
}
- GNUNET_JSON_parse_free (spec);
} /* end for all methods of policy */
} /* end for all policies */
if (async_truth > 0)
@@ -4246,16 +3505,17 @@ upload (json_t *state,
* leaves 512 kb for the @a secret_size, which should be plenty (given
* that this is supposed to be for a master key, and not the actual data).
*
- * @param state our state, could be used in the future to calculate the
+ * @param rs our state, could be used in the future to calculate the
* size of the recovery document without the core secret
* @param secret_size size of the core secret
* @param min_limit_in_mb minimum upload size of all providers
*/
static bool
-core_secret_fits (const json_t *state,
+core_secret_fits (const struct ANASTASIS_ReduxState *rs,
size_t secret_size,
uint32_t min_limit_in_mb)
{
+ (void) rs;
return (min_limit_in_mb * 1024LL * 1024LL >
512LLU * 1024LLU + secret_size);
}
@@ -4264,21 +3524,17 @@ core_secret_fits (const json_t *state,
/**
* Check if the upload size limit is satisfied.
*
- * @param state our state
+ * @param rs our state
* @param jsecret the uploaded secret
* @return #GNUNET_OK if @a secret_size works for all providers,
* #GNUNET_NO if the @a secret_size is too big,
* #GNUNET_SYSERR if a provider has a limit of 0
*/
static enum GNUNET_GenericReturnValue
-check_upload_size_limit (json_t *state,
+check_upload_size_limit (const struct ANASTASIS_ReduxState *rs,
const json_t *jsecret)
{
uint32_t min_limit = UINT32_MAX;
- json_t *aps = json_object_get (state,
- "authentication_providers");
- const char *url;
- json_t *ap;
size_t secret_size;
{
@@ -4295,44 +3551,20 @@ check_upload_size_limit (json_t *state,
this is under the (simplified) assumption that we store the
recovery document at all providers; this may be changed later,
see #6760. */
- json_object_foreach (aps, url, ap)
+ for (unsigned int i = 0; i < rs->common.providers_len; i++)
{
- uint32_t limit = 0;
- const char *status;
- uint32_t http_status = 0;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("http_status",
- &http_status),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
- &limit),
- NULL),
- GNUNET_JSON_spec_end ()
- };
+ const struct ANASTASIS_ReduxProvider *p = &rs->common.providers[i];
- if (GNUNET_OK !=
- GNUNET_JSON_parse (ap,
- spec,
- NULL, NULL))
- {
- /* skip malformed provider, likely /config failed */
- GNUNET_break_op (0);
- continue;
- }
- if ( (MHD_HTTP_OK != http_status) ||
- (0 != strcmp (status,
- "ok")) )
+ if ( (ANASTASIS_RPS_OK != p->status) ||
+ (! p->have_config) ||
+ (MHD_HTTP_OK != p->config.http_status) )
continue;
- if (0 == limit)
+ if (0 == p->config.storage_limit_in_megabytes)
return GNUNET_SYSERR;
min_limit = GNUNET_MIN (min_limit,
- limit);
+ p->config.storage_limit_in_megabytes);
}
- if (! core_secret_fits (state,
+ if (! core_secret_fits (rs,
secret_size,
min_limit))
return GNUNET_NO;
@@ -4351,17 +3583,18 @@ check_upload_size_limit (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-enter_secret (json_t *state,
+enter_secret (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *jsecret;
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
+ const json_t *jsecret;
struct GNUNET_TIME_Timestamp expiration
= GNUNET_TIME_UNIT_ZERO_TS;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("secret",
- &jsecret),
+ GNUNET_JSON_spec_object_const ("secret",
+ &jsecret),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_timestamp ("expiration",
&expiration),
@@ -4371,7 +3604,8 @@ enter_secret (json_t *state,
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -4382,7 +3616,8 @@ enter_secret (json_t *state,
spec,
NULL, NULL))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'secret' argument required");
@@ -4390,50 +3625,46 @@ enter_secret (json_t *state,
}
/* check upload size limit */
+ switch (check_upload_size_limit (rs,
+ jsecret))
{
- enum GNUNET_GenericReturnValue ret;
-
- ret = check_upload_size_limit (state,
- jsecret);
- switch (ret)
- {
- case GNUNET_SYSERR:
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "provider has an upload limit of 0");
- return NULL;
- case GNUNET_NO:
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_SECRET_TOO_BIG,
- NULL);
- return NULL;
- default:
- break;
- }
+ case GNUNET_SYSERR:
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "provider has an upload limit of 0");
+ return NULL;
+ case GNUNET_NO:
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_SECRET_TOO_BIG,
+ NULL);
+ return NULL;
+ default:
+ break;
}
if (! GNUNET_TIME_absolute_is_zero (expiration.abs_time))
{
if (GNUNET_OK !=
- update_expiration_cost (state,
+ update_expiration_cost (rs,
expiration))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
"could not calculate expiration cost");
return NULL;
}
}
- GNUNET_assert (0 ==
- json_object_set (state,
- "core_secret",
- jsecret));
- cb (cb_cls,
- TALER_EC_NONE,
- state);
- GNUNET_JSON_parse_free (spec);
+ json_decref (b->core_secret);
+ b->core_secret = json_incref ((json_t *) jsecret);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -4449,24 +3680,28 @@ enter_secret (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-clear_secret (json_t *state,
+clear_secret (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- if (0 !=
- json_object_del (state,
- "core_secret"))
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
+
+ if (NULL == b->core_secret)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'core_secret' not set");
return NULL;
}
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ json_decref (b->core_secret);
+ b->core_secret = NULL;
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -4482,11 +3717,12 @@ clear_secret (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-enter_secret_name (json_t *state,
+enter_secret_name (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
const char *secret_name = NULL;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("name",
@@ -4496,7 +3732,8 @@ enter_secret_name (json_t *state,
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -4507,21 +3744,19 @@ enter_secret_name (json_t *state,
spec,
NULL, NULL))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'name' argument required");
return NULL;
}
-
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "secret_name",
- json_string (secret_name)));
- cb (cb_cls,
- TALER_EC_NONE,
- state);
- GNUNET_JSON_parse_free (spec);
+ GNUNET_free (b->secret_name);
+ b->secret_name = GNUNET_strdup (secret_name);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -4539,7 +3774,7 @@ enter_secret_name (json_t *state,
* @return NULL (synchronous operation)
*/
static struct ANASTASIS_ReduxAction *
-update_expiration (json_t *state,
+update_expiration (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
@@ -4554,7 +3789,8 @@ update_expiration (json_t *state,
if (NULL == arguments)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -4566,26 +3802,29 @@ update_expiration (json_t *state,
NULL, NULL))
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'expiration' argument required");
return NULL;
}
if (GNUNET_OK !=
- update_expiration_cost (state,
+ update_expiration_cost (rs,
expiration))
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
"could not calculate expiration cost");
return NULL;
}
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -4601,24 +3840,17 @@ update_expiration (json_t *state,
* @param cb_cls callback closure
*/
static struct ANASTASIS_ReduxAction *
-finish_secret (json_t *state,
+finish_secret (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *core_secret;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("core_secret",
- &core_secret),
- GNUNET_JSON_spec_end ()
- };
+ const struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
- if (GNUNET_OK !=
- GNUNET_JSON_parse (state,
- spec,
- NULL, NULL))
+ if (NULL == b->core_secret)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"State parsing failed: 'core_secret' is missing");
@@ -4626,64 +3858,107 @@ finish_secret (json_t *state,
}
/* check upload size limit */
+ switch (check_upload_size_limit (rs,
+ b->core_secret))
{
- enum GNUNET_GenericReturnValue ret;
-
- ret = check_upload_size_limit (state,
- core_secret);
- switch (ret)
- {
- case GNUNET_SYSERR:
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "provider has an upload limit of 0");
- GNUNET_JSON_parse_free (spec);
- return NULL;
- case GNUNET_NO:
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_SECRET_TOO_BIG,
- NULL);
- GNUNET_JSON_parse_free (spec);
- return NULL;
- default:
- break;
- }
+ case GNUNET_SYSERR:
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "provider has an upload limit of 0");
+ return NULL;
+ case GNUNET_NO:
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_SECRET_TOO_BIG,
+ NULL);
+ return NULL;
+ default:
+ break;
}
-
- GNUNET_JSON_parse_free (spec);
- return upload (state,
+ return upload (rs,
cb,
cb_cls);
}
/**
+ * Remember the arguments of a "pay" action in @a rs, so that they are
+ * still around when the upload is retried after the payment.
+ *
+ * @param[in,out] rs state to update
+ * @param arguments arguments of the action, may be NULL
+ * @param cb callback to report a failure to
+ * @param cb_cls closure for @a cb
+ * @return false if @a arguments were malformed, in which case @a cb has
+ * been invoked and @a rs freed
+ */
+static bool
+set_pay_arguments (struct ANASTASIS_ReduxState *rs,
+ const json_t *arguments,
+ ANASTASIS_ActionCallback cb,
+ void *cb_cls)
+{
+ struct ANASTASIS_ReduxBackup *b = &rs->details.backup;
+ bool no_timeout;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_relative_time ("timeout",
+ &b->pay_arguments.timeout),
+ &no_timeout),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (NULL == arguments)
+ return true;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (arguments,
+ spec,
+ NULL, NULL))
+ {
+ json_dumpf ((json_t *) arguments,
+ stderr,
+ JSON_INDENT (2));
+ GNUNET_break (0);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'timeout' must be valid delay");
+ return false;
+ }
+ b->have_pay_arguments = true;
+ b->pay_arguments.have_timeout = ! no_timeout;
+ return true;
+}
+
+
+/**
* DispatchHandler/Callback function which is called for a
* "pay" action.
* Returns an #ANASTASIS_ReduxAction as operation is async.
*
- * @param state state to operate on
+ * @param[in] rs state to operate on
* @param arguments arguments to use for operation on state
* @param cb callback to call during/after operation
* @param cb_cls callback closure
*/
static struct ANASTASIS_ReduxAction *
-pay_truths_backup (json_t *state,
+pay_truths_backup (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
/* Clear 'payments' if it exists */
- (void) json_object_del (state,
- "payments");
- if (NULL != arguments)
- GNUNET_assert (0 ==
- json_object_set (state,
- "pay_arguments",
- (json_t *) arguments));
- return upload (state,
+ ANASTASIS_REDUX_payments_clear_ (&rs->details.backup);
+ if (! set_pay_arguments (rs,
+ arguments,
+ cb,
+ cb_cls))
+ return NULL;
+ return upload (rs,
cb,
cb_cls);
}
@@ -4700,20 +3975,19 @@ pay_truths_backup (json_t *state,
* @param cb_cls callback closure
*/
static struct ANASTASIS_ReduxAction *
-pay_policies_backup (json_t *state,
+pay_policies_backup (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
/* Clear 'policy_payment_requests' if it exists */
- (void) json_object_del (state,
- "policy_payment_requests");
- if (NULL != arguments)
- GNUNET_assert (0 ==
- json_object_set (state,
- "pay_arguments",
- (json_t *) arguments));
- return upload (state,
+ ANASTASIS_REDUX_policy_payment_requests_clear_ (&rs->details.backup);
+ if (! set_pay_arguments (rs,
+ arguments,
+ cb,
+ cb_cls))
+ return NULL;
+ return upload (rs,
cb,
cb_cls);
}
@@ -4730,16 +4004,17 @@ pay_policies_backup (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-back_finished (json_t *state,
+back_finished (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- set_state (state,
+ set_state (rs,
ANASTASIS_BACKUP_STATE_SECRET_EDITING);
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -4747,20 +4022,20 @@ back_finished (json_t *state,
/**
* Signature of callback function that implements a state transition.
*
- * @param state current state
+ * @param[in] rs current state
* @param arguments arguments for the state transition
* @param cb function to call when done
* @param cb_cls closure for @a cb
*/
typedef struct ANASTASIS_ReduxAction *
-(*DispatchHandler)(json_t *state,
+(*DispatchHandler)(struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
struct ANASTASIS_ReduxAction *
-ANASTASIS_backup_action_ (json_t *state,
+ANASTASIS_backup_action_ (struct ANASTASIS_ReduxState *rs,
const char *action,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
@@ -4879,33 +4154,23 @@ ANASTASIS_backup_action_ (json_t *state,
},
{ ANASTASIS_BACKUP_STATE_INVALID, NULL, NULL }
};
- const char *s = json_string_value (json_object_get (state,
- "backup_state"));
- enum ANASTASIS_BackupState bs;
+ enum ANASTASIS_BackupState bs = rs->details.backup.state;
- GNUNET_assert (NULL != s); /* holds as per invariant of caller */
- bs = ANASTASIS_backup_state_from_string_ (s);
- if (ANASTASIS_BACKUP_STATE_INVALID == bs)
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "unknown 'backup_state'");
- return NULL;
- }
+ GNUNET_assert (ANASTASIS_RT_BACKUP == rs->type);
for (unsigned int i = 0; NULL != dispatchers[i].fun; i++)
{
if ( (bs == dispatchers[i].backup_state) &&
(0 == strcmp (action,
dispatchers[i].backup_action)) )
{
- return dispatchers[i].fun (state,
+ return dispatchers[i].fun (rs,
arguments,
cb,
cb_cls);
}
}
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
action);
@@ -4941,11 +4206,6 @@ struct BackupStartStateProviderEntry
struct BackupStartState *bss;
/**
- * Resulting provider information, NULL if not (yet) available.
- */
- json_t *istate;
-
- /**
* Ongoing reducer action to obtain /config, NULL if completed.
*/
struct ANASTASIS_ReduxAction *ra;
@@ -4970,9 +4230,10 @@ struct BackupStartState
struct BackupStartStateProviderEntry *pe_tail;
/**
- * State we are updating.
+ * State we are updating; we own it. All our entries update it in
+ * place, so there is nothing to merge once they are done.
*/
- json_t *state;
+ struct ANASTASIS_ReduxState *rs;
/**
* Function to call when we are done.
@@ -5015,117 +4276,85 @@ abort_backup_begin_cb (void *cls)
pe);
if (NULL != pe->ra)
pe->ra->cleanup (pe->ra->cleanup_cls);
- json_decref (pe->istate);
GNUNET_free (pe);
}
- json_decref (bss->state);
+ ANASTASIS_REDUX_state_free_ (bss->rs);
GNUNET_free (bss);
}
/**
- * We finished downloading /config from all providers, merge
- * into the main state, trigger the continuation and free our
- * state.
+ * We finished downloading /config from all providers, trigger the
+ * continuation and free our state.
*
- * @param[in] bss main state to merge into
+ * @param[in] bss main state to return
*/
static void
providers_complete (struct BackupStartState *bss)
{
- struct BackupStartStateProviderEntry *pe;
- json_t *tlist;
-
- tlist = json_object_get (bss->state,
- "authentication_providers");
- if (NULL == tlist)
- {
- tlist = json_object ();
- GNUNET_assert (NULL != tlist);
- GNUNET_assert (0 ==
- json_object_set_new (bss->state,
- "authentication_providers",
- tlist));
- }
- while (NULL != (pe = bss->pe_head))
- {
- json_t *provider_list;
-
- GNUNET_CONTAINER_DLL_remove (bss->pe_head,
- bss->pe_tail,
- pe);
- provider_list = json_object_get (pe->istate,
- "authentication_providers");
- /* merge provider_list into tlist (overriding existing entries) */
- if (NULL != provider_list)
- {
- const char *url;
- json_t *value;
-
- json_object_foreach (provider_list, url, value) {
- GNUNET_assert (0 ==
- json_object_set (tlist,
- url,
- value));
- }
- }
- json_decref (pe->istate);
- GNUNET_free (pe);
- }
- bss->cb (bss->cb_cls,
- TALER_EC_NONE,
- bss->state);
- json_decref (bss->state);
- GNUNET_free (bss);
+ struct ANASTASIS_ReduxState *rs = bss->rs;
+ ANASTASIS_ActionCallback cb = bss->cb;
+ void *cb_cls = bss->cb_cls;
+
+ bss->rs = NULL;
+ abort_backup_begin_cb (bss);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
}
/**
* Function called when the complete information about a provider
- * was added to @a new_state.
+ * was added to the state.
*
* @param cls a `struct BackupStartStateProviderEntry`
* @param error error code
- * @param new_state resulting new state
+ * @param rs the state, updated in place
*/
static void
provider_added_cb (void *cls,
enum TALER_ErrorCode error,
- json_t *new_state)
+ struct ANASTASIS_ReduxState *rs)
{
struct BackupStartStateProviderEntry *pe = cls;
+ struct BackupStartState *bss = pe->bss;
+ GNUNET_assert (rs == bss->rs);
+ /* our waiter unlinks and frees itself right after this call */
pe->ra = NULL;
- pe->istate = json_incref (new_state);
+ GNUNET_CONTAINER_DLL_remove (bss->pe_head,
+ bss->pe_tail,
+ pe);
pe->ec = error;
- pe->bss->pending--;
- if (0 == pe->bss->pending)
- providers_complete (pe->bss);
+ GNUNET_free (pe);
+ bss->pending--;
+ if (0 == bss->pending)
+ providers_complete (bss);
}
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_backup_begin_ (json_t *state,
+ANASTASIS_REDUX_backup_begin_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *provider_list;
struct BackupStartState *bss;
- provider_list = json_object_get (state,
- "authentication_providers");
- if (NULL == provider_list)
+ if (! rs->common.have_providers)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_providers' missing");
return NULL;
}
bss = GNUNET_new (struct BackupStartState);
- bss->state = json_incref (state);
+ bss->rs = rs;
bss->cb = cb;
bss->cb_cls = cb_cls;
bss->ra.cleanup_cls = bss;
@@ -5133,45 +4362,35 @@ ANASTASIS_REDUX_backup_begin_ (json_t *state,
bss->pending = 1; /* decremented after initialization loop */
{
- json_t *prov;
- const char *url;
- json_object_foreach (provider_list, url, prov) {
+ /* The /config replies add providers to the state, so take a
+ snapshot of the URLs to query before starting any of them. */
+ unsigned int len = rs->common.providers_len;
+ char *urls[GNUNET_NZL (len)];
+
+ for (unsigned int i = 0; i < len; i++)
+ urls[i] = (ANASTASIS_RPS_DISABLED == rs->common.providers[i].status)
+ ? NULL
+ : GNUNET_strdup (rs->common.providers[i].url.url);
+ for (unsigned int i = 0; i < len; i++)
+ {
struct BackupStartStateProviderEntry *pe;
- json_t *istate;
- const char *status;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_end ()
- };
- if (GNUNET_OK !=
- GNUNET_JSON_parse (prov,
- spec,
- NULL, NULL))
- {
- /* skip malformed provider entry */
- GNUNET_break_op (0);
- continue;
- }
- if (0 == strcmp (status,
- "disabled"))
+ if (NULL == urls[i])
continue;
pe = GNUNET_new (struct BackupStartStateProviderEntry);
pe->bss = bss;
- istate = json_object ();
- GNUNET_assert (NULL != istate);
GNUNET_CONTAINER_DLL_insert (bss->pe_head,
bss->pe_tail,
pe);
- pe->ra = ANASTASIS_REDUX_add_provider_to_state_ (url,
- istate,
+ bss->pending++;
+ pe->ra = ANASTASIS_REDUX_add_provider_to_state_ (urls[i],
+ rs,
&provider_added_cb,
pe);
- json_decref (istate);
- if (NULL != pe->ra)
- bss->pending++;
+ GNUNET_assert (NULL != pe->ra);
}
+ for (unsigned int i = 0; i < len; i++)
+ GNUNET_free (urls[i]);
}
bss->pending--;
if (0 == bss->pending)
diff --git a/src/reducer/anastasis_api_discovery.c b/src/reducer/anastasis_api_discovery.c
@@ -24,6 +24,7 @@
#include "anastasis_error_codes.h"
#include <taler/taler_json_lib.h>
#include "anastasis_api_redux.h"
+#include "anastasis_api_redux_state.h"
#include <dlfcn.h>
@@ -61,7 +62,7 @@ struct ProviderOperation
* Attribute mask applied to the identity attributes
* for this operation.
*/
- json_int_t attribute_mask;
+ struct ANASTASIS_AttributeMask attribute_mask;
};
@@ -100,16 +101,65 @@ struct ANASTASIS_PolicyDiscovery
/**
* State we are operating on.
*/
- json_t *state;
+ struct ANASTASIS_ReduxState *rs;
/**
* Number of optional fields in our identity attributes.
*/
- json_int_t opt_cnt;
+ unsigned int opt_cnt;
};
/**
+ * Return a copy of @a master_id with the optional attributes selected
+ * by @a mask removed. The internal, typed counterpart of
+ * #ANASTASIS_mask_id_data().
+ *
+ * @param common state describing which attributes exist
+ * @param master_id the user's identity attributes
+ * @param mask which of the optional attributes to drop
+ * @return NULL if @a master_id does not match @a common
+ */
+static json_t *
+mask_id_data (const struct ANASTASIS_ReduxCommon *common,
+ const json_t *master_id,
+ struct ANASTASIS_AttributeMask mask)
+{
+ json_t *ret = json_deep_copy (master_id);
+ unsigned int bit = 0;
+
+ GNUNET_assert (NULL != ret);
+ for (unsigned int i = 0; i < common->required_attributes_len; i++)
+ {
+ const struct ANASTASIS_ReduxAttributeSpec *a
+ = &common->required_attributes[i];
+ bool present;
+
+ present = (NULL !=
+ json_object_get (master_id,
+ a->name));
+ if ( (! present) && (! a->optional) )
+ {
+ GNUNET_break (0);
+ json_decref (ret);
+ return NULL;
+ }
+ if (present && a->optional)
+ {
+ if (0 != ((1LLU << bit) & mask.mask))
+ {
+ GNUNET_assert (0 ==
+ json_object_del (ret,
+ a->name));
+ }
+ bit++;
+ }
+ }
+ return ret;
+}
+
+
+/**
* Callback which passes back meta data about one of the
* recovery documents available at the provider.
*
@@ -175,7 +225,7 @@ meta_cb (void *cls,
recdoc_id,
po->provider_url,
version,
- po->attribute_mask,
+ (json_int_t) po->attribute_mask.mask,
server_time,
secret_name,
pa);
@@ -195,11 +245,10 @@ meta_cb (void *cls,
static void
start_po (struct ANASTASIS_PolicyDiscovery *pd,
const json_t *id_data,
- json_int_t mask,
+ struct ANASTASIS_AttributeMask mask,
const char *provider_url,
const json_t *cursor)
{
- const json_t *state = pd->state;
struct ProviderOperation *po;
uint32_t max_version = UINT32_MAX;
struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
@@ -236,7 +285,7 @@ start_po (struct ANASTASIS_PolicyDiscovery *pd,
JSON_INDENT (2));
return;
}
- if ( (cmask == mask) &&
+ if ( (cmask == mask.mask) &&
(0 == strcmp (url,
provider_url)) )
{
@@ -247,9 +296,9 @@ start_po (struct ANASTASIS_PolicyDiscovery *pd,
}
if (GNUNET_OK !=
- ANASTASIS_reducer_lookup_salt (state,
- provider_url,
- &provider_salt))
+ ANASTASIS_REDUX_lookup_salt_ (&pd->rs->common,
+ provider_url,
+ &provider_salt))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"No /config for `%s', skipping provider\n",
@@ -287,90 +336,61 @@ ANASTASIS_policy_discovery_start (const json_t *state,
void *cb_cls)
{
struct ANASTASIS_PolicyDiscovery *pd;
- json_t *master_id = json_object_get (state,
- "identity_attributes");
- json_t *providers = json_object_get (state,
- "authentication_providers");
- json_t *required_attributes = json_object_get (state,
- "required_attributes");
+ struct ANASTASIS_ReduxState *rs;
+ const json_t *master_id;
unsigned int opt_cnt;
- if ( (NULL == master_id) ||
- (! json_is_object (master_id)) )
{
- GNUNET_break (0);
- json_dumpf (state,
- stderr,
- JSON_INDENT (2));
- return NULL;
- }
- if ( (NULL == providers) ||
- (! json_is_object (providers)) )
- {
- GNUNET_break (0);
- json_dumpf (state,
- stderr,
- JSON_INDENT (2));
- return NULL;
+ enum TALER_ErrorCode ec;
+ const char *detail;
+
+ rs = ANASTASIS_REDUX_state_parse_ (state,
+ &ec,
+ &detail);
+ if (NULL == rs)
+ {
+ GNUNET_break (0);
+ json_dumpf ((json_t *) state,
+ stderr,
+ JSON_INDENT (2));
+ return NULL;
+ }
}
- if ( (NULL == required_attributes) ||
- (! json_is_array (required_attributes)) )
+ master_id = rs->common.identity_attributes;
+ if ( (NULL == master_id) ||
+ (! rs->common.have_providers) ||
+ (! rs->common.have_required_attributes) )
{
GNUNET_break (0);
- json_dumpf (required_attributes,
+ json_dumpf ((json_t *) state,
stderr,
JSON_INDENT (2));
+ ANASTASIS_REDUX_state_free_ (rs);
return NULL;
}
/* count optional attributes present in 'master_id' */
opt_cnt = 0;
+ for (unsigned int i = 0; i < rs->common.required_attributes_len; i++)
{
- size_t index;
- json_t *required_attribute;
+ const struct ANASTASIS_ReduxAttributeSpec *a
+ = &rs->common.required_attributes[i];
+ bool present;
- json_array_foreach (required_attributes,
- index,
- required_attribute)
+ present = (NULL !=
+ json_object_get (master_id,
+ a->name));
+ if ((! present) && (! a->optional))
{
- const char *name;
- int optional = false;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("name",
- &name),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_boolean ("optional",
- &optional),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- bool present;
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (required_attribute,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- json_dumpf (required_attribute,
- stderr,
- JSON_INDENT (2));
- return NULL;
- }
- present = (NULL !=
- json_object_get (master_id,
- name));
- if ((! present) && (! optional))
- {
- GNUNET_break (0);
- json_dumpf (master_id,
- stderr,
- JSON_INDENT (2));
- return NULL;
- }
- if (present && optional)
- opt_cnt++;
+ GNUNET_break (0);
+ json_dumpf ((json_t *) master_id,
+ stderr,
+ JSON_INDENT (2));
+ ANASTASIS_REDUX_state_free_ (rs);
+ return NULL;
}
+ if (present && a->optional)
+ opt_cnt++;
}
pd = GNUNET_new (struct ANASTASIS_PolicyDiscovery);
@@ -379,26 +399,25 @@ ANASTASIS_policy_discovery_start (const json_t *state,
pd->cb = cb;
pd->cb_cls = cb_cls;
pd->opt_cnt = opt_cnt;
- pd->state = json_deep_copy (state);
+ pd->rs = rs;
/* Compute 'id_data' for all possible masks, and then
start downloads at all providers for 'id_data' */
- for (json_int_t mask = 0; mask < (1LL << opt_cnt); mask++)
+ for (uint64_t m = 0; m < (1LLU << opt_cnt); m++)
{
- json_t *id_data = ANASTASIS_mask_id_data (state,
- master_id,
- mask);
- json_t *value;
- const char *url;
+ struct ANASTASIS_AttributeMask mask = {
+ .mask = m
+ };
+ json_t *id_data = mask_id_data (&rs->common,
+ master_id,
+ mask);
- json_object_foreach (providers, url, value)
- {
+ for (unsigned int i = 0; i < rs->common.providers_len; i++)
start_po (pd,
id_data,
mask,
- url,
+ rs->common.providers[i].url.url,
cursor);
- }
json_decref (id_data);
}
return pd;
@@ -410,24 +429,29 @@ ANASTASIS_policy_discovery_more (struct ANASTASIS_PolicyDiscovery *pd,
const char *provider_url,
json_t *provider_state)
{
- json_t *master_id = json_object_get (pd->state,
- "identity_attributes");
- json_t *providers = json_object_get (pd->state,
- "authentication_providers");
+ const json_t *master_id = pd->rs->common.identity_attributes;
+ const char *detail;
GNUNET_assert (NULL != master_id);
- GNUNET_assert (NULL != providers);
- GNUNET_assert (0 ==
- json_object_set (providers,
- provider_url,
- provider_state));
+ if (GNUNET_OK !=
+ ANASTASIS_REDUX_provider_set_ (&pd->rs->common,
+ provider_url,
+ provider_state,
+ &detail))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
/* Compute 'id_data' for all possible masks, and then
start downloads at provider for 'id_data' */
- for (json_int_t mask = 0; mask < (1LL << pd->opt_cnt); mask++)
+ for (uint64_t m = 0; m < (1LLU << pd->opt_cnt); m++)
{
- json_t *id_data = ANASTASIS_mask_id_data (pd->state,
- master_id,
- mask);
+ struct ANASTASIS_AttributeMask mask = {
+ .mask = m
+ };
+ json_t *id_data = mask_id_data (&pd->rs->common,
+ master_id,
+ mask);
start_po (pd,
id_data,
@@ -479,7 +503,7 @@ ANASTASIS_policy_discovery_stop (struct ANASTASIS_PolicyDiscovery *pd)
&free_dd_json,
NULL);
GNUNET_CONTAINER_multihashmap_destroy (pd->dd_map);
- json_decref (pd->state);
+ ANASTASIS_REDUX_state_free_ (pd->rs);
GNUNET_free (pd);
}
@@ -489,61 +513,34 @@ ANASTASIS_mask_id_data (const json_t *state,
const json_t *master_id,
json_int_t mask)
{
- json_t *required_attributes = json_object_get (state,
- "required_attributes");
- size_t index;
- json_t *required_attribute;
- json_t *ret = json_deep_copy (master_id);
- unsigned int bit = 0;
+ struct ANASTASIS_ReduxState *rs;
+ struct ANASTASIS_AttributeMask m = {
+ .mask = (uint64_t) mask
+ };
+ json_t *ret;
- if ( (NULL == required_attributes) ||
- (! json_is_array (required_attributes)) )
{
- GNUNET_break (0);
- return NULL;
- }
+ enum TALER_ErrorCode ec;
+ const char *detail;
- json_array_foreach (required_attributes, index, required_attribute)
- {
- const char *name;
- int optional = false;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("name",
- &name),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_boolean ("optional",
- &optional),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- bool present;
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (required_attribute,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- return NULL;
- }
- present = (NULL !=
- json_object_get (master_id,
- name));
- if ((! present) && (! optional))
+ rs = ANASTASIS_REDUX_state_parse_ (state,
+ &ec,
+ &detail);
+ if (NULL == rs)
{
GNUNET_break (0);
return NULL;
}
- if (present && optional)
- {
- if (0 != ((1LL << bit) & mask))
- {
- GNUNET_assert (0 ==
- json_object_del (ret,
- name));
- }
- bit++;
- }
}
+ if (! rs->common.have_required_attributes)
+ {
+ GNUNET_break (0);
+ ANASTASIS_REDUX_state_free_ (rs);
+ return NULL;
+ }
+ ret = mask_id_data (&rs->common,
+ master_id,
+ m);
+ ANASTASIS_REDUX_state_free_ (rs);
return ret;
}
diff --git a/src/reducer/anastasis_api_providers.c b/src/reducer/anastasis_api_providers.c
@@ -24,6 +24,7 @@
#include "anastasis_redux.h"
#include "anastasis_error_codes.h"
#include "anastasis_api_redux.h"
+#include "anastasis_api_redux_state.h"
/**
@@ -87,6 +88,12 @@ struct MasterSync
*/
void *cb_cls;
+ /**
+ * State all our entries share. We own it until the first entry
+ * reports back, at which point it is handed to @e cb.
+ */
+ struct ANASTASIS_ReduxState *rs;
+
};
@@ -109,121 +116,99 @@ clean_sync (void *cls)
se->ra->cleanup (se->ra->cleanup_cls);
GNUNET_free (se);
}
+ ANASTASIS_REDUX_state_free_ (ms->rs);
GNUNET_free (ms);
}
/**
* Function called when we have made progress on any of the
- * providers we are trying to sync with.
+ * providers we are trying to sync with. The first one to report wins:
+ * we return its result and drop the rest.
*
* @param cls closure
- * @param error error code, #TALER_EC_NONE if @a new_bs is the new successful state
- * @param new_state the new state of the operation (client should json_incref() to keep an alias)
+ * @param error error code, #TALER_EC_NONE if the state is the new successful state
+ * @param[in] rs the state, updated for the provider that reported
*/
static void
sync_progress (void *cls,
enum TALER_ErrorCode error,
- json_t *new_state)
+ struct ANASTASIS_ReduxState *rs)
{
struct SyncEntry *se = cls;
struct MasterSync *ms = se->ms;
+ ANASTASIS_ActionCallback cb = ms->cb;
+ void *cb_cls = ms->cb_cls;
+ GNUNET_assert (rs == ms->rs);
GNUNET_CONTAINER_DLL_remove (ms->se_head,
ms->se_tail,
se);
GNUNET_free (se);
- ms->cb (ms->cb_cls,
- error,
- new_state);
+ /* The remaining entries are cancelled below; none of them touches the
+ state once it has been unlinked, so handing it over here is safe. */
+ ms->rs = NULL;
clean_sync (ms);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ error);
}
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_sync_providers_ (json_t *state,
+ANASTASIS_REDUX_sync_providers_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *rd;
- json_t *cs_arr;
+ const struct ANASTASIS_RecoveryInformation *ri;
struct MasterSync *ms;
- rd = json_object_get (state,
- "recovery_document");
- if (NULL == rd)
+ if (NULL == rs->details.recovery.r)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'recovery_document' missing");
return NULL;
}
- cs_arr = json_object_get (rd,
- "challenges");
- if (! json_is_array (cs_arr))
- {
- GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'recovery_document' must be an array");
- return NULL;
- }
+ ri = ANASTASIS_recovery_get_info (rs->details.recovery.r);
ms = GNUNET_new (struct MasterSync);
ms->cb = cb;
ms->cb_cls = cb_cls;
+ ms->rs = rs;
+ for (unsigned int i = 0; i < ri->cs_len; i++)
{
- json_t *cs;
- unsigned int n_index;
-
- json_array_foreach (cs_arr, n_index, cs)
- {
- const char *provider_url;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("url",
- &provider_url),
- GNUNET_JSON_spec_end ()
- };
- struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
- struct SyncEntry *se;
+ const struct ANASTASIS_ChallengeDetails *cd;
+ struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
+ struct SyncEntry *se;
- if (GNUNET_OK !=
- GNUNET_JSON_parse (cs,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'recovery_document' missing");
- clean_sync (ms);
- return NULL;
- }
- if (GNUNET_OK ==
- ANASTASIS_reducer_lookup_salt (state,
- provider_url,
- &provider_salt))
- continue; /* provider already ready */
- se = GNUNET_new (struct SyncEntry);
- se->ms = ms;
- GNUNET_CONTAINER_DLL_insert (ms->se_head,
- ms->se_tail,
- se);
- se->ra = ANASTASIS_REDUX_add_provider_to_state_ (provider_url,
- state,
- &sync_progress,
- se);
- }
+ cd = ANASTASIS_challenge_get_details (ri->cs[i]);
+ if (GNUNET_OK ==
+ ANASTASIS_REDUX_lookup_salt_ (&rs->common,
+ cd->provider_url,
+ &provider_salt))
+ continue; /* provider already ready */
+ se = GNUNET_new (struct SyncEntry);
+ se->ms = ms;
+ GNUNET_CONTAINER_DLL_insert (ms->se_head,
+ ms->se_tail,
+ se);
+ se->ra = ANASTASIS_REDUX_add_provider_to_state_ (cd->provider_url,
+ rs,
+ &sync_progress,
+ se);
}
if (NULL == ms->se_head)
{
/* everything already synced */
+ ms->rs = NULL;
clean_sync (ms);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED,
"already in sync");
@@ -236,22 +221,18 @@ ANASTASIS_REDUX_sync_providers_ (json_t *state,
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_poll_providers_ (json_t *state,
+ANASTASIS_REDUX_poll_providers_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *ap;
- const char *url;
- json_t *obj;
struct MasterSync *ms;
- ap = json_object_get (state,
- "authentication_providers");
- if (NULL == ap)
+ if (! rs->common.have_providers)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_providers' missing");
@@ -260,35 +241,35 @@ ANASTASIS_REDUX_poll_providers_ (json_t *state,
ms = GNUNET_new (struct MasterSync);
ms->cb = cb;
ms->cb_cls = cb_cls;
- json_object_foreach (ap, url, obj)
+ ms->rs = rs;
+ for (unsigned int i = 0; i < rs->common.providers_len; i++)
{
+ const char *url = rs->common.providers[i].url.url;
struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
struct SyncEntry *se;
- struct ANASTASIS_ReduxAction *ra;
if (GNUNET_OK ==
- ANASTASIS_reducer_lookup_salt (state,
- url,
- &provider_salt))
+ ANASTASIS_REDUX_lookup_salt_ (&rs->common,
+ url,
+ &provider_salt))
continue;
se = GNUNET_new (struct SyncEntry);
se->ms = ms;
GNUNET_CONTAINER_DLL_insert (ms->se_head,
ms->se_tail,
se);
- ra = ANASTASIS_REDUX_add_provider_to_state_ (url,
- state,
- &sync_progress,
- se);
- if (NULL == ra)
- return NULL; /* sync_progress already called! */
- se->ra = ra;
+ se->ra = ANASTASIS_REDUX_add_provider_to_state_ (url,
+ rs,
+ &sync_progress,
+ se);
}
if (NULL == ms->se_head)
{
/* everything already synced */
+ ms->rs = NULL;
clean_sync (ms);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
"already in sync");
diff --git a/src/reducer/anastasis_api_recovery_redux.c b/src/reducer/anastasis_api_recovery_redux.c
@@ -25,6 +25,7 @@
#include "anastasis_redux.h"
#include "anastasis_error_codes.h"
#include "anastasis_api_redux.h"
+#include "anastasis_api_redux_state.h"
#define GENERATE_STRING(STRING) #STRING,
@@ -60,16 +61,18 @@ ANASTASIS_recovery_state_to_string_ (enum ANASTASIS_RecoveryState rs)
}
+/**
+ * Transition @a rs to @a new_recovery_state.
+ *
+ * @param[in,out] rs state to transition
+ * @param new_recovery_state state to transition to
+ */
static void
-set_state (json_t *state,
+set_state (struct ANASTASIS_ReduxState *rs,
enum ANASTASIS_RecoveryState new_recovery_state)
{
- GNUNET_assert (
- 0 ==
- json_object_set_new (
- state,
- "recovery_state",
- json_string (ANASTASIS_recovery_state_to_string_ (new_recovery_state))));
+ GNUNET_assert (ANASTASIS_RT_RECOVERY == rs->type);
+ rs->details.recovery.state = new_recovery_state;
}
@@ -158,8 +161,14 @@ ANASTASIS_recovery_start (const struct GNUNET_CONFIGURATION_Handle *cfg)
json_object_set_new (initial_state,
"reducer_type",
json_string ("recovery")));
- set_state (initial_state,
- ANASTASIS_RECOVERY_STATE_CONTINENT_SELECTING);
+ GNUNET_assert (
+ 0 ==
+ json_object_set_new (
+ initial_state,
+ "recovery_state",
+ json_string (
+ ANASTASIS_recovery_state_to_string_ (
+ ANASTASIS_RECOVERY_STATE_CONTINENT_SELECTING))));
return initial_state;
}
@@ -185,11 +194,6 @@ struct SelectChallengeContext
struct GNUNET_TIME_Relative timeout;
/**
- * Overall recovery action.
- */
- struct ANASTASIS_Recovery *r;
-
- /**
* Function to call with the next state.
*/
ANASTASIS_ActionCallback cb;
@@ -200,9 +204,11 @@ struct SelectChallengeContext
void *cb_cls;
/**
- * Our state.
+ * Our state; we own it. The recovery operation we drive lives in
+ * `rs->details.recovery.r`, so there is no second handle to keep in
+ * sync here.
*/
- json_t *state;
+ struct ANASTASIS_ReduxState *rs;
/**
* Our arguments (like answers to the challenge, if already provided).
@@ -241,12 +247,9 @@ sctx_free (void *cls)
{
struct SelectChallengeContext *sctx = cls;
- if (NULL != sctx->r)
- {
- ANASTASIS_recovery_abort (sctx->r);
- sctx->r = NULL;
- }
- json_decref (sctx->state);
+ /* Freeing the state also aborts the recovery operation, if one is
+ still running. */
+ ANASTASIS_REDUX_state_free_ (sctx->rs);
json_decref (sctx->args);
if (NULL != sctx->delayed_report)
{
@@ -258,72 +261,114 @@ sctx_free (void *cls)
/**
- * Call the action callback with an error result
+ * Hand our state back to the application and dispose of @a sctx.
*
- * @param cb action callback to call
- * @param cb_cls closure for @a cb
- * @param rc error code to translate to JSON
+ * @param[in] sctx context to finish
+ * @param ec error code to report alongside the state
+ */
+static void
+sctx_return (struct SelectChallengeContext *sctx,
+ enum TALER_ErrorCode ec)
+{
+ struct ANASTASIS_ReduxState *rs = sctx->rs;
+ ANASTASIS_ActionCallback cb = sctx->cb;
+ void *cb_cls = sctx->cb_cls;
+
+ sctx->rs = NULL;
+ sctx_free (sctx);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ ec);
+}
+
+
+/**
+ * Report an error to the application and dispose of @a sctx.
+ *
+ * @param[in] sctx context to finish
+ * @param ec error to report
+ * @param detail human-readable detail, may be NULL
*/
static void
-fail_by_error (ANASTASIS_ActionCallback cb,
- void *cb_cls,
- enum ANASTASIS_RecoveryStatus rc)
+sctx_fail (struct SelectChallengeContext *sctx,
+ enum TALER_ErrorCode ec,
+ const char *detail)
+{
+ ANASTASIS_ActionCallback cb = sctx->cb;
+ void *cb_cls = sctx->cb_cls;
+
+ sctx_free (sctx);
+ ANASTASIS_redux_fail_ (cb,
+ cb_cls,
+ ec,
+ detail);
+}
+
+
+/**
+ * Translate a recovery failure into an error code and message.
+ *
+ * @param rc status to translate
+ * @param[out] msg set to a human-readable, translatable message
+ * @return the error code to report
+ */
+static enum TALER_ErrorCode
+error_by_status (enum ANASTASIS_RecoveryStatus rc,
+ const char **msg)
{
- const char *msg = NULL;
enum TALER_ErrorCode ec = TALER_EC_INVALID;
+ *msg = NULL;
switch (rc)
{
case ANASTASIS_RS_SUCCESS:
GNUNET_assert (0);
break;
case ANASTASIS_RS_POLICY_DOWNLOAD_FAILED:
- msg = gettext_noop ("download failed due to unexpected network issue");
+ *msg = gettext_noop ("download failed due to unexpected network issue");
ec = TALER_EC_ANASTASIS_REDUCER_NETWORK_FAILED;
break;
case ANASTASIS_RS_POLICY_DOWNLOAD_NO_POLICY:
GNUNET_break (0);
- msg = gettext_noop ("policy document returned was malformed");
+ *msg = gettext_noop ("policy document returned was malformed");
ec = TALER_EC_ANASTASIS_REDUCER_POLICY_MALFORMED;
break;
case ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG:
GNUNET_break (0);
- msg = gettext_noop ("policy document too large for client memory");
+ *msg = gettext_noop ("policy document too large for client memory");
ec = TALER_EC_ANASTASIS_REDUCER_POLICY_MALFORMED;
break;
case ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION:
GNUNET_break (0);
- msg = gettext_noop ("failed to decompress policy document");
+ *msg = gettext_noop ("failed to decompress policy document");
ec = TALER_EC_ANASTASIS_REDUCER_POLICY_MALFORMED;
break;
case ANASTASIS_RS_POLICY_DOWNLOAD_NO_JSON:
GNUNET_break (0);
- msg = gettext_noop ("policy document returned was not in JSON format");
+ *msg = gettext_noop ("policy document returned was not in JSON format");
ec = TALER_EC_ANASTASIS_REDUCER_POLICY_MALFORMED;
break;
case ANASTASIS_RS_POLICY_MALFORMED_JSON:
GNUNET_break (0);
- msg = gettext_noop (
+ *msg = gettext_noop (
"policy document returned was not in required JSON format");
ec = TALER_EC_ANASTASIS_REDUCER_POLICY_MALFORMED;
break;
case ANASTASIS_RS_POLICY_SERVER_ERROR:
- msg = gettext_noop ("Anastasis server reported transient internal error");
+ *msg = gettext_noop ("Anastasis server reported transient internal error");
ec = TALER_EC_ANASTASIS_REDUCER_BACKUP_PROVIDER_FAILED;
break;
case ANASTASIS_RS_POLICY_GONE:
- msg = gettext_noop ("policy document no longer exists");
+ *msg = gettext_noop ("policy document no longer exists");
ec = TALER_EC_ANASTASIS_REDUCER_POLICY_LOOKUP_FAILED;
break;
case ANASTASIS_RS_POLICY_UNKNOWN:
- msg = gettext_noop ("account unknown to Anastasis server");
+ *msg = gettext_noop ("account unknown to Anastasis server");
ec = TALER_EC_ANASTASIS_REDUCER_POLICY_LOOKUP_FAILED;
break;
}
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- ec,
- msg);
+ return ec;
}
@@ -343,8 +388,10 @@ core_secret_cb (void *cls,
size_t secret_size)
{
struct SelectChallengeContext *sctx = cls;
+ struct ANASTASIS_ReduxRecovery *rr = &sctx->rs->details.recovery;
- sctx->r = NULL;
+ /* the library disposed of the operation before calling us */
+ rr->r = NULL;
if (ANASTASIS_RS_SUCCESS == rc)
{
json_t *jsecret;
@@ -355,29 +402,29 @@ core_secret_cb (void *cls,
NULL);
if (NULL == jsecret)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_SECRET_MALFORMED,
- NULL);
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_SECRET_MALFORMED,
+ NULL);
return;
}
- GNUNET_assert (0 ==
- json_object_set_new (sctx->state,
- "core_secret",
- jsecret));
- set_state (sctx->state,
+ json_decref (rr->core_secret);
+ rr->core_secret = jsecret;
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_RECOVERY_FINISHED);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
}
- fail_by_error (sctx->cb,
- sctx->cb_cls,
- rc);
- sctx_free (sctx);
+ {
+ const char *msg;
+ enum TALER_ErrorCode ec;
+
+ ec = error_by_status (rc,
+ &msg);
+ sctx_fail (sctx,
+ ec,
+ msg);
+ }
}
@@ -393,114 +440,33 @@ report_solved (void *cls)
struct SelectChallengeContext *sctx = cls;
sctx->delayed_report = NULL;
- set_state (sctx->state,
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
}
/**
- * Find challenge of @a uuid in @a state under "recovery_information".
+ * Obtain the feedback entry for challenge @a uuid, reset to a fresh
+ * variant of kind @a status.
*
- * @param state the state to search
- * @param uuid the UUID to search for
- * @return NULL on error, otherwise challenge entry; RC is NOT incremented
+ * @param[in,out] sctx context whose state to update
+ * @param uuid challenge the feedback is about
+ * @param status which variant the caller is about to fill in
+ * @return the entry to fill in
*/
-static json_t *
-find_challenge_in_ri (json_t *state,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid)
+static struct ANASTASIS_ReduxFeedback *
+set_feedback (struct SelectChallengeContext *sctx,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ enum ANASTASIS_ReduxFeedbackStatus status)
{
- struct ANASTASIS_CRYPTO_TruthUUIDP u;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("uuid",
- &u),
- GNUNET_JSON_spec_end ()
- };
- json_t *ri;
- json_t *challenges;
- json_t *challenge;
- size_t index;
+ struct ANASTASIS_ReduxFeedback *fb;
- ri = json_object_get (state,
- "recovery_information");
- if (NULL == ri)
- {
- GNUNET_break (0);
- return NULL;
- }
- challenges = json_object_get (ri,
- "challenges");
- if (NULL == challenges)
- {
- GNUNET_break (0);
- return NULL;
- }
- json_array_foreach (challenges, index, challenge)
- {
- if (GNUNET_OK !=
- GNUNET_JSON_parse (challenge,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- return NULL;
- }
- if (0 ==
- GNUNET_memcmp (&u,
- uuid))
- {
- return challenge;
- }
- }
- return NULL;
-}
-
-
-/**
- * Find challenge of @a uuid in @a state under "challenges".
- *
- * @param state the state to search
- * @param uuid the UUID to search for
- * @return NULL on error, otherwise challenge entry; RC is NOT incremented
- */
-static json_t *
-find_challenge_in_cs (json_t *state,
- const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid)
-{
- json_t *rd = json_object_get (state,
- "recovery_document");
- json_t *cs = json_object_get (rd,
- "challenges");
- json_t *c;
- size_t off;
-
- json_array_foreach (cs, off, c)
- {
- struct ANASTASIS_CRYPTO_TruthUUIDP u;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("uuid",
- &u),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (c,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- continue;
- }
- if (0 !=
- GNUNET_memcmp (uuid,
- &u))
- continue;
- return c;
- }
- return NULL;
+ fb = ANASTASIS_REDUX_feedback_get_ (&sctx->rs->details.recovery,
+ uuid);
+ fb->status = status;
+ return fb;
}
@@ -517,286 +483,142 @@ start_feedback_cb (
const struct ANASTASIS_ChallengeStartResponse *csr)
{
struct SelectChallengeContext *sctx = cls;
+ struct ANASTASIS_ReduxRecovery *rr = &sctx->rs->details.recovery;
const struct ANASTASIS_ChallengeDetails *cd;
- char uuid[sizeof (cd->uuid) * 2];
- char *end;
- json_t *feedback;
+ struct ANASTASIS_ReduxFeedback *fb;
cd = ANASTASIS_challenge_get_details (csr->challenge);
- end = GNUNET_STRINGS_data_to_string (&cd->uuid,
- sizeof (cd->uuid),
- uuid,
- sizeof (uuid));
- GNUNET_assert (NULL != end);
- *end = '\0';
- feedback = json_object_get (sctx->state,
- "challenge_feedback");
- if (NULL == feedback)
- {
- feedback = json_object ();
- GNUNET_assert (0 ==
- json_object_set_new (sctx->state,
- "challenge_feedback",
- feedback));
- }
switch (csr->cs)
{
case ANASTASIS_CHALLENGE_START_STATUS_FILENAME_PROVIDED:
- {
- json_t *instructions;
- char *hint;
-
- GNUNET_asprintf (&hint,
- _ ("Required TAN can be found in `%s'"),
- csr->details.tan_filename);
- instructions = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "code-in-file"),
- GNUNET_JSON_pack_string ("filename",
- csr->details.tan_filename),
- GNUNET_JSON_pack_string ("display_hint",
- hint));
- GNUNET_free (hint);
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- instructions));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_CODE_IN_FILE);
+ fb->details.code_in_file.filename
+ = GNUNET_strdup (csr->details.tan_filename);
+ GNUNET_asprintf (&fb->display_hint,
+ _ ("Required TAN can be found in `%s'"),
+ csr->details.tan_filename);
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
case ANASTASIS_CHALLENGE_START_STATUS_TAN_SENT_HINT_PROVIDED:
- {
- json_t *instructions;
- char *hint;
-
- GNUNET_asprintf (&hint,
- _ ("TAN code was sent to `%s'"),
- csr->details.tan_address_hint);
- instructions = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "send-to-address"),
- GNUNET_JSON_pack_string ("address_hint",
- csr->details.tan_address_hint),
- GNUNET_JSON_pack_string ("display_hint",
- hint));
- GNUNET_free (hint);
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- instructions));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_SEND_TO_ADDRESS);
+ fb->details.send_to_address.address_hint
+ = GNUNET_strdup (csr->details.tan_address_hint);
+ GNUNET_asprintf (&fb->display_hint,
+ _ ("TAN code was sent to `%s'"),
+ csr->details.tan_address_hint);
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
case ANASTASIS_CHALLENGE_START_STATUS_TAN_ALREADY_SENT:
- {
- json_t *instructions;
- char *hint;
-
- GNUNET_asprintf (&hint,
- _ ("TAN code already sent."));
- instructions = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "send-to-address"),
- GNUNET_JSON_pack_string ("display_hint",
- hint));
- GNUNET_free (hint);
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- instructions));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_SEND_TO_ADDRESS);
+ GNUNET_asprintf (&fb->display_hint,
+ _ ("TAN code already sent."));
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
case ANASTASIS_CHALLENGE_START_STATUS_PAYMENT_REQUIRED:
- {
- json_t *pay;
- char *hint;
-
- GNUNET_asprintf (&hint,
- _ ("Taler payment to `%s' required"),
- csr->details.payment_required.taler_pay_uri);
- pay = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "taler-payment"),
- GNUNET_JSON_pack_string (
- "taler_pay_uri",
- csr->details.payment_required.taler_pay_uri),
- GNUNET_JSON_pack_string ("provider",
- cd->provider_url),
- GNUNET_JSON_pack_string ("display_hint",
- hint),
- GNUNET_JSON_pack_data_auto (
- "payment_secret",
- &csr->details.payment_required.payment_secret));
- GNUNET_free (hint);
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- pay));
- }
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_TALER_PAYMENT);
+ fb->details.taler_payment.taler_pay_uri
+ = GNUNET_strdup (csr->details.payment_required.taler_pay_uri);
+ ANASTASIS_REDUX_provider_url_set_ (&fb->details.taler_payment.provider,
+ cd->provider_url);
+ fb->details.taler_payment.payment_secret
+ = csr->details.payment_required.payment_secret;
+ GNUNET_asprintf (&fb->display_hint,
+ _ ("Taler payment to `%s' required"),
+ csr->details.payment_required.taler_pay_uri);
/* Remember payment secret for later (once application claims it paid) */
{
- json_t *challenge = find_challenge_in_ri (sctx->state,
- &cd->uuid);
+ struct ANASTASIS_ReduxChallengeInfo *ci;
- GNUNET_assert (NULL != challenge);
- GNUNET_assert (0 ==
- json_object_set_new (
- challenge,
- "payment_secret",
- GNUNET_JSON_from_data_auto (
- &csr->details.payment_required.payment_secret)));
+ ci = ANASTASIS_REDUX_challenge_find_ (rr,
+ &cd->uuid);
+ GNUNET_assert (NULL != ci);
+ ci->payment_secret = csr->details.payment_required.payment_secret;
+ ci->have_payment_secret = true;
}
- set_state (sctx->state,
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
case ANASTASIS_CHALLENGE_START_STATUS_SERVER_FAILURE:
- {
- json_t *err;
-
- err = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "server-failure"),
- GNUNET_JSON_pack_uint64 ("http_status",
- csr->http_status),
- GNUNET_JSON_pack_uint64 ("error_code",
- csr->ec));
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- err));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_SERVER_FAILURE);
+ fb->details.server_failure.http_status = csr->http_status;
+ fb->details.server_failure.ec = csr->ec;
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- sctx->cb (sctx->cb_cls,
- csr->ec,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ csr->ec);
return;
case ANASTASIS_CHALLENGE_START_STATUS_TRUTH_UNKNOWN:
- {
- json_t *err;
-
- err = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "truth-unknown"),
- GNUNET_JSON_pack_uint64 ("http_status",
- csr->http_status),
- GNUNET_JSON_pack_uint64 ("error_code",
- TALER_EC_ANASTASIS_TRUTH_UNKNOWN));
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- err));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_TRUTH_UNKNOWN);
+ fb->details.server_failure.http_status = csr->http_status;
+ fb->details.server_failure.ec = TALER_EC_ANASTASIS_TRUTH_UNKNOWN;
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_ANASTASIS_TRUTH_UNKNOWN,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_ANASTASIS_TRUTH_UNKNOWN);
return;
case ANASTASIS_CHALLENGE_START_STATUS_BANK_TRANSFER_REQUIRED:
- {
- json_t *reply;
- json_t *c;
- char *hint;
-
- c = find_challenge_in_cs (sctx->state,
- &cd->uuid);
- if (NULL == c)
- {
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- NULL);
- sctx_free (sctx);
- return;
- }
- GNUNET_assert (0 ==
- json_object_set_new (c,
- "async",
- json_true ()));
- GNUNET_assert (
- 0 ==
- json_object_set_new (
- c,
- "answer-pin",
- json_integer (
- csr->details.bank_transfer_required.answer_code)));
- GNUNET_asprintf (&hint,
- _ ("Wire %s to %s (%s) with subject %s\n"),
- TALER_amount2s (
- &csr->details.bank_transfer_required.amount),
- csr->details.bank_transfer_required.target_iban,
- csr->details.bank_transfer_required.target_business_name,
- csr->details.bank_transfer_required.wire_transfer_subject
- );
- reply = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "iban-instructions"),
- GNUNET_JSON_pack_string (
- "target_iban",
- csr->details.bank_transfer_required.target_iban),
- GNUNET_JSON_pack_string (
- "display_hint",
- hint),
- GNUNET_JSON_pack_string (
- "target_business_name",
- csr->details.bank_transfer_required.target_business_name),
- GNUNET_JSON_pack_string (
- "wire_transfer_subject",
- csr->details.bank_transfer_required.wire_transfer_subject),
- TALER_JSON_pack_amount (
- "challenge_amount",
- &csr->details.bank_transfer_required.amount));
- GNUNET_free (hint);
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- reply));
- }
- GNUNET_assert (0 ==
- json_object_set_new (sctx->state,
- "selected_challenge_uuid",
- GNUNET_JSON_from_data_auto (
- &cd->uuid)));
- set_state (sctx->state,
+ /* The provider turned this into an asynchronous challenge: remember
+ the answer code so that a later "poll" can pick it up again. */
+ ANASTASIS_challenge_set_async (
+ csr->challenge,
+ csr->details.bank_transfer_required.answer_code);
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_IBAN_INSTRUCTIONS);
+ fb->details.iban_instructions.target_iban
+ = GNUNET_strdup (csr->details.bank_transfer_required.target_iban);
+ fb->details.iban_instructions.target_business_name
+ = GNUNET_strdup (
+ csr->details.bank_transfer_required.target_business_name);
+ fb->details.iban_instructions.wire_transfer_subject
+ = GNUNET_strdup (
+ csr->details.bank_transfer_required.wire_transfer_subject);
+ fb->details.iban_instructions.amount
+ = csr->details.bank_transfer_required.amount;
+ GNUNET_asprintf (&fb->display_hint,
+ _ ("Wire %s to %s (%s) with subject %s\n"),
+ TALER_amount2s (
+ &csr->details.bank_transfer_required.amount),
+ csr->details.bank_transfer_required.target_iban,
+ csr->details.bank_transfer_required.target_business_name,
+ csr->details.bank_transfer_required.wire_transfer_subject);
+ rr->selected_challenge = cd->uuid;
+ rr->have_selected_challenge = true;
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
}
GNUNET_break (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- NULL);
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ NULL);
}
@@ -813,61 +635,17 @@ answer_feedback_cb (
const struct ANASTASIS_ChallengeAnswerResponse *csr)
{
struct SelectChallengeContext *sctx = cls;
+ struct ANASTASIS_ReduxRecovery *rr = &sctx->rs->details.recovery;
const struct ANASTASIS_ChallengeDetails *cd;
- char uuid[sizeof (cd->uuid) * 2];
- char *end;
- json_t *feedback;
+ struct ANASTASIS_ReduxFeedback *fb;
cd = ANASTASIS_challenge_get_details (csr->challenge);
- end = GNUNET_STRINGS_data_to_string (&cd->uuid,
- sizeof (cd->uuid),
- uuid,
- sizeof (uuid));
- GNUNET_assert (NULL != end);
- *end = '\0';
- feedback = json_object_get (sctx->state,
- "challenge_feedback");
- if (NULL == feedback)
- {
- feedback = json_object ();
- GNUNET_assert (0 ==
- json_object_set_new (sctx->state,
- "challenge_feedback",
- feedback));
- }
switch (csr->cs)
{
case ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED:
- {
- json_t *rd;
-
- rd = ANASTASIS_recovery_serialize (sctx->r);
- if (NULL == rd)
- {
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "unable to serialize recovery state");
- sctx_free (sctx);
- return;
- }
- GNUNET_assert (0 ==
- json_object_set_new (sctx->state,
- "recovery_document",
- rd));
- }
- {
- json_t *solved;
-
- solved = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "solved"));
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- solved));
- }
+ (void) set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_SOLVED);
/* Delay reporting challenge success, as we MAY still
also see a secret recovery success (and we can only
call the callback once) */
@@ -875,168 +653,92 @@ answer_feedback_cb (
sctx);
return;
case ANASTASIS_CHALLENGE_ANSWER_STATUS_INVALID_ANSWER:
- {
- json_t *instructions;
-
- instructions = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "incorrect-answer"),
- GNUNET_JSON_pack_uint64 ("error_code",
- csr->ec));
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- instructions));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_INCORRECT_ANSWER);
+ fb->details.incorrect_answer.ec = csr->ec;
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
case ANASTASIS_CHALLENGE_ANSWER_STATUS_PAYMENT_REQUIRED:
- {
- json_t *pay;
- char *hint;
-
- GNUNET_asprintf (&hint,
- _ ("Taler payment to `%s' required"),
- csr->details.payment_required.taler_pay_uri);
- pay = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "taler-payment"),
- GNUNET_JSON_pack_string (
- "taler_pay_uri",
- csr->details.payment_required.taler_pay_uri),
- GNUNET_JSON_pack_string (
- "display_hint",
- hint),
- GNUNET_JSON_pack_string ("provider",
- cd->provider_url),
- GNUNET_JSON_pack_data_auto (
- "payment_secret",
- &csr->details.payment_required.payment_secret));
- GNUNET_free (hint);
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- pay));
- }
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_TALER_PAYMENT);
+ fb->details.taler_payment.taler_pay_uri
+ = GNUNET_strdup (csr->details.payment_required.taler_pay_uri);
+ ANASTASIS_REDUX_provider_url_set_ (&fb->details.taler_payment.provider,
+ cd->provider_url);
+ fb->details.taler_payment.payment_secret
+ = csr->details.payment_required.payment_secret;
+ GNUNET_asprintf (&fb->display_hint,
+ _ ("Taler payment to `%s' required"),
+ csr->details.payment_required.taler_pay_uri);
/* Remember payment secret for later (once application claims it paid) */
{
- json_t *challenge = find_challenge_in_ri (sctx->state,
- &cd->uuid);
+ struct ANASTASIS_ReduxChallengeInfo *ci;
- GNUNET_assert (NULL != challenge);
- GNUNET_assert (0 ==
- json_object_set_new (
- challenge,
- "payment_secret",
- GNUNET_JSON_from_data_auto (
- &csr->details.payment_required.payment_secret)));
+ ci = ANASTASIS_REDUX_challenge_find_ (rr,
+ &cd->uuid);
+ GNUNET_assert (NULL != ci);
+ ci->payment_secret = csr->details.payment_required.payment_secret;
+ ci->have_payment_secret = true;
}
- set_state (sctx->state,
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
case ANASTASIS_CHALLENGE_ANSWER_STATUS_SERVER_FAILURE:
- {
- json_t *err;
-
- err = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "server-failure"),
- GNUNET_JSON_pack_uint64 ("http_status",
- csr->http_status),
- GNUNET_JSON_pack_uint64 ("error_code",
- csr->ec));
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- err));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_SERVER_FAILURE);
+ fb->details.server_failure.http_status = csr->http_status;
+ fb->details.server_failure.ec = csr->ec;
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- sctx->cb (sctx->cb_cls,
- csr->ec,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ csr->ec);
return;
case ANASTASIS_CHALLENGE_ANSWER_STATUS_TRUTH_UNKNOWN:
- {
- json_t *err;
-
- err = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("state",
- "truth-unknown"),
- GNUNET_JSON_pack_uint64 ("http_status",
- csr->http_status),
- GNUNET_JSON_pack_uint64 ("error_code",
- TALER_EC_ANASTASIS_TRUTH_UNKNOWN));
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- err));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_TRUTH_UNKNOWN);
+ fb->details.server_failure.http_status = csr->http_status;
+ fb->details.server_failure.ec = TALER_EC_ANASTASIS_TRUTH_UNKNOWN;
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_ANASTASIS_TRUTH_UNKNOWN,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_ANASTASIS_TRUTH_UNKNOWN);
return;
case ANASTASIS_CHALLENGE_ANSWER_STATUS_RATE_LIMIT_EXCEEDED:
- {
- json_t *err;
- char *hint;
-
- GNUNET_asprintf (
- &hint,
- _ ("exceeded limit of %llu attempts in %s"),
- (unsigned long long) csr->details.rate_limit_exceeded.request_limit,
- GNUNET_TIME_relative2s (
- csr->details.rate_limit_exceeded.request_frequency,
- true));
- err = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string (
- "state",
- "rate-limit-exceeded"),
- GNUNET_JSON_pack_string (
- "display_hint",
- hint),
- GNUNET_JSON_pack_uint64 (
- "request_limit",
- csr->details.rate_limit_exceeded.request_limit),
- GNUNET_JSON_pack_time_rel (
- "request_frequency",
- csr->details.rate_limit_exceeded.request_frequency),
- GNUNET_JSON_pack_uint64 (
- "error_code",
- TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED));
- GNUNET_free (hint);
- GNUNET_assert (0 ==
- json_object_set_new (feedback,
- uuid,
- err));
- }
- set_state (sctx->state,
+ fb = set_feedback (sctx,
+ &cd->uuid,
+ ANASTASIS_RFS_RATE_LIMIT_EXCEEDED);
+ fb->details.rate_limit_exceeded.ec
+ = TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED;
+ fb->details.rate_limit_exceeded.request_limit
+ = csr->details.rate_limit_exceeded.request_limit;
+ fb->details.rate_limit_exceeded.request_frequency
+ = csr->details.rate_limit_exceeded.request_frequency;
+ GNUNET_asprintf (
+ &fb->display_hint,
+ _ ("exceeded limit of %llu attempts in %s"),
+ (unsigned long long) csr->details.rate_limit_exceeded.request_limit,
+ GNUNET_TIME_relative2s (
+ csr->details.rate_limit_exceeded.request_frequency,
+ true));
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED);
return;
}
GNUNET_break (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- NULL);
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ NULL);
}
@@ -1056,6 +758,7 @@ solve_challenge_cb (void *cls,
const struct ANASTASIS_RecoveryInformation *ri)
{
struct SelectChallengeContext *sctx = cls;
+ struct ANASTASIS_ReduxRecovery *rr = &sctx->rs->details.recovery;
const struct ANASTASIS_PaymentSecretP *psp = NULL;
struct ANASTASIS_PaymentSecretP ps;
struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO;
@@ -1071,15 +774,14 @@ solve_challenge_cb (void *cls,
&ps),
GNUNET_JSON_spec_end ()
};
+ struct ANASTASIS_ReduxChallengeInfo *sci;
if (NULL == ri)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "recovery information could not be deserialized");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "recovery information could not be deserialized");
return;
}
@@ -1090,11 +792,9 @@ solve_challenge_cb (void *cls,
NULL, NULL)) )
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'timeout' malformed");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'timeout' malformed");
return;
}
@@ -1106,51 +806,30 @@ solve_challenge_cb (void *cls,
{
struct ANASTASIS_Challenge *ci = ri->cs[i];
const struct ANASTASIS_ChallengeDetails *cd;
- json_t *challenge;
- json_t *pin;
cd = ANASTASIS_challenge_get_details (ci);
if (cd->solved ||
(! cd->async) )
continue;
-
- challenge = find_challenge_in_cs (sctx->state,
- &cd->uuid);
- if (NULL == challenge)
- {
- GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "challenge not found");
- sctx_free (sctx);
- return;
- }
- pin = json_object_get (challenge,
- "answer-pin");
- if (! json_is_integer (pin))
+ if (! cd->have_answer_pin)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "async challenge 'answer-pin' not found");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "async challenge 'answer-pin' not found");
return;
}
if (GNUNET_OK !=
ANASTASIS_challenge_answer2 (ci,
psp,
timeout,
- json_integer_value (pin),
+ cd->answer_pin,
&answer_feedback_cb,
sctx))
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "Failed to begin answering asynchronous challenge");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "Failed to begin answering asynchronous challenge");
return;
}
poll_started = true;
@@ -1173,61 +852,37 @@ solve_challenge_cb (void *cls,
} /* end resuming async challenges */
/* Check if we got a payment_secret */
+ sci = ANASTASIS_REDUX_challenge_find_ (rr,
+ &sctx->uuid);
+ if (NULL == sci)
{
- json_t *challenge;
-
- challenge = find_challenge_in_ri (sctx->state,
- &sctx->uuid);
- if (NULL == challenge)
+ GNUNET_break_op (0);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "challenge not found");
+ return;
+ }
+ if (NULL !=
+ json_object_get (sctx->args,
+ "payment_secret"))
+ {
+ /* check if we got payment secret in args */
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (sctx->args,
+ pspec,
+ NULL, NULL))
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "challenge not found");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'payment_secret' malformed");
return;
}
-
- if (NULL !=
- json_object_get (sctx->args,
- "payment_secret"))
- {
- /* check if we got payment secret in args */
- if (GNUNET_OK !=
- GNUNET_JSON_parse (sctx->args,
- pspec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'payment_secret' malformed");
- sctx_free (sctx);
- return;
- }
- psp = &ps;
- }
- else if (NULL !=
- json_object_get (challenge,
- "payment_secret"))
- {
- if (GNUNET_OK !=
- GNUNET_JSON_parse (challenge,
- pspec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'payment_secret' malformed");
- sctx_free (sctx);
- return;
- }
- psp = &ps;
- }
+ psp = &ps;
+ }
+ else if (sci->have_payment_secret)
+ {
+ psp = &sci->payment_secret;
}
/* start or solve selected challenge */
@@ -1236,7 +891,6 @@ solve_challenge_cb (void *cls,
struct ANASTASIS_Challenge *ci = ri->cs[i];
const struct ANASTASIS_ChallengeDetails *cd;
int ret;
- json_t *c;
cd = ANASTASIS_challenge_get_details (ci);
if (cd->async)
@@ -1247,38 +901,28 @@ solve_challenge_cb (void *cls,
continue;
if (cd->solved)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "Selected challenge already solved");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "Selected challenge already solved");
return;
}
- c = find_challenge_in_cs (sctx->state,
- &cd->uuid);
- GNUNET_assert (NULL != c);
if (0 == strcmp ("question",
cd->type))
{
/* security question, answer must be a string */
- json_t *janswer = json_object_get (sctx->args,
- "answer");
- const char *answer = json_string_value (janswer);
+ const char *answer = json_string_value (json_object_get (sctx->args,
+ "answer"));
if (NULL == answer)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'answer' missing");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'answer' missing");
return;
}
/* persist answer, in case payment is required */
- GNUNET_assert (0 ==
- json_object_set (c,
- "answer",
- janswer));
+ GNUNET_free (sci->answer);
+ sci->answer = GNUNET_strdup (answer);
ret = ANASTASIS_challenge_answer (ci,
psp,
timeout,
@@ -1299,10 +943,8 @@ solve_challenge_cb (void *cls,
/* persist answer, in case async processing
happens via poll */
- GNUNET_assert (0 ==
- json_object_set (c,
- "answer-pin",
- pin));
+ ANASTASIS_challenge_set_answer_pin (ci,
+ ianswer);
ret = ANASTASIS_challenge_answer2 (ci,
psp,
timeout,
@@ -1324,11 +966,9 @@ solve_challenge_cb (void *cls,
spec,
NULL, NULL))
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'answer' malformed");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'answer' malformed");
return;
}
ret = ANASTASIS_challenge_answer3 (ci,
@@ -1349,20 +989,16 @@ solve_challenge_cb (void *cls,
}
if (GNUNET_OK != ret)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "Failed to begin answering challenge");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "Failed to begin answering challenge");
return;
}
return; /* await answer feedback */
}
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'uuid' not in list of challenges");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'uuid' not in list of challenges");
}
@@ -1382,37 +1018,31 @@ pay_challenge_cb (void *cls,
const struct ANASTASIS_RecoveryInformation *ri)
{
struct SelectChallengeContext *sctx = cls;
- json_t *challenge;
+ struct ANASTASIS_ReduxRecovery *rr = &sctx->rs->details.recovery;
+ struct ANASTASIS_ReduxChallengeInfo *sci;
if (NULL == ri)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "recovery information could not be deserialized");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "recovery information could not be deserialized");
return;
}
- challenge = find_challenge_in_ri (sctx->state,
- &sctx->uuid);
- if (NULL == challenge)
+ sci = ANASTASIS_REDUX_challenge_find_ (rr,
+ &sctx->uuid);
+ if (NULL == sci)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "challenge not found");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "challenge not found");
return;
}
/* persist payment, in case we need to run the request again */
- GNUNET_assert (
- 0 ==
- json_object_set_new (challenge,
- "payment_secret",
- GNUNET_JSON_from_data_auto (&sctx->ps)));
+ sci->payment_secret = sctx->ps;
+ sci->have_payment_secret = true;
for (unsigned int i = 0; i<ri->cs_len; i++)
{
@@ -1427,11 +1057,9 @@ pay_challenge_cb (void *cls,
continue;
if (cd->solved)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "Selected challenge already solved");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "Selected challenge already solved");
return;
}
@@ -1439,23 +1067,17 @@ pay_challenge_cb (void *cls,
cd->type))
{
/* security question, answer must be a string and already ready */
- json_t *janswer = json_object_get (challenge,
- "answer");
- const char *answer = json_string_value (janswer);
-
- if (NULL == answer)
+ if (NULL == sci->answer)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'answer' missing");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'answer' missing");
return;
}
ret = ANASTASIS_challenge_answer (ci,
&sctx->ps,
sctx->timeout,
- answer,
+ sci->answer,
&answer_feedback_cb,
sctx);
}
@@ -1468,20 +1090,16 @@ pay_challenge_cb (void *cls,
}
if (GNUNET_OK != ret)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "Failed to begin answering challenge");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "Failed to begin answering challenge");
return;
}
return; /* await answer feedback */
}
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'uuid' not in list of challenges");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'uuid' not in list of challenges");
}
@@ -1496,77 +1114,59 @@ pay_challenge_cb (void *cls,
* @return handle to cancel challenge selection step
*/
static struct ANASTASIS_ReduxAction *
-solve_challenge (json_t *state,
+solve_challenge (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- struct SelectChallengeContext *sctx
- = GNUNET_new (struct SelectChallengeContext);
- json_t *rd;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("selected_challenge_uuid",
- &sctx->uuid),
- GNUNET_JSON_spec_end ()
- };
+ struct ANASTASIS_ReduxRecovery *rr = &rs->details.recovery;
+ struct SelectChallengeContext *sctx;
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
return NULL;
}
- if (GNUNET_OK !=
- GNUNET_JSON_parse (state,
- spec,
- NULL, NULL))
+ if (! rr->have_selected_challenge)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'selected_challenge_uuid' missing");
return NULL;
}
- rd = json_object_get (state,
- "recovery_document");
- if (NULL == rd)
+ if (NULL == rr->r)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"solve_challenge");
return NULL;
}
+ sctx = GNUNET_new (struct SelectChallengeContext);
+ sctx->uuid = rr->selected_challenge;
sctx->cb = cb;
sctx->cb_cls = cb_cls;
- sctx->state = json_incref (state);
+ sctx->rs = rs;
sctx->args = json_incref ((json_t*) arguments);
- sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_,
- rd);
- if ( (NULL != sctx->r) &&
- (GNUNET_OK !=
- ANASTASIS_recovery_resume (sctx->r,
- &solve_challenge_cb,
- sctx,
- &core_secret_cb,
- sctx)) )
- {
- ANASTASIS_recovery_abort (sctx->r);
- sctx->r = NULL;
- }
- if (NULL == sctx->r)
+ if (GNUNET_OK !=
+ ANASTASIS_recovery_resume (rr->r,
+ &solve_challenge_cb,
+ sctx,
+ &core_secret_cb,
+ sctx))
{
- json_decref (sctx->state);
- json_decref (sctx->args);
- GNUNET_free (sctx);
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'recovery_document' invalid");
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'recovery_document' invalid");
return NULL;
}
sctx->ra.cleanup = &sctx_free;
@@ -1587,54 +1187,41 @@ solve_challenge (json_t *state,
* @return handle to cancel challenge selection step
*/
static struct ANASTASIS_ReduxAction *
-poll_challenges (json_t *state,
+poll_challenges (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- struct SelectChallengeContext *sctx
- = GNUNET_new (struct SelectChallengeContext);
- json_t *rd;
+ struct ANASTASIS_ReduxRecovery *rr = &rs->details.recovery;
+ struct SelectChallengeContext *sctx;
- rd = json_object_get (state,
- "recovery_document");
- if (NULL == rd)
+ if (NULL == rr->r)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"poll_challenges");
return NULL;
}
+ sctx = GNUNET_new (struct SelectChallengeContext);
sctx->poll_only = true;
sctx->cb = cb;
sctx->cb_cls = cb_cls;
- sctx->state = json_incref (state);
+ sctx->rs = rs;
sctx->args = json_incref ((json_t*) arguments);
- sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_,
- rd);
- if ( (NULL != sctx->r) &&
- (GNUNET_OK !=
- ANASTASIS_recovery_resume (sctx->r,
- &solve_challenge_cb,
- sctx,
- &core_secret_cb,
- sctx)) )
- {
- ANASTASIS_recovery_abort (sctx->r);
- sctx->r = NULL;
- }
- if (NULL == sctx->r)
+ if (GNUNET_OK !=
+ ANASTASIS_recovery_resume (rr->r,
+ &solve_challenge_cb,
+ sctx,
+ &core_secret_cb,
+ sctx))
{
- json_decref (sctx->state);
- json_decref (sctx->args);
- GNUNET_free (sctx);
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'recovery_document' invalid");
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'recovery_document' invalid");
return NULL;
}
sctx->ra.cleanup = &sctx_free;
@@ -1654,33 +1241,29 @@ poll_challenges (json_t *state,
* @return handle to cancel challenge selection step
*/
static struct ANASTASIS_ReduxAction *
-pay_challenge (json_t *state,
+pay_challenge (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- struct SelectChallengeContext *sctx
- = GNUNET_new (struct SelectChallengeContext);
- json_t *rd;
+ struct ANASTASIS_ReduxRecovery *rr = &rs->details.recovery;
+ struct SelectChallengeContext *sctx;
struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("selected_challenge_uuid",
- &sctx->uuid),
- GNUNET_JSON_spec_end ()
- };
+ struct ANASTASIS_PaymentSecretP ps;
struct GNUNET_JSON_Specification aspec[] = {
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_relative_time ("timeout",
&timeout),
NULL),
GNUNET_JSON_spec_fixed_auto ("payment_secret",
- &sctx->ps),
+ &ps),
GNUNET_JSON_spec_end ()
};
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -1691,62 +1274,51 @@ pay_challenge (json_t *state,
aspec,
NULL, NULL))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'payment_secret' missing");
return NULL;
}
- if (GNUNET_OK !=
- GNUNET_JSON_parse (state,
- spec,
- NULL, NULL))
+ if (! rr->have_selected_challenge)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'selected_challenge_uuid' missing");
return NULL;
}
- rd = json_object_get (state,
- "recovery_document");
- if (NULL == rd)
+ if (NULL == rr->r)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"pay_challenge");
return NULL;
}
+ sctx = GNUNET_new (struct SelectChallengeContext);
+ sctx->uuid = rr->selected_challenge;
+ sctx->ps = ps;
sctx->timeout = timeout;
sctx->cb = cb;
sctx->cb_cls = cb_cls;
- sctx->state = json_incref (state);
+ sctx->rs = rs;
sctx->args = json_incref ((json_t*) arguments);
- sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_,
- rd);
- if ( (NULL != sctx->r) &&
- (GNUNET_OK !=
- ANASTASIS_recovery_resume (sctx->r,
- &pay_challenge_cb,
- sctx,
- &core_secret_cb,
- sctx)) )
- {
- ANASTASIS_recovery_abort (sctx->r);
- sctx->r = NULL;
- }
- if (NULL == sctx->r)
+ if (GNUNET_OK !=
+ ANASTASIS_recovery_resume (rr->r,
+ &pay_challenge_cb,
+ sctx,
+ &core_secret_cb,
+ sctx))
{
- json_decref (sctx->state);
- json_decref (sctx->args);
- GNUNET_free (sctx);
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'recovery_document' invalid");
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'recovery_document' invalid");
return NULL;
}
sctx->ra.cleanup = &sctx_free;
@@ -1771,6 +1343,7 @@ select_challenge_cb (void *cls,
const struct ANASTASIS_RecoveryInformation *ri)
{
struct SelectChallengeContext *sctx = cls;
+ struct ANASTASIS_ReduxRecovery *rr = &sctx->rs->details.recovery;
const struct ANASTASIS_PaymentSecretP *psp = NULL;
struct ANASTASIS_PaymentSecretP ps;
struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO;
@@ -1787,15 +1360,12 @@ select_challenge_cb (void *cls,
GNUNET_JSON_spec_end ()
};
-
if (NULL == ri)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "recovery information could not be deserialized");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "recovery information could not be deserialized");
return;
}
@@ -1805,11 +1375,9 @@ select_challenge_cb (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'timeout' malformed");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'timeout' malformed");
return;
}
@@ -1825,11 +1393,9 @@ select_challenge_cb (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'payment_secret' malformed");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'payment_secret' malformed");
return;
}
psp = &ps;
@@ -1837,36 +1403,21 @@ select_challenge_cb (void *cls,
else
{
/* Check if we got a payment_secret in state */
- json_t *challenge = find_challenge_in_ri (sctx->state,
- &sctx->uuid);
+ const struct ANASTASIS_ReduxChallengeInfo *sci;
- if (NULL == challenge)
+ sci = ANASTASIS_REDUX_challenge_find_ (rr,
+ &sctx->uuid);
+ if (NULL == sci)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "challenge not found");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "challenge not found");
return;
}
- if (NULL !=
- json_object_get (challenge,
- "payment_secret"))
+ if (sci->have_payment_secret)
{
- if (GNUNET_OK !=
- GNUNET_JSON_parse (challenge,
- pspec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'payment_secret' malformed");
- sctx_free (sctx);
- return;
- }
+ ps = sci->payment_secret;
psp = &ps;
}
}
@@ -1884,18 +1435,13 @@ select_challenge_cb (void *cls,
continue;
if (cd->solved)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "Selected challenge already solved");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "Selected challenge already solved");
return;
}
- GNUNET_assert (
- 0 ==
- json_object_set_new (sctx->state,
- "selected_challenge_uuid",
- GNUNET_JSON_from_data_auto (&cd->uuid)));
+ rr->selected_challenge = cd->uuid;
+ rr->have_selected_challenge = true;
if ( (0 == strcmp ("question",
cd->type)) ||
(0 == strcmp ("totp",
@@ -1903,56 +1449,37 @@ select_challenge_cb (void *cls,
{
/* security question or TOTP:
immediately request user to answer it */
- set_state (sctx->state,
+ set_state (sctx->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING);
- sctx->cb (sctx->cb_cls,
- TALER_EC_NONE,
- sctx->state);
- sctx_free (sctx);
+ sctx_return (sctx,
+ TALER_EC_NONE);
return;
}
/* trigger challenge */
- {
- json_t *c = find_challenge_in_cs (sctx->state,
- &cd->uuid);
- json_t *pin = json_object_get (c,
- "answer-pin");
-
- if (NULL != pin)
- {
- uint64_t ianswer = json_integer_value (pin);
-
- ret = ANASTASIS_challenge_answer2 (ci,
- psp,
- timeout,
- ianswer,
- &answer_feedback_cb,
- sctx);
- }
- else
- {
- ret = ANASTASIS_challenge_start (ci,
+ if (cd->have_answer_pin)
+ ret = ANASTASIS_challenge_answer2 (ci,
psp,
- &start_feedback_cb,
+ timeout,
+ cd->answer_pin,
+ &answer_feedback_cb,
sctx);
- }
- }
+ else
+ ret = ANASTASIS_challenge_start (ci,
+ psp,
+ &start_feedback_cb,
+ sctx);
if (GNUNET_OK != ret)
{
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "Failed to begin answering challenge");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "Failed to begin answering challenge");
return;
}
return; /* await answer feedback */
}
- ANASTASIS_redux_fail_ (sctx->cb,
- sctx->cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
- "'uuid' not in list of challenges");
- sctx_free (sctx);
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ "'uuid' not in list of challenges");
}
@@ -1967,23 +1494,24 @@ select_challenge_cb (void *cls,
* @return handle to cancel challenge selection step
*/
static struct ANASTASIS_ReduxAction *
-select_challenge (json_t *state,
+select_challenge (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- struct SelectChallengeContext *sctx
- = GNUNET_new (struct SelectChallengeContext);
- json_t *rd;
+ struct ANASTASIS_ReduxRecovery *rr = &rs->details.recovery;
+ struct SelectChallengeContext *sctx;
+ struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("uuid",
- &sctx->uuid),
+ &uuid),
GNUNET_JSON_spec_end ()
};
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -1994,50 +1522,40 @@ select_challenge (json_t *state,
spec,
NULL, NULL))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'uuid' missing");
return NULL;
}
- rd = json_object_get (state,
- "recovery_document");
- if (NULL == rd)
+ if (NULL == rr->r)
{
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"select_challenge");
return NULL;
}
+ sctx = GNUNET_new (struct SelectChallengeContext);
+ sctx->uuid = uuid;
sctx->cb = cb;
sctx->cb_cls = cb_cls;
- sctx->state = json_incref (state);
+ sctx->rs = rs;
sctx->args = json_incref ((json_t*) arguments);
- sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_,
- rd);
- if ( (NULL != sctx->r) &&
- (GNUNET_OK !=
- ANASTASIS_recovery_resume (sctx->r,
- &select_challenge_cb,
- sctx,
- &core_secret_cb,
- sctx)) )
- {
- ANASTASIS_recovery_abort (sctx->r);
- sctx->r = NULL;
- }
- if (NULL == sctx->r)
+ if (GNUNET_OK !=
+ ANASTASIS_recovery_resume (rr->r,
+ &select_challenge_cb,
+ sctx,
+ &core_secret_cb,
+ sctx))
{
- json_decref (sctx->state);
- json_decref (sctx->args);
- GNUNET_free (sctx);
GNUNET_break_op (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'recovery_document' invalid");
+ sctx_fail (sctx,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "'recovery_document' invalid");
return NULL;
}
sctx->ra.cleanup = &sctx_free;
@@ -2057,20 +1575,19 @@ select_challenge (json_t *state,
* @return NULL (synchronous operation)
*/
static struct ANASTASIS_ReduxAction *
-back_challenge_solving (json_t *state,
+back_challenge_solving (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
(void) arguments;
- GNUNET_assert (0 ==
- json_object_del (state,
- "selected_challenge_uuid"));
- set_state (state,
+ rs->details.recovery.have_selected_challenge = false;
+ set_state (rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -2107,9 +1624,9 @@ struct PolicyDownloadEntry
void *cb_cls;
/**
- * State we are using.
+ * State we are using; we own it.
*/
- json_t *state;
+ struct ANASTASIS_ReduxState *rs;
};
@@ -2130,7 +1647,7 @@ free_pd (void *cls)
pd->recovery = NULL;
}
GNUNET_free (pd->backend_url);
- json_decref (pd->state);
+ ANASTASIS_REDUX_state_free_ (pd->rs);
GNUNET_free (pd);
}
@@ -2152,22 +1669,16 @@ return_no_policy (struct PolicyDownloadEntry *pd,
const char *detail = (offline)
? "could not contact provider (offline)"
: "provider does not know this policy";
- json_t *estate;
+ ANASTASIS_ActionCallback cb = pd->cb;
+ void *cb_cls = pd->cb_cls;
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Provider offline!\n");
- estate = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("detail",
- detail)),
- GNUNET_JSON_pack_uint64 ("code",
- ec),
- GNUNET_JSON_pack_string ("hint",
- TALER_ErrorCode_get_hint (ec)));
- pd->cb (pd->cb_cls,
- ec,
- estate);
free_pd (pd);
+ ANASTASIS_redux_fail_ (cb,
+ cb_cls,
+ ec,
+ detail);
}
@@ -2188,111 +1699,75 @@ policy_lookup_cb (void *cls,
const struct ANASTASIS_RecoveryInformation *ri)
{
struct PolicyDownloadEntry *pd = cls;
- json_t *policies;
- json_t *challenges;
- json_t *recovery_information;
+ struct ANASTASIS_ReduxRecovery *rr = &pd->rs->details.recovery;
+ struct ANASTASIS_ReduxRecoveryInfo *nri;
+ struct ANASTASIS_ReduxState *rs;
+ ANASTASIS_ActionCallback cb;
+ void *cb_cls;
if (NULL == ri)
{
/* Woopsie, failed hard. */
- ANASTASIS_recovery_abort (pd->recovery);
- GNUNET_free (pd->backend_url);
- GNUNET_free (pd);
return_no_policy (pd,
false);
return;
}
- policies = json_array ();
- GNUNET_assert (NULL != policies);
+ nri = GNUNET_new (struct ANASTASIS_ReduxRecoveryInfo);
+ nri->challenges_len = ri->cs_len;
+ nri->challenges = GNUNET_new_array (nri->challenges_len,
+ struct ANASTASIS_ReduxChallengeInfo);
+ for (unsigned int i = 0; i<ri->cs_len; i++)
+ {
+ struct ANASTASIS_ReduxChallengeInfo *ci = &nri->challenges[i];
+ const struct ANASTASIS_ChallengeDetails *cd;
+
+ cd = ANASTASIS_challenge_get_details (ri->cs[i]);
+ ci->uuid = cd->uuid;
+ ci->type = GNUNET_strdup (cd->type);
+ ci->instructions = GNUNET_strdup (cd->instructions);
+ } /* end for all challenges */
+ nri->policies_len = ri->dps_len;
+ nri->policies = GNUNET_new_array (nri->policies_len,
+ struct ANASTASIS_ReduxRecoveryPolicy);
for (unsigned int i = 0; i<ri->dps_len; i++)
{
- struct ANASTASIS_DecryptionPolicy *dps = ri->dps[i];
- json_t *pchallenges;
+ const struct ANASTASIS_DecryptionPolicy *dps = ri->dps[i];
+ struct ANASTASIS_ReduxRecoveryPolicy *p = &nri->policies[i];
- pchallenges = json_array ();
- GNUNET_assert (NULL != pchallenges);
+ p->uuids_len = dps->challenges_length;
+ p->uuids = GNUNET_new_array (p->uuids_len,
+ struct ANASTASIS_CRYPTO_TruthUUIDP);
for (unsigned int j = 0; j<dps->challenges_length; j++)
{
- struct ANASTASIS_Challenge *c = dps->challenges[j];
const struct ANASTASIS_ChallengeDetails *cd;
- json_t *cj;
-
- cd = ANASTASIS_challenge_get_details (c);
- cj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("uuid",
- &cd->uuid));
- GNUNET_assert (0 ==
- json_array_append_new (pchallenges,
- cj));
+ cd = ANASTASIS_challenge_get_details (dps->challenges[j]);
+ p->uuids[j] = cd->uuid;
}
- GNUNET_assert (0 ==
- json_array_append_new (policies,
- pchallenges));
} /* end for all policies */
- challenges = json_array ();
- GNUNET_assert (NULL != challenges);
- for (unsigned int i = 0; i<ri->cs_len; i++)
- {
- struct ANASTASIS_Challenge *c = ri->cs[i];
- const struct ANASTASIS_ChallengeDetails *cd;
- json_t *cj;
-
- cd = ANASTASIS_challenge_get_details (c);
- cj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("uuid",
- &cd->uuid),
- GNUNET_JSON_pack_string ("type",
- cd->type),
- GNUNET_JSON_pack_string ("uuid-display",
- ANASTASIS_CRYPTO_uuid2s (&cd->uuid)),
- GNUNET_JSON_pack_string ("instructions",
- cd->instructions));
- GNUNET_assert (0 ==
- json_array_append_new (challenges,
- cj));
- } /* end for all challenges */
- recovery_information = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("challenges",
- challenges),
- GNUNET_JSON_pack_array_steal ("policies",
- policies),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("secret_name",
- ri->secret_name)),
- GNUNET_JSON_pack_string ("provider_url",
- pd->backend_url),
- GNUNET_JSON_pack_uint64 ("version",
- ri->version));
- GNUNET_assert (0 ==
- json_object_set_new (pd->state,
- "recovery_information",
- recovery_information));
- {
- json_t *rd;
-
- rd = ANASTASIS_recovery_serialize (pd->recovery);
- if (NULL == rd)
- {
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (pd->cb,
- pd->cb_cls,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "unable to serialize recovery state");
- free_pd (pd);
- return;
- }
- GNUNET_assert (0 ==
- json_object_set_new (pd->state,
- "recovery_document",
- rd));
- }
- set_state (pd->state,
+ if (NULL != ri->secret_name)
+ nri->secret_name = GNUNET_strdup (ri->secret_name);
+ ANASTASIS_REDUX_provider_url_set_ (&nri->provider_url,
+ pd->backend_url);
+ nri->version = ri->version;
+ ANASTASIS_REDUX_recovery_info_free_ (rr->ri);
+ rr->ri = nri;
+ /* The state takes over the operation: it is what gets serialized as
+ `recovery_document`, and it is aborted when the state is freed. */
+ GNUNET_assert (NULL == rr->r);
+ rr->r = pd->recovery;
+ pd->recovery = NULL;
+ set_state (pd->rs,
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
- pd->cb (pd->cb_cls,
- TALER_EC_NONE,
- pd->state);
+ rs = pd->rs;
+ cb = pd->cb;
+ cb_cls = pd->cb_cls;
+ pd->rs = NULL;
free_pd (pd);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
}
@@ -2314,14 +1789,21 @@ core_early_secret_cb (void *cls,
size_t secret_size)
{
struct PolicyDownloadEntry *pd = cls;
+ ANASTASIS_ActionCallback cb = pd->cb;
+ void *cb_cls = pd->cb_cls;
+ const char *msg;
+ enum TALER_ErrorCode ec;
pd->recovery = NULL;
GNUNET_assert (NULL == secret);
GNUNET_assert (ANASTASIS_RS_SUCCESS != rc);
- fail_by_error (pd->cb,
- pd->cb_cls,
- rc);
+ ec = error_by_status (rc,
+ &msg);
free_pd (pd);
+ ANASTASIS_redux_fail_ (cb,
+ cb_cls,
+ ec,
+ msg);
}
@@ -2336,7 +1818,7 @@ core_early_secret_cb (void *cls,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-done_secret_selecting (json_t *state,
+done_secret_selecting (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
@@ -2350,15 +1832,6 @@ done_secret_selecting (json_t *state,
&pa),
GNUNET_JSON_spec_end ()
};
- struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
- struct GNUNET_JSON_Specification pspec[] = {
- GNUNET_JSON_spec_fixed_auto ("provider_salt",
- &provider_salt),
- GNUNET_JSON_spec_end ()
- };
- json_t *p_cfg;
- json_t *id_data;
- const json_t *providers;
if (GNUNET_OK !=
GNUNET_JSON_parse (arguments,
@@ -2369,19 +1842,18 @@ done_secret_selecting (json_t *state,
json_dumpf (arguments,
stderr,
JSON_INDENT (2));
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
NULL);
return NULL;
}
- providers = json_object_get (state,
- "authentication_providers");
- if ( (NULL == providers) ||
- (! json_is_object (providers)) )
+ if (! rs->common.have_providers)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_providers' missing");
@@ -2396,6 +1868,7 @@ done_secret_selecting (json_t *state,
json_array_foreach (pa, poff, pe)
{
+ const struct ANASTASIS_ReduxProvider *p;
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_uint64 ("version",
&version),
@@ -2413,37 +1886,25 @@ done_secret_selecting (json_t *state,
json_dumpf (pe,
stderr,
JSON_INDENT (2));
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
NULL);
return NULL;
}
- p_cfg = json_object_get (providers,
- provider_url);
- if (MHD_HTTP_OK !=
- json_integer_value (json_object_get (p_cfg,
- "http_status")))
+ p = ANASTASIS_REDUX_provider_find_ (&rs->common,
+ provider_url);
+ if ( (NULL == p) ||
+ (! p->have_config) ||
+ (MHD_HTTP_OK != p->config.http_status) )
continue;
- if (GNUNET_OK !=
- GNUNET_JSON_parse (p_cfg,
- pspec,
- NULL, NULL))
- {
- GNUNET_break (0); /* should be impossible for well-formed state */
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "Salt unknown for selected provider");
- return NULL;
- }
- id_data = json_object_get (state,
- "identity_attributes");
- if (NULL == id_data)
+ if (NULL == rs->common.identity_attributes)
{
GNUNET_break (0); /* should be impossible for well-formed state */
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'identity_attributes' missing");
@@ -2455,27 +1916,26 @@ done_secret_selecting (json_t *state,
pd->cb = cb;
pd->cb_cls = cb_cls;
- pd->state = json_incref (state);
+ pd->rs = rs;
pd->backend_url = GNUNET_strdup (provider_url);
- pd->recovery = ANASTASIS_recovery_begin (ANASTASIS_REDUX_ctx_,
- id_data,
- version,
- pd->backend_url,
- &provider_salt,
- &policy_lookup_cb,
- pd,
- &core_early_secret_cb,
- pd);
+ pd->recovery = ANASTASIS_recovery_begin (
+ ANASTASIS_REDUX_ctx_,
+ rs->common.identity_attributes,
+ version,
+ pd->backend_url,
+ &p->config.provider_salt,
+ &policy_lookup_cb,
+ pd,
+ &core_early_secret_cb,
+ pd);
if (NULL == pd->recovery)
{
GNUNET_break (0);
+ free_pd (pd);
ANASTASIS_redux_fail_ (cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INTERNAL_ERROR,
NULL);
- GNUNET_free (pd->backend_url);
- json_decref (pd->state);
- GNUNET_free (pd);
return NULL;
}
pd->ra.cleanup = &free_pd;
@@ -2486,7 +1946,8 @@ done_secret_selecting (json_t *state,
}
/* no provider worked */
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"selected provider is not online");
@@ -2504,7 +1965,7 @@ done_secret_selecting (json_t *state,
* @return handle to cancel challenge selection step
*/
static struct ANASTASIS_ReduxAction *
-add_provider (json_t *state,
+add_provider (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
@@ -2522,36 +1983,37 @@ add_provider (json_t *state,
NULL, NULL))
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
NULL);
return NULL;
}
- return ANASTASIS_REDUX_add_provider_to_state_ (provider_url,
- state,
- cb,
- cb_cls);
+ return ANASTASIS_REDUX_provider_add_ (provider_url,
+ rs,
+ cb,
+ cb_cls);
}
/**
* Signature of callback function that implements a state transition.
*
- * @param state current state
+ * @param[in] rs current state
* @param arguments arguments for the state transition
* @param cb function to call when done
* @param cb_cls closure for @a cb
*/
typedef struct ANASTASIS_ReduxAction *
-(*DispatchHandler)(json_t *state,
+(*DispatchHandler)(struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
struct ANASTASIS_ReduxAction *
-ANASTASIS_recovery_action_ (json_t *state,
+ANASTASIS_recovery_action_ (struct ANASTASIS_ReduxState *rs,
const char *action,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
@@ -2625,33 +2087,23 @@ ANASTASIS_recovery_action_ (json_t *state,
},
{ ANASTASIS_RECOVERY_STATE_INVALID, NULL, NULL }
};
- const char *s = json_string_value (json_object_get (state,
- "recovery_state"));
- enum ANASTASIS_RecoveryState rs;
+ enum ANASTASIS_RecoveryState state = rs->details.recovery.state;
- GNUNET_assert (NULL != s);
- rs = ANASTASIS_recovery_state_from_string_ (s);
- if (ANASTASIS_RECOVERY_STATE_INVALID == rs)
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'recovery_state' field invalid");
- return NULL;
- }
+ GNUNET_assert (ANASTASIS_RT_RECOVERY == rs->type);
for (unsigned int i = 0; NULL != dispatchers[i].fun; i++)
{
- if ( (rs == dispatchers[i].recovery_state) &&
+ if ( (state == dispatchers[i].recovery_state) &&
(0 == strcmp (action,
dispatchers[i].recovery_action)) )
{
- return dispatchers[i].fun (state,
+ return dispatchers[i].fun (rs,
arguments,
cb,
cb_cls);
}
}
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
action);
@@ -2660,21 +2112,18 @@ ANASTASIS_recovery_action_ (json_t *state,
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_recovery_challenge_begin_ (json_t *state,
+ANASTASIS_REDUX_recovery_challenge_begin_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- const json_t *providers;
json_t *attributes;
- providers = json_object_get (state,
- "authentication_providers");
- if ( (NULL == providers) ||
- (! json_is_object (providers)) )
+ if (! rs->common.have_providers)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'authentication_providers' missing");
@@ -2686,20 +2135,20 @@ ANASTASIS_REDUX_recovery_challenge_begin_ (json_t *state,
(! json_is_object (attributes)) )
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'identity_attributes' missing");
return NULL;
}
- GNUNET_assert (0 ==
- json_object_set (state,
- "identity_attributes",
- attributes));
- set_state (state,
+ json_decref (rs->common.identity_attributes);
+ rs->common.identity_attributes = json_incref (attributes);
+ set_state (rs,
ANASTASIS_RECOVERY_STATE_SECRET_SELECTING);
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
diff --git a/src/reducer/anastasis_api_redux.c b/src/reducer/anastasis_api_redux.c
@@ -26,6 +26,7 @@
#include "anastasis_error_codes.h"
#include <taler/taler_json_lib.h>
#include "anastasis_api_redux.h"
+#include "anastasis_api_redux_state.h"
#include <dlfcn.h>
@@ -77,14 +78,16 @@ struct ConfigReduxWaiting
struct ConfigRequest *cr;
/**
- * State we are processing.
+ * State we are processing. Borrowed, not owned: the operation that
+ * started us keeps the state alive until it has cancelled us. See
+ * #ANASTASIS_REDUX_add_provider_to_state_.
*/
- json_t *state;
+ struct ANASTASIS_ReduxState *rs;
/**
- * Function to call with updated @e state.
+ * Function to call with updated @e rs.
*/
- ANASTASIS_ActionCallback cb;
+ ANASTASIS_REDUX_StateCallback cb;
/**
* Closure for @e cb.
@@ -272,20 +275,36 @@ ANASTASIS_REDUX_probe_external_reducer (void)
/**
- * Extract the mode of a state from json
+ * Extract the generic part of the step @a rs is at.
+ *
+ * The generic states are the common prefix of the backup and the
+ * recovery state enumerations (see #ANASTASIS_GENERIC_STATES), so a
+ * value that is in range for #ANASTASIS_GenericState means the same
+ * thing in either variant.
*
- * @param state the state to operate on
- * @return "backup_state" or "recovery_state"
+ * @param rs the state to inspect
+ * @return #ANASTASIS_GENERIC_STATE_INVALID if @a rs is past the generic
+ * steps, or is an `error` state
*/
-static const char *
-get_state_mode (const json_t *state)
+static enum ANASTASIS_GenericState
+get_generic_state (const struct ANASTASIS_ReduxState *rs)
{
- if (json_object_get (state, "backup_state"))
- return "backup_state";
- if (json_object_get (state, "recovery_state"))
- return "recovery_state";
- GNUNET_assert (0);
- return NULL;
+ unsigned int s;
+
+ switch (rs->type)
+ {
+ case ANASTASIS_RT_BACKUP:
+ s = (unsigned int) rs->details.backup.state;
+ break;
+ case ANASTASIS_RT_RECOVERY:
+ s = (unsigned int) rs->details.recovery.state;
+ break;
+ case ANASTASIS_RT_ERROR:
+ return ANASTASIS_GENERIC_STATE_INVALID;
+ }
+ if (s >= sizeof (generic_strings) / sizeof(*generic_strings))
+ return ANASTASIS_GENERIC_STATE_INVALID;
+ return (enum ANASTASIS_GenericState) s;
}
@@ -341,24 +360,27 @@ ANASTASIS_redux_fail_ (ANASTASIS_ActionCallback cb,
/**
- * Transition the @a state to @a gs.
+ * Transition @a rs to the generic state @a gs.
*
- * @param[in,out] state to transition
+ * @param[in,out] rs state to transition
* @param gs state to transition to
*/
static void
-redux_transition (json_t *state,
+redux_transition (struct ANASTASIS_ReduxState *rs,
enum ANASTASIS_GenericState gs)
{
- const char *s_mode = get_state_mode (state);
-
- GNUNET_assert (0 ==
- json_object_set_new (
- state,
- s_mode,
- json_string (
- ANASTASIS_generic_state_to_string_ (gs))));
-
+ switch (rs->type)
+ {
+ case ANASTASIS_RT_BACKUP:
+ rs->details.backup.state = (enum ANASTASIS_BackupState) gs;
+ return;
+ case ANASTASIS_RT_RECOVERY:
+ rs->details.recovery.state = (enum ANASTASIS_RecoveryState) gs;
+ return;
+ case ANASTASIS_RT_ERROR:
+ break;
+ }
+ GNUNET_assert (0);
}
@@ -480,7 +502,7 @@ abort_provider_config_cb (void *cls)
GNUNET_CONTAINER_DLL_remove (cr->w_head,
cr->w_tail,
w);
- json_decref (w->state);
+ /* w->rs is borrowed; freeing it is the caller's business. */
GNUNET_free (w);
}
@@ -498,73 +520,47 @@ notify_waiting (struct ConfigRequest *cr)
while (NULL != (w = cr->w_head))
{
- json_t *apl;
- json_t *prov;
+ struct ANASTASIS_ReduxProvider *p;
- if (NULL == (apl = json_object_get (w->state,
- "authentication_providers")))
- {
- GNUNET_assert (0 ==
- json_object_set_new (w->state,
- "authentication_providers",
- apl = json_object ()));
- }
+ p = ANASTASIS_REDUX_provider_get_ (&w->rs->common,
+ cr->url);
+ if (p->have_config)
+ ANASTASIS_REDUX_provider_config_clear_ (&p->config);
+ p->have_config = false;
+ memset (&p->error,
+ 0,
+ sizeof (p->error));
if (TALER_EC_NONE != cr->ec)
{
- prov = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("status",
- "error"),
- GNUNET_JSON_pack_uint64 ("error_code",
- cr->ec),
- GNUNET_JSON_pack_uint64 ("http_status",
- cr->http_status));
+ p->status = ANASTASIS_RPS_ERROR;
+ p->error.ec = cr->ec;
+ p->error.http_status = cr->http_status;
}
else
{
- json_t *methods_list;
+ struct ANASTASIS_ReduxProviderConfig *cfg = &p->config;
- methods_list = json_array ();
- GNUNET_assert (NULL != methods_list);
+ p->status = ANASTASIS_RPS_OK;
+ p->have_config = true;
+ cfg->methods_len = cr->methods_length;
+ cfg->methods = GNUNET_new_array (cfg->methods_len,
+ struct ANASTASIS_ReduxMethodSpec);
for (unsigned int i = 0; i<cr->methods_length; i++)
{
- struct AuthorizationMethodConfig *method = &cr->methods[i];
- json_t *mj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- method->type),
- TALER_JSON_pack_amount ("usage_fee",
- &method->usage_fee));
-
- GNUNET_assert (0 ==
- json_array_append_new (methods_list,
- mj));
+ cfg->methods[i].type = GNUNET_strdup (cr->methods[i].type);
+ cfg->methods[i].usage_fee = cr->methods[i].usage_fee;
}
- prov = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("status",
- "ok"),
- GNUNET_JSON_pack_array_steal ("methods",
- methods_list),
- TALER_JSON_pack_amount ("annual_fee",
- &cr->annual_fee),
- TALER_JSON_pack_amount ("truth_upload_fee",
- &cr->truth_upload_fee),
- TALER_JSON_pack_amount ("liability_limit",
- &cr->liability_limit),
- GNUNET_JSON_pack_string ("business_name",
- cr->business_name),
- GNUNET_JSON_pack_uint64 ("storage_limit_in_megabytes",
- cr->storage_limit_in_megabytes),
- GNUNET_JSON_pack_data_auto ("provider_salt",
- &cr->provider_salt),
- GNUNET_JSON_pack_uint64 ("http_status",
- cr->http_status));
+ cfg->annual_fee = cr->annual_fee;
+ cfg->truth_upload_fee = cr->truth_upload_fee;
+ cfg->liability_limit = cr->liability_limit;
+ cfg->provider_salt = cr->provider_salt;
+ cfg->business_name = GNUNET_strdup (cr->business_name);
+ cfg->storage_limit_in_megabytes = cr->storage_limit_in_megabytes;
+ cfg->http_status = cr->http_status;
}
- GNUNET_assert (0 ==
- json_object_set_new (apl,
- cr->url,
- prov));
w->cb (w->cb_cls,
cr->ec,
- w->state);
+ w->rs);
abort_provider_config_cb (w);
}
}
@@ -792,12 +788,12 @@ check_config (struct GNUNET_TIME_Relative timeout,
* Begin asynchronous check for provider configurations.
*
* @param cc country code that was selected
- * @param[in,out] state to set provider list for
+ * @param[in,out] common state to set the provider list for
* @return #TALER_EC_NONE on success
*/
static enum TALER_ErrorCode
begin_provider_config_check (const char *cc,
- json_t *state)
+ struct ANASTASIS_ReduxCommon *common)
{
if (NULL == provider_list)
{
@@ -839,9 +835,11 @@ begin_provider_config_check (const char *cc,
json_t *provider;
const json_t *provider_arr = json_object_get (provider_list,
"anastasis_provider");
- json_t *pl;
- pl = json_object ();
+ /* The applicable providers depend on the country, so start over
+ rather than merge into whatever an earlier selection left. */
+ ANASTASIS_REDUX_providers_clear_ (common);
+ common->have_providers = true;
json_array_foreach (provider_arr, index, provider)
{
const char *url;
@@ -855,7 +853,6 @@ begin_provider_config_check (const char *cc,
NULL),
GNUNET_JSON_spec_end ()
};
- json_t *prov;
if (GNUNET_OK !=
GNUNET_JSON_parse (provider,
@@ -863,7 +860,7 @@ begin_provider_config_check (const char *cc,
NULL, NULL))
{
GNUNET_break (0);
- json_decref (pl);
+ ANASTASIS_REDUX_providers_clear_ (common);
return TALER_EC_ANASTASIS_REDUCER_RESOURCE_MALFORMED;
}
if ( (NULL != restricted) &&
@@ -885,21 +882,11 @@ begin_provider_config_check (const char *cc,
/* demo mode, skipping regular providers */
continue;
}
- prov = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("status",
- "not-contacted"));
- GNUNET_assert (NULL != prov);
- GNUNET_assert (0 ==
- json_object_set_new (pl,
- url,
- prov));
+ (void) ANASTASIS_REDUX_provider_get_ (common,
+ url);
check_config (CONFIG_GENERIC_TIMEOUT,
url);
}
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "authentication_providers",
- pl));
}
return TALER_EC_NONE;
}
@@ -1015,14 +1002,14 @@ redux_id_attr_init (const char *country_code)
* DispatchHandler/Callback function which is called for a
* "select_continent" action.
*
- * @param state state to operate on
+ * @param[in] rs state to operate on
* @param arguments arguments to use for operation on state
* @param cb callback to call during/after operation
* @param cb_cls callback closure
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-select_continent (json_t *state,
+select_continent (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
@@ -1031,11 +1018,13 @@ select_continent (json_t *state,
const json_t *root = json_object_get (rc,
"countries");
const json_t *continent;
+ const char *cname;
json_t *countries;
if (NULL == root)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_RESOURCE_MALFORMED,
"'countries' missing");
@@ -1043,7 +1032,8 @@ select_continent (json_t *state,
}
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -1053,54 +1043,71 @@ select_continent (json_t *state,
"continent");
if (NULL == continent)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'continent' missing");
return NULL;
}
+ cname = json_string_value (continent);
countries = json_array ();
GNUNET_assert (NULL != countries);
{
size_t index;
const json_t *country;
- bool found = false;
json_array_foreach (root, index, country)
{
- json_t *temp_continent = json_object_get (country,
- "continent");
- if (1 == json_equal (continent,
- temp_continent))
- {
+ const char *cc = json_string_value (json_object_get (country,
+ "continent"));
+
+ if ( (NULL != cname) &&
+ (NULL != cc) &&
+ (0 == strcmp (cname,
+ cc)) )
GNUNET_assert (0 ==
json_array_append (countries,
(json_t *) country));
- found = true;
- }
}
- if (! found)
+ if (0 == json_array_size (countries))
{
- ANASTASIS_redux_fail_ (cb,
+ json_decref (countries);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'continent' unknown");
return NULL;
}
}
- redux_transition (state,
+ {
+ const char *detail;
+
+ if (GNUNET_OK !=
+ ANASTASIS_REDUX_countries_set_ (&rs->common,
+ countries,
+ &detail))
+ {
+ GNUNET_break (0);
+ json_decref (countries);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_RESOURCE_MALFORMED,
+ detail);
+ return NULL;
+ }
+ }
+ json_decref (countries);
+ redux_transition (rs,
ANASTASIS_GENERIC_STATE_COUNTRY_SELECTING);
- GNUNET_assert (0 ==
- json_object_set (state,
- "selected_continent",
- (json_t *) continent));
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "countries",
- countries));
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ GNUNET_free (rs->common.selected_continent);
+ rs->common.selected_continent = GNUNET_strdup (cname);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -1116,54 +1123,51 @@ select_continent (json_t *state,
* @return #ANASTASIS_ReduxAction
*/
static struct ANASTASIS_ReduxAction *
-select_country (json_t *state,
+select_country (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
const json_t *required_attrs;
- const json_t *country_code;
+ const char *country_code;
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
return NULL;
}
- country_code = json_object_get (arguments,
- "country_code");
- if (NULL == country_code)
+ if (NULL == json_object_get (arguments,
+ "country_code"))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'country_code' missing");
return NULL;
}
+ country_code = json_string_value (json_object_get (arguments,
+ "country_code"));
{
- json_t *countries = json_object_get (state,
- "countries");
- size_t index;
- json_t *country;
bool found = false;
- json_array_foreach (countries, index, country)
- {
- json_t *cc = json_object_get (country,
- "code");
- if (1 == json_equal (country_code,
- cc))
+ for (unsigned int i = 0; i < rs->common.countries_len; i++)
+ if ( (NULL != country_code) &&
+ (0 == strcmp (rs->common.countries[i].code,
+ country_code)) )
{
found = true;
break;
}
- }
if (! found)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"specified country not on selected continent");
@@ -1175,12 +1179,13 @@ select_country (json_t *state,
{
enum TALER_ErrorCode ec;
- ec = begin_provider_config_check (json_string_value (country_code),
- state);
+ ec = begin_provider_config_check (country_code,
+ &rs->common);
if (TALER_EC_NONE != ec)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
ec,
NULL);
@@ -1191,14 +1196,15 @@ select_country (json_t *state,
{
const json_t *ria;
- ria = redux_id_attr_init (json_string_value (country_code));
+ ria = redux_id_attr_init (country_code);
if (NULL == ria)
{
GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_RESOURCE_MISSING,
- json_string_value (country_code));
+ country_code);
return NULL;
}
required_attrs = json_object_get (ria,
@@ -1206,25 +1212,38 @@ select_country (json_t *state,
}
if (NULL == required_attrs)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_RESOURCE_MALFORMED,
"'required_attributes' missing");
return NULL;
}
- redux_transition (state,
+ {
+ const char *detail;
+
+ if (GNUNET_OK !=
+ ANASTASIS_REDUX_required_attributes_set_ (&rs->common,
+ required_attrs,
+ &detail))
+ {
+ GNUNET_break (0);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_RESOURCE_MALFORMED,
+ detail);
+ return NULL;
+ }
+ }
+ redux_transition (rs,
ANASTASIS_GENERIC_STATE_USER_ATTRIBUTES_COLLECTING);
- GNUNET_assert (0 ==
- json_object_set (state,
- "selected_country",
- (json_t *) country_code));
- GNUNET_assert (0 ==
- json_object_set (state,
- "required_attributes",
- (json_t *) required_attrs));
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ GNUNET_free (rs->common.selected_country);
+ rs->common.selected_country = GNUNET_strdup (country_code);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -1240,24 +1259,25 @@ select_country (json_t *state,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-unselect_continent (json_t *state,
+unselect_continent (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- redux_transition (state,
+ redux_transition (rs,
ANASTASIS_GENERIC_STATE_CONTINENT_SELECTING);
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
struct ANASTASIS_ReduxAction *
ANASTASIS_REDUX_add_provider_to_state_ (const char *url,
- json_t *state,
- ANASTASIS_ActionCallback cb,
+ struct ANASTASIS_ReduxState *rs,
+ ANASTASIS_REDUX_StateCallback cb,
void *cb_cls)
{
struct ConfigRequest *cr;
@@ -1267,7 +1287,7 @@ ANASTASIS_REDUX_add_provider_to_state_ (const char *url,
url);
w = GNUNET_new (struct ConfigReduxWaiting);
w->cr = cr;
- w->state = json_incref (state);
+ w->rs = rs;
w->cb = cb;
w->cb_cls = cb_cls;
w->ra.cleanup = &abort_provider_config_cb;
@@ -1287,6 +1307,107 @@ ANASTASIS_REDUX_add_provider_to_state_ (const char *url,
/**
+ * Context for #ANASTASIS_REDUX_provider_add_().
+ */
+struct ProviderAddContext
+{
+ /**
+ * Handle we returned for cancellation of the operation.
+ */
+ struct ANASTASIS_ReduxAction ra;
+
+ /**
+ * The /config request we are waiting for, NULL once it completed.
+ */
+ struct ANASTASIS_ReduxAction *inner;
+
+ /**
+ * State we own until we hand it to @e cb.
+ */
+ struct ANASTASIS_ReduxState *rs;
+
+ /**
+ * Function to call with the new state.
+ */
+ ANASTASIS_ActionCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+};
+
+
+/**
+ * Free @a cls.
+ *
+ * @param[in] cls a `struct ProviderAddContext *`
+ */
+static void
+provider_add_cleanup (void *cls)
+{
+ struct ProviderAddContext *pac = cls;
+
+ if (NULL != pac->inner)
+ pac->inner->cleanup (pac->inner->cleanup_cls);
+ ANASTASIS_REDUX_state_free_ (pac->rs);
+ GNUNET_free (pac);
+}
+
+
+/**
+ * The /config request completed; return the updated state.
+ *
+ * @param cls a `struct ProviderAddContext *`
+ * @param ec status of the request
+ * @param[in] rs the updated state
+ */
+static void
+provider_add_done (void *cls,
+ enum TALER_ErrorCode ec,
+ struct ANASTASIS_ReduxState *rs)
+{
+ struct ProviderAddContext *pac = cls;
+ ANASTASIS_ActionCallback cb = pac->cb;
+ void *cb_cls = pac->cb_cls;
+
+ GNUNET_assert (rs == pac->rs);
+ /* our waiter unlinks and frees itself right after this call */
+ pac->inner = NULL;
+ pac->rs = NULL;
+ provider_add_cleanup (pac);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ ec);
+}
+
+
+struct ANASTASIS_ReduxAction *
+ANASTASIS_REDUX_provider_add_ (const char *url,
+ struct ANASTASIS_ReduxState *rs,
+ ANASTASIS_ActionCallback cb,
+ void *cb_cls)
+{
+ struct ProviderAddContext *pac;
+
+ pac = GNUNET_new (struct ProviderAddContext);
+ pac->rs = rs;
+ pac->cb = cb;
+ pac->cb_cls = cb_cls;
+ pac->inner = ANASTASIS_REDUX_add_provider_to_state_ (url,
+ rs,
+ &provider_add_done,
+ pac);
+ /* the /config request never completes synchronously */
+ GNUNET_assert (NULL != pac->inner);
+ pac->ra.cleanup = &provider_add_cleanup;
+ pac->ra.cleanup_cls = pac;
+ return &pac->ra;
+}
+
+
+/**
* DispatchHandler/Callback function which is called for a
* "enter_user_attributes" action.
* Returns an #ANASTASIS_ReduxAction if operation is async.
@@ -1298,17 +1419,17 @@ ANASTASIS_REDUX_add_provider_to_state_ (const char *url,
* @return NULL
*/
static struct ANASTASIS_ReduxAction *
-enter_user_attributes (json_t *state,
+enter_user_attributes (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
const json_t *attributes;
- const json_t *required_attributes;
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
@@ -1318,155 +1439,106 @@ enter_user_attributes (json_t *state,
"identity_attributes");
if (NULL == attributes)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"'identity_attributes' missing");
return NULL;
}
- GNUNET_assert (0 ==
- json_object_set (state,
- "identity_attributes",
- (json_t *) attributes));
+ json_decref (rs->common.identity_attributes);
+ rs->common.identity_attributes = json_incref ((json_t *) attributes);
- /* Verify required attributes are present and well-formed */
- required_attributes = json_object_get (state,
- "required_attributes");
- if ( (NULL == required_attributes) ||
- (! json_is_array (required_attributes)) )
+ if (! rs->common.have_required_attributes)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
"'required_attributes' must be an array");
return NULL;
}
+ /* Verify required attributes are present and well-formed */
+ for (unsigned int i = 0; i < rs->common.required_attributes_len; i++)
{
- size_t index;
- json_t *required_attribute;
+ const struct ANASTASIS_ReduxAttributeSpec *a
+ = &rs->common.required_attributes[i];
+ const char *attribute_value;
- json_array_foreach (required_attributes, index, required_attribute)
+ attribute_value = json_string_value (json_object_get (attributes,
+ a->name));
+ if (NULL == attribute_value)
{
- const char *name;
- const char *attribute_value;
- const char *regexp = NULL;
- const char *reglog = NULL;
- bool optional = false;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("name",
- &name),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("validation-regex",
- ®exp),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("validation-logic",
- ®log),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_bool ("optional",
- &optional),
- NULL),
- GNUNET_JSON_spec_end ()
- };
+ if (a->optional)
+ continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Request is missing required attribute `%s'\n",
+ a->name);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ a->name);
+ return NULL;
+ }
+ if ( (NULL != a->validation_regex) &&
+ (! validate_regex (attribute_value,
+ a->validation_regex)) )
+ {
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_REGEX_FAILED,
+ a->name);
+ return NULL;
+ }
+ if (NULL != a->validation_logic)
+ {
+ bool (*regfun)(const char *);
- if (GNUNET_OK !=
- GNUNET_JSON_parse (required_attribute,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- "'required_attributes' lacks required fields");
- return NULL;
- }
- attribute_value = json_string_value (json_object_get (attributes,
- name));
- if (NULL == attribute_value)
+ regfun = dlsym (RTLD_DEFAULT,
+ a->validation_logic);
+ if (NULL == regfun)
{
- if (optional)
- continue;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Request is missing required attribute `%s'\n",
- name);
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_GENERIC_PARAMETER_MISSING,
- name);
- return NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Custom validation function `%s' is not available: %s\n",
+ a->validation_logic,
+ dlerror ());
}
- if ( (NULL != regexp) &&
- (! validate_regex (attribute_value,
- regexp)) )
+ else if (! regfun (attribute_value))
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_REGEX_FAILED,
- name);
+ TALER_EC_ANASTASIS_REDUCER_INPUT_VALIDATION_FAILED,
+ a->name);
return NULL;
}
-
- if (NULL != reglog)
- {
- bool (*regfun)(const char *);
-
- regfun = dlsym (RTLD_DEFAULT,
- reglog);
- if (NULL == regfun)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Custom validation function `%s' is not available: %s\n",
- reglog,
- dlerror ());
- }
- else if (! regfun (attribute_value))
- {
- ANASTASIS_redux_fail_ (cb,
- cb_cls,
- TALER_EC_ANASTASIS_REDUCER_INPUT_VALIDATION_FAILED,
- name);
- return NULL;
- }
- }
- } /* end for all attributes loop */
- } /* end for all attributes scope */
+ }
+ } /* end for all attributes loop */
/* Transition based on mode */
- {
- const char *s_mode = get_state_mode (state);
-
- if (0 == strcmp (s_mode,
- "backup_state"))
- {
- GNUNET_assert (0 ==
- json_object_set_new (
- state,
- "backup_state",
- json_string (
- ANASTASIS_backup_state_to_string_ (
- ANASTASIS_BACKUP_STATE_AUTHENTICATIONS_EDITING))));
- return ANASTASIS_REDUX_backup_begin_ (state,
- arguments,
- cb,
- cb_cls);
- }
- else
- {
- GNUNET_assert (0 ==
- json_object_set_new (
- state,
- "recovery_state",
- json_string (
- ANASTASIS_recovery_state_to_string_ (
- ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING))));
- return ANASTASIS_REDUX_recovery_challenge_begin_ (state,
- arguments,
- cb,
- cb_cls);
- }
+ switch (rs->type)
+ {
+ case ANASTASIS_RT_BACKUP:
+ rs->details.backup.state
+ = ANASTASIS_BACKUP_STATE_AUTHENTICATIONS_EDITING;
+ return ANASTASIS_REDUX_backup_begin_ (rs,
+ arguments,
+ cb,
+ cb_cls);
+ case ANASTASIS_RT_RECOVERY:
+ rs->details.recovery.state
+ = ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING;
+ return ANASTASIS_REDUX_recovery_challenge_begin_ (rs,
+ arguments,
+ cb,
+ cb_cls);
+ case ANASTASIS_RT_ERROR:
+ break;
}
+ GNUNET_assert (0);
+ return NULL;
}
@@ -1481,60 +1553,59 @@ enter_user_attributes (json_t *state,
* @param cb_cls callback closure
*/
static struct ANASTASIS_ReduxAction *
-add_provider (json_t *state,
+add_provider (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- if (ANASTASIS_add_provider_ (state,
+ if (ANASTASIS_add_provider_ (rs,
arguments,
cb,
cb_cls))
return NULL;
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
bool
-ANASTASIS_add_provider_ (json_t *state,
+ANASTASIS_add_provider_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- json_t *tlist;
+ const char *url;
+ json_t *params;
if (NULL == arguments)
{
- ANASTASIS_redux_fail_ (cb,
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
cb_cls,
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
"arguments missing");
return true; /* cb was invoked */
}
- tlist = json_object_get (state,
- "authentication_providers");
- if (NULL == tlist)
+ json_object_foreach (((json_t *) arguments), url, params)
{
- tlist = json_object ();
- GNUNET_assert (NULL != tlist);
- GNUNET_assert (0 ==
- json_object_set_new (state,
- "authentication_providers",
- tlist));
- }
- {
- json_t *params;
- const char *url;
+ const char *detail;
- json_object_foreach (((json_t *) arguments), url, params)
+ if (GNUNET_OK !=
+ ANASTASIS_REDUX_provider_set_ (&rs->common,
+ url,
+ params,
+ &detail))
{
- GNUNET_assert (0 ==
- json_object_set (tlist,
- url,
- params));
+ GNUNET_break_op (0);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+ detail);
+ return true; /* cb was invoked */
}
}
return false; /* cb not invoked */
@@ -1542,50 +1613,30 @@ ANASTASIS_add_provider_ (json_t *state,
struct ANASTASIS_ReduxAction *
-ANASTASIS_back_generic_decrement_ (json_t *state,
+ANASTASIS_back_generic_decrement_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls)
{
- const char *s_mode = get_state_mode (state);
- const char *state_string = json_string_value (json_object_get (state,
- s_mode));
-
(void) arguments;
- GNUNET_assert (NULL != state_string);
- if (0 == strcmp ("backup_state",
- s_mode))
- {
- enum ANASTASIS_BackupState state_index;
-
- state_index = ANASTASIS_backup_state_from_string_ (state_string);
- GNUNET_assert (state_index > 0);
- state_index = state_index - 1;
-
- GNUNET_assert (0 ==
- json_object_set_new (
- state,
- s_mode,
- json_string (
- ANASTASIS_backup_state_to_string_ (state_index))));
- }
- else
+ switch (rs->type)
{
- enum ANASTASIS_RecoveryState state_index;
-
- state_index = ANASTASIS_recovery_state_from_string_ (state_string);
- GNUNET_assert (state_index > 0);
- state_index = state_index - 1;
- GNUNET_assert (0 ==
- json_object_set_new (
- state,
- s_mode,
- json_string (
- ANASTASIS_recovery_state_to_string_ (state_index))));
+ case ANASTASIS_RT_BACKUP:
+ GNUNET_assert (rs->details.backup.state > 0);
+ rs->details.backup.state--;
+ break;
+ case ANASTASIS_RT_RECOVERY:
+ GNUNET_assert (rs->details.recovery.state > 0);
+ rs->details.recovery.state--;
+ break;
+ case ANASTASIS_RT_ERROR:
+ GNUNET_assert (0);
+ break;
}
- cb (cb_cls,
- TALER_EC_NONE,
- state);
+ ANASTASIS_REDUX_return_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_NONE);
return NULL;
}
@@ -1594,14 +1645,18 @@ ANASTASIS_back_generic_decrement_ (json_t *state,
* Callback function which is called by the reducer in dependence of
* given state and action.
*
- * @param state the previous state to operate on
+ * The handler takes ownership of @a rs and must dispose of it, either by
+ * handing it to #ANASTASIS_REDUX_return_ / #ANASTASIS_REDUX_fail_ or by
+ * passing it on to another handler that does.
+ *
+ * @param[in] rs the previous state to operate on
* @param arguments the arguments needed by operation to operate on state
* @param cb Callback function which returns the new state
* @param cb_cls closure for @a cb
* @return handle to cancel async actions, NULL if @a cb was already called
*/
typedef struct ANASTASIS_ReduxAction *
-(*DispatchHandler)(json_t *state,
+(*DispatchHandler)(struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
@@ -1924,9 +1979,7 @@ ANASTASIS_redux_action (const json_t *state,
},
{ ANASTASIS_GENERIC_STATE_INVALID, NULL, NULL }
};
- bool recovery_mode = false;
- const char *s = json_string_value (json_object_get (state,
- "backup_state"));
+ struct ANASTASIS_ReduxState *rs;
enum ANASTASIS_GenericState gs;
/* If requested, handle action with external reducer, used for testing. */
@@ -1941,63 +1994,62 @@ ANASTASIS_redux_action (const json_t *state,
cb_cls);
}
- if (NULL == s)
+ /* This is the one place where a state is read. Everything below
+ operates on the typed representation, and every path back out goes
+ through ANASTASIS_REDUX_return_() or ANASTASIS_REDUX_fail_(). */
{
- s = json_string_value (json_object_get (state,
- "recovery_state"));
- if (NULL == s)
+ enum TALER_ErrorCode ec;
+ const char *detail;
+
+ rs = ANASTASIS_REDUX_state_parse_ (state,
+ &ec,
+ &detail);
+ if (NULL == rs)
{
GNUNET_break_op (0);
- cb (cb_cls,
- TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
- NULL);
+ ANASTASIS_redux_fail_ (cb,
+ cb_cls,
+ ec,
+ detail);
return NULL;
}
- recovery_mode = true;
}
- gs = ANASTASIS_generic_state_from_string_ (s);
+ if (ANASTASIS_RT_ERROR == rs->type)
{
- json_t *new_state;
- struct ANASTASIS_ReduxAction *ret;
-
- new_state = json_deep_copy (state);
- GNUNET_assert (NULL != new_state);
- if (gs != ANASTASIS_GENERIC_STATE_INVALID)
- {
- for (unsigned int i = 0; NULL != dispatchers[i].fun; i++)
- {
- if ( (gs == dispatchers[i].redux_state) &&
- (0 == strcmp (action,
- dispatchers[i].redux_action)) )
- {
- ret = dispatchers[i].fun (new_state,
- arguments,
- cb,
- cb_cls);
- json_decref (new_state);
- return ret;
- }
- }
- }
- if (recovery_mode)
- {
- ret = ANASTASIS_recovery_action_ (new_state,
- action,
- arguments,
- cb,
- cb_cls);
- }
- else
+ /* An error state has no step to advance from. */
+ GNUNET_break_op (0);
+ ANASTASIS_REDUX_fail_ (rs,
+ cb,
+ cb_cls,
+ TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+ "reducer_type");
+ return NULL;
+ }
+ gs = get_generic_state (rs);
+ if (ANASTASIS_GENERIC_STATE_INVALID != gs)
+ {
+ for (unsigned int i = 0; NULL != dispatchers[i].fun; i++)
{
- ret = ANASTASIS_backup_action_ (new_state,
- action,
- arguments,
- cb,
- cb_cls);
+ if ( (gs == dispatchers[i].redux_state) &&
+ (0 == strcmp (action,
+ dispatchers[i].redux_action)) )
+ return dispatchers[i].fun (rs,
+ arguments,
+ cb,
+ cb_cls);
}
- json_decref (new_state);
- return ret;
}
+ if (ANASTASIS_RT_RECOVERY == rs->type)
+ return ANASTASIS_recovery_action_ (rs,
+ action,
+ arguments,
+ cb,
+ cb_cls);
+ return ANASTASIS_backup_action_ (rs,
+ action,
+ arguments,
+ cb,
+ cb_cls);
}
@@ -2118,9 +2170,36 @@ ANASTASIS_REDUX_load_continents_ ()
}
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_lookup_salt_ (
+ const struct ANASTASIS_ReduxCommon *common,
+ const char *provider_url,
+ struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt)
+{
+ const struct ANASTASIS_ReduxProvider *p;
+
+ p = ANASTASIS_REDUX_provider_find_ (common,
+ provider_url);
+ if (NULL == p)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (ANASTASIS_RPS_DISABLED == p->status)
+ return GNUNET_NO;
+ if (! p->have_config)
+ return GNUNET_NO;
+ *provider_salt = p->config.provider_salt;
+ return GNUNET_OK;
+}
+
+
/**
* Lookup @a provider_salt of @a provider_url in @a state.
*
+ * The public API still speaks JSON here, so this is the typed lookup
+ * with a parse in front of it.
+ *
* @param state the state to inspect
* @param provider_url provider to look into
* @param[out] provider_salt value to extract
@@ -2132,52 +2211,25 @@ ANASTASIS_reducer_lookup_salt (
const char *provider_url,
struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt)
{
- const json_t *aps;
- const json_t *cfg;
- uint32_t http_status = 0;
- const char *status;
- bool no_salt;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("status",
- &status),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("http_status",
- &http_status),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto ("provider_salt",
- provider_salt),
- &no_salt),
- GNUNET_JSON_spec_end ()
- };
+ struct ANASTASIS_ReduxState *rs;
+ enum GNUNET_GenericReturnValue ret;
- aps = json_object_get (state,
- "authentication_providers");
- if (NULL == aps)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- cfg = json_object_get (aps,
- provider_url);
- if (NULL == cfg)
{
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_JSON_parse (cfg,
- spec,
- NULL, NULL))
- {
- /* provider not working */
- GNUNET_break_op (0);
- return GNUNET_NO;
+ enum TALER_ErrorCode ec;
+ const char *detail;
+
+ rs = ANASTASIS_REDUX_state_parse_ (state,
+ &ec,
+ &detail);
+ if (NULL == rs)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
}
- if (0 == strcmp (status,
- "disabled"))
- return GNUNET_NO;
- if (no_salt)
- return GNUNET_NO;
- return GNUNET_OK;
+ ret = ANASTASIS_REDUX_lookup_salt_ (&rs->common,
+ provider_url,
+ provider_salt);
+ ANASTASIS_REDUX_state_free_ (rs);
+ return ret;
}
diff --git a/src/reducer/anastasis_api_redux.h b/src/reducer/anastasis_api_redux.h
@@ -23,12 +23,44 @@
#ifndef ANASTASIS_API_REDUX_H
#define ANASTASIS_API_REDUX_H
+/**
+ * The typed state the reducer operates on internally; see
+ * `anastasis_api_redux_state.h`, which includes this header.
+ */
+struct ANASTASIS_ReduxState;
+
+/**
+ * Fields the backup and recovery variants of a state share.
+ */
+struct ANASTASIS_ReduxCommon;
+
+/**
+ * Signature of the callback used to hand a typed state back to whoever
+ * started an asynchronous step inside the reducer. The mirror image of
+ * #ANASTASIS_ActionCallback, which is what the same result eventually
+ * becomes once it leaves the reducer.
+ *
+ * Unlike the callback APIs in `anastasis.h` this one does not declare an
+ * overridable closure type: its closure is almost always the opaque
+ * `cb_cls` of the public action the reducer is in the middle of
+ * executing, which by construction has no type to name here.
+ *
+ * @param cls closure
+ * @param ec status of the step
+ * @param[in,out] rs the state that was passed in, updated in place;
+ * ownership is *not* transferred by this call
+ */
+typedef void
+(*ANASTASIS_REDUX_StateCallback)(void *cls,
+ enum TALER_ErrorCode ec,
+ struct ANASTASIS_ReduxState *rs);
+
#define ANASTASIS_GENERIC_STATES(REDUX_STATE) \
- REDUX_STATE (INVALID) \
- REDUX_STATE (CONTINENT_SELECTING) \
- REDUX_STATE (COUNTRY_SELECTING) \
- REDUX_STATE (USER_ATTRIBUTES_COLLECTING)
+ REDUX_STATE (INVALID) \
+ REDUX_STATE (CONTINENT_SELECTING) \
+ REDUX_STATE (COUNTRY_SELECTING) \
+ REDUX_STATE (USER_ATTRIBUTES_COLLECTING)
#define GENERATE_GENERIC_ENUM(ENUM) ANASTASIS_GENERIC_STATE_ ## ENUM,
@@ -40,13 +72,13 @@ enum ANASTASIS_GenericState
#undef GENERATE_GENERIC_ENUM
#define ANASTASIS_BACKUP_STATES(REDUX_STATE) \
- ANASTASIS_GENERIC_STATES (REDUX_STATE) \
- REDUX_STATE (AUTHENTICATIONS_EDITING) \
- REDUX_STATE (POLICIES_REVIEWING) \
- REDUX_STATE (SECRET_EDITING) \
- REDUX_STATE (TRUTHS_PAYING) \
- REDUX_STATE (POLICIES_PAYING) \
- REDUX_STATE (BACKUP_FINISHED)
+ ANASTASIS_GENERIC_STATES (REDUX_STATE) \
+ REDUX_STATE (AUTHENTICATIONS_EDITING) \
+ REDUX_STATE (POLICIES_REVIEWING) \
+ REDUX_STATE (SECRET_EDITING) \
+ REDUX_STATE (TRUTHS_PAYING) \
+ REDUX_STATE (POLICIES_PAYING) \
+ REDUX_STATE (BACKUP_FINISHED)
#define GENERATE_BACKUP_ENUM(ENUM) ANASTASIS_BACKUP_STATE_ ## ENUM,
@@ -58,12 +90,12 @@ enum ANASTASIS_BackupState
#undef GENERATE_BACKUP_ENUM
#define ANASTASIS_RECOVERY_STATES(REDUX_STATE) \
- ANASTASIS_GENERIC_STATES (REDUX_STATE) \
- REDUX_STATE (SECRET_SELECTING) \
- REDUX_STATE (CHALLENGE_SELECTING) \
- REDUX_STATE (CHALLENGE_PAYING) \
- REDUX_STATE (CHALLENGE_SOLVING) \
- REDUX_STATE (RECOVERY_FINISHED)
+ ANASTASIS_GENERIC_STATES (REDUX_STATE) \
+ REDUX_STATE (SECRET_SELECTING) \
+ REDUX_STATE (CHALLENGE_SELECTING) \
+ REDUX_STATE (CHALLENGE_PAYING) \
+ REDUX_STATE (CHALLENGE_SOLVING) \
+ REDUX_STATE (RECOVERY_FINISHED)
#define GENERATE_RECOVERY_ENUM(ENUM) ANASTASIS_RECOVERY_STATE_ ## ENUM,
@@ -112,14 +144,14 @@ ANASTASIS_REDUX_load_continents_ (void);
* providers. Upon success, call @a cb with the updated provider
* status data.
*
- * @param[in] state we are in
+ * @param[in] rs state we are in
* @param arguments our arguments with the solution
* @param cb functiont o call with the new state
* @param cb_cls closure for @a cb
* @return handle to cancel challenge selection step
*/
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_poll_providers_ (json_t *state,
+ANASTASIS_REDUX_poll_providers_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
@@ -130,14 +162,14 @@ ANASTASIS_REDUX_poll_providers_ (json_t *state,
* a recovery procedure, and if not, try to obtain it. Upon
* success, call @a cb with the updated provider status data.
*
- * @param[in] state we are in
+ * @param[in] rs state we are in
* @param arguments our arguments with the solution
* @param cb functiont o call with the new state
* @param cb_cls closure for @a cb
* @return handle to cancel challenge selection step
*/
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_sync_providers_ (json_t *state,
+ANASTASIS_REDUX_sync_providers_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
@@ -218,6 +250,24 @@ ANASTASIS_reducer_lookup_salt (const json_t *state,
/**
+ * Lookup @a salt of @a provider_url in @a common. The typed
+ * counterpart of #ANASTASIS_reducer_lookup_salt(), which stays around
+ * for the public discovery API.
+ *
+ * @param common the state to inspect
+ * @param provider_url provider to look into
+ * @param[out] salt value to extract
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if the provider is disabled or has no /config,
+ * #GNUNET_SYSERR if the provider is not in @a common at all
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_lookup_salt_ (const struct ANASTASIS_ReduxCommon *common,
+ const char *provider_url,
+ struct ANASTASIS_CRYPTO_ProviderSaltP *salt);
+
+
+/**
* Function to return a json error response.
*
* @param cb callback to give error to
@@ -237,14 +287,14 @@ ANASTASIS_redux_fail_ (ANASTASIS_ActionCallback cb,
* "add_provider" action. Adds another Anastasis provider
* to the list of available providers for storing information.
*
- * @param state state to operate on
+ * @param[in] rs state to operate on
* @param arguments arguments with a provider URL to add
* @param cb callback to call during/after operation
* @param cb_cls callback closure
* @return true if @a cb was invoked
*/
bool
-ANASTASIS_add_provider_ (json_t *state,
+ANASTASIS_add_provider_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
@@ -258,7 +308,8 @@ ANASTASIS_add_provider_ (json_t *state,
* generating a success or failure outcome asynchronously.
*
* @param url the provider's base URL to add
- * @param[in,out] state the json state to operate on
+ * @param[in,out] rs the state to update in place; borrowed,
+ * the caller must keep it alive until it cancels the operation
* @param cb callback to call during/after operation
* @param cb_cls callback closure
* @return handle to cancel asynchronous operation, NULL if
@@ -266,23 +317,41 @@ ANASTASIS_add_provider_ (json_t *state,
*/
struct ANASTASIS_ReduxAction *
ANASTASIS_REDUX_add_provider_to_state_ (const char *url,
- json_t *state,
- ANASTASIS_ActionCallback cb,
+ struct ANASTASIS_ReduxState *rs,
+ ANASTASIS_REDUX_StateCallback cb,
void *cb_cls);
/**
+ * Add the provider at @a url to @a rs and return the updated state to
+ * the application. The whole of the "add_provider" action, for the
+ * state variants that have nothing else to do afterwards.
+ *
+ * @param url the provider's base URL to add
+ * @param[in] rs state to operate on; we take ownership
+ * @param cb callback to call with the new state
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel the asynchronous operation
+ */
+struct ANASTASIS_ReduxAction *
+ANASTASIS_REDUX_provider_add_ (const char *url,
+ struct ANASTASIS_ReduxState *rs,
+ ANASTASIS_ActionCallback cb,
+ void *cb_cls);
+
+
+/**
* A generic DispatchHandler/Callback function which is called for a
* "back" action.
*
- * @param[in,out] state state to operate on
+ * @param[in] rs state to operate on
* @param arguments arguments to use for operation on state
* @param cb callback to call during/after operation
* @param cb_cls callback closure for @a cb
* @return NULL (no asynchronous action)
*/
struct ANASTASIS_ReduxAction *
-ANASTASIS_back_generic_decrement_ (json_t *state,
+ANASTASIS_back_generic_decrement_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
@@ -303,14 +372,14 @@ ANASTASIS_redux_countries_init_ (void);
* by a callback function.
* This function can do network access to talk to anastasis service providers.
*
- * @param[in,out] state input/output state (to be modified)
+ * @param[in] rs state to operate on
* @param action what action to perform
* @param arguments data for the @a action
* @param cb function to call with the result
* @param cb_cls closure for @a cb
*/
struct ANASTASIS_ReduxAction *
-ANASTASIS_recovery_action_ (json_t *state,
+ANASTASIS_recovery_action_ (struct ANASTASIS_ReduxState *rs,
const char *action,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
@@ -325,14 +394,14 @@ ANASTASIS_recovery_action_ (json_t *state,
*
* Returns an #ANASTASIS_ReduxAction.
*
- * @param state state to operate on
+ * @param[in] rs state to operate on
* @param arguments data for the operation
* @param cb callback to call during/after operation
* @param cb_cls callback closure for @a cb
* @return NULL
*/
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_recovery_challenge_begin_ (json_t *state,
+ANASTASIS_REDUX_recovery_challenge_begin_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
@@ -346,13 +415,13 @@ ANASTASIS_REDUX_recovery_challenge_begin_ (json_t *state,
*
* Returns a `struct ANASTASIS_ReduxAction`.
*
- * @param state state to operate on
+ * @param[in] rs state to operate on
* @param arguments data for the operation
* @param cb callback to call during/after operation
* @param cb_cls callback closure
*/
struct ANASTASIS_ReduxAction *
-ANASTASIS_REDUX_backup_begin_ (json_t *state,
+ANASTASIS_REDUX_backup_begin_ (struct ANASTASIS_ReduxState *rs,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
void *cb_cls);
@@ -363,14 +432,14 @@ ANASTASIS_REDUX_backup_begin_ (json_t *state,
* callback function.
* This function can do network access to talk to anastasis service providers.
*
- * @param[in,out] state input/output state (to be modified)
+ * @param[in] rs state to operate on
* @param action what action to perform
* @param arguments data for the @a action
* @param cb function to call with the result
* @param cb_cls closure for @a cb
*/
struct ANASTASIS_ReduxAction *
-ANASTASIS_backup_action_ (json_t *state,
+ANASTASIS_backup_action_ (struct ANASTASIS_ReduxState *rs,
const char *action,
const json_t *arguments,
ANASTASIS_ActionCallback cb,
diff --git a/src/reducer/anastasis_api_redux_free.c b/src/reducer/anastasis_api_redux_free.c
@@ -37,6 +37,22 @@ ANASTASIS_REDUX_provider_url_clear_ (struct ANASTASIS_ProviderUrl *pu)
void
+ANASTASIS_REDUX_provider_config_clear_ (struct ANASTASIS_ReduxProviderConfig *
+ cfg
+ )
+{
+ for (unsigned int j = 0; j < cfg->methods_len; j++)
+ GNUNET_free (cfg->methods[j].type);
+ GNUNET_free (cfg->methods);
+ GNUNET_free (cfg->business_name);
+ GNUNET_free (cfg->currency);
+ memset (cfg,
+ 0,
+ sizeof (*cfg));
+}
+
+
+void
ANASTASIS_REDUX_providers_clear_ (struct ANASTASIS_ReduxCommon *common)
{
for (unsigned int i = 0; i < common->providers_len; i++)
@@ -45,13 +61,7 @@ ANASTASIS_REDUX_providers_clear_ (struct ANASTASIS_ReduxCommon *common)
ANASTASIS_REDUX_provider_url_clear_ (&p->url);
if (p->have_config)
- {
- for (unsigned int j = 0; j < p->config.methods_len; j++)
- GNUNET_free (p->config.methods[j].type);
- GNUNET_free (p->config.methods);
- GNUNET_free (p->config.business_name);
- GNUNET_free (p->config.currency);
- }
+ ANASTASIS_REDUX_provider_config_clear_ (&p->config);
}
GNUNET_free (common->providers);
common->providers = NULL;
@@ -59,13 +69,8 @@ ANASTASIS_REDUX_providers_clear_ (struct ANASTASIS_ReduxCommon *common)
}
-/**
- * Free the contents of @a common.
- *
- * @param[in,out] common state to free
- */
-static void
-free_common (struct ANASTASIS_ReduxCommon *common)
+void
+ANASTASIS_REDUX_continents_clear_ (struct ANASTASIS_ReduxCommon *common)
{
for (unsigned int i = 0; i < common->continents_len; i++)
{
@@ -75,6 +80,14 @@ free_common (struct ANASTASIS_ReduxCommon *common)
json_decref (c->name_i18n);
}
GNUNET_free (common->continents);
+ common->continents = NULL;
+ common->continents_len = 0;
+}
+
+
+void
+ANASTASIS_REDUX_countries_clear_ (struct ANASTASIS_ReduxCommon *common)
+{
for (unsigned int i = 0; i < common->countries_len; i++)
{
struct ANASTASIS_ReduxCountry *c = &common->countries[i];
@@ -88,6 +101,15 @@ free_common (struct ANASTASIS_ReduxCommon *common)
json_decref (c->continent_i18n);
}
GNUNET_free (common->countries);
+ common->countries = NULL;
+ common->countries_len = 0;
+}
+
+
+void
+ANASTASIS_REDUX_required_attributes_clear_ (
+ struct ANASTASIS_ReduxCommon *common)
+{
for (unsigned int i = 0; i < common->required_attributes_len; i++)
{
struct ANASTASIS_ReduxAttributeSpec *a = &common->required_attributes[i];
@@ -104,6 +126,22 @@ free_common (struct ANASTASIS_ReduxCommon *common)
json_decref (a->label_i18n);
}
GNUNET_free (common->required_attributes);
+ common->required_attributes = NULL;
+ common->required_attributes_len = 0;
+}
+
+
+/**
+ * Free the contents of @a common.
+ *
+ * @param[in,out] common state to free
+ */
+static void
+free_common (struct ANASTASIS_ReduxCommon *common)
+{
+ ANASTASIS_REDUX_continents_clear_ (common);
+ ANASTASIS_REDUX_countries_clear_ (common);
+ ANASTASIS_REDUX_required_attributes_clear_ (common);
ANASTASIS_REDUX_providers_clear_ (common);
for (unsigned int i = 0; i < common->currencies_len; i++)
GNUNET_free (common->currencies[i]);
@@ -119,42 +157,62 @@ free_common (struct ANASTASIS_ReduxCommon *common)
*
* @param[in,out] backup state to free
*/
-static void
-free_backup (struct ANASTASIS_ReduxBackup *backup)
+void
+ANASTASIS_REDUX_policy_clear_ (struct ANASTASIS_ReduxPolicy *p)
{
- for (unsigned int i = 0; i < backup->authentication_methods_len; i++)
+ for (unsigned int j = 0; j < p->methods_len; j++)
{
- struct ANASTASIS_ReduxAuthMethod *am = &backup->authentication_methods[i];
+ struct ANASTASIS_ReduxPolicyMethod *pm = &p->methods[j];
- GNUNET_free (am->type);
- GNUNET_free (am->instructions);
- GNUNET_free (am->challenge);
- GNUNET_free (am->mime_type);
+ ANASTASIS_REDUX_provider_url_clear_ (&pm->provider);
+ if (NULL != pm->truth)
+ ANASTASIS_truth_free (pm->truth);
}
- GNUNET_free (backup->authentication_methods);
- for (unsigned int i = 0; i < backup->policies_len; i++)
- {
- struct ANASTASIS_ReduxPolicy *p = &backup->policies[i];
+ GNUNET_free (p->methods);
+ p->methods = NULL;
+ p->methods_len = 0;
+}
- for (unsigned int j = 0; j < p->methods_len; j++)
- {
- struct ANASTASIS_ReduxPolicyMethod *pm = &p->methods[j];
- ANASTASIS_REDUX_provider_url_clear_ (&pm->provider);
- if (NULL != pm->truth)
- ANASTASIS_truth_free (pm->truth);
- }
- GNUNET_free (p->methods);
- }
+void
+ANASTASIS_REDUX_policies_clear_ (struct ANASTASIS_ReduxBackup *backup)
+{
+ for (unsigned int i = 0; i < backup->policies_len; i++)
+ ANASTASIS_REDUX_policy_clear_ (&backup->policies[i]);
GNUNET_free (backup->policies);
+ backup->policies = NULL;
+ backup->policies_len = 0;
+}
+
+
+void
+ANASTASIS_REDUX_policy_providers_clear_ (struct ANASTASIS_ReduxBackup *backup)
+{
for (unsigned int i = 0; i < backup->policy_providers_len; i++)
ANASTASIS_REDUX_provider_url_clear_ (
&backup->policy_providers[i].provider_url);
GNUNET_free (backup->policy_providers);
- GNUNET_free (backup->upload_fees);
+ backup->policy_providers = NULL;
+ backup->policy_providers_len = 0;
+}
+
+
+void
+ANASTASIS_REDUX_payments_clear_ (struct ANASTASIS_ReduxBackup *backup)
+{
for (unsigned int i = 0; i < backup->payments_len; i++)
GNUNET_free (backup->payments[i]);
GNUNET_free (backup->payments);
+ backup->payments = NULL;
+ backup->payments_len = 0;
+ backup->have_payments = false;
+}
+
+
+void
+ANASTASIS_REDUX_policy_payment_requests_clear_ (
+ struct ANASTASIS_ReduxBackup *backup)
+{
for (unsigned int i = 0; i < backup->policy_payment_requests_len; i++)
{
struct ANASTASIS_ReduxPolicyPaymentRequest *ppr
@@ -164,6 +222,30 @@ free_backup (struct ANASTASIS_ReduxBackup *backup)
ANASTASIS_REDUX_provider_url_clear_ (&ppr->provider);
}
GNUNET_free (backup->policy_payment_requests);
+ backup->policy_payment_requests = NULL;
+ backup->policy_payment_requests_len = 0;
+ backup->have_policy_payment_requests = false;
+}
+
+
+static void
+free_backup (struct ANASTASIS_ReduxBackup *backup)
+{
+ for (unsigned int i = 0; i < backup->authentication_methods_len; i++)
+ {
+ struct ANASTASIS_ReduxAuthMethod *am = &backup->authentication_methods[i];
+
+ GNUNET_free (am->type);
+ GNUNET_free (am->instructions);
+ GNUNET_free (am->challenge);
+ GNUNET_free (am->mime_type);
+ }
+ GNUNET_free (backup->authentication_methods);
+ ANASTASIS_REDUX_policies_clear_ (backup);
+ ANASTASIS_REDUX_policy_providers_clear_ (backup);
+ GNUNET_free (backup->upload_fees);
+ ANASTASIS_REDUX_payments_clear_ (backup);
+ ANASTASIS_REDUX_policy_payment_requests_clear_ (backup);
for (unsigned int i = 0; i < backup->success_details_len; i++)
ANASTASIS_REDUX_provider_url_clear_ (
&backup->success_details[i].provider_url);
@@ -214,13 +296,8 @@ ANASTASIS_REDUX_feedback_clear_ (struct ANASTASIS_ReduxFeedback *fb)
}
-/**
- * Free the recovery information @a ri.
- *
- * @param[in] ri recovery information to free, may be NULL
- */
-static void
-free_recovery_info (struct ANASTASIS_ReduxRecoveryInfo *ri)
+void
+ANASTASIS_REDUX_recovery_info_free_ (struct ANASTASIS_ReduxRecoveryInfo *ri)
{
if (NULL == ri)
return;
@@ -228,6 +305,7 @@ free_recovery_info (struct ANASTASIS_ReduxRecoveryInfo *ri)
{
GNUNET_free (ri->challenges[i].type);
GNUNET_free (ri->challenges[i].instructions);
+ GNUNET_free (ri->challenges[i].answer);
}
GNUNET_free (ri->challenges);
for (unsigned int i = 0; i < ri->policies_len; i++)
@@ -249,7 +327,7 @@ free_recovery (struct ANASTASIS_ReduxRecovery *recovery)
{
if (NULL != recovery->r)
ANASTASIS_recovery_abort (recovery->r);
- free_recovery_info (recovery->ri);
+ ANASTASIS_REDUX_recovery_info_free_ (recovery->ri);
for (unsigned int i = 0; i < recovery->challenge_feedback_len; i++)
ANASTASIS_REDUX_feedback_clear_ (&recovery->challenge_feedback[i]);
GNUNET_free (recovery->challenge_feedback);
diff --git a/src/reducer/anastasis_api_redux_parse.c b/src/reducer/anastasis_api_redux_parse.c
@@ -1435,6 +1435,7 @@ parse_recovery_info (const json_t *obj,
"uuid-display",
"type",
"instructions",
+ "answer",
"payment_secret",
NULL
};
@@ -1508,6 +1509,7 @@ parse_recovery_info (const json_t *obj,
struct ANASTASIS_ReduxChallengeInfo *ci = &ri->challenges[index];
const char *type;
const char *instructions;
+ const char *answer = NULL;
bool no_ps;
struct GNUNET_JSON_Specification cspec[] = {
GNUNET_JSON_spec_fixed_auto ("uuid",
@@ -1517,6 +1519,10 @@ parse_recovery_info (const json_t *obj,
GNUNET_JSON_spec_string ("instructions",
&instructions),
GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("answer",
+ &answer),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_fixed_auto ("payment_secret",
&ci->payment_secret),
&no_ps),
@@ -1540,6 +1546,7 @@ parse_recovery_info (const json_t *obj,
}
ci->type = GNUNET_strdup (type);
ci->instructions = GNUNET_strdup (instructions);
+ ci->answer = dup_or_null (answer);
ci->have_payment_secret = ! no_ps;
}
ri->policies_len = (unsigned int) json_array_size (policies);
@@ -2190,4 +2197,75 @@ ANASTASIS_REDUX_state_parse_ (const json_t *json,
}
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_countries_set_ (struct ANASTASIS_ReduxCommon *common,
+ const json_t *arr,
+ const char **detail)
+{
+ ANASTASIS_REDUX_countries_clear_ (common);
+ if (GNUNET_OK !=
+ parse_countries (arr,
+ common,
+ detail))
+ {
+ ANASTASIS_REDUX_countries_clear_ (common);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_required_attributes_set_ (struct ANASTASIS_ReduxCommon *common,
+ const json_t *arr,
+ const char **detail)
+{
+ ANASTASIS_REDUX_required_attributes_clear_ (common);
+ if (GNUNET_OK !=
+ parse_required_attributes (arr,
+ common,
+ detail))
+ {
+ ANASTASIS_REDUX_required_attributes_clear_ (common);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_provider_set_ (struct ANASTASIS_ReduxCommon *common,
+ const char *url,
+ const json_t *val,
+ const char **detail)
+{
+ struct ANASTASIS_ReduxProvider *p;
+
+ p = ANASTASIS_REDUX_provider_get_ (common,
+ url);
+ if (p->have_config)
+ ANASTASIS_REDUX_provider_config_clear_ (&p->config);
+ p->have_config = false;
+ p->status = ANASTASIS_RPS_NOT_CONTACTED;
+ memset (&p->error,
+ 0,
+ sizeof (p->error));
+ if (GNUNET_OK !=
+ parse_provider (url,
+ val,
+ p,
+ detail))
+ {
+ /* Leave a well-defined, if uninformative, entry behind: the caller
+ reports the error, but the state must stay consistent. */
+ if (p->have_config)
+ ANASTASIS_REDUX_provider_config_clear_ (&p->config);
+ p->have_config = false;
+ p->status = ANASTASIS_RPS_NOT_CONTACTED;
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
/* end of anastasis_api_redux_parse.c */
diff --git a/src/reducer/anastasis_api_redux_serialize.c b/src/reducer/anastasis_api_redux_serialize.c
@@ -625,6 +625,10 @@ serialize_recovery_info (const struct ANASTASIS_ReduxRecoveryInfo *ri)
GNUNET_JSON_pack_string ("instructions",
ci->instructions),
GNUNET_JSON_pack_conditional (
+ NULL != ci->answer,
+ GNUNET_JSON_pack_string ("answer",
+ ci->answer)),
+ GNUNET_JSON_pack_conditional (
ci->have_payment_secret,
GNUNET_JSON_pack_data_auto ("payment_secret",
&ci->payment_secret)))));
diff --git a/src/reducer/anastasis_api_redux_state.c b/src/reducer/anastasis_api_redux_state.c
@@ -144,4 +144,19 @@ ANASTASIS_REDUX_return_ (struct ANASTASIS_ReduxState *rs,
}
+void
+ANASTASIS_REDUX_fail_ (struct ANASTASIS_ReduxState *rs,
+ ANASTASIS_ActionCallback cb,
+ void *cb_cls,
+ enum TALER_ErrorCode ec,
+ const char *detail)
+{
+ ANASTASIS_REDUX_state_free_ (rs);
+ ANASTASIS_redux_fail_ (cb,
+ cb_cls,
+ ec,
+ detail);
+}
+
+
/* end of anastasis_api_redux_state.c */
diff --git a/src/reducer/anastasis_api_redux_state.h b/src/reducer/anastasis_api_redux_state.h
@@ -744,6 +744,13 @@ struct ANASTASIS_ReduxChallengeInfo
char *instructions;
/**
+ * Answer the user gave to a secure question, NULL if none. Kept so
+ * that the answer survives the round-trip through the application
+ * when the provider demands payment before accepting it.
+ */
+ char *answer;
+
+ /**
* Payment secret remembered from a payment request for this
* challenge; only valid if @e have_payment_secret.
*/
@@ -1332,6 +1339,30 @@ ANASTASIS_REDUX_return_ (struct ANASTASIS_ReduxState *rs,
enum TALER_ErrorCode ec);
+/**
+ * Report @a ec to @a cb and free @a rs. The counterpart of
+ * #ANASTASIS_REDUX_return_ for the failure path: the reducer replies
+ * with a freshly built `error` state, so whatever @a rs held is
+ * discarded rather than serialized.
+ *
+ * @param[in] rs state to free, may be NULL
+ * @param cb callback to invoke
+ * @param cb_cls closure for @a cb
+ * @param ec error to report
+ * @param detail human-readable detail, may be NULL
+ */
+void
+ANASTASIS_REDUX_fail_ (struct ANASTASIS_ReduxState *rs,
+ ANASTASIS_ActionCallback cb,
+ void *cb_cls,
+ enum TALER_ErrorCode ec,
+ const char *detail);
+
+
+/* #ANASTASIS_REDUX_StateCallback, the internal counterpart of
+ #ANASTASIS_ActionCallback, is declared in `anastasis_api_redux.h`. */
+
+
/* ************************ Small helpers **************************** */
/**
@@ -1358,6 +1389,100 @@ ANASTASIS_REDUX_providers_clear_ (struct ANASTASIS_ReduxCommon *common);
/**
+ * Free the contents of @a cfg and zero it.
+ *
+ * @param[in,out] cfg provider configuration to clear
+ */
+void
+ANASTASIS_REDUX_provider_config_clear_ (
+ struct ANASTASIS_ReduxProviderConfig *cfg);
+
+
+/**
+ * Drop all continents from @a common, freeing them.
+ *
+ * @param[in,out] common state to clear
+ */
+void
+ANASTASIS_REDUX_continents_clear_ (struct ANASTASIS_ReduxCommon *common);
+
+
+/**
+ * Drop all countries from @a common, freeing them.
+ *
+ * @param[in,out] common state to clear
+ */
+void
+ANASTASIS_REDUX_countries_clear_ (struct ANASTASIS_ReduxCommon *common);
+
+
+/**
+ * Drop all required attributes from @a common, freeing them.
+ *
+ * @param[in,out] common state to clear
+ */
+void
+ANASTASIS_REDUX_required_attributes_clear_ (
+ struct ANASTASIS_ReduxCommon *common);
+
+
+/* ****************** Importing from resource files ****************** */
+
+/*
+ * The reducer's resource files (`redux.countries.json`, `redux.$CC.json`)
+ * and the `add_provider` action supply data in exactly the JSON encoding
+ * the parser already understands. Rather than have a second, subtly
+ * different reader for them, the relevant parser fragments are exposed
+ * here. Each replaces whatever the state held before.
+ */
+
+/**
+ * Replace the countries of @a common with those in @a arr.
+ *
+ * @param[in,out] common state to update
+ * @param arr array of countries in the state's JSON encoding
+ * @param[out] detail set to the offending field on failure
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_countries_set_ (struct ANASTASIS_ReduxCommon *common,
+ const json_t *arr,
+ const char **detail);
+
+
+/**
+ * Replace the required attributes of @a common with those in @a arr.
+ *
+ * @param[in,out] common state to update
+ * @param arr array of attribute specifications in the state's JSON
+ * encoding
+ * @param[out] detail set to the offending field on failure
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_required_attributes_set_ (struct ANASTASIS_ReduxCommon *common,
+ const json_t *arr,
+ const char **detail);
+
+
+/**
+ * Replace the entry for provider @a url in @a common with @a val,
+ * adding the provider if it was not known yet.
+ *
+ * @param[in,out] common state to update
+ * @param url provider the entry is about
+ * @param val the entry in the state's JSON encoding
+ * @param[out] detail set to the offending field on failure
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+ANASTASIS_REDUX_provider_set_ (struct ANASTASIS_ReduxCommon *common,
+ const char *url,
+ const json_t *val,
+ const char **detail);
+
+
+/**
* Find, or create, the provider with the given @a url in @a common.
*
* @param[in,out] common state to search and possibly grow
@@ -1422,6 +1547,63 @@ ANASTASIS_REDUX_challenge_find_ (const struct ANASTASIS_ReduxRecovery *rr,
/**
+ * Free the contents of the policy @a p and zero it.
+ *
+ * @param[in,out] p policy to clear
+ */
+void
+ANASTASIS_REDUX_policy_clear_ (struct ANASTASIS_ReduxPolicy *p);
+
+
+/**
+ * Drop all policies from @a backup, freeing them.
+ *
+ * @param[in,out] backup state to clear
+ */
+void
+ANASTASIS_REDUX_policies_clear_ (struct ANASTASIS_ReduxBackup *backup);
+
+
+/**
+ * Drop all policy providers from @a backup, freeing them.
+ *
+ * @param[in,out] backup state to clear
+ */
+void
+ANASTASIS_REDUX_policy_providers_clear_ (struct ANASTASIS_ReduxBackup *backup);
+
+
+/**
+ * Drop the pending truth payments from @a backup, freeing them, and
+ * mark the field as absent.
+ *
+ * @param[in,out] backup state to clear
+ */
+void
+ANASTASIS_REDUX_payments_clear_ (struct ANASTASIS_ReduxBackup *backup);
+
+
+/**
+ * Drop the pending policy payments from @a backup, freeing them, and
+ * mark the field as absent.
+ *
+ * @param[in,out] backup state to clear
+ */
+void
+ANASTASIS_REDUX_policy_payment_requests_clear_ (
+ struct ANASTASIS_ReduxBackup *backup);
+
+
+/**
+ * Free the recovery information @a ri.
+ *
+ * @param[in] ri recovery information to free, may be NULL
+ */
+void
+ANASTASIS_REDUX_recovery_info_free_ (struct ANASTASIS_ReduxRecoveryInfo *ri);
+
+
+/**
* Free the contents of @a pu and set it to NULL.
*
* @param[in,out] pu provider URL to clear