diff --git a/contrib/gana b/contrib/gana index 0e7707e44..1cfd50974 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 0e7707e441874b8aca9801b389d47003ac7a8f73 +Subproject commit 1cfd50974f6e01dee0302b7918c18cc2b06edf71 diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index 3a929be06..0fbdb8e80 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -112,6 +112,7 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_refund.c taler-exchange-httpd_refund.h \ taler-exchange-httpd_reserves_get.c taler-exchange-httpd_reserves_get.h \ taler-exchange-httpd_reserves_history.c taler-exchange-httpd_reserves_history.h \ + taler-exchange-httpd_reserves_purse.c taler-exchange-httpd_reserves_purse.h \ taler-exchange-httpd_reserves_status.c taler-exchange-httpd_reserves_status.h \ taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \ taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \ diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 0ce5add33..7ca56e104 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -393,7 +393,7 @@ TEH_handler_deposit (struct MHD_Connection *connection, TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID, NULL); } @@ -427,7 +427,7 @@ TEH_handler_deposit (struct MHD_Connection *connection, TALER_LOG_WARNING ("Invalid signature on /deposit request\n"); GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID, NULL); } diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c index 8bc2ac196..4a96d4c81 100644 --- a/src/exchange/taler-exchange-httpd_kyc-check.c +++ b/src/exchange/taler-exchange-httpd_kyc-check.c @@ -362,7 +362,7 @@ TEH_handler_kyc_check ( (unsigned long long) kyp->kyc.payment_target_uuid); GNUNET_break_op (0); return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED, "h_payto"); } diff --git a/src/exchange/taler-exchange-httpd_metrics.h b/src/exchange/taler-exchange-httpd_metrics.h index 4fef6464a..ac9e5b505 100644 --- a/src/exchange/taler-exchange-httpd_metrics.h +++ b/src/exchange/taler-exchange-httpd_metrics.h @@ -37,7 +37,8 @@ enum TEH_MetricTypeRequest TEH_MT_REQUEST_MELT = 3, TEH_MT_REQUEST_PURSE_CREATE = 4, TEH_MT_REQUEST_PURSE_MERGE = 5, - TEH_MT_REQUEST_COUNT = 6 /* MUST BE LAST! */ + TEH_MT_REQUEST_RESERVE_PURSE = 6, + TEH_MT_REQUEST_COUNT = 7 /* MUST BE LAST! */ }; /** diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c index 4ea8b7d2d..f4f00bb23 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.c +++ b/src/exchange/taler-exchange-httpd_purses_create.c @@ -500,7 +500,7 @@ parse_coin (struct MHD_Connection *connection, GNUNET_JSON_parse_free (spec); return (MHD_YES == TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID, TEH_base_url)) ? GNUNET_NO : GNUNET_SYSERR; @@ -613,7 +613,7 @@ parse_coin (struct MHD_Connection *connection, GNUNET_JSON_parse_free (spec); return (MHD_YES == TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID, NULL)) ? GNUNET_NO : GNUNET_SYSERR; @@ -816,7 +816,7 @@ TEH_handler_purses_create ( GNUNET_JSON_parse_free (spec); GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID, NULL); } @@ -832,7 +832,7 @@ TEH_handler_purses_create ( GNUNET_JSON_parse_free (spec); GNUNET_free (pcc.coins); return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_PURSE_ECONTRACT_SIGNATURE_INVALID, NULL); } diff --git a/src/exchange/taler-exchange-httpd_purses_create.h b/src/exchange/taler-exchange-httpd_purses_create.h index 4dfbabf9b..7ccba1446 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.h +++ b/src/exchange/taler-exchange-httpd_purses_create.h @@ -36,12 +36,12 @@ * @param purse_pub public key of the purse * @param root uploaded JSON data * @return MHD result code - */ + */ MHD_RESULT -TEH_handler_purses_create (struct MHD_Connection *connection, - const struct - TALER_PurseContractPublicKeyP *purse_pub, - const json_t *root); +TEH_handler_purses_create ( + struct MHD_Connection *connection, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const json_t *root); #endif diff --git a/src/exchange/taler-exchange-httpd_reserves_purse.c b/src/exchange/taler-exchange-httpd_reserves_purse.c index 620e83fc1..442e5a168 100644 --- a/src/exchange/taler-exchange-httpd_reserves_purse.c +++ b/src/exchange/taler-exchange-httpd_reserves_purse.c @@ -55,11 +55,21 @@ struct ReservePurseContext */ struct TALER_Amount amount; + /** + * Total amount already put into the purse. + */ + struct TALER_Amount deposit_total; + /** * When should the purse expire. */ struct GNUNET_TIME_Timestamp purse_expiration; + /** + * Merge time. + */ + struct GNUNET_TIME_Timestamp merge_timestamp; + /** * Our current time. */ @@ -133,13 +143,13 @@ reply_purse_success (struct MHD_Connection *connection, enum TALER_ErrorCode ec; if (TALER_EC_NONE != - (ec = TALER_exchange_online_purse_pursed_sign ( + (ec = TALER_exchange_online_purse_created_sign ( &TEH_keys_exchange_sign_, rpc->exchange_timestamp, rpc->purse_expiration, &rpc->amount, &rpc->deposit_total, - rpc->purse_pub, + &rpc->purse_pub, &rpc->merge_pub, &rpc->h_contract_terms, &pub, @@ -223,7 +233,7 @@ purse_transaction (void *cls, TEH_plugin->rollback (TEH_plugin->cls); qs = TEH_plugin->select_purse_request (TEH_plugin->cls, - rpc->purse_pub, + &rpc->purse_pub, &merge_pub, &purse_expiration, &h_contract_terms, @@ -246,7 +256,7 @@ purse_transaction (void *cls, connection, MHD_HTTP_CONFLICT, TALER_JSON_pack_ec ( - TALER_EC_EXCHANGE_PURSE_PURSE_CONFLICTING_META_DATA), + TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA), TALER_JSON_pack_amount ("amount", &target_amount), GNUNET_JSON_pack_uint64 ("min_age", @@ -268,7 +278,7 @@ purse_transaction (void *cls, /* 3) if present, persist contract */ in_conflict = true; qs = TEH_plugin->insert_contract (TEH_plugin->cls, - rpc->purse_pub, + &rpc->purse_pub, &rpc->contract_pub, rpc->econtract_size, rpc->econtract, @@ -294,7 +304,7 @@ purse_transaction (void *cls, struct GNUNET_HashCode h_econtract; qs = TEH_plugin->select_contract_by_purse (TEH_plugin->cls, - rpc->purse_pub, + &rpc->purse_pub, &pub_ckey, &econtract_sig, &econtract_size, @@ -343,9 +353,6 @@ TEH_handler_reserves_purse ( .reserve_pub = reserve_pub, .exchange_timestamp = GNUNET_TIME_timestamp_get () }; - json_t *deposits; - json_t *deposit; - unsigned int idx; struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount ("purse_value", TEH_currency, @@ -413,7 +420,7 @@ TEH_handler_reserves_purse ( GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_PURSE_PURSE_EXPIRATION_BEFORE_NOW, + TALER_EC_EXCHANGE_RESERVES_PURSE_EXPIRATION_BEFORE_NOW, NULL); } if (GNUNET_TIME_absolute_is_never (rpc.purse_expiration.abs_time)) @@ -422,7 +429,7 @@ TEH_handler_reserves_purse ( GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, - TALER_EC_EXCHANGE_PURSE_PURSE_EXPIRATION_IS_NEVER, + TALER_EC_EXCHANGE_RESERVES_PURSE_EXPIRATION_IS_NEVER, NULL); } gf = TEH_keys_global_fee_by_time (TEH_keys_get_state (), @@ -444,19 +451,19 @@ TEH_handler_reserves_purse ( &rpc.merge_pub, rpc.min_age, &rpc.amount, - rpc.purse_pub, + &rpc.purse_pub, &rpc.purse_sig)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - GNUNET_free (rpc.coins); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, - TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID, - NULL); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID, + NULL); } if (GNUNET_OK != - TALER_wallet_purse_merge_verify ("FIXME exchange_url", + TALER_wallet_purse_merge_verify (TEH_base_url, rpc.merge_timestamp, &rpc.purse_pub, &rpc.merge_pub, @@ -464,43 +471,42 @@ TEH_handler_reserves_purse ( { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - GNUNET_free (rpc.coins); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, - TALER_EC_EXCHANGE_PURSE_MERGE_SIGNATURE_INVALID, - NULL); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_EXCHANGE_RESERVES_PURSE_MERGE_SIGNATURE_INVALID, + NULL); } if (GNUNET_OK != TALER_wallet_account_merge_verify (rpc.merge_timestamp, &rpc.purse_pub, rpc.purse_expiration, &rpc.h_contract_terms, - &rpc.purse_value, + &rpc.amount, rpc.min_age, rpc.reserve_pub, &rpc.reserve_sig)) { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - GNUNET_free (rpc.coins); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, - TALER_EC_EXCHANGE_RESERVE_MERGE_SIGNATURE_INVALID, - NULL); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_EXCHANGE_RESERVES_PURSE_MERGE_SIGNATURE_INVALID, + NULL); } if ( (NULL != rpc.econtract) && (GNUNET_OK != TALER_wallet_econtract_upload_verify (rpc.econtract, rpc.econtract_size, &rpc.contract_pub, - purse_pub, + &rpc.purse_pub, &rpc.econtract_sig)) ) { TALER_LOG_WARNING ("Invalid signature on /reserves/$PID/purse request\n"); GNUNET_JSON_parse_free (spec); - GNUNET_free (rpc.coins); return TALER_MHD_reply_with_error (connection, - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, TALER_EC_EXCHANGE_PURSE_ECONTRACT_SIGNATURE_INVALID, NULL); } @@ -511,7 +517,6 @@ TEH_handler_reserves_purse ( { GNUNET_break (0); GNUNET_JSON_parse_free (spec); - GNUNET_free (rpc.coins); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_START_FAILED, @@ -525,13 +530,12 @@ TEH_handler_reserves_purse ( if (GNUNET_OK != TEH_DB_run_transaction (connection, "execute purse purse", - TEH_MT_REQUEST_PURSE_PURSE, + TEH_MT_REQUEST_RESERVE_PURSE, &mhd_ret, &purse_transaction, &rpc)) { GNUNET_JSON_parse_free (spec); - GNUNET_free (rpc.coins); return mhd_ret; } } diff --git a/src/exchange/taler-exchange-httpd_reserves_purse.h b/src/exchange/taler-exchange-httpd_reserves_purse.h new file mode 100644 index 000000000..0704d1d32 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_reserves_purse.h @@ -0,0 +1,46 @@ +/* + 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 Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see +*/ +/** + * @file taler-exchange-httpd_reserves_purse.h + * @brief Handle /reserves/$RID/purse requests + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_RESERVES_PURSE_H +#define TALER_EXCHANGE_HTTPD_RESERVES_PURSE_H + +#include +#include +#include "taler-exchange-httpd.h" + + +/** + * Handle a "/purses/$PURSE_PUB/create" request. Parses the JSON, and, if + * successful, passes the JSON data to #create_transaction() to further check + * the details of the operation specified. If everything checks out, this + * will ultimately lead to the "purses create" being executed, or rejected. + * + * @param connection the MHD connection to handle + * @param purse_pub public key of the purse + * @param root uploaded JSON data + * @return MHD result code + */ +MHD_RESULT +TEH_handler_reserves_purse ( + struct MHD_Connection *connection, + const struct TALER_ReservePublicKeyP *reserve_pub, + const json_t *root); + +#endif diff --git a/src/lib/exchange_api_kyc_check.c b/src/lib/exchange_api_kyc_check.c index 1f9f3b160..62a1db582 100644 --- a/src/lib/exchange_api_kyc_check.c +++ b/src/lib/exchange_api_kyc_check.c @@ -178,7 +178,7 @@ handle_kyc_check_finished (void *cls, /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ break; - case MHD_HTTP_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: ks.ec = TALER_JSON_get_error_code (j); break; case MHD_HTTP_NOT_FOUND: diff --git a/src/lib/exchange_api_kyc_wallet.c b/src/lib/exchange_api_kyc_wallet.c index 7a78ceb24..fe5e6b702 100644 --- a/src/lib/exchange_api_kyc_wallet.c +++ b/src/lib/exchange_api_kyc_wallet.c @@ -122,7 +122,7 @@ handle_kyc_wallet_finished (void *cls, /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ break; - case MHD_HTTP_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: ks.ec = TALER_JSON_get_error_code (j); break; case MHD_HTTP_NOT_FOUND: diff --git a/src/lib/exchange_api_purse_create_with_merge.c b/src/lib/exchange_api_purse_create_with_merge.c index e37eea2e1..03accce10 100644 --- a/src/lib/exchange_api_purse_create_with_merge.c +++ b/src/lib/exchange_api_purse_create_with_merge.c @@ -427,7 +427,7 @@ TALER_EXCHANGE_purse_create_with_merge ( void -TALER_EXCHANGE_account_create_with_merge_cancel ( +TALER_EXCHANGE_purse_create_with_merge_cancel ( struct TALER_EXCHANGE_PurseCreateMergeHandle *pcm) { if (NULL != pcm->job)