diff options
author | Christian Grothoff <christian@grothoff.org> | 2021-08-19 14:43:39 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-08-19 14:43:39 +0200 |
commit | 677c7e87a5da584e68194c9cca19a91191c3140c (patch) | |
tree | 33425fd28b6580c29d2f5fd80ab7241a5a643f13 | |
parent | 4067891ed9f66eb5e47a709d3ea21c2ed36a1e86 (diff) | |
download | anastasis-677c7e87a5da584e68194c9cca19a91191c3140c.tar.gz anastasis-677c7e87a5da584e68194c9cca19a91191c3140c.zip |
-implement 'poll' transition in state machine
-rw-r--r-- | doc/sphinx/reducer.rst | 228 | ||||
-rw-r--r-- | src/include/anastasis.h | 8 | ||||
-rw-r--r-- | src/lib/anastasis_recovery.c | 8 | ||||
-rw-r--r-- | 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: | |||
1459 | } | 1459 | } |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | - **body**: Here, the server provided an HTTP reply for | 1462 | - **body**: Here, the server provided an HTTP reply for |
1463 | how to solve the challenge, but the reducer could not parse | 1463 | how to solve the challenge, but the reducer could not parse |
1464 | them into a known format. A mime-type may be provided and may | 1464 | them into a known format. A mime-type may be provided and may |
1465 | help parse the details. | 1465 | help parse the details. |
1466 | 1466 | ||
1467 | .. code-block:: json | 1467 | .. code-block:: json |
1468 | 1468 | ||
1469 | { | 1469 | { |
1470 | "recovery_state": "CHALLENGE_SOLVING", | 1470 | "recovery_state": "CHALLENGE_SOLVING", |
1471 | "recovery_information": { | 1471 | "recovery_information": { |
1472 | "...": "..." | 1472 | "...": "..." |
1473 | } | 1473 | } |
1474 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | 1474 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", |
1475 | "challenge_feedback": { | 1475 | "challenge_feedback": { |
1476 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | 1476 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { |
1477 | "state": "body", | 1477 | "state": "body", |
1478 | "body": "CROCKFORDBASE32ENCODEDBODY", | 1478 | "body": "CROCKFORDBASE32ENCODEDBODY", |
1479 | "http_status": 403, | 1479 | "http_status": 403, |
1480 | "mime_type" : "anything/possible" | 1480 | "mime_type" : "anything/possible" |
1481 | } | 1481 | } |
1482 | } | 1482 | } |
1483 | } | 1483 | } |
1484 | 1484 | ||
1485 | - **hint**: Here, the server provided human-readable hint for | 1485 | - **hint**: Here, the server provided human-readable hint for |
1486 | how to solve the challenge. Note that the ``hint`` provided this | 1486 | how to solve the challenge. Note that the ``hint`` provided this |
1487 | time is from the Anastasis provider and may differ from the ``instructions`` | 1487 | time is from the Anastasis provider and may differ from the ``instructions`` |
1488 | for the challenge under ``recovery_information``: | 1488 | for the challenge under ``recovery_information``: |
1489 | 1489 | ||
1490 | .. code-block:: json | 1490 | .. code-block:: json |
1491 | 1491 | ||
1492 | { | 1492 | { |
1493 | "recovery_state": "CHALLENGE_SOLVING", | 1493 | "recovery_state": "CHALLENGE_SOLVING", |
1494 | "recovery_information": { | 1494 | "recovery_information": { |
1495 | "...": "..." | 1495 | "...": "..." |
1496 | } | 1496 | } |
1497 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | 1497 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", |
1498 | "challenge_feedback": { | 1498 | "challenge_feedback": { |
1499 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | 1499 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { |
1500 | "state": "hint", | 1500 | "state": "hint", |
1501 | "hint": "Recovery TAN send to email mail@DOMAIN", | 1501 | "hint": "Recovery TAN send to email mail@DOMAIN", |
1502 | "http_status": 403 | 1502 | "http_status": 403 |
1503 | } | 1503 | } |
1504 | } | ||
1505 | } | ||
1506 | |||
1507 | - **details**: Here, the server provided a detailed JSON status response | ||
1508 | related to solving the challenge: | ||
1509 | |||
1510 | .. code-block:: json | ||
1511 | |||
1512 | { | ||
1513 | "recovery_state": "CHALLENGE_SOLVING", | ||
1514 | "recovery_information": { | ||
1515 | "...": "..." | ||
1516 | } | ||
1517 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | ||
1518 | "challenge_feedback": { | ||
1519 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | ||
1520 | "state": "details", | ||
1521 | "details": { | ||
1522 | "code": 8111, | ||
1523 | "hint": "The client's response to the challenge was invalid.", | ||
1524 | "detail" : null | ||
1525 | }, | ||
1526 | "http_status": 403 | ||
1504 | } | 1527 | } |
1505 | } | 1528 | } |
1529 | } | ||
1506 | 1530 | ||
1507 | - **details**: Here, the server provided a detailed JSON status response | 1531 | - **redirect**: To solve the challenge, the user must visit the indicated |
1508 | related to solving the challenge: | 1532 | Web site at ``redirect_url``, for example to perform video authentication: |
1509 | 1533 | ||
1510 | .. code-block:: json | 1534 | .. code-block:: json |
1511 | 1535 | ||
1512 | { | 1536 | { |
1513 | "recovery_state": "CHALLENGE_SOLVING", | 1537 | "recovery_state": "CHALLENGE_SOLVING", |
1514 | "recovery_information": { | 1538 | "recovery_information": { |
1515 | "...": "..." | 1539 | "...": "..." |
1516 | } | 1540 | } |
1517 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | 1541 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", |
1518 | "challenge_feedback": { | 1542 | "challenge_feedback": { |
1519 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | 1543 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { |
1520 | "state": "details", | 1544 | "state": "redirect", |
1521 | "details": { | 1545 | "redirect_url": "https://videoconf.example.com/", |
1522 | "code": 8111, | 1546 | "http_status": 303 |
1523 | "hint": "The client's response to the challenge was invalid.", | ||
1524 | "detail" : null | ||
1525 | }, | ||
1526 | "http_status": 403 | ||
1527 | } | ||
1528 | } | 1547 | } |
1529 | } | 1548 | } |
1549 | } | ||
1530 | 1550 | ||
1531 | - **redirect**: To solve the challenge, the user must visit the indicated | 1551 | - **server-failure**: This indicates that the Anastasis provider encountered |
1532 | Web site at ``redirect_url``, for example to perform video authentication: | 1552 | a failure and recovery using this challenge cannot proceed at this time. |
1553 | Examples for failures might be that the provider is unable to send SMS | ||
1554 | messages at this time due to an outage. The body includes details about | ||
1555 | the failure. The user may try again later or continue with other challenges. | ||
1533 | 1556 | ||
1534 | .. code-block:: json | 1557 | .. code-block:: json |
1535 | 1558 | ||
1536 | { | 1559 | { |
1537 | "recovery_state": "CHALLENGE_SOLVING", | 1560 | "recovery_state": "CHALLENGE_SELECTING", |
1538 | "recovery_information": { | 1561 | "recovery_information": { |
1539 | "...": "..." | 1562 | "...": "..." |
1540 | } | ||
1541 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | ||
1542 | "challenge_feedback": { | ||
1543 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | ||
1544 | "state": "redirect", | ||
1545 | "redirect_url": "https://videoconf.example.com/", | ||
1546 | "http_status": 303 | ||
1547 | } | ||
1548 | } | ||
1549 | } | 1563 | } |
1564 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | ||
1565 | "challenge_feedback": { | ||
1566 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | ||
1567 | "state": "server-failure", | ||
1568 | "http_status": "500", | ||
1569 | "error_code": 52 | ||
1570 | } | ||
1571 | } | ||
1572 | } | ||
1550 | 1573 | ||
1551 | - **server-failure**: This indicates that the Anastasis provider encountered | 1574 | - **truth-unknown**: This indicates that the Anastasis provider is unaware of |
1552 | a failure and recovery using this challenge cannot proceed at this time. | 1575 | the specified challenge. This is typically a permanent failure, and user |
1553 | Examples for failures might be that the provider is unable to send SMS | 1576 | interfaces should not allow users to re-try this challenge. |
1554 | messages at this time due to an outage. The body includes details about | ||
1555 | the failure. The user may try again later or continue with other challenges. | ||
1556 | 1577 | ||
1557 | .. code-block:: json | 1578 | .. code-block:: json |
1558 | 1579 | ||
1559 | { | 1580 | { |
1560 | "recovery_state": "CHALLENGE_SELECTING", | 1581 | "recovery_state": "CHALLENGE_SELECTING", |
1561 | "recovery_information": { | 1582 | "recovery_information": { |
1562 | "...": "..." | 1583 | "...": "..." |
1563 | } | 1584 | } |
1564 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | 1585 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", |
1565 | "challenge_feedback": { | 1586 | "challenge_feedback": { |
1566 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | 1587 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { |
1567 | "state": "server-failure", | 1588 | "state": "truth-unknown", |
1568 | "http_status": "500", | 1589 | "error_code": 8108 |
1569 | "error_code": 52 | 1590 | } |
1570 | } | 1591 | } |
1571 | } | 1592 | } |
1572 | } | ||
1573 | 1593 | ||
1574 | - **truth-unknown**: This indicates that the Anastasis provider is unaware of | 1594 | - **rate-limit-exceeded**: |
1575 | the specified challenge. This is typically a permanent failure, and user | ||
1576 | interfaces should not allow users to re-try this challenge. | ||
1577 | 1595 | ||
1578 | .. code-block:: json | 1596 | .. code-block:: json |
1579 | 1597 | ||
@@ -1585,13 +1603,13 @@ that applications must all handle. States other than ``solved`` are: | |||
1585 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | 1603 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", |
1586 | "challenge_feedback": { | 1604 | "challenge_feedback": { |
1587 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | 1605 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { |
1588 | "state": "truth-unknown", | 1606 | "state": "rate-limit-exceeded", |
1589 | "error_code": 8108 | 1607 | "error_code": 8121 |
1590 | } | 1608 | } |
1591 | } | 1609 | } |
1592 | } | 1610 | } |
1593 | 1611 | ||
1594 | - **rate-limit-exceeded**: | 1612 | - **authentication-timeout**: |
1595 | 1613 | ||
1596 | .. code-block:: json | 1614 | .. code-block:: json |
1597 | 1615 | ||
@@ -1603,12 +1621,24 @@ that applications must all handle. States other than ``solved`` are: | |||
1603 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", | 1621 | "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0", |
1604 | "challenge_feedback": { | 1622 | "challenge_feedback": { |
1605 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { | 1623 | "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": { |
1606 | "state": "rate-limit-exceeded", | 1624 | "state": "authentication-timeout", |
1607 | "error_code": 8121 | 1625 | "error_code": 8122 |
1608 | } | 1626 | } |
1609 | } | 1627 | } |
1610 | } | 1628 | } |
1611 | 1629 | ||
1630 | |||
1631 | **poll:** | ||
1632 | |||
1633 | 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: | ||
1634 | |||
1635 | .. code-block:: json | ||
1636 | |||
1637 | { | ||
1638 | "timeout" : { "d_ms" : 5000 }, | ||
1639 | } | ||
1640 | |||
1641 | |||
1612 | **pay:** | 1642 | **pay:** |
1613 | 1643 | ||
1614 | With a ``pay`` transition, the application indicates to the reducer that | 1644 | 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 | |||
71 | const char *instructions; | 71 | const char *instructions; |
72 | 72 | ||
73 | /** | 73 | /** |
74 | * true if challenged was already solved, else false. | 74 | * true if challenge was already solved, else false. |
75 | */ | 75 | */ |
76 | bool solved; | 76 | bool solved; |
77 | 77 | ||
78 | /** | ||
79 | * true if challenge is awaiting asynchronous | ||
80 | * resolution by the user. | ||
81 | */ | ||
82 | bool async; | ||
83 | |||
78 | }; | 84 | }; |
79 | 85 | ||
80 | 86 | ||
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, | |||
348 | = dd->details.server_failure.http_status | 348 | = dd->details.server_failure.http_status |
349 | }; | 349 | }; |
350 | 350 | ||
351 | c->ci.async = true; | ||
351 | c->af (c->af_cls, | 352 | c->af (c->af_cls, |
352 | &csr); | 353 | &csr); |
353 | return; | 354 | return; |
@@ -1043,7 +1044,9 @@ ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r) | |||
1043 | GNUNET_JSON_pack_string ("instructions", | 1044 | GNUNET_JSON_pack_string ("instructions", |
1044 | c->instructions), | 1045 | c->instructions), |
1045 | GNUNET_JSON_pack_bool ("solved", | 1046 | GNUNET_JSON_pack_bool ("solved", |
1046 | c->ci.solved)); | 1047 | c->ci.solved), |
1048 | GNUNET_JSON_pack_bool ("async", | ||
1049 | c->ci.async)); | ||
1047 | GNUNET_assert (0 == | 1050 | GNUNET_assert (0 == |
1048 | json_array_append_new (cs_arr, | 1051 | json_array_append_new (cs_arr, |
1049 | cs)); | 1052 | cs)); |
@@ -1119,6 +1122,9 @@ parse_cs_array (struct ANASTASIS_Recovery *r, | |||
1119 | GNUNET_JSON_spec_string ("type", | 1122 | GNUNET_JSON_spec_string ("type", |
1120 | &escrow_type), | 1123 | &escrow_type), |
1121 | GNUNET_JSON_spec_mark_optional ( | 1124 | GNUNET_JSON_spec_mark_optional ( |
1125 | GNUNET_JSON_spec_bool ("async", | ||
1126 | &c->ci.async)), | ||
1127 | GNUNET_JSON_spec_mark_optional ( | ||
1122 | GNUNET_JSON_spec_fixed_auto ("key_share", | 1128 | GNUNET_JSON_spec_fixed_auto ("key_share", |
1123 | &c->key_share)), | 1129 | &c->key_share)), |
1124 | GNUNET_JSON_spec_end () | 1130 | 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 | |||
151 | * Payment secret, if we are in the "pay" state. | 151 | * Payment secret, if we are in the "pay" state. |
152 | */ | 152 | */ |
153 | struct ANASTASIS_PaymentSecretP ps; | 153 | struct ANASTASIS_PaymentSecretP ps; |
154 | |||
155 | /** | ||
156 | * Application asked us to only poll for existing | ||
157 | * asynchronous challenges, and not to being a | ||
158 | * new one. | ||
159 | */ | ||
160 | bool poll_only; | ||
154 | }; | 161 | }; |
155 | 162 | ||
156 | 163 | ||
@@ -741,7 +748,6 @@ solve_challenge_cb (void *cls, | |||
741 | &ps), | 748 | &ps), |
742 | GNUNET_JSON_spec_end () | 749 | GNUNET_JSON_spec_end () |
743 | }; | 750 | }; |
744 | |||
745 | json_t *challenge; | 751 | json_t *challenge; |
746 | 752 | ||
747 | if (NULL == ri) | 753 | if (NULL == ri) |
@@ -769,6 +775,80 @@ solve_challenge_cb (void *cls, | |||
769 | return; | 775 | return; |
770 | } | 776 | } |
771 | 777 | ||
778 | /* resume all async, unsolved challenges */ | ||
779 | { | ||
780 | bool poll_started = false; | ||
781 | |||
782 | for (unsigned int i = 0; i<ri->cs_len; i++) | ||
783 | { | ||
784 | struct ANASTASIS_Challenge *ci = ri->cs[i]; | ||
785 | const struct ANASTASIS_ChallengeDetails *cd; | ||
786 | json_t *challenge; | ||
787 | json_t *pin; | ||
788 | |||
789 | cd = ANASTASIS_challenge_get_details (ci); | ||
790 | if (cd->solved || | ||
791 | (! cd->async) ) | ||
792 | continue; | ||
793 | |||
794 | challenge = find_challenge_in_ri (sctx->state, | ||
795 | &cd->uuid); | ||
796 | if (NULL == challenge) | ||
797 | { | ||
798 | GNUNET_break_op (0); | ||
799 | ANASTASIS_redux_fail_ (sctx->cb, | ||
800 | sctx->cb_cls, | ||
801 | TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, | ||
802 | "challenge not found"); | ||
803 | sctx_free (sctx); | ||
804 | return; | ||
805 | } | ||
806 | pin = json_object_get (challenge, | ||
807 | "answer-pin"); | ||
808 | if (! json_is_integer (pin)) | ||
809 | { | ||
810 | GNUNET_break_op (0); | ||
811 | ANASTASIS_redux_fail_ (sctx->cb, | ||
812 | sctx->cb_cls, | ||
813 | TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, | ||
814 | "async challenge 'answer-pin' not found"); | ||
815 | sctx_free (sctx); | ||
816 | return; | ||
817 | } | ||
818 | if (GNUNET_OK != | ||
819 | ANASTASIS_challenge_answer2 (ci, | ||
820 | psp, | ||
821 | timeout, | ||
822 | json_integer_value (pin), | ||
823 | &answer_feedback_cb, | ||
824 | sctx)) | ||
825 | { | ||
826 | ANASTASIS_redux_fail_ (sctx->cb, | ||
827 | sctx->cb_cls, | ||
828 | TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, | ||
829 | "Failed to begin answering asynchronous challenge"); | ||
830 | sctx_free (sctx); | ||
831 | return; | ||
832 | } | ||
833 | poll_started = true; | ||
834 | } | ||
835 | |||
836 | if (sctx->poll_only) | ||
837 | { | ||
838 | if (! poll_started) | ||
839 | { | ||
840 | GNUNET_break_op (0); | ||
841 | ANASTASIS_redux_fail_ (sctx->cb, | ||
842 | sctx->cb_cls, | ||
843 | TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID, | ||
844 | "no challenge available for polling"); | ||
845 | return; | ||
846 | } | ||
847 | /* only polling, do not start new challenges */ | ||
848 | return; | ||
849 | } | ||
850 | } /* end resuming async challenges */ | ||
851 | |||
772 | /* Check if we got a payment_secret */ | 852 | /* Check if we got a payment_secret */ |
773 | challenge = find_challenge_in_ri (sctx->state, | 853 | challenge = find_challenge_in_ri (sctx->state, |
774 | &sctx->uuid); | 854 | &sctx->uuid); |
@@ -823,6 +903,7 @@ solve_challenge_cb (void *cls, | |||
823 | psp = &ps; | 903 | psp = &ps; |
824 | } | 904 | } |
825 | 905 | ||
906 | /* start or solve selected challenge */ | ||
826 | for (unsigned int i = 0; i<ri->cs_len; i++) | 907 | for (unsigned int i = 0; i<ri->cs_len; i++) |
827 | { | 908 | { |
828 | struct ANASTASIS_Challenge *ci = ri->cs[i]; | 909 | struct ANASTASIS_Challenge *ci = ri->cs[i]; |
@@ -830,6 +911,8 @@ solve_challenge_cb (void *cls, | |||
830 | int ret; | 911 | int ret; |
831 | 912 | ||
832 | cd = ANASTASIS_challenge_get_details (ci); | 913 | cd = ANASTASIS_challenge_get_details (ci); |
914 | if (cd->async) | ||
915 | continue; /* handled above */ | ||
833 | if (0 != | 916 | if (0 != |
834 | GNUNET_memcmp (&sctx->uuid, | 917 | GNUNET_memcmp (&sctx->uuid, |
835 | &cd->uuid)) | 918 | &cd->uuid)) |
@@ -883,6 +966,12 @@ solve_challenge_cb (void *cls, | |||
883 | { | 966 | { |
884 | uint64_t ianswer = json_integer_value (pin); | 967 | uint64_t ianswer = json_integer_value (pin); |
885 | 968 | ||
969 | /* persist answer, in case async processing | ||
970 | happens via poll */ | ||
971 | GNUNET_assert (0 == | ||
972 | json_object_set (challenge, | ||
973 | "answer-pin", | ||
974 | pin)); | ||
886 | ret = ANASTASIS_challenge_answer2 (ci, | 975 | ret = ANASTASIS_challenge_answer2 (ci, |
887 | psp, | 976 | psp, |
888 | timeout, | 977 | timeout, |
@@ -1153,6 +1242,75 @@ solve_challenge (json_t *state, | |||
1153 | 1242 | ||
1154 | 1243 | ||
1155 | /** | 1244 | /** |
1245 | * The user asked for us to poll on pending | ||
1246 | * asynchronous challenges to see if they have | ||
1247 | * now completed / been satisfied. | ||
1248 | * | ||
1249 | * @param[in] state we are in | ||
1250 | * @param arguments our arguments with the solution | ||
1251 | * @param cb functiont o call with the new state | ||
1252 | * @param cb_cls closure for @a cb | ||
1253 | * @return handle to cancel challenge selection step | ||
1254 | */ | ||
1255 | static struct ANASTASIS_ReduxAction * | ||
1256 | poll_challenges (json_t *state, | ||
1257 | const json_t *arguments, | ||
1258 | ANASTASIS_ActionCallback cb, | ||
1259 | void *cb_cls) | ||
1260 | { | ||
1261 | struct SelectChallengeContext *sctx | ||
1262 | = GNUNET_new (struct SelectChallengeContext); | ||
1263 | json_t *rd; | ||
1264 | |||
1265 | if (NULL == arguments) | ||
1266 | { | ||
1267 | ANASTASIS_redux_fail_ (cb, | ||
1268 | cb_cls, | ||
1269 | TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID, | ||
1270 | "arguments missing"); | ||
1271 | return NULL; | ||
1272 | } | ||
1273 | rd = json_object_get (state, | ||
1274 | "recovery_document"); | ||
1275 | if (NULL == rd) | ||
1276 | { | ||
1277 | GNUNET_break_op (0); | ||
1278 | ANASTASIS_redux_fail_ (cb, | ||
1279 | cb_cls, | ||
1280 | TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, | ||
1281 | "poll_challenges"); | ||
1282 | return NULL; | ||
1283 | } | ||
1284 | sctx->poll_only = true; | ||
1285 | sctx->cb = cb; | ||
1286 | sctx->cb_cls = cb_cls; | ||
1287 | sctx->state = json_incref (state); | ||
1288 | sctx->args = json_incref ((json_t*) arguments); | ||
1289 | sctx->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_, | ||
1290 | rd, | ||
1291 | &solve_challenge_cb, | ||
1292 | sctx, | ||
1293 | &core_secret_cb, | ||
1294 | sctx); | ||
1295 | if (NULL == sctx->r) | ||
1296 | { | ||
1297 | json_decref (sctx->state); | ||
1298 | json_decref (sctx->args); | ||
1299 | GNUNET_free (sctx); | ||
1300 | GNUNET_break_op (0); | ||
1301 | ANASTASIS_redux_fail_ (cb, | ||
1302 | cb_cls, | ||
1303 | TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, | ||
1304 | "'recovery_document' invalid"); | ||
1305 | return NULL; | ||
1306 | } | ||
1307 | sctx->ra.cleanup = &sctx_free; | ||
1308 | sctx->ra.cleanup_cls = sctx; | ||
1309 | return &sctx->ra; | ||
1310 | } | ||
1311 | |||
1312 | |||
1313 | /** | ||
1156 | * The user selected a challenge to be solved. Handle the payment | 1314 | * The user selected a challenge to be solved. Handle the payment |
1157 | * process. | 1315 | * process. |
1158 | * | 1316 | * |
@@ -1712,6 +1870,11 @@ ANASTASIS_recovery_action_ (json_t *state, | |||
1712 | }, | 1870 | }, |
1713 | { | 1871 | { |
1714 | ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING, | 1872 | ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING, |
1873 | "poll", | ||
1874 | &poll_challenges | ||
1875 | }, | ||
1876 | { | ||
1877 | ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING, | ||
1715 | "back", | 1878 | "back", |
1716 | &ANASTASIS_back_generic_decrement_ | 1879 | &ANASTASIS_back_generic_decrement_ |
1717 | }, | 1880 | }, |