gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-anastasis] branch master updated: implement new reducer logic (co


From: gnunet
Subject: [taler-anastasis] branch master updated: implement new reducer logic (completely untested though)
Date: Thu, 20 Jan 2022 19:38:58 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository anastasis.

The following commit(s) were added to refs/heads/master by this push:
     new c00d1cb  implement new reducer logic (completely untested though)
c00d1cb is described below

commit c00d1cb084c7c84a74ae39b1848f15c159c58f80
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Jan 20 19:38:55 2022 +0100

    implement new reducer logic (completely untested though)
---
 doc/sphinx/reducer.rst                     |   45 +-
 src/reducer/anastasis_api_recovery_redux.c | 1049 +++++++++-------------------
 2 files changed, 370 insertions(+), 724 deletions(-)

diff --git a/doc/sphinx/reducer.rst b/doc/sphinx/reducer.rst
index 0ab7f2e..cc696a9 100644
--- a/doc/sphinx/reducer.rst
+++ b/doc/sphinx/reducer.rst
@@ -499,8 +499,8 @@ If contacting the provider failed, the information returned 
is:
 
 **add_provider**:
 
-This operation can be performed in states ``USER_ATTRIBUTES_COLLECTING``
-and ``SECRET_SELECTING``.  It
+This operation can be performed in state ``USER_ATTRIBUTES_COLLECTING``.
+It
 adds one or more Anastasis providers to the list of providers the reducer
 should henceforth consider.  Note that removing providers is not possible at
 this time.
@@ -1308,18 +1308,37 @@ Afterwards, the reducer transitions into the 
``SECRET_SELECTING`` state:
       }
     }
 
-Here, it is again possible to add providers (see above under
-``USER_ATTRIBUTES_COLLECTING``).  Typically, the special policy
-discovery process (outside of the state machine) is expected to be
-run in this state.  The discovery process will use the state
-(and in particular the identity attributes and the list of
-active providers) to discover a set of possible recovery documents
-with their respective provider URLs, policy version and identity
-attribute mask. An identity attribute mask is a bitmask that
+Typically, the special policy discovery process (outside of the state
+machine) is expected to be run in this state.  The discovery process
+will use the state (and in particular the identity attributes and the
+list of active providers) to discover a set of possible recovery
+documents with their respective provider URLs, policy version and
+identity attribute mask. An identity attribute mask is a bitmask that
 describes which of the optional attributes from the identity
-attributes should be omitted to recover this backup.  Once the
-user has selected a backup providing this triplet, it is possible
-to proceed.
+attributes should be omitted to recover this backup.  Once the user
+has selected a backup providing this triplet, it is possible to
+proceed using ``next``.
+
+Especially if the discovered policies are inadequate, it is again
+possible to add providers using ``add_provider``.
+
+
+**add_provider**:
+
+This operation can be performed in state ``SECRET_SELECTING``.  It
+adds one additional Anastasis provider to the list of providers that
+the discovery process should henceforth consider.  Note that removing
+providers is not possible at this time.
+
+Here, the client must provide an object with the base URL of the
+providers to add, for example:
+
+.. code-block:: json
+
+    {
+      "provider_url" : "http://localhost:8088/";
+    }
+
 
 **next**:
 
diff --git a/src/reducer/anastasis_api_recovery_redux.c 
b/src/reducer/anastasis_api_recovery_redux.c
index ccef1e2..2cee0ec 100644
--- a/src/reducer/anastasis_api_recovery_redux.c
+++ b/src/reducer/anastasis_api_recovery_redux.c
@@ -1917,242 +1917,6 @@ back_challenge_solving (json_t *state,
 }
 
 
-/**
- * The user wants us to change the policy version. Download another version.
- *
- * @param[in] 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
- */
-static struct ANASTASIS_ReduxAction *
-change_version (json_t *state,
-                const json_t *arguments,
-                ANASTASIS_ActionCallback cb,
-                void *cb_cls)
-{
-  uint64_t version;
-  const char *provider_url;
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_uint64 ("version",
-                             &version),
-    GNUNET_JSON_spec_string ("provider_url",
-                             &provider_url),
-    GNUNET_JSON_spec_end ()
-  };
-  json_t *ia;
-  json_t *args;
-  struct ANASTASIS_ReduxAction *ra;
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (arguments,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break (0);
-    ANASTASIS_redux_fail_ (cb,
-                           cb_cls,
-                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                           "'version' invalid");
-    return NULL;
-  }
-  GNUNET_assert (NULL != provider_url);
-  ia = json_object_get (state,
-                        "identity_attributes");
-  if (NULL == ia)
-  {
-    GNUNET_break (0);
-    ANASTASIS_redux_fail_ (cb,
-                           cb_cls,
-                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                           "'identity_attributes' missing");
-    return NULL;
-  }
-  args = GNUNET_JSON_PACK (
-    GNUNET_JSON_pack_uint64 ("version",
-                             version),
-    GNUNET_JSON_pack_object_incref ("identity_attributes",
-                                    (json_t *) ia),
-    GNUNET_JSON_pack_string ("provider_url",
-                             provider_url));
-  if (NULL == args)
-  {
-    GNUNET_break (0);
-    ANASTASIS_redux_fail_ (cb,
-                           cb_cls,
-                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
-                           NULL);
-    return NULL;
-  }
-  ra = ANASTASIS_REDUX_recovery_challenge_begin_ (state,
-                                                  args,
-                                                  cb,
-                                                  cb_cls);
-  json_decref (args);
-  return ra;
-}
-
-
-/**
- * DispatchHandler/Callback function which is called for a
- * "next" action in "secret_selecting" state.
- *
- * @param state 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 *
-done_secret_selecting (json_t *state,
-                       const json_t *arguments,
-                       ANASTASIS_ActionCallback cb,
-                       void *cb_cls)
-{
-  const json_t *ri;
-
-  ri = json_object_get (state,
-                        "recovery_information");
-  if ( (NULL == ri) ||
-       (NULL == json_object_get (ri,
-                                 "challenges")) )
-  {
-    ANASTASIS_redux_fail_ (cb,
-                           cb_cls,
-                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
-                           "no valid version selected");
-    return NULL;
-  }
-  set_state (state,
-             ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
-  cb (cb_cls,
-      TALER_EC_NONE,
-      state);
-  return NULL;
-}
-
-
-/**
- * Signature of callback function that implements a state transition.
- *
- *  @param state 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,
-                   const json_t *arguments,
-                   ANASTASIS_ActionCallback cb,
-                   void *cb_cls);
-
-
-struct ANASTASIS_ReduxAction *
-ANASTASIS_recovery_action_ (json_t *state,
-                            const char *action,
-                            const json_t *arguments,
-                            ANASTASIS_ActionCallback cb,
-                            void *cb_cls)
-{
-  struct Dispatcher
-  {
-    enum ANASTASIS_RecoveryState recovery_state;
-    const char *recovery_action;
-    DispatchHandler fun;
-  } dispatchers[] = {
-    {
-      ANASTASIS_RECOVERY_STATE_SECRET_SELECTING,
-      "change_version",
-      &change_version
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_SECRET_SELECTING,
-      "next",
-      &done_secret_selecting
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_SECRET_SELECTING,
-      "back",
-      &ANASTASIS_back_generic_decrement_
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
-      "select_challenge",
-      &select_challenge
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
-      "poll",
-      &poll_challenges
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
-      "back",
-      &ANASTASIS_back_generic_decrement_
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING,
-      "pay",
-      &pay_challenge
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING,
-      "back",
-      &ANASTASIS_back_generic_decrement_
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING,
-      "solve_challenge",
-      &solve_challenge
-    },
-    {
-      ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING,
-      "back",
-      &back_challenge_solving
-    },
-    { ANASTASIS_RECOVERY_STATE_INVALID, NULL, NULL }
-  };
-  const char *s = json_string_value (json_object_get (state,
-                                                      "recovery_state"));
-  enum ANASTASIS_RecoveryState rs;
-
-  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;
-  }
-  for (unsigned int i = 0; NULL != dispatchers[i].fun; i++)
-  {
-    if ( (rs == dispatchers[i].recovery_state) &&
-         (0 == strcmp (action,
-                       dispatchers[i].recovery_action)) )
-    {
-      return dispatchers[i].fun (state,
-                                 arguments,
-                                 cb,
-                                 cb_cls);
-    }
-  }
-  ANASTASIS_redux_fail_ (cb,
-                         cb_cls,
-                         TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
-                         action);
-  return NULL;
-}
-
-
-/**
- * State for a "recover secret" CMD.
- */
-struct RecoverSecretState;
-
-
 /**
  * State for a "policy download" as part of a recovery operation.
  */
@@ -2160,14 +1924,9 @@ struct PolicyDownloadEntry
 {
 
   /**
-   * Kept in a DLL.
-   */
-  struct PolicyDownloadEntry *prev;
-
-  /**
-   * Kept in a DLL.
+   * Redux action handle associated with this state.
    */
-  struct PolicyDownloadEntry *next;
+  struct ANASTASIS_ReduxAction ra;
 
   /**
    * Backend we are querying.
@@ -2189,210 +1948,78 @@ struct PolicyDownloadEntry
    */
   struct ANASTASIS_Recovery *recovery;
 
-};
-
-
-/**
- * Entry in the list of all known applicable Anastasis providers.
- * Used to wait for it to complete downloading /config.
- */
-struct RecoveryStartStateProviderEntry
-{
-  /**
-   * Kept in a DLL.
-   */
-  struct RecoveryStartStateProviderEntry *next;
-
-  /**
-   * Kept in a DLL.
-   */
-  struct RecoveryStartStateProviderEntry *prev;
-
-  /**
-   * Main operation this entry is part of.
-   */
-  struct RecoverSecretState *rss;
-
-  /**
-   * Resulting provider information, NULL if not (yet) available.
-   */
-  json_t *istate;
-
-  /**
-   * Ongoing reducer action to obtain /config, NULL if completed.
-   */
-  struct ANASTASIS_ReduxAction *ra;
-
-  /**
-   * Final result of the operation (once completed).
-   */
-  enum TALER_ErrorCode ec;
-};
-
-
-/**
- * State for a "recover secret" CMD.
- */
-struct RecoverSecretState
-{
-
-  /**
-   * Redux action handle associated with this state.
-   */
-  struct ANASTASIS_ReduxAction ra;
-
-  /**
-   * Head of list of provider /config operations we are doing.
-   */
-  struct RecoveryStartStateProviderEntry *pe_head;
-
-  /**
-   * Tail of list of provider /config operations we are doing.
-   */
-  struct RecoveryStartStateProviderEntry *pe_tail;
-
-  /**
-   * Identification data from the user
-   */
-  json_t *id_data;
-
-  /**
-   * Head of DLL of policy downloads.
-   */
-  struct PolicyDownloadEntry *pd_head;
-
-  /**
-   * Tail of DLL of policy downloads.
-   */
-  struct PolicyDownloadEntry *pd_tail;
-
-  /**
-   * Reference to our state.
-   */
-  json_t *state;
-
   /**
-   * callback to call during/after operation
+   * Function to call with the result.
    */
   ANASTASIS_ActionCallback cb;
 
   /**
-   * closure for action callback @e cb.
+   * Closure for @e cb.
    */
   void *cb_cls;
 
   /**
-   * Set if recovery must be done with this provider.
-   */
-  char *provider_url;
-
-  /**
-   * version of the recovery document to request.
-   */
-  unsigned int version;
-
-  /**
-   * Mask to apply to optional attributes when fetching the
-   * recovery document.
-   */
-  json_int_t mask;
-
-  /**
-   * Number of provider /config operations in @e ba_head that
-   * are still awaiting completion.
-   */
-  unsigned int pending;
-
-  /**
-   * Is @e version set?
+   * State we are using.
    */
-  bool have_version;
+  json_t *state;
 
-  /**
-   * Is @e mask set?
-   */
-  bool have_mask;
 };
 
 
 /**
- * Function to free a `struct RecoverSecretState`
+ * Free @a cls data structure.
  *
- * @param cls must be a `struct RecoverSecretState`
+ * @param[in] cls data structure to free, must be a `struct 
PolicyDownloadEntry *`
  */
 static void
-free_rss (void *cls)
+free_pd (void *cls)
 {
-  struct RecoverSecretState *rss = cls;
-  struct PolicyDownloadEntry *pd;
-  struct RecoveryStartStateProviderEntry *pe;
-
-  while (NULL != (pe = rss->pe_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (rss->pe_head,
-                                 rss->pe_tail,
-                                 pe);
-    ANASTASIS_redux_action_cancel (pe->ra);
-    rss->pending--;
-    GNUNET_free (pe);
-  }
-  while (NULL != (pd = rss->pd_head))
+  struct PolicyDownloadEntry *pd = cls;
+
+  if (NULL != pd->recovery)
   {
-    GNUNET_CONTAINER_DLL_remove (rss->pd_head,
-                                 rss->pd_tail,
-                                 pd);
-    if (NULL != pd->recovery)
-    {
-      ANASTASIS_recovery_abort (pd->recovery);
-      pd->recovery = NULL;
-    }
-    GNUNET_free (pd->backend_url);
-    GNUNET_free (pd);
+    ANASTASIS_recovery_abort (pd->recovery);
+    pd->recovery = NULL;
   }
-  json_decref (rss->state);
-  json_decref (rss->id_data);
-  GNUNET_assert (0 == rss->pending);
-  GNUNET_free (rss->provider_url);
-  GNUNET_free (rss);
+  GNUNET_free (pd->backend_url);
+  json_decref (pd->state);
+  GNUNET_free (pd);
 }
 
 
 /**
- * This function is called whenever the recovery process ends.
- * In this case, that should not be possible as this callback
- * is used before we even begin with the challenges. So if
- * we are called, it is because of some fatal error.
+ * We failed to download a policy. Show an error to the user and
+ * allow the user to specify alternative providers and/or policy
+ * versions.
  *
- * @param cls a `struct PolicyDownloadEntry`
- * @param rc error code
- * @param secret contains the core secret which is passed to the user
- * @param secret_size defines the size of the core secret
+ * @param[in] pd state to fail with the policy download
+ * @param offline true of the reason to show is that all providers
+ *        were offline / did not return a salt to us
  */
 static void
-core_early_secret_cb (void *cls,
-                      enum ANASTASIS_RecoveryStatus rc,
-                      const void *secret,
-                      size_t secret_size)
+return_no_policy (struct PolicyDownloadEntry *pd,
+                  bool offline)
 {
-  struct PolicyDownloadEntry *pd = cls;
-  struct RecoverSecretState *rss = pd->rss;
+  enum TALER_ErrorCode ec = TALER_EC_ANASTASIS_REDUCER_NETWORK_FAILED;
+  const char *detail = (offline)
+    ? "could not contact provider (offline)"
+    : "provider does not know this policy";
+  json_t *estate;
 
-  pd->recovery = NULL;
-  GNUNET_assert (NULL == secret);
-  GNUNET_CONTAINER_DLL_remove (rss->pd_head,
-                               rss->pd_tail,
-                               pd);
-  GNUNET_free (pd->backend_url);
-  GNUNET_free (pd);
-  if (NULL != rss->pd_head)
-    return;   /* wait for another one */
-  /* all failed! report failure! */
-  GNUNET_assert (ANASTASIS_RS_SUCCESS != rc);
-  fail_by_error (rss->cb,
-                 rss->cb_cls,
-                 rc);
-  rss->cb = NULL;
-  free_rss (rss);
+  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);
 }
 
 
@@ -2484,47 +2111,6 @@ lookup_cost (const json_t *state,
 }
 
 
-/**
- * We failed to download a policy. Show an error to the user and
- * allow the user to specify alternative providers and/or policy
- * versions.
- *
- * @param[in] rss state to fail with the policy download
- * @param offline true of the reason to show is that all providers
- *        were offline / did not return a salt to us
- */
-static void
-return_no_policy (struct RecoverSecretState *rss,
-                  bool offline)
-{
-  json_t *estate;
-  const char *detail;
-  enum TALER_ErrorCode ec;
-
-  ec = TALER_EC_ANASTASIS_REDUCER_NETWORK_FAILED;
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "No provider online, need user to manually specify 
providers!\n");
-
-  if (offline)
-    detail = "could not contact provider (offline)";
-  else
-    detail = "provider does not know you";
-
-  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)));
-  rss->cb (rss->cb_cls,
-           ec,
-           estate);
-  free_rss (rss);
-}
-
-
 /**
  * Callback which passes back the recovery document and its possible
  * policies. Also passes back the version of the document for the user
@@ -2534,7 +2120,7 @@ return_no_policy (struct RecoverSecretState *rss,
  * cancel all of the others, passing the obtained recovery information
  * back to the user.
  *
- * @param cls closure for the callback
+ * @param cls closure for the callback with a `struct PolicyDownloadEntry *`
  * @param ri recovery information struct which contains the policies
  */
 static void
@@ -2542,7 +2128,6 @@ policy_lookup_cb (void *cls,
                   const struct ANASTASIS_RecoveryInformation *ri)
 {
   struct PolicyDownloadEntry *pd = cls;
-  struct RecoverSecretState *rss = pd->rss;
   json_t *policies;
   json_t *challenges;
   json_t *recovery_information;
@@ -2550,16 +2135,10 @@ policy_lookup_cb (void *cls,
   if (NULL == ri)
   {
     /* Woopsie, failed hard. */
-    GNUNET_CONTAINER_DLL_remove (rss->pd_head,
-                                 rss->pd_tail,
-                                 pd);
     ANASTASIS_recovery_abort (pd->recovery);
     GNUNET_free (pd->backend_url);
     GNUNET_free (pd);
-    if (NULL != rss->pd_head)
-      return; /* wait for another one */
-    /* all failed! report failure! */
-    return_no_policy (rss,
+    return_no_policy (pd,
                       false);
     return;
   }
@@ -2603,7 +2182,7 @@ policy_lookup_cb (void *cls,
     enum TALER_ErrorCode ec;
 
     cd = ANASTASIS_challenge_get_details (c);
-    ret = lookup_cost (rss->state,
+    ret = lookup_cost (pd->state,
                        cd->provider_url,
                        cd->type,
                        &cost,
@@ -2612,11 +2191,11 @@ policy_lookup_cb (void *cls,
     {
       json_decref (challenges);
       json_decref (policies);
-      ANASTASIS_redux_fail_ (rss->cb,
-                             rss->cb_cls,
+      ANASTASIS_redux_fail_ (pd->cb,
+                             pd->cb_cls,
                              ec,
                              "failed to 'lookup_cost'");
-      free_rss (rss);
+      free_pd (pd);
       return;
     }
 
@@ -2650,7 +2229,7 @@ policy_lookup_cb (void *cls,
     GNUNET_JSON_pack_uint64 ("version",
                              ri->version));
   GNUNET_assert (0 ==
-                 json_object_set_new (rss->state,
+                 json_object_set_new (pd->state,
                                       "recovery_information",
                                       recovery_information));
   {
@@ -2660,225 +2239,334 @@ policy_lookup_cb (void *cls,
     if (NULL == rd)
     {
       GNUNET_break (0);
-      ANASTASIS_redux_fail_ (rss->cb,
-                             rss->cb_cls,
+      ANASTASIS_redux_fail_ (pd->cb,
+                             pd->cb_cls,
                              TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
                              "unable to serialize recovery state");
-      free_rss (rss);
+      free_pd (pd);
       return;
     }
     GNUNET_assert (0 ==
-                   json_object_set_new (rss->state,
+                   json_object_set_new (pd->state,
                                         "recovery_document",
                                         rd));
   }
-  set_state (rss->state,
-             ANASTASIS_RECOVERY_STATE_SECRET_SELECTING);
-  rss->cb (rss->cb_cls,
-           TALER_EC_NONE,
-           rss->state);
-  free_rss (rss);
+  set_state (pd->state,
+             ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
+  pd->cb (pd->cb_cls,
+          TALER_EC_NONE,
+          pd->state);
+  free_pd (pd);
 }
 
 
 /**
- * Try to launch recovery at provider @a provider_url with config @a p_cfg.
+ * This function is called whenever the recovery process ends.
+ * In this case, that should not be possible as this callback
+ * is used before we even begin with the challenges. So if
+ * we are called, it is because of some fatal error.
+ *
+ * @param cls a `struct PolicyDownloadEntry`
+ * @param rc error code
+ * @param secret contains the core secret which is passed to the user
+ * @param secret_size defines the size of the core secret
+ */
+static void
+core_early_secret_cb (void *cls,
+                      enum ANASTASIS_RecoveryStatus rc,
+                      const void *secret,
+                      size_t secret_size)
+{
+  struct PolicyDownloadEntry *pd = cls;
+
+  pd->recovery = NULL;
+  GNUNET_assert (NULL == secret);
+  GNUNET_assert (ANASTASIS_RS_SUCCESS != rc);
+  fail_by_error (pd->cb,
+                 pd->cb_cls,
+                 rc);
+  free_pd (pd);
+}
+
+
+/**
+ * DispatchHandler/Callback function which is called for a
+ * "next" action in "secret_selecting" state.
  *
- * @param[in,out] rss recovery context
- * @param provider_url base URL of the provider to try
- * @param p_cfg configuration of the provider
- * @return true if a recovery was launched
+ * @param state 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 bool
-launch_recovery (struct RecoverSecretState *rss,
-                 const char *provider_url,
-                 const json_t *p_cfg)
+static struct ANASTASIS_ReduxAction *
+done_secret_selecting (json_t *state,
+                       const json_t *arguments,
+                       ANASTASIS_ActionCallback cb,
+                       void *cb_cls)
 {
-  struct PolicyDownloadEntry *pd = GNUNET_new (struct PolicyDownloadEntry);
+  uint32_t mask;
+  uint64_t version;
+  const char *provider_url;
   struct GNUNET_JSON_Specification spec[] = {
+    GNUNET_JSON_spec_uint64 ("version",
+                             &version),
+    GNUNET_JSON_spec_uint32 ("mask",
+                             &mask),
+    GNUNET_JSON_spec_string ("provider_url",
+                             &provider_url),
+    GNUNET_JSON_spec_end ()
+  };
+  struct ANASTASIS_CRYPTO_ProviderSaltP salt;
+  struct GNUNET_JSON_Specification pspec[] = {
     GNUNET_JSON_spec_fixed_auto ("salt",
-                                 &pd->salt),
+                                 &salt),
     GNUNET_JSON_spec_end ()
   };
+  json_t *p_cfg;
+  json_t *id_data;
+  const json_t *providers;
 
-  if (MHD_HTTP_OK !=
-      json_integer_value (json_object_get (p_cfg,
-                                           "http_status")))
-    return false; /* skip providers that are down */
   if (GNUNET_OK !=
-      GNUNET_JSON_parse (p_cfg,
+      GNUNET_JSON_parse (arguments,
                          spec,
                          NULL, NULL))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "No salt for `%s', provider offline?\n",
-                provider_url);
-    GNUNET_free (pd);
-    return false;
+    GNUNET_break (0);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           NULL);
+    return NULL;
   }
-  pd->backend_url = GNUNET_strdup (provider_url);
-  pd->rss = rss;
-  pd->recovery = ANASTASIS_recovery_begin (ANASTASIS_REDUX_ctx_,
-                                           rss->id_data,
-                                           rss->have_version
-                                           ? rss->version
-                                           : 0,
-                                           pd->backend_url,
-                                           &pd->salt,
-                                           &policy_lookup_cb,
-                                           pd,
-                                           &core_early_secret_cb,
-                                           pd);
-  if (NULL != pd->recovery)
+  providers = json_object_get (state,
+                               "authentication_providers");
+  if ( (NULL == providers) ||
+       (! json_is_object (providers)) )
   {
-    GNUNET_CONTAINER_DLL_insert (rss->pd_head,
-                                 rss->pd_tail,
-                                 pd);
-    return true;
+    GNUNET_break (0);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "'authentication_providers' missing");
+    return NULL;
   }
-  GNUNET_free (pd->backend_url);
-  GNUNET_free (pd);
-  return false;
-}
-
-
-/**
- * We finished downloading /config from all providers, merge
- * into the main state, trigger the continuation and free our
- * state.
- *
- * @param[in] rss main state to merge into
- */
-static void
-providers_complete (struct RecoverSecretState *rss)
-{
-  bool launched = false;
-  struct RecoveryStartStateProviderEntry *pe;
-  json_t *tlist;
-
-  tlist = json_object_get (rss->state,
-                           "authentication_providers");
-  if (NULL == tlist)
+  p_cfg = json_object_get (providers,
+                           provider_url);
+  if (MHD_HTTP_OK !=
+      json_integer_value (json_object_get (p_cfg,
+                                           "http_status")))
   {
-    tlist = json_object ();
-    GNUNET_assert (NULL != tlist);
-    GNUNET_assert (0 ==
-                   json_object_set_new (rss->state,
-                                        "authentication_providers",
-                                        tlist));
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "selected provider is not online");
+    return NULL;
   }
-  while (NULL != (pe = rss->pe_head))
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (p_cfg,
+                         pspec,
+                         NULL, NULL))
   {
-    json_t *provider_list;
-
-    GNUNET_CONTAINER_DLL_remove (rss->pe_head,
-                                 rss->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);
+    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;
   }
-
-  /* now iterate over providers and begin downloading */
-  if (NULL != rss->provider_url)
+  id_data = json_object_get (state,
+                             "identity_attributes");
+  if (NULL == id_data)
   {
-    json_t *p_cfg;
-
-    p_cfg = json_object_get (tlist,
-                             rss->provider_url);
-    if (NULL != p_cfg)
-      launched = launch_recovery (rss,
-                                  rss->provider_url,
-                                  p_cfg);
+    GNUNET_break (0); /* should be impossible for well-formed state */
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "'identity_attributes' missing");
+    return NULL;
   }
-  else
   {
-    json_t *p_cfg;
-    const char *provider_url;
+    struct PolicyDownloadEntry *pd = GNUNET_new (struct PolicyDownloadEntry);
 
-    json_object_foreach (tlist, provider_url, p_cfg)
+    pd->backend_url = GNUNET_strdup (provider_url);
+    pd->recovery = ANASTASIS_recovery_begin (ANASTASIS_REDUX_ctx_,
+                                             id_data,
+                                             version,
+                                             pd->backend_url,
+                                             &salt,
+                                             &policy_lookup_cb,
+                                             pd,
+                                             &core_early_secret_cb,
+                                             pd);
+    if (NULL == pd->recovery)
     {
-      launched |= launch_recovery (rss,
-                                   provider_url,
-                                   p_cfg);
+      GNUNET_break (0);
+      ANASTASIS_redux_fail_ (cb,
+                             cb_cls,
+                             TALER_EC_ANASTASIS_REDUCER_INTERNAL_ERROR,
+                             NULL);
+      return NULL;
     }
-  }
-  if (! launched)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "No provider online, need user to specify different 
provider!\n");
-    return_no_policy (rss,
-                      true);
-    return;
+    pd->ra.cleanup = &free_pd;
+    pd->ra.cleanup_cls = pd;
+    return &pd->ra;
   }
 }
 
 
 /**
- * Function called when the complete information about a provider
- * was added to @a new_state.
+ * The user wants us to add another provider. Download /config.
  *
- * @param cls a `struct RecoveryStartStateProviderEntry`
- * @param error error code
- * @param new_state resulting new state
+ * @param[in] state we are in
+ * @param arguments our arguments with the solution
+ * @param cb function to call with the new state
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel challenge selection step
  */
-static void
-provider_added_cb (void *cls,
-                   enum TALER_ErrorCode error,
-                   json_t *new_state)
+static struct ANASTASIS_ReduxAction *
+add_provider (json_t *state,
+              const json_t *arguments,
+              ANASTASIS_ActionCallback cb,
+              void *cb_cls)
 {
-  struct RecoveryStartStateProviderEntry *pe = cls;
-
-  pe->ra = NULL;
-  pe->istate = json_incref (new_state);
-  pe->ec = error;
-  pe->rss->pending--;
-  if (0 == pe->rss->pending)
-    providers_complete (pe->rss);
+  const char *provider_url;
+  struct GNUNET_JSON_Specification spec[] = {
+    GNUNET_JSON_spec_string ("provider_url",
+                             &provider_url),
+    GNUNET_JSON_spec_end ()
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (arguments,
+                         spec,
+                         NULL, NULL))
+  {
+    GNUNET_break (0);
+    ANASTASIS_redux_fail_ (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);
 }
 
 
 /**
- * Start to query provider for recovery document.
+ * Signature of callback function that implements a state transition.
  *
- * @param[in,out] rss overall recovery state
- * @param provider_url base URL of the provider to query
+ *  @param state current state
+ *  @param arguments arguments for the state transition
+ *  @param cb function to call when done
+ *  @param cb_cls closure for @a cb
  */
-static void
-begin_query_provider (struct RecoverSecretState *rss,
-                      const char *provider_url)
+typedef struct ANASTASIS_ReduxAction *
+(*DispatchHandler)(json_t *state,
+                   const json_t *arguments,
+                   ANASTASIS_ActionCallback cb,
+                   void *cb_cls);
+
+
+struct ANASTASIS_ReduxAction *
+ANASTASIS_recovery_action_ (json_t *state,
+                            const char *action,
+                            const json_t *arguments,
+                            ANASTASIS_ActionCallback cb,
+                            void *cb_cls)
 {
-  struct RecoveryStartStateProviderEntry *pe;
-  json_t *istate;
-
-  pe = GNUNET_new (struct RecoveryStartStateProviderEntry);
-  pe->rss = rss;
-  istate = json_object ();
-  GNUNET_assert (NULL != istate);
-  GNUNET_CONTAINER_DLL_insert (rss->pe_head,
-                               rss->pe_tail,
-                               pe);
-  pe->ra = ANASTASIS_REDUX_add_provider_to_state_ (provider_url,
-                                                   istate,
-                                                   &provider_added_cb,
-                                                   pe);
-  json_decref (istate);
-  if (NULL != pe->ra)
-    rss->pending++;
+  struct Dispatcher
+  {
+    enum ANASTASIS_RecoveryState recovery_state;
+    const char *recovery_action;
+    DispatchHandler fun;
+  } dispatchers[] = {
+    {
+      ANASTASIS_RECOVERY_STATE_SECRET_SELECTING,
+      "add_provider",
+      &add_provider
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_SECRET_SELECTING,
+      "next",
+      &done_secret_selecting
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_SECRET_SELECTING,
+      "back",
+      &ANASTASIS_back_generic_decrement_
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
+      "select_challenge",
+      &select_challenge
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
+      "poll",
+      &poll_challenges
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
+      "back",
+      &ANASTASIS_back_generic_decrement_
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING,
+      "pay",
+      &pay_challenge
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING,
+      "back",
+      &ANASTASIS_back_generic_decrement_
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING,
+      "solve_challenge",
+      &solve_challenge
+    },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING,
+      "back",
+      &back_challenge_solving
+    },
+    { ANASTASIS_RECOVERY_STATE_INVALID, NULL, NULL }
+  };
+  const char *s = json_string_value (json_object_get (state,
+                                                      "recovery_state"));
+  enum ANASTASIS_RecoveryState rs;
+
+  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;
+  }
+  for (unsigned int i = 0; NULL != dispatchers[i].fun; i++)
+  {
+    if ( (rs == dispatchers[i].recovery_state) &&
+         (0 == strcmp (action,
+                       dispatchers[i].recovery_action)) )
+    {
+      return dispatchers[i].fun (state,
+                                 arguments,
+                                 cb,
+                                 cb_cls);
+    }
+  }
+  ANASTASIS_redux_fail_ (cb,
+                         cb_cls,
+                         TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
+                         action);
+  return NULL;
 }
 
 
@@ -2888,12 +2576,8 @@ ANASTASIS_REDUX_recovery_challenge_begin_ (json_t *state,
                                            ANASTASIS_ActionCallback cb,
                                            void *cb_cls)
 {
-  json_t *version;
-  json_t *mask;
-  json_t *providers;
-  const json_t *attributes;
-  struct RecoverSecretState *rss;
-  const char *provider_url;
+  const json_t *providers;
+  json_t *attributes;
 
   providers = json_object_get (state,
                                "authentication_providers");
@@ -2919,70 +2603,13 @@ ANASTASIS_REDUX_recovery_challenge_begin_ (json_t 
*state,
                            "'identity_attributes' missing");
     return NULL;
   }
-  rss = GNUNET_new (struct RecoverSecretState);
-  rss->id_data = json_incref ((json_t *) attributes);
-  version = json_object_get (arguments,
-                             "version");
-  if (NULL != version)
-  {
-    rss->version = (unsigned int) json_integer_value (version);
-    rss->have_version = true;
-  }
-  mask = json_object_get (arguments,
-                          "mask");
-  if (NULL != mask)
-  {
-    rss->mask = (unsigned int) json_integer_value (mask);
-    rss->have_mask = true;
-  }
-  rss->state = json_incref (state);
-  rss->cb = cb;
-  rss->cb_cls = cb_cls;
-  rss->pending = 1; /* decremented after initialization loop */
-
-  provider_url = json_string_value (json_object_get (arguments,
-                                                     "provider_url"));
-  if (NULL != provider_url)
-  {
-    rss->provider_url = GNUNET_strdup (provider_url);
-    begin_query_provider (rss,
-                          provider_url);
-  }
-  else
-  {
-    json_t *prov;
-    const char *url;
-
-    json_object_foreach (providers, url, prov) {
-      bool disabled = false;
-      struct GNUNET_JSON_Specification spec[] = {
-        GNUNET_JSON_spec_mark_optional (
-          GNUNET_JSON_spec_bool ("disabled",
-                                 &disabled)),
-        GNUNET_JSON_spec_end ()
-      };
-
-      if (GNUNET_OK !=
-          GNUNET_JSON_parse (prov,
-                             spec,
-                             NULL, NULL))
-      {
-        /* skip malformed provider entry */
-        GNUNET_break_op (0);
-        continue;
-      }
-      begin_query_provider (rss,
-                            url);
-    }
-  }
-  rss->pending--;
-  if (0 == rss->pending)
-  {
-    providers_complete (rss);
-    if (NULL == rss->cb)
-      return NULL;
-  }
-  rss->ra.cleanup = &free_rss;
-  rss->ra.cleanup_cls = rss;
-  return &rss->ra;
+  json_object_set (state,
+                   "identity_attributes",
+                   attributes);
+  set_state (state,
+             ANASTASIS_RECOVERY_STATE_SECRET_SELECTING);
+  cb (cb_cls,
+      TALER_EC_NONE,
+      state);
+  return NULL;
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]