gnunet-svn
[Top][All Lists]
Advanced

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

[taler-anastasis] branch master updated: -implement 'poll' transition in


From: gnunet
Subject: [taler-anastasis] branch master updated: -implement 'poll' transition in state machine
Date: Thu, 19 Aug 2021 14:43:43 +0200

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 677c7e8  -implement 'poll' transition in state machine
677c7e8 is described below

commit 677c7e87a5da584e68194c9cca19a91191c3140c
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Aug 19 14:43:39 2021 +0200

    -implement 'poll' transition in state machine
---
 doc/sphinx/reducer.rst                     | 228 ++++++++++++++++-------------
 src/include/anastasis.h                    |   8 +-
 src/lib/anastasis_recovery.c               |   8 +-
 src/reducer/anastasis_api_recovery_redux.c | 165 ++++++++++++++++++++-
 4 files changed, 307 insertions(+), 102 deletions(-)

diff --git a/doc/sphinx/reducer.rst b/doc/sphinx/reducer.rst
index e5f1699..68df5b1 100644
--- a/doc/sphinx/reducer.rst
+++ b/doc/sphinx/reducer.rst
@@ -1459,121 +1459,139 @@ that applications must all handle. States other than 
``solved`` are:
           }
         }
 
-    - **body**: Here, the server provided an HTTP reply for
-      how to solve the challenge, but the reducer could not parse
-      them into a known format. A mime-type may be provided and may
-      help parse the details.
+   - **body**: Here, the server provided an HTTP reply for
+     how to solve the challenge, but the reducer could not parse
+     them into a known format. A mime-type may be provided and may
+     help parse the details.
 
-      .. code-block:: json
+     .. code-block:: json
 
-         {
-           "recovery_state": "CHALLENGE_SOLVING",
-           "recovery_information": {
-               "...": "..."
-           }
-           "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
-           "challenge_feedback": {
-             "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
-               "state": "body",
-               "body": "CROCKFORDBASE32ENCODEDBODY",
-               "http_status": 403,
-               "mime_type" : "anything/possible"
-             }
-           }
-         }
+        {
+          "recovery_state": "CHALLENGE_SOLVING",
+          "recovery_information": {
+              "...": "..."
+          }
+          "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+          "challenge_feedback": {
+            "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+              "state": "body",
+              "body": "CROCKFORDBASE32ENCODEDBODY",
+              "http_status": 403,
+              "mime_type" : "anything/possible"
+            }
+          }
+        }
 
-    - **hint**: Here, the server provided human-readable hint for
-      how to solve the challenge.  Note that the ``hint`` provided this
-      time is from the Anastasis provider and may differ from the 
``instructions``
-      for the challenge under ``recovery_information``:
+   - **hint**: Here, the server provided human-readable hint for
+     how to solve the challenge.  Note that the ``hint`` provided this
+     time is from the Anastasis provider and may differ from the 
``instructions``
+     for the challenge under ``recovery_information``:
 
-      .. code-block:: json
+     .. code-block:: json
 
-         {
-           "recovery_state": "CHALLENGE_SOLVING",
-           "recovery_information": {
-               "...": "..."
-           }
-           "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
-           "challenge_feedback": {
-             "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
-               "state": "hint",
-               "hint": "Recovery TAN send to email mail@DOMAIN",
-               "http_status": 403
-             }
+        {
+          "recovery_state": "CHALLENGE_SOLVING",
+          "recovery_information": {
+              "...": "..."
+          }
+          "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+          "challenge_feedback": {
+            "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+              "state": "hint",
+              "hint": "Recovery TAN send to email mail@DOMAIN",
+              "http_status": 403
+            }
+          }
+        }
+
+   - **details**: Here, the server provided a detailed JSON status response
+     related to solving the challenge:
+
+     .. code-block:: json
+
+       {
+         "recovery_state": "CHALLENGE_SOLVING",
+         "recovery_information": {
+            "...": "..."
+         }
+         "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+         "challenge_feedback": {
+           "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+             "state": "details",
+             "details": {
+               "code": 8111,
+               "hint": "The client's response to the challenge was invalid.",
+               "detail" : null
+             },
+             "http_status": 403
            }
          }
+       }
 
-    - **details**: Here, the server provided a detailed JSON status response
-      related to solving the challenge:
+   - **redirect**: To solve the challenge, the user must visit the indicated
+     Web site at ``redirect_url``, for example to perform video authentication:
 
-      .. code-block:: json
+    .. code-block:: json
 
-         {
-           "recovery_state": "CHALLENGE_SOLVING",
-           "recovery_information": {
-               "...": "..."
-           }
-           "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
-           "challenge_feedback": {
-             "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
-               "state": "details",
-               "details": {
-                 "code": 8111,
-                 "hint": "The client's response to the challenge was invalid.",
-                 "detail" : null
-               },
-               "http_status": 403
-             }
+       {
+         "recovery_state": "CHALLENGE_SOLVING",
+         "recovery_information": {
+            "...": "..."
+         }
+         "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+         "challenge_feedback": {
+           "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+             "state": "redirect",
+             "redirect_url": "https://videoconf.example.com/";,
+             "http_status": 303
            }
          }
+       }
 
-     - **redirect**: To solve the challenge, the user must visit the indicated
-       Web site at ``redirect_url``, for example to perform video 
authentication:
+   - **server-failure**: This indicates that the Anastasis provider encountered
+     a failure and recovery using this challenge cannot proceed at this time.
+     Examples for failures might be that the provider is unable to send SMS
+     messages at this time due to an outage.  The body includes details about
+     the failure. The user may try again later or continue with other 
challenges.
 
-      .. code-block:: json
+     .. code-block:: json
 
-         {
-           "recovery_state": "CHALLENGE_SOLVING",
-           "recovery_information": {
-               "...": "..."
-           }
-           "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
-           "challenge_feedback": {
-             "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
-               "state": "redirect",
-               "redirect_url": "https://videoconf.example.com/";,
-               "http_status": 303
-             }
-           }
+       {
+         "recovery_state": "CHALLENGE_SELECTING",
+         "recovery_information": {
+             "...": "..."
          }
+         "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+         "challenge_feedback": {
+           "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+            "state": "server-failure",
+            "http_status": "500",
+            "error_code": 52
+          }
+        }
+      }
 
-      - **server-failure**: This indicates that the Anastasis provider 
encountered
-        a failure and recovery using this challenge cannot proceed at this 
time.
-        Examples for failures might be that the provider is unable to send SMS
-        messages at this time due to an outage.  The body includes details 
about
-        the failure. The user may try again later or continue with other 
challenges.
+    - **truth-unknown**: This indicates that the Anastasis provider is unaware 
of
+      the specified challenge. This is typically a permanent failure, and user
+      interfaces should not allow users to re-try this challenge.
 
       .. code-block:: json
 
-         {
-           "recovery_state": "CHALLENGE_SELECTING",
-           "recovery_information": {
-               "...": "..."
-           }
-           "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
-           "challenge_feedback": {
-             "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
-               "state": "server-failure",
-               "http_status": "500",
-               "error_code": 52
-             }
-           }
-         }
+        {
+          "recovery_state": "CHALLENGE_SELECTING",
+          "recovery_information": {
+              "...": "..."
+          }
+          "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+          "challenge_feedback": {
+            "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
+              "state": "truth-unknown",
+              "error_code": 8108
+            }
+          }
+        }
 
-      - **truth-unknown**: This indicates that the Anastasis provider is 
unaware of
-        the specified challenge. This is typically a permanent failure, and 
user
-        interfaces should not allow users to re-try this challenge.
+    - **rate-limit-exceeded**:
 
       .. code-block:: json
 
@@ -1585,13 +1603,13 @@ that applications must all handle. States other than 
``solved`` are:
            "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
            "challenge_feedback": {
              "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
-               "state": "truth-unknown",
-               "error_code": 8108
+               "state": "rate-limit-exceeded",
+               "error_code": 8121
              }
            }
          }
 
-      - **rate-limit-exceeded**:
+    - **authentication-timeout**:
 
       .. code-block:: json
 
@@ -1603,12 +1621,24 @@ that applications must all handle. States other than 
``solved`` are:
            "selected_challenge_uuid": 
"TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
            "challenge_feedback": {
              "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
-               "state": "rate-limit-exceeded",
-               "error_code": 8121
+               "state": "authentication-timeout",
+               "error_code": 8122
              }
            }
          }
 
+
+**poll:**
+
+With a ``poll`` transition, the application indicates that it wants to wait 
longer for one or more of the challenges that are in state 
``authentication-timeout`` to possibly complete.  While technically optional, 
the ``timeout`` argument should really be provided to enable long-polling, for 
example:
+
+.. code-block:: json
+
+    {
+        "timeout" : { "d_ms" : 5000 },
+    }
+
+
 **pay:**
 
 With a ``pay`` transition, the application indicates to the reducer that
diff --git a/src/include/anastasis.h b/src/include/anastasis.h
index 8443eb6..3027e2a 100644
--- a/src/include/anastasis.h
+++ b/src/include/anastasis.h
@@ -71,10 +71,16 @@ struct ANASTASIS_ChallengeDetails
   const char *instructions;
 
   /**
-   * true if challenged was already solved, else false.
+   * true if challenge was already solved, else false.
    */
   bool solved;
 
+  /**
+   * true if challenge is awaiting asynchronous
+   * resolution by the user.
+   */
+  bool async;
+
 };
 
 
diff --git a/src/lib/anastasis_recovery.c b/src/lib/anastasis_recovery.c
index 4e23db0..623e882 100644
--- a/src/lib/anastasis_recovery.c
+++ b/src/lib/anastasis_recovery.c
@@ -348,6 +348,7 @@ keyshare_lookup_cb (void *cls,
           = dd->details.server_failure.http_status
       };
 
+      c->ci.async = true;
       c->af (c->af_cls,
              &csr);
       return;
@@ -1043,7 +1044,9 @@ ANASTASIS_recovery_serialize (const struct 
ANASTASIS_Recovery *r)
       GNUNET_JSON_pack_string ("instructions",
                                c->instructions),
       GNUNET_JSON_pack_bool ("solved",
-                             c->ci.solved));
+                             c->ci.solved),
+      GNUNET_JSON_pack_bool ("async",
+                             c->ci.async));
     GNUNET_assert (0 ==
                    json_array_append_new (cs_arr,
                                           cs));
@@ -1118,6 +1121,9 @@ parse_cs_array (struct ANASTASIS_Recovery *r,
                                    &c->provider_salt),
       GNUNET_JSON_spec_string ("type",
                                &escrow_type),
+      GNUNET_JSON_spec_mark_optional (
+        GNUNET_JSON_spec_bool ("async",
+                               &c->ci.async)),
       GNUNET_JSON_spec_mark_optional (
         GNUNET_JSON_spec_fixed_auto ("key_share",
                                      &c->key_share)),
diff --git a/src/reducer/anastasis_api_recovery_redux.c 
b/src/reducer/anastasis_api_recovery_redux.c
index fab3c24..95632cc 100644
--- a/src/reducer/anastasis_api_recovery_redux.c
+++ b/src/reducer/anastasis_api_recovery_redux.c
@@ -151,6 +151,13 @@ struct SelectChallengeContext
    * Payment secret, if we are in the "pay" state.
    */
   struct ANASTASIS_PaymentSecretP ps;
+
+  /**
+   * Application asked us to only poll for existing
+   * asynchronous challenges, and not to being a
+   * new one.
+   */
+  bool poll_only;
 };
 
 
@@ -741,7 +748,6 @@ solve_challenge_cb (void *cls,
                                  &ps),
     GNUNET_JSON_spec_end ()
   };
-
   json_t *challenge;
 
   if (NULL == ri)
@@ -769,6 +775,80 @@ solve_challenge_cb (void *cls,
     return;
   }
 
+  /* resume all async, unsolved challenges */
+  {
+    bool poll_started = false;
+
+    for (unsigned int i = 0; i<ri->cs_len; i++)
+    {
+      struct ANASTASIS_Challenge *ci = ri->cs[i];
+      const struct ANASTASIS_ChallengeDetails *cd;
+      json_t *challenge;
+      json_t *pin;
+
+      cd = ANASTASIS_challenge_get_details (ci);
+      if (cd->solved ||
+          (! cd->async) )
+        continue;
+
+      challenge = find_challenge_in_ri (sctx->state,
+                                        &cd->uuid);
+      if (NULL == challenge)
+      {
+        GNUNET_break_op (0);
+        ANASTASIS_redux_fail_ (sctx->cb,
+                               sctx->cb_cls,
+                               TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                               "challenge not found");
+        sctx_free (sctx);
+        return;
+      }
+      pin = json_object_get (challenge,
+                             "answer-pin");
+      if (! json_is_integer (pin))
+      {
+        GNUNET_break_op (0);
+        ANASTASIS_redux_fail_ (sctx->cb,
+                               sctx->cb_cls,
+                               TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
+                               "async challenge 'answer-pin' not found");
+        sctx_free (sctx);
+        return;
+      }
+      if (GNUNET_OK !=
+          ANASTASIS_challenge_answer2 (ci,
+                                       psp,
+                                       timeout,
+                                       json_integer_value (pin),
+                                       &answer_feedback_cb,
+                                       sctx))
+      {
+        ANASTASIS_redux_fail_ (sctx->cb,
+                               sctx->cb_cls,
+                               TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+                               "Failed to begin answering asynchronous 
challenge");
+        sctx_free (sctx);
+        return;
+      }
+      poll_started = true;
+    }
+
+    if (sctx->poll_only)
+    {
+      if (! poll_started)
+      {
+        GNUNET_break_op (0);
+        ANASTASIS_redux_fail_ (sctx->cb,
+                               sctx->cb_cls,
+                               TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
+                               "no challenge available for polling");
+        return;
+      }
+      /* only polling, do not start new challenges */
+      return;
+    }
+  } /* end resuming async challenges */
+
   /* Check if we got a payment_secret */
   challenge = find_challenge_in_ri (sctx->state,
                                     &sctx->uuid);
@@ -823,6 +903,7 @@ solve_challenge_cb (void *cls,
     psp = &ps;
   }
 
+  /* start or solve selected challenge */
   for (unsigned int i = 0; i<ri->cs_len; i++)
   {
     struct ANASTASIS_Challenge *ci = ri->cs[i];
@@ -830,6 +911,8 @@ solve_challenge_cb (void *cls,
     int ret;
 
     cd = ANASTASIS_challenge_get_details (ci);
+    if (cd->async)
+      continue; /* handled above */
     if (0 !=
         GNUNET_memcmp (&sctx->uuid,
                        &cd->uuid))
@@ -883,6 +966,12 @@ solve_challenge_cb (void *cls,
       {
         uint64_t ianswer = json_integer_value (pin);
 
+        /* persist answer, in case async processing
+           happens via poll */
+        GNUNET_assert (0 ==
+                       json_object_set (challenge,
+                                        "answer-pin",
+                                        pin));
         ret = ANASTASIS_challenge_answer2 (ci,
                                            psp,
                                            timeout,
@@ -1152,6 +1241,75 @@ solve_challenge (json_t *state,
 }
 
 
+/**
+ * The user asked for us to poll on pending
+ * asynchronous challenges to see if they have
+ * now completed / been satisfied.
+ *
+ * @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 *
+poll_challenges (json_t *state,
+                 const json_t *arguments,
+                 ANASTASIS_ActionCallback cb,
+                 void *cb_cls)
+{
+  struct SelectChallengeContext *sctx
+    = GNUNET_new (struct SelectChallengeContext);
+  json_t *rd;
+
+  if (NULL == arguments)
+  {
+    ANASTASIS_redux_fail_ (cb,
+                           cb_cls,
+                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                           "arguments 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,
+                           "poll_challenges");
+    return NULL;
+  }
+  sctx->poll_only = true;
+  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,
+                                            &solve_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.
@@ -1710,6 +1868,11 @@ ANASTASIS_recovery_action_ (json_t *state,
       "select_challenge",
       &select_challenge
     },
+    {
+      ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
+      "poll",
+      &poll_challenges
+    },
     {
       ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
       "back",

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