gnunet-svn
[Top][All Lists]
Advanced

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

[taler-anastasis] branch master updated: fix diversity calculation


From: gnunet
Subject: [taler-anastasis] branch master updated: fix diversity calculation
Date: Thu, 18 Feb 2021 11:43:59 +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 0492831  fix diversity calculation
0492831 is described below

commit 0492831bfb456064477da25b04470c26ee43f96d
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Feb 18 11:43:56 2021 +0100

    fix diversity calculation
---
 src/reducer/anastasis_api_backup_redux.c | 943 +++++++++++++++++++------------
 1 file changed, 592 insertions(+), 351 deletions(-)

diff --git a/src/reducer/anastasis_api_backup_redux.c 
b/src/reducer/anastasis_api_backup_redux.c
index 175061d..e3e533d 100644
--- a/src/reducer/anastasis_api_backup_redux.c
+++ b/src/reducer/anastasis_api_backup_redux.c
@@ -1,6 +1,6 @@
 /*
   This file is part of Anastasis
-  Copyright (C) 2020 Taler Systems SA
+  Copyright (C) 2020, 2021 Taler Systems SA
 
   Anastasis is free software; you can redistribute it and/or modify it under 
the
   terms of the GNU Lesser General Public License as published by the Free 
Software
@@ -262,37 +262,6 @@ typedef struct ANASTASIS_ReduxAction *
                    void *cb_cls);
 
 
-// FIXME: this function should die
-static const char *
-get_provider_url_from_id (const char *id,
-                          json_t *state)
-{
-  const char *key;
-  json_t *method;
-  json_t *methods = json_object_get (state,
-                                     "authentication_providers");
-
-  json_object_foreach (methods, key, method)
-  {
-    GNUNET_assert (json_is_array (method));
-    json_t *method_data;
-    size_t index;
-
-    json_array_foreach (method, index, method_data)
-    {
-      json_t *provider_id = json_object_get (method_data, id);
-      if (NULL == provider_id)
-        continue;
-
-      const char *url = json_string_value (json_object_get (provider_id,
-                                                            "provider_url"));
-      return url;
-    }
-  }
-  return NULL;
-}
-
-
 /**
  * Update the 'backup_state' field of @a state to @a new_backup_state.
  *
@@ -333,6 +302,83 @@ ANASTASIS_backup_start (const struct 
GNUNET_CONFIGURATION_Handle *cfg)
 }
 
 
+/**
+ * DispatchHandler/Callback function which is called for a
+ * "add_provider" action.  Adds another Anastasis provider
+ * to the list of available providers for storing information.
+ *
+ * @param state state to operate on
+ * @param arguments arguments with a provider URL to add
+ * @param cb callback (#DispatchHandler) to call during/after operation
+ * @param cb_cls callback closure
+ */
+static struct ANASTASIS_ReduxAction *
+add_provider (json_t *state,
+              const json_t *arguments,
+              ANASTASIS_ActionCallback cb,
+              void *cb_cls)
+{
+  json_t *urls;
+  json_t *tlist;
+
+  tlist = json_object_get (state,
+                           "authentication_providers");
+  if (NULL == tlist)
+  {
+    tlist = json_object ();
+    GNUNET_assert (NULL != tlist);
+    GNUNET_assert (0 ==
+                   json_object_set_new (state,
+                                        "authentication_providers",
+                                        tlist));
+  }
+
+  if (NULL == arguments)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments missing");
+    return NULL;
+  }
+  urls = json_object_get (arguments,
+                          "urls");
+  if (NULL == urls)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'urls' missing");
+    return NULL;
+  }
+  {
+    size_t index;
+    json_t *url;
+
+    json_array_foreach (urls, index, url)
+    {
+      const char *url_str = json_string_value (url);
+
+      if (NULL == url_str)
+      {
+        ANASTASIS_redux_fail_ (cb,
+                               cb_cls,
+                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                               "'urls' must be strings");
+        return NULL;
+      }
+      GNUNET_assert (json_object_set_new (tlist,
+                                          url_str,
+                                          json_object ()));
+    }
+  }
+  return ANASTASIS_REDUX_backup_begin_ (state,
+                                        arguments,
+                                        cb,
+                                        cb_cls);
+}
+
+
 /**
  * DispatchHandler/Callback function which is called for a
  * "add_authentication" action.
@@ -350,64 +396,193 @@ add_authentication (json_t *state,
                     ANASTASIS_ActionCallback cb,
                     void *cb_cls)
 {
-  json_t *auth_providers = json_object_get (state,
-                                            "authentication_providers");
+  json_t *auth_providers;
+  json_t *method;
+  const char *method_type;
 
-  GNUNET_assert (NULL != auth_providers);
-  json_t *method = json_object_get (arguments, "authentication_method");
+  auth_providers = json_object_get (state,
+                                    "authentication_providers");
+
+  if (NULL == auth_providers)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "'authentication_providers' missing");
+    return NULL;
+  }
 
+  method = json_object_get (arguments,
+                            "authentication_method");
   if (NULL == method)
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Authentication method required!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'authentication_method' required");
     return NULL;
   }
-  const char *method_type = json_string_value (json_object_get (method,
-                                                                "method"));
-  if (! json_object_get (auth_providers,
-                         method_type))
+  method_type = json_string_value (json_object_get (method,
+                                                    "method"));
+  if (NULL == method_type)
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               
TALER_EC_ANASTASIS_REDUCER_AUTHENTICATION_METHOD_NOT_SUPPORTED,
-                               "hint",
-                               "Authentication method not supported!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_AUTHENTICATION_METHOD_NOT_SUPPORTED,
-        error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'method' field must be a valid string");
     return NULL;
   }
   if (! json_object_get (method,
                          "data"))
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Authentication data missing!");
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'data' field missing for authorization method");
+    return NULL;
+  }
+  /* Check we know at least one provider that supports this method */
+  {
+    bool found = false;
+    json_t *details;
+    const char *url;
+
+    json_object_foreach (auth_providers, url, details)
+    {
+      json_t *methods;
+      json_t *method;
+      size_t index;
+
+      methods = json_object_get (details,
+                                 "methods");
+      if (NULL == methods)
+      {
+        GNUNET_break (0);
+        continue;
+      }
+      json_array_foreach (methods, index, method)
+      {
+        const char *name;
+
+        name = json_string_value (json_object_get (method,
+                                                   "name"));
+        GNUNET_break (NULL != name);
+        if ( (NULL != name) &&
+             (0 == strcmp (name,
+                           method_type)) )
+        {
+          found = true;
+          break;
+        }
+      }
+      if (found)
+        break;
+    }
+    if (! found)
+    {
+      ANASTASIS_redux_fail_ (cb,
+                             cb_cls,
+                             
TALER_EC_ANASTASIS_REDUCER_AUTHENTICATION_METHOD_NOT_SUPPORTED,
+                             method_type);
+      return NULL;
+    }
+  }
+
+  /* append provided method to our array */
+  {
+    json_t *auth_method_arr;
+
+    auth_method_arr = json_object_get (state,
+                                       "authentication_methods");
+    if (! json_is_array (auth_method_arr))
+    {
+      ANASTASIS_redux_fail_ (cb,
+                             cb_cls,
+                             TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                             "'authentication_methods' must be an array");
+      return NULL;
+    }
+    if (NULL == auth_method_arr)
+    {
+      auth_method_arr = json_array ();
+      GNUNET_assert (0 == json_object_set_new (state,
+                                               "authentication_methods",
+                                               auth_method_arr));
+    }
+    GNUNET_assert (0 ==
+                   json_array_append (auth_method_arr,
+                                      method));
     cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
+        TALER_EC_NONE,
+        state);
+  }
+  return NULL;
+}
+
+
+/**
+ * DispatchHandler/Callback function which is called for a
+ * "del_authentication" action.
+ * Returns an #ANASTASIS_ReduxAction if operation is async.
+ *
+ * @param state state to operate on
+ * @param arguments arguments to use for operation on state
+ * @param cb callback (#DispatchHandler) to call during/after operation
+ * @param cb_cls callback closure
+ * @return NULL
+ */
+static struct ANASTASIS_ReduxAction *
+del_authentication (json_t *state,
+                    const json_t *arguments,
+                    ANASTASIS_ActionCallback cb,
+                    void *cb_cls)
+{
+  json_t *idx;
+  json_t *auth_method_arr;
+
+  auth_method_arr = json_object_get (state,
+                                     "authentication_methods");
+  if (! json_is_array (auth_method_arr))
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "'authentication_methods' must be an array");
     return NULL;
   }
-  json_t *auth_method_arr = json_object_get (state,
-                                             "authentication_methods");
-  if (NULL == auth_method_arr)
-    auth_method_arr = json_array ();
-  GNUNET_assert (json_is_array (auth_method_arr));
-  GNUNET_assert (0 == json_array_append_new (auth_method_arr, method));
-  GNUNET_assert (0 == json_object_set (state,
-                                       "authentication_methods",
-                                       auth_method_arr));
+  if (NULL == arguments)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments missing");
+    return NULL;
+  }
+  idx = json_object_get (arguments,
+                         "auth_method_index");
+  if ( (NULL == idx) ||
+       (! json_is_integer (idx)) )
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'auth_method_index' must be a number");
+    return NULL;
+  }
+
+  {
+    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;
+    }
+  }
   cb (cb_cls,
       TALER_EC_NONE,
       state);
@@ -415,104 +590,214 @@ add_authentication (json_t *state,
 }
 
 
+/* ********************** done_authentication ******************** */
+
+/**
+ * Information for running done_authentication() logic.
+ */
 struct PolicyBuilder
 {
-  json_t *providers;
-  json_t *methods;
+  /**
+   * Financial cost of the providers selected in @e best_sel.
+   * Only valid during the go_with() function.
+   */
+  struct TALER_Amount best_cost;
+
+  /**
+   * Authentication providers available overall, from our state.
+   */
+  const json_t *providers;
+
+  /**
+   * Authentication methods available overall, from our state.
+   */
+  const json_t *methods;
+
+  /**
+   * Array of authentication policies to be computed.
+   */
   json_t *policies;
-  unsigned int num_methods;
-  unsigned int req_methods;
 
+  /**
+   * Currency we are using.
+   */
+  const char *currency;
 
-  const unsigned int *m_idx;
+  /**
+   * Array of length @e req_methods.
+   */
+  unsigned int *m_idx;
 
+  /**
+   * Array of length @e req_methods identifying a set of providers selected
+   * for each authentication method, while we are trying to compute the
+   * 'best' allocation of providers to authentication methods.
+   * Only valid during the go_with() function.
+   */
   unsigned int *best_sel;
 
+  /**
+   * Error hint to return on failure. Set if @e ec is not #TALER_EC_NONE.
+   */
+  const char *hint;
+
+  /**
+   * Overall number of challenges provided by the user.
+   */
+  unsigned int num_methods;
+
+  /**
+   * Number of challenges that must be satisfied to recover the secret.
+   * Derived from the total number of challenges entered by the user.
+   */
+  unsigned int req_methods;
+
+  /**
+   * Number of different Anastasis providers selected in @e best_sel.
+   * Only valid during the go_with() function.
+   */
   unsigned int best_diversity;
-  struct TALER_Amount best_cost;
 
-  const char *currency;
+  /**
+   * Error code to return, #TALER_EC_NONE on success.
+   */
+  enum TALER_ErrorCode ec;
+
 };
 
 
+/**
+ * Evaluate the cost/benefit of the provider selection in @a prov_sel
+ * and if it is better then the best known one in @a pb, update @a pb.
+ *
+ * @param[in,out] pb our operational context
+ * @param[in,out] prov_sel array of req_methods provider indices to complete
+ */
 static void
 eval_provider_selection (struct PolicyBuilder *pb,
                          const unsigned int *prov_sel)
 {
-  bool better = true;
-  unsigned int curr_diversity = 0;
   struct TALER_Amount curr_cost;
+  unsigned int curr_diversity;
 
+  /* most hold here, as invariant passed earlier in go_with() */
   GNUNET_assert (GNUNET_OK ==
                  TALER_amount_get_zero (pb->currency,
                                         &curr_cost));
 
-  // calculate cost
+  /* calculate cost */
   for (unsigned int i = 0; i < pb->req_methods; i++)
   {
-    json_t *method_obj = json_array_get (pb->methods,
-                                         pb->m_idx[i]);
+    const json_t *method_obj = json_array_get (pb->methods,
+                                               pb->m_idx[i]);
     const char *method_name = json_string_value (json_object_get (method_obj,
                                                                   "method"));
-    json_t *method_providers = json_object_get (pb->providers,
-                                                method_name);
-    json_t *provider_obj = json_array_get (method_providers,
-                                           prov_sel[i]);
-    void *provider_obj_iter = json_object_iter (provider_obj);
-    const char *provider_name = json_object_iter_key (provider_obj_iter);
-    struct TALER_Amount method_cost;
-    json_t *provider_data = json_object_get (provider_obj, provider_name);
+    const json_t *provider_obj = json_array_get (pb->providers,
+                                                 prov_sel[i]);
+    json_t *provider_methods = json_object_get (provider_obj,
+                                                "methods");
+    json_t *md;
+    size_t index;
+    bool found = false;
 
-    GNUNET_assert (GNUNET_OK ==
-                   TALER_string_to_amount (
-                     json_string_value (json_object_get (provider_data,
-                                                         "method_cost")),
-                     &method_cost));
-    if (0 >
-        TALER_amount_add (&curr_cost,
-                          &curr_cost,
-                          &method_cost))
+    if (NULL == provider_methods)
     {
-      GNUNET_break (0);
+      pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID;
+      pb->hint = "'methods' of provider not found";
+      return;
+    }
+    json_array_foreach (provider_methods, index, md)
+    {
+      const char *name;
+      struct TALER_Amount method_cost;
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_string ("name",
+                                 &name),
+        TALER_JSON_spec_amount ("usage_fee",
+                                &method_cost),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (md,
+                             spec,
+                             NULL, NULL))
+      {
+        pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID;
+        pb->hint = "'methods' of provider";
+        return;
+      }
+      if (0 == strcmp (name,
+                       method_name))
+      {
+        if ( (GNUNET_YES !=
+              TALER_amount_cmp_currency (&curr_cost,
+                                         &method_cost)) ||
+             (0 >
+              TALER_amount_add (&curr_cost,
+                                &curr_cost,
+                                &method_cost)) )
+        {
+          GNUNET_break (0);
+          pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID;
+          pb->hint = "'usage_fee' addition failure";
+          return;
+        }
+        found = true;
+      }
+    }
+    if (! found)
+    {
+      /* Provider does not OFFER this method, combination not possible.
+         Cost is basically 'infinite', but we simply then skip this. */
       return;
     }
   }
 
-  // calculate provider diversity
-  unsigned int *tmp_arr;
+  /* calculate provider diversity by counting number of different providers 
selected */
+  curr_diversity = 0;
   for (unsigned int i = 0; i < pb->req_methods; i++)
   {
-    for (unsigned int j = 0; j < curr_diversity; j++)
+    bool found = false;
+
+    for (unsigned int j = 0; j < i; j++)
     {
-      if (curr_diversity == 0)
+      if (prov_sel[i] == prov_sel[j])
       {
-        GNUNET_array_append (tmp_arr, curr_diversity, prov_sel[i]);
+        found = true;
         break;
       }
-      if (tmp_arr[j] == prov_sel[i])
-        break;
-      GNUNET_array_append (tmp_arr, curr_diversity, prov_sel[i]);
     }
+    if (! found)
+      curr_diversity++;
   }
-
   if (curr_diversity < pb->best_diversity)
-    better = false;
-  else if ((GNUNET_YES == TALER_amount_cmp_currency (&curr_cost,
-                                                     &pb->best_cost))
-           && (0 < TALER_amount_cmp (&curr_cost, &pb->best_cost)))
-    better = false;
-
-  if (better)
-  {
-    memcpy (pb->best_sel,
-            prov_sel,
-            sizeof (unsigned int) * pb->req_methods);
-    pb->best_diversity = curr_diversity;
-    pb->best_cost = curr_cost;
-  }
+    return;
+  if ( (GNUNET_YES ==
+        TALER_amount_cmp_currency (&curr_cost,
+                                   &pb->best_cost)) &&
+       (0 < TALER_amount_cmp (&curr_cost,
+                              &pb->best_cost)) )
+    return;
+  memcpy (pb->best_sel,
+          prov_sel,
+          sizeof (unsigned int) * pb->req_methods);
+  pb->best_diversity = curr_diversity;
+  pb->best_cost = curr_cost;
 }
 
 
+/**
+ * Recursively compute possible combination(s) of provider candidates
+ * in @e prov_sel. The selection is complete up to index @a i.  Calls
+ * eval_provider_selection() upon a feasible provider selection for
+ * evaluation, resulting in "better" combinations being persisted in
+ * @a pb.
+ *
+ * @param[in,out] pb our operational context
+ * @param[in,out] prov_sel array of req_methods provider indices to complete
+ * @param i index up to which @a prov_sel is already initialized
+ */
 static void
 provider_candidate (struct PolicyBuilder *pb,
                     unsigned int *prov_sel,
@@ -521,10 +806,7 @@ provider_candidate (struct PolicyBuilder *pb,
   json_t *method_obj;
   const char *method_name;
   json_t *method_providers;
-  unsigned int start = 0;
-
-  if (i > 0)
-    start = prov_sel[i - 1] + 1;
+  size_t num_prov;
 
   method_obj = json_array_get (pb->methods,
                                pb->m_idx[i]);
@@ -532,14 +814,16 @@ provider_candidate (struct PolicyBuilder *pb,
                                                     "method"));
   method_providers = json_object_get (pb->providers,
                                       method_name);
-  size_t num_prov = json_array_size (method_providers);
-  for (size_t j = start; j < num_prov; j++)
+  num_prov = json_array_size (method_providers);
+  for (size_t j = 0; j < num_prov; j++)
   {
     prov_sel[i] = j;
     if (i == pb->req_methods - 1)
     {
       eval_provider_selection (pb,
                                prov_sel);
+      if (TALER_EC_NONE != pb->ec)
+        break;
       continue;
     }
     provider_candidate (pb,
@@ -549,29 +833,42 @@ provider_candidate (struct PolicyBuilder *pb,
 }
 
 
+/**
+ * Using the selection of authentication methods from @a pb in
+ * "m_idx", compute the best choice of providers.
+ *
+ * @param[in,out] pb our operational context
+ */
 static void
-go_with (struct PolicyBuilder *pb,
-         const unsigned int *m_idx)
+go_with (struct PolicyBuilder *pb)
 {
+  const unsigned int *m_idx = pb->m_idx;
   struct TALER_Amount recovery_cost;
   unsigned int best_sel[pb->req_methods];
   unsigned int prov_sel[pb->req_methods];
+  json_t *method_arr;
 
+  /* compute best provider selection (store in best_sel) */
   pb->best_diversity = 0;
   pb->best_sel = best_sel;
-  pb->m_idx = m_idx;
-
   provider_candidate (pb,
                       prov_sel,
                       0);
+  if (GNUNET_OK !=
+      TALER_amount_get_zero (pb->currency,
+                             &recovery_cost))
+  {
+    pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID;
+    pb->hint = "'currency' invalid";
+    return;
+  }
 
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_get_zero (pb->currency,
-                                        &recovery_cost));
-
-  json_t *method_arr = json_array ();
+  /* Convert best_sel to entry in 'policies' array */
+  method_arr = json_array ();
+  GNUNET_assert (NULL != method_arr);
   for (unsigned int i = 0; i < pb->req_methods; i++)
   {
+    // FIXME: ugly!
     json_t *method_obj = json_array_get (pb->methods,
                                          m_idx[i]);
     const char *method_name = json_string_value (json_object_get (method_obj,
@@ -604,20 +901,34 @@ go_with (struct PolicyBuilder *pb,
       return;
     }
   }
-  json_t *policy = json_pack ("{s:o, s:o}",
-                              "recovery_cost",
-                              TALER_JSON_from_amount (&recovery_cost),
-                              "methods", method_arr);
-  json_array_append_new (pb->policies, policy);
+  {
+    json_t *policy = json_pack ("{s:o, s:o}",
+                                "recovery_cost",
+                                TALER_JSON_from_amount (&recovery_cost),
+                                "methods",
+                                method_arr);
+    GNUNET_assert (NULL != policy);
+    GNUNET_assert (0 ==
+                   json_array_append_new (pb->policies,
+                                          policy));
+  }
 }
 
 
+/**
+ * Recursively computes all possible subsets of length "req_methods"
+ * from an array of length "num_methods", calling "go_with" on each of
+ * those subsets (in "m_idx").
+ *
+ * @param[in,out] pb our operational context
+ * @param i offset up to which the "m_idx" has been computed
+ */
 static void
 method_candidate (struct PolicyBuilder *pb,
-                  unsigned int *m_idx,
                   unsigned int i)
 {
   unsigned int start = 0;
+  unsigned int *m_idx = pb->m_idx;
 
   if (i > 0)
     start = m_idx[i - 1] + 1;
@@ -626,13 +937,11 @@ method_candidate (struct PolicyBuilder *pb,
     m_idx[i] = j;
     if (i == pb->req_methods - 1)
     {
-      go_with (pb,
-               m_idx);
+      go_with (pb);
     }
     else
     {
       method_candidate (pb,
-                        m_idx,
                         i + 1);
     }
   }
@@ -641,8 +950,9 @@ method_candidate (struct PolicyBuilder *pb,
 
 /**
  * DispatchHandler/Callback function which is called for a
- * "done_authentication" action.
- * Returns an #ANASTASIS_ReduxAction if operation is async.
+ * "done_authentication" action.  Automaticially computes policies
+ * based on available Anastasis providers and challenges provided by
+ * the user.
  *
  * @param state state to operate on
  * @param arguments arguments to use for operation on state
@@ -656,21 +966,54 @@ done_authentication (json_t *state,
                      ANASTASIS_ActionCallback cb,
                      void *cb_cls)
 {
-  struct PolicyBuilder pb;
+  struct PolicyBuilder pb = {
+    .ec = TALER_EC_NONE
+  };
 
   pb.currency = json_string_value (json_object_get (state,
                                                     "currency"));
+  if (NULL == pb.currency)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "'currency' must be provided");
+    return NULL;
+  }
   pb.providers = json_object_get (state,
                                   "authentication_providers");
+  if ( (NULL == pb.providers) ||
+       (! json_is_array (pb.providers) ) ||
+       (0 == json_array_size (pb.providers)) )
+  {
+    ANASTASIS_redux_fail_ (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)) )
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "'authentication_methods' must be provided");
+    return NULL;
+  }
   pb.policies = json_array ();
   pb.num_methods = json_array_size (pb.methods);
   switch (pb.num_methods)
   {
   case 0:
-    // FAIL
-    break;
+    json_decref (pb.policies);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "'authentication_methods' must not be empty");
+    return NULL;
   case 1:
   case 2:
     pb.req_methods = pb.num_methods;
@@ -679,81 +1022,41 @@ done_authentication (json_t *state,
   case 4:
     pb.req_methods = pb.num_methods - 1;
     break;
-  default:
+  case 5:
+  case 6:
     pb.req_methods = pb.num_methods - 2;
     break;
+  case 7:
+    pb.req_methods = pb.num_methods - 3;
+    break;
+  default:
+    pb.req_methods = pb.num_methods / 2;
+    break;
   }
   {
     unsigned int m_idx[pb.req_methods];
 
     /* select req_methods from num_methods. */
+    pb.m_idx = m_idx;
     method_candidate (&pb,
-                      m_idx,
                       0);
   }
-  GNUNET_assert (0 == json_object_set_new (state,
-                                           "policies",
-                                           pb.policies));
-  set_state (state,
-             ANASTASIS_BACKUP_STATE_POLICIES_REVIEWING);
-  cb (cb_cls,
-      TALER_EC_NONE,
-      state);
-  return NULL;
-}
-
-
-/**
- * DispatchHandler/Callback function which is called for a
- * "del_authentication" action.
- * Returns an #ANASTASIS_ReduxAction if operation is async.
- *
- * @param state state to operate on
- * @param arguments arguments to use for operation on state
- * @param cb callback (#DispatchHandler) to call during/after operation
- * @param cb_cls callback closure
- * @return NULL
- */
-static struct ANASTASIS_ReduxAction *
-del_authentication (json_t *state,
-                    const json_t *arguments,
-                    ANASTASIS_ActionCallback cb,
-                    void *cb_cls)
-{
-  if (NULL == arguments)
-  {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Arguments missing!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
-    return NULL;
-  }
-  size_t index = (size_t) json_integer_value (
-    json_object_get (arguments,
-                     "auth_method_index"));
-  json_t *auth_method_arr = json_object_get (state,
-                                             "authentication_methods");
 
-  GNUNET_assert (json_is_array (auth_method_arr));
-  if (0 != json_array_remove (auth_method_arr, index))
+  if (TALER_EC_NONE != pb.ec)
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
-                               "hint",
-                               "Operation failed");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
-        error);
+    json_decref (pb.policies);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           pb.ec,
+                           pb.hint);
     return NULL;
   }
-
+  GNUNET_assert (0 ==
+                 json_object_set_new (state,
+                                      "policies",
+                                      pb.policies));
+  set_state (state,
+             ANASTASIS_BACKUP_STATE_POLICIES_REVIEWING);
   cb (cb_cls,
       TALER_EC_NONE,
       state);
@@ -761,6 +1064,13 @@ del_authentication (json_t *state,
 }
 
 
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+
 /**
  * DispatchHandler/Callback function which is called for a
  * "add_policy" action.
@@ -780,15 +1090,10 @@ add_policy (json_t *state,
 {
   if (NULL == arguments)
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Arguments missing!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments missing");
     return NULL;
   }
 
@@ -809,15 +1114,10 @@ add_policy (json_t *state,
                                        "policy");
   if (! json_is_array (arg_array))
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Policy is malformed!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'policy' not an array");
     return NULL;
   }
   GNUNET_assert (GNUNET_OK ==
@@ -915,15 +1215,10 @@ del_policy (json_t *state,
 {
   if (NULL == arguments)
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Arguments missing!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments missing");
     return NULL;
   }
 
@@ -936,15 +1231,10 @@ del_policy (json_t *state,
   GNUNET_assert (json_is_array (policy_arr));
   if (0 != json_array_remove (policy_arr, index))
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               
TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
-                               "hint",
-                               "Operation failed");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
-        error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID_FOR_STATE,
+                           "removal failed");
     return NULL;
   }
   cb (cb_cls,
@@ -1235,6 +1525,37 @@ initialize_payment_details (json_t *state,
 }
 
 
+// FIXME: this function should die
+static const char *
+get_provider_url_from_id (const char *id,
+                          json_t *state)
+{
+  const char *key;
+  json_t *method;
+  json_t *methods = json_object_get (state,
+                                     "authentication_providers");
+
+  json_object_foreach (methods, key, method)
+  {
+    GNUNET_assert (json_is_array (method));
+    json_t *method_data;
+    size_t index;
+
+    json_array_foreach (method, index, method_data)
+    {
+      json_t *provider_id = json_object_get (method_data, id);
+      if (NULL == provider_id)
+        continue;
+
+      const char *url = json_string_value (json_object_get (provider_id,
+                                                            "provider_url"));
+      return url;
+    }
+  }
+  return NULL;
+}
+
+
 /**
  * Initialize policies for recovery document.
  *
@@ -1930,16 +2251,10 @@ enter_secret (json_t *state,
 
   if (NULL == arguments)
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Arguments missing!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
-    json_decref (error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments missing");
     return NULL;
   }
   GNUNET_assert (NULL != state);
@@ -1947,16 +2262,10 @@ enter_secret (json_t *state,
   if ((NULL == json_object_get (arguments,"secret"))
       || (NULL == json_object_get (arguments, "type")))
   {
-    json_t *error = json_pack ("{s:I, s:s}",
-                               "code",
-                               (json_int_t)
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "hint",
-                               "Secret is malformed!");
-    cb (cb_cls,
-        TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-        error);
-    json_decref (error);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'secret' malformed");
     return NULL;
   }
   GNUNET_assert (0 ==
@@ -2036,6 +2345,15 @@ pay_backup (json_t *state,
 }
 
 
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+
 /**
  * DispatchHandler/Callback function which is called for a
  * "back" action if state is "FINISHED".
@@ -2061,83 +2379,6 @@ back_finished (json_t *state,
 }
 
 
-/**
- * DispatchHandler/Callback function which is called for a
- * "add_provider" action.  Adds another Anastasis provider
- * to the list of available providers for storing information.
- *
- * @param state state to operate on
- * @param arguments arguments with a provider URL to add
- * @param cb callback (#DispatchHandler) to call during/after operation
- * @param cb_cls callback closure
- */
-static struct ANASTASIS_ReduxAction *
-add_provider (json_t *state,
-              const json_t *arguments,
-              ANASTASIS_ActionCallback cb,
-              void *cb_cls)
-{
-  json_t *urls;
-  json_t *tlist;
-
-  tlist = json_object_get (state,
-                           "authentication_providers");
-  if (NULL == tlist)
-  {
-    tlist = json_object ();
-    GNUNET_assert (NULL != tlist);
-    GNUNET_assert (0 ==
-                   json_object_set_new (state,
-                                        "authentication_providers",
-                                        tlist));
-  }
-
-  if (NULL == arguments)
-  {
-    ANASTASIS_redux_fail_ (cb,
-                           cb_cls,
-                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                           "arguments missing");
-    return NULL;
-  }
-  urls = json_object_get (arguments,
-                          "urls");
-  if (NULL == urls)
-  {
-    ANASTASIS_redux_fail_ (cb,
-                           cb_cls,
-                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                           "'urls' missing");
-    return NULL;
-  }
-  {
-    size_t index;
-    json_t *url;
-
-    json_array_foreach (urls, index, url)
-    {
-      const char *url_str = json_string_value (url);
-
-      if (NULL == url_str)
-      {
-        ANASTASIS_redux_fail_ (cb,
-                               cb_cls,
-                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                               "'urls' must be strings");
-        return NULL;
-      }
-      GNUNET_assert (json_object_set_new (tlist,
-                                          url_str,
-                                          json_object ()));
-    }
-  }
-  return ANASTASIS_REDUX_backup_begin_ (state,
-                                        arguments,
-                                        cb,
-                                        cb_cls);
-}
-
-
 /**
  * Operates on a backup state depending on given #ANASTASIS_BackupState
  * and #ANASTASIS_BackupAction. The new #ANASTASIS_BackupState is returned

-- 
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]