diff --git a/contrib/gana b/contrib/gana index f794cafbc..f2babbbdd 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit f794cafbc16ce0eae2826695235275e1e16c64db +Subproject commit f2babbbdd477eeafb17292e16f335226ea02cb6a diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index 949a1dcba..3a929be06 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -79,6 +79,7 @@ taler_exchange_transfer_LDADD = \ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd.c taler-exchange-httpd.h \ taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \ + taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \ taler-exchange-httpd_csr.c taler-exchange-httpd_csr \ taler-exchange-httpd_db.c taler-exchange-httpd_db.h \ taler-exchange-httpd_deposit.c taler-exchange-httpd_deposit.h \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index 1f7f699c7..aa3a7c412 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-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 @@ -30,6 +30,7 @@ #include #include "taler_mhd_lib.h" #include "taler-exchange-httpd_auditors.h" +#include "taler-exchange-httpd_contract.h" #include "taler-exchange-httpd_csr.h" #include "taler-exchange-httpd_deposit.h" #include "taler-exchange-httpd_deposits_get.h" @@ -1067,6 +1068,13 @@ handle_mhd_request (void *cls, .handler.get = &TEH_handler_deposits_get, .nargs = 4 }, + /* Getting purse contracts */ + { + .url = "contracts", + .method = MHD_HTTP_METHOD_GET, + .handler.get = &TEH_handler_contracts_get, + .nargs = 1 + }, /* KYC endpoints */ { .url = "kyc-check", diff --git a/src/exchange/taler-exchange-httpd_contract.c b/src/exchange/taler-exchange-httpd_contract.c new file mode 100644 index 000000000..defb7816d --- /dev/null +++ b/src/exchange/taler-exchange-httpd_contract.c @@ -0,0 +1,99 @@ +/* + 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_contract.c + * @brief Handle GET /contracts/$C_PUB requests + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include +#include "taler_mhd_lib.h" +#include "taler-exchange-httpd_contract.h" +#include "taler-exchange-httpd_mhd.h" +#include "taler-exchange-httpd_responses.h" + + +MHD_RESULT +TEH_handler_contracts_get (struct TEH_RequestContext *rc, + const char *const args[1]) +{ + struct TALER_ContractDiffiePublicP contract_pub; + struct TALER_PurseContractPublicKeyP purse_pub; + void *econtract; + size_t econtract_size; + enum GNUNET_DB_QueryStatus qs; + struct TALER_PurseContractSignatureP econtract_sig; + MHD_RESULT res; + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (args[0], + strlen (args[0]), + &contract_pub, + sizeof (contract_pub))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_EXCHANGE_CONTRACTS_INVALID_CONTRACT_PUB, + args[0]); + } + + qs = TEH_plugin->select_contract (TEH_plugin->cls, + &contract_pub, + &purse_pub, + &econtract_sig, + &econtract_size, + &econtract); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "select_contract"); + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "select_contract"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_EXCHANGE_CONTRACTS_UNKNOWN, + NULL); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; /* handled below */ + } + res = TALER_MHD_REPLY_JSON_PACK ( + rc->connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_data_auto ("purse_pub", + &purse_pub), + GNUNET_JSON_pack_data_auto ("econtract_sig", + &econtract_sig), + GNUNET_JSON_pack_data_varsize ("econtract", + econtract, + econtract_size)); + GNUNET_free (econtract); + return res; +} + + +/* end of taler-exchange-httpd_contract.c */ diff --git a/src/exchange/taler-exchange-httpd_contract.h b/src/exchange/taler-exchange-httpd_contract.h new file mode 100644 index 000000000..dac6b81e3 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_contract.h @@ -0,0 +1,44 @@ +/* + 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_contract.h + * @brief Handle /coins/$COIN_PUB/contract requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_CONTRACT_H +#define TALER_EXCHANGE_HTTPD_CONTRACT_H + +#include +#include +#include "taler-exchange-httpd.h" + + +/** + * Handle a GET "/contracts/$C_PUB" request. Returns the + * encrypted contract. + * + * @param rc request context + * @param args array of additional options (length: 1, first is the contract_pub) + * @return MHD result code + */ +MHD_RESULT +TEH_handler_contracts_get (struct TEH_RequestContext *rc, + const char *const args[1]); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c index 00bb1d1e7..4ea8b7d2d 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.c +++ b/src/exchange/taler-exchange-httpd_purses_create.c @@ -404,12 +404,12 @@ create_transaction (void *cls, void *econtract; struct GNUNET_HashCode h_econtract; - qs = TEH_plugin->select_contract (TEH_plugin->cls, - pcc->purse_pub, - &pub_ckey, - &econtract_sig, - &econtract_size, - &econtract); + qs = TEH_plugin->select_contract_by_purse (TEH_plugin->cls, + pcc->purse_pub, + &pub_ckey, + &econtract_sig, + &econtract_size, + &econtract); if (qs <= 0) { if (GNUNET_DB_STATUS_SOFT_ERROR == qs) diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 47ac6ad25..b79c8dd89 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -3429,9 +3429,19 @@ prepare_statements (struct PostgresClosure *pg) GNUNET_PQ_make_prepare ( "select_contract", "SELECT " + " purse_pub" + ",e_contract" + ",contract_sig" + " FROM contracts" + " WHERE pub_ckey=$1;", + 1), + /* Used in #postgres_select_contract_by_purse */ + GNUNET_PQ_make_prepare ( + "select_contract_by_purse", + "SELECT " " pub_ckey" ",e_contract" - // ",econtract_sig" + ",contract_sig" " FROM contracts" " WHERE purse_pub=$1;", 1), @@ -12997,14 +13007,58 @@ postgres_insert_partner (void *cls, */ static enum GNUNET_DB_QueryStatus postgres_select_contract (void *cls, - const struct TALER_PurseContractPublicKeyP *purse_pub, - struct TALER_ContractDiffiePublicP *pub_ckey, + const struct TALER_ContractDiffiePublicP *pub_ckey, + struct TALER_PurseContractPublicKeyP *purse_pub, struct TALER_PurseContractSignatureP *econtract_sig, size_t *econtract_size, void **econtract) { struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (pub_ckey), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("purse_pub", + purse_pub), + GNUNET_PQ_result_spec_auto_from_type ("contract_sig", + econtract_sig), + GNUNET_PQ_result_spec_variable_size ("econtract", + econtract, + econtract_size), + GNUNET_PQ_result_spec_end + }; + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "select_contract", + params, + rs); + +} + + +/** + * Function called to retrieve an encrypted contract. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param purse_pub key to lookup the contract by + * @param[out] pub_ckey set to the ephemeral DH used to encrypt the contract + * @param[out] econtract_sig set to the signature over the encrypted contract + * @param[out] econtract_size set to the number of bytes in @a econtract + * @param[out] econtract set to the encrypted contract on success, to be freed by the caller + * @return transaction status code + */ +static enum GNUNET_DB_QueryStatus +postgres_select_contract_by_purse (void *cls, + const struct + TALER_PurseContractPublicKeyP *purse_pub, + struct TALER_ContractDiffiePublicP *pub_ckey, + struct TALER_PurseContractSignatureP * + econtract_sig, + size_t *econtract_size, + void **econtract) +{ + struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (purse_pub), GNUNET_PQ_query_param_end @@ -13019,8 +13073,9 @@ postgres_select_contract (void *cls, econtract_size), GNUNET_PQ_result_spec_end }; + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "select_contract", + "select_contract_by_purse", params, rs); @@ -13075,12 +13130,12 @@ postgres_insert_contract ( size_t econtract_size2; void *econtract2; - qs = postgres_select_contract (pg, - purse_pub, - &pub_ckey2, - &esig2, - &econtract_size2, - &econtract2); + qs = postgres_select_contract_by_purse (pg, + purse_pub, + &pub_ckey2, + &esig2, + &econtract_size2, + &econtract2); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { GNUNET_break (0); @@ -13797,6 +13852,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_insert_contract; plugin->select_contract = &postgres_select_contract; + plugin->select_contract_by_purse + = &postgres_select_contract_by_purse; plugin->insert_purse_request = &postgres_insert_purse_request; plugin->select_purse_request diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index c065f581f..39fa2ecdf 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4443,6 +4443,26 @@ struct TALER_EXCHANGEDB_Plugin bool *in_conflict); + /** + * Function called to retrieve an encrypted contract. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param pub_ckey set to the ephemeral DH used to encrypt the contract, key used to lookup the contract by + * @param[out] purse_pub public key of the purse of the contract + * @param[out] econtract_sig set to the signature over the encrypted contract + * @param[out] econtract_size set to the number of bytes in @a econtract + * @param[out] econtract set to the encrypted contract on success, to be freed by the caller + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*select_contract)( + void *cls, + const struct TALER_ContractDiffiePublicP *pub_ckey, + struct TALER_PurseContractPublicKeyP *purse_pub, + struct TALER_PurseContractSignatureP *econtract_sig, + size_t *econtract_size, + void **econtract); + /** * Function called to retrieve an encrypted contract. * @@ -4455,12 +4475,13 @@ struct TALER_EXCHANGEDB_Plugin * @return transaction status code */ enum GNUNET_DB_QueryStatus - (*select_contract)(void *cls, - const struct TALER_PurseContractPublicKeyP *purse_pub, - struct TALER_ContractDiffiePublicP *pub_ckey, - struct TALER_PurseContractSignatureP *econtract_sig, - size_t *econtract_size, - void **econtract); + (*select_contract_by_purse)( + void *cls, + const struct TALER_PurseContractPublicKeyP *purse_pub, + struct TALER_ContractDiffiePublicP *pub_ckey, + struct TALER_PurseContractSignatureP *econtract_sig, + size_t *econtract_size, + void **econtract); /**