From 4e3b133e47e2549682209feca61590f7e8fcd0ac Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 17 Oct 2021 14:12:13 +0200 Subject: [PATCH] -incomplete draft for /kyc-wallet handler --- contrib/gana | 2 +- debian/.gitignore | 1 + src/exchange/Makefile.am | 1 + src/exchange/taler-exchange-httpd.c | 1 + .../taler-exchange-httpd_kyc-wallet.c | 151 ++++++++++++++++++ .../taler-exchange-httpd_kyc-wallet.h | 43 +++++ src/exchangedb/plugin_exchangedb_postgres.c | 76 +++++++++ src/include/taler_exchangedb_plugin.h | 16 ++ src/include/taler_signatures.h | 2 +- 9 files changed, 291 insertions(+), 2 deletions(-) create mode 100644 src/exchange/taler-exchange-httpd_kyc-wallet.c create mode 100644 src/exchange/taler-exchange-httpd_kyc-wallet.h diff --git a/contrib/gana b/contrib/gana index 0272caa8f..ca56accac 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 0272caa8ff8ee7553d035d29fb19d01866df43e4 +Subproject commit ca56accac72b6ce050a38d36172390b14100a538 diff --git a/debian/.gitignore b/debian/.gitignore index 5671f21f6..f3ddfd1d2 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -20,3 +20,4 @@ taler-auditor/ taler-exchange.postrm.debhelper *.debhelper *.substvars +taler-exchange-offline diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index 1f53b0123..a0fe1c201 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -83,6 +83,7 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_deposit.c taler-exchange-httpd_deposit.h \ taler-exchange-httpd_deposits_get.c taler-exchange-httpd_deposits_get.h \ taler-exchange-httpd_keys.c taler-exchange-httpd_keys.h \ + taler-exchange-httpd_kyc-wallet.c taler-exchange-httpd_kyc-wallet.h \ taler-exchange-httpd_link.c taler-exchange-httpd_link.h \ taler-exchange-httpd_management.h \ taler-exchange-httpd_management_auditors.c \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index e9aa94c0a..7386a8a45 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -33,6 +33,7 @@ #include "taler-exchange-httpd_deposit.h" #include "taler-exchange-httpd_deposits_get.h" #include "taler-exchange-httpd_keys.h" +#include "taler-exchange-httpd_kyc-wallet.h" #include "taler-exchange-httpd_link.h" #include "taler-exchange-httpd_management.h" #include "taler-exchange-httpd_melt.h" diff --git a/src/exchange/taler-exchange-httpd_kyc-wallet.c b/src/exchange/taler-exchange-httpd_kyc-wallet.c new file mode 100644 index 000000000..84eb28fa5 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_kyc-wallet.c @@ -0,0 +1,151 @@ +/* + This file is part of TALER + Copyright (C) 2021 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_kyc-wallet.c + * @brief Handle request for wallet for KYC check. + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include +#include +#include +#include "taler_json_lib.h" +#include "taler_mhd_lib.h" +#include "taler-exchange-httpd_kyc-wallet.h" +#include "taler-exchange-httpd_responses.h" + + +/** + * Context for the request. + */ +struct KycRequestContext +{ + /** + * Public key of the reserve/wallet this is about. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Current KYC status. + */ + struct TALER_EXCHANGEDB_KycStatus kyc; +}; + + +/** + * Function implementing database transaction to check wallet's KYC status. + * Runs the transaction logic; IF it returns a non-error code, the transaction + * logic MUST NOT queue a MHD response. IF it returns an hard error, the + * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it + * returns the soft error code, the function MAY be called again to retry and + * MUST not queue a MHD response. + * + * @param cls closure with a `struct KycRequestContext *` + * @param connection MHD request which triggered the transaction + * @param[out] mhd_ret set to MHD response status for @a connection, + * if transaction failed (!) + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +wallet_kyc_check (void *cls, + struct MHD_Connection *connection, + MHD_RESULT *mhd_ret) +{ + struct KycRequestContext *krc = cls; + enum GNUNET_DB_QueryStatus qs; + + qs = TEH_plugin->inselect_wallet_kyc_status (TEH_plugin->cls, + &krc->reserve_pub, + &krc->kyc); + if (qs < 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + GNUNET_break (0); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "inselect_wallet_status"); + return qs; + } + return qs; +} + + +MHD_RESULT +TEH_handler_kyc_wallet ( + struct MHD_Connection *connection, + const json_t *root) +{ + struct TALER_ReserveSignatureP reserve_sig; + struct KycRequestContext krc; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("reserve_sig", + &reserve_sig), + GNUNET_JSON_spec_fixed_auto ("reserve_pub", + &krc.reserve_pub), + GNUNET_JSON_spec_end () + }; + MHD_RESULT res; + enum GNUNET_GenericReturnValue ret; + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP) + }; + + ret = TALER_MHD_parse_json_data (connection, + root, + spec); + if (GNUNET_SYSERR == ret) + return MHD_NO; /* hard failure */ + if (GNUNET_NO == ret) + return MHD_YES; /* failure */ + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP, + &purpose, + &reserve_sig.eddsa_signature, + &krc.reserve_pub.eddsa_pub)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_EXCHANGE_KYC_WALLET_SIGNATURE_INVALID, + NULL); + } + + ret = TEH_DB_run_transaction (connection, + "check wallet kyc", + &res, + &wallet_kyc_check, + &krc); + if (GNUNET_SYSERR == ret) + return res; + + // FIXME: act on krc.kyc! + return TALER_MHD_reply_static ( + connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +/* end of taler-exchange-httpd_kyc-wallet.c */ diff --git a/src/exchange/taler-exchange-httpd_kyc-wallet.h b/src/exchange/taler-exchange-httpd_kyc-wallet.h new file mode 100644 index 000000000..70ac50949 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_kyc-wallet.h @@ -0,0 +1,43 @@ +/* + This file is part of TALER + Copyright (C) 2021 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_kyc-wallet.h + * @brief Handle /kyc-wallet requests + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_KYC_WALLET_H +#define TALER_EXCHANGE_HTTPD_KYC_WALLET_H + +#include +#include "taler-exchange-httpd.h" + + +/** + * Handle a "/kyc-wallet" request. Parses the "reserve_pub" EdDSA key of the + * reserve and the signature "reserve_sig" which affirms the operation. If OK, + * a KYC record is created (if missing) and the KYC status returned. + * + * @param connection request to handle + * @param root uploaded JSON data + * @return MHD result code + */ +MHD_RESULT +TEH_handler_kyc_wallet ( + struct MHD_Connection *connection, + const json_t *root); + + +#endif diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 54a03dce9..b4738ef4a 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -369,6 +369,23 @@ prepare_statements (struct PostgresClosure *pg) " WHERE payto_uri=$1" " LIMIT 1;", 1), + /* Used in #postgres_inselect_wallet_kyc_status() */ + // FIXME: Note that this statement has not been debugged at all... + // It just represents the _idea_. + GNUNET_PQ_make_prepare ("inselect_wallet_kyc_status", + "INSERT INTO wire_targets" + "(payto_uri" + ") VALUES " + "($1)" + " ON CONFLICT (wire_target_serial_id) DO " + " (SELECT " + " kyc_ok" + " ,wire_target_serial_id" + " )" + " RETURNING " + " FALSE AS kyc_ok" + " wire_target_serial_id;", + 1), #endif /* Used in #reserves_get() */ GNUNET_PQ_make_prepare ("reserves_get", @@ -3542,12 +3559,15 @@ postgres_get_kyc_status (void *cls, const char *payto_uri, struct TALER_EXCHANGEDB_KycStatus *kyc) { +#if FIXME_DD23 struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (payto_uri), GNUNET_PQ_query_param_end }; +#endif uint8_t ok8; +#if FIXME_DD23 struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_uint64 ("payment_target_uuid", &kyc->payment_target_uuid), @@ -3555,6 +3575,7 @@ postgres_get_kyc_status (void *cls, &ok8), GNUNET_PQ_result_spec_end }; +#endif enum GNUNET_DB_QueryStatus qs; #if FIXME_DD23 @@ -3573,6 +3594,60 @@ postgres_get_kyc_status (void *cls, } +/** + * Get the KYC status for a wallet. If the status is unknown, + * inserts a new status record (hence INsertSELECT). + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param reserve_pub public key of the wallet + * @param[out] kyc set to the KYC status of the wallet + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_inselect_wallet_kyc_status ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_EXCHANGEDB_KycStatus *kyc) +{ +#if FIXME_DD23 + struct PostgresClosure *pg = cls; + /* FIXME: maybe prepared statement will take + a payto:// URI instead of the reserve public key? + => figure out once DB schema is stable! */ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", + reserve_pub), + GNUNET_PQ_query_param_end + }; +#endif + uint8_t ok8; +#if FIXME_DD23 + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("payment_target_uuid", + &kyc->payment_target_uuid), + GNUNET_PQ_result_spec_auto_from_type ("kyc_ok", + &ok8), + GNUNET_PQ_result_spec_end + }; +#endif + enum GNUNET_DB_QueryStatus qs; + +#if FIXME_DD23 + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "inselect_wallet_kyc_status", + params, + rs); +#else + qs = 1; + ok8 = 0; + kyc->payment_target_uuid = 0; +#endif + kyc->type = TALER_EXCHANGEDB_KYC_BALANCE; + kyc->ok = (0 != ok8); + return qs; +} + + /** * Get the summary of a reserve. * @@ -11128,6 +11203,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) &postgres_iterate_auditor_denominations; plugin->reserves_get = &postgres_reserves_get; plugin->get_kyc_status = &postgres_get_kyc_status; + plugin->inselect_wallet_kyc_status = &postgres_inselect_wallet_kyc_status; plugin->reserves_in_insert = &postgres_reserves_in_insert; plugin->get_latest_reserve_in_reference = &postgres_get_latest_reserve_in_reference; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 286162fbc..4b90396bb 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -2367,6 +2367,22 @@ struct TALER_EXCHANGEDB_Plugin struct TALER_EXCHANGEDB_KycStatus *kyc); + /** + * Get the KYC status for a wallet. If the status is unknown, + * inserts a new status record (hence INsertSELECT). + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param reserve_pub public key of the wallet + * @param[out] kyc set to the KYC status of the wallet + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*inselect_wallet_kyc_status)( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_EXCHANGEDB_KycStatus *kyc); + + /** * Insert a incoming transaction into reserves. New reserves are * also created through this function. diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 55b30669f..17150df68 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-2021 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