From 487f23502f00cc0ec54e7cec043f41582030613d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 25 Apr 2023 23:06:58 +0200 Subject: add nexus-fetch-transactions --- src/include/taler_testing_lib.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/include') diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 37d347c3..5fc930a8 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -1242,6 +1242,36 @@ TALER_TESTING_cmd_exec_wirewatch (const char *label, const char *config_filename); +/** + * Request URL via "wget". + * + * @param label command label. + * @param url URL to fetch + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_wget (const char *label, + const char *url); + + +/** + * Request fetch-transactions via "wget". + * + * @param label command label. + * @param username username to use + * @param password password to use + * @param bank_base_url base URL of the nexus + * @param account_id account to fetch transactions for + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_nexus_fetch_transactions (const char *label, + const char *username, + const char *password, + const char *bank_base_url, + const char *account_id); + + /** * Make a "expire" CMD. * -- cgit v1.2.3 From 1a63275d9804762f0bcdc1cd23060c2e9b364fbb Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Mon, 1 May 2023 14:05:58 +0200 Subject: WiP: age-withdraw, finished reveal-request, 10/n - /age-withdraw/$ACH/reveal handler now fully implemented - for consistency with api: rename of tables from withdraw_age_... to age_withdraw --- .../taler-exchange-httpd_age-withdraw_reveal.c | 163 +++++++++++++++++++-- src/exchange/taler-exchange-httpd_metrics.h | 3 +- .../taler-exchange-httpd_refreshes_reveal.c | 10 +- src/exchangedb/0003-age_withdraw_commitments.sql | 134 +++++++++++++++++ src/exchangedb/0003-age_withdraw_reveals.sql | 152 +++++++++++++++++++ src/exchangedb/0003-withdraw_age_commitments.sql | 142 ------------------ src/exchangedb/0003-withdraw_age_reveals.sql | 159 -------------------- src/exchangedb/exchange-0003.sql.in | 2 + src/exchangedb/pg_get_age_withdraw_info.c | 2 +- src/exchangedb/pg_insert_age_withdraw_reveal.c | 4 +- src/exchangedb/pg_insert_records_by_table.c | 60 ++++---- src/exchangedb/pg_lookup_records_by_table.c | 58 ++++---- src/exchangedb/pg_lookup_serial_by_table.c | 20 +-- src/include/taler_exchangedb_plugin.h | 46 ++++-- 14 files changed, 548 insertions(+), 407 deletions(-) create mode 100644 src/exchangedb/0003-age_withdraw_commitments.sql create mode 100644 src/exchangedb/0003-age_withdraw_reveals.sql delete mode 100644 src/exchangedb/0003-withdraw_age_commitments.sql delete mode 100644 src/exchangedb/0003-withdraw_age_reveals.sql (limited to 'src/include') diff --git a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c index 5cee7277..931463cb 100644 --- a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c +++ b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c @@ -22,6 +22,8 @@ #include #include #include +#include "taler-exchange-httpd_metrics.h" +#include "taler_exchangedb_plugin.h" #include "taler_mhd_lib.h" #include "taler-exchange-httpd_mhd.h" #include "taler-exchange-httpd_age-withdraw_reveal.h" @@ -387,12 +389,10 @@ denomination_is_valid ( struct TEH_DenominationKey *dks, MHD_RESULT *result) { - dks = TEH_keys_denomination_by_hash2 ( - ksh, - denom_h, - connection, - result); - + dks = TEH_keys_denomination_by_hash2 (ksh, + denom_h, + connection, + result); if (NULL == dks) { /* The denomination doesn't exist */ @@ -784,6 +784,43 @@ verify_commitment_and_max_age ( } +/** + * @brief Send a response for "/age-withdraw/$RCH/reveal" + * + * @param connection The http connection to the client to send the reponse to + * @param num_coins Number of new coins with age restriction for which we reveal data + * @param awrcs array of @a num_coins signatures revealed + * @return a MHD result code + */ +static MHD_RESULT +reply_age_withdraw_reveal_success ( + struct MHD_Connection *connection, + unsigned int num_coins, + const struct TALER_EXCHANGEDB_AgeWithdrawRevealedCoin *awrcs) +{ + json_t *list = json_array (); + GNUNET_assert (NULL != list); + + for (unsigned int index = 0; + index < num_coins; + index++) + { + json_t *obj = GNUNET_JSON_PACK ( + TALER_JSON_pack_blinded_denom_sig ("ev_sig", + &awrcs[index].coin_sig)); + GNUNET_assert (0 == + json_array_append_new (list, + obj)); + } + + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("ev_sigs", + list)); +} + + /** * @brief Signs and persists the undisclosed coins * @@ -796,7 +833,7 @@ verify_commitment_and_max_age ( * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ static enum GNUNET_GenericReturnValue -finalize_age_withdraw_and_sign ( +sign_and_finalize_age_withdraw ( struct MHD_Connection *connection, const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, const uint32_t num_coins, @@ -806,7 +843,9 @@ finalize_age_withdraw_and_sign ( { enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; struct TEH_CoinSignData csds[num_coins]; - struct TALER_BlindedDenominationSignature bss[num_coins]; + struct TALER_BlindedDenominationSignature bds[num_coins]; + struct TALER_EXCHANGEDB_AgeWithdrawRevealedCoin awrcs[num_coins]; + enum GNUNET_DB_QueryStatus qs; for (uint32_t i = 0; istart (TEH_plugin->cls, + "insert_age_withdraw_reveal batch")) + { + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_START_FAILED, + NULL); + goto cleanup; + } + + qs = TEH_plugin->insert_age_withdraw_reveal (TEH_plugin->cls, + h_commitment, + num_coins, + awrcs); + + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + { + TEH_plugin->rollback (TEH_plugin->cls); + continue; + } + else if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + GNUNET_break (0); + TEH_plugin->rollback (TEH_plugin->cls); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert_age_withdraw_reveal"); + goto cleanup; + } + + changed = (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); + + /* Commit the transaction */ + qs = TEH_plugin->commit (TEH_plugin->cls); + if (qs >= 0) + { + if (changed) + TEH_METRICS_num_success[TEH_MT_SUCCESS_AGE_WITHDRAW_REVEAL]++; + + break; /* success */ -#pragma message "FIXME[oec]: implement finalize_age_withdraw_and_sign" + } + else if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + GNUNET_break (0); + TEH_plugin->rollback (TEH_plugin->cls); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_COMMIT_FAILED, + NULL); + goto cleanup; + } + else + { + TEH_plugin->rollback (TEH_plugin->cls); + } + } /* end of retry */ + + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + { + GNUNET_break (0); + TEH_plugin->rollback (TEH_plugin->cls); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_SOFT_FAILURE, + NULL); + goto cleanup; + } + + /* Generate final (positive) response */ + ret = reply_age_withdraw_reveal_success (connection, + num_coins, + awrcs); +cleanup: + // TODO[oec]: handle error cases + // TODO[oec]: cleanup! return ret; } @@ -922,7 +1053,7 @@ TEH_handler_age_withdraw_reveal ( break; /* Finally, sign and persist the coins */ - if (GNUNET_OK != finalize_age_withdraw_and_sign ( + if (GNUNET_OK != sign_and_finalize_age_withdraw ( rc->connection, &actx.commitment.h_commitment, actx.num_coins, diff --git a/src/exchange/taler-exchange-httpd_metrics.h b/src/exchange/taler-exchange-httpd_metrics.h index 8f680435..318113c1 100644 --- a/src/exchange/taler-exchange-httpd_metrics.h +++ b/src/exchange/taler-exchange-httpd_metrics.h @@ -61,7 +61,8 @@ enum TEH_MetricTypeSuccess TEH_MT_SUCCESS_BATCH_WITHDRAW = 3, TEH_MT_SUCCESS_MELT = 4, TEH_MT_SUCCESS_REFRESH_REVEAL = 5, - TEH_MT_SUCCESS_COUNT = 6 /* MUST BE LAST! */ + TEH_MT_SUCCESS_AGE_WITHDRAW_REVEAL = 6, + TEH_MT_SUCCESS_COUNT = 7 /* MUST BE LAST! */ }; /** diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c index 08a85265..89bdf272 100644 --- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c +++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c @@ -773,12 +773,17 @@ clean_age: NULL); goto cleanup; } + for (unsigned int i = 0; inum_fresh_coins; i++) + { rrcs[i].coin_sig = bss[i]; + rrcs[i].blinded_planchet = rcds[i].blinded_planchet; + } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Signatures ready, starting DB interaction\n"); + for (unsigned int r = 0; rnum_fresh_coins; i++) - { - struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i]; - rrc->blinded_planchet = rcds[i].blinded_planchet; - } qs = TEH_plugin->insert_refresh_reveal ( TEH_plugin->cls, melt_serial_id, diff --git a/src/exchangedb/0003-age_withdraw_commitments.sql b/src/exchangedb/0003-age_withdraw_commitments.sql new file mode 100644 index 00000000..d74a697c --- /dev/null +++ b/src/exchangedb/0003-age_withdraw_commitments.sql @@ -0,0 +1,134 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2022 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 +-- + +CREATE FUNCTION create_table_age_withdraw_commitments( + IN partition_suffix VARCHAR DEFAULT NULL +) +RETURNS VOID +LANGUAGE plpgsql +AS $$ +DECLARE + table_name VARCHAR DEFAULT 'age_withdraw_commitments'; +BEGIN + PERFORM create_partitioned_table( + 'CREATE TABLE %I' + '(age_withdraw_commitment_id BIGINT GENERATED BY DEFAULT AS IDENTITY' + ',h_commitment BYTEA CHECK (LENGTH(h_commitment)=64)' + ',amount_with_fee_val INT8 NOT NULL' + ',amount_with_fee_frac INT4 NOT NULL' + ',max_age INT2 NOT NULL' + ',reserve_pub BYTEA CHECK (LENGTH(reserve_pub)=32)' + ',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)' + ',noreveal_index INT4 NOT NULL' + ') %s ;' + ,table_name + ,'PARTITION BY HASH (reserve_pub)' + ,partition_suffix + ); + PERFORM comment_partitioned_table( + 'Commitments made when withdrawing coins with age restriction and the gamma value chosen by the exchange.' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'The gamma value chosen by the exchange in the cut-and-choose protocol' + ,'noreveal_index' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'The maximum age (in years) that the client commits to with this request' + ,'max_age' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Commitment made by the client, hash over the various client inputs in the cut-and-choose protocol' + ,'h_commitment' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Reference to the public key of the reserve from which the coins are going to be withdrawn' + ,'reserve_pub' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Signature of the reserve''s private key over the withdraw-age request' + ,'reserve_sig' + ,table_name + ,partition_suffix + ); +END +$$; + + +CREATE FUNCTION constrain_table_age_withdraw_commitments( + IN partition_suffix VARCHAR +) +RETURNS void +LANGUAGE plpgsql +AS $$ +DECLARE + table_name VARCHAR DEFAULT 'age_withdraw_commitments'; +BEGIN + table_name = concat_ws('_', table_name, partition_suffix); + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD PRIMARY KEY (h_commitment);' + ); + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD CONSTRAINT ' || table_name || '_h_commitment_reserve_pub_key' + ' UNIQUE (h_commitment, reserve_pub);' + ); + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD CONSTRAINT ' || table_name || '_age_withdraw_commitment_id_key' + ' UNIQUE (age_withdraw_commitment_id);' + ); +END +$$; + + +CREATE FUNCTION foreign_table_age_withdraw_commitments() +RETURNS void +LANGUAGE plpgsql +AS $$ +DECLARE + table_name VARCHAR DEFAULT 'age_withdraw_commitments'; +BEGIN + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD CONSTRAINT ' || table_name || '_foreign_reserve_pub' + ' FOREIGN KEY (reserve_pub)' + ' REFERENCES reserves(reserve_pub) ON DELETE CASCADE;' + ); +END +$$; + + +INSERT INTO exchange_tables + (name + ,version + ,action + ,partitioned + ,by_range) +VALUES + ('age_withdraw_commitments', 'exchange-0003', 'create', TRUE ,FALSE), + ('age_withdraw_commitments', 'exchange-0003', 'constrain',TRUE ,FALSE), + ('age_withdraw_commitments', 'exchange-0003', 'foreign', TRUE ,FALSE); diff --git a/src/exchangedb/0003-age_withdraw_reveals.sql b/src/exchangedb/0003-age_withdraw_reveals.sql new file mode 100644 index 00000000..1c55fb19 --- /dev/null +++ b/src/exchangedb/0003-age_withdraw_reveals.sql @@ -0,0 +1,152 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2022 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 +-- + +CREATE FUNCTION create_table_age_withdraw_revealed_coins( + IN partition_suffix VARCHAR DEFAULT NULL +) +RETURNS VOID +LANGUAGE plpgsql +AS $$ +DECLARE + table_name VARCHAR DEFAULT 'age_withdraw_revealed_coins'; +BEGIN + PERFORM create_partitioned_table( + 'CREATE TABLE %I' + '(age_withdraw_revealed_coins_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE + ',h_commitment BYTEA NOT NULL CHECK (LENGTH(h_commitment)=64)' + ',freshcoin_index INT4 NOT NULL' + ',denominations_serial INT8 NOT NULL' + ',coin_ev BYTEA NOT NULL' + ',h_coin_ev BYTEA CHECK (LENGTH(h_coin_ev)=64)' + ',ev_sig BYTEA NOT NULL' + ') %s ;' + ,table_name + ,'PARTITION BY HASH (h_commitment)' + ,partition_suffix + ); + PERFORM comment_partitioned_table( + 'Reveal of proofs of the correct age restriction after the commitment when withdrawing coins with age restriction' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Foreign key reference to the corresponding commitment' + ,'h_commitment' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Index of the coin in the withdraw-age request, which is implicitly a batch request' + ,'freshcoin_index' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Foreign key reference to the denominations' + ,'denominations_serial' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Envelope of the new coin to be signed' + ,'coin_ev' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Hash of the envelope of the new coin to be signed (for lookups)' + ,'h_coin_ev' + ,table_name + ,partition_suffix + ); + PERFORM comment_partitioned_column( + 'Exchange signature over the envelope' + ,'ev_sig' + ,table_name + ,partition_suffix + ); +END +$$; + +CREATE FUNCTION constrain_table_age_withdraw_revealed_coins( + IN partition_suffix VARCHAR +) +RETURNS void +LANGUAGE plpgsql +AS $$ +DECLARE + table_name VARCHAR DEFAULT 'age_withdraw_revealed_coins'; +BEGIN + table_name = concat_ws('_', table_name, partition_suffix); + + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD CONSTRAINT ' || table_name || '_age_withdraw_revealed_coins_id_key' + ' UNIQUE (age_withdraw_revealed_coins_id);' + ); + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD CONSTRAINT ' || table_name || '_freshcoin_index_and_h_commitment_uniqueness' + ' UNIQUE (freshcoin_index, h_commitment);' + ); +END +$$; + +CREATE FUNCTION foreign_table_age_withdraw_revealed_coins() +RETURNS void +LANGUAGE plpgsql +AS $$ +DECLARE + table_name VARCHAR DEFAULT 'age_withdraw_revealed_coins'; +BEGIN + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD CONSTRAINT ' || table_name || '_foreign_h_commitment' + ' FOREIGN KEY (h_commitment)' + ' REFERENCES age_withdraw_commitments (h_commitment) ON DELETE CASCADE;' + ); + EXECUTE FORMAT ( + 'ALTER TABLE ' || table_name || + ' ADD CONSTRAINT ' || table_name || '_foreign_denominations_serial' + ' FOREIGN KEY (denominations_serial) ' + ' REFERENCES denominations (denominations_serial) ON DELETE CASCADE;' + ); +END +$$; + + +INSERT INTO exchange_tables + (name + ,version + ,action + ,partitioned + ,by_range) + VALUES + ('age_withdraw_revealed_coins' + ,'exchange-0003' + ,'create' + ,TRUE + ,FALSE), + ('age_withdraw_revealed_coins' + ,'exchange-0003' + ,'constrain' + ,TRUE + ,FALSE), + ('age_withdraw_revealed_coins' + ,'exchange-0003' + ,'foreign' + ,TRUE + ,FALSE); diff --git a/src/exchangedb/0003-withdraw_age_commitments.sql b/src/exchangedb/0003-withdraw_age_commitments.sql deleted file mode 100644 index b8451129..00000000 --- a/src/exchangedb/0003-withdraw_age_commitments.sql +++ /dev/null @@ -1,142 +0,0 @@ --- --- This file is part of TALER --- Copyright (C) 2022 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 --- - -CREATE FUNCTION create_table_withdraw_age_commitments( - IN partition_suffix VARCHAR DEFAULT NULL -) -RETURNS VOID -LANGUAGE plpgsql -AS $$ -DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_commitments'; -BEGIN - PERFORM create_partitioned_table( - 'CREATE TABLE %I' - '(withdraw_age_commitment_id BIGINT GENERATED BY DEFAULT AS IDENTITY' - ',h_commitment BYTEA PRIMARY KEY CHECK (LENGTH(h_commitment)=64)' - ',amount_with_fee_val INT8 NOT NULL' - ',amount_with_fee_frac INT4 NOT NULL' - ',max_age INT2 NOT NULL' - ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)' - ',reserve_sig BYTEA CHECK (LENGTH(reserve_sig)=64)' - ',noreveal_index INT4 NOT NULL' - ') %s ;' - ,table_name - ,'PARTITION BY HASH (reserve_pub)' - ,partition_suffix - ); - PERFORM comment_partitioned_table( - 'Commitments made when withdrawing coins with age restriction and the gamma value chosen by the exchange.' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'The gamma value chosen by the exchange in the cut-and-choose protocol' - ,'noreveal_index' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'The maximum age (in years) that the client commits to with this request' - ,'max_age' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Commitment made by the client, hash over the various client inputs in the cut-and-choose protocol' - ,'h_commitment' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Reference to the public key of the reserve from which the coins are going to be withdrawn' - ,'reserve_pub' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Signature of the reserve''s private key over the withdraw-age request' - ,'reserve_sig' - ,table_name - ,partition_suffix - ); -END -$$; - - -CREATE FUNCTION constrain_table_withdraw_age_commitments( - IN partition_suffix VARCHAR -) -RETURNS void -LANGUAGE plpgsql -AS $$ -DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_commitments'; -BEGIN - table_name = concat_ws('_', table_name, partition_suffix); - - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || - ' ADD PRIMARY KEY (h_commitment, reserve_pub);' - ); - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || - ' ADD CONSTRAINT ' || table_name || '_withdraw_age_commitment_id_key' - ' UNIQUE (withdraw_age_commitment_id);' - ); -END -$$; - - -CREATE FUNCTION foreign_table_withdraw_age_commitments() -RETURNS void -LANGUAGE plpgsql -AS $$ -DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_commitments'; -BEGIN - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || - ' ADD CONSTRAINT ' || table_name || '_foreign_reserve_pub' - ' FOREIGN KEY (reserve_pub)' - ' REFERENCES reserves (reserve_pub) ON DELETE CASCADE;' - ); -END -$$; - - -INSERT INTO exchange_tables - (name - ,version - ,action - ,partitioned - ,by_range) - VALUES - ('withdraw_age_commitments' - ,'exchange-0003' - ,'create' - ,TRUE - ,FALSE), - ('withdraw_age_commitments' - ,'exchange-0003' - ,'constrain' - ,TRUE - ,FALSE), - ('withdraw_age_commitments' - ,'exchange-0003' - ,'foreign' - ,TRUE - ,FALSE); diff --git a/src/exchangedb/0003-withdraw_age_reveals.sql b/src/exchangedb/0003-withdraw_age_reveals.sql deleted file mode 100644 index af66eab7..00000000 --- a/src/exchangedb/0003-withdraw_age_reveals.sql +++ /dev/null @@ -1,159 +0,0 @@ --- --- This file is part of TALER --- Copyright (C) 2022 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 --- - -CREATE FUNCTION create_table_withdraw_age_revealed_coins( - IN partition_suffix VARCHAR DEFAULT NULL -) -RETURNS VOID -LANGUAGE plpgsql -AS $$ -DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins'; -BEGIN - PERFORM create_partitioned_table( - 'CREATE TABLE %I' - '(withdraw_age_revealed_coins_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE - ',h_commitment BYTEA NOT NULL CHECK (LENGTH(h_commitment)=64)' - ',freshcoin_index INT4 NOT NULL' - ',denominations_serial INT8 NOT NULL' - ',coin_ev BYTEA NOT NULL' - ',h_coin_ev BYTEA CHECK (LENGTH(h_coin_ev)=64)' - ',ev_sig BYTEA NOT NULL' - ',ewv BYTEA NOT NULL' - ') %s ;' - ,table_name - ,'PARTITION BY HASH (h_commitment)' - ,partition_suffix - ); - PERFORM comment_partitioned_table( - 'Reveal of proofs of the correct age restriction after the commitment when withdrawing coins with age restriction' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Foreign key reference to the corresponding commitment' - ,'h_commitment' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Index of the coin in the withdraw-age request, which is implicitly a batch request' - ,'freshcoin_index' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Foreign key reference to the denominations' - ,'denominations_serial' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Envelope of the new coin to be signed' - ,'coin_ev' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Hash of the envelope of the new coin to be signed (for lookups)' - ,'h_coin_ev' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Exchange signature over the envelope' - ,'ev_sig' - ,table_name - ,partition_suffix - ); - PERFORM comment_partitioned_column( - 'Exchange contributed values in the creation of the fresh coin (see /csr)' - ,'ewv' - ,table_name - ,partition_suffix - ); -END -$$; - -CREATE FUNCTION constrain_table_withdraw_age_revealed_coins( - IN partition_suffix VARCHAR -) -RETURNS void -LANGUAGE plpgsql -AS $$ -DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins'; -BEGIN - table_name = concat_ws('_', table_name, partition_suffix); - - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || - ' ADD CONSTRAINT ' || table_name || '_withdraw_age_revealed_coins_id_key' - ' UNIQUE (withdraw_age_revealed_coins_id);' - ); - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || - ' ADD CONSTRAINT ' || table_name || '_freshcoin_index_and_h_commitment_uniqueness' - ' UNIQUE (freshcoin_index, h_commitment);' - ); -END -$$; - -CREATE FUNCTION foreign_table_withdraw_age_revealed_coins() -RETURNS void -LANGUAGE plpgsql -AS $$ -DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins'; -BEGIN - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || - ' ADD CONSTRAINT ' || table_name || '_foreign_h_commitment' - ' FOREIGN KEY (h_commitment)' - ' REFERENCES withdraw_age_commitments (h_commitment) ON DELETE CASCADE;' - ); - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || - ' ADD CONSTRAINT ' || table_name || '_foreign_denominations_serial' - ' FOREIGN KEY (denominations_serial) ' - ' REFERENCES denominations (denominations_serial) ON DELETE CASCADE;' - ); -END -$$; - - -INSERT INTO exchange_tables - (name - ,version - ,action - ,partitioned - ,by_range) - VALUES - ('withdraw_age_revealed_coins' - ,'exchange-0003' - ,'create' - ,TRUE - ,FALSE), - ('withdraw_age_revealed_coins' - ,'exchange-0003' - ,'constrain' - ,TRUE - ,FALSE), - ('withdraw_age_revealed_coins' - ,'exchange-0003' - ,'foreign' - ,TRUE - ,FALSE); diff --git a/src/exchangedb/exchange-0003.sql.in b/src/exchangedb/exchange-0003.sql.in index 5461c0dd..01733ea2 100644 --- a/src/exchangedb/exchange-0003.sql.in +++ b/src/exchangedb/exchange-0003.sql.in @@ -25,6 +25,8 @@ SET search_path TO exchange; #include "0003-aml_status.sql" #include "0003-aml_staff.sql" #include "0003-aml_history.sql" +#include "0003-age_withdraw_commitments.sql" +#include "0003-age_withdraw_reveals.sql" COMMIT; diff --git a/src/exchangedb/pg_get_age_withdraw_info.c b/src/exchangedb/pg_get_age_withdraw_info.c index 754b572c..f4a68b37 100644 --- a/src/exchangedb/pg_get_age_withdraw_info.c +++ b/src/exchangedb/pg_get_age_withdraw_info.c @@ -69,7 +69,7 @@ TEH_PG_get_age_withdraw_info ( ",amount_with_fee_val" ",amount_with_fee_frac" ",noreveal_index" - " FROM withdraw_age_commitments" + " FROM age_withdraw_commitments" " WHERE reserve_pub=$1 and h_commitment=$2;"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_age_withdraw_info", diff --git a/src/exchangedb/pg_insert_age_withdraw_reveal.c b/src/exchangedb/pg_insert_age_withdraw_reveal.c index 336ed384..ebba7ebb 100644 --- a/src/exchangedb/pg_insert_age_withdraw_reveal.c +++ b/src/exchangedb/pg_insert_age_withdraw_reveal.c @@ -42,8 +42,8 @@ TEH_PG_insert_age_withdraw_reveal ( /* TODO */ #if 0 PREPARE (pg, - "insert_withdraw_age_revealed_coin", - "INSERT INTO withdraw_age_reveals " + "insert_age_withdraw_revealed_coin", + "INSERT INTO age_withdraw_reveals " "(h_commitment " ",freshcoin_index " ",denominations_serial " diff --git a/src/exchangedb/pg_insert_records_by_table.c b/src/exchangedb/pg_insert_records_by_table.c index 3ec9c77c..e597f2bf 100644 --- a/src/exchangedb/pg_insert_records_by_table.c +++ b/src/exchangedb/pg_insert_records_by_table.c @@ -2062,39 +2062,39 @@ irbt_cb_table_purse_deletion (struct PostgresClosure *pg, /** - * Function called with withdraw_age_commitments records to insert into table. + * Function called with age_withdraw_commitments records to insert into table. * * @param pg plugin context * @param td record to insert */ static enum GNUNET_DB_QueryStatus -irbt_cb_table_withdraw_age_commitments (struct PostgresClosure *pg, +irbt_cb_table_age_withdraw_commitments (struct PostgresClosure *pg, const struct TALER_EXCHANGEDB_TableData *td) { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&td->serial), GNUNET_PQ_query_param_auto_from_type ( - &td->details.withdraw_age_commitments.h_commitment), + &td->details.age_withdraw_commitments.h_commitment), TALER_PQ_query_param_amount ( - &td->details.withdraw_age_commitments.amount_with_fee), + &td->details.age_withdraw_commitments.amount_with_fee), GNUNET_PQ_query_param_uint16 ( - &td->details.withdraw_age_commitments.max_age), + &td->details.age_withdraw_commitments.max_age), GNUNET_PQ_query_param_auto_from_type ( - &td->details.withdraw_age_commitments.reserve_pub), + &td->details.age_withdraw_commitments.reserve_pub), GNUNET_PQ_query_param_auto_from_type ( - &td->details.withdraw_age_commitments.reserve_sig), + &td->details.age_withdraw_commitments.reserve_sig), GNUNET_PQ_query_param_uint32 ( - &td->details.withdraw_age_commitments.noreveal_index), + &td->details.age_withdraw_commitments.noreveal_index), GNUNET_PQ_query_param_absolute_time ( - &td->details.withdraw_age_commitments.timestamp), + &td->details.age_withdraw_commitments.timestamp), GNUNET_PQ_query_param_end }; PREPARE (pg, - "insert_into_table_withdraw_age_commitments", - "INSERT INTO withdraw_age_commitments" - "(withdraw_age_commitment_id" + "insert_into_table_age_withdraw_commitments", + "INSERT INTO age_withdraw_commitments" + "(age_withdraw_commitment_id" ",h_commitment" ",amount_with_fee_val" ",amount_with_fee_frac" @@ -2106,19 +2106,19 @@ irbt_cb_table_withdraw_age_commitments (struct PostgresClosure *pg, ") VALUES " "($1, $2, $3, $4, $5, $6, $7, $8, $9);"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_into_table_withdraw_age_commitments", + "insert_into_table_age_withdraw_commitments", params); } /** - * Function called with withdraw_age_revealed_coins records to insert into table. + * Function called with age_withdraw_revealed_coins records to insert into table. * * @param pg plugin context * @param td record to insert */ static enum GNUNET_DB_QueryStatus -irbt_cb_table_withdraw_age_revealed_coins (struct PostgresClosure *pg, +irbt_cb_table_age_withdraw_revealed_coins (struct PostgresClosure *pg, const struct TALER_EXCHANGEDB_TableData *td) { @@ -2126,26 +2126,26 @@ irbt_cb_table_withdraw_age_revealed_coins (struct PostgresClosure *pg, struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&td->serial), GNUNET_PQ_query_param_auto_from_type ( - &td->details.withdraw_age_revealed_coins.h_commitment), + &td->details.age_withdraw_revealed_coins.h_commitment), GNUNET_PQ_query_param_uint32 ( - &td->details.withdraw_age_revealed_coins.freshcoin_index), + &td->details.age_withdraw_revealed_coins.freshcoin_index), GNUNET_PQ_query_param_uint64 ( - &td->details.withdraw_age_revealed_coins.denominations_serial), + &td->details.age_withdraw_revealed_coins.denominations_serial), GNUNET_PQ_query_param_fixed_size ( - td->details.withdraw_age_revealed_coins.coin_ev, - td->details.withdraw_age_revealed_coins.coin_ev_size), + td->details.age_withdraw_revealed_coins.coin_ev, + td->details.age_withdraw_revealed_coins.coin_ev_size), GNUNET_PQ_query_param_auto_from_type (&h_coin_ev), TALER_PQ_query_param_blinded_denom_sig ( - &td->details.withdraw_age_revealed_coins.ev_sig), + &td->details.age_withdraw_revealed_coins.ev_sig), TALER_PQ_query_param_exchange_withdraw_values ( - &td->details.withdraw_age_revealed_coins.ewv), + &td->details.age_withdraw_revealed_coins.ewv), GNUNET_PQ_query_param_end }; PREPARE (pg, - "insert_into_table_withdraw_age_revealed_coins", - "INSERT INTO withdraw_age_revealed_coins" - "(withdraw_age_revealed_coins_id" + "insert_into_table_age_withdraw_revealed_coins", + "INSERT INTO age_withdraw_revealed_coins" + "(age_withdraw_revealed_coins_id" ",h_commitment" ",freshcoin_index" ",denominations_serial" @@ -2156,12 +2156,12 @@ irbt_cb_table_withdraw_age_revealed_coins (struct PostgresClosure *pg, ") VALUES " "($1, $2, $3, $4, $5, $6, $7, $8);"); - GNUNET_CRYPTO_hash (td->details.withdraw_age_revealed_coins.coin_ev, - td->details.withdraw_age_revealed_coins.coin_ev_size, + GNUNET_CRYPTO_hash (td->details.age_withdraw_revealed_coins.coin_ev, + td->details.age_withdraw_revealed_coins.coin_ev_size, &h_coin_ev); return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_into_table_withdraw_age_revealed_coins", + "insert_into_table_age_withdraw_revealed_coins", params); } @@ -2314,10 +2314,10 @@ TEH_PG_insert_records_by_table (void *cls, rh = &irbt_cb_table_purse_deletion; break; case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS: - rh = &irbt_cb_table_withdraw_age_commitments; + rh = &irbt_cb_table_age_withdraw_commitments; break; case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS: - rh = &irbt_cb_table_withdraw_age_revealed_coins; + rh = &irbt_cb_table_age_withdraw_revealed_coins; break; } if (NULL == rh) diff --git a/src/exchangedb/pg_lookup_records_by_table.c b/src/exchangedb/pg_lookup_records_by_table.c index 2e157360..efa0fec5 100644 --- a/src/exchangedb/pg_lookup_records_by_table.c +++ b/src/exchangedb/pg_lookup_records_by_table.c @@ -2767,14 +2767,14 @@ lrbt_cb_table_purse_deletion (void *cls, /** - * Function called with withdraw_age_commitments table entries. + * Function called with age_withdraw_commitments table entries. * * @param cls closure * @param result the postgres result * @param num_results the number of results in @a result */ static void -lrbt_cb_table_withdraw_age_commitments (void *cls, +lrbt_cb_table_age_withdraw_commitments (void *cls, PGresult *result, unsigned int num_results) { @@ -2788,26 +2788,26 @@ lrbt_cb_table_withdraw_age_commitments (void *cls, { struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_uint64 ( - "withdraw_age_commitment_id", + "age_withdraw_commitment_id", &td.serial), GNUNET_PQ_result_spec_auto_from_type ( "h_commitment", - &td.details.withdraw_age_commitments.h_commitment), + &td.details.age_withdraw_commitments.h_commitment), GNUNET_PQ_result_spec_uint16 ( "max_age", - &td.details.withdraw_age_commitments.max_age), + &td.details.age_withdraw_commitments.max_age), TALER_PQ_RESULT_SPEC_AMOUNT ( "amount_with_fee", - &td.details.withdraw_age_commitments.amount_with_fee), + &td.details.age_withdraw_commitments.amount_with_fee), GNUNET_PQ_result_spec_auto_from_type ( "reserve_pub", - &td.details.withdraw_age_commitments.reserve_pub), + &td.details.age_withdraw_commitments.reserve_pub), GNUNET_PQ_result_spec_auto_from_type ( "reserve_sig", - &td.details.withdraw_age_commitments.reserve_sig), + &td.details.age_withdraw_commitments.reserve_sig), GNUNET_PQ_result_spec_uint32 ( "noreveal_index", - &td.details.withdraw_age_commitments.noreveal_index), + &td.details.age_withdraw_commitments.noreveal_index), GNUNET_PQ_result_spec_end }; @@ -2828,14 +2828,14 @@ lrbt_cb_table_withdraw_age_commitments (void *cls, /** - * Function called with withdraw_age_revealed_coins table entries. + * Function called with age_withdraw_revealed_coins table entries. * * @param cls closure * @param result the postgres result * @param num_results the number of results in @a result */ static void -lrbt_cb_table_withdraw_age_revealed_coins (void *cls, +lrbt_cb_table_age_withdraw_revealed_coins (void *cls, PGresult *result, unsigned int num_results) { @@ -2848,22 +2848,22 @@ lrbt_cb_table_withdraw_age_revealed_coins (void *cls, { struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_uint64 ( - "withdraw_age_revealed_coins_id", + "age_withdraw_revealed_coins_id", &td.serial), GNUNET_PQ_result_spec_auto_from_type ( "h_commitment", - &td.details.withdraw_age_revealed_coins.h_commitment), + &td.details.age_withdraw_revealed_coins.h_commitment), GNUNET_PQ_result_spec_uint32 ( "freshcoin_index", - &td.details.withdraw_age_revealed_coins.freshcoin_index), + &td.details.age_withdraw_revealed_coins.freshcoin_index), GNUNET_PQ_result_spec_uint64 ( "denominations_serial", - &td.details.withdraw_age_revealed_coins.denominations_serial), + &td.details.age_withdraw_revealed_coins.denominations_serial), /* Note: h_coin_ev is recalculated */ GNUNET_PQ_result_spec_variable_size ( "coin_ev", - (void **) &td.details.withdraw_age_revealed_coins.coin_ev, - &td.details.withdraw_age_revealed_coins.coin_ev_size), + (void **) &td.details.age_withdraw_revealed_coins.coin_ev, + &td.details.age_withdraw_revealed_coins.coin_ev_size), TALER_PQ_result_spec_blinded_denom_sig ( "ev_sig", &td.details.refresh_revealed_coins.ev_sig), @@ -3598,9 +3598,9 @@ TEH_PG_lookup_records_by_table (void *cls, rh = &lrbt_cb_table_purse_deletion; break; case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS: - XPREPARE ("select_above_serial_by_table_withdraw_age_commitments", + XPREPARE ("select_above_serial_by_table_age_withdraw_commitments", "SELECT" - " withdraw_age_commitment_id" + " age_withdraw_commitment_id" ",h_commitment" ",amount_with_fee_val" ",amount_with_fee_frac" @@ -3608,15 +3608,15 @@ TEH_PG_lookup_records_by_table (void *cls, ",reserve_pub" ",reserve_sig" ",noreveal_index" - " FROM withdraw_age_commitments" - " WHERE withdraw_age_commitment_id > $1" - " ORDER BY withdraw_age_commitment_id ASC;"); - rh = &lrbt_cb_table_withdraw_age_commitments; + " FROM age_withdraw_commitments" + " WHERE age_withdraw_commitment_id > $1" + " ORDER BY age_withdraw_commitment_id ASC;"); + rh = &lrbt_cb_table_age_withdraw_commitments; break; case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS: - XPREPARE ("select_above_serial_by_table_withdraw_age_revealed_coins", + XPREPARE ("select_above_serial_by_table_age_withdraw_revealed_coins", "SELECT" - " withdraw_age_revealed_coins_serial_id" + " age_withdraw_revealed_coins_serial_id" ",h_commitment" ",freshcoin_index" ",denominations_serial" @@ -3624,10 +3624,10 @@ TEH_PG_lookup_records_by_table (void *cls, ",h_coin_ev" ",ev_sig" ",ewv" - " FROM withdraw_age_revealed_coins" - " WHERE withdraw_age_revealed_coins_serial_id > $1" - " ORDER BY withdraw_age_revealed_coins_serial_id ASC;"); - rh = &lrbt_cb_table_withdraw_age_revealed_coins; + " FROM age_withdraw_revealed_coins" + " WHERE age_withdraw_revealed_coins_serial_id > $1" + " ORDER BY age_withdraw_revealed_coins_serial_id ASC;"); + rh = &lrbt_cb_table_age_withdraw_revealed_coins; break; } if (NULL == rh) diff --git a/src/exchangedb/pg_lookup_serial_by_table.c b/src/exchangedb/pg_lookup_serial_by_table.c index c98b4539..2e3b4130 100644 --- a/src/exchangedb/pg_lookup_serial_by_table.c +++ b/src/exchangedb/pg_lookup_serial_by_table.c @@ -427,22 +427,22 @@ TEH_PG_lookup_serial_by_table (void *cls, statement = "select_serial_by_table_purse_deletion"; break; case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS: - XPREPARE ("select_serial_by_table_withdraw_age_commitments", + XPREPARE ("select_serial_by_table_age_withdraw_commitments", "SELECT" - " withdraw_age_commitment_id AS serial" - " FROM withdraw_age_commitments" - " ORDER BY withdraw_age_commitment_id DESC" + " age_withdraw_commitment_id AS serial" + " FROM age_withdraw_commitments" + " ORDER BY age_withdraw_commitment_id DESC" " LIMIT 1;"); - statement = "select_serial_by_table_withdraw_age_commitments"; + statement = "select_serial_by_table_age_withdraw_commitments"; break; case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS: - XPREPARE ("select_serial_by_table_withdraw_age_revealed_coins", + XPREPARE ("select_serial_by_table_age_withdraw_revealed_coins", "SELECT" - " withdraw_age_revealed_coins_id AS serial" - " FROM withdraw_age_revealed_coins" - " ORDER BY withdraw_age_revealed_coins_id DESC" + " age_withdraw_revealed_coins_id AS serial" + " FROM age_withdraw_revealed_coins" + " ORDER BY age_withdraw_revealed_coins_id DESC" " LIMIT 1;"); - statement = "select_serial_by_table_withdraw_age_revealed_coins"; + statement = "select_serial_by_table_age_withdraw_revealed_coins"; break; } if (NULL == statement) diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 43f6b73e..e4c9a28b 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -760,7 +760,7 @@ struct TALER_EXCHANGEDB_TableData struct TALER_ReserveSignatureP reserve_sig; uint32_t noreveal_index; struct GNUNET_TIME_Absolute timestamp; - } withdraw_age_commitments; + } age_withdraw_commitments; struct { @@ -772,7 +772,7 @@ struct TALER_EXCHANGEDB_TableData struct TALER_ExchangeWithdrawValues ewv; // h_coin_ev omitted, to be recomputed! struct TALER_BlindedDenominationSignature ev_sig; - } withdraw_age_revealed_coins; + } age_withdraw_revealed_coins; } details; @@ -1200,8 +1200,9 @@ struct TALER_EXCHANGEDB_AgeWithdrawCommitment struct TALER_ReservePublicKeyP reserve_pub; /** - * Signature confirming the age withdrawal, matching @e reserve_pub, @e - * maximum_age_group and @e h_commitment and @e total_amount_with_fee. + * Signature confirming the age withdrawal commitment, matching @e + * reserve_pub, @e maximum_age_group and @e h_commitment and @e + * total_amount_with_fee. */ struct TALER_ReserveSignatureP reserve_sig; @@ -2737,6 +2738,28 @@ struct TALER_EXCHANGEDB_CsRevealFreshCoinData uint32_t coin_off; }; +/** + * Information about a coin that was revealed to the exchange + * during reveal. + */ +struct TALER_EXCHANGEDB_AgeWithdrawRevealedCoin +{ + /** + * Hash of the public denomination key of the coin. + */ + struct TALER_DenominationHashP h_denom_pub; + + /** + * Signature generated by the exchange over the coin (in blinded format). + */ + struct TALER_BlindedDenominationSignature coin_sig; + + /** + * Blinded hash of the new coin + */ + struct TALER_BlindedCoinHashP h_coin_ev; +}; + /** * Generic KYC status for some operation. @@ -3810,19 +3833,18 @@ struct TALER_EXCHANGEDB_Plugin * age restriction enabled in a given age-withdraw operation and the relevant * information we learned or created in the reveal steop * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param h_commitment The hash of the original age-withdraw commitment, which is a key into the withdraw_age_commitments table - * @param num_coins number of coins to generate, size of the @a coin_evs array - * TODO: oec + * @param cls The `struct PostgresClosure` with the plugin-specific state + * @param h_commitment The hash of the original age-withdraw commitment, which is a key into the age_withdraw_commitments table + * @param num_awrcs Number of coins to generate, size of the @a coin_evs array + * @param awrcs Array of @a num_awrcs information about coins to be created * @return query execution status */ enum GNUNET_DB_QueryStatus (*insert_age_withdraw_reveal)( void *cls, - uint64_t h_commitment, - uint32_t num_coins - /* TODO: oec */ - ); + const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + uint32_t num_awrcs, + const struct TALER_EXCHANGEDB_AgeWithdrawRevealedCoin *awrcs); /** * Lookup in the database for the fresh coins with age-restriction that -- cgit v1.2.3 From 84bde679a78e8a681ded484bec8d256e07bf77e6 Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Mon, 1 May 2023 20:19:51 +0200 Subject: -typos --- src/exchange/taler-exchange-httpd_age-withdraw_reveal.c | 2 +- src/exchangedb/pg_insert_records_by_table.c | 2 -- src/include/taler_exchangedb_plugin.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'src/include') diff --git a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c index 67e5facd..776c0d8d 100644 --- a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c +++ b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c @@ -966,7 +966,7 @@ sign_and_finalize_age_withdraw ( num_coins, awrcs); cleanup: - GNUNET_break (MHD_NO != ret); + GNUNET_break (GNUNET_OK != ret); /* Free resources */ for (unsigned int i = 0; idetails.age_withdraw_revealed_coins.ev_sig), - TALER_PQ_query_param_exchange_withdraw_values ( - &td->details.age_withdraw_revealed_coins.ewv), GNUNET_PQ_query_param_end }; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index e4c9a28b..7c175764 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -769,7 +769,6 @@ struct TALER_EXCHANGEDB_TableData uint64_t denominations_serial; void *coin_ev; size_t coin_ev_size; - struct TALER_ExchangeWithdrawValues ewv; // h_coin_ev omitted, to be recomputed! struct TALER_BlindedDenominationSignature ev_sig; } age_withdraw_revealed_coins; -- cgit v1.2.3 From 75f75c4a51c4700da9bde18cc9a9b5d9df1e8457 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 30 Apr 2023 16:21:07 +0200 Subject: breaking protocol changes towards fixing #7810 (incomplete, taler-exchange-offline still unfinished) --- contrib/gana | 2 +- src/auditor/taler-helper-auditor-wire.c | 8 +- src/bank-lib/bank_api_credit.c | 4 +- src/bank-lib/bank_api_debit.c | 4 +- src/bank-lib/taler-exchange-wire-gateway-client.c | 8 +- src/exchange-tools/taler-auditor-offline.c | 23 +- src/exchange-tools/taler-exchange-offline.c | 92 ++- src/exchange/taler-exchange-httpd_config.h | 2 +- .../taler-exchange-httpd_management_wire_disable.c | 5 +- .../taler-exchange-httpd_management_wire_enable.c | 46 +- src/exchange/taler-exchange-httpd_wire.c | 17 +- src/exchange/taler-exchange-wirewatch.c | 4 +- src/exchangedb/.gitignore | 3 +- src/exchangedb/0004-wire_accounts.sql | 26 + src/exchangedb/Makefile.am | 13 +- src/exchangedb/drop.sql | 1 + src/exchangedb/exchange-0004.sql.in | 24 + src/exchangedb/pg_get_wire_accounts.c | 32 +- src/exchangedb/pg_insert_wire.c | 15 +- src/exchangedb/pg_insert_wire.h | 6 + src/exchangedb/pg_update_wire.c | 20 +- src/exchangedb/pg_update_wire.h | 8 + src/include/taler_bank_service.h | 6 +- src/include/taler_crypto_lib.h | 24 + src/include/taler_exchange_service.h | 666 ++++++++++++++++++--- src/include/taler_exchangedb_plugin.h | 18 + src/include/taler_json_lib.h | 27 - src/include/taler_testing_lib.h | 8 +- src/json/Makefile.am | 16 +- src/json/json_wire.c | 74 --- src/json/test_json_wire.c | 80 --- src/lib/exchange_api_batch_deposit.c | 12 +- src/lib/exchange_api_batch_withdraw.c | 37 +- src/lib/exchange_api_batch_withdraw2.c | 68 +-- src/lib/exchange_api_contracts_get.c | 8 +- src/lib/exchange_api_csr_melt.c | 4 +- src/lib/exchange_api_csr_withdraw.c | 2 +- src/lib/exchange_api_deposit.c | 8 +- src/lib/exchange_api_deposits_get.c | 22 +- src/lib/exchange_api_handle.c | 88 ++- src/lib/exchange_api_kyc_check.c | 20 +- src/lib/exchange_api_link.c | 4 +- src/lib/exchange_api_lookup_aml_decision.c | 12 +- src/lib/exchange_api_lookup_aml_decisions.c | 6 +- src/lib/exchange_api_management_drain_profits.c | 28 +- src/lib/exchange_api_management_get_keys.c | 78 ++- src/lib/exchange_api_management_post_extensions.c | 22 +- src/lib/exchange_api_management_post_keys.c | 26 +- ...change_api_management_revoke_denomination_key.c | 22 +- .../exchange_api_management_revoke_signing_key.c | 22 +- .../exchange_api_management_update_aml_officer.c | 26 +- src/lib/exchange_api_management_wire_disable.c | 30 +- src/lib/exchange_api_management_wire_enable.c | 38 +- src/lib/exchange_api_melt.c | 10 +- src/lib/exchange_api_purse_deposit.c | 16 +- src/lib/exchange_api_purse_merge.c | 14 +- src/lib/exchange_api_purses_get.c | 14 +- src/lib/exchange_api_recoup.c | 69 +-- src/lib/exchange_api_recoup_refresh.c | 67 +-- src/lib/exchange_api_refreshes_reveal.c | 4 +- src/lib/exchange_api_refund.c | 75 +-- src/lib/exchange_api_transfers_get.c | 103 ++-- src/lib/exchange_api_wire.c | 383 +++++++----- src/lib/exchange_api_withdraw.c | 28 +- src/lib/exchange_api_withdraw2.c | 69 +-- src/testing/testing_api_cmd_bank_history_credit.c | 4 +- src/testing/testing_api_cmd_bank_history_debit.c | 4 +- src/testing/testing_api_cmd_batch_deposit.c | 10 +- src/testing/testing_api_cmd_batch_withdraw.c | 2 +- src/testing/testing_api_cmd_check_aml_decision.c | 4 +- src/testing/testing_api_cmd_contract_get.c | 10 +- src/testing/testing_api_cmd_deposit.c | 6 +- src/testing/testing_api_cmd_deposits_get.c | 4 +- .../testing_api_cmd_nexus_fetch_transactions.c | 1 + src/testing/testing_api_cmd_purse_create_deposit.c | 4 +- src/testing/testing_api_cmd_purse_deposit.c | 10 +- src/testing/testing_api_cmd_purse_get.c | 4 +- src/testing/testing_api_cmd_recoup.c | 17 +- src/testing/testing_api_cmd_recoup_refresh.c | 9 +- src/testing/testing_api_cmd_refresh.c | 34 +- src/testing/testing_api_cmd_refund.c | 13 +- src/testing/testing_api_cmd_revoke_denom_key.c | 5 +- src/testing/testing_api_cmd_revoke_sign_key.c | 7 +- src/testing/testing_api_cmd_set_officer.c | 6 +- src/testing/testing_api_cmd_transfer_get.c | 223 +++---- src/testing/testing_api_cmd_wire.c | 75 ++- src/testing/testing_api_cmd_wire_add.c | 22 +- src/testing/testing_api_cmd_wire_del.c | 7 +- src/testing/testing_api_cmd_withdraw.c | 8 +- src/testing/testing_api_loop.c | 57 +- src/util/offline_signatures.c | 78 ++- 91 files changed, 2058 insertions(+), 1283 deletions(-) create mode 100644 src/exchangedb/0004-wire_accounts.sql create mode 100644 src/exchangedb/exchange-0004.sql.in delete mode 100644 src/json/test_json_wire.c (limited to 'src/include') diff --git a/contrib/gana b/contrib/gana index bd4e73b2..5cfe18c5 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit bd4e73b2ed06269fdee42eaad21acb5be8be9302 +Subproject commit 5cfe18c5bbfd404a5f7cf27a78577c881ddb9ebd diff --git a/src/auditor/taler-helper-auditor-wire.c b/src/auditor/taler-helper-auditor-wire.c index e3e3764a..8615c439 100644 --- 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; idetails.success.details_length; i++) + for (unsigned int i = 0; idetails.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; idetails.success.details_length; i++) + for (unsigned int i = 0; idetails.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 index 4842de96..14ddcd72 100644 --- 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 index bd9b1194..e40156ce 100644 --- 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 index 5bfd9311..a972bcfd 100644 --- 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; idetails.success.details_length; i++) + for (unsigned int i = 0; idetails.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; idetails.success.details_length; i++) + for (unsigned int i = 0; idetails.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 index 53135d9f..f239c11a 100644 --- 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 index 660864b7..ec48ec83 100644 --- 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 index 7763cdeb..95380e0a 100644 --- 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 index 34825eda..077a56b2 100644 --- 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 index 25ee0eea..6743b485 100644 --- 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 @@ -54,6 +54,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. */ @@ -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 index 34010462..17875a72 100644 --- 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 index 235c0153..04704242 100644 --- 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 index fa833d81..6e67fadb 100644 --- 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 new file mode 100644 index 00000000..6114c821 --- /dev/null +++ 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 +-- + +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 index de76997c..ee78b87f 100644 --- 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 index ecebde6f..843cda8e 100644 --- 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 new file mode 100644 index 00000000..00979e19 --- /dev/null +++ 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 +-- + +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 index 43590acf..23b93904 100644 --- 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 index 75323b6f..8329a04a 100644 --- 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 index 670928d7..c949327d 100644 --- 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 index 4059348c..0c4ec7b5 100644 --- 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 index 67038b58..360b8845 100644 --- 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 index b5d4dcce..5ce5e254 100644 --- 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 index 61d92483..16644076 100644 --- 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 index 4099d6bb..f9330ec5 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -461,22 +461,53 @@ 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 { @@ -743,6 +774,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. */ @@ -753,38 +873,104 @@ 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. @@ -2430,19 +2644,46 @@ TALER_EXCHANGE_batch_withdraw_cancel ( struct TALER_EXCHANGE_BatchWithdrawHandle *wh); +/** + * 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); /** @@ -2492,21 +2733,53 @@ void 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; @@ -3059,19 +3332,44 @@ 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 @@ -3315,6 +3613,37 @@ TALER_EXCHANGE_free_reserve_history ( 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 @@ -3322,14 +3651,12 @@ struct TALER_EXCHANGE_RecoupHandle; * 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); /** @@ -3377,19 +3704,48 @@ TALER_EXCHANGE_recoup_cancel (struct TALER_EXCHANGE_RecoupHandle *ph); 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. @@ -3898,19 +4254,48 @@ 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); /** @@ -4012,16 +4397,29 @@ 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. @@ -4118,6 +4530,19 @@ TALER_EXCHANGE_management_post_extensions_cancel ( struct TALER_EXCHANGE_ManagementPostExtensionsHandle *ph); +/** + * 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. * @@ -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); /** @@ -4175,6 +4600,19 @@ TALER_EXCHANGE_management_drain_profits_cancel ( struct TALER_EXCHANGE_ManagementDrainProfitsHandle *dp); +/** + * 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. * @@ -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); /** @@ -4224,6 +4662,18 @@ TALER_EXCHANGE_management_revoke_denomination_key_cancel ( struct TALER_EXCHANGE_ManagementRevokeDenominationKeyHandle *rh); +/** + * 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. * @@ -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); /** @@ -4273,6 +4723,18 @@ TALER_EXCHANGE_management_revoke_signing_key_cancel ( struct TALER_EXCHANGE_ManagementRevokeSigningKeyHandle *rh); +/** + * 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, @@ -4832,16 +5298,28 @@ TALER_EXCHANGE_management_disable_auditor_cancel ( struct TALER_EXCHANGE_ManagementAuditorDisableHandle *ah); +/** + * 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, @@ -4887,16 +5371,27 @@ TALER_EXCHANGE_management_enable_wire_cancel ( struct TALER_EXCHANGE_ManagementWireEnableHandle *wh); +/** + * 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 index 7c175764..d025b532 100644 --- 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 index 7f17df03..d0749808 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -674,33 +674,6 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s, struct TALER_MerchantWireHashP *hc); -/** - * 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 diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 5fc930a8..664db6cc 100644 --- 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 index 2f5ec3f1..6bd5b464 100644 --- 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 index 544b5645..9d22d28e 100644 --- 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 deleted file mode 100644 index b417b25f..00000000 --- a/src/json/test_json_wire.c +++ /dev/null @@ -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 -*/ - -/** - * @file json/test_json_wire.c - * @brief Tests for Taler-specific crypto logic - * @author Christian Grothoff - */ -#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 index 4665908d..c583d5ad 100644 --- 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 index 9bb158f8..4817ae40 100644 --- 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; inum_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 index e14ed92f..04c2c010 100644 --- 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; inum_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 index 263a0cbe..8fd4ba1e 100644 --- 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 index 9de8cd8d..67b1a9b7 100644 --- 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; iexchange_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 index 2e8a5e5e..bd5f2f65 100644 --- 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 index 8501ed11..f6a5e979 100644 --- 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; ikeys_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 index 2f03730a..d1580e76 100644 --- 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 index 9e8625ed..3b998f23 100644 --- 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 index 897a21f1..fc1a8a8e 100644 --- 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 index f8a1d7fa..403acb54 100644 --- 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 index 9cf1af85..bc7232b8 100644 --- 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 index 80c47144..c649f397 100644 --- 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; inum_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; inum_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; inum_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 index abec4ef0..b9721a98 100644 --- 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 index 291c0ac0..a46124d9 100644 --- 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 index 8d65b645..aa4d527a 100644 --- 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 index aac27678..c4d63424 100644 --- 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 index 6e166946..0033a130 100644 --- 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 index 5d97eef7..30a01076 100644 --- 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 index 55480474..23a98b15 100644 --- 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 index feeef400..3a8144a3 100644 --- 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 index f5a503b0..f88d2329 100644 --- 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 index fd11978d..6e1995e0 100644 --- 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 index 5d63ecf1..4c2fdd79 100644 --- 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 index 8de4da12..b89bda8b 100644 --- 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 index 00eeca07..7b42aa7e 100644 --- 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 index cd2a1d1f..3bdef202 100644 --- 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 index 855b4fcc..7c9616ea 100644 --- 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 index 06465618..c2a1c0b1 100644 --- 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; idetails_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 index c23ea62d..49826528 100644 --- 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; inext; + 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; icredit_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,61 +349,70 @@ 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; ipayto_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, @@ -337,80 +420,104 @@ 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; } - 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 index 62c04203..2a3c095a 100644 --- 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 index 04881804..bf2bd023 100644 --- 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 index 9a61d6d5..119c5d86 100644 --- 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; idetails.success.details_length; i++) + for (unsigned int i = 0; idetails.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 index 33b212ad..fd1e8199 100644 --- 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; idetails.success.details_length; i++) + for (unsigned int i = 0; idetails.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 index 54a20cdb..d3275875 100644 --- 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 index a5229ae9..2aa549c0 100644 --- 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 index d77e9b6b..dd317142 100644 --- 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; idetails.success.aml_history_length; i++) + for (unsigned int i = 0; idetails.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 index 428bf7e8..d599cb59 100644 --- 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 index 16ac139f..1b097a34 100644 --- 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 index 8fd4e813..8f797089 100644 --- 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 index 15264796..ff1497f3 100644 --- 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 index 200127b7..6fa7d91f 100644 --- 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 index ff8e6d2e..aaf6ff6b 100644 --- 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 index 3e7da38f..60638752 100644 --- 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 index ed8c7eed..e11475f2 100644 --- 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 index 6081a4ba..ff7dab00 100644 --- 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 index 2aad77ce..a8e2e8f3 100644 --- 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; inum_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; idetails.success.num_coins; i++) - for (unsigned int j = i + 1; jdetails.success.num_coins; j++) + for (unsigned int i = 0; idetails.ok.num_coins; i++) + for (unsigned int j = i + 1; jdetails.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; idetails.success.num_coins; i++) + for (unsigned int i = 0; idetails.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; jdetails.success.num_coins; j++) + for (unsigned int j = 0; jdetails.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 index 4be3605a..d41700d1 100644 --- 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 index 7c77c356..8afd4f20 100644 --- 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 index 9745d728..3b869312 100644 --- 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 index 0e6de262..1c0495f3 100644 --- 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 index 3c467e6d..cb6bb7df 100644 --- 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 index 6e44403b..5fbd41b1 100644 --- 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; imethod_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; iexpected_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 index c07e9bba..c36f03b1 100644 --- 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 index 15d29d72..89fb8395 100644 --- 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 index 1bd3c187..8d53f4d0 100644 --- 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 index 1865a112..3ac9bea2 100644 --- 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 index b1e3b93a..15dda8b3 100644 --- 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); -- cgit v1.2.3 From faca037018820ba3c21724c7f6ab41a72206e4ff Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 30 Apr 2023 23:37:01 +0200 Subject: expose TALER_EXCHANGE_parse_accounts() in external API --- contrib/gana | 2 +- src/include/taler_exchange_service.h | 27 +++++ src/lib/exchange_api_common.c | 192 ++++++++++++++++++++++++++++++++ src/lib/exchange_api_wire.c | 208 ++--------------------------------- 4 files changed, 232 insertions(+), 197 deletions(-) (limited to 'src/include') diff --git a/contrib/gana b/contrib/gana index 5cfe18c5..d831c7f7 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 5cfe18c5bbfd404a5f7cf27a78577c881ddb9ebd +Subproject commit d831c7f72a5030e20efb4ada7babc103ccd01fab diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index f9330ec5..fc5fb284 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -909,6 +909,33 @@ struct TALER_EXCHANGE_WireAccount }; +/** + * Parse array of @a accounts of the exchange into @a was. + * + * @param master_pub master public key of the exchange, NULL to not verify signatures + * @param accounts array of accounts to parse + * @param[out] was where to write the result (already allocated) + * @param was_length length of the @a was array, must match the length of @a accounts + * @return #GNUNET_OK if parsing @a accounts succeeded + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_parse_accounts (const struct TALER_MasterPublicKeyP *master_pub, + const json_t *accounts, + struct TALER_EXCHANGE_WireAccount was[], + unsigned int was_length); + + +/** + * Free data within @a was, but not @a was itself. + * + * @param was array of wire account data + * @param was_len length of the @a was array + */ +void +TALER_EXCHANGE_free_accounts (struct TALER_EXCHANGE_WireAccount *was, + unsigned int was_len); + + /** * Response to a /wire request. */ diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index b895bf9a..285a5292 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -2194,4 +2194,196 @@ TALER_EXCHANGE_verify_deposit_signature_ ( } +/** + * 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 GNUNET_OK; +fail: + GNUNET_free (*resta); + *resta_len = 0; + return GNUNET_SYSERR; +} + + +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_parse_accounts (const struct TALER_MasterPublicKeyP *master_pub, + const json_t *accounts, + struct TALER_EXCHANGE_WireAccount was[], + unsigned int was_length) +{ + memset (was, + 0, + sizeof (struct TALER_EXCHANGE_WireAccount) * was_length); + GNUNET_assert (was_length == + json_array_size (accounts)); + for (unsigned int i = 0; + ipayto_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 () + }; + json_t *account; + + account = json_array_get (accounts, + i); + if (GNUNET_OK != + GNUNET_JSON_parse (account, + spec_account, + NULL, NULL)) + { + /* bogus reply */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + char *err; + + err = TALER_payto_validate (wa->payto_uri); + if (NULL != err) + { + GNUNET_break_op (0); + GNUNET_free (err); + return GNUNET_SYSERR; + } + } + + if ( (NULL != master_pub) && + (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); + return GNUNET_SYSERR; + } + 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); + return GNUNET_SYSERR; + } + GNUNET_JSON_parse_free (spec_account); + } /* end 'for all accounts */ + return GNUNET_OK; +} + + +void +TALER_EXCHANGE_free_accounts (struct TALER_EXCHANGE_WireAccount *was, + unsigned int was_len) +{ + for (unsigned int i = 0; icredit_restrictions); + GNUNET_free (wa->debit_restrictions); + } +} + + /* end of exchange_api_common.c */ diff --git a/src/lib/exchange_api_wire.c b/src/lib/exchange_api_wire.c index 49826528..f38ca86b 100644 --- a/src/lib/exchange_api_wire.c +++ b/src/lib/exchange_api_wire.c @@ -173,114 +173,6 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, } -/** - * 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 GNUNET_OK; -fail: - GNUNET_free (*resta); - *resta_len = 0; - return GNUNET_SYSERR; -} - - -/** - * Free data within @a was, but not @a was itself. - * - * @param was array of wire account data - * @param was_len length of the @a was array - */ -static void -free_accounts (struct TALER_EXCHANGE_WireAccount *was, - unsigned int was_len) -{ - for (unsigned int i = 0; icredit_restrictions); - GNUNET_free (wa->debit_restrictions); - } -} - - /** * Function called when we're done processing the * HTTP /wire request. @@ -383,101 +275,25 @@ handle_wire_finished (void *cls, { 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; - ipayto_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 () - }; - json_t *account; - - account = json_array_get (accounts, - i); - if (GNUNET_OK != - GNUNET_JSON_parse (account, - spec_account, - NULL, NULL)) - { - /* bogus reply */ - GNUNET_break_op (0); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - { - 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); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID; - break; - } - 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); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - GNUNET_JSON_parse_free (spec_account); - } /* end 'for all accounts */ - if ( (0 != wr.hr.http_status) && - (NULL != wh->cb) ) + GNUNET_break_op (0); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + } + else if (NULL != wh->cb) { wh->cb (wh->cb_cls, &wr); wh->cb = NULL; } - free_accounts (was, - wr.details.ok.accounts_len); + TALER_EXCHANGE_free_accounts (was, + wr.details.ok.accounts_len); } /* end of 'parse accounts */ free_fees (fbm, wr.details.ok.fees_len); -- cgit v1.2.3 From 4c1a2c030761fc64773d035df6cdd01db0204d13 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 4 May 2023 14:42:06 +0200 Subject: more shared logic for argument/header parsing --- src/exchange/taler-exchange-httpd_deposits_get.c | 158 +++++++++++-------- src/exchange/taler-exchange-httpd_kyc-check.c | 30 +--- src/exchange/taler-exchange-httpd_kyc-proof.c | 27 +--- src/exchange/taler-exchange-httpd_purses_delete.c | 26 +--- src/exchange/taler-exchange-httpd_purses_get.c | 32 +--- src/exchange/taler-exchange-httpd_reserves_get.c | 33 +--- src/include/taler_mhd_lib.h | 182 +++++++++++++++++++++- src/mhd/mhd_parsing.c | 112 +++++++++++-- 8 files changed, 380 insertions(+), 220 deletions(-) (limited to 'src/include') diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c index ebbb13e0..26c9e261 100644 --- a/src/exchange/taler-exchange-httpd_deposits_get.c +++ b/src/exchange/taler-exchange-httpd_deposits_get.c @@ -64,6 +64,12 @@ struct DepositWtidContext */ struct TALER_WireTransferIdentifierRawP wtid; + /** + * Signature by the merchant. + */ + struct TALER_MerchantSignatureP merchant_sig; + + /** * Set by #handle_wtid data to the coin's contribution to the wire transfer. */ @@ -275,89 +281,103 @@ handle_track_transaction_request ( } +/** + * Function called to clean up a context. + * + * @param rc request context with data to clean up + */ +static void +dwc_cleaner (struct TEH_RequestContext *rc) +{ + struct DepositWtidContext *ctx = rc->rh_ctx; + + GNUNET_free (ctx); +} + + MHD_RESULT TEH_handler_deposits_get (struct TEH_RequestContext *rc, const char *const args[4]) { - enum GNUNET_GenericReturnValue res; - struct TALER_MerchantSignatureP merchant_sig; - struct DepositWtidContext ctx; + struct DepositWtidContext *ctx = rc->rh_ctx; - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (args[0], - strlen (args[0]), - &ctx.h_wire, - sizeof (ctx.h_wire))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_WIRE, - args[0]); - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (args[1], - strlen (args[1]), - &ctx.merchant, - sizeof (ctx.merchant))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_MERCHANT_PUB, - args[1]); - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (args[2], - strlen (args[2]), - &ctx.h_contract_terms, - sizeof (ctx.h_contract_terms))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_CONTRACT_TERMS, - args[2]); - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (args[3], - strlen (args[3]), - &ctx.coin_pub, - sizeof (ctx.coin_pub))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_COIN_PUB, - args[3]); - } - res = TALER_MHD_parse_request_arg_data (rc->connection, - "merchant_sig", - &merchant_sig, - sizeof (merchant_sig)); - if (GNUNET_SYSERR == res) - return MHD_NO; /* internal error */ - if (GNUNET_NO == res) - return MHD_YES; /* parse error */ - TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + if (NULL == ctx) { + ctx = GNUNET_new (struct DepositWtidContext); + rc->rh_ctx = ctx; + rc->rh_cleaner = &dwc_cleaner; + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (args[0], + strlen (args[0]), + &ctx->h_wire, + sizeof (ctx->h_wire))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_WIRE, + args[0]); + } + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (args[1], + strlen (args[1]), + &ctx->merchant, + sizeof (ctx->merchant))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_MERCHANT_PUB, + args[1]); + } if (GNUNET_OK != - TALER_merchant_deposit_verify (&ctx.merchant, - &ctx.coin_pub, - &ctx.h_contract_terms, - &ctx.h_wire, - &merchant_sig)) + GNUNET_STRINGS_string_to_data (args[2], + strlen (args[2]), + &ctx->h_contract_terms, + sizeof (ctx->h_contract_terms))) { GNUNET_break_op (0); return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_EXCHANGE_DEPOSITS_GET_MERCHANT_SIGNATURE_INVALID, - NULL); + MHD_HTTP_BAD_REQUEST, + TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_CONTRACT_TERMS, + args[2]); + } + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (args[3], + strlen (args[3]), + &ctx->coin_pub, + sizeof (ctx->coin_pub))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_COIN_PUB, + args[3]); + } + TALER_MHD_parse_request_arg_auto_t (rc->connection, + "merchant_sig", + &ctx->merchant_sig); + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + { + if (GNUNET_OK != + TALER_merchant_deposit_verify (&ctx->merchant, + &ctx->coin_pub, + &ctx->h_contract_terms, + &ctx->h_wire, + &ctx->merchant_sig)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_EXCHANGE_DEPOSITS_GET_MERCHANT_SIGNATURE_INVALID, + NULL); + } } } return handle_track_transaction_request (rc->connection, - &ctx); + ctx); } diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c index bf4e4dea..0372573b 100644 --- a/src/exchange/taler-exchange-httpd_kyc-check.c +++ b/src/exchange/taler-exchange-httpd_kyc-check.c @@ -520,34 +520,8 @@ TEH_handler_kyc_check ( "usertype"); } - { - const char *ts; - - ts = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "timeout_ms"); - if (NULL != ts) - { - char dummy; - unsigned long long tms; - - if (1 != - sscanf (ts, - "%llu%c", - &tms, - &dummy)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "timeout_ms"); - } - kyp->timeout = GNUNET_TIME_relative_to_absolute ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - tms)); - } - } + TALER_MHD_parse_request_timeout (rc->connection, + &kyp->timeout); } if ( (NULL == kyp->eh) && diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c index 6d06f0c8..9668ee54 100644 --- a/src/exchange/taler-exchange-httpd_kyc-proof.c +++ b/src/exchange/taler-exchange-httpd_kyc-proof.c @@ -297,7 +297,6 @@ TEH_handler_kyc_proof ( { struct KycProofContext *kpc = rc->rh_ctx; const char *provider_section_or_logic = args[0]; - const char *h_payto; if (NULL == kpc) { @@ -310,33 +309,13 @@ TEH_handler_kyc_proof ( TALER_EC_GENERIC_ENDPOINT_UNKNOWN, "'/kyc-proof/$PROVIDER_SECTION?state=$H_PAYTO' required"); } - h_payto = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "state"); - if (NULL == h_payto) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MISSING, - "h_payto"); - } kpc = GNUNET_new (struct KycProofContext); kpc->rc = rc; rc->rh_ctx = kpc; rc->rh_cleaner = &clean_kpc; - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (h_payto, - strlen (h_payto), - &kpc->h_payto, - sizeof (kpc->h_payto))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "h_payto"); - } + TALER_MHD_parse_request_arg_auto_t (rc->connection, + "state", + &kpc->h_payto); if (GNUNET_OK != TALER_KYCLOGIC_lookup_logic (provider_section_or_logic, &kpc->logic, diff --git a/src/exchange/taler-exchange-httpd_purses_delete.c b/src/exchange/taler-exchange-httpd_purses_delete.c index 58cc7825..5bf7c24c 100644 --- a/src/exchange/taler-exchange-httpd_purses_delete.c +++ b/src/exchange/taler-exchange-httpd_purses_delete.c @@ -57,29 +57,9 @@ TEH_handler_purses_delete ( TALER_EC_EXCHANGE_GENERIC_PURSE_PUB_MALFORMED, args[0]); } - { - const char *sig; - - sig = MHD_lookup_connection_value (connection, - MHD_HEADER_KIND, - "Taler-Purse-Signature"); - if ( (NULL == sig) || - (GNUNET_OK != - GNUNET_STRINGS_string_to_data (sig, - strlen (sig), - &purse_sig, - sizeof (purse_sig))) ) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - (NULL == sig) - ? TALER_EC_GENERIC_PARAMETER_MISSING - : TALER_EC_GENERIC_PARAMETER_MALFORMED, - "Taler-Purse-Signature"); - } - } - + TALER_MHD_parse_request_header_auto_t (connection, + "Taler-Purse-Signature", + &purse_sig); if (GNUNET_OK != TALER_wallet_purse_delete_verify (&purse_pub, &purse_sig)) diff --git a/src/exchange/taler-exchange-httpd_purses_get.c b/src/exchange/taler-exchange-httpd_purses_get.c index 434798a8..61337235 100644 --- a/src/exchange/taler-exchange-httpd_purses_get.c +++ b/src/exchange/taler-exchange-httpd_purses_get.c @@ -243,36 +243,8 @@ TEH_handler_purses_get (struct TEH_RequestContext *rc, args[1]); } - { - const char *long_poll_timeout_ms; - - long_poll_timeout_ms - = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "timeout_ms"); - if (NULL != long_poll_timeout_ms) - { - unsigned int timeout_ms; - char dummy; - struct GNUNET_TIME_Relative timeout; - - if (1 != sscanf (long_poll_timeout_ms, - "%u%c", - &timeout_ms, - &dummy)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "timeout_ms (must be non-negative number)"); - } - timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - timeout_ms); - gc->timeout = GNUNET_TIME_relative_to_absolute (timeout); - } - } - + TALER_MHD_parse_request_timeout (rc->connection, + &gc->timeout); if ( (GNUNET_TIME_absolute_is_future (gc->timeout)) && (NULL == gc->eh) ) { diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index 21c0b74a..3ffbda29 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -178,9 +178,6 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc, if (NULL == rp) { - struct GNUNET_TIME_Relative timeout - = GNUNET_TIME_UNIT_ZERO; - rp = GNUNET_new (struct ReservePoller); rp->connection = rc->connection; rp->rc = rc; @@ -201,34 +198,8 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc, TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, args[0]); } - { - const char *long_poll_timeout_ms; - - long_poll_timeout_ms - = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "timeout_ms"); - if (NULL != long_poll_timeout_ms) - { - unsigned int timeout_ms; - char dummy; - - if (1 != sscanf (long_poll_timeout_ms, - "%u%c", - &timeout_ms, - &dummy)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "timeout_ms (must be non-negative number)"); - } - timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - timeout_ms); - } - } - rp->timeout = GNUNET_TIME_relative_to_absolute (timeout); + TALER_MHD_parse_request_timeout (rc->connection, + &rp->timeout); } if ( (GNUNET_TIME_absolute_is_future (rp->timeout)) && diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index b6423135..e2e8ecb0 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -437,7 +437,47 @@ TALER_MHD_parse_json_array (struct MHD_Connection *connection, /** - * Extract fixed-size base32crockford encoded data from request. + * Extract optional "timeout_ms" argument from request. + * + * @param connection the MHD connection + * @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout, + * the current time plus the value given under "timeout_ms" otherwise + * @return #GNUNET_OK on success, #GNUNET_NO if an + * error was returned on @a connection (caller should return #MHD_YES) and + * #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO) + */ +enum GNUNET_GenericReturnValue +TALER_MHD_parse_request_arg_timeout (struct MHD_Connection *connection, + struct GNUNET_TIME_Absolute *expiration); + + +/** + * Extract optional "timeout_ms" argument from request. + * Macro that *returns* #MHD_YES/#MHD_NO if the "timeout_ms" + * argument existed but failed to parse. + * + * @param connection the MHD connection + * @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout, + * the current time plus the value given under "timeout_ms" otherwise + */ +#define TALER_MHD_parse_request_timeout(connection,expiration) \ + do { \ + switch (TALER_MHD_parse_request_arg_timeout (connection, \ + expiration)) \ + { \ + case GNUNET_SYSERR: \ + GNUNET_break (0); \ + return MHD_NO; \ + case GNUNET_NO: \ + GNUNET_break_op (0); \ + case GNUNET_OK: \ + break; \ + } \ + } while (0) + + +/** + * Extract fixed-size base32crockford encoded data from request argument. * * Queues an error response to the connection if the parameter is missing or * invalid. @@ -446,16 +486,152 @@ TALER_MHD_parse_json_array (struct MHD_Connection *connection, * @param param_name the name of the parameter with the key * @param[out] out_data pointer to store the result * @param out_size expected size of @a out_data + * @param[out] present set to true if argument was found * @return * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_NO if the argument is malformed * #GNUNET_SYSERR on internal error (error response could not be sent) */ enum GNUNET_GenericReturnValue TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection, const char *param_name, void *out_data, - size_t out_size); + size_t out_size, + bool *present); + + +/** + * Extract fixed-size base32crockford encoded data from request header. + * + * Queues an error response to the connection if the parameter is missing or + * invalid. + * + * @param connection the MHD connection + * @param header_name the name of the HTTP header with the value + * @param[out] out_data pointer to store the result + * @param out_size expected size of @a out_data + * @param[out] present set to true if argument was found + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +enum GNUNET_GenericReturnValue +TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, + const char *header_name, + void *out_data, + size_t out_size, + bool *present); + +/** + * Extract fixed-size base32crockford encoded data from request. + * + * @param connection the MHD connection + * @param name the name of the parameter with the key + * @param[out] out_data pointer to store the result, type must determine size + * @param[in,out] required pass true to require presence of this argument; if 'false' + * set to true if the argument was found + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +#define TALER_MHD_parse_request_arg_auto(connection,name,val,required) \ + do { \ + bool p; \ + switch (TALER_MHD_parse_request_arg_data (connection, name, \ + val, sizeof (*val), &p)) \ + { \ + case GNUNET_SYSERR: \ + GNUNET_break (0); \ + return MHD_NO; \ + case GNUNET_NO: \ + GNUNET_break_op (0); \ + return MHD_YES; \ + case GNUNET_OK: \ + if (required & (! p)) \ + return TALER_MHD_reply_with_error ( \ + connection, \ + MHD_HTTP_BAD_REQUEST, \ + TALER_EC_GENERIC_PARAMETER_MISSING, \ + name); \ + required = p; \ + break; \ + } \ + } while (0) + + +/** + * Extract required fixed-size base32crockford encoded data from request. + * + * @param connection the MHD connection + * @param name the name of the parameter with the key + * @param[out] out_data pointer to store the result, type must determine size + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +#define TALER_MHD_parse_request_arg_auto_t(connection,name,val) \ + do { \ + bool b = true; \ + TALER_MHD_parse_request_arg_auto (connection,name,val,b); \ + } while (0) + +/** + * Extract fixed-size base32crockford encoded data from request. + * + * @param connection the MHD connection + * @param name the name of the header with the key + * @param[out] out_data pointer to store the result, type must determine size + * @param[in,out] required pass true to require presence of this argument; if 'false' + * set to true if the argument was found + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +#define TALER_MHD_parse_request_header_auto(connection,name,val,required) \ + do { \ + bool p; \ + switch (TALER_MHD_parse_request_header_data (connection, name, \ + val, sizeof (*val), &p)) \ + { \ + case GNUNET_SYSERR: \ + GNUNET_break (0); \ + return MHD_NO; \ + case GNUNET_NO: \ + GNUNET_break_op (0); \ + return MHD_YES; \ + case GNUNET_OK: \ + if (required & (! p)) \ + return TALER_MHD_reply_with_error ( \ + connection, \ + MHD_HTTP_BAD_REQUEST, \ + TALER_EC_GENERIC_PARAMETER_MISSING, \ + name); \ + required = p; \ + break; \ + } \ + } while (0) + + +/** + * Extract required fixed-size base32crockford encoded data from request. + * + * @param connection the MHD connection + * @param name the name of the header with the key + * @param[out] out_data pointer to store the result, type must determine size + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +#define TALER_MHD_parse_request_header_auto_t(connection,name,val) \ + do { \ + bool b = true; \ + TALER_MHD_parse_request_header_auto (connection,name,val,b); \ + } while (0) /** diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c index ee647f4b..e7645083 100644 --- a/src/mhd/mhd_parsing.c +++ b/src/mhd/mhd_parsing.c @@ -86,25 +86,40 @@ TALER_MHD_parse_post_cleanup_callback (void *con_cls) } -enum GNUNET_GenericReturnValue -TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size) +/** + * Extract fixed-size base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing or + * invalid. + * + * @param connection the MHD connection + * @param param_name the name of the HTTP key with the value + * @param kind whether to extract from header, argument or footer + * @param[out] out_data pointer to store the result + * @param out_size expected size of @a out_data + * @param[out] present set to true if argument was found + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +static enum GNUNET_GenericReturnValue +parse_request_data (struct MHD_Connection *connection, + const char *param_name, + enum MHD_ValueKind kind, + void *out_data, + size_t out_size, + bool *present) { const char *str; str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, + kind, param_name); if (NULL == str) { - return (MHD_NO == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MISSING, - param_name)) - ? GNUNET_SYSERR : GNUNET_NO; + *present = false; + return GNUNET_OK; } if (GNUNET_OK != GNUNET_STRINGS_string_to_data (str, @@ -117,6 +132,79 @@ TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection, TALER_EC_GENERIC_PARAMETER_MALFORMED, param_name)) ? GNUNET_SYSERR : GNUNET_NO; + *present = true; + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size, + bool *present) +{ + return parse_request_data (connection, + param_name, + MHD_GET_ARGUMENT_KIND, + out_data, + out_size, + present); +} + + +enum GNUNET_GenericReturnValue +TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, + const char *header_name, + void *out_data, + size_t out_size, + bool *present) +{ + return parse_request_data (connection, + header_name, + MHD_HEADER_KIND, + out_data, + out_size, + present); +} + + +enum GNUNET_GenericReturnValue +TALER_MHD_parse_request_arg_timeout (struct MHD_Connection *connection, + struct GNUNET_TIME_Absolute *expiration) +{ + const char *ts; + char dummy; + unsigned long long tms; + + ts = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "timeout_ms"); + if (NULL == ts) + { + *expiration = GNUNET_TIME_UNIT_ZERO_ABS; + return GNUNET_OK; + } + if (1 != + sscanf (ts, + "%llu%c", + &tms, + &dummy)) + { + MHD_RESULT mret; + + GNUNET_break_op (0); + mret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "timeout_ms"); + return (MHD_YES == mret) + ? GNUNET_NO + : GNUNET_SYSERR; + } + *expiration = GNUNET_TIME_relative_to_absolute ( + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + tms)); return GNUNET_OK; } -- cgit v1.2.3 From 7c0de44a2b62fe47168eaa857c038901533bd48b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 4 May 2023 17:14:54 +0200 Subject: towards LP support for GET /deposits (#7808) --- src/exchange/taler-exchange-httpd.c | 1 + src/exchange/taler-exchange-httpd_deposits_get.c | 167 +++++++++++++++++++++-- src/exchange/taler-exchange-httpd_deposits_get.h | 7 + src/exchange/taler-exchange-httpd_reserves_get.c | 3 +- src/include/taler_exchangedb_plugin.h | 30 +++- 5 files changed, 190 insertions(+), 18 deletions(-) (limited to 'src/include') diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index d247d981..ac3eae27 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -2215,6 +2215,7 @@ do_shutdown (void *cls) mhd = TALER_MHD_daemon_stop (); TEH_resume_keys_requests (true); + TEH_deposits_get_cleanup (); TEH_reserves_get_cleanup (); TEH_purses_get_cleanup (); TEH_kyc_check_cleanup (); diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c index 26c9e261..10b4af51 100644 --- a/src/exchange/taler-exchange-httpd_deposits_get.c +++ b/src/exchange/taler-exchange-httpd_deposits_get.c @@ -23,6 +23,7 @@ #include #include #include +#include "taler_dbevents.h" #include "taler_json_lib.h" #include "taler_mhd_lib.h" #include "taler_signatures.h" @@ -37,6 +38,26 @@ struct DepositWtidContext { + /** + * Kept in a DLL. + */ + struct DepositWtidContext *next; + + /** + * Kept in a DLL. + */ + struct DepositWtidContext *prev; + + /** + * Context for the request we are processing. + */ + struct TEH_RequestContext *rc; + + /** + * Subscription for the database event we are waiting for. + */ + struct GNUNET_DB_EventHandler *eh; + /** * Hash over the proposal data of the contract for which this deposit is made. */ @@ -85,6 +106,11 @@ struct DepositWtidContext */ struct GNUNET_TIME_Timestamp execution_time; + /** + * Timeout of the request, for long-polling. + */ + struct GNUNET_TIME_Absolute timeout; + /** * Set by #handle_wtid to the coin contribution to the transaction * (that is, @e coin_contribution minus @e coin_fee). @@ -107,9 +133,45 @@ struct DepositWtidContext * Set to #GNUNET_SYSERR if there was a serious error. */ enum GNUNET_GenericReturnValue pending; + + /** + * #GNUNET_YES if we were suspended, #GNUNET_SYSERR + * if we were woken up due to shutdown. + */ + enum GNUNET_GenericReturnValue suspended; }; +/** + * Head of DLL of suspended requests. + */ +static struct DepositWtidContext *dwc_head; + +/** + * Tail of DLL of suspended requests. + */ +static struct DepositWtidContext *dwc_tail; + + +void +TEH_deposits_get_cleanup () +{ + struct DepositWtidContext *n; + for (struct DepositWtidContext *ctx = dwc_head; + NULL != ctx; + ctx = n) + { + n = ctx->next; + GNUNET_assert (GNUNET_YES == ctx->suspended); + ctx->suspended = GNUNET_SYSERR; + MHD_resume_connection (ctx->rc->connection); + GNUNET_CONTAINER_DLL_remove (dwc_head, + dwc_tail, + ctx); + } +} + + /** * A merchant asked for details about a deposit. Provide * them. Generates the 200 reply. @@ -233,34 +295,99 @@ deposits_get_transaction (void *cls, } +/** + * Function called on events received from Postgres. + * Wakes up long pollers. + * + * @param cls the `struct DepositWtidContext *` + * @param extra additional event data provided + * @param extra_size number of bytes in @a extra + */ +static void +db_event_cb (void *cls, + const void *extra, + size_t extra_size) +{ + struct DepositWtidContext *ctx = cls; + struct GNUNET_AsyncScopeSave old_scope; + + (void) extra; + (void) extra_size; + if (GNUNET_NO != ctx->suspended) + return; /* might get multiple wake-up events */ + GNUNET_CONTAINER_DLL_remove (dwc_head, + dwc_tail, + ctx); + GNUNET_async_scope_enter (&ctx->rc->async_scope_id, + &old_scope); + TEH_check_invariants (); + ctx->suspended = GNUNET_NO; + MHD_resume_connection (ctx->rc->connection); + TALER_MHD_daemon_trigger (); + TEH_check_invariants (); + GNUNET_async_scope_restore (&old_scope); +} + + /** * Lookup and return the wire transfer identifier. * - * @param connection the MHD connection to handle * @param ctx context of the signed request to execute * @return MHD result code */ static MHD_RESULT handle_track_transaction_request ( - struct MHD_Connection *connection, struct DepositWtidContext *ctx) { - MHD_RESULT mhd_ret; - - if (GNUNET_OK != - TEH_DB_run_transaction (connection, - "handle deposits GET", - TEH_MT_REQUEST_OTHER, - &mhd_ret, - &deposits_get_transaction, - ctx)) - return mhd_ret; + struct MHD_Connection *connection = ctx->rc->connection; + + if ( (GNUNET_TIME_absolute_is_future (ctx->timeout)) && + (NULL == ctx->eh) ) + { + struct TALER_CoinDepositEventP rep = { + .header.size = htons (sizeof (rep)), + .header.type = htons (TALER_DBEVENT_EXCHANGE_DEPOSIT_STATUS_CHANGED), + .coin_pub = ctx->coin_pub, + .merchant_pub = ctx->merchant, + .h_wire = ctx->h_wire + }; + + ctx->eh = TEH_plugin->event_listen ( + TEH_plugin->cls, + GNUNET_TIME_absolute_get_remaining (ctx->timeout), + &rep.header, + &db_event_cb, + ctx); + } + { + MHD_RESULT mhd_ret; + + if (GNUNET_OK != + TEH_DB_run_transaction (connection, + "handle deposits GET", + TEH_MT_REQUEST_OTHER, + &mhd_ret, + &deposits_get_transaction, + ctx)) + return mhd_ret; + } if (GNUNET_SYSERR == ctx->pending) return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_INVARIANT_FAILURE, "wire fees exceed aggregate in database"); - if (ctx->pending) + if (GNUNET_YES == ctx->pending) + { + if ( (GNUNET_TIME_absolute_is_future (ctx->timeout)) && + (GNUNET_NO == ctx->suspended) ) + { + GNUNET_CONTAINER_DLL_insert (dwc_head, + dwc_tail, + ctx); + ctx->suspended = GNUNET_YES; + MHD_suspend_connection (connection); + return MHD_YES; + } return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_ACCEPTED, @@ -276,6 +403,7 @@ handle_track_transaction_request ( ctx->kyc.ok), GNUNET_JSON_pack_timestamp ("execution_time", ctx->execution_time)); + } return reply_deposit_details (connection, ctx); } @@ -291,6 +419,13 @@ dwc_cleaner (struct TEH_RequestContext *rc) { struct DepositWtidContext *ctx = rc->rh_ctx; + GNUNET_assert (GNUNET_NO == ctx->suspended); + if (NULL != ctx->eh) + { + TEH_plugin->event_listen_cancel (TEH_plugin->cls, + ctx->eh); + ctx->eh = NULL; + } GNUNET_free (ctx); } @@ -304,6 +439,7 @@ TEH_handler_deposits_get (struct TEH_RequestContext *rc, if (NULL == ctx) { ctx = GNUNET_new (struct DepositWtidContext); + ctx->rc = rc; rc->rh_ctx = ctx; rc->rh_cleaner = &dwc_cleaner; @@ -358,6 +494,8 @@ TEH_handler_deposits_get (struct TEH_RequestContext *rc, TALER_MHD_parse_request_arg_auto_t (rc->connection, "merchant_sig", &ctx->merchant_sig); + TALER_MHD_parse_request_timeout (rc->connection, + &ctx->timeout); TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; { if (GNUNET_OK != @@ -376,8 +514,7 @@ TEH_handler_deposits_get (struct TEH_RequestContext *rc, } } - return handle_track_transaction_request (rc->connection, - ctx); + return handle_track_transaction_request (ctx); } diff --git a/src/exchange/taler-exchange-httpd_deposits_get.h b/src/exchange/taler-exchange-httpd_deposits_get.h index aee7521a..c7b1698b 100644 --- a/src/exchange/taler-exchange-httpd_deposits_get.h +++ b/src/exchange/taler-exchange-httpd_deposits_get.h @@ -26,6 +26,13 @@ #include "taler-exchange-httpd.h" +/** + * Resume long pollers on GET /deposits. + */ +void +TEH_deposits_get_cleanup (void); + + /** * Handle a "/deposits/$H_WIRE/$MERCHANT_PUB/$H_CONTRACT_TERMS/$COIN_PUB" * request. diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index 3ffbda29..bbaac853 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -57,8 +57,7 @@ struct ReservePoller struct TEH_RequestContext *rc; /** - * Subscription for the database event we are - * waiting for. + * Subscription for the database event we are waiting for. */ struct GNUNET_DB_EventHandler *eh; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index d025b532..d55f9642 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -149,7 +149,35 @@ struct TALER_EXCHANGEDB_DenominationKeyInformation GNUNET_NETWORK_STRUCT_BEGIN /** - * Signature of events signalling a reserve got funding. + * Events signalling that a coin deposit status + * changed. + */ +struct TALER_CoinDepositEventP +{ + /** + * Of type #TALER_DBEVENT_EXCHANGE_DEPOSIT_STATUS_CHANGED. + */ + struct GNUNET_DB_EventHeaderP header; + + /** + * The coin's public key. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * The Merchant's public key. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Hash over the wiring information of the merchant. + */ + struct TALER_MerchantWireHashP h_wire; + +}; + +/** + * Events signalling a reserve got funding. */ struct TALER_ReserveEventP { -- cgit v1.2.3 From 1e88796045ca0216b6c83234522423d1f9831fdd Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 4 May 2023 17:36:43 +0200 Subject: finish implementation for #7808 --- src/exchange/taler-exchange-httpd_deposits_get.c | 6 +-- src/exchangedb/pg_aggregate.c | 69 ++++++++++++++---------- src/include/taler_exchange_service.h | 2 + src/include/taler_exchangedb_plugin.h | 12 +---- src/lib/exchange_api_deposits_get.c | 26 +++++++-- src/testing/testing_api_cmd_deposits_get.c | 1 + 6 files changed, 70 insertions(+), 46 deletions(-) (limited to 'src/include') diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c index 10b4af51..818900c6 100644 --- a/src/exchange/taler-exchange-httpd_deposits_get.c +++ b/src/exchange/taler-exchange-httpd_deposits_get.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2017, 2021 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 Affero General Public License as published by the Free Software @@ -347,9 +347,7 @@ handle_track_transaction_request ( struct TALER_CoinDepositEventP rep = { .header.size = htons (sizeof (rep)), .header.type = htons (TALER_DBEVENT_EXCHANGE_DEPOSIT_STATUS_CHANGED), - .coin_pub = ctx->coin_pub, - .merchant_pub = ctx->merchant, - .h_wire = ctx->h_wire + .merchant_pub = ctx->merchant }; ctx->eh = TEH_plugin->event_listen ( diff --git a/src/exchangedb/pg_aggregate.c b/src/exchangedb/pg_aggregate.c index 6e94cbeb..76d0adec 100644 --- a/src/exchangedb/pg_aggregate.c +++ b/src/exchangedb/pg_aggregate.c @@ -22,6 +22,7 @@ #include "taler_error_codes.h" #include "taler_dbevents.h" #include "taler_pq_lib.h" +#include "pg_event_notify.h" #include "pg_aggregate.h" #include "pg_helper.h" @@ -35,34 +36,12 @@ TEH_PG_aggregate ( { struct PostgresClosure *pg = cls; struct GNUNET_TIME_Absolute now = {0}; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&now), - GNUNET_PQ_query_param_auto_from_type (merchant_pub), - GNUNET_PQ_query_param_auto_from_type (h_payto), - GNUNET_PQ_query_param_auto_from_type (wtid), - GNUNET_PQ_query_param_end - }; uint64_t sum_deposit_value; uint64_t sum_deposit_frac; uint64_t sum_refund_value; uint64_t sum_refund_frac; uint64_t sum_fee_value; uint64_t sum_fee_frac; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("sum_deposit_value", - &sum_deposit_value), - GNUNET_PQ_result_spec_uint64 ("sum_deposit_fraction", - &sum_deposit_frac), - GNUNET_PQ_result_spec_uint64 ("sum_refund_value", - &sum_refund_value), - GNUNET_PQ_result_spec_uint64 ("sum_refund_fraction", - &sum_refund_frac), - GNUNET_PQ_result_spec_uint64 ("sum_fee_value", - &sum_fee_value), - GNUNET_PQ_result_spec_uint64 ("sum_fee_fraction", - &sum_fee_frac), - GNUNET_PQ_result_spec_end - }; enum GNUNET_DB_QueryStatus qs; struct TALER_Amount sum_deposit; struct TALER_Amount sum_refund; @@ -71,8 +50,6 @@ TEH_PG_aggregate ( now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (), pg->aggregator_shift); - - /* Used in #postgres_aggregate() */ PREPARE (pg, "aggregate", "WITH dep AS (" /* restrict to our merchant and account and mark as done */ @@ -148,11 +125,35 @@ TEH_PG_aggregate ( " FULL OUTER JOIN ref ON (FALSE)" /* We just want all sums */ " FULL OUTER JOIN fees ON (FALSE);"); + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), + GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_auto_from_type (wtid), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("sum_deposit_value", + &sum_deposit_value), + GNUNET_PQ_result_spec_uint64 ("sum_deposit_fraction", + &sum_deposit_frac), + GNUNET_PQ_result_spec_uint64 ("sum_refund_value", + &sum_refund_value), + GNUNET_PQ_result_spec_uint64 ("sum_refund_fraction", + &sum_refund_frac), + GNUNET_PQ_result_spec_uint64 ("sum_fee_value", + &sum_fee_value), + GNUNET_PQ_result_spec_uint64 ("sum_fee_fraction", + &sum_fee_frac), + GNUNET_PQ_result_spec_end + }; - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "aggregate", - params, - rs); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "aggregate", + params, + rs); + } if (qs < 0) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -165,6 +166,18 @@ TEH_PG_aggregate ( total)); return qs; } + { + struct TALER_CoinDepositEventP rep = { + .header.size = htons (sizeof (rep)), + .header.type = htons (TALER_DBEVENT_EXCHANGE_DEPOSIT_STATUS_CHANGED), + .merchant_pub = *merchant_pub + }; + + TEH_PG_event_notify (pg, + &rep.header, + NULL, + 0); + } GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (pg->currency, &sum_deposit)); diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index fc5fb284..3769315e 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -3546,6 +3546,7 @@ typedef void * @param h_wire hash of merchant's wire transfer details * @param h_contract_terms hash of the proposal data * @param coin_pub public key of the coin + * @param timeout timeout to use for long-polling, 0 for no long polling * @param cb function to call with the result * @param cb_cls closure for @a cb * @return handle to abort request @@ -3557,6 +3558,7 @@ TALER_EXCHANGE_deposits_get ( const struct TALER_MerchantWireHashP *h_wire, const struct TALER_PrivateContractHashP *h_contract_terms, const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct GNUNET_TIME_Relative timeout, TALER_EXCHANGE_DepositGetCallback cb, void *cb_cls); diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index d55f9642..3a6ba651 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -160,20 +160,10 @@ struct TALER_CoinDepositEventP struct GNUNET_DB_EventHeaderP header; /** - * The coin's public key. - */ - struct TALER_CoinSpendPublicKeyP coin_pub; - - /** - * The Merchant's public key. + * Public key of the merchant. */ struct TALER_MerchantPublicKeyP merchant_pub; - /** - * Hash over the wiring information of the merchant. - */ - struct TALER_MerchantWireHashP h_wire; - }; /** diff --git a/src/lib/exchange_api_deposits_get.c b/src/lib/exchange_api_deposits_get.c index bd5f2f65..9ec25e45 100644 --- a/src/lib/exchange_api_deposits_get.c +++ b/src/lib/exchange_api_deposits_get.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 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 @@ -260,6 +260,7 @@ TALER_EXCHANGE_deposits_get ( const struct TALER_MerchantWireHashP *h_wire, const struct TALER_PrivateContractHashP *h_contract_terms, const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct GNUNET_TIME_Relative timeout, TALER_EXCHANGE_DepositGetCallback cb, void *cb_cls) { @@ -293,6 +294,7 @@ TALER_EXCHANGE_deposits_get ( char msig_str[sizeof (struct TALER_MerchantSignatureP) * 2]; char chash_str[sizeof (struct TALER_PrivateContractHashP) * 2]; char whash_str[sizeof (struct TALER_MerchantWireHashP) * 2]; + char timeout_str[24]; char *end; end = GNUNET_STRINGS_data_to_string (h_wire, @@ -320,15 +322,33 @@ TALER_EXCHANGE_deposits_get ( msig_str, sizeof (msig_str)); *end = '\0'; + if (GNUNET_TIME_relative_is_zero (timeout)) + { + timeout_str[0] = '\0'; + } + else + { + GNUNET_snprintf ( + timeout_str, + sizeof (timeout_str), + "%llu", + (unsigned long long) ( + timeout.rel_value_us + / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us)); + } GNUNET_snprintf (arg_str, sizeof (arg_str), - "/deposits/%s/%s/%s/%s?merchant_sig=%s", + "/deposits/%s/%s/%s/%s?merchant_sig=%s%s%s", whash_str, mpub_str, chash_str, cpub_str, - msig_str); + msig_str, + GNUNET_TIME_relative_is_zero (timeout) + ? "" + : "&timeout_ms=", + timeout_str); } dwh = GNUNET_new (struct TALER_EXCHANGE_DepositGetHandle); diff --git a/src/testing/testing_api_cmd_deposits_get.c b/src/testing/testing_api_cmd_deposits_get.c index 8f797089..c39d7f6c 100644 --- a/src/testing/testing_api_cmd_deposits_get.c +++ b/src/testing/testing_api_cmd_deposits_get.c @@ -281,6 +281,7 @@ track_transaction_run (void *cls, &h_wire_details, &h_contract_terms, &coin_pub, + GNUNET_TIME_UNIT_ZERO, &deposit_wtid_cb, tts); GNUNET_assert (NULL != tts->tth); -- cgit v1.2.3 From 737b3338ed460b56096b9b016b727a0d34b30d23 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 4 May 2023 21:32:36 +0200 Subject: -doxygen --- contrib/gnunet.tag | 8 +++++++- src/include/taler_mhd_lib.h | 8 ++++---- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/include') diff --git a/contrib/gnunet.tag b/contrib/gnunet.tag index f270ba5e..bdc112a1 100644 --- a/contrib/gnunet.tag +++ b/contrib/gnunet.tag @@ -31,7 +31,13 @@ #define GNUNET_TIME_UNIT_FOREVER_ABS - gnunet_util_lib.h + gnunet_time_lib.h + + + + #define + GNUNET_TIME_UNIT_ZERO_ABS + gnunet_time_lib.h diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index e2e8ecb0..9c7c06d9 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -528,7 +528,7 @@ TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, * * @param connection the MHD connection * @param name the name of the parameter with the key - * @param[out] out_data pointer to store the result, type must determine size + * @param[out] val pointer to store the result, type must determine size * @param[in,out] required pass true to require presence of this argument; if 'false' * set to true if the argument was found * @return @@ -566,7 +566,7 @@ TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, * * @param connection the MHD connection * @param name the name of the parameter with the key - * @param[out] out_data pointer to store the result, type must determine size + * @param[out] val pointer to store the result, type must determine size * @return * #GNUNET_YES if the the argument is present * #GNUNET_NO if the argument is absent or malformed @@ -583,7 +583,7 @@ TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, * * @param connection the MHD connection * @param name the name of the header with the key - * @param[out] out_data pointer to store the result, type must determine size + * @param[out] val pointer to store the result, type must determine size * @param[in,out] required pass true to require presence of this argument; if 'false' * set to true if the argument was found * @return @@ -621,7 +621,7 @@ TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, * * @param connection the MHD connection * @param name the name of the header with the key - * @param[out] out_data pointer to store the result, type must determine size + * @param[out] val pointer to store the result, type must determine size * @return * #GNUNET_YES if the the argument is present * #GNUNET_NO if the argument is absent or malformed -- cgit v1.2.3 From 1f9427e1d9672b93577aea4c9d5a63575ee0b525 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 6 May 2023 19:43:17 +0200 Subject: add convenience function for content-length limiation --- contrib/gana | 2 +- src/exchange/taler-exchange-httpd.c | 29 ++---------------- src/include/taler_mhd_lib.h | 59 ++++++++++++++++++++++++++++++++----- src/mhd/mhd_parsing.c | 42 ++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 36 deletions(-) (limited to 'src/include') diff --git a/contrib/gana b/contrib/gana index 85736484..4654d82b 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 85736484cb0da26aded705ebb1e944e8bb1b8504 +Subproject commit 4654d82b143cd69dfe7a7bf2f816f6f91f6052e2 diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index ac3eae27..97cf54c8 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -1617,33 +1617,8 @@ handle_mhd_request (void *cls, if (0 == strcasecmp (method, MHD_HTTP_METHOD_POST)) { - const char *cl; - - /* Maybe check for maximum upload size - and refuse requests if they are just too big. */ - cl = MHD_lookup_connection_value (connection, - MHD_HEADER_KIND, - MHD_HTTP_HEADER_CONTENT_LENGTH); - if (NULL != cl) - { - unsigned long long cv; - char dummy; - - if (1 != sscanf (cl, - "%llu%c", - &cv, - &dummy)) - { - /* Not valid HTTP request, just close connection. */ - GNUNET_break_op (0); - return MHD_NO; - } - if (cv > TALER_MHD_REQUEST_BUFFER_MAX) - { - GNUNET_break_op (0); - return TALER_MHD_reply_request_too_large (connection); - } - } + TALER_MHD_check_content_length (connection, + TALER_MHD_REQUEST_BUFFER_MAX); } } diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index 9c7c06d9..e4aa916e 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -596,14 +596,14 @@ TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, bool p; \ switch (TALER_MHD_parse_request_header_data (connection, name, \ val, sizeof (*val), &p)) \ - { \ - case GNUNET_SYSERR: \ - GNUNET_break (0); \ - return MHD_NO; \ - case GNUNET_NO: \ - GNUNET_break_op (0); \ - return MHD_YES; \ - case GNUNET_OK: \ + { \ + case GNUNET_SYSERR: \ + GNUNET_break (0); \ + return MHD_NO; \ + case GNUNET_NO: \ + GNUNET_break_op (0); \ + return MHD_YES; \ + case GNUNET_OK: \ if (required & (! p)) \ return TALER_MHD_reply_with_error ( \ connection, \ @@ -634,6 +634,49 @@ TALER_MHD_parse_request_header_data (struct MHD_Connection *connection, } while (0) +/** + * Check that the 'Content-Length' header is giving + * a length below @a max_len. If not, return an + * appropriate error response and return the + * correct #MHD_YES/#MHD_NO value from this function. + * + * @param connection the MHD connection + * @param max_len maximum allowed content length + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +enum GNUNET_GenericReturnValue +TALER_MHD_check_content_length_ (struct MHD_Connection *connection, + unsigned long long max_len); + + +/** + * Check that the 'Content-Length' header is giving + * a length below @a max_len. If not, return an + * appropriate error response and return the + * correct #MHD_YES/#MHD_NO value from this function. + * + * @param connection the MHD connection + * @param max_len maximum allowed content length + */ +#define TALER_MHD_check_content_length(connection,max_len) \ + do { \ + switch (TALER_MHD_check_content_length_ (connection, max_len)) \ + { \ + case GNUNET_SYSERR: \ + GNUNET_break (0); \ + return MHD_NO; \ + case GNUNET_NO: \ + GNUNET_break_op (0); \ + return MHD_YES; \ + case GNUNET_OK: \ + break; \ + } \ + } while (0) + + /** * Parse the configuration to determine on which port * or UNIX domain path we should run an HTTP service. diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c index e7645083..b047df7d 100644 --- a/src/mhd/mhd_parsing.c +++ b/src/mhd/mhd_parsing.c @@ -350,4 +350,46 @@ TALER_MHD_parse_json_array (struct MHD_Connection *connection, } +enum GNUNET_GenericReturnValue +TALER_MHD_check_content_length_ (struct MHD_Connection *connection, + unsigned long long max_len) +{ + const char *cl; + unsigned long long cv; + char dummy; + + /* Maybe check for maximum upload size + and refuse requests if they are just too big. */ + cl = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONTENT_LENGTH); + if (NULL == cl) + return GNUNET_OK; + if (1 != sscanf (cl, + "%llu%c", + &cv, + &dummy)) + { + /* Not valid HTTP request, just close connection. */ + GNUNET_break_op (0); + return (MHD_YES == + TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + MHD_HTTP_HEADER_CONTENT_LENGTH)) + ? GNUNET_NO + : GNUNET_SYSERR; + } + if (cv > TALER_MHD_REQUEST_BUFFER_MAX) + { + GNUNET_break_op (0); + return (MHD_YES == + TALER_MHD_reply_request_too_large (connection)) + ? GNUNET_NO + : GNUNET_SYSERR; + } + return GNUNET_OK; +} + + /* end of mhd_parsing.c */ -- cgit v1.2.3 From 404b2b78f187e3da2fedee5748b9bfcdfa4a105c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 6 May 2023 20:55:40 +0200 Subject: add convenience function TALER_TEMPLATING_reply_error --- src/include/taler_templating_lib.h | 20 +++++++++++++++++++ src/mhd/mhd_parsing.c | 11 ++++++++++- src/templating/templating_api.c | 39 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) (limited to 'src/include') diff --git a/src/include/taler_templating_lib.h b/src/include/taler_templating_lib.h index 53946b9c..ebda2ecf 100644 --- a/src/include/taler_templating_lib.h +++ b/src/include/taler_templating_lib.h @@ -91,6 +91,26 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection, const char *taler_uri, const json_t *root); + +/** + * Load a @a template and substitute an error message based on @a ec and @a + * detail, returning the result to the @a connection with the given @a + * http_status code. + * + * @param connection the connection we act upon + * @param template basename of the template to load + * @param http_status code to use on success + * @param ec error code to return + * @param detail optional text to add to the template + * @return #MHD_YES on success, #MHD_NO to just close the connection + */ +MHD_RESULT +TALER_TEMPLATING_reply_error (struct MHD_Connection *connection, + const char *template_basename, + unsigned int http_status, + enum TALER_ErrorCode ec, + const char *detail); + /** * Preload templates. * diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c index b047df7d..9e3cb571 100644 --- a/src/mhd/mhd_parsing.c +++ b/src/mhd/mhd_parsing.c @@ -364,7 +364,16 @@ TALER_MHD_check_content_length_ (struct MHD_Connection *connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH); if (NULL == cl) - return GNUNET_OK; + { + GNUNET_break_op (0); + return (MHD_YES == + TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MISSING, + MHD_HTTP_HEADER_CONTENT_LENGTH)) + ? GNUNET_NO + : GNUNET_SYSERR; + } if (1 != sscanf (cl, "%llu%c", &cv, diff --git a/src/templating/templating_api.c b/src/templating/templating_api.c index 324e199e..dba042e5 100644 --- a/src/templating/templating_api.c +++ b/src/templating/templating_api.c @@ -428,6 +428,45 @@ load_template (void *cls, } +MHD_RESULT +TALER_TEMPLATING_reply_error (struct MHD_Connection *connection, + const char *template_basename, + unsigned int http_status, + enum TALER_ErrorCode ec, + const char *detail) +{ + json_t *data; + enum GNUNET_GenericReturnValue ret; + + data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("ec", + ec), + GNUNET_JSON_pack_string ("hint", + TALER_ErrorCode_get_hint (ec)), + GNUNET_JSON_pack_string ("detail", + detail) + ); + ret = TALER_TEMPLATING_reply (connection, + http_status, + template_basename, + NULL, + NULL, + data); + json_decref (data); + switch (ret) + { + case GNUNET_OK: + return MHD_YES; + case GNUNET_NO: + return MHD_YES; + case GNUNET_SYSERR: + return MHD_NO; + } + GNUNET_assert (0); + return MHD_NO; +} + + enum GNUNET_GenericReturnValue TALER_TEMPLATING_init (const char *subsystem) { -- cgit v1.2.3 From 1639cefa617435ac4df5a8cd70c298aa1e1a820a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 6 May 2023 21:29:43 +0200 Subject: -doxygen --- contrib/gana | 2 +- src/include/taler_templating_lib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/include') diff --git a/contrib/gana b/contrib/gana index 4654d82b..e50e3767 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 4654d82b143cd69dfe7a7bf2f816f6f91f6052e2 +Subproject commit e50e37672fae7983fb5e934cd1d381b92648f7b6 diff --git a/src/include/taler_templating_lib.h b/src/include/taler_templating_lib.h index ebda2ecf..a4665a11 100644 --- a/src/include/taler_templating_lib.h +++ b/src/include/taler_templating_lib.h @@ -98,7 +98,7 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection, * http_status code. * * @param connection the connection we act upon - * @param template basename of the template to load + * @param template_basename basename of the template to load * @param http_status code to use on success * @param ec error code to return * @param detail optional text to add to the template -- cgit v1.2.3 From d1379e492de19070a8f7c2c3dba70f39fe956888 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 9 May 2023 14:11:21 +0200 Subject: -fix include --- src/include/taler_templating_lib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/include') diff --git a/src/include/taler_templating_lib.h b/src/include/taler_templating_lib.h index a4665a11..6af6db71 100644 --- a/src/include/taler_templating_lib.h +++ b/src/include/taler_templating_lib.h @@ -22,7 +22,7 @@ #define TALER_TEMPLATING_LIB_H #include - +#include "taler_mhd_lib.h" /** * Fill in Mustach template @a tmpl using the data from @a root -- cgit v1.2.3 From dc5b0fb0d35b9758f6eac7b0bd144db00eef7216 Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Tue, 9 May 2023 20:40:43 +0200 Subject: Fix age mask parsing from config - initialize age mask to zero - drop default bitstring for age mask, use string instead -remove default age mask bits, use string instead -strdup --- src/extensions/age_restriction/age_restriction.c | 6 +++--- src/include/taler_extensions.h | 4 ---- src/util/age_restriction.c | 3 +++ 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src/include') diff --git a/src/extensions/age_restriction/age_restriction.c b/src/extensions/age_restriction/age_restriction.c index 2d6d0cbd..481cb133 100644 --- a/src/extensions/age_restriction/age_restriction.c +++ b/src/extensions/age_restriction/age_restriction.c @@ -207,10 +207,10 @@ libtaler_extension_age_restriction_init (void *arg) return NULL; } - mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK; + if (NULL == groups) + groups = GNUNET_strdup (TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_GROUPS); - if ((groups != NULL) && - (GNUNET_OK != TALER_parse_age_group_string (groups, &mask))) + if (GNUNET_OK != TALER_parse_age_group_string (groups, &mask)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[age restriction] couldn't parse age groups: '%s'\n", diff --git a/src/include/taler_extensions.h b/src/include/taler_extensions.h index bd5b7248..75f22534 100644 --- a/src/include/taler_extensions.h +++ b/src/include/taler_extensions.h @@ -344,10 +344,6 @@ TALER_extensions_verify_manifests_signature ( * The default age mask represents the age groups * 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-20, 21-... */ -#define TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK (1 | 1 << 8 | 1 << 10 \ - | 1 << 12 | 1 << 14 \ - | 1 << 16 | 1 << 18 \ - | 1 << 21) #define TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_GROUPS "8:10:12:14:16:18:21" diff --git a/src/util/age_restriction.c b/src/util/age_restriction.c index beb68e5a..cf81d915 100644 --- a/src/util/age_restriction.c +++ b/src/util/age_restriction.c @@ -513,6 +513,9 @@ TALER_parse_age_group_string ( unsigned int val = 0; char c; + /* reset mask */ + mask->bits = 0; + while (*pos) { c = *pos++; -- cgit v1.2.3 From 1cf58e8ff8efc82f0e8bf1a058047d48b86e060e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 00:02:52 +0200 Subject: -fix warning --- src/include/taler_util.h | 10 ++++++++++ src/util/util.c | 6 ------ 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/include') diff --git a/src/include/taler_util.h b/src/include/taler_util.h index 8192ed87..6c294822 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -229,6 +229,16 @@ void TALER_OS_init (void); +/** + * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). + * + * @param[in,out] inp pointer to string to re-encode + * @return number of bytes in resulting @a inp + */ +size_t +TALER_rfc8785encode (char **inp); + + /** * URL-encode a string according to rfc3986. * diff --git a/src/util/util.c b/src/util/util.c index 7cd4b0c3..82c5f7f3 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -258,12 +258,6 @@ lowdump (struct GNUNET_Buffer *buf, } -/** - * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). - * - * @param[in,out] inp pointer to string to re-encode - * @return number of bytes in resulting @a inp - */ size_t TALER_rfc8785encode (char **inp) { -- cgit v1.2.3 From b15713f42e9ecbc67e9b8ffd178d97d08b7377bb Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 22:09:47 +0200 Subject: add helper logic for JSON2JSON conversion --- src/include/taler_util.h | 54 +++++- src/util/Makefile.am | 13 +- src/util/conversion.c | 402 ++++++++++++++++++++++++++++++++++++++++++++ src/util/test_conversion.c | 149 ++++++++++++++++ src/util/test_conversion.sh | 5 + 5 files changed, 621 insertions(+), 2 deletions(-) create mode 100644 src/util/conversion.c create mode 100644 src/util/test_conversion.c create mode 100755 src/util/test_conversion.sh (limited to 'src/include') diff --git a/src/include/taler_util.h b/src/include/taler_util.h index 6c294822..0b15eb8a 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 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 @@ -569,6 +569,58 @@ enum GNUNET_GenericReturnValue TALER_JSON_parse_age_groups (const json_t *root, struct TALER_AgeMask *mask); + +/** + * Handle to an external process that will assist + * with some JSON-to-JSON conversion. + */ +struct TALER_JSON_ExternalConversion; + +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure + * @param status_type how did the process die + * @apram code termination status code from the process + * @param result some JSON result, NULL if we failed to get an JSON output + */ +typedef void +(*TALER_JSON_JsonCallback) (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *result); + + +/** + * Launch some external helper @a binary to convert some @a input + * and eventually call @a cb with the result. + * + * @param input JSON to serialize and pass to the helper process + * @param cb function to call on the result + * @param cb_cls closure for @a cb + * @param binary name of the binary to execute + * @param ... NULL-terminated list of arguments for the @a binary, + * usually starting with again the name of the binary + * @return handle to cancel the operation (and kill the helper) + */ +struct TALER_JSON_ExternalConversion * +TALER_JSON_external_conversion_start (const json_t *input, + TALER_JSON_JsonCallback cb, + void *cb_cls, + const char *binary, + ...); + +/** + * Abort external conversion, killing the process and preventing + * the callback from being called. Must not be called after the + * callback was invoked. + * + * @param[in] ec external conversion handle to cancel + */ +void +TALER_JSON_external_conversion_stop ( + struct TALER_JSON_ExternalConversion *ec); + #undef __TALER_UTIL_LIB_H_INSIDE__ #endif diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 115ea505..9d1ec9d4 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -20,7 +20,8 @@ EXTRA_DIST = \ taler-config.in \ test_helper_eddsa.conf \ test_helper_rsa.conf \ - test_helper_cs.conf + test_helper_cs.conf \ + test_conversion.sh bin_PROGRAMS = \ taler-exchange-secmod-eddsa \ @@ -80,6 +81,7 @@ libtalerutil_la_SOURCES = \ aml_signatures.c \ auditor_signatures.c \ config.c \ + conversion.c \ crypto.c \ crypto_confirmation.c \ crypto_contract.c \ @@ -125,6 +127,7 @@ AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH= check_PROGRAMS = \ test_age_restriction \ test_amount \ + test_conversion \ test_crypto \ test_helper_eddsa \ test_helper_rsa \ @@ -141,6 +144,14 @@ test_age_restriction_LDADD = \ -lgnunetutil \ libtalerutil.la +test_conversion_SOURCES = \ + test_conversion.c +test_conversion_LDADD = \ + -lgnunetjson \ + -lgnunetutil \ + -ljansson \ + libtalerutil.la + test_amount_SOURCES = \ test_amount.c test_amount_LDADD = \ diff --git a/src/util/conversion.c b/src/util/conversion.c new file mode 100644 index 00000000..501ca014 --- /dev/null +++ b/src/util/conversion.c @@ -0,0 +1,402 @@ +/* + 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 +*/ +/** + * @file conversion.c + * @brief helper routines to run some external JSON-to-JSON converter + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include + + +struct TALER_JSON_ExternalConversion +{ + /** + * Callback to call with the result. + */ + TALER_JSON_JsonCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Handle to the helper process. + */ + struct GNUNET_OS_Process *helper; + + /** + * Pipe for the stdin of the @e helper. + */ + struct GNUNET_DISK_FileHandle *chld_stdin; + + /** + * Pipe for the stdout of the @e helper. + */ + struct GNUNET_DISK_FileHandle *chld_stdout; + + /** + * Handle to wait on the child to terminate. + */ + struct GNUNET_ChildWaitHandle *cwh; + + /** + * Task to read JSON output from the child. + */ + struct GNUNET_SCHEDULER_Task *read_task; + + /** + * Task to send JSON input to the child. + */ + struct GNUNET_SCHEDULER_Task *write_task; + + /** + * Buffer with data we need to send to the helper. + */ + void *write_buf; + + /** + * Buffer for reading data from the helper. + */ + void *read_buf; + + /** + * Total length of @e write_buf. + */ + size_t write_size; + + /** + * Current write position in @e write_buf. + */ + size_t write_pos; + + /** + * Current size of @a read_buf. + */ + size_t read_size; + + /** + * Current offset in @a read_buf. + */ + size_t read_pos; + +}; + + +/** + * Function called when we can read more data from + * the child process. + * + * @param cls our `struct TALER_JSON_ExternalConversion *` + */ +static void +read_cb (void *cls) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + + ec->read_task = NULL; + while (1) + { + ssize_t ret; + + if (ec->read_size == ec->read_pos) + { + /* Grow input buffer */ + size_t ns; + void *tmp; + + ns = GNUNET_MAX (2 * ec->read_size, + 1024); + if (ns > GNUNET_MAX_MALLOC_CHECKED) + ns = GNUNET_MAX_MALLOC_CHECKED; + if (ec->read_size == ns) + { + /* Helper returned more than 40 MB of data! Stop reading! */ + GNUNET_break (0); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + return; + } + tmp = GNUNET_malloc_large (ns); + if (NULL == tmp) + { + /* out of memory, also stop reading */ + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "malloc"); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + return; + } + GNUNET_memcpy (tmp, + ec->read_buf, + ec->read_pos); + GNUNET_free (ec->read_buf); + ec->read_buf = tmp; + ec->read_size = ns; + } + ret = GNUNET_DISK_file_read (ec->chld_stdout, + ec->read_buf, + ec->read_size - ec->read_pos); + if (ret < 0) + { + if ( (EAGAIN != errno) && + (EWOULDBLOCK != errno) && + (EINTR != errno) ) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "read"); + return; + } + break; + } + if (0 == ret) + { + /* regular end of stream, good! */ + return; + } + GNUNET_assert (ec->read_size >= ec->read_pos + ret); + ec->read_pos += ret; + } + ec->read_task + = GNUNET_SCHEDULER_add_read_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdout, + &read_cb, + ec); +} + + +/** + * Function called when we can write more data to + * the child process. + * + * @param cls our `struct TALER_JSON_ExternalConversion *` + */ +static void +write_cb (void *cls) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + ssize_t ret; + + ec->write_task = NULL; + while (ec->write_size > ec->write_pos) + { + ret = GNUNET_DISK_file_write (ec->chld_stdin, + ec->write_buf + ec->write_pos, + ec->write_size - ec->write_pos); + if (ret < 0) + { + if ( (EAGAIN != errno) && + (EINTR != errno) ) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + break; + } + if (0 == ret) + { + GNUNET_break (0); + break; + } + GNUNET_assert (ec->write_size >= ec->write_pos + ret); + ec->write_pos += ret; + } + if ( (ec->write_size > ec->write_pos) && + ( (EAGAIN == errno) || + (EWOULDBLOCK == errno) || + (EINTR == errno) ) ) + { + ec->write_task + = GNUNET_SCHEDULER_add_write_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdin, + &write_cb, + ec); + } + else + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + ec->chld_stdin = NULL; + } +} + + +/** + * Defines a GNUNET_ChildCompletedCallback which is sent back + * upon death or completion of a child process. + * + * @param cls handle for the callback + * @param type type of the process + * @param exit_code status code of the process + * + */ +static void +child_done_cb (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + json_t *j; + json_error_t err; + + ec->cwh = NULL; + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + /* We could get the process termination notification before having drained + the read buffer. So drain it now, just in case. */ + read_cb (ec); + } + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + ec->read_task = NULL; + } + GNUNET_OS_process_destroy (ec->helper); + ec->helper = NULL; + j = json_loadb (ec->read_buf, + ec->read_pos, + JSON_REJECT_DUPLICATES, + &err); + if (NULL == j) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse JSON from helper at %d: %s\n", + err.position, + err.text); + } + ec->cb (ec->cb_cls, + type, + exit_code, + j); + json_decref (j); + TALER_JSON_external_conversion_stop (ec); +} + + +struct TALER_JSON_ExternalConversion * +TALER_JSON_external_conversion_start (const json_t *input, + TALER_JSON_JsonCallback cb, + void *cb_cls, + const char *binary, + ...) +{ + struct TALER_JSON_ExternalConversion *ec; + struct GNUNET_DISK_PipeHandle *pipe_stdin; + struct GNUNET_DISK_PipeHandle *pipe_stdout; + va_list ap; + + ec = GNUNET_new (struct TALER_JSON_ExternalConversion); + ec->cb = cb; + ec->cb_cls = cb_cls; + pipe_stdin = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_READ); + GNUNET_assert (NULL != pipe_stdin); + pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_WRITE); + GNUNET_assert (NULL != pipe_stdout); + va_start (ap, + binary); + ec->helper = GNUNET_OS_start_process_va (GNUNET_OS_INHERIT_STD_ERR, + pipe_stdin, + pipe_stdout, + NULL, + binary, + ap); + va_end (ap); + if (NULL == ec->helper) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to run conversion helper `%s'\n", + binary); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdin)); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdout)); + GNUNET_free (ec); + return NULL; + } + ec->chld_stdin = + GNUNET_DISK_pipe_detach_end (pipe_stdin, + GNUNET_DISK_PIPE_END_WRITE); + ec->chld_stdout = + GNUNET_DISK_pipe_detach_end (pipe_stdout, + GNUNET_DISK_PIPE_END_READ); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdin)); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdout)); + ec->write_buf = json_dumps (input, JSON_COMPACT); + ec->write_size = strlen (ec->write_buf); + ec->read_task + = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdout, + &read_cb, + ec); + ec->write_task + = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdin, + &write_cb, + ec); + ec->cwh = GNUNET_wait_child (ec->helper, + &child_done_cb, + ec); + return ec; +} + + +void +TALER_JSON_external_conversion_stop ( + struct TALER_JSON_ExternalConversion *ec) +{ + if (NULL != ec->cwh) + { + GNUNET_wait_child_cancel (ec->cwh); + ec->cwh = NULL; + } + if (NULL != ec->helper) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ec->helper, + SIGKILL)); + GNUNET_OS_process_destroy (ec->helper); + } + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + ec->read_task = NULL; + } + if (NULL != ec->write_task) + { + GNUNET_SCHEDULER_cancel (ec->write_task); + ec->write_task = NULL; + } + if (NULL != ec->chld_stdin) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + ec->chld_stdin = NULL; + } + if (NULL != ec->chld_stdout) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdout)); + ec->chld_stdout = NULL; + } + GNUNET_free (ec->read_buf); + free (ec->write_buf); + GNUNET_free (ec); +} diff --git a/src/util/test_conversion.c b/src/util/test_conversion.c new file mode 100644 index 00000000..00cb35e7 --- /dev/null +++ b/src/util/test_conversion.c @@ -0,0 +1,149 @@ +/* + This file is part of TALER + (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 +*/ +/** + * @file util/test_conversion.c + * @brief Tests for conversion logic + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include + +/** + * Return value from main(). + */ +static int global_ret; + +/** + * Handle to our helper. + */ +static struct TALER_JSON_ExternalConversion *ec; + + +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure + * @param status_type how did the process die + * @apram code termination status code from the process + * @param result some JSON result, NULL if we failed to get an JSON output + */ +static void +conv_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *result) +{ + json_t *expect; + + (void) cls; + (void) status_type; + ec = NULL; + global_ret = 3; + if (42 != code) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected return value from helper: %u\n", + (unsigned int) code); + return; + } + expect = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("foo", + "arg") + ); + if (1 == json_equal (expect, + result)) + { + global_ret = 0; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected JSON result\n"); + json_dumpf (result, + stderr, + JSON_INDENT (2)); + global_ret = 4; + } + json_decref (expect); +} + + +/** + * Function called on shutdown/CTRL-C. + * + * @param cls NULL + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + if (NULL != ec) + { + GNUNET_break (0); + global_ret = 2; + TALER_JSON_external_conversion_stop (ec); + ec = NULL; + } +} + + +/** + * Main test function. + * + * @param cls NULL + */ +static void +run (void *cls) +{ + json_t *input; + + (void) cls; + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + input = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("key", + "foo") + ); + ec = TALER_JSON_external_conversion_start (input, + &conv_cb, + NULL, + "./test_conversion.sh", + "test_conversion.sh", + "arg", + NULL); + json_decref (input); + GNUNET_assert (NULL != ec); +} + + +int +main (int argc, + const char *const argv[]) +{ + (void) argc; + (void) argv; + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-conversion", + "WARNING", + NULL); + GNUNET_OS_init (TALER_project_data_default ()); + global_ret = 1; + GNUNET_SCHEDULER_run (&run, + NULL); + return global_ret; +} diff --git a/src/util/test_conversion.sh b/src/util/test_conversion.sh new file mode 100755 index 00000000..26e1a36d --- /dev/null +++ b/src/util/test_conversion.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +KEY=$(jq -r .key) +echo -n "{\"$KEY\":\"$1\"}" +exit 42 -- cgit v1.2.3 From 0dd0fff17d0802f48bfab0bac498968abc8a59cf Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 10 May 2023 22:13:18 +0200 Subject: -typo --- src/include/taler_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/include') diff --git a/src/include/taler_util.h b/src/include/taler_util.h index 0b15eb8a..1de264c1 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -581,7 +581,7 @@ struct TALER_JSON_ExternalConversion; * * @param cls closure * @param status_type how did the process die - * @apram code termination status code from the process + * @param code termination status code from the process * @param result some JSON result, NULL if we failed to get an JSON output */ typedef void -- cgit v1.2.3