exchange

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

commit 75f75c4a51c4700da9bde18cc9a9b5d9df1e8457
parent 5ee567d1bacf1422745bb0867a1022fd695bc5dc
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 30 Apr 2023 16:21:07 +0200

breaking protocol changes towards fixing #7810 (incomplete, taler-exchange-offline still unfinished)

Diffstat:
Msrc/auditor/taler-helper-auditor-wire.c | 8++++----
Msrc/bank-lib/bank_api_credit.c | 4++--
Msrc/bank-lib/bank_api_debit.c | 4++--
Msrc/bank-lib/taler-exchange-wire-gateway-client.c | 8++++----
Msrc/exchange-tools/taler-auditor-offline.c | 23++++++++---------------
Msrc/exchange-tools/taler-exchange-offline.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/exchange/taler-exchange-httpd_config.h | 2+-
Msrc/exchange/taler-exchange-httpd_management_wire_disable.c | 5++++-
Msrc/exchange/taler-exchange-httpd_management_wire_enable.c | 46++++++++++++++++++++++++++++++++++++++++++++--
Msrc/exchange/taler-exchange-httpd_wire.c | 17++++++++++++++++-
Msrc/exchange/taler-exchange-wirewatch.c | 4++--
Msrc/exchangedb/.gitignore | 4++--
Asrc/exchangedb/0004-wire_accounts.sql | 26++++++++++++++++++++++++++
Msrc/exchangedb/Makefile.am | 13+++++++++++--
Msrc/exchangedb/drop.sql | 1+
Asrc/exchangedb/exchange-0004.sql.in | 24++++++++++++++++++++++++
Msrc/exchangedb/pg_get_wire_accounts.c | 32+++++++++++++++++++++++++++++++-
Msrc/exchangedb/pg_insert_wire.c | 15+++++++++++++--
Msrc/exchangedb/pg_insert_wire.h | 6++++++
Msrc/exchangedb/pg_update_wire.c | 20+++++++++++++++++---
Msrc/exchangedb/pg_update_wire.h | 8++++++++
Msrc/include/taler_bank_service.h | 6++++--
Msrc/include/taler_crypto_lib.h | 24++++++++++++++++++++++++
Msrc/include/taler_exchange_service.h | 666+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/include/taler_exchangedb_plugin.h | 18++++++++++++++++++
Msrc/include/taler_json_lib.h | 27---------------------------
Msrc/include/taler_testing_lib.h | 8++------
Msrc/json/Makefile.am | 16++--------------
Msrc/json/json_wire.c | 74--------------------------------------------------------------------------
Dsrc/json/test_json_wire.c | 80-------------------------------------------------------------------------------
Msrc/lib/exchange_api_batch_deposit.c | 12++++++------
Msrc/lib/exchange_api_batch_withdraw.c | 37+++++++++++++++++--------------------
Msrc/lib/exchange_api_batch_withdraw2.c | 68+++++++++++++++++++++++++++++++++-----------------------------------
Msrc/lib/exchange_api_contracts_get.c | 8++++----
Msrc/lib/exchange_api_csr_melt.c | 4++--
Msrc/lib/exchange_api_csr_withdraw.c | 2+-
Msrc/lib/exchange_api_deposit.c | 8++++----
Msrc/lib/exchange_api_deposits_get.c | 22+++++++++++-----------
Msrc/lib/exchange_api_handle.c | 88+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/lib/exchange_api_kyc_check.c | 20++++++++++----------
Msrc/lib/exchange_api_link.c | 4++--
Msrc/lib/exchange_api_lookup_aml_decision.c | 12++++++------
Msrc/lib/exchange_api_lookup_aml_decisions.c | 6+++---
Msrc/lib/exchange_api_management_drain_profits.c | 28++++++++++++++--------------
Msrc/lib/exchange_api_management_get_keys.c | 78++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/lib/exchange_api_management_post_extensions.c | 22+++++++++++-----------
Msrc/lib/exchange_api_management_post_keys.c | 26+++++++++++++-------------
Msrc/lib/exchange_api_management_revoke_denomination_key.c | 22+++++++++++-----------
Msrc/lib/exchange_api_management_revoke_signing_key.c | 22+++++++++++-----------
Msrc/lib/exchange_api_management_update_aml_officer.c | 26+++++++++++++-------------
Msrc/lib/exchange_api_management_wire_disable.c | 30+++++++++++++++---------------
Msrc/lib/exchange_api_management_wire_enable.c | 38++++++++++++++++++++++++--------------
Msrc/lib/exchange_api_melt.c | 10+++++-----
Msrc/lib/exchange_api_purse_deposit.c | 16++++++++--------
Msrc/lib/exchange_api_purse_merge.c | 14+++++++-------
Msrc/lib/exchange_api_purses_get.c | 14+++++++-------
Msrc/lib/exchange_api_recoup.c | 69+++++++++++++++++++++++++++++++++------------------------------------
Msrc/lib/exchange_api_recoup_refresh.c | 67++++++++++++++++++++++++++++++++-----------------------------------
Msrc/lib/exchange_api_refreshes_reveal.c | 4++--
Msrc/lib/exchange_api_refund.c | 75++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/lib/exchange_api_transfers_get.c | 103++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/lib/exchange_api_wire.c | 383++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/lib/exchange_api_withdraw.c | 28+++++++++++++---------------
Msrc/lib/exchange_api_withdraw2.c | 69+++++++++++++++++++++++++++++++++------------------------------------
Msrc/testing/testing_api_cmd_bank_history_credit.c | 4++--
Msrc/testing/testing_api_cmd_bank_history_debit.c | 4++--
Msrc/testing/testing_api_cmd_batch_deposit.c | 10+++++-----
Msrc/testing/testing_api_cmd_batch_withdraw.c | 2+-
Msrc/testing/testing_api_cmd_check_aml_decision.c | 4++--
Msrc/testing/testing_api_cmd_contract_get.c | 10+++++-----
Msrc/testing/testing_api_cmd_deposit.c | 6+++---
Msrc/testing/testing_api_cmd_deposits_get.c | 4++--
Msrc/testing/testing_api_cmd_nexus_fetch_transactions.c | 1+
Msrc/testing/testing_api_cmd_purse_create_deposit.c | 4++--
Msrc/testing/testing_api_cmd_purse_deposit.c | 10+++++-----
Msrc/testing/testing_api_cmd_purse_get.c | 4++--
Msrc/testing/testing_api_cmd_recoup.c | 17+++++------------
Msrc/testing/testing_api_cmd_recoup_refresh.c | 9++++-----
Msrc/testing/testing_api_cmd_refresh.c | 34+++++++++++++++++-----------------
Msrc/testing/testing_api_cmd_refund.c | 13++++---------
Msrc/testing/testing_api_cmd_revoke_denom_key.c | 5+++--
Msrc/testing/testing_api_cmd_revoke_sign_key.c | 7++++---
Msrc/testing/testing_api_cmd_set_officer.c | 6++++--
Msrc/testing/testing_api_cmd_transfer_get.c | 223+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/testing/testing_api_cmd_wire.c | 75+++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/testing/testing_api_cmd_wire_add.c | 22+++++++++++++++++++---
Msrc/testing/testing_api_cmd_wire_del.c | 7++++---
Msrc/testing/testing_api_cmd_withdraw.c | 8++++----
Msrc/testing/testing_api_loop.c | 57+++++++++++++++++++++++++++------------------------------
Msrc/util/offline_signatures.c | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
90 files changed, 2057 insertions(+), 1283 deletions(-)

diff --git a/src/auditor/taler-helper-auditor-wire.c b/src/auditor/taler-helper-auditor-wire.c @@ -1483,10 +1483,10 @@ history_debit_cb (void *cls, switch (dhr->http_status) { case MHD_HTTP_OK: - for (unsigned int i = 0; i<dhr->details.success.details_length; i++) + for (unsigned int i = 0; i<dhr->details.ok.details_length; i++) { const struct TALER_BANK_DebitDetails *dd - = &dhr->details.success.details[i]; + = &dhr->details.ok.details[i]; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Analyzing bank DEBIT at %s of %s with WTID %s\n", GNUNET_TIME_timestamp2s (dd->execution_date), @@ -1978,10 +1978,10 @@ history_credit_cb (void *cls, switch (chr->http_status) { case MHD_HTTP_OK: - for (unsigned int i = 0; i<chr->details.success.details_length; i++) + for (unsigned int i = 0; i<chr->details.ok.details_length; i++) { const struct TALER_BANK_CreditDetails *cd - = &chr->details.success.details[i]; + = &chr->details.ok.details[i]; if (! analyze_credit (wa, cd)) diff --git a/src/bank-lib/bank_api_credit.c b/src/bank-lib/bank_api_credit.c @@ -131,8 +131,8 @@ parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh, return GNUNET_SYSERR; } } - chr.details.success.details_length = len; - chr.details.success.details = cd; + chr.details.ok.details_length = len; + chr.details.ok.details = cd; hh->hcb (hh->hcb_cls, &chr); } diff --git a/src/bank-lib/bank_api_debit.c b/src/bank-lib/bank_api_debit.c @@ -133,8 +133,8 @@ parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh, return GNUNET_SYSERR; } } - dhr.details.success.details_length = len; - dhr.details.success.details = dd; + dhr.details.ok.details_length = len; + dhr.details.ok.details = dd; hh->hcb (hh->hcb_cls, &dhr); } diff --git a/src/bank-lib/taler-exchange-wire-gateway-client.c b/src/bank-lib/taler-exchange-wire-gateway-client.c @@ -179,10 +179,10 @@ credit_history_cb (void *cls, global_ret = 0; break; case MHD_HTTP_OK: - for (unsigned int i = 0; i<reply->details.success.details_length; i++) + for (unsigned int i = 0; i<reply->details.ok.details_length; i++) { const struct TALER_BANK_CreditDetails *cd = - &reply->details.success.details[i]; + &reply->details.ok.details[i]; /* If credit/debit accounts were specified, use as a filter */ if ( (NULL != credit_account) && @@ -279,10 +279,10 @@ debit_history_cb (void *cls, global_ret = 0; break; case MHD_HTTP_OK: - for (unsigned int i = 0; i<reply->details.success.details_length; i++) + for (unsigned int i = 0; i<reply->details.ok.details_length; i++) { const struct TALER_BANK_DebitDetails *dd = - &reply->details.success.details[i]; + &reply->details.ok.details[i]; /* If credit/debit accounts were specified, use as a filter */ if ( (NULL != credit_account) && diff --git a/src/exchange-tools/taler-auditor-offline.c b/src/exchange-tools/taler-auditor-offline.c @@ -644,26 +644,19 @@ do_upload (char *const *args) * a particular exchange and what keys the exchange is using. * * @param cls closure with the `char **` remaining args - * @param hr HTTP response data - * @param keys information about the various keys used - * by the exchange, NULL if /keys failed - * @param compat protocol compatibility information + * @param kr response data */ static void keys_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat) + const struct TALER_EXCHANGE_KeysResponse *kr) { char *const *args = cls; - (void) keys; - (void) compat; - switch (hr->http_status) + switch (kr->hr.http_status) { case MHD_HTTP_OK: - if (! json_is_object (hr->reply)) + if (! json_is_object (kr->hr.reply)) { GNUNET_break (0); TALER_EXCHANGE_disconnect (exchange); @@ -676,9 +669,9 @@ keys_cb ( default: fprintf (stderr, "Failed to download keys: %s (HTTP status: %u/%u)\n", - hr->hint, - hr->http_status, - (unsigned int) hr->ec); + kr->hr.hint, + kr->hr.http_status, + (unsigned int) kr->hr.ec); TALER_EXCHANGE_disconnect (exchange); exchange = NULL; test_shutdown (); @@ -689,7 +682,7 @@ keys_cb ( GNUNET_JSON_pack_string ("operation", OP_INPUT_KEYS), GNUNET_JSON_pack_object_incref ("arguments", - (json_t *) hr->reply)); + (json_t *) kr->hr.reply)); if (NULL == args[0]) { json_dumpf (in, diff --git a/src/exchange-tools/taler-exchange-offline.c b/src/exchange-tools/taler-exchange-offline.c @@ -1119,14 +1119,15 @@ load_offline_key (int do_create) * Function called with information about the post revocation operation result. * * @param cls closure with a `struct DenomRevocationRequest` - * @param hr HTTP response data + * @param dr response data */ static void denom_revocation_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *dr) { struct DenomRevocationRequest *drr = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &dr->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -1208,14 +1209,15 @@ upload_denom_revocation (const char *exchange_url, * Function called with information about the post revocation operation result. * * @param cls closure with a `struct SignkeyRevocationRequest` - * @param hr HTTP response data + * @param sr response data */ static void signkey_revocation_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *sr) { struct SignkeyRevocationRequest *srr = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &sr->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -1489,13 +1491,14 @@ upload_auditor_del (const char *exchange_url, * Function called with information about the post wire add operation result. * * @param cls closure with a `struct WireAddRequest` - * @param hr HTTP response data + * @param wer response data */ static void wire_add_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer) { struct WireAddRequest *war = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -1533,10 +1536,21 @@ upload_wire_add (const char *exchange_url, struct GNUNET_TIME_Timestamp start_time; struct WireAddRequest *war; const char *err_name; + const char *conversion_url = NULL; + json_t *debit_restrictions; + json_t *credit_restrictions; unsigned int err_line; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("payto_uri", &payto_uri), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("conversion_url", + &conversion_url), + NULL), + GNUNET_JSON_spec_json ("debit_restrictions", + &debit_restrictions), + GNUNET_JSON_spec_json ("credit_restrictions", + &credit_restrictions), GNUNET_JSON_spec_timestamp ("validity_start", &start_time), GNUNET_JSON_spec_fixed_auto ("master_sig_add", @@ -1561,6 +1575,7 @@ upload_wire_add (const char *exchange_url, stderr, JSON_INDENT (2)); global_ret = EXIT_FAILURE; + GNUNET_JSON_parse_free (spec); test_shutdown (); return; } @@ -1574,6 +1589,7 @@ upload_wire_add (const char *exchange_url, "payto:// URI `%s' is malformed\n", payto_uri); global_ret = EXIT_FAILURE; + GNUNET_JSON_parse_free (spec); test_shutdown (); return; } @@ -1588,6 +1604,7 @@ upload_wire_add (const char *exchange_url, "payto URI is malformed: %s\n", msg); GNUNET_free (msg); + GNUNET_JSON_parse_free (spec); test_shutdown (); global_ret = EXIT_INVALIDARGUMENT; return; @@ -1599,6 +1616,9 @@ upload_wire_add (const char *exchange_url, TALER_EXCHANGE_management_enable_wire (ctx, exchange_url, payto_uri, + conversion_url, + debit_restrictions, + credit_restrictions, start_time, &master_sig_add, &master_sig_wire, @@ -1607,6 +1627,7 @@ upload_wire_add (const char *exchange_url, GNUNET_CONTAINER_DLL_insert (war_head, war_tail, war); + GNUNET_JSON_parse_free (spec); } @@ -1614,13 +1635,14 @@ upload_wire_add (const char *exchange_url, * Function called with information about the post wire del operation result. * * @param cls closure with a `struct WireDelRequest` - * @param hr HTTP response data + * @param wdres response data */ static void wire_del_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdres) { struct WireDelRequest *wdr = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &wdres->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -1927,14 +1949,15 @@ upload_global_fee (const char *exchange_url, * Function called with information about the drain profits operation. * * @param cls closure with a `struct DrainProfitsRequest` - * @param hr HTTP response data + * @param mdr response data */ static void drain_profits_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementDrainResponse *mdr) { struct DrainProfitsRequest *dpr = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &mdr->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -2033,14 +2056,15 @@ upload_drain (const char *exchange_url, * Function called with information about the post upload keys operation result. * * @param cls closure with a `struct UploadKeysRequest` - * @param hr HTTP response data + * @param mr response data */ static void keys_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementPostKeysResponse *mr) { struct UploadKeysRequest *ukr = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -2206,14 +2230,15 @@ upload_keys (const char *exchange_url, * Function called with information about the post upload extensions operation result. * * @param cls closure with a `struct UploadExtensionsRequest` - * @param hr HTTP response data + * @param er response data */ static void extensions_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementPostExtensionsResponse *er) { struct UploadExtensionsRequest *uer = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &er->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -2447,14 +2472,15 @@ add_partner (const char *exchange_url, * Function called with information about the AML officer update operation. * * @param cls closure with a `struct AmlStaffRequest` - * @param hr HTTP response data + * @param ar response data */ static void update_aml_officer_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *ar) { struct AmlStaffRequest *asr = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr; if (MHD_HTTP_NO_CONTENT != hr->http_status) { @@ -2961,6 +2987,10 @@ do_add_wire (char *const *args) struct TALER_MasterSignatureP master_sig_add; struct TALER_MasterSignatureP master_sig_wire; struct GNUNET_TIME_Timestamp now; + const char *conversion_url = NULL; + json_t *debit_restrictions; + json_t *credit_restrictions; + unsigned int num_args = 1; if (NULL != in) { @@ -3011,24 +3041,43 @@ do_add_wire (char *const *args) } GNUNET_free (wire_method); } + // FIXME: init new args properly! + debit_restrictions = json_array (); + GNUNET_assert (NULL != debit_restrictions); + credit_restrictions = json_array (); + GNUNET_assert (NULL != credit_restrictions); + TALER_exchange_offline_wire_add_sign (args[0], + conversion_url, + debit_restrictions, + credit_restrictions, now, &master_priv, &master_sig_add); TALER_exchange_wire_signature_make (args[0], + conversion_url, + debit_restrictions, + credit_restrictions, &master_priv, &master_sig_wire); output_operation (OP_ENABLE_WIRE, GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("payto_uri", args[0]), + GNUNET_JSON_pack_array_steal ("debit_restrictions", + debit_restrictions), + GNUNET_JSON_pack_array_steal ("credit_restrictions", + credit_restrictions), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("conversion_url", + conversion_url)), GNUNET_JSON_pack_timestamp ("validity_start", now), GNUNET_JSON_pack_data_auto ("master_sig_add", &master_sig_add), GNUNET_JSON_pack_data_auto ("master_sig_wire", &master_sig_wire))); - next (args + 1); + next (args + num_args); } @@ -3643,18 +3692,15 @@ enable_aml_staff (char *const *args) * whether there are subsequent commands). * * @param cls closure with the `char **` remaining args - * @param hr HTTP response data - * @param keys information about the various keys used - * by the exchange, NULL if /management/keys failed + * @param mgr response data */ static void download_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_FutureKeys *keys) + const struct TALER_EXCHANGE_ManagementGetKeysResponse *mgr) { char *const *args = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &mgr->hr; - (void) keys; mgkh = NULL; switch (hr->http_status) { diff --git a/src/exchange/taler-exchange-httpd_config.h b/src/exchange/taler-exchange-httpd_config.h @@ -41,7 +41,7 @@ * * Returned via both /config and /keys endpoints. */ -#define EXCHANGE_PROTOCOL_VERSION "14:0:2" +#define EXCHANGE_PROTOCOL_VERSION "15:0:0" /** diff --git a/src/exchange/taler-exchange-httpd_management_wire_disable.c b/src/exchange/taler-exchange-httpd_management_wire_disable.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020 Taler Systems SA + Copyright (C) 2020-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -114,6 +114,9 @@ del_wire (void *cls, } qs = TEH_plugin->update_wire (TEH_plugin->cls, awc->payto_uri, + NULL, + NULL, + NULL, awc->validity_end, false); if (qs < 0) diff --git a/src/exchange/taler-exchange-httpd_management_wire_enable.c b/src/exchange/taler-exchange-httpd_management_wire_enable.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020 Taler Systems SA + Copyright (C) 2020-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -55,6 +55,21 @@ struct AddWireContext const char *payto_uri; /** + * (optional) address of a conversion service for this account. + */ + const char *conversion_url; + + /** + * Restrictions imposed when crediting this account. + */ + json_t *credit_restrictions; + + /** + * Restrictions imposed when debiting this account. + */ + json_t *debit_restrictions; + + /** * Timestamp for checking against replay attacks. */ struct GNUNET_TIME_Timestamp validity_start; @@ -114,11 +129,17 @@ add_wire (void *cls, if (0 == qs) qs = TEH_plugin->insert_wire (TEH_plugin->cls, awc->payto_uri, + awc->conversion_url, + awc->debit_restrictions, + awc->credit_restrictions, awc->validity_start, &awc->master_sig_wire); else qs = TEH_plugin->update_wire (TEH_plugin->cls, awc->payto_uri, + awc->conversion_url, + awc->debit_restrictions, + awc->credit_restrictions, awc->validity_start, true); if (qs < 0) @@ -141,7 +162,9 @@ TEH_handler_management_post_wire ( struct MHD_Connection *connection, const json_t *root) { - struct AddWireContext awc; + struct AddWireContext awc = { + .conversion_url = NULL + }; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("master_sig_wire", &awc.master_sig_wire), @@ -149,6 +172,14 @@ TEH_handler_management_post_wire ( &awc.master_sig_add), GNUNET_JSON_spec_string ("payto_uri", &awc.payto_uri), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("conversion_url", + &awc.conversion_url), + NULL), + GNUNET_JSON_spec_json ("credit_restrictions", + &awc.credit_restrictions), + GNUNET_JSON_spec_json ("debit_restrictions", + &awc.debit_restrictions), GNUNET_JSON_spec_timestamp ("validity_start", &awc.validity_start), GNUNET_JSON_spec_end () @@ -179,17 +210,22 @@ TEH_handler_management_post_wire ( MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PAYTO_URI_MALFORMED, msg); + GNUNET_JSON_parse_free (spec); GNUNET_free (msg); return ret; } } if (GNUNET_OK != TALER_exchange_offline_wire_add_verify (awc.payto_uri, + awc.conversion_url, + awc.debit_restrictions, + awc.credit_restrictions, awc.validity_start, &TEH_master_public_key, &awc.master_sig_add)) { GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error ( connection, MHD_HTTP_FORBIDDEN, @@ -199,10 +235,14 @@ TEH_handler_management_post_wire ( TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; if (GNUNET_OK != TALER_exchange_wire_signature_check (awc.payto_uri, + awc.conversion_url, + awc.debit_restrictions, + awc.credit_restrictions, &TEH_master_public_key, &awc.master_sig_wire)) { GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error ( connection, MHD_HTTP_FORBIDDEN, @@ -218,6 +258,7 @@ TEH_handler_management_post_wire ( GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "payto:// URI `%s' is malformed\n", awc.payto_uri); + GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error ( connection, MHD_HTTP_BAD_REQUEST, @@ -237,6 +278,7 @@ TEH_handler_management_post_wire ( &ret, &add_wire, &awc); + GNUNET_JSON_parse_free (spec); if (GNUNET_SYSERR == res) return ret; } diff --git a/src/exchange/taler-exchange-httpd_wire.c b/src/exchange/taler-exchange-httpd_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2022 Taler Systems SA + Copyright (C) 2015-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -224,12 +224,18 @@ TEH_wire_done () * * @param cls a `json_t *` object to expand with wire account details * @param payto_uri the exchange bank account URI to add + * @param conversion_url URL of a conversion service, NULL if there is no conversion + * @param debit_restrictions JSON array with debit restrictions on the account + * @param credit_restrictions JSON array with credit restrictions on the account * @param master_sig master key signature affirming that this is a bank * account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS) */ static void add_wire_account (void *cls, const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterSignatureP *master_sig) { json_t *a = cls; @@ -240,6 +246,13 @@ add_wire_account (void *cls, GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("payto_uri", payto_uri), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("conversion_url", + conversion_url)), + GNUNET_JSON_pack_array_incref ("debit_restrictions", + (json_t *) debit_restrictions), + GNUNET_JSON_pack_array_incref ("credit_restrictions", + (json_t *) credit_restrictions), GNUNET_JSON_pack_data_auto ("master_sig", master_sig)))) { @@ -462,6 +475,8 @@ build_wire_state (void) wsh->wire_reply = TALER_MHD_MAKE_JSON_PACK ( GNUNET_JSON_pack_array_steal ("accounts", wire_accounts_array), + GNUNET_JSON_pack_array_steal ("wads", /* #7271 */ + json_array ()), GNUNET_JSON_pack_object_steal ("fees", wire_fee_object), GNUNET_JSON_pack_data_auto ("master_public_key", diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c @@ -731,8 +731,8 @@ history_cb (void *cls, { case MHD_HTTP_OK: process_reply (wrap_size, - reply->details.success.details, - reply->details.success.details_length); + reply->details.ok.details, + reply->details.ok.details_length); return; case MHD_HTTP_NO_CONTENT: transaction_completed (); diff --git a/src/exchangedb/.gitignore b/src/exchangedb/.gitignore @@ -12,4 +12,5 @@ test-exchangedb-batch-reserves-in-insert-postgres test-exchangedb-by-j-postgres test-exchangedb-populate-link-data-postgres test-exchangedb-populate-ready-deposit-postgres -test-exchangedb-populate-select-refunds-by-coin-postgres -\ No newline at end of file +test-exchangedb-populate-select-refunds-by-coin-postgres +exchange-0004.sql diff --git a/src/exchangedb/0004-wire_accounts.sql b/src/exchangedb/0004-wire_accounts.sql @@ -0,0 +1,26 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2023 Taler Systems SA +-- +-- TALER is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +-- + +ALTER TABLE wire_accounts + ADD COLUMN conversion_url VARCHAR DEFAULT (NULL), + ADD COLUMN debit_restrictions VARCHAR DEFAULT (NULL), + ADD COLUMN credit_restrictions VARCHAR DEFAULT (NULL); +COMMENT ON COLUMN wire_accounts.conversion_url + IS 'URL of a currency conversion service if conversion is needed when this account is used; NULL if there is no conversion.'; +COMMENT ON COLUMN wire_accounts.debit_restrictions + IS 'JSON array describing restrictions imposed when debiting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.'; +COMMENT ON COLUMN wire_accounts.credit_restrictions + IS 'JSON array describing restrictions imposed when crediting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.'; diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am @@ -20,7 +20,9 @@ sqlinputs = \ 0002-*.sql \ exchange-0002.sql.in \ 0003-*.sql \ - exchange-0003.sql.in + exchange-0003.sql.in \ + 0004-*.sql \ + exchange-0004.sql.in sql_DATA = \ benchmark-0001.sql \ @@ -28,6 +30,7 @@ sql_DATA = \ exchange-0001.sql \ exchange-0002.sql \ exchange-0003.sql \ + exchange-0004.sql \ drop.sql \ procedures.sql @@ -39,7 +42,8 @@ BUILT_SOURCES = \ CLEANFILES = \ exchange-0002.sql \ - exchange-0003.sql + exchange-0003.sql \ + exchange-0004.sql procedures.sql: procedures.sql.in exchange_do_*.sql chmod +w $@ || true @@ -56,6 +60,11 @@ exchange-0003.sql: exchange-0003.sql.in 0003-*.sql gcc -E -P -undef - < exchange-0003.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@ chmod ugo-w $@ +exchange-0004.sql: exchange-0004.sql.in 0004-*.sql + chmod +w $@ || true + gcc -E -P -undef - < exchange-0004.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@ + chmod ugo-w $@ + EXTRA_DIST = \ exchangedb.conf \ exchangedb-postgres.conf \ diff --git a/src/exchangedb/drop.sql b/src/exchangedb/drop.sql @@ -21,6 +21,7 @@ BEGIN; SELECT _v.unregister_patch('exchange-0001'); SELECT _v.unregister_patch('exchange-0002'); SELECT _v.unregister_patch('exchange-0003'); +SELECT _v.unregister_patch('exchange-0004'); DROP SCHEMA exchange CASCADE; diff --git a/src/exchangedb/exchange-0004.sql.in b/src/exchangedb/exchange-0004.sql.in @@ -0,0 +1,24 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2014--2023 Taler Systems SA +-- +-- TALER is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +-- + +BEGIN; + +SELECT _v.register_patch('exchange-0004', NULL, NULL); +SET search_path TO exchange; + +#include "0004-wire_accounts.sql" + +COMMIT; diff --git a/src/exchangedb/pg_get_wire_accounts.c b/src/exchangedb/pg_get_wire_accounts.c @@ -66,10 +66,25 @@ get_wire_accounts_cb (void *cls, for (unsigned int i = 0; i < num_results; i++) { char *payto_uri; + char *conversion_url = NULL; + json_t *debit_restrictions = NULL; + json_t *credit_restrictions = NULL; struct TALER_MasterSignatureP master_sig; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_string ("payto_uri", &payto_uri), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("conversion_url", + &conversion_url), + NULL), + GNUNET_PQ_result_spec_allow_null ( + TALER_PQ_result_spec_json ("debit_restrictions", + &debit_restrictions), + NULL), + GNUNET_PQ_result_spec_allow_null ( + TALER_PQ_result_spec_json ("credit_restrictions", + &credit_restrictions), + NULL), GNUNET_PQ_result_spec_auto_from_type ("master_sig", &master_sig), GNUNET_PQ_result_spec_end @@ -84,8 +99,21 @@ get_wire_accounts_cb (void *cls, ctx->status = GNUNET_SYSERR; return; } + if (NULL == debit_restrictions) + { + debit_restrictions = json_array (); + GNUNET_assert (NULL != debit_restrictions); + } + if (NULL == credit_restrictions) + { + credit_restrictions = json_array (); + GNUNET_assert (NULL != credit_restrictions); + } ctx->cb (ctx->cb_cls, payto_uri, + conversion_url, + debit_restrictions, + credit_restrictions, &master_sig); GNUNET_PQ_cleanup_result (rs); } @@ -112,6 +140,9 @@ TEH_PG_get_wire_accounts (void *cls, "get_wire_accounts", "SELECT" " payto_uri" + ",conversion_url" + ",debit_restrictions" + ",credit_restrictions" ",master_sig" " FROM wire_accounts" " WHERE is_active"); @@ -123,5 +154,4 @@ TEH_PG_get_wire_accounts (void *cls, if (GNUNET_OK != ctx.status) return GNUNET_DB_STATUS_HARD_ERROR; return qs; - } diff --git a/src/exchangedb/pg_insert_wire.c b/src/exchangedb/pg_insert_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2022 Taler Systems SA + Copyright (C) 2022, 2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -29,12 +29,20 @@ enum GNUNET_DB_QueryStatus TEH_PG_insert_wire (void *cls, const char *payto_uri, + const char *conversion_url, + json_t *debit_restrictions, + json_t *credit_restrictions, struct GNUNET_TIME_Timestamp start_date, const struct TALER_MasterSignatureP *master_sig) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (payto_uri), + NULL == conversion_url + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_string (conversion_url), + TALER_PQ_query_param_json (debit_restrictions), + TALER_PQ_query_param_json (credit_restrictions), GNUNET_PQ_query_param_auto_from_type (master_sig), GNUNET_PQ_query_param_timestamp (&start_date), GNUNET_PQ_query_param_end @@ -44,11 +52,14 @@ TEH_PG_insert_wire (void *cls, "insert_wire", "INSERT INTO wire_accounts " "(payto_uri" + ",conversion_url" + ",debit_restrictions" + ",credit_restrictions" ",master_sig" ",is_active" ",last_change" ") VALUES " - "($1, $2, true, $3);"); + "($1, $2, $3, $4, $5, true, $6);"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "insert_wire", params); diff --git a/src/exchangedb/pg_insert_wire.h b/src/exchangedb/pg_insert_wire.h @@ -29,6 +29,9 @@ * * @param cls closure * @param payto_uri wire account of the exchange + * @param conversion_url URL of a conversion service, NULL if there is no conversion + * @param debit_restrictions JSON array with debit restrictions on the account + * @param credit_restrictions JSON array with credit restrictions on the account * @param start_date date when the account was added by the offline system * (only to be used for replay detection) * @param master_sig public signature affirming the existence of the account, @@ -38,6 +41,9 @@ enum GNUNET_DB_QueryStatus TEH_PG_insert_wire (void *cls, const char *payto_uri, + const char *conversion_url, + json_t *debit_restrictions, + json_t *credit_restrictions, struct GNUNET_TIME_Timestamp start_date, const struct TALER_MasterSignatureP *master_sig); diff --git a/src/exchangedb/pg_update_wire.c b/src/exchangedb/pg_update_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2022 Taler Systems SA + Copyright (C) 2022, 2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -29,6 +29,9 @@ enum GNUNET_DB_QueryStatus TEH_PG_update_wire (void *cls, const char *payto_uri, + const char *conversion_url, + json_t *debit_restrictions, + json_t *credit_restrictions, struct GNUNET_TIME_Timestamp change_date, bool enabled) { @@ -36,17 +39,28 @@ TEH_PG_update_wire (void *cls, struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (payto_uri), GNUNET_PQ_query_param_bool (enabled), + NULL == conversion_url + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_string (conversion_url), + enabled + ? TALER_PQ_query_param_json (debit_restrictions) + : GNUNET_PQ_query_param_null (), + enabled + ? TALER_PQ_query_param_json (credit_restrictions) + : GNUNET_PQ_query_param_null (), GNUNET_PQ_query_param_timestamp (&change_date), GNUNET_PQ_query_param_end }; - /* used in #postgres_update_wire() */ PREPARE (pg, "update_wire", "UPDATE wire_accounts" " SET" " is_active=$2" - " ,last_change=$3" + " ,conversion_url=$3" + " ,debit_restrictions=$4" + " ,credit_restrictions=$5" + " ,last_change=$6" " WHERE payto_uri=$1"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "update_wire", diff --git a/src/exchangedb/pg_update_wire.h b/src/exchangedb/pg_update_wire.h @@ -24,11 +24,16 @@ #include "taler_util.h" #include "taler_json_lib.h" #include "taler_exchangedb_plugin.h" + + /** * Update information about a wire account of the exchange. * * @param cls closure * @param payto_uri account the update is about + * @param conversion_url URL of a conversion service, NULL if there is no conversion + * @param debit_restrictions JSON array with debit restrictions on the account; NULL allowed if not @a enabled + * @param credit_restrictions JSON array with credit restrictions on the account; NULL allowed if not @a enabled * @param change_date date when the account status was last changed * (only to be used for replay detection) * @param enabled true to enable, false to disable (the actual change) @@ -37,6 +42,9 @@ enum GNUNET_DB_QueryStatus TEH_PG_update_wire (void *cls, const char *payto_uri, + const char *conversion_url, + json_t *debit_restrictions, + json_t *credit_restrictions, struct GNUNET_TIME_Timestamp change_date, bool enabled); diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h @@ -111,6 +111,7 @@ struct TALER_BANK_AdminAddIncomingHandle; * @param timestamp time when the transaction was made. * @param json detailed response from the HTTPD, or NULL if reply was not in JSON */ +// FIXME: bad API typedef void (*TALER_BANK_AdminAddIncomingCallback) ( void *cls, @@ -199,6 +200,7 @@ struct TALER_BANK_TransferHandle; * @param row_id unique ID of the wire transfer in the bank's records * @param timestamp when did the transaction go into effect */ +// FIXME: bad API typedef void (*TALER_BANK_TransferCallback)( void *cls, @@ -337,7 +339,7 @@ struct TALER_BANK_CreditHistoryResponse */ unsigned int details_length; - } success; + } ok; } details; @@ -493,7 +495,7 @@ struct TALER_BANK_DebitHistoryResponse */ unsigned int details_length; - } success; + } ok; } details; diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h @@ -5512,6 +5512,9 @@ TALER_exchange_offline_global_fee_verify ( * Create wire account addition signature. * * @param payto_uri bank account + * @param conversion_url URL of the conversion service, or NULL if none + * @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec + * @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec * @param now timestamp to use for the signature (rounded) * @param master_priv private key to sign with * @param[out] master_sig where to write the signature @@ -5519,6 +5522,9 @@ TALER_exchange_offline_global_fee_verify ( void TALER_exchange_offline_wire_add_sign ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp now, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig); @@ -5528,6 +5534,9 @@ TALER_exchange_offline_wire_add_sign ( * Verify wire account addition signature. * * @param payto_uri bank account + * @param conversion_url URL of the conversion service, or NULL if none + * @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec + * @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec * @param sign_time timestamp when signature was created * @param master_pub public key to verify against * @param master_sig the signature the signature @@ -5536,6 +5545,9 @@ TALER_exchange_offline_wire_add_sign ( enum GNUNET_GenericReturnValue TALER_exchange_offline_wire_add_verify ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp sign_time, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig); @@ -5578,6 +5590,9 @@ TALER_exchange_offline_wire_del_verify ( * Check the signature in @a master_sig. * * @param payto_uri URI that is signed + * @param conversion_url URL of the conversion service, or NULL if none + * @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec + * @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec * @param master_pub master public key of the exchange * @param master_sig signature of the exchange * @return #GNUNET_OK if signature is valid @@ -5585,6 +5600,9 @@ TALER_exchange_offline_wire_del_verify ( enum GNUNET_GenericReturnValue TALER_exchange_wire_signature_check ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig); @@ -5593,12 +5611,18 @@ TALER_exchange_wire_signature_check ( * Create a signed wire statement for the given account. * * @param payto_uri account specification + * @param conversion_url URL of the conversion service, or NULL if none + * @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec + * @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec * @param master_priv private key to sign with * @param[out] master_sig where to write the signature */ void TALER_exchange_wire_signature_make ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig); diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h @@ -462,21 +462,52 @@ struct TALER_EXCHANGE_HttpResponse /** + * Response from /keys. + */ +struct TALER_EXCHANGE_KeysResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Details depending on the HTTP status code. + */ + union + { + + /** + * Details on #MHD_HTTP_OK. + */ + struct + { + /** + * Information about the various keys used by the exchange. + */ + const struct TALER_EXCHANGE_Keys *keys; + + /** + * Protocol compatibility information + */ + enum TALER_EXCHANGE_VersionCompatibility compat; + } ok; + } details; + +}; + + +/** * Function called with information about who is auditing * a particular exchange and what keys the exchange is using. * * @param cls closure - * @param hr HTTP response data - * @param keys information about the various keys used - * by the exchange, NULL if /keys failed - * @param compat protocol compatibility information + * @param kr response from /keys */ typedef void (*TALER_EXCHANGE_CertificationCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat); + const struct TALER_EXCHANGE_KeysResponse *kr); /** @@ -712,7 +743,7 @@ TALER_EXCHANGE_get_signing_key_info ( /** - * Sorted list of fees to be paid for aggregate wire transfers. + * List sorted by @a start_date with fees to be paid for aggregate wire transfers. */ struct TALER_EXCHANGE_WireAggregateFees { @@ -744,6 +775,95 @@ struct TALER_EXCHANGE_WireAggregateFees /** + * Information about wire fees by wire method. + */ +struct TALER_EXCHANGE_WireFeesByMethod +{ + /** + * Wire method with the given @e fees. + */ + const char *method; + + /** + * Linked list of wire fees the exchange charges for + * accounts of the wire @e method. + */ + struct TALER_EXCHANGE_WireAggregateFees *fees_head; + +}; + + +/** + * Type of an account restriction. + */ +enum TALER_EXCHANGE_AccountRestrictionType +{ + /** + * Invalid restriction. + */ + TALER_EXCHANGE_AR_INVALID = 0, + + /** + * Account must not be used for this operation. + */ + TALER_EXCHANGE_AR_DENY = 1, + + /** + * Other account must match given regular expression. + */ + TALER_EXCHANGE_AR_REGEX = 2 +}; + +/** + * Restrictions that apply to using a given exchange bank account. + */ +struct TALER_EXCHANGE_AccountRestriction +{ + + /** + * Type of the account restriction. + */ + enum TALER_EXCHANGE_AccountRestrictionType type; + + /** + * Restriction details depending on @e type. + */ + union + { + /** + * Details if type is #TALER_EXCHANGE_AR_REGEX. + */ + struct + { + /** + * Regular expression that the payto://-URI of the partner account must + * follow. The regular expression should follow posix-egrep, but + * without support for character classes, GNU extensions, + * back-references or intervals. See + * https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002degrep-regular-expression-syntax.html + * for a description of the posix-egrep syntax. Applications may support + * regexes with additional features, but exchanges must not use such + * regexes. + */ + const char *posix_egrep; + + /** + * Hint for a human to understand the restriction. + */ + const char *human_hint; + + /** + * Internationalizations for the @e human_hint. Map from IETF BCP 47 + * language tax to localized human hints. + */ + const json_t *human_hint_i18n; + } regex; + } details; + +}; + + +/** * Information about a wire account of the exchange. */ struct TALER_EXCHANGE_WireAccount @@ -754,37 +874,103 @@ struct TALER_EXCHANGE_WireAccount const char *payto_uri; /** + * URL of a conversion service in case using this account is subject to + * currency conversion. NULL for no conversion needed. + */ + const char *conversion_url; + + /** + * Array of restrictions that apply when crediting + * this account. + */ + struct TALER_EXCHANGE_AccountRestriction *credit_restrictions; + + /** + * Array of restrictions that apply when debiting + * this account. + */ + struct TALER_EXCHANGE_AccountRestriction *debit_restrictions; + + /** + * Length of the @e credit_restrictions array. + */ + unsigned int credit_restrictions_length; + + /** + * Length of the @e debit_restrictions array. + */ + unsigned int debit_restrictions_length; + + /** * Signature of the exchange over the account (was checked by the API). */ struct TALER_MasterSignatureP master_sig; +}; + + +/** + * Response to a /wire request. + */ +struct TALER_EXCHANGE_WireResponse +{ /** - * Linked list of wire fees the exchange charges for - * accounts of the wire method matching @e payto_uri. + * HTTP response details. */ - const struct TALER_EXCHANGE_WireAggregateFees *fees; + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Response details depending on status. + */ + union + { + + /** + * Details for #MHD_HTTP_OK. + */ + struct + { + + /** + * Array of accounts of the exchange. + */ + const struct TALER_EXCHANGE_WireAccount *accounts; + /** + * Array of wire fees by wire method. + */ + const struct TALER_EXCHANGE_WireFeesByMethod *fees; + + /** + * Length of @e accounts array. + */ + unsigned int accounts_len; + + /** + * Length of @e fees array. + */ + unsigned int fees_len; + + } ok; + + } details; }; /** - * Callbacks of this type are used to serve the result of submitting a - * wire format inquiry request to a exchange. + * Callbacks of this type are used to serve the result of submitting a wire + * format inquiry request to a exchange. * * If the request fails to generate a valid response from the - * exchange, @a http_status will also be zero. + * exchange, the http_status will also be zero. * * @param cls closure - * @param hr HTTP response data - * @param accounts_len length of the @a accounts array - * @param accounts list of wire accounts of the exchange, NULL on error + * @param wr response data */ typedef void (*TALER_EXCHANGE_WireCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - unsigned int accounts_len, - const struct TALER_EXCHANGE_WireAccount *accounts); + const struct TALER_EXCHANGE_WireResponse *wr); /** @@ -976,7 +1162,7 @@ struct TALER_EXCHANGE_DepositResult */ const char *transaction_base_url; - } success; + } ok; /** * Information returned if the HTTP status is @@ -1110,7 +1296,7 @@ struct TALER_EXCHANGE_BatchDepositResult */ unsigned int num_signatures; - } success; + } ok; /** * Information returned if the HTTP status is @@ -1202,23 +1388,51 @@ TALER_EXCHANGE_batch_deposit_cancel ( */ struct TALER_EXCHANGE_RefundHandle; +/** + * Response from the /refund API. + */ +struct TALER_EXCHANGE_RefundResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Response details depending on the HTTP status code. + */ + union + { + /** + * Details on #MHD_HTTP_OK. + */ + struct + { + /** + * Exchange key used to sign. + */ + struct TALER_ExchangePublicKeyP exchange_pub; + + /** + * The actual signature + */ + struct TALER_ExchangeSignatureP exchange_sig; + } ok; + } details; +}; + /** * Callbacks of this type are used to serve the result of submitting a * refund request to an exchange. * * @param cls closure - * @param hr HTTP response data - * @param sign_key exchange key used to sign @a obj, or NULL - * @param signature the actual signature, or NULL on error + * @param rr refund response */ typedef void (*TALER_EXCHANGE_RefundCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_ExchangePublicKeyP *sign_key, - const struct TALER_ExchangeSignatureP *signature); - + const struct TALER_EXCHANGE_RefundResponse *rr); /** * Submit a refund request to the exchange and get the exchange's response. @@ -1311,7 +1525,7 @@ struct TALER_EXCHANGE_CsRMeltResponse * respective coin's withdraw operation. */ const struct TALER_ExchangeWithdrawValues *alg_values; - } success; + } ok; /** * Details if the status is #MHD_HTTP_GONE. @@ -1423,7 +1637,7 @@ struct TALER_EXCHANGE_CsRWithdrawResponse * respective coin's withdraw operation. */ struct TALER_ExchangeWithdrawValues alg_values; - } success; + } ok; /** * Details if the status is #MHD_HTTP_GONE. @@ -2209,7 +2423,7 @@ struct TALER_EXCHANGE_WithdrawResponse /** * Details if the status is #MHD_HTTP_OK. */ - struct TALER_EXCHANGE_PrivateCoinDetails success; + struct TALER_EXCHANGE_PrivateCoinDetails ok; /** * Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS. @@ -2336,7 +2550,7 @@ struct TALER_EXCHANGE_BatchWithdrawResponse * Length of the @e coins array. */ unsigned int num_coins; - } success; + } ok; /** * Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS. @@ -2431,18 +2645,45 @@ TALER_EXCHANGE_batch_withdraw_cancel ( /** + * Response from a withdraw2 request. + */ +struct TALER_EXCHANGE_Withdraw2Response +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Response details depending on the HTTP status. + */ + union + { + /** + * Details if HTTP status is #MHD_HTTP_OK. + */ + struct + { + /** + * blind signature over the coin + */ + struct TALER_BlindedDenominationSignature blind_sig; + } ok; + } details; + +}; + +/** * Callbacks of this type are used to serve the result of submitting a * withdraw request to a exchange without the (un)blinding factor. * * @param cls closure - * @param hr HTTP response data - * @param blind_sig blind signature over the coin, NULL on error + * @param w2r response data */ typedef void (*TALER_EXCHANGE_Withdraw2Callback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_BlindedDenominationSignature *blind_sig); + const struct TALER_EXCHANGE_Withdraw2Response *w2r); /** @@ -2493,20 +2734,52 @@ TALER_EXCHANGE_withdraw2_cancel (struct TALER_EXCHANGE_Withdraw2Handle *wh); /** + * Response from a batch-withdraw request (2nd variant). + */ +struct TALER_EXCHANGE_BatchWithdraw2Response +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Response details depending on the HTTP status. + */ + union + { + /** + * Details if HTTP status is #MHD_HTTP_OK. + */ + struct + { + /** + * array of blind signatures over the coins. + */ + const struct TALER_BlindedDenominationSignature *blind_sigs; + + /** + * length of @e blind_sigs + */ + unsigned int blind_sigs_length; + + } ok; + } details; + +}; + + +/** * Callbacks of this type are used to serve the result of submitting a batch * withdraw request to a exchange without the (un)blinding factor. * * @param cls closure - * @param hr HTTP response data - * @param blind_sigs array of blind signatures over the coins, NULL on error - * @param blind_sigs_length length of @a blind_sigs + * @param bw2r response data */ typedef void (*TALER_EXCHANGE_BatchWithdraw2Callback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_BlindedDenominationSignature *blind_sigs, - unsigned int blind_sigs_length); + const struct TALER_EXCHANGE_BatchWithdraw2Response *bw2r); /** @@ -2675,7 +2948,7 @@ struct TALER_EXCHANGE_MeltResponse * Gamma value chosen by the exchange. */ uint32_t noreveal_index; - } success; + } ok; } details; }; @@ -2801,7 +3074,7 @@ struct TALER_EXCHANGE_RevealResult * Number of coins returned. */ unsigned int num_coins; - } success; + } ok; } details; @@ -2947,7 +3220,7 @@ struct TALER_EXCHANGE_LinkResult * Number of coins returned. */ unsigned int num_coins; - } success; + } ok; } details; @@ -3060,18 +3333,43 @@ struct TALER_EXCHANGE_TransferData /** + * Response for a GET /transfers request. + */ +struct TALER_EXCHANGE_TransfersGetResponse +{ + /** + * HTTP response. + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Details depending on HTTP status code. + */ + union + { + /** + * Details if status code is #MHD_HTTP_OK. + */ + struct + { + struct TALER_EXCHANGE_TransferData td; + } ok; + + } details; +}; + + +/** * Function called with detailed wire transfer data, including all * of the coin transactions that were combined into the wire transfer. * * @param cls closure - * @param hr HTTP response data - * @param ta transfer data, (set only if @a http_status is #MHD_HTTP_OK, otherwise NULL) + * @param tgr response data */ typedef void (*TALER_EXCHANGE_TransfersGetCallback)( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_TransferData *ta); + const struct TALER_EXCHANGE_TransfersGetResponse *tgr); /** @@ -3163,7 +3461,7 @@ struct TALER_EXCHANGE_GetDepositResponse */ struct TALER_Amount coin_contribution; - } success; + } ok; /** * Response if the status was #MHD_HTTP_ACCEPTED @@ -3316,20 +3614,49 @@ struct TALER_EXCHANGE_RecoupHandle; /** + * Response from a recoup request. + */ +struct TALER_EXCHANGE_RecoupResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Response details depending on the HTTP status. + */ + union + { + /** + * Details if HTTP status is #MHD_HTTP_OK. + */ + struct + { + /** + * public key of the reserve receiving the recoup + */ + struct TALER_ReservePublicKeyP reserve_pub; + + } ok; + } details; + +}; + + +/** * Callbacks of this type are used to return the final result of * submitting a recoup request to a exchange. If the operation was * successful, this function returns the @a reserve_pub of the * reserve that was credited. * * @param cls closure - * @param hr HTTP response data - * @param reserve_pub public key of the reserve receiving the recoup + * @param rr response data */ typedef void (*TALER_EXCHANGE_RecoupResultCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_ReservePublicKeyP *reserve_pub); + const struct TALER_EXCHANGE_RecoupResponse *rr); /** @@ -3378,18 +3705,47 @@ struct TALER_EXCHANGE_RecoupRefreshHandle; /** + * Response from a /recoup-refresh request. + */ +struct TALER_EXCHANGE_RecoupRefreshResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Response details depending on the HTTP status. + */ + union + { + /** + * Details if HTTP status is #MHD_HTTP_OK. + */ + struct + { + /** + * public key of the dirty coin that was credited + */ + struct TALER_CoinSpendPublicKeyP old_coin_pub; + + } ok; + } details; + +}; + + +/** * Callbacks of this type are used to return the final result of * submitting a recoup-refresh request to a exchange. * * @param cls closure - * @param hr HTTP response data - * @param old_coin_pub public key of the dirty coin that was credited + * @param rrr response data */ typedef void (*TALER_EXCHANGE_RecoupRefreshResultCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_CoinSpendPublicKeyP *old_coin_pub); + const struct TALER_EXCHANGE_RecoupRefreshResponse *rrr); /** @@ -3495,7 +3851,7 @@ struct TALER_EXCHANGE_KycStatus */ enum TALER_AmlDecisionState aml_status; - } success; + } ok; /** * KYC is required. @@ -3899,18 +4255,47 @@ struct TALER_EXCHANGE_FutureKeys /** + * Response from a /management/keys request. + */ +struct TALER_EXCHANGE_ManagementGetKeysResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + + /** + * Response details depending on the HTTP status. + */ + union + { + /** + * Details if HTTP status is #MHD_HTTP_OK. + */ + struct + { + /** + * information about the various keys used + * by the exchange + */ + struct TALER_EXCHANGE_FutureKeys keys; + + } ok; + } details; + +}; + + +/** * Function called with information about future keys. * * @param cls closure - * @param hr HTTP response data - * @param keys information about the various keys used - * by the exchange, NULL if /management/keys failed + * @param mgr HTTP response data */ typedef void (*TALER_EXCHANGE_ManagementGetKeysCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_FutureKeys *keys); + const struct TALER_EXCHANGE_ManagementGetKeysResponse *mgr); /** @@ -4013,15 +4398,28 @@ struct TALER_EXCHANGE_ManagementPostKeysData /** + * Response from a POST /management/keys request. + */ +struct TALER_EXCHANGE_ManagementPostKeysResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + +}; + + +/** * Function called with information about the post keys operation result. * * @param cls closure - * @param hr HTTP response data + * @param mr response data */ typedef void (*TALER_EXCHANGE_ManagementPostKeysCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementPostKeysResponse *mr); /** @@ -4071,6 +4469,20 @@ struct TALER_EXCHANGE_ManagementPostExtensionsData struct TALER_MasterSignatureP extensions_sig; }; + +/** + * Response from a POST /management/extensions request. + */ +struct TALER_EXCHANGE_ManagementPostExtensionsResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + +}; + + /** * Function called with information about the post extensions operation result. * @@ -4080,7 +4492,7 @@ struct TALER_EXCHANGE_ManagementPostExtensionsData typedef void (*TALER_EXCHANGE_ManagementPostExtensionsCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementPostExtensionsResponse *hr); /** * @brief Handle for a POST /management/extensions request. @@ -4119,6 +4531,19 @@ TALER_EXCHANGE_management_post_extensions_cancel ( /** + * Response from a POST /management/drain request. + */ +struct TALER_EXCHANGE_ManagementDrainResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + +}; + + +/** * Function called with information about the drain profits result. * * @param cls closure @@ -4127,7 +4552,7 @@ TALER_EXCHANGE_management_post_extensions_cancel ( typedef void (*TALER_EXCHANGE_ManagementDrainProfitsCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementDrainResponse *hr); /** @@ -4176,6 +4601,19 @@ TALER_EXCHANGE_management_drain_profits_cancel ( /** + * Response from a POST /management/denominations/$DENOM/revoke request. + */ +struct TALER_EXCHANGE_ManagementRevokeDenominationResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + +}; + + +/** * Function called with information about the post revocation operation result. * * @param cls closure @@ -4184,7 +4622,7 @@ TALER_EXCHANGE_management_drain_profits_cancel ( typedef void (*TALER_EXCHANGE_ManagementRevokeDenominationKeyCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *hr); /** @@ -4225,6 +4663,18 @@ TALER_EXCHANGE_management_revoke_denomination_key_cancel ( /** + * Response from a POST /management/signkeys/$SK/revoke request. + */ +struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + +}; + +/** * Function called with information about the post revocation operation result. * * @param cls closure @@ -4233,7 +4683,7 @@ TALER_EXCHANGE_management_revoke_denomination_key_cancel ( typedef void (*TALER_EXCHANGE_ManagementRevokeSigningKeyCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *hr); /** @@ -4274,6 +4724,18 @@ TALER_EXCHANGE_management_revoke_signing_key_cancel ( /** + * Response from a POST /management/aml-officers request. + */ +struct TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse +{ + /** + * HTTP response data + */ + struct TALER_EXCHANGE_HttpResponse hr; + +}; + +/** * Function called with information about the change to * an AML officer status. * @@ -4283,7 +4745,7 @@ TALER_EXCHANGE_management_revoke_signing_key_cancel ( typedef void (*TALER_EXCHANGE_ManagementUpdateAmlOfficerCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *hr); /** @@ -4390,7 +4852,7 @@ struct TALER_EXCHANGE_AmlDecisionsResponse */ unsigned int decisions_length; - } success; + } ok; } details; }; @@ -4547,7 +5009,7 @@ struct TALER_EXCHANGE_AmlDecisionResponse */ unsigned int kyc_attributes_length; - } success; + } ok; } details; }; @@ -4617,6 +5079,7 @@ struct TALER_EXCHANGE_AddAmlDecision; * @param cls closure * @param hr HTTP response data */ +// FIXME: bad API typedef void (*TALER_EXCHANGE_AddAmlDecisionCallback) ( void *cls, @@ -4672,6 +5135,7 @@ TALER_EXCHANGE_add_aml_decision_cancel ( * @param cls closure * @param hr HTTP response data */ +// FIXME: bad API typedef void (*TALER_EXCHANGE_ManagementAddPartnerCallback) ( void *cls, @@ -4732,6 +5196,7 @@ TALER_EXCHANGE_management_add_partner_cancel ( * @param cls closure * @param hr HTTP response data */ +// FIXME: bad API typedef void (*TALER_EXCHANGE_ManagementAuditorEnableCallback) ( void *cls, @@ -4787,6 +5252,7 @@ TALER_EXCHANGE_management_enable_auditor_cancel ( * @param cls closure * @param hr HTTP response data */ +// FIXME: bad API typedef void (*TALER_EXCHANGE_ManagementAuditorDisableCallback) ( void *cls, @@ -4833,15 +5299,27 @@ TALER_EXCHANGE_management_disable_auditor_cancel ( /** + * Response from an exchange account/enable operation. + */ +struct TALER_EXCHANGE_ManagementWireEnableResponse +{ + /** + * HTTP response data. + */ + struct TALER_EXCHANGE_HttpResponse hr; +}; + + +/** * Function called with information about the wire enable operation result. * * @param cls closure - * @param hr HTTP response data + * @param wer HTTP response data */ typedef void (*TALER_EXCHANGE_ManagementWireEnableCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer); /** @@ -4856,6 +5334,9 @@ struct TALER_EXCHANGE_ManagementWireEnableHandle; * @param ctx the context * @param url HTTP base URL for the exchange * @param payto_uri RFC 8905 URI of the exchange's bank account + * @param conversion_url URL of the conversion service, or NULL if none + * @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec + * @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec * @param validity_start when was this decided? * @param master_sig1 signature affirming the wire addition * of purpose #TALER_SIGNATURE_MASTER_ADD_WIRE @@ -4870,6 +5351,9 @@ TALER_EXCHANGE_management_enable_wire ( struct GNUNET_CURL_Context *ctx, const char *url, const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp validity_start, const struct TALER_MasterSignatureP *master_sig1, const struct TALER_MasterSignatureP *master_sig2, @@ -4888,15 +5372,26 @@ TALER_EXCHANGE_management_enable_wire_cancel ( /** + * Response from an exchange account/disable operation. + */ +struct TALER_EXCHANGE_ManagementWireDisableResponse +{ + /** + * HTTP response data. + */ + struct TALER_EXCHANGE_HttpResponse hr; +}; + +/** * Function called with information about the wire disable operation result. * * @param cls closure - * @param hr HTTP response data + * @param wdr response data */ typedef void (*TALER_EXCHANGE_ManagementWireDisableCallback) ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr); + const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdr); /** @@ -4945,6 +5440,7 @@ TALER_EXCHANGE_management_disable_wire_cancel ( * @param cls closure * @param hr HTTP response data */ +// FIXME: bad API typedef void (*TALER_EXCHANGE_ManagementSetWireFeeCallback) ( void *cls, @@ -5001,6 +5497,7 @@ TALER_EXCHANGE_management_set_wire_fees_cancel ( * @param cls closure * @param hr HTTP response data */ +// FIXME: bad API typedef void (*TALER_EXCHANGE_ManagementSetGlobalFeeCallback) ( void *cls, @@ -5062,6 +5559,7 @@ TALER_EXCHANGE_management_set_global_fees_cancel ( * @param cls closure * @param hr HTTP response data */ +// FIXME: bad API typedef void (*TALER_EXCHANGE_AuditorAddDenominationCallback) ( void *cls, @@ -5147,7 +5645,7 @@ struct TALER_EXCHANGE_ContractGetResponse */ size_t econtract_size; - } success; + } ok; } details; @@ -5243,7 +5741,7 @@ struct TALER_EXCHANGE_PurseGetResponse */ struct GNUNET_TIME_Timestamp purse_expiration; - } success; + } ok; } details; @@ -5333,7 +5831,7 @@ struct TALER_EXCHANGE_PurseCreateDepositResponse struct TALER_ExchangeSignatureP exchange_sig; - } success; + } ok; } details; @@ -5532,7 +6030,7 @@ struct TALER_EXCHANGE_AccountMergeResponse */ struct GNUNET_TIME_Timestamp etime; - } success; + } ok; /** * Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS. @@ -5640,7 +6138,7 @@ struct TALER_EXCHANGE_PurseCreateMergeResponse struct { - } success; + } ok; /** * Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS. @@ -5760,7 +6258,7 @@ struct TALER_EXCHANGE_PurseDepositResponse */ struct TALER_PrivateContractHashP h_contract_terms; - } success; + } ok; } details; }; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h @@ -2881,6 +2881,9 @@ typedef enum GNUNET_GenericReturnValue * * @param cls closure * @param payto_uri the exchange bank account URI + * @param conversion_url URL of a conversion service, NULL if there is no conversion + * @param debit_restrictions JSON array with debit restrictions on the account + * @param credit_restrictions JSON array with credit restrictions on the account * @param master_sig master key signature affirming that this is a bank * account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS) */ @@ -2888,6 +2891,9 @@ typedef void (*TALER_EXCHANGEDB_WireAccountCallback)( void *cls, const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterSignatureP *master_sig); @@ -5544,6 +5550,9 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls closure * @param payto_uri wire account of the exchange + * @param conversion_url URL of a conversion service, NULL if there is no conversion + * @param debit_restrictions JSON array with debit restrictions on the account + * @param credit_restrictions JSON array with credit restrictions on the account * @param start_date date when the account was added by the offline system * (only to be used for replay detection) * @param master_sig public signature affirming the existence of the account, @@ -5553,6 +5562,9 @@ struct TALER_EXCHANGEDB_Plugin enum GNUNET_DB_QueryStatus (*insert_wire)(void *cls, const char *payto_uri, + const char *conversion_url, + json_t *debit_restrictions, + json_t *credit_restrictions, struct GNUNET_TIME_Timestamp start_date, const struct TALER_MasterSignatureP *master_sig); @@ -5562,6 +5574,9 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls closure * @param payto_uri account the update is about + * @param conversion_url URL of a conversion service, NULL if there is no conversion + * @param debit_restrictions JSON array with debit restrictions on the account; NULL allowed if not @a enabled + * @param credit_restrictions JSON array with credit restrictions on the account; NULL allowed if not @a enabled * @param change_date date when the account status was last changed * (only to be used for replay detection) * @param enabled true to enable, false to disable (the actual change) @@ -5570,6 +5585,9 @@ struct TALER_EXCHANGEDB_Plugin enum GNUNET_DB_QueryStatus (*update_wire)(void *cls, const char *payto_uri, + const char *conversion_url, + json_t *debit_restrictions, + json_t *credit_restrictions, struct GNUNET_TIME_Timestamp change_date, bool enabled); diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h @@ -675,33 +675,6 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s, /** - * Check the signature in @a wire_s. Also performs rudimentary - * checks on the account data *if* supported. - * - * @param wire_s signed wire information of an exchange - * @param master_pub master public key of the exchange - * @return #GNUNET_OK if signature is valid - */ -enum GNUNET_GenericReturnValue -TALER_JSON_exchange_wire_signature_check ( - const json_t *wire_s, - const struct TALER_MasterPublicKeyP *master_pub); - - -/** - * Create a signed wire statement for the given account. - * - * @param payto_uri account specification - * @param master_priv private key to sign with - * @return NULL if @a payto_uri is malformed - */ -json_t * -TALER_JSON_exchange_wire_signature_make ( - const char *payto_uri, - const struct TALER_MasterPrivateKeyP *master_priv); - - -/** * Extract a string from @a object under the field @a field, but respecting * the Taler i18n rules and the language preferences expressed in @a * language_pattern. diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h @@ -147,15 +147,11 @@ TALER_TESTING_prepare_exchange (const char *config_filename, * * @param cls closure, typically, the "run" method containing * all the commands to be run, and a closure for it. - * @param hr http response details - * @param keys the exchange's keys. - * @param compat protocol compatibility information. + * @param kr response details */ void TALER_TESTING_cert_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat); + const struct TALER_EXCHANGE_KeysResponse *kr); /** diff --git a/src/json/Makefile.am b/src/json/Makefile.am @@ -28,12 +28,10 @@ libtalerjson_la_LIBADD = \ $(XLIB) TESTS = \ - test_json \ - test_json_wire + test_json check_PROGRAMS= \ - test_json \ - test_json_wire + test_json test_json_SOURCES = \ test_json.c @@ -43,13 +41,3 @@ test_json_LDADD = \ $(top_builddir)/src/util/libtalerutil.la \ -lgnunetutil \ -ljansson - - -test_json_wire_SOURCES = \ - test_json_wire.c -test_json_wire_LDADD = \ - $(top_builddir)/src/json/libtalerjson.la \ - -lgnunetjson \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetutil \ - -ljansson diff --git a/src/json/json_wire.c b/src/json/json_wire.c @@ -70,80 +70,6 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s, } -enum GNUNET_GenericReturnValue -TALER_JSON_exchange_wire_signature_check ( - const json_t *wire_s, - const struct TALER_MasterPublicKeyP *master_pub) -{ - const char *payto_uri; - struct TALER_MasterSignatureP master_sig; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("payto_uri", - &payto_uri), - GNUNET_JSON_spec_fixed_auto ("master_sig", - &master_sig), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (wire_s, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - { - char *err; - - err = TALER_payto_validate (payto_uri); - if (NULL != err) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "URI `%s' ill-formed: %s\n", - payto_uri, - err); - GNUNET_free (err); - return GNUNET_SYSERR; - } - } - - return TALER_exchange_wire_signature_check (payto_uri, - master_pub, - &master_sig); -} - - -json_t * -TALER_JSON_exchange_wire_signature_make ( - const char *payto_uri, - const struct TALER_MasterPrivateKeyP *master_priv) -{ - struct TALER_MasterSignatureP master_sig; - char *err; - - if (NULL != - (err = TALER_payto_validate (payto_uri))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid payto URI `%s': %s\n", - payto_uri, - err); - GNUNET_free (err); - return NULL; - } - TALER_exchange_wire_signature_make (payto_uri, - master_priv, - &master_sig); - return GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("payto_uri", - payto_uri), - GNUNET_JSON_pack_data_auto ("master_sig", - &master_sig)); -} - - char * TALER_JSON_wire_to_payto (const json_t *wire_s) { diff --git a/src/json/test_json_wire.c b/src/json/test_json_wire.c @@ -1,80 +0,0 @@ -/* - This file is part of TALER - (C) 2015, 2016 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file json/test_json_wire.c - * @brief Tests for Taler-specific crypto logic - * @author Christian Grothoff <christian@grothoff.org> - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_json_lib.h" - - -int -main (int argc, - const char *const argv[]) -{ - struct TALER_MasterPublicKeyP master_pub; - struct TALER_MasterPrivateKeyP master_priv; - json_t *wire_xtalerbank; - json_t *wire_iban; - const char *payto_xtalerbank = "payto://x-taler-bank/42"; - const char *payto_iban = - "payto://iban/BIC-TO-BE-SKIPPED/DE89370400440532013000?receiver-name=Test"; - char *p_xtalerbank; - char *p_iban; - - (void) argc; - (void) argv; - GNUNET_log_setup ("test-json-wire", - "WARNING", - NULL); - GNUNET_CRYPTO_eddsa_key_create (&master_priv.eddsa_priv); - GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv, - &master_pub.eddsa_pub); - wire_xtalerbank = TALER_JSON_exchange_wire_signature_make (payto_xtalerbank, - &master_priv); - wire_iban = TALER_JSON_exchange_wire_signature_make (payto_iban, - &master_priv); - if (NULL == wire_iban) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not parse payto/IBAN (%s) into 'wire object'\n", - payto_iban); - return 1; - } - p_xtalerbank = TALER_JSON_wire_to_payto (wire_xtalerbank); - p_iban = TALER_JSON_wire_to_payto (wire_iban); - GNUNET_assert (0 == strcmp (p_xtalerbank, payto_xtalerbank)); - GNUNET_assert (0 == strcmp (p_iban, payto_iban)); - GNUNET_free (p_xtalerbank); - GNUNET_free (p_iban); - - GNUNET_assert (GNUNET_OK == - TALER_JSON_exchange_wire_signature_check (wire_xtalerbank, - &master_pub)); - GNUNET_assert (GNUNET_OK == - TALER_JSON_exchange_wire_signature_check (wire_iban, - &master_pub)); - json_decref (wire_xtalerbank); - json_decref (wire_iban); - - return 0; -} - - -/* end of test_json_wire.c */ diff --git a/src/lib/exchange_api_batch_deposit.c b/src/lib/exchange_api_batch_deposit.c @@ -247,7 +247,7 @@ handle_deposit_finished (void *cls, &dh->exchange_pub), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("transaction_base_url", - &dr.details.success.transaction_base_url), + &dr.details.ok.transaction_base_url), NULL), GNUNET_JSON_spec_timestamp ("exchange_timestamp", &dh->exchange_timestamp), @@ -332,7 +332,7 @@ handle_deposit_finished (void *cls, GNUNET_break_op (0); dr.hr.http_status = 0; dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; - GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (spec); break; } } @@ -341,10 +341,10 @@ handle_deposit_finished (void *cls, dh); GNUNET_JSON_parse_free (spec); } - dr.details.success.exchange_sigs = dh->exchange_sigs; - dr.details.success.exchange_pub = &dh->exchange_pub; - dr.details.success.deposit_timestamp = dh->exchange_timestamp; - dr.details.success.num_signatures = dh->num_cdds; + dr.details.ok.exchange_sigs = dh->exchange_sigs; + dr.details.ok.exchange_pub = &dh->exchange_pub; + dr.details.ok.deposit_timestamp = dh->exchange_timestamp; + dr.details.ok.num_signatures = dh->num_cdds; break; case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy diff --git a/src/lib/exchange_api_batch_withdraw.c b/src/lib/exchange_api_batch_withdraw.c @@ -144,37 +144,34 @@ struct TALER_EXCHANGE_BatchWithdrawHandle * HTTP /reserves/$RESERVE_PUB/batch-withdraw request. * * @param cls the `struct TALER_EXCHANGE_BatchWithdrawHandle` - * @param hr HTTP response data - * @param blind_sigs array of blind signatures over the coins, NULL on error - * @param blind_sigs_length length of the @a blind_sigs array + * @param bw2r response data */ static void handle_reserve_batch_withdraw_finished ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_BlindedDenominationSignature *blind_sigs, - unsigned int blind_sigs_length) + const struct TALER_EXCHANGE_BatchWithdraw2Response *bw2r) { struct TALER_EXCHANGE_BatchWithdrawHandle *wh = cls; struct TALER_EXCHANGE_BatchWithdrawResponse wr = { - .hr = *hr + .hr = bw2r->hr }; - struct TALER_EXCHANGE_PrivateCoinDetails coins[wh->num_coins]; + struct TALER_EXCHANGE_PrivateCoinDetails coins[GNUNET_NZL (wh->num_coins)]; wh->wh2 = NULL; memset (coins, 0, sizeof (coins)); - if (blind_sigs_length != wh->num_coins) - { - GNUNET_break_op (0); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } - switch (hr->http_status) + switch (bw2r->hr.http_status) { case MHD_HTTP_OK: { + if (bw2r->details.ok.blind_sigs_length != wh->num_coins) + { + GNUNET_break_op (0); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } for (unsigned int i = 0; i<wh->num_coins; i++) { struct CoinData *cd = &wh->coins[i]; @@ -183,7 +180,7 @@ handle_reserve_batch_withdraw_finished ( if (GNUNET_OK != TALER_planchet_to_coin (&cd->pk.key, - &blind_sigs[i], + &bw2r->details.ok.blind_sigs[i], &cd->bks, &cd->priv, cd->ach, @@ -200,8 +197,8 @@ handle_reserve_batch_withdraw_finished ( coin->sig = fc.sig; coin->exchange_vals = cd->alg_values; } - wr.details.success.coins = coins; - wr.details.success.num_coins = wh->num_coins; + wr.details.ok.coins = coins; + wr.details.ok.num_coins = wh->num_coins; break; } case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: @@ -217,7 +214,7 @@ handle_reserve_batch_withdraw_finished ( }; if (GNUNET_OK != - GNUNET_JSON_parse (hr->reply, + GNUNET_JSON_parse (bw2r->hr.reply, spec, NULL, NULL)) { @@ -289,7 +286,7 @@ withdraw_cs_stage_two_callback ( switch (csrr->hr.http_status) { case MHD_HTTP_OK: - cd->alg_values = csrr->details.success.alg_values; + cd->alg_values = csrr->details.ok.alg_values; TALER_planchet_setup_coin_priv (&cd->ps, &cd->alg_values, &cd->priv); diff --git a/src/lib/exchange_api_batch_withdraw2.c b/src/lib/exchange_api_batch_withdraw2.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -108,9 +108,9 @@ reserve_batch_withdraw_ok (struct TALER_EXCHANGE_BatchWithdraw2Handle *wh, "ev_sigs"); const json_t *j; unsigned int index; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = json, - .http_status = MHD_HTTP_OK + struct TALER_EXCHANGE_BatchWithdraw2Response bwr = { + .hr.reply = json, + .hr.http_status = MHD_HTTP_OK }; if ( (NULL == ja) || @@ -141,10 +141,10 @@ reserve_batch_withdraw_ok (struct TALER_EXCHANGE_BatchWithdraw2Handle *wh, } /* signature is valid, return it to the application */ + bwr.details.ok.blind_sigs = blind_sigs; + bwr.details.ok.blind_sigs_length = wh->num_coins; wh->cb (wh->cb_cls, - &hr, - blind_sigs, - wh->num_coins); + &bwr); /* make sure callback isn't called again after return */ wh->cb = NULL; for (unsigned int i = 0; i<wh->num_coins; i++) @@ -264,16 +264,16 @@ handle_reserve_batch_withdraw_finished (void *cls, { struct TALER_EXCHANGE_BatchWithdraw2Handle *wh = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_BatchWithdraw2Response bwr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; wh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + bwr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: if (GNUNET_OK != @@ -281,8 +281,8 @@ handle_reserve_batch_withdraw_finished (void *cls, j)) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + bwr.hr.http_status = 0; + bwr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } GNUNET_assert (NULL == wh->cb); @@ -304,8 +304,8 @@ handle_reserve_batch_withdraw_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + bwr.hr.http_status = 0; + bwr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } } @@ -313,24 +313,24 @@ handle_reserve_batch_withdraw_finished (void *cls, case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + bwr.hr.ec = TALER_JSON_get_error_code (j); + bwr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: GNUNET_break_op (0); /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + bwr.hr.ec = TALER_JSON_get_error_code (j); + bwr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, the exchange basically just says that it doesn't know this reserve. Can happen if we query before the wire transfer went through. We should simply pass the JSON reply to the application. */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + bwr.hr.ec = TALER_JSON_get_error_code (j); + bwr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_CONFLICT: /* The exchange says that the reserve has insufficient funds; @@ -340,13 +340,13 @@ handle_reserve_batch_withdraw_finished (void *cls, j)) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + bwr.hr.http_status = 0; + bwr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; } else { - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + bwr.hr.ec = TALER_JSON_get_error_code (j); + bwr.hr.hint = TALER_JSON_get_error_hint (j); } break; case MHD_HTTP_GONE: @@ -354,32 +354,30 @@ handle_reserve_batch_withdraw_finished (void *cls, /* Note: one might want to check /keys for revocation signature here, alas tricky in case our /keys is outdated => left to clients */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + bwr.hr.ec = TALER_JSON_get_error_code (j); + bwr.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 */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + bwr.hr.ec = TALER_JSON_get_error_code (j); + bwr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + bwr.hr.ec = TALER_JSON_get_error_code (j); + bwr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange batch withdraw\n", (unsigned int) response_code, - (int) hr.ec); + (int) bwr.hr.ec); break; } if (NULL != wh->cb) { wh->cb (wh->cb_cls, - &hr, - NULL, - 0); + &bwr); wh->cb = NULL; } TALER_EXCHANGE_batch_withdraw2_cancel (wh); diff --git a/src/lib/exchange_api_contracts_get.c b/src/lib/exchange_api_contracts_get.c @@ -109,7 +109,7 @@ handle_contract_get_finished (void *cls, struct TALER_PurseContractSignatureP econtract_sig; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("purse_pub", - &dr.details.success.purse_pub), + &dr.details.ok.purse_pub), GNUNET_JSON_spec_fixed_auto ("econtract_sig", &econtract_sig), GNUNET_JSON_spec_varsize ("econtract", @@ -133,7 +133,7 @@ handle_contract_get_finished (void *cls, econtract, econtract_size, &cgh->cpub, - &dr.details.success.purse_pub, + &dr.details.ok.purse_pub, &econtract_sig)) { GNUNET_break (0); @@ -142,8 +142,8 @@ handle_contract_get_finished (void *cls, GNUNET_JSON_parse_free (spec); break; } - dr.details.success.econtract = econtract; - dr.details.success.econtract_size = econtract_size; + dr.details.ok.econtract = econtract; + dr.details.ok.econtract_size = econtract_size; cgh->cb (cgh->cb_cls, &dr); GNUNET_JSON_parse_free (spec); diff --git a/src/lib/exchange_api_csr_melt.c b/src/lib/exchange_api_csr_melt.c @@ -94,8 +94,8 @@ csr_ok (struct TALER_EXCHANGE_CsRMeltHandle *csrh, struct TALER_ExchangeWithdrawValues alg_values[GNUNET_NZL (alen)]; struct TALER_EXCHANGE_CsRMeltResponse csrr = { .hr = *hr, - .details.success.alg_values_len = alen, - .details.success.alg_values = alg_values + .details.ok.alg_values_len = alen, + .details.ok.alg_values = alg_values }; for (unsigned int i = 0; i<alen; i++) diff --git a/src/lib/exchange_api_csr_withdraw.c b/src/lib/exchange_api_csr_withdraw.c @@ -96,7 +96,7 @@ csr_ok (struct TALER_EXCHANGE_CsRWithdrawHandle *csrh, struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_exchange_withdraw_values ( "ewv", - &csrr.details.success.alg_values), + &csrr.details.ok.alg_values), GNUNET_JSON_spec_end () }; diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c @@ -236,7 +236,7 @@ handle_deposit_finished (void *cls, &dh->exchange_pub), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("transaction_base_url", - &dr.details.success.transaction_base_url), + &dr.details.ok.transaction_base_url), NULL), GNUNET_JSON_spec_timestamp ("exchange_timestamp", &dh->exchange_timestamp), @@ -297,9 +297,9 @@ handle_deposit_finished (void *cls, &auditor_cb, dh); } - dr.details.success.exchange_sig = &dh->exchange_sig; - dr.details.success.exchange_pub = &dh->exchange_pub; - dr.details.success.deposit_timestamp = dh->exchange_timestamp; + dr.details.ok.exchange_sig = &dh->exchange_sig; + dr.details.ok.exchange_pub = &dh->exchange_pub; + dr.details.ok.deposit_timestamp = dh->exchange_timestamp; break; case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy diff --git a/src/lib/exchange_api_deposits_get.c b/src/lib/exchange_api_deposits_get.c @@ -118,15 +118,15 @@ handle_deposit_wtid_finished (void *cls, { struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("wtid", - &dr.details.success.wtid), + &dr.details.ok.wtid), GNUNET_JSON_spec_timestamp ("execution_time", - &dr.details.success.execution_time), + &dr.details.ok.execution_time), TALER_JSON_spec_amount_any ("coin_contribution", - &dr.details.success.coin_contribution), + &dr.details.ok.coin_contribution), GNUNET_JSON_spec_fixed_auto ("exchange_sig", - &dr.details.success.exchange_sig), + &dr.details.ok.exchange_sig), GNUNET_JSON_spec_fixed_auto ("exchange_pub", - &dr.details.success.exchange_pub), + &dr.details.ok.exchange_pub), GNUNET_JSON_spec_end () }; const struct TALER_EXCHANGE_Keys *key_state; @@ -145,7 +145,7 @@ handle_deposit_wtid_finished (void *cls, } if (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_state, - &dr.details.success.exchange_pub)) + &dr.details.ok.exchange_pub)) { GNUNET_break_op (0); dr.hr.http_status = 0; @@ -156,12 +156,12 @@ handle_deposit_wtid_finished (void *cls, TALER_exchange_online_confirm_wire_verify ( &dwh->h_wire, &dwh->h_contract_terms, - &dr.details.success.wtid, + &dr.details.ok.wtid, &dwh->coin_pub, - dr.details.success.execution_time, - &dr.details.success.coin_contribution, - &dr.details.success.exchange_pub, - &dr.details.success.exchange_sig)) + dr.details.ok.execution_time, + &dr.details.ok.coin_contribution, + &dr.details.ok.exchange_pub, + &dr.details.ok.exchange_sig)) { GNUNET_break_op (0); dr.hr.http_status = 0; diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -40,7 +40,7 @@ * Which version of the Taler protocol is implemented * by this library? Used to determine compatibility. */ -#define EXCHANGE_PROTOCOL_CURRENT 14 +#define EXCHANGE_PROTOCOL_CURRENT 15 /** * How many versions are we backwards compatible with? @@ -1305,15 +1305,18 @@ keys_completed_cb (void *cls, { struct KeysRequest *kr = cls; struct TALER_EXCHANGE_Handle *exchange = kr->exchange; - struct TALER_EXCHANGE_Keys kd; struct TALER_EXCHANGE_Keys kd_old; - enum TALER_EXCHANGE_VersionCompatibility vc; const json_t *j = resp_obj; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_Keys kd; + struct TALER_EXCHANGE_KeysResponse kresp = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code, + .details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR, }; + memset (&kd, + 0, + sizeof (kd)); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received keys from URL `%s' with status %ld and expiration %s.\n", kr->url, @@ -1330,10 +1333,6 @@ keys_completed_cb (void *cls, GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION)); } kd_old = exchange->key_data; - memset (&kd, - 0, - sizeof (struct TALER_EXCHANGE_Keys)); - vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR; switch (response_code) { case 0: @@ -1358,8 +1357,10 @@ keys_completed_cb (void *cls, } /* We keep the denomination keys and auditor signatures from the previous iteration (/keys cherry picking) */ - kd.num_denom_keys = kd_old.num_denom_keys; - kd.last_denom_issue_date = kd_old.last_denom_issue_date; + kd.num_denom_keys + = kd_old.num_denom_keys; + kd.last_denom_issue_date + = kd_old.last_denom_issue_date; GNUNET_array_grow (kd.denom_keys, kd.denom_keys_size, kd.num_denom_keys); @@ -1401,11 +1402,11 @@ keys_completed_cb (void *cls, decode_keys_json (j, true, &kd, - &vc)) + &kresp.details.ok.compat)) { TALER_LOG_ERROR ("Could not decode /keys response\n"); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + kresp.hr.http_status = 0; + kresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; for (unsigned int i = 0; i<kd.num_auditors; i++) { struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i]; @@ -1436,13 +1437,13 @@ keys_completed_cb (void *cls, case MHD_HTTP_NOT_FOUND: if (NULL == j) { - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = TALER_ErrorCode_get_hint (hr.ec); + kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec); } else { - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + kresp.hr.ec = TALER_JSON_get_error_code (j); + kresp.hr.hint = TALER_JSON_get_error_hint (j); } break; default: @@ -1450,18 +1451,18 @@ keys_completed_cb (void *cls, exchange->keys_error_count++; if (NULL == j) { - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = TALER_ErrorCode_get_hint (hr.ec); + kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec); } else { - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + kresp.hr.ec = TALER_JSON_get_error_code (j); + kresp.hr.hint = TALER_JSON_get_error_hint (j); } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d\n", (unsigned int) response_code, - (int) hr.ec); + (int) kresp.hr.ec); break; } exchange->key_data = kd; @@ -1491,9 +1492,7 @@ keys_completed_cb (void *cls, free_key_data (&kd_old); /* notify application that we failed */ exchange->cert_cb (exchange->cert_cb_cls, - &hr, - NULL, - vc); + &kresp); return; } @@ -1504,11 +1503,11 @@ keys_completed_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Successfully downloaded exchange's keys\n"); update_auditors (exchange); + kresp.details.ok.keys = &exchange->key_data; + /* notify application about the key information */ exchange->cert_cb (exchange->cert_cb_cls, - &hr, - &exchange->key_data, - vc); + &kresp); free_key_data (&kd_old); } @@ -1702,7 +1701,6 @@ static void deserialize_data (struct TALER_EXCHANGE_Handle *exchange, const json_t *data) { - enum TALER_EXCHANGE_VersionCompatibility vc; json_t *keys; const char *url; uint32_t version; @@ -1719,10 +1717,11 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange, GNUNET_JSON_spec_end () }; struct TALER_EXCHANGE_Keys key_data; - struct TALER_EXCHANGE_HttpResponse hr = { - .ec = TALER_EC_NONE, - .http_status = MHD_HTTP_OK, - .reply = data + struct TALER_EXCHANGE_KeysResponse kresp = { + .hr.ec = TALER_EC_NONE, + .hr.http_status = MHD_HTTP_OK, + .hr.reply = data, + .details.ok.keys = &exchange->key_data }; if (NULL == data) @@ -1754,7 +1753,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange, decode_keys_json (keys, false, &key_data, - &vc)) + &kresp.details.ok.compat)) { GNUNET_break (0); GNUNET_JSON_parse_free (spec); @@ -1771,9 +1770,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange, update_auditors (exchange); /* notify application about the key information */ exchange->cert_cb (exchange->cert_cb_cls, - &hr, - &exchange->key_data, - vc); + &kresp); GNUNET_JSON_parse_free (spec); } @@ -2056,17 +2053,18 @@ request_keys (void *cls) url); if (NULL == kr->url) { - struct TALER_EXCHANGE_HttpResponse hr = { - .ec = TALER_EC_GENERIC_CONFIGURATION_INVALID + struct TALER_EXCHANGE_KeysResponse kresp = { + .hr.ec = TALER_EC_GENERIC_CONFIGURATION_INVALID, + /* Next line is technically unnecessary, as the + http status we set is 0 */ + .details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR }; GNUNET_free (kr); exchange->keys_error_count++; exchange->state = MHS_FAILED; exchange->cert_cb (exchange->cert_cb_cls, - &hr, - NULL, - TALER_EXCHANGE_VC_PROTOCOL_ERROR); + &kresp); return; } diff --git a/src/lib/exchange_api_kyc_check.c b/src/lib/exchange_api_kyc_check.c @@ -100,11 +100,11 @@ handle_kyc_check_finished (void *cls, uint32_t status; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("exchange_sig", - &ks.details.success.exchange_sig), + &ks.details.ok.exchange_sig), GNUNET_JSON_spec_fixed_auto ("exchange_pub", - &ks.details.success.exchange_pub), + &ks.details.ok.exchange_pub), GNUNET_JSON_spec_timestamp ("now", - &ks.details.success.timestamp), + &ks.details.ok.timestamp), GNUNET_JSON_spec_json ("kyc_details", &kyc_details), GNUNET_JSON_spec_uint32 ("aml_status", @@ -123,13 +123,13 @@ handle_kyc_check_finished (void *cls, ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; } - ks.details.success.kyc_details = kyc_details; - ks.details.success.aml_status + ks.details.ok.kyc_details = kyc_details; + ks.details.ok.aml_status = (enum TALER_AmlDecisionState) status; key_state = TALER_EXCHANGE_get_keys (kch->exchange); if (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_state, - &ks.details.success.exchange_pub)) + &ks.details.ok.exchange_pub)) { GNUNET_break_op (0); ks.http_status = 0; @@ -141,10 +141,10 @@ handle_kyc_check_finished (void *cls, if (GNUNET_OK != TALER_exchange_online_account_setup_success_verify ( &kch->h_payto, - ks.details.success.kyc_details, - ks.details.success.timestamp, - &ks.details.success.exchange_pub, - &ks.details.success.exchange_sig)) + ks.details.ok.kyc_details, + ks.details.ok.timestamp, + &ks.details.ok.exchange_pub, + &ks.details.ok.exchange_sig)) { GNUNET_break_op (0); ks.http_status = 0; diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c @@ -365,8 +365,8 @@ parse_link_ok (struct TALER_EXCHANGE_LinkHandle *lh, if (off_coin == num_coins) { - lr.details.success.num_coins = num_coins; - lr.details.success.coins = lcis; + lr.details.ok.num_coins = num_coins; + lr.details.ok.coins = lcis; lh->link_cb (lh->link_cb_cls, &lr); lh->link_cb = NULL; diff --git a/src/lib/exchange_api_lookup_aml_decision.c b/src/lib/exchange_api_lookup_aml_decision.c @@ -190,17 +190,17 @@ parse_decision_ok (struct TALER_EXCHANGE_LookupAmlDecision *lh, GNUNET_break_op (0); return GNUNET_SYSERR; } - lr.details.success.aml_history_length = json_array_size (aml_history); - lr.details.success.kyc_attributes_length = json_array_size (kyc_attributes); + lr.details.ok.aml_history_length = json_array_size (aml_history); + lr.details.ok.kyc_attributes_length = json_array_size (kyc_attributes); { struct TALER_EXCHANGE_AmlDecisionDetail aml_history_ar[ - GNUNET_NZL (lr.details.success.aml_history_length)]; + GNUNET_NZL (lr.details.ok.aml_history_length)]; struct TALER_EXCHANGE_KycHistoryDetail kyc_attributes_ar[ - lr.details.success.kyc_attributes_length]; + lr.details.ok.kyc_attributes_length]; enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; - lr.details.success.aml_history = aml_history_ar; - lr.details.success.kyc_attributes = kyc_attributes_ar; + lr.details.ok.aml_history = aml_history_ar; + lr.details.ok.kyc_attributes = kyc_attributes_ar; ret = parse_aml_history (aml_history, aml_history_ar); if (GNUNET_OK == ret) diff --git a/src/lib/exchange_api_lookup_aml_decisions.c b/src/lib/exchange_api_lookup_aml_decisions.c @@ -139,13 +139,13 @@ parse_decisions_ok (struct TALER_EXCHANGE_LookupAmlDecisions *lh, GNUNET_break_op (0); return GNUNET_SYSERR; } - lr.details.success.decisions_length = json_array_size (records); + lr.details.ok.decisions_length = json_array_size (records); { struct TALER_EXCHANGE_AmlDecisionSummary decisions[ - GNUNET_NZL (lr.details.success.decisions_length)]; + GNUNET_NZL (lr.details.ok.decisions_length)]; enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; - lr.details.success.decisions = decisions; + lr.details.ok.decisions = decisions; ret = parse_aml_decisions (records, decisions); if (GNUNET_OK == ret) diff --git a/src/lib/exchange_api_management_drain_profits.c b/src/lib/exchange_api_management_drain_profits.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020-2022 Taler Systems SA + Copyright (C) 2020-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -79,9 +79,9 @@ handle_drain_profits_finished (void *cls, { struct TALER_EXCHANGE_ManagementDrainProfitsHandle *dp = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementDrainResponse dr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; dp->job = NULL; @@ -90,32 +90,32 @@ handle_drain_profits_finished (void *cls, case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dr.hr.ec = TALER_JSON_get_error_code (json); + dr.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_CONFLICT: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dr.hr.ec = TALER_JSON_get_error_code (json); + dr.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_PRECONDITION_FAILED: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dr.hr.ec = TALER_JSON_get_error_code (json); + dr.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dr.hr.ec = TALER_JSON_get_error_code (json); + dr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management drain profits\n", (unsigned int) response_code, - (int) hr.ec); + (int) dr.hr.ec); break; } if (NULL != dp->cb) { dp->cb (dp->cb_cls, - &hr); + &dr); dp->cb = NULL; } TALER_EXCHANGE_management_drain_profits_cancel (dp); diff --git a/src/lib/exchange_api_management_get_keys.c b/src/lib/exchange_api_management_get_keys.c @@ -75,11 +75,16 @@ struct TALER_EXCHANGE_ManagementGetKeysHandle * @param response the response * @return #GNUNET_OK if the response was well-formed */ -static int +static enum GNUNET_GenericReturnValue handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, const json_t *response) { - struct TALER_EXCHANGE_FutureKeys fk; + struct TALER_EXCHANGE_ManagementGetKeysResponse gkr = { + .hr.http_status = MHD_HTTP_OK, + .hr.reply = response, + }; + struct TALER_EXCHANGE_FutureKeys *fk + = &gkr.details.ok.keys; json_t *sk; json_t *dk; bool ok; @@ -89,13 +94,13 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, GNUNET_JSON_spec_json ("future_signkeys", &sk), GNUNET_JSON_spec_fixed_auto ("master_pub", - &fk.master_pub), + &fk->master_pub), GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key", - &fk.denom_secmod_public_key), + &fk->denom_secmod_public_key), GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key", - &fk.denom_secmod_cs_public_key), + &fk->denom_secmod_cs_public_key), GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key", - &fk.signkey_secmod_public_key), + &fk->signkey_secmod_public_key), GNUNET_JSON_spec_end () }; @@ -107,21 +112,21 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, GNUNET_break_op (0); return GNUNET_SYSERR; } - fk.num_sign_keys = json_array_size (sk); - fk.num_denom_keys = json_array_size (dk); - fk.sign_keys = GNUNET_new_array ( - fk.num_sign_keys, + fk->num_sign_keys = json_array_size (sk); + fk->num_denom_keys = json_array_size (dk); + fk->sign_keys = GNUNET_new_array ( + fk->num_sign_keys, struct TALER_EXCHANGE_FutureSigningPublicKey); - fk.denom_keys = GNUNET_new_array ( - fk.num_denom_keys, + fk->denom_keys = GNUNET_new_array ( + fk->num_denom_keys, struct TALER_EXCHANGE_FutureDenomPublicKey); ok = true; - for (unsigned int i = 0; i<fk.num_sign_keys; i++) + for (unsigned int i = 0; i<fk->num_sign_keys; i++) { json_t *j = json_array_get (sk, i); struct TALER_EXCHANGE_FutureSigningPublicKey *sign_key - = &fk.sign_keys[i]; + = &fk->sign_keys[i]; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("key", &sign_key->key), @@ -155,7 +160,7 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, &sign_key->key, sign_key->valid_from, duration, - &fk.signkey_secmod_public_key, + &fk->signkey_secmod_public_key, &sign_key->signkey_secmod_sig)) { GNUNET_break_op (0); @@ -164,12 +169,12 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, } } } - for (unsigned int i = 0; i<fk.num_denom_keys; i++) + for (unsigned int i = 0; i<fk->num_denom_keys; i++) { json_t *j = json_array_get (dk, i); struct TALER_EXCHANGE_FutureDenomPublicKey *denom_key - = &fk.denom_keys[i]; + = &fk->denom_keys[i]; const char *section_name; struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount_any ("value", @@ -236,7 +241,7 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, section_name, denom_key->valid_from, duration, - &fk.denom_secmod_public_key, + &fk->denom_secmod_public_key, &denom_key->denom_secmod_sig)) { GNUNET_break_op (0); @@ -256,7 +261,7 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, section_name, denom_key->valid_from, duration, - &fk.denom_secmod_cs_public_key, + &fk->denom_secmod_cs_public_key, &denom_key->denom_secmod_sig)) { GNUNET_break_op (0); @@ -277,19 +282,13 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, } if (ok) { - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = MHD_HTTP_OK, - .reply = response - }; - gh->cb (gh->cb_cls, - &hr, - &fk); + &gkr); } - for (unsigned int i = 0; i<fk.num_denom_keys; i++) - TALER_denom_pub_free (&fk.denom_keys[i].key); - GNUNET_free (fk.sign_keys); - GNUNET_free (fk.denom_keys); + for (unsigned int i = 0; i<fk->num_denom_keys; i++) + TALER_denom_pub_free (&fk->denom_keys[i].key); + GNUNET_free (fk->sign_keys); + GNUNET_free (fk->denom_keys); GNUNET_JSON_parse_free (spec); return (ok) ? GNUNET_OK : GNUNET_SYSERR; } @@ -310,9 +309,9 @@ handle_get_keys_finished (void *cls, { struct TALER_EXCHANGE_ManagementGetKeysHandle *gh = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementGetKeysResponse gkr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; gh->job = NULL; @@ -334,25 +333,24 @@ handle_get_keys_finished (void *cls, /* unexpected response code */ if (NULL != json) { - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + gkr.hr.ec = TALER_JSON_get_error_code (json); + gkr.hr.hint = TALER_JSON_get_error_hint (json); } else { - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = TALER_ErrorCode_get_hint (hr.ec); + gkr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + gkr.hr.hint = TALER_ErrorCode_get_hint (gkr.hr.ec); } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management get keys\n", (unsigned int) response_code, - (int) hr.ec); + (int) gkr.hr.ec); break; } if (NULL != gh->cb) { gh->cb (gh->cb_cls, - &hr, - NULL); + &gkr); gh->cb = NULL; } TALER_EXCHANGE_get_management_keys_cancel (gh); diff --git a/src/lib/exchange_api_management_post_extensions.c b/src/lib/exchange_api_management_post_extensions.c @@ -83,9 +83,9 @@ handle_post_extensions_finished (void *cls, { struct TALER_EXCHANGE_ManagementPostExtensionsHandle *ph = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementPostExtensionsResponse per = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; ph->job = NULL; @@ -94,28 +94,28 @@ handle_post_extensions_finished (void *cls, case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + per.hr.ec = TALER_JSON_get_error_code (json); + per.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_NOT_FOUND: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + per.hr.ec = TALER_JSON_get_error_code (json); + per.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + per.hr.ec = TALER_JSON_get_error_code (json); + per.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management post extensions\n", (unsigned int) response_code, - (int) hr.ec); + (int) per.hr.ec); break; } if (NULL != ph->cb) { ph->cb (ph->cb_cls, - &hr); + &per); ph->cb = NULL; } TALER_EXCHANGE_management_post_extensions_cancel (ph); diff --git a/src/lib/exchange_api_management_post_keys.c b/src/lib/exchange_api_management_post_keys.c @@ -82,9 +82,9 @@ handle_post_keys_finished (void *cls, { struct TALER_EXCHANGE_ManagementPostKeysHandle *ph = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementPostKeysResponse pkr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; ph->job = NULL; @@ -93,32 +93,32 @@ handle_post_keys_finished (void *cls, case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + pkr.hr.ec = TALER_JSON_get_error_code (json); + pkr.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_NOT_FOUND: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + pkr.hr.ec = TALER_JSON_get_error_code (json); + pkr.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_REQUEST_ENTITY_TOO_LARGE: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + pkr.hr.ec = TALER_JSON_get_error_code (json); + pkr.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + pkr.hr.ec = TALER_JSON_get_error_code (json); + pkr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management post keys\n", (unsigned int) response_code, - (int) hr.ec); + (int) pkr.hr.ec); break; } if (NULL != ph->cb) { ph->cb (ph->cb_cls, - &hr); + &pkr); ph->cb = NULL; } TALER_EXCHANGE_post_management_keys_cancel (ph); diff --git a/src/lib/exchange_api_management_revoke_denomination_key.c b/src/lib/exchange_api_management_revoke_denomination_key.c @@ -82,9 +82,9 @@ handle_revoke_denomination_finished (void *cls, { struct TALER_EXCHANGE_ManagementRevokeDenominationKeyHandle *rh = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementRevokeDenominationResponse rdr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; rh->job = NULL; @@ -92,30 +92,30 @@ handle_revoke_denomination_finished (void *cls, { case 0: /* no reply */ - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = "server offline?"; + rdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + rdr.hr.hint = "server offline?"; break; case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + rdr.hr.ec = TALER_JSON_get_error_code (json); + rdr.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + rdr.hr.ec = TALER_JSON_get_error_code (json); + rdr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management revoke denomination\n", (unsigned int) response_code, - (int) hr.ec); + (int) rdr.hr.ec); break; } if (NULL != rh->cb) { rh->cb (rh->cb_cls, - &hr); + &rdr); rh->cb = NULL; } TALER_EXCHANGE_management_revoke_denomination_key_cancel (rh); diff --git a/src/lib/exchange_api_management_revoke_signing_key.c b/src/lib/exchange_api_management_revoke_signing_key.c @@ -79,9 +79,9 @@ handle_revoke_signing_finished (void *cls, { struct TALER_EXCHANGE_ManagementRevokeSigningKeyHandle *rh = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse rsr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; rh->job = NULL; @@ -89,30 +89,30 @@ handle_revoke_signing_finished (void *cls, { case 0: /* no reply */ - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = "server offline?"; + rsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + rsr.hr.hint = "server offline?"; break; case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + rsr.hr.ec = TALER_JSON_get_error_code (json); + rsr.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + rsr.hr.ec = TALER_JSON_get_error_code (json); + rsr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management revoke signkey\n", (unsigned int) response_code, - (int) hr.ec); + (int) rsr.hr.ec); break; } if (NULL != rh->cb) { rh->cb (rh->cb_cls, - &hr); + &rsr); rh->cb = NULL; } TALER_EXCHANGE_management_revoke_signing_key_cancel (rh); diff --git a/src/lib/exchange_api_management_update_aml_officer.c b/src/lib/exchange_api_management_update_aml_officer.c @@ -79,9 +79,9 @@ handle_update_aml_officer_finished (void *cls, { struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *wh = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse uar = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; wh->job = NULL; @@ -89,34 +89,34 @@ handle_update_aml_officer_finished (void *cls, { case 0: /* no reply */ - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = "server offline?"; + uar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + uar.hr.hint = "server offline?"; break; case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + uar.hr.ec = TALER_JSON_get_error_code (json); + uar.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_CONFLICT: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + uar.hr.ec = TALER_JSON_get_error_code (json); + uar.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + uar.hr.ec = TALER_JSON_get_error_code (json); + uar.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management update AML officer\n", (unsigned int) response_code, - (int) hr.ec); + (int) uar.hr.ec); break; } if (NULL != wh->cb) { wh->cb (wh->cb_cls, - &hr); + &uar); wh->cb = NULL; } TALER_EXCHANGE_management_update_aml_officer_cancel (wh); diff --git a/src/lib/exchange_api_management_wire_disable.c b/src/lib/exchange_api_management_wire_disable.c @@ -79,9 +79,9 @@ handle_auditor_disable_finished (void *cls, { struct TALER_EXCHANGE_ManagementWireDisableHandle *wh = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementWireDisableResponse wdr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; wh->job = NULL; @@ -89,38 +89,38 @@ handle_auditor_disable_finished (void *cls, { case 0: /* no reply */ - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = "server offline?"; + wdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + wdr.hr.hint = "server offline?"; break; case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + wdr.hr.ec = TALER_JSON_get_error_code (json); + wdr.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_NOT_FOUND: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + wdr.hr.ec = TALER_JSON_get_error_code (json); + wdr.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_CONFLICT: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + wdr.hr.ec = TALER_JSON_get_error_code (json); + wdr.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + wdr.hr.ec = TALER_JSON_get_error_code (json); + wdr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d exchange management disable wire\n", (unsigned int) response_code, - (int) hr.ec); + (int) wdr.hr.ec); break; } if (NULL != wh->cb) { wh->cb (wh->cb_cls, - &hr); + &wdr); wh->cb = NULL; } TALER_EXCHANGE_management_disable_wire_cancel (wh); diff --git a/src/lib/exchange_api_management_wire_enable.c b/src/lib/exchange_api_management_wire_enable.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2021 Taler Systems SA + Copyright (C) 2015-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -79,9 +79,9 @@ handle_auditor_enable_finished (void *cls, { struct TALER_EXCHANGE_ManagementWireEnableHandle *wh = cls; const json_t *json = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_EXCHANGE_ManagementWireEnableResponse wer = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; wh->job = NULL; @@ -89,34 +89,34 @@ handle_auditor_enable_finished (void *cls, { case 0: /* no reply */ - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - hr.hint = "server offline?"; + wer.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + wer.hr.hint = "server offline?"; break; case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + wer.hr.ec = TALER_JSON_get_error_code (json); + wer.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_CONFLICT: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + wer.hr.ec = TALER_JSON_get_error_code (json); + wer.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + wer.hr.ec = TALER_JSON_get_error_code (json); + wer.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange management enable wire\n", (unsigned int) response_code, - (int) hr.ec); + (int) wer.hr.ec); break; } if (NULL != wh->cb) { wh->cb (wh->cb_cls, - &hr); + &wer); wh->cb = NULL; } TALER_EXCHANGE_management_enable_wire_cancel (wh); @@ -128,6 +128,9 @@ TALER_EXCHANGE_management_enable_wire ( struct GNUNET_CURL_Context *ctx, const char *url, const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp validity_start, const struct TALER_MasterSignatureP *master_sig1, const struct TALER_MasterSignatureP *master_sig2, @@ -167,6 +170,13 @@ TALER_EXCHANGE_management_enable_wire ( body = GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("payto_uri", payto_uri), + GNUNET_JSON_pack_array_incref ("debit_restrictions", + (json_t *) debit_restrictions), + GNUNET_JSON_pack_array_incref ("credit_restrictions", + (json_t *) credit_restrictions), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("conversion_url", + conversion_url)), GNUNET_JSON_pack_data_auto ("master_sig_add", master_sig1), GNUNET_JSON_pack_data_auto ("master_sig_wire", diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c @@ -221,16 +221,16 @@ handle_melt_finished (void *cls, if (GNUNET_OK != verify_melt_signature_ok (mh, j, - &mr.details.success.sign_key)) + &mr.details.ok.sign_key)) { GNUNET_break_op (0); mr.hr.http_status = 0; mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE; break; } - mr.details.success.noreveal_index = mh->noreveal_index; - mr.details.success.num_mbds = mh->rd->fresh_pks_len; - mr.details.success.mbds = mh->mbds; + mr.details.ok.noreveal_index = mh->noreveal_index; + mr.details.ok.num_mbds = mh->rd->fresh_pks_len; + mr.details.ok.mbds = mh->mbds; mh->melt_cb (mh->melt_cb_cls, &mr); mh->melt_cb = NULL; @@ -478,7 +478,7 @@ csr_cb (void *cls, break; case TALER_DENOMINATION_CS: GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher); - *wv = csrr->details.success.alg_values[nks_off]; + *wv = csrr->details.ok.alg_values[nks_off]; nks_off++; break; } diff --git a/src/lib/exchange_api_purse_deposit.c b/src/lib/exchange_api_purse_deposit.c @@ -164,17 +164,17 @@ handle_purse_deposit_finished (void *cls, GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub), GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &dr.details.success.h_contract_terms), + &dr.details.ok.h_contract_terms), GNUNET_JSON_spec_timestamp ("exchange_timestamp", &etime), GNUNET_JSON_spec_timestamp ("purse_expiration", - &dr.details.success.purse_expiration), + &dr.details.ok.purse_expiration), TALER_JSON_spec_amount ("total_deposited", keys->currency, - &dr.details.success.total_deposited), + &dr.details.ok.total_deposited), TALER_JSON_spec_amount ("purse_value_after_fees", keys->currency, - &dr.details.success.purse_value_after_fees), + &dr.details.ok.purse_value_after_fees), GNUNET_JSON_spec_end () }; @@ -200,11 +200,11 @@ handle_purse_deposit_finished (void *cls, if (GNUNET_OK != TALER_exchange_online_purse_created_verify ( etime, - dr.details.success.purse_expiration, - &dr.details.success.purse_value_after_fees, - &dr.details.success.total_deposited, + dr.details.ok.purse_expiration, + &dr.details.ok.purse_value_after_fees, + &dr.details.ok.total_deposited, &pch->purse_pub, - &dr.details.success.h_contract_terms, + &dr.details.ok.h_contract_terms, &exchange_pub, &exchange_sig)) { diff --git a/src/lib/exchange_api_purse_merge.c b/src/lib/exchange_api_purse_merge.c @@ -152,11 +152,11 @@ handle_purse_merge_finished (void *cls, struct TALER_Amount total_deposited; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("exchange_sig", - &dr.details.success.exchange_sig), + &dr.details.ok.exchange_sig), GNUNET_JSON_spec_fixed_auto ("exchange_pub", - &dr.details.success.exchange_pub), + &dr.details.ok.exchange_pub), GNUNET_JSON_spec_timestamp ("exchange_timestamp", - &dr.details.success.etime), + &dr.details.ok.etime), TALER_JSON_spec_amount ("merge_amount", pch->purse_value_after_fees.currency, &total_deposited), @@ -176,7 +176,7 @@ handle_purse_merge_finished (void *cls, key_state = TALER_EXCHANGE_get_keys (pch->exchange); if (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_state, - &dr.details.success.exchange_pub)) + &dr.details.ok.exchange_pub)) { GNUNET_break_op (0); dr.hr.http_status = 0; @@ -185,15 +185,15 @@ handle_purse_merge_finished (void *cls, } if (GNUNET_OK != TALER_exchange_online_purse_merged_verify ( - dr.details.success.etime, + dr.details.ok.etime, pch->purse_expiration, &pch->purse_value_after_fees, &pch->purse_pub, &pch->h_contract_terms, &pch->reserve_pub, pch->provider_url, - &dr.details.success.exchange_pub, - &dr.details.success.exchange_sig)) + &dr.details.ok.exchange_pub, + &dr.details.ok.exchange_sig)) { GNUNET_break_op (0); dr.hr.http_status = 0; diff --git a/src/lib/exchange_api_purses_get.c b/src/lib/exchange_api_purses_get.c @@ -101,16 +101,16 @@ handle_purse_get_finished (void *cls, struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("merge_timestamp", - &dr.details.success.merge_timestamp), + &dr.details.ok.merge_timestamp), &no_merge), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("deposit_timestamp", - &dr.details.success.deposit_timestamp), + &dr.details.ok.deposit_timestamp), &no_deposit), TALER_JSON_spec_amount_any ("balance", - &dr.details.success.balance), + &dr.details.ok.balance), GNUNET_JSON_spec_timestamp ("purse_expiration", - &dr.details.success.purse_expiration), + &dr.details.ok.purse_expiration), GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub), GNUNET_JSON_spec_fixed_auto ("exchange_sig", @@ -142,9 +142,9 @@ handle_purse_get_finished (void *cls, } if (GNUNET_OK != TALER_exchange_online_purse_status_verify ( - dr.details.success.merge_timestamp, - dr.details.success.deposit_timestamp, - &dr.details.success.balance, + dr.details.ok.merge_timestamp, + dr.details.ok.deposit_timestamp, + &dr.details.ok.balance, &exchange_pub, &exchange_sig)) { diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2017-2022 Taler Systems SA + Copyright (C) 2017-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -100,16 +100,15 @@ static enum GNUNET_GenericReturnValue process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph, const json_t *json) { - struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_EXCHANGE_RecoupResponse rr = { + .hr.reply = json, + .hr.http_status = MHD_HTTP_OK + }; struct GNUNET_JSON_Specification spec_withdraw[] = { GNUNET_JSON_spec_fixed_auto ("reserve_pub", - &reserve_pub), + &rr.details.ok.reserve_pub), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = json, - .http_status = MHD_HTTP_OK - }; if (GNUNET_OK != GNUNET_JSON_parse (json, @@ -120,8 +119,7 @@ process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph, return GNUNET_SYSERR; } ph->cb (ph->cb_cls, - &hr, - &reserve_pub); + &rr); return GNUNET_OK; } @@ -141,9 +139,9 @@ handle_recoup_finished (void *cls, { struct TALER_EXCHANGE_RecoupHandle *ph = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_RecoupResponse rr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; const struct TALER_EXCHANGE_Keys *keys; @@ -152,7 +150,7 @@ handle_recoup_finished (void *cls, switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: if (GNUNET_OK != @@ -160,8 +158,8 @@ handle_recoup_finished (void *cls, j)) { GNUNET_break_op (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + rr.hr.http_status = 0; break; } TALER_EXCHANGE_recoup_cancel (ph); @@ -169,22 +167,22 @@ handle_recoup_finished (void *cls, case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_CONFLICT: { struct TALER_Amount min_key; - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); if (GNUNET_OK != TALER_EXCHANGE_get_min_denomination_ (keys, &min_key)) { GNUNET_break (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + rr.hr.http_status = 0; break; } if (GNUNET_OK != @@ -197,8 +195,8 @@ handle_recoup_finished (void *cls, &min_key)) { GNUNET_break (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + rr.hr.http_status = 0; break; } break; @@ -207,41 +205,40 @@ handle_recoup_finished (void *cls, /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_GONE: /* Kind of normal: the money was already sent to the merchant (it was too late for the refund). */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + 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 */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange recoup\n", (unsigned int) response_code, - (int) hr.ec); + (int) rr.hr.ec); GNUNET_break (0); break; } ph->cb (ph->cb_cls, - &hr, - NULL); + &rr); TALER_EXCHANGE_recoup_cancel (ph); } diff --git a/src/lib/exchange_api_recoup_refresh.c b/src/lib/exchange_api_recoup_refresh.c @@ -101,16 +101,15 @@ process_recoup_response ( const struct TALER_EXCHANGE_RecoupRefreshHandle *ph, const json_t *json) { - struct TALER_CoinSpendPublicKeyP old_coin_pub; + struct TALER_EXCHANGE_RecoupRefreshResponse rrr = { + .hr.reply = json, + .hr.http_status = MHD_HTTP_OK + }; struct GNUNET_JSON_Specification spec_refresh[] = { GNUNET_JSON_spec_fixed_auto ("old_coin_pub", - &old_coin_pub), + &rrr.details.ok.old_coin_pub), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = json, - .http_status = MHD_HTTP_OK - }; if (GNUNET_OK != GNUNET_JSON_parse (json, @@ -121,8 +120,7 @@ process_recoup_response ( return GNUNET_SYSERR; } ph->cb (ph->cb_cls, - &hr, - &old_coin_pub); + &rrr); return GNUNET_OK; } @@ -142,9 +140,9 @@ handle_recoup_refresh_finished (void *cls, { struct TALER_EXCHANGE_RecoupRefreshHandle *ph = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_RecoupRefreshResponse rrr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; const struct TALER_EXCHANGE_Keys *keys; @@ -153,7 +151,7 @@ handle_recoup_refresh_finished (void *cls, switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + rrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: if (GNUNET_OK != @@ -161,8 +159,8 @@ handle_recoup_refresh_finished (void *cls, j)) { GNUNET_break_op (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + rrr.hr.http_status = 0; break; } TALER_EXCHANGE_recoup_refresh_cancel (ph); @@ -170,35 +168,35 @@ handle_recoup_refresh_finished (void *cls, case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_CONFLICT: { struct TALER_Amount min_key; - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.hr.hint = TALER_JSON_get_error_hint (j); if (GNUNET_OK != TALER_EXCHANGE_get_min_denomination_ (keys, &min_key)) { GNUNET_break (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + rrr.hr.http_status = 0; break; } if (GNUNET_OK != @@ -211,8 +209,8 @@ handle_recoup_refresh_finished (void *cls, &min_key)) { GNUNET_break (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + rrr.hr.http_status = 0; break; } break; @@ -220,29 +218,28 @@ handle_recoup_refresh_finished (void *cls, case MHD_HTTP_GONE: /* Kind of normal: the money was already sent to the merchant (it was too late for the refund). */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.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 */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rrr.hr.ec = TALER_JSON_get_error_code (j); + rrr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange recoup\n", (unsigned int) response_code, - (int) hr.ec); + (int) rrr.hr.ec); GNUNET_break (0); break; } ph->cb (ph->cb_cls, - &hr, - NULL); + &rrr); TALER_EXCHANGE_recoup_refresh_cancel (ph); } diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c @@ -266,8 +266,8 @@ handle_refresh_reveal_finished (void *cls, else { GNUNET_assert (rrh->noreveal_index < TALER_CNC_KAPPA); - rr.details.success.num_coins = rrh->md.num_fresh_coins; - rr.details.success.coins = rcis; + rr.details.ok.num_coins = rrh->md.num_fresh_coins; + rr.details.ok.coins = rcis; rrh->reveal_cb (rrh->reveal_cb_cls, &rr); rrh->reveal_cb = NULL; diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c @@ -585,37 +585,28 @@ handle_refund_finished (void *cls, const void *response) { struct TALER_EXCHANGE_RefundHandle *rh = cls; - struct TALER_ExchangePublicKeyP exchange_pub; - struct TALER_ExchangeSignatureP exchange_sig; - struct TALER_ExchangePublicKeyP *ep = NULL; - struct TALER_ExchangeSignatureP *es = NULL; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_RefundResponse rr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; rh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: if (GNUNET_OK != verify_refund_signature_ok (rh, j, - &exchange_pub, - &exchange_sig)) + &rr.details.ok.exchange_pub, + &rr.details.ok.exchange_sig)) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_SIGNATURE_BY_EXCHANGE; - } - else - { - ep = &exchange_pub; - es = &exchange_sig; + rr.hr.http_status = 0; + rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_SIGNATURE_BY_EXCHANGE; } break; case MHD_HTTP_BAD_REQUEST: @@ -623,21 +614,21 @@ handle_refund_finished (void *cls, (or API version conflict); also can happen if the currency differs (which we should obviously never support). Just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_CONFLICT: /* Requested total refunds exceed deposited amount */ @@ -649,19 +640,19 @@ handle_refund_finished (void *cls, json_dumpf (j, stderr, JSON_INDENT (2)); - hr.http_status = 0; - hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE; - hr.hint = "conflict information provided by exchange is invalid"; + rr.hr.http_status = 0; + rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE; + rr.hr.hint = "conflict information provided by exchange is invalid"; break; } - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_GONE: /* Kind of normal: the money was already sent to the merchant (it was too late for the refund). */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + 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 != @@ -669,37 +660,35 @@ handle_refund_finished (void *cls, j)) { GNUNET_break (0); - hr.http_status = 0; - hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE; - hr.hint = "failed precondition proof returned by exchange is invalid"; + 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. */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + 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 */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + rr.hr.ec = TALER_JSON_get_error_code (j); + rr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange refund\n", (unsigned int) response_code, - hr.ec); + rr.hr.ec); break; } rh->cb (rh->cb_cls, - &hr, - ep, - es); + &rr); TALER_EXCHANGE_refund_cancel (rh); } diff --git a/src/lib/exchange_api_transfers_get.c b/src/lib/exchange_api_transfers_get.c @@ -85,24 +85,33 @@ check_transfers_get_response_ok ( const json_t *json) { json_t *details_j; - struct TALER_EXCHANGE_TransferData td; struct TALER_Amount total_expected; struct TALER_MerchantPublicKeyP merchant_pub; + struct TALER_EXCHANGE_TransfersGetResponse tgr = { + .hr.reply = json, + .hr.http_status = MHD_HTTP_OK + }; + struct TALER_EXCHANGE_TransferData *td + = &tgr.details.ok.td; struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("total", &td.total_amount), - TALER_JSON_spec_amount_any ("wire_fee", &td.wire_fee), - GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub), - GNUNET_JSON_spec_fixed_auto ("h_payto", &td.h_payto), - GNUNET_JSON_spec_timestamp ("execution_time", &td.execution_time), - GNUNET_JSON_spec_json ("deposits", &details_j), - GNUNET_JSON_spec_fixed_auto ("exchange_sig", &td.exchange_sig), - GNUNET_JSON_spec_fixed_auto ("exchange_pub", &td.exchange_pub), + TALER_JSON_spec_amount_any ("total", + &td->total_amount), + TALER_JSON_spec_amount_any ("wire_fee", + &td->wire_fee), + GNUNET_JSON_spec_fixed_auto ("merchant_pub", + &merchant_pub), + GNUNET_JSON_spec_fixed_auto ("h_payto", + &td->h_payto), + GNUNET_JSON_spec_timestamp ("execution_time", + &td->execution_time), + GNUNET_JSON_spec_json ("deposits", + &details_j), + GNUNET_JSON_spec_fixed_auto ("exchange_sig", + &td->exchange_sig), + GNUNET_JSON_spec_fixed_auto ("exchange_pub", + &td->exchange_pub), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = json, - .http_status = MHD_HTTP_OK - }; if (GNUNET_OK != GNUNET_JSON_parse (json, @@ -113,7 +122,7 @@ check_transfers_get_response_ok ( return GNUNET_SYSERR; } if (GNUNET_OK != - TALER_amount_set_zero (td.total_amount.currency, + TALER_amount_set_zero (td->total_amount.currency, &total_expected)) { GNUNET_break_op (0); @@ -123,22 +132,22 @@ check_transfers_get_response_ok ( if (GNUNET_OK != TALER_EXCHANGE_test_signing_key ( TALER_EXCHANGE_get_keys (wdh->exchange), - &td.exchange_pub)) + &td->exchange_pub)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); return GNUNET_SYSERR; } - td.details_length = json_array_size (details_j); + td->details_length = json_array_size (details_j); { struct GNUNET_HashContext *hash_context; struct TALER_TrackTransferDetails *details; - details = GNUNET_new_array (td.details_length, + details = GNUNET_new_array (td->details_length, struct TALER_TrackTransferDetails); - td.details = details; + td->details = details; hash_context = GNUNET_CRYPTO_hash_context_start (); - for (unsigned int i = 0; i<td.details_length; i++) + for (unsigned int i = 0; i<td->details_length; i++) { struct TALER_TrackTransferDetails *detail = &details[i]; struct json_t *detail_j = json_array_get (details_j, i); @@ -180,7 +189,7 @@ check_transfers_get_response_ok ( TALER_exchange_online_wire_deposit_append ( hash_context, &detail->h_contract_terms, - td.execution_time, + td->execution_time, &detail->coin_pub, &detail->coin_value, &detail->coin_fee); @@ -193,13 +202,13 @@ check_transfers_get_response_ok ( &h_details); if (GNUNET_OK != TALER_exchange_online_wire_deposit_verify ( - &td.total_amount, - &td.wire_fee, + &td->total_amount, + &td->wire_fee, &merchant_pub, - &td.h_payto, + &td->h_payto, &h_details, - &td.exchange_pub, - &td.exchange_sig)) + &td->exchange_pub, + &td->exchange_sig)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); @@ -211,7 +220,7 @@ check_transfers_get_response_ok ( if (0 > TALER_amount_subtract (&total_expected, &total_expected, - &td.wire_fee)) + &td->wire_fee)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); @@ -220,7 +229,7 @@ check_transfers_get_response_ok ( } if (0 != TALER_amount_cmp (&total_expected, - &td.total_amount)) + &td->total_amount)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); @@ -228,8 +237,7 @@ check_transfers_get_response_ok ( return GNUNET_SYSERR; } wdh->cb (wdh->cb_cls, - &hr, - &td); + &tgr); GNUNET_free (details); } GNUNET_JSON_parse_free (spec); @@ -253,16 +261,16 @@ handle_transfers_get_finished (void *cls, { struct TALER_EXCHANGE_TransfersGetHandle *wdh = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_TransfersGetResponse tgr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; wdh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: if (GNUNET_OK == @@ -270,48 +278,47 @@ handle_transfers_get_finished (void *cls, j)) return; GNUNET_break_op (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + tgr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + tgr.hr.http_status = 0; break; case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + tgr.hr.ec = TALER_JSON_get_error_code (j); + tgr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + tgr.hr.ec = TALER_JSON_get_error_code (j); + tgr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Exchange does not know about transaction; we should pass the reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + tgr.hr.ec = TALER_JSON_get_error_code (j); + tgr.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 */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + tgr.hr.ec = TALER_JSON_get_error_code (j); + tgr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + tgr.hr.ec = TALER_JSON_get_error_code (j); + tgr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for transfers get\n", (unsigned int) response_code, - (int) hr.ec); + (int) tgr.hr.ec); break; } wdh->cb (wdh->cb_cls, - &hr, - NULL); + &tgr); TALER_EXCHANGE_transfers_get_cancel (wdh); } diff --git a/src/lib/exchange_api_wire.c b/src/lib/exchange_api_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -66,82 +66,65 @@ struct TALER_EXCHANGE_WireHandle /** - * List of wire fees by method. - */ -struct FeeMap -{ - /** - * Next entry in list. - */ - struct FeeMap *next; - - /** - * Wire method this fee structure is for. - */ - char *method; - - /** - * Array of wire fees, also linked list, but allocated - * only once. - */ - struct TALER_EXCHANGE_WireAggregateFees *fee_list; -}; - - -/** - * Frees @a fm. + * Frees @a wfm array. * - * @param fm memory to release + * @param wfm fee array to release + * @param wfm_len length of the @a wfm array */ static void -free_fees (struct FeeMap *fm) +free_fees (struct TALER_EXCHANGE_WireFeesByMethod *wfm, + unsigned int wfm_len) { - while (NULL != fm) + for (unsigned int i = 0; i<wfm_len; i++) { - struct FeeMap *fe = fm->next; + struct TALER_EXCHANGE_WireFeesByMethod *wfmi = &wfm[i]; - GNUNET_free (fm->fee_list); - GNUNET_free (fm->method); - GNUNET_free (fm); - fm = fe; + while (NULL != wfmi->fees_head) + { + struct TALER_EXCHANGE_WireAggregateFees *fe + = wfmi->fees_head; + + wfmi->fees_head = fe->next; + GNUNET_free (fe); + } } + GNUNET_free (wfm); } /** - * Parse wire @a fees and return map. + * Parse wire @a fees and return array. * * @param master_pub master public key to use to check signatures * @param fees json AggregateTransferFee to parse + * @param[out] fees_len set to length of returned array * @return NULL on error */ -static struct FeeMap * +static struct TALER_EXCHANGE_WireFeesByMethod * parse_fees (const struct TALER_MasterPublicKeyP *master_pub, - json_t *fees) + const json_t *fees, + unsigned int *fees_len) { - struct FeeMap *fm = NULL; + struct TALER_EXCHANGE_WireFeesByMethod *fbm; + unsigned int fbml = json_object_size (fees); + unsigned int i = 0; const char *key; - json_t *fee_array; + const json_t *fee_array; - json_object_foreach (fees, key, fee_array) { - struct FeeMap *fe = GNUNET_new (struct FeeMap); - unsigned int len; + fbm = GNUNET_new_array (fbml, + struct TALER_EXCHANGE_WireFeesByMethod); + *fees_len = fbml; + json_object_foreach ((json_t *) fees, key, fee_array) { + struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++]; unsigned int idx; json_t *fee; - if (0 == (len = json_array_size (fee_array))) - { - GNUNET_free (fe); - continue; /* skip */ - } - fe->method = GNUNET_strdup (key); - fe->next = fm; - fe->fee_list = GNUNET_new_array (len, - struct TALER_EXCHANGE_WireAggregateFees); - fm = fe; + fe->method = key; + fe->fees_head = NULL; json_array_foreach (fee_array, idx, fee) { - struct TALER_EXCHANGE_WireAggregateFees *wa = &fe->fee_list[idx]; + struct TALER_EXCHANGE_WireAggregateFees *wa + = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees); struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("sig", &wa->master_sig), @@ -156,6 +139,8 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, GNUNET_JSON_spec_end () }; + wa->next = fe->fees_head; + fe->fees_head = wa; if (GNUNET_OK != GNUNET_JSON_parse (fee, spec, @@ -163,7 +148,8 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, NULL)) { GNUNET_break_op (0); - free_fees (fm); + free_fees (fbm, + i); return NULL; } if (GNUNET_OK != @@ -176,35 +162,122 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, &wa->master_sig)) { GNUNET_break_op (0); - free_fees (fm); + free_fees (fbm, + i); return NULL; } - if (idx + 1 < len) - wa->next = &fe->fee_list[idx + 1]; - else - wa->next = NULL; + } /* for all fees over time */ + } /* for all methods */ + GNUNET_assert (i == fbml); + return fbm; +} + + +/** + * Parse account restriction in @a jrest into @a rest. + * + * @param jrest array of account restrictions in JSON + * @param[out] resta_len set to length of @a resta + * @param[out] resta account restriction array to set + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +parse_restrictions (const json_t *jresta, + unsigned int *resta_len, + struct TALER_EXCHANGE_AccountRestriction **resta) +{ + if (! json_is_array (jresta)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + *resta_len = json_array_size (jresta); + if (0 == *resta_len) + { + /* no restrictions, perfectly OK */ + *resta = NULL; + return GNUNET_OK; + } + *resta = GNUNET_new_array (*resta_len, + struct TALER_EXCHANGE_AccountRestriction); + for (unsigned int i = 0; i<*resta_len; i++) + { + const json_t *jr = json_array_get (jresta, + i); + struct TALER_EXCHANGE_AccountRestriction *ar = &(*resta)[i]; + const char *type = json_string_value (json_object_get (jr, + "type")); + + if (NULL == type) + { + GNUNET_break (0); + goto fail; + } + if (0 == strcmp (type, + "deny")) + { + ar->type = TALER_EXCHANGE_AR_DENY; + continue; + } + if (0 == strcmp (type, + "regex")) + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ( + "payto_regex", + &ar->details.regex.posix_egrep), + GNUNET_JSON_spec_string ( + "human_hint", + &ar->details.regex.human_hint), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_object_const ( + "human_hint_i18n", + &ar->details.regex.human_hint_i18n), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (jr, + spec, + NULL, NULL)) + { + /* bogus reply */ + GNUNET_break_op (0); + goto fail; + } + ar->type = TALER_EXCHANGE_AR_REGEX; + continue; } + /* unsupported type */ + GNUNET_break (0); + return GNUNET_SYSERR; } - return fm; + return GNUNET_OK; +fail: + GNUNET_free (*resta); + *resta_len = 0; + return GNUNET_SYSERR; } /** - * Find fee by @a method. + * Free data within @a was, but not @a was itself. * - * @param fm map to look in - * @param method key to look for - * @return NULL if fee is not specified in @a fm + * @param was array of wire account data + * @param was_len length of the @a was array */ -static const struct TALER_EXCHANGE_WireAggregateFees * -lookup_fee (const struct FeeMap *fm, - const char *method) +static void +free_accounts (struct TALER_EXCHANGE_WireAccount *was, + unsigned int was_len) { - for (; NULL != fm; fm = fm->next) - if (0 == strcasecmp (fm->method, - method)) - return fm->fee_list; - return NULL; + for (unsigned int i = 0; i<was_len; i++) + { + struct TALER_EXCHANGE_WireAccount *wa = &was[i]; + + GNUNET_free (wa->credit_restrictions); + GNUNET_free (wa->debit_restrictions); + } } @@ -223,9 +296,9 @@ handle_wire_finished (void *cls, { struct TALER_EXCHANGE_WireHandle *wh = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_WireResponse wr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; TALER_LOG_DEBUG ("Checking raw /wire response\n"); @@ -233,28 +306,29 @@ handle_wire_finished (void *cls, switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + wr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; wh->exchange->wire_error_count++; break; case MHD_HTTP_OK: { - json_t *accounts; - json_t *fees; - unsigned int num_accounts; - struct FeeMap *fm; + const json_t *accounts; + const json_t *fees; + const json_t *wads; + struct TALER_EXCHANGE_WireFeesByMethod *fbm; struct TALER_MasterPublicKeyP master_pub; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("master_public_key", &master_pub), - GNUNET_JSON_spec_json ("accounts", - &accounts), - GNUNET_JSON_spec_json ("fees", - &fees), + GNUNET_JSON_spec_array_const ("accounts", + &accounts), + GNUNET_JSON_spec_object_const ("fees", + &fees), + GNUNET_JSON_spec_array_const ("wads", + &wads), GNUNET_JSON_spec_end () }; wh->exchange->wire_error_count = 0; - if (GNUNET_OK != GNUNET_JSON_parse (j, spec, @@ -262,8 +336,8 @@ handle_wire_finished (void *cls, { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } { @@ -275,142 +349,175 @@ handle_wire_finished (void *cls, { /* bogus reply: master public key in /wire differs from that in /keys */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } } - if (0 == (num_accounts = json_array_size (accounts))) + wr.details.ok.accounts_len + = json_array_size (accounts); + if (0 == wr.details.ok.accounts_len) { /* bogus reply */ GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - if (NULL == (fm = parse_fees (&master_pub, - fees))) + fbm = parse_fees (&master_pub, + fees, + &wr.details.ok.fees_len); + if (NULL == fbm) { /* bogus reply */ GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } /* parse accounts */ { - struct TALER_EXCHANGE_WireAccount was[num_accounts]; - - for (unsigned int i = 0; i<num_accounts; i++) + struct TALER_EXCHANGE_WireAccount was[wr.details.ok.accounts_len]; + + memset (was, + 0, + sizeof (was)); + wr.details.ok.accounts = was; + for (unsigned int i = 0; + i<wr.details.ok.accounts_len; + i++) { struct TALER_EXCHANGE_WireAccount *wa = &was[i]; - json_t *account; + json_t *credit_restrictions; + json_t *debit_restrictions; struct GNUNET_JSON_Specification spec_account[] = { GNUNET_JSON_spec_string ("payto_uri", &wa->payto_uri), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("conversion_url", + &wa->conversion_url), + NULL), + GNUNET_JSON_spec_json ("credit_restrictions", + &credit_restrictions), + GNUNET_JSON_spec_json ("debit_restrictions", + &debit_restrictions), GNUNET_JSON_spec_fixed_auto ("master_sig", &wa->master_sig), GNUNET_JSON_spec_end () }; - char *method; + json_t *account; account = json_array_get (accounts, i); if (GNUNET_OK != - TALER_JSON_exchange_wire_signature_check (account, - &master_pub)) - { - /* bogus reply */ - GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID; - break; - } - if (GNUNET_OK != GNUNET_JSON_parse (account, spec_account, NULL, NULL)) { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - if (NULL == (method = TALER_payto_get_method (wa->payto_uri))) + { + char *err; + + err = TALER_payto_validate (wa->payto_uri); + if (NULL != err) + { + GNUNET_break_op (0); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + GNUNET_free (err); + break; + } + } + + if (GNUNET_OK != + TALER_exchange_wire_signature_check (wa->payto_uri, + wa->conversion_url, + debit_restrictions, + credit_restrictions, + &master_pub, + &wa->master_sig)) { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID; break; } - if (NULL == (wa->fees = lookup_fee (fm, - method))) + if ( (GNUNET_OK != + parse_restrictions (credit_restrictions, + &wa->credit_restrictions_length, + &wa->credit_restrictions)) || + (GNUNET_OK != + parse_restrictions (debit_restrictions, + &wa->debit_restrictions_length, + &wa->debit_restrictions)) ) { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - GNUNET_free (method); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - GNUNET_free (method); + GNUNET_JSON_parse_free (spec_account); } /* end 'for all accounts */ - if ( (0 != response_code) && + if ( (0 != wr.hr.http_status) && (NULL != wh->cb) ) { wh->cb (wh->cb_cls, - &hr, - num_accounts, - was); + &wr); wh->cb = NULL; } + free_accounts (was, + wr.details.ok.accounts_len); } /* end of 'parse accounts */ - free_fees (fm); + free_fees (fbm, + wr.details.ok.fees_len); GNUNET_JSON_parse_free (spec); } /* end of MHD_HTTP_OK */ break; case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.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 */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ if (MHD_HTTP_GATEWAY_TIMEOUT == response_code) wh->exchange->wire_error_count++; GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange wire\n", (unsigned int) response_code, - (int) hr.ec); + (int) wr.hr.ec); break; } if (NULL != wh->cb) wh->cb (wh->cb_cls, - &hr, - 0, - NULL); + &wr); TALER_EXCHANGE_wire_cancel (wh); } diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c @@ -116,22 +116,20 @@ struct TALER_EXCHANGE_WithdrawHandle * HTTP /reserves/$RESERVE_PUB/withdraw request. * * @param cls the `struct TALER_EXCHANGE_WithdrawHandle` - * @param hr HTTP response data - * @param blind_sig blind signature over the coin, NULL on error + * @param w2r response data */ static void handle_reserve_withdraw_finished ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_BlindedDenominationSignature *blind_sig) + const struct TALER_EXCHANGE_Withdraw2Response *w2r) { struct TALER_EXCHANGE_WithdrawHandle *wh = cls; struct TALER_EXCHANGE_WithdrawResponse wr = { - .hr = *hr + .hr = w2r->hr }; wh->wh2 = NULL; - switch (hr->http_status) + switch (w2r->hr.http_status) { case MHD_HTTP_OK: { @@ -139,7 +137,7 @@ handle_reserve_withdraw_finished ( if (GNUNET_OK != TALER_planchet_to_coin (&wh->pk.key, - blind_sig, + &w2r->details.ok.blind_sig, &wh->bks, &wh->priv, wh->ach, @@ -151,10 +149,10 @@ handle_reserve_withdraw_finished ( wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE; break; } - wr.details.success.coin_priv = wh->priv; - wr.details.success.bks = wh->bks; - wr.details.success.sig = fc.sig; - wr.details.success.exchange_vals = wh->alg_values; + wr.details.ok.coin_priv = wh->priv; + wr.details.ok.bks = wh->bks; + wr.details.ok.sig = fc.sig; + wr.details.ok.exchange_vals = wh->alg_values; break; } case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: @@ -170,7 +168,7 @@ handle_reserve_withdraw_finished ( }; if (GNUNET_OK != - GNUNET_JSON_parse (hr->reply, + GNUNET_JSON_parse (w2r->hr.reply, spec, NULL, NULL)) { @@ -186,8 +184,8 @@ handle_reserve_withdraw_finished ( } wh->cb (wh->cb_cls, &wr); - if (MHD_HTTP_OK == hr->http_status) - TALER_denom_sig_free (&wr.details.success.sig); + if (MHD_HTTP_OK == w2r->hr.http_status) + TALER_denom_sig_free (&wr.details.ok.sig); TALER_EXCHANGE_withdraw_cancel (wh); } @@ -213,7 +211,7 @@ withdraw_cs_stage_two_callback ( switch (csrr->hr.http_status) { case MHD_HTTP_OK: - wh->alg_values = csrr->details.success.alg_values; + wh->alg_values = csrr->details.ok.alg_values; TALER_planchet_setup_coin_priv (&wh->ps, &wh->alg_values, &wh->priv); diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -99,16 +99,15 @@ static enum GNUNET_GenericReturnValue reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh, const json_t *json) { - struct TALER_BlindedDenominationSignature blind_sig; + struct TALER_EXCHANGE_Withdraw2Response w2r = { + .hr.reply = json, + .hr.http_status = MHD_HTTP_OK + }; struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_blinded_denom_sig ("ev_sig", - &blind_sig), + &w2r.details.ok.blind_sig), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = json, - .http_status = MHD_HTTP_OK - }; if (GNUNET_OK != GNUNET_JSON_parse (json, @@ -121,8 +120,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh, /* signature is valid, return it to the application */ wh->cb (wh->cb_cls, - &hr, - &blind_sig); + &w2r); /* make sure callback isn't called again after return */ wh->cb = NULL; GNUNET_JSON_parse_free (spec); @@ -240,16 +238,16 @@ handle_reserve_withdraw_finished (void *cls, { struct TALER_EXCHANGE_Withdraw2Handle *wh = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_Withdraw2Response w2r = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; wh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + w2r.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: if (GNUNET_OK != @@ -257,8 +255,8 @@ handle_reserve_withdraw_finished (void *cls, j)) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + w2r.hr.http_status = 0; + w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } GNUNET_assert (NULL == wh->cb); @@ -267,24 +265,24 @@ handle_reserve_withdraw_finished (void *cls, case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + w2r.hr.ec = TALER_JSON_get_error_code (j); + w2r.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: GNUNET_break_op (0); /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + w2r.hr.ec = TALER_JSON_get_error_code (j); + w2r.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, the exchange basically just says that it doesn't know this reserve. Can happen if we query before the wire transfer went through. We should simply pass the JSON reply to the application. */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + w2r.hr.ec = TALER_JSON_get_error_code (j); + w2r.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_CONFLICT: /* The exchange says that the reserve has insufficient funds; @@ -294,13 +292,13 @@ handle_reserve_withdraw_finished (void *cls, j)) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + w2r.hr.http_status = 0; + w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; } else { - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + w2r.hr.ec = TALER_JSON_get_error_code (j); + w2r.hr.hint = TALER_JSON_get_error_hint (j); } break; case MHD_HTTP_GONE: @@ -308,8 +306,8 @@ handle_reserve_withdraw_finished (void *cls, /* Note: one might want to check /keys for revocation signature here, alas tricky in case our /keys is outdated => left to clients */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + w2r.hr.ec = TALER_JSON_get_error_code (j); + w2r.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: /* only validate reply is well-formed */ @@ -327,8 +325,8 @@ handle_reserve_withdraw_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + w2r.hr.http_status = 0; + w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } } @@ -336,25 +334,24 @@ handle_reserve_withdraw_finished (void *cls, case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + w2r.hr.ec = TALER_JSON_get_error_code (j); + w2r.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + w2r.hr.ec = TALER_JSON_get_error_code (j); + w2r.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange withdraw\n", (unsigned int) response_code, - (int) hr.ec); + (int) w2r.hr.ec); break; } if (NULL != wh->cb) { wh->cb (wh->cb_cls, - &hr, - NULL); + &w2r); wh->cb = NULL; } TALER_EXCHANGE_withdraw2_cancel (wh); diff --git a/src/testing/testing_api_cmd_bank_history_credit.c b/src/testing/testing_api_cmd_bank_history_credit.c @@ -386,10 +386,10 @@ history_cb (void *cls, GNUNET_break (0); goto error; case MHD_HTTP_OK: - for (unsigned int i = 0; i<chr->details.success.details_length; i++) + for (unsigned int i = 0; i<chr->details.ok.details_length; i++) { const struct TALER_BANK_CreditDetails *cd = - &chr->details.success.details[i]; + &chr->details.ok.details[i]; /* check current element */ if (GNUNET_OK != diff --git a/src/testing/testing_api_cmd_bank_history_debit.c b/src/testing/testing_api_cmd_bank_history_debit.c @@ -378,10 +378,10 @@ history_cb (void *cls, GNUNET_break (0); goto error; case MHD_HTTP_OK: - for (unsigned int i = 0; i<dhr->details.success.details_length; i++) + for (unsigned int i = 0; i<dhr->details.ok.details_length; i++) { const struct TALER_BANK_DebitDetails *dd = - &dhr->details.success.details[i]; + &dhr->details.ok.details[i]; /* check current element */ if (GNUNET_OK != diff --git a/src/testing/testing_api_cmd_batch_deposit.c b/src/testing/testing_api_cmd_batch_deposit.c @@ -212,17 +212,17 @@ batch_deposit_cb (void *cls, } if (MHD_HTTP_OK == dr->hr.http_status) { - if (ds->num_coins != dr->details.success.num_signatures) + if (ds->num_coins != dr->details.ok.num_signatures) { GNUNET_break (0); TALER_TESTING_interpreter_fail (ds->is); return; } ds->deposit_succeeded = GNUNET_YES; - ds->exchange_timestamp = dr->details.success.deposit_timestamp; - ds->exchange_pub = *dr->details.success.exchange_pub; - ds->exchange_sigs = GNUNET_memdup (dr->details.success.exchange_sigs, - dr->details.success.num_signatures + ds->exchange_timestamp = dr->details.ok.deposit_timestamp; + ds->exchange_pub = *dr->details.ok.exchange_pub; + ds->exchange_sigs = GNUNET_memdup (dr->details.ok.exchange_sigs, + dr->details.ok.num_signatures * sizeof (struct TALER_ExchangeSignatureP)); } diff --git a/src/testing/testing_api_cmd_batch_withdraw.c b/src/testing/testing_api_cmd_batch_withdraw.c @@ -210,7 +210,7 @@ reserve_batch_withdraw_cb (void *cls, { struct CoinState *cs = &ws->coins[i]; const struct TALER_EXCHANGE_PrivateCoinDetails *pcd - = &wr->details.success.coins[i]; + = &wr->details.ok.coins[i]; TALER_denom_sig_deep_copy (&cs->sig, &pcd->sig); diff --git a/src/testing/testing_api_cmd_check_aml_decision.c b/src/testing/testing_api_cmd_check_aml_decision.c @@ -116,10 +116,10 @@ check_aml_decision_cb (void *cls, GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_amount (ref, &amount)); - for (unsigned int i = 0; i<adr->details.success.aml_history_length; i++) + for (unsigned int i = 0; i<adr->details.ok.aml_history_length; i++) { const struct TALER_EXCHANGE_AmlDecisionDetail *aml_history - = &adr->details.success.aml_history[i]; + = &adr->details.ok.aml_history[i]; if ( (NULL == oldest) || (0 != diff --git a/src/testing/testing_api_cmd_contract_get.c b/src/testing/testing_api_cmd_contract_get.c @@ -121,7 +121,7 @@ get_cb (void *cls, const struct TALER_PurseMergePrivateKeyP *mp; const json_t *ct; - ds->purse_pub = dr->details.success.purse_pub; + ds->purse_pub = dr->details.ok.purse_pub; if (ds->merge) { if (GNUNET_OK != @@ -136,8 +136,8 @@ get_cb (void *cls, TALER_CRYPTO_contract_decrypt_for_merge ( &ds->contract_priv, &ds->purse_pub, - dr->details.success.econtract, - dr->details.success.econtract_size, + dr->details.ok.econtract, + dr->details.ok.econtract_size, &ds->merge_priv); if (0 != GNUNET_memcmp (mp, @@ -153,8 +153,8 @@ get_cb (void *cls, ds->contract_terms = TALER_CRYPTO_contract_decrypt_for_deposit ( &ds->contract_priv, - dr->details.success.econtract, - dr->details.success.econtract_size); + dr->details.ok.econtract, + dr->details.ok.econtract_size); } if (NULL == ds->contract_terms) { diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c @@ -264,9 +264,9 @@ deposit_cb (void *cls, if (MHD_HTTP_OK == dr->hr.http_status) { ds->deposit_succeeded = GNUNET_YES; - ds->exchange_timestamp = dr->details.success.deposit_timestamp; - ds->exchange_pub = *dr->details.success.exchange_pub; - ds->exchange_sig = *dr->details.success.exchange_sig; + ds->exchange_timestamp = dr->details.ok.deposit_timestamp; + ds->exchange_pub = *dr->details.ok.exchange_pub; + ds->exchange_sig = *dr->details.ok.exchange_sig; } TALER_TESTING_interpreter_next (ds->is); } diff --git a/src/testing/testing_api_cmd_deposits_get.c b/src/testing/testing_api_cmd_deposits_get.c @@ -128,7 +128,7 @@ deposit_wtid_cb (void *cls, switch (dr->hr.http_status) { case MHD_HTTP_OK: - tts->wtid = dr->details.success.wtid; + tts->wtid = dr->details.ok.wtid; if (NULL != tts->bank_transfer_reference) { const struct TALER_TESTING_Command *bank_transfer_cmd; @@ -155,7 +155,7 @@ deposit_wtid_cb (void *cls, } /* Compare that expected and gotten subjects match. */ - if (0 != GNUNET_memcmp (&dr->details.success.wtid, + if (0 != GNUNET_memcmp (&dr->details.ok.wtid, wtid_want)) { GNUNET_break (0); diff --git a/src/testing/testing_api_cmd_nexus_fetch_transactions.c b/src/testing/testing_api_cmd_nexus_fetch_transactions.c @@ -80,6 +80,7 @@ nft_run (void *cls, "wget", "--header=Content-Type:application/json", "--auth-no-challenge", + "--output-file=/dev/null", "--post-data={\"level\":\"all\",\"rangeType\":\"latest\"}", user, pass, diff --git a/src/testing/testing_api_cmd_purse_create_deposit.c b/src/testing/testing_api_cmd_purse_create_deposit.c @@ -176,8 +176,8 @@ deposit_cb (void *cls, } if (MHD_HTTP_OK == dr->hr.http_status) { - ds->exchange_pub = dr->details.success.exchange_pub; - ds->exchange_sig = dr->details.success.exchange_sig; + ds->exchange_pub = dr->details.ok.exchange_pub; + ds->exchange_sig = dr->details.ok.exchange_sig; } TALER_TESTING_interpreter_next (ds->is); } diff --git a/src/testing/testing_api_cmd_purse_deposit.c b/src/testing/testing_api_cmd_purse_deposit.c @@ -152,8 +152,8 @@ deposit_cb (void *cls, if (MHD_HTTP_OK == dr->hr.http_status) { if (-1 != - TALER_amount_cmp (&dr->details.success.total_deposited, - &dr->details.success.purse_value_after_fees)) + TALER_amount_cmp (&dr->details.ok.total_deposited, + &dr->details.ok.purse_value_after_fees)) { const struct TALER_TESTING_Command *purse_cmd; const struct TALER_ReserveSignatureP *reserve_sig; @@ -213,7 +213,7 @@ deposit_cb (void *cls, /* Note: change when flags below changes! */ ds->reserve_history.amount - = dr->details.success.purse_value_after_fees; + = dr->details.ok.purse_value_after_fees; if (true) { ds->reserve_history.details.merge_details.purse_fee = gf->fees.purse; @@ -226,7 +226,7 @@ deposit_cb (void *cls, } } ds->reserve_history.details.merge_details.h_contract_terms - = dr->details.success.h_contract_terms; + = dr->details.ok.h_contract_terms; ds->reserve_history.details.merge_details.merge_pub = *merge_pub; ds->reserve_history.details.merge_details.purse_pub @@ -236,7 +236,7 @@ deposit_cb (void *cls, ds->reserve_history.details.merge_details.merge_timestamp = *merge_timestamp; ds->reserve_history.details.merge_details.purse_expiration - = dr->details.success.purse_expiration; + = dr->details.ok.purse_expiration; ds->reserve_history.details.merge_details.min_age = ds->min_age; ds->reserve_history.details.merge_details.flags diff --git a/src/testing/testing_api_cmd_purse_get.c b/src/testing/testing_api_cmd_purse_get.c @@ -147,11 +147,11 @@ purse_status_cb (void *cls, TALER_string_to_amount (ss->expected_balance, &eb)); if (0 != TALER_amount_cmp (&eb, - &rs->details.success.balance)) + &rs->details.ok.balance)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected amount in purse: %s\n", - TALER_amount_to_string (&rs->details.success.balance)); + TALER_amount_to_string (&rs->details.ok.balance)); TALER_TESTING_interpreter_fail (ss->is); return; } diff --git a/src/testing/testing_api_cmd_recoup.c b/src/testing/testing_api_cmd_recoup.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -73,15 +73,14 @@ struct RecoupState * was paid back belonged to the right reserve. * * @param cls closure - * @param hr HTTP response details - * @param reserve_pub public key of the reserve receiving the recoup + * @param rr response details */ static void recoup_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_ReservePublicKeyP *reserve_pub) + const struct TALER_EXCHANGE_RecoupResponse *rr) { struct RecoupState *ps = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr; struct TALER_TESTING_Interpreter *is = ps->is; struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; const struct TALER_TESTING_Command *reserve_cmd; @@ -135,12 +134,6 @@ recoup_cb (void *cls, { const struct TALER_ReservePrivateKeyP *reserve_priv; - if (NULL == reserve_pub) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv (reserve_cmd, &reserve_priv)) @@ -151,7 +144,7 @@ recoup_cb (void *cls, } GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, &ps->reserve_pub.eddsa_pub); - if (0 != GNUNET_memcmp (reserve_pub, + if (0 != GNUNET_memcmp (&rr->details.ok.reserve_pub, &ps->reserve_pub)) { GNUNET_break (0); diff --git a/src/testing/testing_api_cmd_recoup_refresh.c b/src/testing/testing_api_cmd_recoup_refresh.c @@ -73,15 +73,14 @@ struct RecoupRefreshState * was paid back belonged to the right old coin. * * @param cls closure - * @param hr HTTP response details - * @param old_coin_pub public key of the dirty coin + * @param rrr response details */ static void recoup_refresh_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_CoinSpendPublicKeyP *old_coin_pub) + const struct TALER_EXCHANGE_RecoupRefreshResponse *rrr) { struct RecoupRefreshState *rrs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rrr->hr; struct TALER_TESTING_Interpreter *is = rrs->is; struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; char *cref; @@ -150,7 +149,7 @@ recoup_refresh_cb (void *cls, GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv, &oc.eddsa_pub); if (0 != GNUNET_memcmp (&oc, - old_coin_pub)) + &rrr->details.ok.old_coin_pub)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c @@ -411,7 +411,7 @@ reveal_cb (void *cls, switch (hr->http_status) { case MHD_HTTP_OK: - rrs->num_fresh_coins = rr->details.success.num_coins; + rrs->num_fresh_coins = rr->details.ok.num_coins; rrs->psa = GNUNET_new_array (rrs->num_fresh_coins, struct TALER_PlanchetMasterSecretP); rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins, @@ -419,7 +419,7 @@ reveal_cb (void *cls, for (unsigned int i = 0; i<rrs->num_fresh_coins; i++) { const struct TALER_EXCHANGE_RevealedCoinInfo *coin - = &rr->details.success.coins[i]; + = &rr->details.ok.coins[i]; struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i]; rrs->psa[i] = coin->ps; @@ -675,11 +675,11 @@ link_cb (void *cls, TALER_TESTING_interpreter_fail (rls->is); return; } - if (lr->details.success.num_coins != *num_fresh_coins) + if (lr->details.ok.num_coins != *num_fresh_coins) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected number of fresh coins: %d vs %d in %s:%u\n", - lr->details.success.num_coins, + lr->details.ok.num_coins, *num_fresh_coins, __FILE__, __LINE__); @@ -687,11 +687,11 @@ link_cb (void *cls, return; } /* check that the coins match */ - for (unsigned int i = 0; i<lr->details.success.num_coins; i++) - for (unsigned int j = i + 1; j<lr->details.success.num_coins; j++) + for (unsigned int i = 0; i<lr->details.ok.num_coins; i++) + for (unsigned int j = i + 1; j<lr->details.ok.num_coins; j++) if (0 == - GNUNET_memcmp (&lr->details.success.coins[i].coin_priv, - &lr->details.success.coins[j].coin_priv)) + GNUNET_memcmp (&lr->details.ok.coins[i].coin_priv, + &lr->details.ok.coins[j].coin_priv)) GNUNET_break (0); /* Note: coins might be legitimately permutated in here... */ found = 0; @@ -709,12 +709,12 @@ link_cb (void *cls, return; } - for (unsigned int i = 0; i<lr->details.success.num_coins; i++) + for (unsigned int i = 0; i<lr->details.ok.num_coins; i++) { const struct TALER_EXCHANGE_LinkedCoinInfo *lci_i - = &lr->details.success.coins[i]; + = &lr->details.ok.coins[i]; - for (unsigned int j = 0; j<lr->details.success.num_coins; j++) + for (unsigned int j = 0; j<lr->details.ok.num_coins; j++) { const struct TALER_TESTING_FreshCoinData *fcj = &(*fc)[j]; @@ -735,12 +735,12 @@ link_cb (void *cls, } /* for j*/ } /* for i */ } - if (found != lr->details.success.num_coins) + if (found != lr->details.ok.num_coins) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Only %u/%u coins match expectations\n", found, - lr->details.success.num_coins); + lr->details.ok.num_coins); GNUNET_break (0); TALER_TESTING_interpreter_fail (rls->is); return; @@ -952,16 +952,16 @@ melt_cb (void *cls, } if (MHD_HTTP_OK == hr->http_status) { - rms->noreveal_index = mr->details.success.noreveal_index; - if (mr->details.success.num_mbds != rms->num_fresh_coins) + rms->noreveal_index = mr->details.ok.noreveal_index; + if (mr->details.ok.num_mbds != rms->num_fresh_coins) { GNUNET_break (0); TALER_TESTING_interpreter_fail (rms->is); return; } GNUNET_free (rms->mbds); - rms->mbds = GNUNET_memdup (mr->details.success.mbds, - mr->details.success.num_mbds + rms->mbds = GNUNET_memdup (mr->details.ok.mbds, + mr->details.ok.num_mbds * sizeof (struct TALER_EXCHANGE_MeltBlindingDetail)); } diff --git a/src/testing/testing_api_cmd_refund.c b/src/testing/testing_api_cmd_refund.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -75,19 +75,14 @@ struct RefundState * response code is acceptable. * * @param cls closure - * @param hr HTTP response details - * @param exchange_pub public key the exchange - * used for signing @a obj. - * @param exchange_sig actual signature confirming the refund + * @param rr response details */ static void refund_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const struct TALER_ExchangeSignatureP *exchange_sig) + const struct TALER_EXCHANGE_RefundResponse *rr) { - struct RefundState *rs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr; struct TALER_TESTING_Command *refund_cmd; refund_cmd = &rs->is->commands[rs->is->ip]; diff --git a/src/testing/testing_api_cmd_revoke_denom_key.c b/src/testing/testing_api_cmd_revoke_denom_key.c @@ -65,14 +65,15 @@ struct RevokeState * Function called with information about the post revocation operation result. * * @param cls closure with a `struct RevokeState *` - * @param hr HTTP response data + * @param rdr response data */ static void success_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *rdr) { struct RevokeState *rs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rdr->hr; rs->kh = NULL; if (rs->expected_response_code != hr->http_status) diff --git a/src/testing/testing_api_cmd_revoke_sign_key.c b/src/testing/testing_api_cmd_revoke_sign_key.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -65,14 +65,15 @@ struct RevokeState * Function called with information about the post revocation operation result. * * @param cls closure with a `struct RevokeState *` - * @param hr HTTP response data + * @param rsr response data */ static void success_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *rsr) { struct RevokeState *rs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rsr->hr; rs->kh = NULL; if (rs->expected_response_code != hr->http_status) diff --git a/src/testing/testing_api_cmd_set_officer.c b/src/testing/testing_api_cmd_set_officer.c @@ -84,13 +84,15 @@ struct SetOfficerState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param ar response details */ static void set_officer_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct + TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *ar) { struct SetOfficerState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr; ds->dh = NULL; if (MHD_HTTP_NO_CONTENT != hr->http_status) diff --git a/src/testing/testing_api_cmd_transfer_get.c b/src/testing/testing_api_cmd_transfer_get.c @@ -115,15 +115,14 @@ track_transfer_cleanup (void *cls, * wire fees and hashed wire details as well. * * @param cls closure. - * @param hr HTTP response details - * @param ta transfer data returned by the exchange + * @param tgr response details */ static void track_transfer_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_TransferData *ta) + const struct TALER_EXCHANGE_TransfersGetResponse *tgr) { struct TrackTransferState *tts = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &tgr->hr; struct TALER_TESTING_Interpreter *is = tts->is; struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; struct TALER_Amount expected_amount; @@ -148,138 +147,62 @@ track_transfer_cb (void *cls, switch (hr->http_status) { case MHD_HTTP_OK: - if (NULL == tts->expected_total_amount) { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (NULL == tts->expected_wire_fee) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_string_to_amount (tts->expected_total_amount, - &expected_amount)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (0 != TALER_amount_cmp (&ta->total_amount, - &expected_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Total amount mismatch to command %s - " - "%s vs %s\n", - cmd->label, - TALER_amount_to_string (&ta->total_amount), - TALER_amount_to_string (&expected_amount)); - json_dumpf (hr->reply, - stderr, - 0); - fprintf (stderr, "\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_string_to_amount (tts->expected_wire_fee, - &expected_amount)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (0 != TALER_amount_cmp (&ta->wire_fee, - &expected_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fee mismatch to command %s\n", - cmd->label); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (is); - return; - } + const struct TALER_EXCHANGE_TransferData *ta + = &tgr->details.ok.td; - /** - * Optionally checking: (1) wire-details for this transfer - * match the ones from a referenced "deposit" operation - - * or any operation that could provide wire-details. (2) - * Total amount for this transfer matches the one from any - * referenced command that could provide one. - */ - if (NULL != tts->wire_details_reference) - { - const struct TALER_TESTING_Command *wire_details_cmd; - const char **payto_uri; - struct TALER_PaytoHashP h_payto; - - wire_details_cmd - = TALER_TESTING_interpreter_lookup_command (is, - tts->wire_details_reference); - if (NULL == wire_details_cmd) + if (NULL == tts->expected_total_amount) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } + if (NULL == tts->expected_wire_fee) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != - TALER_TESTING_get_trait_payto_uri (wire_details_cmd, - &payto_uri)) + TALER_string_to_amount (tts->expected_total_amount, + &expected_amount)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } - TALER_payto_hash (*payto_uri, - &h_payto); - if (0 != GNUNET_memcmp (&h_payto, - &ta->h_payto)) + if (0 != TALER_amount_cmp (&ta->total_amount, + &expected_amount)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire hash missmath to command %s\n", - cmd->label); + "Total amount mismatch to command %s - " + "%s vs %s\n", + cmd->label, + TALER_amount_to_string (&ta->total_amount), + TALER_amount_to_string (&expected_amount)); json_dumpf (hr->reply, stderr, 0); + fprintf (stderr, "\n"); TALER_TESTING_interpreter_fail (is); return; } - } - if (NULL != tts->total_amount_reference) - { - const struct TALER_TESTING_Command *total_amount_cmd; - const struct TALER_Amount *total_amount_from_reference; - total_amount_cmd - = TALER_TESTING_interpreter_lookup_command (is, - tts->total_amount_reference); - if (NULL == total_amount_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } if (GNUNET_OK != - TALER_TESTING_get_trait_amount (total_amount_cmd, - &total_amount_from_reference)) + TALER_string_to_amount (tts->expected_wire_fee, + &expected_amount)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } - if (0 != TALER_amount_cmp (&ta->total_amount, - total_amount_from_reference)) + + if (0 != TALER_amount_cmp (&ta->wire_fee, + &expected_amount)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Amount missmath to command %s\n", + "Wire fee mismatch to command %s\n", cmd->label); json_dumpf (hr->reply, stderr, @@ -287,8 +210,92 @@ track_transfer_cb (void *cls, TALER_TESTING_interpreter_fail (is); return; } - } - } + + /** + * Optionally checking: (1) wire-details for this transfer + * match the ones from a referenced "deposit" operation - + * or any operation that could provide wire-details. (2) + * Total amount for this transfer matches the one from any + * referenced command that could provide one. + */ + if (NULL != tts->wire_details_reference) + { + const struct TALER_TESTING_Command *wire_details_cmd; + const char **payto_uri; + struct TALER_PaytoHashP h_payto; + + wire_details_cmd + = TALER_TESTING_interpreter_lookup_command (is, + tts-> + wire_details_reference); + if (NULL == wire_details_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_payto_uri (wire_details_cmd, + &payto_uri)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_payto_hash (*payto_uri, + &h_payto); + if (0 != GNUNET_memcmp (&h_payto, + &ta->h_payto)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire hash missmath to command %s\n", + cmd->label); + json_dumpf (hr->reply, + stderr, + 0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + if (NULL != tts->total_amount_reference) + { + const struct TALER_TESTING_Command *total_amount_cmd; + const struct TALER_Amount *total_amount_from_reference; + + total_amount_cmd + = TALER_TESTING_interpreter_lookup_command (is, + tts-> + total_amount_reference); + if (NULL == total_amount_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_amount (total_amount_cmd, + &total_amount_from_reference)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (0 != TALER_amount_cmp (&ta->total_amount, + total_amount_from_reference)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Amount missmath to command %s\n", + cmd->label); + json_dumpf (hr->reply, + stderr, + 0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + break; + } /* case OK */ + } /* switch on status */ TALER_TESTING_interpreter_next (is); } diff --git a/src/testing/testing_api_cmd_wire.c b/src/testing/testing_api_cmd_wire.c @@ -72,18 +72,14 @@ struct WireState * that the wire fee is acceptable too. * * @param cls closure. - * @param hr HTTP response details - * @param accounts_len length of the @a accounts array. - * @param accounts list of wire accounts of the exchange, - * NULL on error. + * @param wr response details */ static void wire_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - unsigned int accounts_len, - const struct TALER_EXCHANGE_WireAccount *accounts) + const struct TALER_EXCHANGE_WireResponse *wr) { struct WireState *ws = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &wr->hr; struct TALER_TESTING_Command *cmd = &ws->is->commands[ws->is->ip]; struct TALER_Amount expected_fee; @@ -100,6 +96,15 @@ wire_cb (void *cls, if (MHD_HTTP_OK == hr->http_status) { + unsigned int accounts_len + = wr->details.ok.accounts_len; + unsigned int fees_len + = wr->details.ok.fees_len; + const struct TALER_EXCHANGE_WireAccount *accounts + = wr->details.ok.accounts; + const struct TALER_EXCHANGE_WireFeesByMethod *fees + = wr->details.ok.fees; + for (unsigned int i = 0; i<accounts_len; i++) { char *method; @@ -115,32 +120,46 @@ wire_cb (void *cls, method)) { ws->method_found = GNUNET_OK; - if (NULL != ws->expected_fee) + } + GNUNET_free (method); + } + if (NULL != ws->expected_fee) + { + bool fee_found = false; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (ws->expected_fee, + &expected_fee)); + for (unsigned int i = 0; i<fees_len; i++) + { + if (0 != strcmp (fees[i].method, + ws->expected_method)) + continue; + for (const struct TALER_EXCHANGE_WireAggregateFees *waf + = fees[i].fees_head; + NULL != waf; + waf = waf->next) { - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (ws->expected_fee, - &expected_fee)); - for (const struct TALER_EXCHANGE_WireAggregateFees *waf - = accounts[i].fees; - NULL != waf; - waf = waf->next) + if (0 != TALER_amount_cmp (&waf->fees.wire, + &expected_fee)) { - if (0 != TALER_amount_cmp (&waf->fees.wire, - &expected_fee)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fee mismatch to command %s\n", - cmd->label); - TALER_TESTING_interpreter_fail (ws->is); - GNUNET_free (method); - return; - } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire fee mismatch to command %s\n", + cmd->label); + TALER_TESTING_interpreter_fail (ws->is); + return; } + fee_found = true; } } - TALER_LOG_DEBUG ("Freeing method '%s'\n", - method); - GNUNET_free (method); + if (! fee_found) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "/wire does not contain expected fee '%s'\n", + ws->expected_fee); + TALER_TESTING_interpreter_fail (ws->is); + return; + } } if (GNUNET_OK != ws->method_found) { diff --git a/src/testing/testing_api_cmd_wire_add.c b/src/testing/testing_api_cmd_wire_add.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020 Taler Systems SA + Copyright (C) 2020-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -67,13 +67,14 @@ struct WireAddState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param wer response details */ static void wire_add_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer) { struct WireAddState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) @@ -110,10 +111,14 @@ wire_add_run (void *cls, struct TALER_MasterSignatureP master_sig1; struct TALER_MasterSignatureP master_sig2; struct GNUNET_TIME_Timestamp now; + json_t *credit_rest; + json_t *debit_rest; (void) cmd; now = GNUNET_TIME_timestamp_get (); ds->is = is; + debit_rest = json_array (); + credit_rest = json_array (); if (ds->bad_sig) { memset (&master_sig1, @@ -126,10 +131,16 @@ wire_add_run (void *cls, else { TALER_exchange_offline_wire_add_sign (ds->payto_uri, + NULL, + debit_rest, + credit_rest, now, &is->master_priv, &master_sig1); TALER_exchange_wire_signature_make (ds->payto_uri, + NULL, + debit_rest, + credit_rest, &is->master_priv, &master_sig2); } @@ -137,11 +148,16 @@ wire_add_run (void *cls, is->ctx, is->exchange_url, ds->payto_uri, + NULL, + debit_rest, + credit_rest, now, &master_sig1, &master_sig2, &wire_add_cb, ds); + json_decref (debit_rest); + json_decref (credit_rest); if (NULL == ds->dh) { GNUNET_break (0); diff --git a/src/testing/testing_api_cmd_wire_del.c b/src/testing/testing_api_cmd_wire_del.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020 Taler Systems SA + Copyright (C) 2020, 2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -67,13 +67,14 @@ struct WireDelState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param wdr response details */ static void wire_del_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdr) { struct WireDelState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &wdr->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c @@ -297,10 +297,10 @@ reserve_withdraw_cb (void *cls, { case MHD_HTTP_OK: TALER_denom_sig_deep_copy (&ws->sig, - &wr->details.success.sig); - ws->coin_priv = wr->details.success.coin_priv; - ws->bks = wr->details.success.bks; - ws->exchange_vals = wr->details.success.exchange_vals; + &wr->details.ok.sig); + ws->coin_priv = wr->details.ok.coin_priv; + ws->bks = wr->details.ok.bks; + ws->exchange_vals = wr->details.ok.exchange_vals; if (0 != ws->total_backoff.rel_value_us) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c @@ -526,49 +526,46 @@ sighandler_child_death (void) void TALER_TESTING_cert_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat) + const struct TALER_EXCHANGE_KeysResponse *kr) { + const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr; struct MainContext *main_ctx = cls; struct TALER_TESTING_Interpreter *is = main_ctx->is; - (void) compat; - if (NULL == keys) + switch (hr->http_status) { - if (GNUNET_NO == is->working) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Got NULL response for /keys during startup (%u/%d), retrying!\n", - hr->http_status, - (int) hr->ec); - TALER_EXCHANGE_disconnect (is->exchange); - GNUNET_assert ( - NULL != (is->exchange - = TALER_EXCHANGE_connect (is->ctx, - main_ctx->exchange_url, - &TALER_TESTING_cert_cb, - main_ctx, - TALER_EXCHANGE_OPTION_END))); - return; - } - else + case MHD_HTTP_OK: + /* dealt with below */ + break; + default: + if (GNUNET_YES == is->working) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got NULL response for /keys during execution (%u/%d)!\n", hr->http_status, (int) hr->ec); + return; } + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Got failure response for /keys during startup (%u/%d), retrying!\n", + hr->http_status, + (int) hr->ec); + TALER_EXCHANGE_disconnect (is->exchange); + GNUNET_assert ( + NULL != (is->exchange + = TALER_EXCHANGE_connect (is->ctx, + main_ctx->exchange_url, + &TALER_TESTING_cert_cb, + main_ctx, + TALER_EXCHANGE_OPTION_END))); + return; } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got %d DK from /keys in generation %u\n", - keys->num_denom_keys, - is->key_generation + 1); - } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got %d DK from /keys in generation %u\n", + kr->details.ok.keys->num_denom_keys, + is->key_generation + 1); is->key_generation++; - is->keys = keys; + is->keys = kr->details.ok.keys; /* /keys has been called for some reason and * the interpreter is already running. */ diff --git a/src/util/offline_signatures.c b/src/util/offline_signatures.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020-2022 Taler Systems SA + Copyright (C) 2020-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -677,6 +677,22 @@ struct TALER_MasterAddWirePS * Hash over the exchange's payto URI. */ struct TALER_PaytoHashP h_payto GNUNET_PACKED; + + /** + * Hash over the conversion URL, all zeros if there + * is no conversion URL. + */ + struct GNUNET_HashCode h_conversion_url; + + /** + * Hash over the debit restrictions. + */ + struct GNUNET_HashCode h_debit_restrictions; + + /** + * Hash over the credit restrictions. + */ + struct GNUNET_HashCode h_credit_restrictions; }; GNUNET_NETWORK_STRUCT_END @@ -685,6 +701,9 @@ GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_wire_add_sign ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp now, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) @@ -697,6 +716,14 @@ TALER_exchange_offline_wire_add_sign ( TALER_payto_hash (payto_uri, &kv.h_payto); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &kv.h_conversion_url); + TALER_json_hash (debit_restrictions, + &kv.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &kv.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); @@ -706,6 +733,9 @@ TALER_exchange_offline_wire_add_sign ( enum GNUNET_GenericReturnValue TALER_exchange_offline_wire_add_verify ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp sign_time, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) @@ -718,6 +748,14 @@ TALER_exchange_offline_wire_add_verify ( TALER_payto_hash (payto_uri, &aw.h_payto); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &aw.h_conversion_url); + TALER_json_hash (debit_restrictions, + &aw.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &aw.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_ADD_WIRE, @@ -1095,6 +1133,22 @@ struct TALER_MasterWireDetailsPS */ struct TALER_PaytoHashP h_wire_details GNUNET_PACKED; + /** + * Hash over the conversion URL, all zeros if there + * is no conversion URL. + */ + struct GNUNET_HashCode h_conversion_url; + + /** + * Hash over the debit restrictions. + */ + struct GNUNET_HashCode h_debit_restrictions; + + /** + * Hash over the credit restrictions. + */ + struct GNUNET_HashCode h_credit_restrictions; + }; GNUNET_NETWORK_STRUCT_END @@ -1103,6 +1157,9 @@ GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue TALER_exchange_wire_signature_check ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { @@ -1113,6 +1170,14 @@ TALER_exchange_wire_signature_check ( TALER_payto_hash (payto_uri, &wd.h_wire_details); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &wd.h_conversion_url); + TALER_json_hash (debit_restrictions, + &wd.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &wd.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_DETAILS, &wd, &master_sig->eddsa_signature, @@ -1123,6 +1188,9 @@ TALER_exchange_wire_signature_check ( void TALER_exchange_wire_signature_make ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { @@ -1133,6 +1201,14 @@ TALER_exchange_wire_signature_make ( TALER_payto_hash (payto_uri, &wd.h_wire_details); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url), + &wd.h_conversion_url); + TALER_json_hash (debit_restrictions, + &wd.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &wd.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &wd, &master_sig->eddsa_signature);