exchange

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

commit 6a879a63af5b71f07d098181f449e537ba3135f3
parent 2a3fb278f3d32feca6077eead2551ee8d11b40b8
Author: Özgür Kesim <oec@codeblau.de>
Date:   Tue,  6 May 2025 16:01:22 +0200

Removal of linking protocol

With the new refresh protocol introduced with v27, there is no need
for the /linking protocol anymore:  The history data on an old coin is sufficient
to re-create a the fresh coin(s) by the owner of the private key of the old coin.

This commit removes the REST-API endpoint to /linking, the C-API support
for it and the database plugin components.

Diffstat:
Msrc/exchange/Makefile.am | 1-
Msrc/exchange/taler-exchange-httpd.c | 5-----
Dsrc/exchange/taler-exchange-httpd_link.c | 210-------------------------------------------------------------------------------
Dsrc/exchange/taler-exchange-httpd_link.h | 43-------------------------------------------
Msrc/exchangedb/Makefile.am | 15---------------
Dsrc/exchangedb/pg_get_link_data.c | 367-------------------------------------------------------------------------------
Dsrc/exchangedb/pg_get_link_data.h | 45---------------------------------------------
Msrc/exchangedb/plugin_exchangedb_postgres.c | 3---
Msrc/include/taler_exchange_service.h | 131-------------------------------------------------------------------------------
Msrc/include/taler_exchangedb_plugin.h | 20--------------------
Msrc/lib/Makefile.am | 1-
Dsrc/lib/exchange_api_link.c | 519-------------------------------------------------------------------------------
12 files changed, 0 insertions(+), 1360 deletions(-)

diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am @@ -173,7 +173,6 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_kyc-wallet.c taler-exchange-httpd_kyc-wallet.h \ taler-exchange-httpd_kyc-webhook.c taler-exchange-httpd_kyc-webhook.h \ taler-exchange-httpd_legitimization-measures-get.c taler-exchange-httpd_legitimization-measures-get.h \ - taler-exchange-httpd_link.c taler-exchange-httpd_link.h \ taler-exchange-httpd_management.h \ taler-exchange-httpd_management_aml-officers.c \ taler-exchange-httpd_management_auditors.c \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c @@ -57,7 +57,6 @@ #include "taler-exchange-httpd_kyc-webhook.h" #include "taler-exchange-httpd_aml-decision.h" #include "taler-exchange-httpd_legitimization-measures-get.h" -#include "taler-exchange-httpd_link.h" #include "taler-exchange-httpd_management.h" #include "taler-exchange-httpd_melt.h" #include "taler-exchange-httpd_melt_v27.h" @@ -467,10 +466,6 @@ handle_get_coins (struct TEH_RequestContext *rc, "history")) return TEH_handler_coins_get (rc, &coin_pub); - if (0 == strcmp (args[1], - "link")) - return TEH_handler_link (rc, - &coin_pub); } return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_NOT_FOUND, diff --git a/src/exchange/taler-exchange-httpd_link.c b/src/exchange/taler-exchange-httpd_link.c @@ -1,210 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2019, 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-exchange-httpd_link.c - * @brief Handle /coins/$COIN_PUB/link requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include "taler_mhd_lib.h" -#include "taler-exchange-httpd_mhd.h" -#include "taler-exchange-httpd_link.h" -#include "taler-exchange-httpd_responses.h" - - -/** - * Closure for #handle_link_data(). - */ -struct HTD_Context -{ - - /** - * Public key of the coin for which we are running link. - */ - const struct TALER_CoinSpendPublicKeyP *coin_pub; - - /** - * Json array with transfer data we collect. - */ - json_t *mlist; - - /** - * Taler error code. - */ - enum TALER_ErrorCode ec; -}; - - -/** - * Function called with the session hashes and transfer secret - * information for a given coin. Gets the linkage data and - * builds the reply for the client. - * - * @param cls closure, a `struct HTD_Context` - * @param transfer_pub public transfer key for the session - * @param ldl link data related to @a transfer_pub - */ -static void -handle_link_data (void *cls, - const struct TALER_TransferPublicKeyP *transfer_pub, - const struct TALER_EXCHANGEDB_LinkList *ldl) -{ - struct HTD_Context *ctx = cls; - json_t *list; - - if (NULL == ctx->mlist) - return; /* we failed earlier */ - if (NULL == (list = json_array ())) - goto fail; - - for (const struct TALER_EXCHANGEDB_LinkList *pos = ldl; - NULL != pos; - pos = pos->next) - { - json_t *obj; - - obj = GNUNET_JSON_PACK ( - TALER_JSON_pack_denom_pub ("denom_pub", - &pos->denom_pub), - TALER_JSON_pack_blinded_denom_sig ("ev_sig", - &pos->ev_sig), - GNUNET_JSON_pack_uint64 ("coin_idx", - pos->coin_refresh_offset), - TALER_JSON_pack_exchange_blinding_values ("ewv", - &pos->alg_values), - GNUNET_JSON_pack_data_auto ("link_sig", - &pos->orig_coin_link_sig), - GNUNET_JSON_pack_allow_null ( - pos->have_nonce - ? GNUNET_JSON_pack_data_auto ("cs_nonce", - &pos->nonce) - : GNUNET_JSON_pack_string ("cs_nonce", - NULL))); - if ( (NULL == obj) || - (0 != - json_array_append_new (list, - obj)) ) - { - json_decref (list); - goto fail; - } - } - { - json_t *root; - - root = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_array_steal ("new_coins", - list), - GNUNET_JSON_pack_data_auto ("transfer_pub", - transfer_pub)); - if ( (NULL == root) || - (0 != - json_array_append_new (ctx->mlist, - root)) ) - goto fail; - } - return; -fail: - ctx->ec = TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE; - json_decref (ctx->mlist); - ctx->mlist = NULL; -} - - -/** - * Execute a link operation. Returns the linkage information that will allow - * the owner of a coin to follow the trail to the refreshed coin. - * - * 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 - * @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 -link_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct HTD_Context *ctx = cls; - enum GNUNET_DB_QueryStatus qs; - - qs = TEH_plugin->get_link_data (TEH_plugin->cls, - ctx->coin_pub, - &handle_link_data, - ctx); - if (NULL == ctx->mlist) - { - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - ctx->ec, - NULL); - return GNUNET_DB_STATUS_HARD_ERROR; - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_LINK_COIN_UNKNOWN, - NULL); - return GNUNET_DB_STATUS_HARD_ERROR; - } - return qs; -} - - -MHD_RESULT -TEH_handler_link (struct TEH_RequestContext *rc, - const struct TALER_CoinSpendPublicKeyP *coin_pub) -{ - struct HTD_Context ctx = { - .coin_pub = coin_pub - }; - MHD_RESULT mhd_ret; - - ctx.mlist = json_array (); - GNUNET_assert (NULL != ctx.mlist); - if (GNUNET_OK != - TEH_DB_run_transaction (rc->connection, - "run link", - TEH_MT_REQUEST_OTHER, - &mhd_ret, - &link_transaction, - &ctx)) - { - if (NULL != ctx.mlist) - json_decref (ctx.mlist); - return mhd_ret; - } - mhd_ret = TALER_MHD_reply_json (rc->connection, - ctx.mlist, - MHD_HTTP_OK); - json_decref (ctx.mlist); - return mhd_ret; -} - - -/* end of taler-exchange-httpd_link.c */ diff --git a/src/exchange/taler-exchange-httpd_link.h b/src/exchange/taler-exchange-httpd_link.h @@ -1,43 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2017 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-exchange-httpd_link.h - * @brief Handle /coins/$COIN_PUB/link requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_EXCHANGE_HTTPD_LINK_H -#define TALER_EXCHANGE_HTTPD_LINK_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-exchange-httpd.h" - - -/** - * Handle a "/coins/$COIN_PUB/link" request. - * - * @param rc request context - * @param coin_pub the coin public key - * @return MHD result code - */ -MHD_RESULT -TEH_handler_link (struct TEH_RequestContext *rc, - const struct TALER_CoinSpendPublicKeyP *coin_pub); - - -#endif diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am @@ -208,7 +208,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_get_global_fees.h pg_get_global_fees.c \ pg_get_known_coin.h pg_get_known_coin.c \ pg_get_kyc_rules.h pg_get_kyc_rules.c \ - pg_get_link_data.h pg_get_link_data.c \ pg_get_melt.h pg_get_melt.c \ pg_get_refresh.h pg_get_refresh.c \ pg_get_old_coin_by_h_blind.h pg_get_old_coin_by_h_blind.c \ @@ -408,7 +407,6 @@ libtalerexchangedb_la_LDFLAGS = \ noinst_PROGRAMS = \ bench-db-postgres\ - perf_get_link_data-postgres\ perf_select_refunds_by_coin-postgres\ perf_reserves_in_insert-postgres \ perf_deposits_get_ready-postgres @@ -466,19 +464,6 @@ perf_select_refunds_by_coin_postgres_LDADD = \ -lm \ $(XLIB) -perf_get_link_data_postgres_SOURCES = \ - perf_get_link_data.c -perf_get_link_data_postgres_LDADD = \ - libtalerexchangedb.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/pq/libtalerpq.la \ - -ljansson \ - -lgnunetjson \ - -lgnunetutil \ - -lm \ - $(XLIB) - perf_deposits_get_ready_postgres_SOURCES = \ perf_deposits_get_ready.c perf_deposits_get_ready_postgres_LDADD = \ diff --git a/src/exchangedb/pg_get_link_data.c b/src/exchangedb/pg_get_link_data.c @@ -1,367 +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 <http://www.gnu.org/licenses/> - */ -/** - * @file exchangedb/pg_get_link_data.c - * @brief Implementation of the get_link_data 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_get_link_data.h" -#include "pg_helper.h" - - -/** - * Closure for #add_ldl(). - */ -struct LinkDataContext -{ - /** - * Function to call on each result. - */ - TALER_EXCHANGEDB_LinkCallback ldc; - - /** - * Closure for @e ldc. - */ - void *ldc_cls; - - /** - * Last transfer public key for which we have information in @e last. - * Only valid if @e last is non-NULL. - */ - struct TALER_TransferPublicKeyP transfer_pub; - - /** - * Status, set to #GNUNET_SYSERR on errors, - */ - enum GNUNET_GenericReturnValue status; -}; - - -/** - * Free memory of the link data list. - * - * @param ldl link data list to release - */ -static void -free_link_data_list (struct TALER_EXCHANGEDB_LinkList *ldl) -{ - struct TALER_EXCHANGEDB_LinkList *next; - - while (NULL != ldl) - { - next = ldl->next; - TALER_denom_pub_free (&ldl->denom_pub); - TALER_blinded_denom_sig_free (&ldl->ev_sig); - TALER_denom_ewv_free (&ldl->alg_values); - GNUNET_free (ldl); - ldl = next; - } -} - - -struct Results -{ - struct TALER_EXCHANGEDB_LinkList *pos; - struct TALER_TransferPublicKeyP transfer_pub; -}; - - -static int -transfer_pub_cmp (const void *a, - const void *b) -{ - const struct Results *ra = a; - const struct Results *rb = b; - - return GNUNET_memcmp (&ra->transfer_pub, - &rb->transfer_pub); -} - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results. - * - * @param cls closure of type `struct LinkDataContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -add_ldl (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LinkDataContext *ldctx = cls; - struct Results *temp = GNUNET_new_array (num_results, - struct Results); - unsigned int temp_off = 0; - - for (int i = num_results - 1; i >= 0; i--) - { - struct TALER_EXCHANGEDB_LinkList *pos; - - pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkList); - { - struct TALER_BlindedPlanchet bp; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", - &temp[temp_off].transfer_pub), - GNUNET_PQ_result_spec_auto_from_type ("link_sig", - &pos->orig_coin_link_sig), - TALER_PQ_result_spec_blinded_denom_sig ("ev_sig", - &pos->ev_sig), - GNUNET_PQ_result_spec_uint32 ("freshcoin_index", - &pos->coin_refresh_offset), - TALER_PQ_result_spec_exchange_withdraw_values ("ewv", - &pos->alg_values), - TALER_PQ_result_spec_denom_pub ("denom_pub", - &pos->denom_pub), - TALER_PQ_result_spec_blinded_planchet ("coin_ev", - &bp), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - GNUNET_free (pos); - ldctx->status = GNUNET_SYSERR; - return; - } - if (GNUNET_CRYPTO_BSA_CS == bp.blinded_message->cipher) - { - pos->nonce.cs_nonce - = bp.blinded_message->details.cs_blinded_message.nonce; - pos->have_nonce = true; - } - TALER_blinded_planchet_free (&bp); - } - temp[temp_off].pos = pos; - temp_off++; - } - qsort (temp, - temp_off, - sizeof (struct Results), - &transfer_pub_cmp); - if (temp_off > 0) - { - struct TALER_EXCHANGEDB_LinkList *head = NULL; - - head = temp[0].pos; - for (unsigned int i = 1; i < temp_off; i++) - { - struct TALER_EXCHANGEDB_LinkList *pos = temp[i].pos; - const struct TALER_TransferPublicKeyP *tp = &temp[i].transfer_pub; - - if (0 == GNUNET_memcmp (tp, - &temp[i - 1].transfer_pub)) - { - pos->next = head; - head = pos; - } - else - { - ldctx->ldc (ldctx->ldc_cls, - &temp[i - 1].transfer_pub, - head); - free_link_data_list (head); - head = pos; - } - } - ldctx->ldc (ldctx->ldc_cls, - &temp[temp_off - 1].transfer_pub, - head); - free_link_data_list (head); - } - GNUNET_free (temp); -} - - -enum GNUNET_DB_QueryStatus -TEH_PG_get_link_data (void *cls, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - TALER_EXCHANGEDB_LinkCallback ldc, - void *ldc_cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (coin_pub), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - struct LinkDataContext ldctx; - static int percent_refund = -2; - const char *query; - - if (-2 == percent_refund) - { - const char *mode = getenv ("TALER_POSTGRES_GET_LINK_DATA_LOGIC"); - char dummy; - - if ( (NULL==mode) || - (1 != sscanf (mode, - "%d%c", - &percent_refund, - &dummy)) ) - { - if (NULL != mode) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Bad mode `%s' specified\n", - mode); - percent_refund = 4; /* Fastest known */ - } - } - switch (percent_refund) - { - case 0: - query = "get_link"; - PREPARE (pg, - query, - "SELECT " - " tp.transfer_pub" - ",denoms.denom_pub" - ",rrc.ev_sig" - ",rrc.ewv" - ",rrc.link_sig" - ",rrc.freshcoin_index" - ",rrc.coin_ev" - " FROM refresh_commitments" - " JOIN refresh_revealed_coins rrc" - " USING (melt_serial_id)" - " JOIN refresh_transfer_keys tp" - " USING (melt_serial_id)" - " JOIN denominations denoms" - " ON (rrc.denominations_serial = denoms.denominations_serial)" - " WHERE old_coin_pub=$1" - " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC"); - break; - case 1: - query = "get_link_v1"; - PREPARE (pg, - query, - "WITH rc AS MATERIALIZED (" - "SELECT" - " melt_serial_id" - " FROM refresh_commitments" - " WHERE old_coin_pub=$1" - ")" - "SELECT " - " tp.transfer_pub" - ",denoms.denom_pub" - ",rrc.ev_sig" - ",rrc.ewv" - ",rrc.link_sig" - ",rrc.freshcoin_index" - ",rrc.coin_ev " - "FROM " - "refresh_revealed_coins rrc" - " JOIN refresh_transfer_keys tp" - " USING (melt_serial_id)" - " JOIN denominations denoms" - " USING (denominations_serial)" - " WHERE rrc.melt_serial_id = (SELECT melt_serial_id FROM rc)" - " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC"); - break; - case 2: - query = "get_link_v2"; - PREPARE (pg, - query, - "SELECT" - " *" - " FROM" - " exchange_do_get_link_data" - " ($1) " - " AS " - " (transfer_pub BYTEA" - " ,denom_pub BYTEA" - " ,ev_sig BYTEA" - " ,ewv BYTEA" - " ,link_sig BYTEA" - " ,freshcoin_index INT4" - " ,coin_ev BYTEA);"); - break; - case 3: - query = "get_link_v3"; - PREPARE (pg, - query, - "SELECT " - " tp.transfer_pub" - ",denoms.denom_pub" - ",rrc.ev_sig" - ",rrc.ewv" - ",rrc.link_sig" - ",rrc.freshcoin_index" - ",rrc.coin_ev" - " FROM refresh_commitments" - " JOIN refresh_revealed_coins rrc" - " USING (melt_serial_id)" - " JOIN refresh_transfer_keys tp" - " USING (melt_serial_id)" - " JOIN denominations denoms" - " ON (rrc.denominations_serial = denoms.denominations_serial)" - " WHERE old_coin_pub=$1"); - break; - case 4: - query = "get_link_v4"; - PREPARE (pg, - query, - "WITH rc AS MATERIALIZED (" - "SELECT" - " melt_serial_id" - " FROM refresh_commitments" - " WHERE old_coin_pub=$1" - ")" - "SELECT " - " tp.transfer_pub" - ",denoms.denom_pub" - ",rrc.ev_sig" - ",rrc.ewv" - ",rrc.link_sig" - ",rrc.freshcoin_index" - ",rrc.coin_ev " - "FROM " - "refresh_revealed_coins rrc" - " JOIN refresh_transfer_keys tp" - " USING (melt_serial_id)" - " JOIN denominations denoms" - " USING (denominations_serial)" - " WHERE rrc.melt_serial_id = (SELECT melt_serial_id FROM rc)" - ); - break; - default: - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - ldctx.ldc = ldc; - ldctx.ldc_cls = ldc_cls; - ldctx.status = GNUNET_OK; - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - query, - params, - &add_ldl, - &ldctx); - if (GNUNET_OK != ldctx.status) - return GNUNET_DB_STATUS_HARD_ERROR; - return qs; -} diff --git a/src/exchangedb/pg_get_link_data.h b/src/exchangedb/pg_get_link_data.h @@ -1,45 +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 <http://www.gnu.org/licenses/> - */ -/** - * @file exchangedb/pg_get_link_data.h - * @brief implementation of the get_link_data function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_GET_LINK_DATA_H -#define PG_GET_LINK_DATA_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" - - -/** - * Obtain the link data of a coin, that is the encrypted link - * information, the denomination keys and the signatures. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param coin_pub public key of the coin - * @param ldc function to call for each session the coin was melted into - * @param ldc_cls closure for @a tdc - * @return transaction status code - */ -enum GNUNET_DB_QueryStatus -TEH_PG_get_link_data (void *cls, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - TALER_EXCHANGEDB_LinkCallback ldc, - void *ldc_cls); - -#endif diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c @@ -83,7 +83,6 @@ #include "pg_get_global_fees.h" #include "pg_get_known_coin.h" #include "pg_get_kyc_rules.h" -#include "pg_get_link_data.h" #include "pg_get_melt.h" #include "pg_get_old_coin_by_h_blind.h" #include "pg_get_pending_kyc_requirement_process.h" @@ -409,8 +408,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_insert_close_request; plugin->delete_aggregation_transient = &TEH_PG_delete_aggregation_transient; - plugin->get_link_data - = &TEH_PG_get_link_data; plugin->iterate_reserve_close_info = &TEH_PG_iterate_reserve_close_info; plugin->iterate_kyc_reference diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h @@ -4064,137 +4064,6 @@ TALER_EXCHANGE_refreshes_reveal_cancel ( struct TALER_EXCHANGE_RefreshesRevealHandle *rrh); -/* ********************* /coins/$COIN_PUB/link ***************************** */ - - -/** - * @brief A /coins/$COIN_PUB/link Handle - */ -struct TALER_EXCHANGE_LinkHandle; - - -/** - * Information about a coin obtained via /link. - */ -struct TALER_EXCHANGE_LinkedCoinInfo -{ - /** - * Private key of the coin. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * Age commitment and its hash, if applicable. - */ - bool has_age_commitment; - struct TALER_AgeCommitmentProof age_commitment_proof; - struct TALER_AgeCommitmentHash h_age_commitment; - - /** - * Master secret of this coin. - */ - struct TALER_PlanchetMasterSecretP ps; - - /** - * Signature affirming the validity of the coin. - */ - struct TALER_DenominationSignature sig; - - /** - * Denomination public key of the coin. - */ - struct TALER_DenominationPublicKey pub; -}; - - -/** - * Result of a /link request. - */ -struct TALER_EXCHANGE_LinkResult -{ - /** - * HTTP status. - */ - struct TALER_EXCHANGE_HttpResponse hr; - - /** - * Parsed response details, variant depending on the - * @e hr.http_status. - */ - union - { - /** - * Results for status #MHD_HTTP_OK. - */ - struct - { - /** - * Array of @e num_coins values about the - * coins obtained via linkage. - */ - const struct TALER_EXCHANGE_LinkedCoinInfo *coins; - - /** - * Number of coins returned. - */ - unsigned int num_coins; - } ok; - - } details; - -}; - - -/** - * Callbacks of this type are used to return the final result of submitting a - * /coins/$COIN_PUB/link request to a exchange. If the operation was - * successful, this function returns the signatures over the coins that were - * created when the original coin was melted. - * - * @param cls closure - * @param lr result of the /link operation - */ -typedef void -(*TALER_EXCHANGE_LinkCallback) ( - void *cls, - const struct TALER_EXCHANGE_LinkResult *lr); - - -/** - * Submit a link request to the exchange and get the exchange's response. - * - * This API is typically not used by anyone, it is more a threat against those - * trying to receive a funds transfer by abusing the refresh protocol. - * - * @param ctx CURL context - * @param url exchange base URL - * @param coin_priv private key to request link data for - * @param age_commitment_proof age commitment to the corresponding coin, might be NULL - * @param link_cb the callback to call with the useful result of the - * refresh operation the @a coin_priv was involved in (if any) - * @param link_cb_cls closure for @a link_cb - * @return a handle for this request - */ -struct TALER_EXCHANGE_LinkHandle * -TALER_EXCHANGE_link ( - struct GNUNET_CURL_Context *ctx, - const char *url, - const struct TALER_CoinSpendPrivateKeyP *coin_priv, - const struct TALER_AgeCommitmentProof *age_commitment_proof, - TALER_EXCHANGE_LinkCallback link_cb, - void *link_cb_cls); - - -/** - * Cancel a link request. This function cannot be used - * on a request handle if the callback was already invoked. - * - * @param lh the link handle - */ -void -TALER_EXCHANGE_link_cancel (struct TALER_EXCHANGE_LinkHandle *lh); - - /* ********************* /transfers/$WTID *********************** */ /** diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h @@ -5235,26 +5235,6 @@ struct TALER_EXCHANGEDB_Plugin TALER_EXCHANGEDB_RefreshCallback cb, void *cb_cls); - - /** - * Obtain shared secret and transfer public key from the public key of - * the coin. This information and the link information returned by - * @e get_link_data_list() enable the owner of an old coin to determine - * the private keys of the new coins after the melt. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param coin_pub public key of the coin - * @param ldc function to call for each session the coin was melted into - * @param ldc_cls closure for @a tdc - * @return statement execution status - */ - enum GNUNET_DB_QueryStatus - (*get_link_data)(void *cls, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - TALER_EXCHANGEDB_LinkCallback ldc, - void *tdc_cls); - - /** * Compile a list of (historic) transactions performed with the given coin * (melt, refund, recoup and deposit operations). Should return 0 if the @a diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -39,7 +39,6 @@ libtalerexchange_la_SOURCES = \ exchange_api_kyc_proof.c \ exchange_api_kyc_start.c \ exchange_api_kyc_wallet.c \ - exchange_api_link.c \ exchange_api_lookup_aml_decisions.c \ exchange_api_lookup_kyc_attributes.c \ exchange_api_management_add_partner.c \ diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c @@ -1,519 +0,0 @@ -/* - This file is part of TALER - 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 - 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 lib/exchange_api_link.c - * @brief Implementation of the /coins/$COIN_PUB/link request - * @author Christian Grothoff - */ -#include "platform.h" -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "exchange_api_curl_defaults.h" - - -/** - * @brief A /coins/$COIN_PUB/link Handle - */ -struct TALER_EXCHANGE_LinkHandle -{ - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_EXCHANGE_LinkCallback link_cb; - - /** - * Closure for @e cb. - */ - void *link_cb_cls; - - /** - * Private key of the coin, required to decode link information. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * Age commitment and proof of the original coin, might be NULL. - * Required to derive the new age commitment and proof. - */ - const struct TALER_AgeCommitmentProof *age_commitment_proof; - -}; - - -/** - * Parse the provided linkage data from the "200 OK" response - * for one of the coins. - * - * @param lh link handle - * @param json json reply with the data for one coin - * @param trans_pub our transfer public key - * @param[out] lci where to return coin details - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static enum GNUNET_GenericReturnValue -parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh, - const json_t *json, - const struct TALER_TransferPublicKeyP *trans_pub, - struct TALER_EXCHANGE_LinkedCoinInfo *lci) -{ - struct TALER_BlindedDenominationSignature bsig; - struct TALER_DenominationPublicKey rpub; - struct TALER_CoinSpendSignatureP link_sig; - union GNUNET_CRYPTO_BlindingSecretP bks; - struct TALER_ExchangeBlindingValues blinding_values; - union GNUNET_CRYPTO_BlindSessionNonce nonce; - bool no_nonce; - uint32_t coin_idx; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_denom_pub ("denom_pub", - &rpub), - TALER_JSON_spec_blinded_denom_sig ("ev_sig", - &bsig), - TALER_JSON_spec_exchange_blinding_values ("ewv", - &blinding_values), - GNUNET_JSON_spec_fixed_auto ("link_sig", - &link_sig), - GNUNET_JSON_spec_uint32 ("coin_idx", - &coin_idx), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ("cs_nonce", - &nonce), - &no_nonce), - GNUNET_JSON_spec_end () - }; - struct TALER_TransferSecretP secret; - struct TALER_PlanchetDetail pd; - struct TALER_CoinPubHashP c_hash; - struct TALER_AgeCommitmentHash *pah = NULL; - - /* parse reply */ - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - TALER_link_recover_transfer_secret (trans_pub, - &lh->coin_priv, - &secret); - TALER_transfer_secret_to_planchet_secret (&secret, - coin_idx, - &lci->ps); - TALER_planchet_setup_coin_priv (&lci->ps, - &blinding_values, - &lci->coin_priv); - TALER_planchet_blinding_secret_create (&lci->ps, - &blinding_values, - &bks); - - lci->has_age_commitment = false; - - /* Derive the age commitment and calculate the hash */ - if (NULL != lh->age_commitment_proof) - { - - GNUNET_assert (GNUNET_OK == - TALER_age_commitment_proof_derive ( - lh->age_commitment_proof, - &secret.key, - &lci->age_commitment_proof)); - - TALER_age_commitment_hash ( - &lci->age_commitment_proof.commitment, - &lci->h_age_commitment); - - lci->has_age_commitment = true; - pah = &lci->h_age_commitment; - } - - if (GNUNET_OK != - TALER_planchet_prepare ( - &rpub, - &blinding_values, - &bks, - no_nonce - ? NULL - : &nonce, - &lci->coin_priv, - pah, - &c_hash, - &pd)) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - return GNUNET_SYSERR; - } - /* extract coin and signature */ - if (GNUNET_OK != - TALER_denom_sig_unblind (&lci->sig, - &bsig, - &bks, - &c_hash, - &blinding_values, - &rpub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* verify link_sig */ - { - struct TALER_CoinSpendPublicKeyP old_coin_pub; - struct TALER_BlindedCoinHashP coin_envelope_hash; - - GNUNET_CRYPTO_eddsa_key_get_public (&lh->coin_priv.eddsa_priv, - &old_coin_pub.eddsa_pub); - - TALER_coin_ev_hash (&pd.blinded_planchet, - &pd.denom_pub_hash, - &coin_envelope_hash); - if (GNUNET_OK != - TALER_wallet_link_verify (&pd.denom_pub_hash, - trans_pub, - &coin_envelope_hash, - &old_coin_pub, - &link_sig)) - { - GNUNET_break_op (0); - TALER_blinded_planchet_free (&pd.blinded_planchet); - GNUNET_JSON_parse_free (spec); - return GNUNET_SYSERR; - } - TALER_blinded_planchet_free (&pd.blinded_planchet); - } - - /* clean up */ - TALER_denom_pub_copy (&lci->pub, - &rpub); - GNUNET_JSON_parse_free (spec); - return GNUNET_OK; -} - - -/** - * Parse the provided linkage data from the "200 OK" response - * for one of the coins. - * - * @param[in,out] lh link handle (callback may be zero'ed out) - * @param json json reply with the data for one coin - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static enum GNUNET_GenericReturnValue -parse_link_ok (struct TALER_EXCHANGE_LinkHandle *lh, - const json_t *json) -{ - unsigned int session; - unsigned int num_coins; - int ret; - struct TALER_EXCHANGE_LinkResult lr = { - .hr.reply = json, - .hr.http_status = MHD_HTTP_OK - }; - - if (! json_is_array (json)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - num_coins = 0; - /* Theoretically, a coin may have been melted repeatedly - into different sessions; so the response is an array - which contains information by melting session. That - array contains another array. However, our API returns - a single 1d array, so we flatten the 2d array that is - returned into a single array. Note that usually a coin - is melted at most once, and so we'll only run this - loop once for 'session=0' in most cases. - - num_coins tracks the size of the 1d array we return, - whilst 'i' and 'session' track the 2d array. */// - for (session = 0; session<json_array_size (json); session++) - { - const json_t *jsona; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("new_coins", - &jsona), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json_array_get (json, - session), - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* count all coins over all sessions */ - num_coins += json_array_size (jsona); - } - /* Now that we know how big the 1d array is, allocate - and fill it. */ - { - unsigned int off_coin; /* index into 1d array */ - unsigned int i; - struct TALER_EXCHANGE_LinkedCoinInfo lcis[GNUNET_NZL (num_coins)]; - - memset (lcis, 0, sizeof (lcis)); - off_coin = 0; - for (session = 0; session<json_array_size (json); session++) - { - const json_t *jsona; - struct TALER_TransferPublicKeyP trans_pub; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("new_coins", - &jsona), - GNUNET_JSON_spec_fixed_auto ("transfer_pub", - &trans_pub), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json_array_get (json, - session), - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* decode all coins */ - for (i = 0; i<json_array_size (jsona); i++) - { - struct TALER_EXCHANGE_LinkedCoinInfo *lci; - - lci = &lcis[i + off_coin]; - GNUNET_assert (i + off_coin < num_coins); - if (GNUNET_OK != - parse_link_coin (lh, - json_array_get (jsona, - i), - &trans_pub, - lci)) - { - GNUNET_break_op (0); - break; - } - } - /* check if we really got all, then invoke callback */ - off_coin += i; - if (i != json_array_size (jsona)) - { - GNUNET_break_op (0); - ret = GNUNET_SYSERR; - break; - } - } /* end of for (session) */ - - if (off_coin == num_coins) - { - lr.details.ok.num_coins = num_coins; - lr.details.ok.coins = lcis; - lh->link_cb (lh->link_cb_cls, - &lr); - lh->link_cb = NULL; - ret = GNUNET_OK; - } - else - { - GNUNET_break_op (0); - ret = GNUNET_SYSERR; - } - - /* clean up */ - GNUNET_assert (off_coin <= num_coins); - for (i = 0; i<off_coin; i++) - { - TALER_denom_sig_free (&lcis[i].sig); - TALER_denom_pub_free (&lcis[i].pub); - if (lcis[i].has_age_commitment) - TALER_age_commitment_proof_free (&lcis[i].age_commitment_proof); - } - } - return ret; -} - - -/** - * Function called when we're done processing the - * HTTP /coins/$COIN_PUB/link request. - * - * @param cls the `struct TALER_EXCHANGE_LinkHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_link_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_EXCHANGE_LinkHandle *lh = cls; - const json_t *j = response; - struct TALER_EXCHANGE_LinkResult lr = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - - lh->job = NULL; - switch (response_code) - { - case 0: - lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - parse_link_ok (lh, - j)) - { - GNUNET_break_op (0); - lr.hr.http_status = 0; - lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - GNUNET_assert (NULL == lh->link_cb); - TALER_EXCHANGE_link_cancel (lh); - return; - case MHD_HTTP_BAD_REQUEST: - lr.hr.ec = TALER_JSON_get_error_code (j); - lr.hr.hint = TALER_JSON_get_error_hint (j); - /* 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_NOT_FOUND: - lr.hr.ec = TALER_JSON_get_error_code (j); - lr.hr.hint = TALER_JSON_get_error_hint (j); - /* Nothing really to verify, exchange says this coin was not melted; we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - lr.hr.ec = TALER_JSON_get_error_code (j); - lr.hr.hint = TALER_JSON_get_error_hint (j); - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - lr.hr.ec = TALER_JSON_get_error_code (j); - lr.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for exchange link\n", - (unsigned int) response_code, - (int) lr.hr.ec); - break; - } - if (NULL != lh->link_cb) - lh->link_cb (lh->link_cb_cls, - &lr); - TALER_EXCHANGE_link_cancel (lh); -} - - -struct TALER_EXCHANGE_LinkHandle * -TALER_EXCHANGE_link ( - struct GNUNET_CURL_Context *ctx, - const char *url, - const struct TALER_CoinSpendPrivateKeyP *coin_priv, - const struct TALER_AgeCommitmentProof *age_commitment_proof, - TALER_EXCHANGE_LinkCallback link_cb, - void *link_cb_cls) -{ - struct TALER_EXCHANGE_LinkHandle *lh; - CURL *eh; - struct TALER_CoinSpendPublicKeyP coin_pub; - char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32]; - - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - { - char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2]; - char *end; - - end = GNUNET_STRINGS_data_to_string ( - &coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP), - pub_str, - sizeof (pub_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "coins/%s/link", - pub_str); - } - lh = GNUNET_new (struct TALER_EXCHANGE_LinkHandle); - lh->link_cb = link_cb; - lh->link_cb_cls = link_cb_cls; - lh->coin_priv = *coin_priv; - lh->age_commitment_proof = age_commitment_proof; - lh->url = TALER_url_join (url, - arg_str, - NULL); - if (NULL == lh->url) - { - GNUNET_free (lh); - return NULL; - } - eh = TALER_EXCHANGE_curl_easy_get_ (lh->url); - if (NULL == eh) - { - GNUNET_break (0); - GNUNET_free (lh->url); - GNUNET_free (lh); - return NULL; - } - lh->job = GNUNET_CURL_job_add_with_ct_json (ctx, - eh, - &handle_link_finished, - lh); - return lh; -} - - -void -TALER_EXCHANGE_link_cancel (struct TALER_EXCHANGE_LinkHandle *lh) -{ - if (NULL != lh->job) - { - GNUNET_CURL_job_cancel (lh->job); - lh->job = NULL; - } - - GNUNET_free (lh->url); - GNUNET_free (lh); -} - - -/* end of exchange_api_link.c */