From 81d0e570be0db784e98fdb7ad63f9b65c6745be3 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 19 Aug 2021 13:41:30 +0200 Subject: -implement DB triggers and check for inbound wire transfers in IBAN plugin --- .../anastasis_authorization_plugin_iban.c | 134 ++++++++++++++++++++- 1 file changed, 132 insertions(+), 2 deletions(-) (limited to 'src/authorization/anastasis_authorization_plugin_iban.c') diff --git a/src/authorization/anastasis_authorization_plugin_iban.c b/src/authorization/anastasis_authorization_plugin_iban.c index eee8e7e..4f43d3f 100644 --- a/src/authorization/anastasis_authorization_plugin_iban.c +++ b/src/authorization/anastasis_authorization_plugin_iban.c @@ -28,6 +28,16 @@ #include "anastasis_util_lib.h" #include "iban.h" +/** + * How long is a code valid once generated? Very long + * here as we do not want to refuse authentication + * just because the user took a while to execute the + * wire transfer (and then get back to their recovery + * operation). + */ +#define CODE_VALIDITY_PERIOD GNUNET_TIME_UNIT_MONTHS + + /** * Saves the State of a authorization plugin. */ @@ -367,7 +377,116 @@ respond_with_challenge (struct ANASTASIS_AUTHORIZATION_State *as, return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED; return ANASTASIS_AUTHORIZATION_RES_SUCCESS; } +} + + +#include "iban.c" + + +/** + * Check if the @a wire_subject matches the challenge in the context + * and if the @a amount is sufficient. If so, return true. + * + * @param cls a `const struct ANASTASIS_AUTHORIZATION_State *` + * @param amount the amount that was transferred + * @param wire_subject a wire subject we received + * @return true if the wire transfer satisfied the check + */ +static bool +check_payment_ok (void *cls, + const struct TALER_Amount *amount, + const char *wire_subject) +{ + const struct ANASTASIS_AUTHORIZATION_State *as = cls; + struct IBAN_Context *ctx = as->ctx; + uint64_t code; + + if (GNUNET_OK != + extract_code (wire_subject, + &code)) + return false; + if (GNUNET_OK != + TALER_amount_cmp_currency (&ctx->expected_amount, + amount)) + { + /* currency wrong!? */ + GNUNET_break (0); + return false; + } + if (1 == + TALER_amount_cmp (&ctx->expected_amount, + amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Amount `%s' insufficient for authorization\n", + TALER_amount2s (amount)); + return false; + } + return (code == as->code); +} + +/** + * Check if we have received a wire transfer with a subject + * authorizing the disclosure of the credential in the meantime. + * + * @param as state to check for + * @return WTS_SUCCESS if a transfer was received, + * WTS_NOT_READY if no transfer was received, + * WTS_FAILED_WITH_REPLY if we had an internal error and queued a reply + * WTS_FAILED_WITHOUT_REPLY if we had an internal error and failed to queue a reply + */ +static enum +{ + WTS_SUCCESS, + WTS_NOT_READY, + WTS_FAILED_WITH_REPLY, + WTS_FAILED_WITHOUT_REPLY +} +test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as) +{ + struct IBAN_Context *ctx = as->ctx; + struct ANASTASIS_DatabasePlugin *db = ctx->ac->db; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute limit; + char *debit_account_uri; + + now = GNUNET_TIME_absolute_get (); + limit = GNUNET_TIME_absolute_subtract (now, + CODE_VALIDITY_PERIOD); + GNUNET_asprintf (&debit_account_uri, + "payto://iban/%s", + as->iban_number); + qs = db->test_auth_iban_payment ( + db->cls, + debit_account_uri, + limit, + &check_payment_ok, + as); + GNUNET_free (debit_account_uri); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + return (MHD_YES == + TALER_MHD_reply_with_error (as->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + NULL)) + ? WTS_FAILED_WITH_REPLY + : WTS_FAILED_WITHOUT_REPLY; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return WTS_NOT_READY; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + qs = db->mark_challenge_code_satisfied ( + db->cls, + &as->truth_uuid, + as->code); + GNUNET_break (qs > 0); + return WTS_SUCCESS; } @@ -423,6 +542,17 @@ iban_process (struct ANASTASIS_AUTHORIZATION_State *as, return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED; return ANASTASIS_AUTHORIZATION_RES_FAILED; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + switch (test_wire_transfers (as)) + { + case WTS_SUCCESS: + return ANASTASIS_AUTHORIZATION_RES_FINISHED; + case WTS_NOT_READY: + break; /* continue below */ + case WTS_FAILED_WITH_REPLY: + return ANASTASIS_AUTHORIZATION_RES_FAILED; + case WTS_FAILED_WITHOUT_REPLY: + return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED; + } if (GNUNET_TIME_absolute_is_future (timeout)) { as->connection = connection; @@ -529,9 +659,9 @@ libanastasis_plugin_authorization_iban_init (void *cls) ctx->ac = ac; plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); plugin->payment_plugin_managed = true; - plugin->code_validity_period = GNUNET_TIME_UNIT_MONTHS; + plugin->code_validity_period = CODE_VALIDITY_PERIOD; plugin->code_rotation_period = GNUNET_TIME_UNIT_WEEKS; - plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_FOREVER_REL; + plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_FOREVER_REL; /* not applicable */ plugin->cls = ctx; plugin->validate = &iban_validate; plugin->start = &iban_start; -- cgit v1.2.3