gnunet-svn
[Top][All Lists]
Advanced

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

[taler-anastasis] branch master updated: clean up state machine in redux


From: gnunet
Subject: [taler-anastasis] branch master updated: clean up state machine in redux
Date: Sat, 06 Mar 2021 22:54:56 +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 f445071  clean up state machine in redux
f445071 is described below

commit f445071568a63e489ee7098f5512b1662a32d7c5
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Mar 6 22:54:54 2021 +0100

    clean up state machine in redux
---
 ...tasis_reducer_recovery_enter_user_attributes.sh |  11 +-
 src/lib/anastasis_recovery.c                       |  12 +-
 src/reducer/anastasis_api_recovery_redux.c         | 511 +++++++++++++++++++--
 3 files changed, 502 insertions(+), 32 deletions(-)

diff --git a/src/cli/test_anastasis_reducer_recovery_enter_user_attributes.sh 
b/src/cli/test_anastasis_reducer_recovery_enter_user_attributes.sh
index 1419048..dcd9098 100755
--- a/src/cli/test_anastasis_reducer_recovery_enter_user_attributes.sh
+++ b/src/cli/test_anastasis_reducer_recovery_enter_user_attributes.sh
@@ -397,7 +397,7 @@ echo -n "Running challenge logic ..."
 UUID0=`jq -r -e .recovery_information.challenges[0].uuid < $R2FILE`
 UUID1=`jq -r -e .recovery_information.challenges[1].uuid < $R2FILE`
 
-valgrind anastasis-reducer -a \
+anastasis-reducer -a \
   "$(jq -n '
     {
         uuid: $UUID
@@ -422,6 +422,15 @@ anastasis-reducer -a \
   )" \
   solve_challenge < $R1FILE > $R2FILE
 
+anastasis-reducer -a \
+  "$(jq -n '
+    {
+        uuid: $UUID
+    }' \
+    --arg UUID "$UUID1"
+  )" \
+  select_challenge < $R2FILE > $R1FILE
+
 anastasis-reducer -a \
   "$(jq -n '
     {
diff --git a/src/lib/anastasis_recovery.c b/src/lib/anastasis_recovery.c
index d90c24f..7b3fdf9 100644
--- a/src/lib/anastasis_recovery.c
+++ b/src/lib/anastasis_recovery.c
@@ -1030,9 +1030,15 @@ parse_cs_array (struct ANASTASIS_Recovery *r,
     c->ci.type = c->type;
     c->instructions = GNUNET_strdup (instructions);
     c->ci.instructions = c->instructions;
-    if (NULL != json_object_get (cs,
-                                 "key_share"))
-      c->ci.solved = true;
+    {
+      json_t *ks;
+
+      ks = json_object_get (cs,
+                            "key_share");
+      if ( (NULL != ks) &&
+           (! json_is_null (ks)) )
+        c->ci.solved = true;
+    }
   }
 
   return GNUNET_OK;
diff --git a/src/reducer/anastasis_api_recovery_redux.c 
b/src/reducer/anastasis_api_recovery_redux.c
index 2872506..bc24be4 100644
--- a/src/reducer/anastasis_api_recovery_redux.c
+++ b/src/reducer/anastasis_api_recovery_redux.c
@@ -141,6 +141,11 @@ struct SelectChallengeContext
    * recovered.
    */
   struct GNUNET_SCHEDULER_Task *delayed_report;
+
+  /**
+   * Payment secret, if we are in the "pay" state.
+   */
+  struct ANASTASIS_PaymentSecretP ps;
 };
 
 
@@ -519,6 +524,7 @@ run_challenge_cb (void *cls,
                                  &ps),
     GNUNET_JSON_spec_end ()
   };
+  json_t *challenge;
 
   if (NULL == ri)
   {
@@ -532,42 +538,38 @@ run_challenge_cb (void *cls,
   }
 
   /* Check if we got a payment_secret */
+  challenge = find_challenge_in_ri (sctx->state,
+                                    &sctx->uuid);
+  if (NULL == challenge)
   {
-    json_t *challenge = find_challenge_in_ri (sctx->state,
-                                              &sctx->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;
+  }
+  if (NULL !=
+      json_object_get (challenge,
+                       "payment_secret"))
+  {
+    if (GNUNET_OK !=
+        GNUNET_JSON_parse (sctx->args,
+                           spec,
+                           NULL, NULL))
     {
       GNUNET_break_op (0);
       ANASTASIS_redux_fail_ (sctx->cb,
                              sctx->cb_cls,
                              TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
-                             "challenge not found");
+                             "'payment_secret' malformed");
       sctx_free (sctx);
       return;
     }
-    if (NULL !=
-        json_object_get (challenge,
-                         "payment_secret"))
-    {
-      if (GNUNET_OK !=
-          GNUNET_JSON_parse (sctx->args,
-                             spec,
-                             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;
   }
 
-
   for (unsigned int i = 0; i<ri->cs_len; i++)
   {
     struct ANASTASIS_Challenge *ci = ri->cs[i];
@@ -575,6 +577,15 @@ run_challenge_cb (void *cls,
     int ret;
 
     cd = ANASTASIS_challenge_get_details (ci);
+    if (cd->solved)
+    {
+      ANASTASIS_redux_fail_ (sctx->cb,
+                             sctx->cb_cls,
+                             TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                             "Selected challenge already solved");
+      sctx_free (sctx);
+      return;
+    }
     if (0 ==
         GNUNET_memcmp (&sctx->uuid,
                        &cd->uuid))
@@ -596,6 +607,11 @@ run_challenge_cb (void *cls,
           sctx_free (sctx);
           return;
         }
+        /* persist answer, in case payment is required */
+        GNUNET_assert (0 ==
+                       json_object_set (challenge,
+                                        "answer",
+                                        janswer));
         ret = ANASTASIS_challenge_answer (ci,
                                           psp,
                                           answer,
@@ -676,6 +692,126 @@ run_challenge_cb (void *cls,
 }
 
 
+/**
+ * Callback which passes back the recovery document and its possible
+ * policies. Also passes back the version of the document for the user
+ * to check.
+ *
+ * We find the selected challenge and try to answer it (or begin
+ * the process).
+ *
+ * @param cls a `struct SelectChallengeContext *`
+ * @param ri recovery information struct which contains the policies
+ */
+static void
+pay_challenge_cb (void *cls,
+                  const struct ANASTASIS_RecoveryInformation *ri)
+{
+  struct SelectChallengeContext *sctx = cls;
+  json_t *challenge;
+
+  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);
+    return;
+  }
+
+  challenge = find_challenge_in_ri (sctx->state,
+                                    &sctx->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;
+  }
+  /* 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)));
+
+  for (unsigned int i = 0; i<ri->cs_len; i++)
+  {
+    struct ANASTASIS_Challenge *ci = ri->cs[i];
+    const struct ANASTASIS_ChallengeDetails *cd;
+    int ret;
+
+    cd = ANASTASIS_challenge_get_details (ci);
+    if (cd->solved)
+    {
+      ANASTASIS_redux_fail_ (sctx->cb,
+                             sctx->cb_cls,
+                             TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                             "Selected challenge already solved");
+      sctx_free (sctx);
+      return;
+    }
+
+    if (0 ==
+        GNUNET_memcmp (&sctx->uuid,
+                       &cd->uuid))
+    {
+      if (0 == strcmp ("question",
+                       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)
+        {
+          ANASTASIS_redux_fail_ (sctx->cb,
+                                 sctx->cb_cls,
+                                 TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                                 "'answer' missing");
+          sctx_free (sctx);
+          return;
+        }
+        ret = ANASTASIS_challenge_answer (ci,
+                                          &sctx->ps,
+                                          answer,
+                                          &answer_feedback_cb,
+                                          sctx);
+      }
+      else
+      {
+        ret = ANASTASIS_challenge_start (ci,
+                                         &sctx->ps,
+                                         NULL, /* no answer yet */
+                                         &answer_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);
+        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);
+}
+
+
 /**
  * The user selected a challenge to be solved. Begin the solving
  * process.
@@ -691,6 +827,322 @@ run_challenge (json_t *state,
                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 ()
+  };
+
+  if (NULL == arguments)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments missing");
+    return NULL;
+  }
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (state,
+                         spec,
+                         NULL, NULL))
+  {
+    ANASTASIS_redux_fail_ (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)
+  {
+    GNUNET_break_op (0);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "run_challenge");
+    return NULL;
+  }
+  sctx->cb = cb;
+  sctx->cb_cls = cb_cls;
+  sctx->state = json_incref (state);
+  sctx->args = json_incref ((json_t*) arguments);
+  sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_,
+                                            rd,
+                                            &run_challenge_cb,
+                                            sctx,
+                                            &core_secret_cb,
+                                            sctx);
+  if (NULL == sctx->r)
+  {
+    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");
+    return NULL;
+  }
+  sctx->ra.cleanup = &sctx_free;
+  sctx->ra.cleanup_cls = sctx;
+  return &sctx->ra;
+}
+
+
+/**
+ * The user selected a challenge to be solved. Handle the payment
+ * process.
+ *
+ * @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 *
+pay_challenge (json_t *state,
+               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 GNUNET_JSON_Specification aspec[] = {
+    GNUNET_JSON_spec_fixed_auto ("payment_secret",
+                                 &sctx->ps),
+    GNUNET_JSON_spec_end ()
+  };
+
+  if (NULL == arguments)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments missing");
+    return NULL;
+  }
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (arguments,
+                         aspec,
+                         NULL, NULL))
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "'payment_secret' missing");
+    return NULL;
+  }
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (state,
+                         spec,
+                         NULL, NULL))
+  {
+    ANASTASIS_redux_fail_ (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)
+  {
+    GNUNET_break_op (0);
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                           "pay_challenge");
+    return NULL;
+  }
+  sctx->cb = cb;
+  sctx->cb_cls = cb_cls;
+  sctx->state = json_incref (state);
+  sctx->args = json_incref ((json_t*) arguments);
+  sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_,
+                                            rd,
+                                            &pay_challenge_cb,
+                                            sctx,
+                                            &core_secret_cb,
+                                            sctx);
+  if (NULL == sctx->r)
+  {
+    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");
+    return NULL;
+  }
+  sctx->ra.cleanup = &sctx_free;
+  sctx->ra.cleanup_cls = sctx;
+  return &sctx->ra;
+}
+
+
+/**
+ * Callback which passes back the recovery document and its possible
+ * policies. Also passes back the version of the document for the user
+ * to check.
+ *
+ * We find the selected challenge and try to answer it (or begin
+ * the process).
+ *
+ * @param cls a `struct SelectChallengeContext *`
+ * @param ri recovery information struct which contains the policies
+ */
+static void
+select_challenge_cb (void *cls,
+                     const struct ANASTASIS_RecoveryInformation *ri)
+{
+  struct SelectChallengeContext *sctx = cls;
+  const struct ANASTASIS_PaymentSecretP *psp = NULL;
+  struct ANASTASIS_PaymentSecretP ps;
+  struct GNUNET_JSON_Specification spec[] = {
+    GNUNET_JSON_spec_fixed_auto ("payment_secret",
+                                 &ps),
+    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);
+    return;
+  }
+
+  /* Check if we got a payment_secret */
+  {
+    json_t *challenge = find_challenge_in_ri (sctx->state,
+                                              &sctx->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;
+    }
+    if (NULL !=
+        json_object_get (challenge,
+                         "payment_secret"))
+    {
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (sctx->args,
+                             spec,
+                             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;
+    }
+  }
+
+  for (unsigned int i = 0; i<ri->cs_len; i++)
+  {
+    struct ANASTASIS_Challenge *ci = ri->cs[i];
+    const struct ANASTASIS_ChallengeDetails *cd;
+    int ret;
+
+    cd = ANASTASIS_challenge_get_details (ci);
+    if (cd->solved)
+    {
+      ANASTASIS_redux_fail_ (sctx->cb,
+                             sctx->cb_cls,
+                             TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                             "Selected challenge already solved");
+      sctx_free (sctx);
+      return;
+    }
+    if (0 ==
+        GNUNET_memcmp (&sctx->uuid,
+                       &cd->uuid))
+    {
+      GNUNET_assert (
+        0 ==
+        json_object_set_new (sctx->state,
+                             "selected_challenge_uuid",
+                             GNUNET_JSON_from_data_auto (&cd->uuid)));
+      if (0 == strcmp ("question",
+                       cd->type))
+      {
+        /* security question, immediately request user to answer it */
+        set_state (sctx->state,
+                   ANASTASIS_RECOVERY_STATE_CHALLENGE_SOLVING);
+        sctx->cb (sctx->cb_cls,
+                  TALER_EC_NONE,
+                  sctx->state);
+        sctx_free (sctx);
+        return;
+      }
+      /* trigger challenge */
+      ret = ANASTASIS_challenge_start (ci,
+                                       psp,
+                                       NULL, /* no answer */
+                                       &answer_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);
+        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);
+}
+
+
+/**
+ * The user selected a challenge to be solved. Begin the solving
+ * process.
+ *
+ * @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 *
+select_challenge (json_t *state,
+                  const json_t *arguments,
+                  ANASTASIS_ActionCallback cb,
+                  void *cb_cls)
 {
   struct SelectChallengeContext *sctx
     = GNUNET_new (struct SelectChallengeContext);
@@ -737,7 +1189,7 @@ run_challenge (json_t *state,
   sctx->args = json_incref ((json_t*) arguments);
   sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_,
                                             rd,
-                                            &run_challenge_cb,
+                                            &select_challenge_cb,
                                             sctx,
                                             &core_secret_cb,
                                             sctx);
@@ -776,6 +1228,9 @@ back_challenge_solving (json_t *state,
                         void *cb_cls)
 {
   (void) arguments;
+  GNUNET_assert (0 ==
+                 json_object_del (state,
+                                  "selected_challenge_uuid"));
   set_state (state,
              ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING);
   cb (cb_cls,
@@ -828,7 +1283,7 @@ ANASTASIS_recovery_action_ (json_t *state,
     {
       ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
       "select_challenge",
-      &run_challenge
+      &select_challenge
     },
     {
       ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
@@ -838,7 +1293,7 @@ ANASTASIS_recovery_action_ (json_t *state,
     {
       ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING,
       "pay",
-      &run_challenge
+      &pay_challenge
     },
     {
       ANASTASIS_RECOVERY_STATE_CHALLENGE_PAYING,

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