summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-08-19 14:43:39 +0200
committerChristian Grothoff <christian@grothoff.org>2021-08-19 14:43:39 +0200
commit677c7e87a5da584e68194c9cca19a91191c3140c (patch)
tree33425fd28b6580c29d2f5fd80ab7241a5a643f13 /src
parent4067891ed9f66eb5e47a709d3ea21c2ed36a1e86 (diff)
downloadanastasis-677c7e87a5da584e68194c9cca19a91191c3140c.tar.gz
anastasis-677c7e87a5da584e68194c9cca19a91191c3140c.tar.bz2
anastasis-677c7e87a5da584e68194c9cca19a91191c3140c.zip
-implement 'poll' transition in state machine
Diffstat (limited to 'src')
-rw-r--r--src/include/anastasis.h8
-rw-r--r--src/lib/anastasis_recovery.c8
-rw-r--r--src/reducer/anastasis_api_recovery_redux.c165
3 files changed, 178 insertions, 3 deletions
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));
@@ -1119,6 +1122,9 @@ parse_cs_array (struct ANASTASIS_Recovery *r,
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)),
GNUNET_JSON_spec_end ()
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,
@@ -1153,6 +1242,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.
*
@@ -1712,6 +1870,11 @@ ANASTASIS_recovery_action_ (json_t *state,
},
{
ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
+ "poll",
+ &poll_challenges
+ },
+ {
+ ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING,
"back",
&ANASTASIS_back_generic_decrement_
},