exchange

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

commit 250a2376b5d2941647220676e33b7086f3a32648
parent ffdbf19f3a1724d1217de1a8f5ff67271f1f2e12
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 11 Jun 2025 22:37:05 +0200

expose kycauth wire transfers to AML officers, should address backend changes for #10031

Diffstat:
Msrc/exchange/taler-exchange-httpd.c | 4++++
Msrc/exchange/taler-exchange-httpd_aml-transfer-get.c | 56+++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/exchange/taler-exchange-httpd_aml-transfer-get.h | 17+++++++++++++++++
Msrc/exchange/taler-exchange-httpd_config.h | 2+-
Msrc/exchangedb/Makefile.am | 1+
Asrc/exchangedb/pg_select_exchange_kycauth_transfers.c | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/exchangedb/pg_select_exchange_kycauth_transfers.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/exchangedb/plugin_exchangedb_postgres.c | 3+++
Msrc/include/taler_exchangedb_plugin.h | 21+++++++++++++++++++++
Msrc/lib/exchange_api_handle.c | 4++--
10 files changed, 323 insertions(+), 12 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c @@ -609,6 +609,10 @@ handle_get_aml (struct TEH_RequestContext *rc, .handler = &TEH_handler_aml_transfer_credit_get }, { + .op = "transfers-kycauth", + .handler = &TEH_handler_aml_transfer_kycauth_get + }, + { .op = "transfers-debit", .handler = &TEH_handler_aml_transfer_debit_get }, diff --git a/src/exchange/taler-exchange-httpd_aml-transfer-get.c b/src/exchange/taler-exchange-httpd_aml-transfer-get.c @@ -31,6 +31,15 @@ #include "taler-exchange-httpd_aml-transfer-get.h" #include "taler-exchange-httpd_metrics.h" + +enum TransferType +{ + TT_CREDIT, + TT_DEBIT, + TT_KYCAUTH +}; + + /** * Maximum number of transfers we return in one request. */ @@ -78,7 +87,7 @@ record_cb ( * * @param rc request context * @param officer_pub the AML officer - * @param is_debit false to return credit data, true to return debit data + * @param tt which type of transfer data to return * @param args further arguments provided (should be empty) * @return MHD status */ @@ -86,7 +95,7 @@ static MHD_RESULT aml_transfer_get ( struct TEH_RequestContext *rc, const struct TALER_AmlOfficerPublicKeyP *officer_pub, - bool is_debit, + enum TransferType tt, const char *const args[]) { int64_t limit = -20; @@ -126,6 +135,7 @@ aml_transfer_get ( { json_t *transfers; enum GNUNET_DB_QueryStatus qs; + const char *query; transfers = json_array (); GNUNET_assert (NULL != transfers); @@ -133,7 +143,9 @@ aml_transfer_get ( limit = MAX_TRANSFERS; if (limit < -MAX_TRANSFERS) limit = -MAX_TRANSFERS; - if (is_debit) + switch (tt) + { + case TT_DEBIT: qs = TEH_plugin->select_exchange_debit_transfers ( TEH_plugin->cls, &threshold, @@ -141,7 +153,9 @@ aml_transfer_get ( limit, &record_cb, transfers); - else + query = "select_exchange_debit_transfers"; + break; + case TT_CREDIT: qs = TEH_plugin->select_exchange_credit_transfers ( TEH_plugin->cls, &threshold, @@ -149,6 +163,19 @@ aml_transfer_get ( limit, &record_cb, transfers); + query = "select_exchange_credit_transfers"; + break; + case TT_KYCAUTH: + qs = TEH_plugin->select_exchange_kycauth_transfers ( + TEH_plugin->cls, + &threshold, + offset, + limit, + &record_cb, + transfers); + query = "select_exchange_kycauth_transfers"; + break; + } switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: @@ -159,9 +186,7 @@ aml_transfer_get ( rc->connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, - (is_debit) - ? "select_exchange_debit_transfers" - : "select_exchange_credit_transfers"); + query); case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: json_decref (transfers); return TALER_MHD_reply_static ( @@ -190,7 +215,20 @@ TEH_handler_aml_transfer_credit_get ( { return aml_transfer_get (rc, officer_pub, - false, + TT_CREDIT, + args); +} + + +MHD_RESULT +TEH_handler_aml_transfer_kycauth_get ( + struct TEH_RequestContext *rc, + const struct TALER_AmlOfficerPublicKeyP *officer_pub, + const char *const args[]) +{ + return aml_transfer_get (rc, + officer_pub, + TT_KYCAUTH, args); } @@ -203,7 +241,7 @@ TEH_handler_aml_transfer_debit_get ( { return aml_transfer_get (rc, officer_pub, - true, + TT_DEBIT, args); } diff --git a/src/exchange/taler-exchange-httpd_aml-transfer-get.h b/src/exchange/taler-exchange-httpd_aml-transfer-get.h @@ -43,6 +43,23 @@ TEH_handler_aml_transfer_credit_get ( /** + * Handle a GET "/aml/$OFFICER_PUB/transfer-kycauth" request. Parses the + * request details, checks the signatures and if appropriately authorized + * returns the matching wire transfers. + * + * @param rc request context + * @param officer_pub public key of the AML officer who made the request + * @param args GET arguments (should be empty) + * @return MHD result code + */ +MHD_RESULT +TEH_handler_aml_transfer_kycauth_get ( + struct TEH_RequestContext *rc, + const struct TALER_AmlOfficerPublicKeyP *officer_pub, + const char *const args[]); + + +/** * Handle a GET "/aml/$OFFICER_PUB/transfer-debit" request. Parses the * request details, checks the signatures and if appropriately authorized * returns the matching wire transfers. diff --git a/src/exchange/taler-exchange-httpd_config.h b/src/exchange/taler-exchange-httpd_config.h @@ -41,7 +41,7 @@ * * Returned via both /config and /keys endpoints. */ -#define EXCHANGE_PROTOCOL_VERSION "28:0:6" +#define EXCHANGE_PROTOCOL_VERSION "29:0:7" /** diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am @@ -250,6 +250,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_select_contract_by_purse.h pg_select_contract_by_purse.c \ pg_select_deposit_amounts_for_kyc_check.h pg_select_deposit_amounts_for_kyc_check.c \ pg_select_exchange_credit_transfers.h pg_select_exchange_credit_transfers.c \ + pg_select_exchange_kycauth_transfers.h pg_select_exchange_kycauth_transfers.c \ pg_select_exchange_debit_transfers.h pg_select_exchange_debit_transfers.c \ pg_select_kyc_attributes.h pg_select_kyc_attributes.c \ pg_select_merge_amounts_for_kyc_check.h pg_select_merge_amounts_for_kyc_check.c \ diff --git a/src/exchangedb/pg_select_exchange_kycauth_transfers.c b/src/exchangedb/pg_select_exchange_kycauth_transfers.c @@ -0,0 +1,178 @@ +/* + This file is part of TALER + Copyright (C) 2025 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/pg_select_exchange_kycauth_transfers.c + * @brief Implementation of the select_exchange_kycauth_transfers function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_select_exchange_kycauth_transfers.h" +#include "pg_helper.h" + +/** + * Closure for #handle_aml_result. + */ +struct SelectTransferContext +{ + /** + * Function to call on each result. + */ + TALER_EXCHANGEDB_AmlTransferCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Plugin context. + */ + struct PostgresClosure *pg; + + /** + * Set to #GNUNET_SYSERR on serious errors. + */ + enum GNUNET_GenericReturnValue status; +}; + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. Helper function + * for #TEH_PG_select_exchange_debit_transfers(). + * + * @param cls closure of type `struct SelectTransferContext *` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +handle_transfer_result (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct SelectTransferContext *stc = cls; + struct PostgresClosure *pg = stc->pg; + + for (unsigned int i = 0; i<num_results; i++) + { + char *payto_uri; + uint64_t rowid; + struct GNUNET_TIME_Absolute execution_time; + struct TALER_Amount amount; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("serial_id", + &rowid), + GNUNET_PQ_result_spec_string ("payto_uri", + &payto_uri), + GNUNET_PQ_result_spec_absolute_time ("execution_time", + &execution_time), + TALER_PQ_RESULT_SPEC_AMOUNT ("amount", + &amount), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + stc->status = GNUNET_SYSERR; + return; + } + stc->cb (stc->cb_cls, + rowid, + payto_uri, + execution_time, + &amount); + GNUNET_PQ_cleanup_result (rs); + } +} + + +enum GNUNET_DB_QueryStatus +TEH_PG_select_exchange_kycauth_transfers ( + void *cls, + const struct TALER_Amount *threshold, + uint64_t offset, + int64_t limit, + TALER_EXCHANGEDB_AmlTransferCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + struct SelectTransferContext stc = { + .pg = pg, + .cb = cb, + .cb_cls = cb_cls, + .status = GNUNET_OK + }; + uint64_t ulimit = (limit > 0) ? limit : -limit; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&offset), + GNUNET_PQ_query_param_uint64 (&ulimit), + TALER_PQ_query_param_amount (pg->conn, + threshold), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + PREPARE (pg, + "select_exchange_kycauth_transfers_inc", + "SELECT" + " ki.kycauth_in_serial_id AS serial_id" + ",wt.payto_uri" + ",ki.execution_date AS execution_time" + ",ki.credit AS amount" + " FROM kycauths_in ki" + " LEFT JOIN wire_targets wt" + " ON (ki.wire_source_h_payto = wt.wire_target_h_payto)" + " WHERE (ki.reserve_in_serial_id > $1)" + " AND ( ( (ki.credit).val > ($3::taler_amount).val)" + " OR ( ( (ki.credit).val >= ($3::taler_amount).val)" + " AND ( (ki.credit).frac >= ($3::taler_amount).frac) ) )" + " ORDER BY ki.kycauth_in_serial_id ASC" + " LIMIT $2"); + PREPARE (pg, + "select_exchange_kycauth_transfers_dec", + "SELECT" + " ki.kycauth_in_serial_id AS serial_id" + ",wt.payto_uri" + ",ki.execution_date AS execution_time" + ",ki.credit AS amount" + " FROM kycauths_in ki" + " LEFT JOIN wire_targets wt" + " ON (ki.wire_source_h_payto = wt.wire_target_h_payto)" + " WHERE (ki.kycauth_in_serial_id < $1)" + " AND ( ( (ki.credit).val > ($3::taler_amount).val)" + " OR ( ( (ki.credit).val >= ($3::taler_amount).val)" + " AND ( (ki.credit).frac >= ($3::taler_amount).frac) ) )" + " ORDER BY ki.kycauth_in_serial_id DESC" + " LIMIT $2"); + qs = GNUNET_PQ_eval_prepared_multi_select ( + pg->conn, + (limit > 0) + ? "select_exchange_kycauth_transfers_inc" + : "select_exchange_kycauth_transfers_dec", + params, + &handle_transfer_result, + &stc); + if (GNUNET_OK != stc.status) + return GNUNET_DB_STATUS_HARD_ERROR; + return qs; +} diff --git a/src/exchangedb/pg_select_exchange_kycauth_transfers.h b/src/exchangedb/pg_select_exchange_kycauth_transfers.h @@ -0,0 +1,49 @@ +/* + This file is part of TALER + Copyright (C) 2025 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/pg_select_exchange_kycauth_transfers.h + * @brief implementation of the select_exchange_kycauth_transfers function for Postgres + * @author Christian Grothoff + */ +#ifndef PG_SELECT_EXCHANGE_KYCAUTH_TRANSFERS_H +#define PG_SELECT_EXCHANGE_KYCAUTH_TRANSFERS_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Return wire transfer kycauth data. + * + * @param cls closure + * @param threshold minimum wire amount to return data for + * @param offset offset in table to filter by + * @param limit maximum number of entries to return, negative for descending + * @param cb function to call on each result + * @param cb_cls closure to pass to @a cb + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +TEH_PG_select_exchange_kycauth_transfers ( + void *cls, + const struct TALER_Amount *threshold, + uint64_t offset, + int64_t limit, + TALER_EXCHANGEDB_AmlTransferCallback cb, + void *cb_cls); + +#endif diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c @@ -188,6 +188,7 @@ #include "pg_select_deposit_amounts_for_kyc_check.h" #include "pg_select_exchange_credit_transfers.h" #include "pg_select_exchange_debit_transfers.h" +#include "pg_select_exchange_kycauth_transfers.h" #include "pg_select_kyc_attributes.h" #include "pg_select_merge_amounts_for_kyc_check.h" #include "pg_select_purse.h" @@ -719,6 +720,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_select_exchange_debit_transfers; plugin->select_exchange_credit_transfers = &TEH_PG_select_exchange_credit_transfers; + plugin->select_exchange_kycauth_transfers + = &TEH_PG_select_exchange_kycauth_transfers; plugin->select_all_kyc_attributes = &TEH_PG_select_all_kyc_attributes; plugin->begin_shard diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h @@ -8048,6 +8048,27 @@ struct TALER_EXCHANGEDB_Plugin /** + * Return wire transfer kycauth data. + * + * @param cls closure + * @param threshold minimum wire amount to return data for + * @param offset offset in table to filter by + * @param limit maximum number of entries to return, negative for descending + * @param cb function to call on each result + * @param cb_cls closure to pass to @a cb + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*select_exchange_kycauth_transfers) ( + void *cls, + const struct TALER_Amount *threshold, + uint64_t offset, + int64_t limit, + TALER_EXCHANGEDB_AmlTransferCallback cb, + void *cb_cls); + + + /** * Disable (delete/drop) customization rule schema from a deployment. * * @param cls closure diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c @@ -40,12 +40,12 @@ * Which version of the Taler protocol is implemented * by this library? Used to determine compatibility. */ -#define EXCHANGE_PROTOCOL_CURRENT 26 +#define EXCHANGE_PROTOCOL_CURRENT 29 /** * How many versions are we backwards compatible with? */ -#define EXCHANGE_PROTOCOL_AGE 0 +#define EXCHANGE_PROTOCOL_AGE 3 /** * Set to 1 for extra debug logging.