From 0325a79631d1abba7fdf414748a34c0e8bca55c3 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 15 Nov 2021 14:39:18 +0100 Subject: avoid duplication --- contrib/gana | 2 +- src/exchange/taler-exchange-httpd_kyc-check.c | 227 +++++++++++++++++--------- src/exchangedb/plugin_exchangedb_postgres.c | 42 ++++- src/include/taler_crypto_lib.h | 6 - src/include/taler_exchangedb_plugin.h | 19 ++- 5 files changed, 205 insertions(+), 91 deletions(-) diff --git a/contrib/gana b/contrib/gana index 15a8cae39..597e273cc 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 15a8cae393bf35f95ae15836c4ec4b2b22e42604 +Subproject commit 597e273cc73122ba5cd0023f37b43b4f3784fe0c diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c index 3648617d7..69798a56d 100644 --- a/src/exchange/taler-exchange-httpd_kyc-check.c +++ b/src/exchange/taler-exchange-httpd_kyc-check.c @@ -27,6 +27,7 @@ #include "taler_json_lib.h" #include "taler_mhd_lib.h" #include "taler_signatures.h" +#include "taler_dbevents.h" #include "taler-exchange-httpd_keys.h" #include "taler-exchange-httpd_kyc-wallet.h" #include "taler-exchange-httpd_responses.h" @@ -187,6 +188,42 @@ kyc_check (void *cls, } +/** + * Function called on events received from Postgres. + * Wakes up long pollers. + * + * @param cls the `struct TEH_RequestContext *` + * @param extra additional event data provided + * @param extra_size number of bytes in @a extra + */ +static void +db_event_cb (void *cls, + const void *extra, + size_t extra_size) +{ + struct TEH_RequestContext *rc = cls; + struct KycPoller *kyp = rc->rh_ctx; + struct GNUNET_AsyncScopeSave old_scope; + + (void) extra; + (void) extra_size; + if (! kyp->suspended) + return; /* event triggered while main transaction + was still running, or got multiple wake-up events */ + kyp->suspended = false; + GNUNET_async_scope_enter (&rc->async_scope_id, + &old_scope); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Resuming from long-polling on KYC status\n"); + GNUNET_CONTAINER_DLL_remove (kyp_head, + kyp_tail, + kyp); + MHD_resume_connection (kyp->connection); + TALER_MHD_daemon_trigger (); + GNUNET_async_scope_restore (&old_scope); +} + + MHD_RESULT TEH_handler_kyc_check ( struct TEH_RequestContext *rc, @@ -195,6 +232,7 @@ TEH_handler_kyc_check ( struct KycPoller *kyp = rc->rh_ctx; MHD_RESULT res; enum GNUNET_GenericReturnValue ret; + struct GNUNET_TIME_Absolute now; if (NULL == kyp) { @@ -285,87 +323,120 @@ TEH_handler_kyc_check ( NULL, NULL, 0); + + if ( (NULL == kyp->eh) && + GNUNET_TIME_absolute_is_future (kyp->timeout) ) { - struct GNUNET_TIME_Absolute now; - - now = GNUNET_TIME_absolute_get (); - (void) GNUNET_TIME_round_abs (&now); - ret = TEH_DB_run_transaction (rc->connection, - "kyc check", - &res, - &kyc_check, - kyp); - if (GNUNET_SYSERR == ret) - return res; - if (0 != - GNUNET_memcmp (&kyp->h_payto, - &kyp->auth_h_payto)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_UNAUTHORIZED, - TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED, - "h_payto"); - } - if (! kyp->kyc.ok) - { - char *url; - char *redirect_uri; - char *redirect_uri_encoded; - - GNUNET_assert (TEH_KYC_OAUTH2 == TEH_kyc_config.mode); - GNUNET_asprintf (&redirect_uri, - "%s/kyc-proof/%llu", - TEH_base_url, - (unsigned long long) kyp->payment_target_uuid); - redirect_uri_encoded = TALER_urlencode (redirect_uri); - GNUNET_free (redirect_uri); - GNUNET_asprintf (&url, - "%s/login?client_id=%s&redirect_uri=%s", - TEH_kyc_config.details.oauth2.url, - TEH_kyc_config.details.oauth2.client_id, - redirect_uri_encoded); - GNUNET_free (redirect_uri_encoded); - - res = TALER_MHD_REPLY_JSON_PACK ( - rc->connection, - MHD_HTTP_ACCEPTED, - GNUNET_JSON_pack_string ("kyc_url", - url)); - GNUNET_free (url); - return res; - } + struct TALER_KycCompletedEventP rep = { + .header.size = htons (sizeof (rep)), + .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED), + .h_payto = kyp->auth_h_payto + }; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Starting DB event listening\n"); + kyp->eh = TEH_plugin->event_listen ( + TEH_plugin->cls, + GNUNET_TIME_absolute_get_remaining (kyp->timeout), + &rep.header, + &db_event_cb, + rc); + } + + now = GNUNET_TIME_absolute_get (); + (void) GNUNET_TIME_round_abs (&now); + ret = TEH_DB_run_transaction (rc->connection, + "kyc check", + &res, + &kyc_check, + kyp); + if (GNUNET_SYSERR == ret) + return res; + if (0 != + GNUNET_memcmp (&kyp->h_payto, + &kyp->auth_h_payto)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_UNAUTHORIZED, + TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED, + "h_payto"); + } + + /* long polling? */ + if ( (! kyp->kyc.ok) && + GNUNET_TIME_absolute_is_future (kyp->timeout)) + { + GNUNET_assert (NULL != kyp->eh); + kyp->suspended = true; + GNUNET_CONTAINER_DLL_insert (kyp_head, + kyp_tail, + kyp); + MHD_suspend_connection (kyp->connection); + return MHD_YES; + } + + /* KYC failed? */ + if (! kyp->kyc.ok) + { + char *url; + char *redirect_uri; + char *redirect_uri_encoded; + + GNUNET_assert (TEH_KYC_OAUTH2 == TEH_kyc_config.mode); + GNUNET_asprintf (&redirect_uri, + "%s/kyc-proof/%llu", + TEH_base_url, + (unsigned long long) kyp->payment_target_uuid); + redirect_uri_encoded = TALER_urlencode (redirect_uri); + GNUNET_free (redirect_uri); + GNUNET_asprintf (&url, + "%s/login?client_id=%s&redirect_uri=%s", + TEH_kyc_config.details.oauth2.url, + TEH_kyc_config.details.oauth2.client_id, + redirect_uri_encoded); + GNUNET_free (redirect_uri_encoded); + + res = TALER_MHD_REPLY_JSON_PACK ( + rc->connection, + MHD_HTTP_ACCEPTED, + GNUNET_JSON_pack_string ("kyc_url", + url)); + GNUNET_free (url); + return res; + } + + /* KYC succeeded! */ + { + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + struct TALER_ExchangeAccountSetupSuccessPS as = { + .purpose.purpose = htonl ( + TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS), + .purpose.size = htonl (sizeof (as)), + .h_payto = kyp->h_payto, + .timestamp = GNUNET_TIME_absolute_hton (now) + }; + enum TALER_ErrorCode ec; + + if (TALER_EC_NONE != + (ec = TEH_keys_exchange_sign (&as, + &pub, + &sig))) { - struct TALER_ExchangePublicKeyP pub; - struct TALER_ExchangeSignatureP sig; - struct TALER_ExchangeAccountSetupSuccessPS as = { - .purpose.purpose = htonl ( - TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS), - .purpose.size = htonl (sizeof (as)), - .h_payto = kyp->h_payto, - .timestamp = GNUNET_TIME_absolute_hton (now) - }; - enum TALER_ErrorCode ec; - - if (TALER_EC_NONE != - (ec = TEH_keys_exchange_sign (&as, - &pub, - &sig))) - { - return TALER_MHD_reply_with_ec (rc->connection, - ec, - NULL); - } - return TALER_MHD_REPLY_JSON_PACK ( - rc->connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_data_auto ("exchange_sig", - &sig), - GNUNET_JSON_pack_data_auto ("exchange_pub", - &pub), - GNUNET_JSON_pack_time_abs ("now", - now)); + return TALER_MHD_reply_with_ec (rc->connection, + ec, + NULL); } + return TALER_MHD_REPLY_JSON_PACK ( + rc->connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_data_auto ("exchange_sig", + &sig), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &pub), + GNUNET_JSON_pack_time_abs ("now", + now)); } } diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index f9f3fd16f..6e77cb232 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -385,6 +385,14 @@ prepare_statements (struct PostgresClosure *pg) " SET kyc_ok=TRUE" " WHERE wire_target_serial_id=$1", 1), + GNUNET_PQ_make_prepare ( + "get_kyc_h_payto", + "SELECT" + " h_payto" + " FROM wire_targets" + " WHERE wire_target_serial_id=$1" + " LIMIT 1;", + 1), /* Used in #postgres_get_kyc_status() */ GNUNET_PQ_make_prepare ( "get_kyc_status", @@ -3804,10 +3812,33 @@ postgres_set_kyc_ok (void *cls, GNUNET_PQ_query_param_uint64 (&payment_target_uuid), GNUNET_PQ_query_param_end }; + struct TALER_KycCompletedEventP rep = { + .header.size = htons (sizeof (rep)), + .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED) + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("h_payto", + &rep.h_payto), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_DB_QueryStatus qs; - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "set_kyc_ok", - params); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "set_kyc_ok", + params); + if (qs <= 0) + return qs; + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "get_kyc_h_payto", + params, + rs); + if (qs <= 0) + return qs; + postgres_event_notify (pg, + &rep.header, + NULL, + 0); + return qs; } @@ -5684,9 +5715,10 @@ postgres_ensure_coin_known (void *cls, switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: - return TALER_EXCHANGEDB_CKS_SOFT_FAIL; - case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); return TALER_EXCHANGEDB_CKS_HARD_FAIL; + case GNUNET_DB_STATUS_SOFT_ERROR: + return TALER_EXCHANGEDB_CKS_SOFT_FAIL; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: GNUNET_break (0); return TALER_EXCHANGEDB_CKS_HARD_FAIL; diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index d354add1a..3da178ca4 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -323,12 +323,6 @@ struct TALER_CoinSpendPublicKeyP */ struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub; - /* - * If age restriction applies to the coin, it must come with a hash of the - * age commitment. A zero value indicates that the coin has no age - * commitment set. - */ - struct TALER_AgeHash age_commitment_hash; }; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 7520779e3..420e1e1e0 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -74,7 +74,7 @@ struct TALER_EXCHANGEDB_DenominationKeyInformationP /** - * Signature of events signalling a reseve got funding. + * Signature of events signalling a reserve got funding. */ struct TALER_ReserveEventP { @@ -90,6 +90,23 @@ struct TALER_ReserveEventP }; +/** + * Signature of events signalling a KYC process was completed. + */ +struct TALER_KycCompletedEventP +{ + /** + * Of type #TALER_DBEVENT_EXCHANGE_KYC_COMPLETED. + */ + struct GNUNET_DB_EventHeaderP header; + + /** + * Public key of the reserve the event is about. + */ + struct TALER_PaytoHash h_payto; +}; + + GNUNET_NETWORK_STRUCT_END /** -- cgit v1.2.3