exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 004d573289d52bc13b5266f2d73f93b770254144
parent 702b929080885825309044348d24559471cd46a9
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun,  5 Apr 2026 00:15:55 +0200

fix misc minor specification inconsistencies

Diffstat:
Msrc/exchange/taler-exchange-httpd_get-transfers-WTID.c | 65++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/exchange/taler-exchange-httpd_post-auditors-AUDITOR_PUB-H_DENOM_PUB.c | 6++----
Msrc/exchange/taler-exchange-httpd_post-coins-COIN_PUB-refund.c | 56+++++++++++++++++++++++++++++++-------------------------
Msrc/lib/exchange_api_post-coins-COIN_PUB-refund.c | 111-------------------------------------------------------------------------------
Msrc/lib/exchange_api_post-purses-PURSE_PUB-merge.c | 72+++++++++++++++++++++++++++++++++++-------------------------------------
5 files changed, 104 insertions(+), 206 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_get-transfers-WTID.c b/src/exchange/taler-exchange-httpd_get-transfers-WTID.c @@ -516,28 +516,31 @@ get_transfer_deposits (void *cls, 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_FETCH_FAILED, - "wire transfer"); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "wire transfer"); } return qs; } if (GNUNET_SYSERR == ctx->is_valid) { GNUNET_break (0); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_INVARIANT_FAILURE, - "wire history malformed"); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "wire history malformed"); return GNUNET_DB_STATUS_HARD_ERROR; } if (GNUNET_NO == ctx->is_valid) { - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_TRANSFERS_GET_WTID_NOT_FOUND, - NULL); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_EXCHANGE_TRANSFERS_GET_WTID_NOT_FOUND, + NULL); return GNUNET_DB_STATUS_HARD_ERROR; } { @@ -548,10 +551,11 @@ get_transfer_deposits (void *cls, if (NULL == wire_method) { GNUNET_break (0); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_INVARIANT_FAILURE, - "payto:// without wire method encountered"); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "payto:// without wire method encountered"); return GNUNET_DB_STATUS_HARD_ERROR; } qs = TEH_plugin->get_wire_fee (TEH_plugin->cls, @@ -570,10 +574,11 @@ get_transfer_deposits (void *cls, (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ) { GNUNET_break (0); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_TRANSFERS_GET_WIRE_FEE_NOT_FOUND, - NULL); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_TRANSFERS_GET_WIRE_FEE_NOT_FOUND, + NULL); } return qs; } @@ -583,10 +588,11 @@ get_transfer_deposits (void *cls, &ctx->fees.wire)) { GNUNET_break (0); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_TRANSFERS_GET_WIRE_FEE_INCONSISTENT, - NULL); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_TRANSFERS_GET_WIRE_FEE_INCONSISTENT, + NULL); return GNUNET_DB_STATUS_HARD_ERROR; } return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; @@ -610,10 +616,11 @@ TEH_handler_transfers_get (struct TEH_RequestContext *rc, sizeof (ctx.wtid))) { GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_TRANSFERS_GET_WTID_MALFORMED, - args[0]); + return TALER_MHD_reply_with_error ( + rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_EXCHANGE_TRANSFERS_GET_WTID_MALFORMED, + args[0]); } if (GNUNET_OK != TEH_DB_run_transaction (rc->connection, @@ -638,4 +645,4 @@ TEH_handler_transfers_get (struct TEH_RequestContext *rc, } -/* end of taler-exchange-httpd_transfers_get.c */ +/* end of taler-exchange-httpd_get-transfers-WTID.c */ diff --git a/src/exchange/taler-exchange-httpd_post-auditors-AUDITOR_PUB-H_DENOM_PUB.c b/src/exchange/taler-exchange-httpd_post-auditors-AUDITOR_PUB-H_DENOM_PUB.c @@ -97,11 +97,9 @@ add_auditor_denom_sig (void *cls, } if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { - *mhd_ret = TALER_MHD_reply_with_error ( + *mhd_ret = TEH_RESPONSE_reply_invalid_denom_cipher_for_operation ( connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN, - GNUNET_h2s (&awc->h_denom_pub->hash)); + awc->h_denom_pub); return GNUNET_DB_STATUS_HARD_ERROR; } diff --git a/src/exchange/taler-exchange-httpd_post-coins-COIN_PUB-refund.c b/src/exchange/taler-exchange-httpd_post-coins-COIN_PUB-refund.c @@ -147,19 +147,21 @@ refund_transaction (void *cls, if (0 > qs) { if (GNUNET_DB_STATUS_HARD_ERROR == qs) - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "do refund"); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "do refund"); return qs; } if (gone) { - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_GONE, - TALER_EC_EXCHANGE_REFUND_MERCHANT_ALREADY_PAID, - NULL); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_GONE, + TALER_EC_EXCHANGE_REFUND_MERCHANT_ALREADY_PAID, + NULL); return GNUNET_DB_STATUS_HARD_ERROR; } if (conflict) @@ -174,10 +176,11 @@ refund_transaction (void *cls, } if (not_found) { - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_REFUND_DEPOSIT_NOT_FOUND, - NULL); + *mhd_ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_EXCHANGE_REFUND_DEPOSIT_NOT_FOUND, + NULL); return GNUNET_DB_STATUS_HARD_ERROR; } if (! refund_ok) @@ -220,11 +223,12 @@ verify_and_execute_refund (struct MHD_Connection *connection, &refund->details.merchant_pub, &refund->details.merchant_sig)) { - TALER_LOG_WARNING ("Invalid signature on refund request\n"); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_EXCHANGE_REFUND_MERCHANT_SIGNATURE_INVALID, - NULL); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_EXCHANGE_REFUND_MERCHANT_SIGNATURE_INVALID, + NULL); } /* Fetch the coin's denomination (hash) */ @@ -244,10 +248,11 @@ verify_and_execute_refund (struct MHD_Connection *connection, /* otherwise: fall-through */ case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_coin_denomination"); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "get_coin_denomination"); case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: { MHD_RESULT res; @@ -257,10 +262,11 @@ verify_and_execute_refund (struct MHD_Connection *connection, dhs = GNUNET_STRINGS_data_to_string_alloc ( &refund->coin.denom_pub_hash, sizeof (refund->coin.denom_pub_hash)); - res = TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_REFUND_COIN_NOT_FOUND, - dhs); + res = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_EXCHANGE_REFUND_COIN_NOT_FOUND, + dhs); GNUNET_free (dhs); return res; } diff --git a/src/lib/exchange_api_post-coins-COIN_PUB-refund.c b/src/lib/exchange_api_post-coins-COIN_PUB-refund.c @@ -172,101 +172,6 @@ verify_refund_signature_ok (struct TALER_EXCHANGE_PostCoinsRefundHandle *rh, /** - * Verify that the information on the "412 Dependency Failed" response - * from the exchange is valid. - * - * @param[in,out] rh refund handle - * @param json json reply with the signature - * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not - */ -static enum GNUNET_GenericReturnValue -verify_failed_dependency_ok (struct TALER_EXCHANGE_PostCoinsRefundHandle *rh, - const json_t *json) -{ - const json_t *h; - json_t *e; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("history", - &h), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (1 != json_array_size (h)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - e = json_array_get (h, 0); - { - struct TALER_Amount amount; - const char *type; - struct TALER_MerchantSignatureP sig; - struct TALER_Amount refund_fee; - struct TALER_PrivateContractHashP h_contract_terms; - uint64_t rtransaction_id; - struct TALER_MerchantPublicKeyP merchant_pub; - struct GNUNET_JSON_Specification ispec[] = { - TALER_JSON_spec_amount_any ("amount", - &amount), - GNUNET_JSON_spec_string ("type", - &type), - TALER_JSON_spec_amount_any ("refund_fee", - &refund_fee), - GNUNET_JSON_spec_fixed_auto ("merchant_sig", - &sig), - GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &h_contract_terms), - GNUNET_JSON_spec_fixed_auto ("merchant_pub", - &merchant_pub), - GNUNET_JSON_spec_uint64 ("rtransaction_id", - &rtransaction_id), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (e, - ispec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_merchant_refund_verify (&rh->coin_pub, - &h_contract_terms, - rtransaction_id, - &amount, - &merchant_pub, - &sig)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if ( (rtransaction_id != rh->rtransaction_id) || - (0 != GNUNET_memcmp (&rh->h_contract_terms, - &h_contract_terms)) || - (0 != GNUNET_memcmp (&rh->merchant_pub, - &merchant_pub)) || - (0 == TALER_amount_cmp (&rh->refund_amount, - &amount)) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - } - return GNUNET_OK; -} - - -/** * Function called when we're done processing the * HTTP /refund request. * @@ -340,22 +245,6 @@ handle_refund_finished (void *cls, rr.hr.ec = TALER_JSON_get_error_code (j); rr.hr.hint = TALER_JSON_get_error_hint (j); break; - case MHD_HTTP_PRECONDITION_FAILED: - if (GNUNET_OK != - verify_failed_dependency_ok (rh, - j)) - { - GNUNET_break (0); - rr.hr.http_status = 0; - rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE; - rr.hr.hint = "failed precondition proof returned by exchange is invalid"; - break; - } - /* Two different refund requests were made about the same deposit, but - carrying identical refund transaction ids. */ - rr.hr.ec = TALER_JSON_get_error_code (j); - rr.hr.hint = TALER_JSON_get_error_hint (j); - break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ diff --git a/src/lib/exchange_api_post-purses-PURSE_PUB-merge.c b/src/lib/exchange_api_post-purses-PURSE_PUB-merge.c @@ -117,6 +117,11 @@ struct TALER_EXCHANGE_PostPursesMergeHandle struct GNUNET_TIME_Timestamp purse_expiration; /** + * Time of the merge. + */ + struct GNUNET_TIME_Timestamp merge_timestamp; + + /** * Our merge key. */ struct TALER_PurseMergePrivateKeyP merge_priv; @@ -324,7 +329,6 @@ TALER_EXCHANGE_post_purses_merge_create ( struct GNUNET_TIME_Timestamp merge_timestamp) { struct TALER_EXCHANGE_PostPursesMergeHandle *pch; - struct TALER_NormalizedPayto reserve_url; pch = GNUNET_new (struct TALER_EXCHANGE_PostPursesMergeHandle); pch->ctx = ctx; @@ -334,6 +338,7 @@ TALER_EXCHANGE_post_purses_merge_create ( pch->h_contract_terms = *h_contract_terms; pch->purse_expiration = purse_expiration; pch->purse_value_after_fees = *purse_value_after_fees; + pch->merge_timestamp = merge_timestamp; if (NULL == reserve_exchange_url) pch->provider_url = GNUNET_strdup (url); else @@ -341,29 +346,14 @@ TALER_EXCHANGE_post_purses_merge_create ( GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, &pch->reserve_pub.eddsa_pub); - reserve_url = TALER_reserve_make_payto (pch->provider_url, - &pch->reserve_pub); - if (NULL == reserve_url.normalized_payto) - { - GNUNET_break (0); - GNUNET_free (pch->provider_url); - GNUNET_free (pch->base_url); - GNUNET_free (pch); - return NULL; - } - TALER_wallet_purse_merge_sign (reserve_url, - merge_timestamp, - purse_pub, - merge_priv, - &pch->merge_sig); { struct TALER_Amount zero_purse_fee; GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (purse_value_after_fees->currency, &zero_purse_fee)); - TALER_wallet_account_merge_sign (merge_timestamp, - purse_pub, + TALER_wallet_account_merge_sign (pch->merge_timestamp, + &pch->purse_pub, purse_expiration, h_contract_terms, purse_value_after_fees, @@ -373,25 +363,6 @@ TALER_EXCHANGE_post_purses_merge_create ( reserve_priv, &pch->reserve_sig); } - // FIXME: move JSON construction into _start() function - pch->body = GNUNET_JSON_PACK ( - TALER_JSON_pack_normalized_payto ("payto_uri", - reserve_url), - GNUNET_JSON_pack_data_auto ("merge_sig", - &pch->merge_sig), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &pch->reserve_sig), - GNUNET_JSON_pack_timestamp ("merge_timestamp", - merge_timestamp)); - GNUNET_free (reserve_url.normalized_payto); - if (NULL == pch->body) - { - GNUNET_break (0); - GNUNET_free (pch->provider_url); - GNUNET_free (pch->base_url); - GNUNET_free (pch); - return NULL; - } pch->keys = TALER_EXCHANGE_keys_incref (keys); return pch; } @@ -435,6 +406,33 @@ TALER_EXCHANGE_post_purses_merge_start ( GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URL for purse merge: `%s'\n", pch->url); + { + struct TALER_NormalizedPayto reserve_url; + + reserve_url = TALER_reserve_make_payto (pch->provider_url, + &pch->reserve_pub); + if (NULL == reserve_url.normalized_payto) + { + GNUNET_break (0); + return TALER_EC_GENERIC_ALLOCATION_FAILURE; + } + TALER_wallet_purse_merge_sign (reserve_url, + pch->merge_timestamp, + &pch->purse_pub, + &pch->merge_priv, + &pch->merge_sig); + pch->body = GNUNET_JSON_PACK ( + TALER_JSON_pack_normalized_payto ("payto_uri", + reserve_url), + GNUNET_JSON_pack_data_auto ("merge_sig", + &pch->merge_sig), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &pch->reserve_sig), + GNUNET_JSON_pack_timestamp ("merge_timestamp", + pch->merge_timestamp)); + GNUNET_free (reserve_url.normalized_payto); + } + eh = TALER_EXCHANGE_curl_easy_get_ (pch->url); if ( (NULL == eh) || (GNUNET_OK !=