diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_purses_merge.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_purses_merge.c | 240 |
1 files changed, 169 insertions, 71 deletions
diff --git a/src/exchange/taler-exchange-httpd_purses_merge.c b/src/exchange/taler-exchange-httpd_purses_merge.c index 144571d22..fb5ce4d90 100644 --- a/src/exchange/taler-exchange-httpd_purses_merge.c +++ b/src/exchange/taler-exchange-httpd_purses_merge.c @@ -28,12 +28,12 @@ #include <pthread.h> #include "taler_dbevents.h" #include "taler_json_lib.h" +#include "taler_kyclogic_lib.h" #include "taler_mhd_lib.h" #include "taler-exchange-httpd_purses_merge.h" #include "taler-exchange-httpd_responses.h" #include "taler_exchangedb_lib.h" #include "taler-exchange-httpd_keys.h" -#include "taler-exchange-httpd_wire.h" /** @@ -103,11 +103,21 @@ struct PurseMergeContext /** * URI of the account the purse is to be merged into. - * Must be of the form 'payto://taler/$EXCHANGE_URL/RESERVE_PUB'. + * Must be of the form 'payto://taler-reserve/$EXCHANGE_URL/RESERVE_PUB'. */ const char *payto_uri; /** + * Hash of the @e payto_uri. + */ + struct TALER_PaytoHashP h_payto; + + /** + * KYC status of the operation. + */ + struct TALER_EXCHANGEDB_KycStatus kyc; + + /** * Base URL of the exchange provider hosting the reserve. */ char *provider_url; @@ -157,15 +167,20 @@ reply_merge_success (struct MHD_Connection *connection, } else { +#if WAD_NOT_IMPLEMENTED + /* FIXME: figure out partner, lookup wad fee by partner! #7271 */ if (0 > TALER_amount_subtract (&merge_amount, &pcc->target_amount, - &pcc->wf->wad)) + &wad_fee)) { GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TEH_currency, &merge_amount)); } +#else + merge_amount = pcc->target_amount; +#endif } if (TALER_EC_NONE != (ec = TALER_exchange_online_purse_merged_sign ( @@ -202,6 +217,46 @@ reply_merge_success (struct MHD_Connection *connection, /** + * Function called to iterate over KYC-relevant + * transaction amounts for a particular time range. + * Called within a database transaction, so must + * not start a new one. + * + * @param cls a `struct PurseMergeContext` + * @param limit maximum time-range for which events + * should be fetched (timestamp in the past) + * @param cb function to call on each event found, + * events must be returned in reverse chronological + * order + * @param cb_cls closure for @a cb + */ +static void +amount_iterator (void *cls, + struct GNUNET_TIME_Absolute limit, + TALER_EXCHANGEDB_KycAmountCallback cb, + void *cb_cls) +{ + struct PurseMergeContext *pcc = cls; + enum GNUNET_DB_QueryStatus qs; + + cb (cb_cls, + &pcc->target_amount, + GNUNET_TIME_absolute_get ()); + qs = TEH_plugin->select_merge_amounts_for_kyc_check ( + TEH_plugin->cls, + &pcc->h_payto, + limit, + cb, + cb_cls); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Got %d additional transactions for this merge and limit %llu\n", + qs, + (unsigned long long) limit.abs_value_us); + GNUNET_break (qs >= 0); +} + + +/** * Execute database transaction for /purses/$PID/merge. Runs the transaction * logic; IF it returns a non-error code, the transaction logic MUST NOT queue * a MHD response. IF it returns an hard error, the transaction logic MUST @@ -224,9 +279,50 @@ merge_transaction (void *cls, bool in_conflict = true; bool no_balance = true; bool no_partner = true; - bool no_kyc = true; - bool no_reserve = true; + char *required; + qs = TALER_KYCLOGIC_kyc_test_required ( + TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE, + &pcc->h_payto, + TEH_plugin->select_satisfied_kyc_processes, + TEH_plugin->cls, + &amount_iterator, + pcc, + &required); + if (qs < 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + GNUNET_break (0); + *mhd_ret = + TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "kyc_test_required"); + return qs; + } + if (NULL != required) + { + pcc->kyc.ok = false; + qs = TEH_plugin->insert_kyc_requirement_for_account ( + TEH_plugin->cls, + required, + &pcc->h_payto, + &pcc->reserve_pub, + &pcc->kyc.requirement_row); + GNUNET_free (required); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + GNUNET_break (0); + *mhd_ret + = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert_kyc_requirement_for_account"); + } + return qs; + } + pcc->kyc.ok = true; qs = TEH_plugin->do_purse_merge ( TEH_plugin->cls, pcc->purse_pub, @@ -235,18 +331,14 @@ merge_transaction (void *cls, &pcc->reserve_sig, pcc->provider_url, &pcc->reserve_pub, - TEH_KYC_NONE != TEH_kyc_config.mode, &no_partner, &no_balance, - &no_reserve, - &no_kyc, &in_conflict); if (qs < 0) { if (GNUNET_DB_STATUS_SOFT_ERROR == qs) return qs; - TALER_LOG_WARNING ( - "Failed to store merge purse information in database\n"); + GNUNET_break (0); *mhd_ret = TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -263,26 +355,6 @@ merge_transaction (void *cls, pcc->provider_url); return GNUNET_DB_STATUS_HARD_ERROR; } - if (no_reserve) - { - *mhd_ret = - TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN, - NULL); - return GNUNET_DB_STATUS_HARD_ERROR; - } - if ( (no_kyc) && - (TEH_KYC_NONE != TEH_kyc_config.mode) ) - { - *mhd_ret - = TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, - TALER_JSON_pack_ec ( - TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED)); - return GNUNET_DB_STATUS_HARD_ERROR; - } if (no_balance) { *mhd_ret = @@ -298,13 +370,15 @@ merge_transaction (void *cls, struct GNUNET_TIME_Timestamp merge_timestamp; char *partner_url = NULL; struct TALER_ReservePublicKeyP reserve_pub; + bool refunded; qs = TEH_plugin->select_purse_merge (TEH_plugin->cls, pcc->purse_pub, &merge_sig, &merge_timestamp, &partner_url, - &reserve_pub); + &reserve_pub, + &refunded); if (qs <= 0) { if (GNUNET_DB_STATUS_SOFT_ERROR == qs) @@ -318,21 +392,43 @@ merge_transaction (void *cls, "select purse merge"); return qs; } - *mhd_ret = TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_CONFLICT, - GNUNET_JSON_pack_timestamp ("merge_timestamp", - merge_timestamp), - GNUNET_JSON_pack_data_auto ("merge_sig", - &merge_sig), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("partner_url", - partner_url)), - GNUNET_JSON_pack_data_auto ("reserve_pub", - &reserve_pub)); + if (refunded) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Purse was already refunded\n"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_GONE, + TALER_EC_EXCHANGE_GENERIC_PURSE_EXPIRED, + NULL); + GNUNET_free (partner_url); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (0 != + GNUNET_memcmp (&merge_sig, + &pcc->merge_sig)) + { + *mhd_ret = TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_CONFLICT, + GNUNET_JSON_pack_timestamp ("merge_timestamp", + merge_timestamp), + GNUNET_JSON_pack_data_auto ("merge_sig", + &merge_sig), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("partner_url", + partner_url)), + GNUNET_JSON_pack_data_auto ("reserve_pub", + &reserve_pub)); + GNUNET_free (partner_url); + return GNUNET_DB_STATUS_HARD_ERROR; + } + /* idempotent! */ + *mhd_ret = reply_merge_success (connection, + pcc); GNUNET_free (partner_url); return GNUNET_DB_STATUS_HARD_ERROR; } + return qs; } @@ -348,8 +444,8 @@ TEH_handler_purses_merge ( .exchange_timestamp = GNUNET_TIME_timestamp_get () }; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("payto_uri", - &pcc.payto_uri), + TALER_JSON_spec_payto_uri ("payto_uri", + &pcc.payto_uri), GNUNET_JSON_spec_fixed_auto ("reserve_sig", &pcc.reserve_sig), GNUNET_JSON_spec_fixed_auto ("merge_sig", @@ -381,15 +477,15 @@ TEH_handler_purses_merge ( } /* Fetch purse details */ - qs = TEH_plugin->select_purse_request (TEH_plugin->cls, - pcc.purse_pub, - &pcc.merge_pub, - &pcc.purse_expiration, - &pcc.h_contract_terms, - &pcc.min_age, - &pcc.target_amount, - &pcc.balance, - &purse_sig); + qs = TEH_plugin->get_purse_request (TEH_plugin->cls, + pcc.purse_pub, + &pcc.merge_pub, + &pcc.purse_expiration, + &pcc.h_contract_terms, + &pcc.min_age, + &pcc.target_amount, + &pcc.balance, + &purse_sig); switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: @@ -421,11 +517,11 @@ TEH_handler_purses_merge ( "Received payto: `%s'\n", pcc.payto_uri); if ( (0 != strncmp (pcc.payto_uri, - "payto://taler/", - strlen ("payto://taler/"))) && + "payto://taler-reserve/", + strlen ("payto://taler-reserve/"))) && (0 != strncmp (pcc.payto_uri, - "payto://taler+http/", - strlen ("payto://taler+http/"))) ) + "payto://taler-reserve-http/", + strlen ("payto://taler-reserve+http/"))) ) { GNUNET_break_op (0); return TALER_MHD_reply_with_error ( @@ -434,15 +530,14 @@ TEH_handler_purses_merge ( TALER_EC_GENERIC_PARAMETER_MALFORMED, "payto_uri"); } - http = (0 == strncmp (pcc.payto_uri, - "payto://taler+http/", - strlen ("payto://taler+http/"))); + "payto://taler-reserve-http/", + strlen ("payto://taler-reserve-http/"))); { const char *host = &pcc.payto_uri[http - ? strlen ("payto://taler+http/") - : strlen ("payto://taler/")]; + ? strlen ("payto://taler-reserve-http/") + : strlen ("payto://taler-reserve/")]; const char *slash = strchr (host, '/'); @@ -477,6 +572,8 @@ TEH_handler_purses_merge ( } slash++; } + TALER_payto_hash (pcc.payto_uri, + &pcc.h_payto); if (0 == strcmp (pcc.provider_url, TEH_base_url)) { @@ -485,9 +582,9 @@ TEH_handler_purses_merge ( } else { - char *method = GNUNET_strdup ("FIXME-WAD"); + char *method = GNUNET_strdup ("FIXME-WAD #7271"); - /* FIXME: lookup wire method by pcc.provider_url! */ + /* FIXME-#7271: lookup wire method by pcc.provider_url! */ pcc.wf = TEH_wire_fees_by_time (pcc.exchange_timestamp, method); if (NULL == pcc.wf) @@ -551,11 +648,6 @@ TEH_handler_purses_merge ( } } - if (GNUNET_TIME_absolute_is_past (pcc.purse_expiration.abs_time)) - { - // FIXME: idempotency check, otherwise generate 410! - } - /* execute transaction */ { MHD_RESULT mhd_ret; @@ -573,6 +665,13 @@ TEH_handler_purses_merge ( } } + + GNUNET_free (pcc.provider_url); + if (! pcc.kyc.ok) + return TEH_RESPONSE_reply_kyc_required (connection, + &pcc.h_payto, + &pcc.kyc); + { struct TALER_PurseEventP rep = { .header.size = htons (sizeof (rep)), @@ -588,7 +687,6 @@ TEH_handler_purses_merge ( 0); } - GNUNET_free (pcc.provider_url); /* generate regular response */ return reply_merge_success (connection, &pcc); |