merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 357a283adfe6c1413d7ce2f6f769a7f0e0bba249
parent c77d9adc0abcc48a7adb579688a4d590f3663e79
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue,  2 Jun 2026 19:36:29 +0200

new endpoint for #11183

Diffstat:
Msrc/backend/meson.build | 1+
Msrc/backend/taler-merchant-httpd_dispatcher.c | 10++++++++++
Msrc/backend/taler-merchant-httpd_get-private-kyc.c | 26++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_post-private-accept-tos-early.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_post-private-accept-tos-early.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backenddb/insert_tos_accepted_early.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backenddb/lookup_tos_accepted_early.c | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/backenddb/meson.build | 2++
Asrc/backenddb/sql-schema/merchant-0037.sql | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/backenddb/sql-schema/meson.build | 1+
Msrc/include/merchant-database/all.h | 2++
Asrc/include/merchant-database/insert_tos_accepted_early.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/merchant-database/lookup_tos_accepted_early.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 files changed, 464 insertions(+), 0 deletions(-)

diff --git a/src/backend/meson.build b/src/backend/meson.build @@ -145,6 +145,7 @@ taler_merchant_httpd_SOURCES = [ 'taler-merchant-httpd_post-private-transfers.c', 'taler-merchant-httpd_post-private-webhooks.c', 'taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c', + 'taler-merchant-httpd_post-private-accept-tos-early.c', 'taler-merchant-httpd_post-challenge-ID.c', 'taler-merchant-httpd_post-challenge-ID-confirm.c', 'taler-merchant-httpd_post-orders-ORDER_ID-abort.c', diff --git a/src/backend/taler-merchant-httpd_dispatcher.c b/src/backend/taler-merchant-httpd_dispatcher.c @@ -95,6 +95,7 @@ #include "taler-merchant-httpd_post-private-transfers.h" #include "taler-merchant-httpd_post-private-webhooks.h" #include "taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.h" +#include "taler-merchant-httpd_post-private-accept-tos-early.h" #include "taler-merchant-httpd_post-challenge-ID.h" #include "taler-merchant-httpd_post-challenge-ID-confirm.h" #include "taler-merchant-httpd_post-orders-ORDER_ID-abort.h" @@ -815,6 +816,15 @@ determine_handler_group (const char **urlp, /* allow exchange URL up to 4 kb, that should be plenty */ .max_upload = 1024 * 4 }, + /* POST /accept-tos-early: */ + { + .url_prefix = "/accept-tos-early", + .method = MHD_HTTP_METHOD_POST, + .permission = "accounts-write", + .handler = &TMH_private_post_accept_tos_early, + /* allow exchange URL plus terms version up to 4 kb */ + .max_upload = 1024 * 4 + }, /* PATCH /accounts/$H_WIRE: */ { .url_prefix = "/accounts/", diff --git a/src/backend/taler-merchant-httpd_get-private-kyc.c b/src/backend/taler-merchant-httpd_get-private-kyc.c @@ -33,6 +33,7 @@ #include <regex.h> #include "merchant-database/account_kyc_get_status.h" #include "merchant-database/event_listen.h" +#include "merchant-database/lookup_tos_accepted_early.h" /** * Information we keep per /kyc request. @@ -857,6 +858,8 @@ ekr_expand_response (struct ExchangeKycRequest *ekr) const char *status; const char *q; char *short_account; + bool kyc_swap_tos_acceptance = false; + char *tos_accepted_early = NULL; GNUNET_assert (NULL != e); status = map_to_status (ekr); @@ -874,6 +877,22 @@ ekr_expand_response (struct ExchangeKycRequest *ekr) else short_account = GNUNET_strndup (ekr->payto_uri.full_payto, q - ekr->payto_uri.full_payto); + if (NULL != ekr->keys) + kyc_swap_tos_acceptance = ekr->keys->kyc_swap_tos_acceptance; + { + enum GNUNET_DB_QueryStatus qs; + + qs = TALER_MERCHANTDB_lookup_tos_accepted_early (TMH_db, + kc->mi->settings.id, + ekr->exchange_url, + &tos_accepted_early); + if (qs < 0) + { + GNUNET_break (0); + /* fall through with tos_accepted_early == NULL */ + tos_accepted_early = NULL; + } + } GNUNET_assert ( 0 == json_array_append_new ( @@ -902,6 +921,12 @@ ekr_expand_response (struct ExchangeKycRequest *ekr) ekr->no_keys), GNUNET_JSON_pack_bool ("auth_conflict", ekr->kyc_auth_conflict), + GNUNET_JSON_pack_bool ("kyc_swap_tos_acceptance", + kyc_swap_tos_acceptance), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ( + "tos_accepted_early", + tos_accepted_early)), GNUNET_JSON_pack_uint64 ("exchange_http_status", ekr->last_http_status), (TALER_EC_NONE == ekr->last_ec) @@ -927,6 +952,7 @@ ekr_expand_response (struct ExchangeKycRequest *ekr) GNUNET_JSON_pack_array_incref ("payto_kycauths", ekr->pkaa)) ))); + GNUNET_free (tos_accepted_early); GNUNET_free (short_account); } diff --git a/src/backend/taler-merchant-httpd_post-private-accept-tos-early.c b/src/backend/taler-merchant-httpd_post-private-accept-tos-early.c @@ -0,0 +1,100 @@ +/* + This file is part of TALER + (C) 2026 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 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 src/backend/taler-merchant-httpd_post-private-accept-tos-early.c + * @brief implementing POST /private/accept-tos-early request handling + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_post-private-accept-tos-early.h" +#include "taler-merchant-httpd_helper.h" +#include <taler/taler_json_lib.h> +#include "merchant-database/insert_tos_accepted_early.h" + + +/** + * How often do we retry the simple INSERT database transaction? + */ +#define MAX_RETRIES 3 + + +enum MHD_Result +TMH_private_post_accept_tos_early ( + const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + const char *exchange_url; + const char *tos_version; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("exchange_url", + &exchange_url), + GNUNET_JSON_spec_string ("tos_version", + &tos_version), + GNUNET_JSON_spec_end () + }; + enum GNUNET_DB_QueryStatus qs; + + (void) rh; + GNUNET_assert (NULL != mi); + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + } + for (unsigned int i = 0; i < MAX_RETRIES; i++) + { + qs = TALER_MERCHANTDB_insert_tos_accepted_early (TMH_db, + mi->settings.id, + exchange_url, + tos_version); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } + GNUNET_JSON_parse_free (spec); + if (qs < 0) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + (GNUNET_DB_STATUS_SOFT_ERROR == qs) + ? TALER_EC_GENERIC_DB_SOFT_FAILURE + : TALER_EC_GENERIC_DB_STORE_FAILED, + NULL); + } + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +/* end of taler-merchant-httpd_post-private-accept-tos-early.c */ diff --git a/src/backend/taler-merchant-httpd_post-private-accept-tos-early.h b/src/backend/taler-merchant-httpd_post-private-accept-tos-early.h @@ -0,0 +1,47 @@ +/* + This file is part of TALER + (C) 2026 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 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 src/backend/taler-merchant-httpd_post-private-accept-tos-early.h + * @brief implementing POST /private/accept-tos-early request handling + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_POST_PRIVATE_ACCEPT_TOS_EARLY_H +#define TALER_MERCHANT_HTTPD_POST_PRIVATE_ACCEPT_TOS_EARLY_H + +#include "taler-merchant-httpd.h" + + +/** + * Record that the user has accepted a specific version of the + * terms of service of an exchange ahead of the regular KYC + * flow. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +enum MHD_Result +TMH_private_post_accept_tos_early ( + const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +#endif diff --git a/src/backenddb/insert_tos_accepted_early.c b/src/backenddb/insert_tos_accepted_early.c @@ -0,0 +1,54 @@ +/* + This file is part of TALER + Copyright (C) 2026 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 src/backenddb/insert_tos_accepted_early.c + * @brief Implementation of the insert_tos_accepted_early function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include <taler/taler_pq_lib.h> +#include "merchant-database/insert_tos_accepted_early.h" +#include "helper.h" + + +enum GNUNET_DB_QueryStatus +TALER_MERCHANTDB_insert_tos_accepted_early ( + struct TALER_MERCHANTDB_PostgresContext *pg, + const char *merchant_id, + const char *exchange_url, + const char *tos_version) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (exchange_url), + GNUNET_PQ_query_param_string (tos_version), + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (NULL != pg->current_merchant_id); + GNUNET_assert (0 == strcmp (merchant_id, + pg->current_merchant_id)); + check_connection (pg); + TMH_PQ_prepare_anon (pg, + "INSERT INTO merchant_tos_accepted" + " (exchange_url" + " ,tos_version)" + " VALUES ($1, $2)" + " ON CONFLICT (exchange_url)" + " DO UPDATE SET tos_version=$2"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "", + params); +} diff --git a/src/backenddb/lookup_tos_accepted_early.c b/src/backenddb/lookup_tos_accepted_early.c @@ -0,0 +1,57 @@ +/* + This file is part of TALER + Copyright (C) 2026 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 src/backenddb/lookup_tos_accepted_early.c + * @brief Implementation of the lookup_tos_accepted_early function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include <taler/taler_pq_lib.h> +#include "merchant-database/lookup_tos_accepted_early.h" +#include "helper.h" + + +enum GNUNET_DB_QueryStatus +TALER_MERCHANTDB_lookup_tos_accepted_early ( + struct TALER_MERCHANTDB_PostgresContext *pg, + const char *merchant_id, + const char *exchange_url, + char **tos_version) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (exchange_url), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_string ("tos_version", + tos_version), + GNUNET_PQ_result_spec_end + }; + + *tos_version = NULL; + GNUNET_assert (NULL != pg->current_merchant_id); + GNUNET_assert (0 == strcmp (merchant_id, + pg->current_merchant_id)); + check_connection (pg); + TMH_PQ_prepare_anon (pg, + "SELECT tos_version" + " FROM merchant_tos_accepted" + " WHERE exchange_url=$1"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "", + params, + rs); +} diff --git a/src/backenddb/meson.build b/src/backenddb/meson.build @@ -62,6 +62,7 @@ libtalermerchantdb = library( 'insert_refund_proof.c', 'insert_spent_token.c', 'insert_template.c', + 'insert_tos_accepted_early.c', 'update_unit.c', 'insert_token_family.c', 'insert_token_family_key.c', @@ -199,6 +200,7 @@ libtalermerchantdb = library( 'select_donau_instance_by_serial.c', 'lookup_donau_keys.c', 'lookup_order_charity.c', + 'lookup_tos_accepted_early.c', 'upsert_donau_keys.c', 'update_donau_instance.c', 'merchantdb_helper.c', diff --git a/src/backenddb/sql-schema/merchant-0037.sql b/src/backenddb/sql-schema/merchant-0037.sql @@ -0,0 +1,56 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2026 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 merchant-0037.sql +-- @brief Add a per-instance table tracking, per exchange, the latest +-- Taler-Terms-Version (etag) of the terms of service that the user +-- accepted ahead of the regular KYC flow (POST /private/accept-tos-early). +-- @author Christian Grothoff + +BEGIN; + +SELECT _v.register_patch('merchant-0037', NULL, NULL); + +SET search_path TO merchant; + +CREATE PROCEDURE merchant.merchant_0037_init(s TEXT) + LANGUAGE plpgsql + AS $$ +BEGIN + EXECUTE format('CREATE TABLE %I.merchant_tos_accepted (' + || ' tos_accepted_serial INT8 GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,' + || ' exchange_url TEXT NOT NULL UNIQUE,' + || ' tos_version TEXT NOT NULL' + || ')', s); + EXECUTE format('COMMENT ON TABLE %I.merchant_tos_accepted IS %L', s, + 'Latest Taler-Terms-Version (etag) of the terms of service accepted' + ' early (ahead of the KYC flow) by the user, one row per exchange.'); + EXECUTE format('COMMENT ON COLUMN %I.merchant_tos_accepted.exchange_url IS %L', + s, 'Base URL of the exchange the terms of service were accepted for.'); + EXECUTE format('COMMENT ON COLUMN %I.merchant_tos_accepted.tos_version IS %L', + s, 'Accepted Taler-Terms-Version of the exchange terms of service.'); +END +$$; + +INSERT INTO merchant.instance_fixups + (migration_name + ,version) + VALUES + ('merchant_0037_init' + ,37); +-- Apply new fix-up to existing instances +CALL merchant.merchant_create_instance_schema (37); + +COMMIT; diff --git a/src/backenddb/sql-schema/meson.build b/src/backenddb/sql-schema/meson.build @@ -108,6 +108,7 @@ generated_sql = [ ['merchant-0033.sql'], ['merchant-0034.sql'], ['merchant-0035.sql'], + ['merchant-0037.sql'], ] foreach g : generated_sql diff --git a/src/include/merchant-database/all.h b/src/include/merchant-database/all.h @@ -66,6 +66,7 @@ #include "merchant-database/insert_template.h" #include "merchant-database/insert_token_family.h" #include "merchant-database/insert_token_family_key.h" +#include "merchant-database/insert_tos_accepted_early.h" #include "merchant-database/insert_transfer.h" #include "merchant-database/insert_transfer_details.h" #include "merchant-database/insert_unclaim_signature.h" @@ -123,6 +124,7 @@ #include "merchant-database/lookup_token_family.h" #include "merchant-database/lookup_token_family_key.h" #include "merchant-database/lookup_token_family_keys.h" +#include "merchant-database/lookup_tos_accepted_early.h" #include "merchant-database/lookup_transfer_details.h" #include "merchant-database/lookup_transfer_details_by_order.h" #include "merchant-database/lookup_transfer_summary.h" diff --git a/src/include/merchant-database/insert_tos_accepted_early.h b/src/include/merchant-database/insert_tos_accepted_early.h @@ -0,0 +1,54 @@ +/* + This file is part of TALER + Copyright (C) 2026 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 src/include/merchant-database/insert_tos_accepted_early.h + * @brief implementation of the insert_tos_accepted_early function for Postgres + * @author Christian Grothoff + */ +#ifndef MERCHANT_DATABASE_INSERT_TOS_ACCEPTED_EARLY_H +#define MERCHANT_DATABASE_INSERT_TOS_ACCEPTED_EARLY_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "merchantdb_lib.h" + + +struct TALER_MERCHANTDB_PostgresContext; + +/** + * Record that the user has accepted version @a tos_version + * of the terms of service of the exchange identified by + * @a exchange_url ahead of the regular KYC flow. If an + * acceptance already exists for the given @a merchant_id + * and @a exchange_url, it is updated to the new + * @a tos_version. + * + * @param pg database context + * @param merchant_id merchant backend instance ID + * @param exchange_url base URL of the exchange the user + * accepted the terms of service for + * @param tos_version ``Taler-Terms-Version`` of the + * terms of service the user accepted + * @return database result code + */ +enum GNUNET_DB_QueryStatus +TALER_MERCHANTDB_insert_tos_accepted_early ( + struct TALER_MERCHANTDB_PostgresContext *pg, + const char *merchant_id, + const char *exchange_url, + const char *tos_version); + +#endif diff --git a/src/include/merchant-database/lookup_tos_accepted_early.h b/src/include/merchant-database/lookup_tos_accepted_early.h @@ -0,0 +1,54 @@ +/* + This file is part of TALER + Copyright (C) 2026 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 src/include/merchant-database/lookup_tos_accepted_early.h + * @brief implementation of the lookup_tos_accepted_early function for Postgres + * @author Christian Grothoff + */ +#ifndef MERCHANT_DATABASE_LOOKUP_TOS_ACCEPTED_EARLY_H +#define MERCHANT_DATABASE_LOOKUP_TOS_ACCEPTED_EARLY_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "merchantdb_lib.h" + + +struct TALER_MERCHANTDB_PostgresContext; + +/** + * Look up the ``Taler-Terms-Version`` of the terms of + * service that the user has accepted early for a given + * exchange (via the ``POST /private/accept-tos-early`` + * endpoint). + * + * @param pg database context + * @param merchant_id merchant backend instance ID + * @param exchange_url base URL of the exchange to look up + * @param[out] tos_version set to a newly allocated string with the + * accepted ``Taler-Terms-Version``; caller must @a GNUNET_free + * it. Set to NULL if no acceptance is on record for this + * @a exchange_url, in which case the query status will be + * ``GNUNET_DB_STATUS_SUCCESS_NO_RESULTS``. + * @return database result code + */ +enum GNUNET_DB_QueryStatus +TALER_MERCHANTDB_lookup_tos_accepted_early ( + struct TALER_MERCHANTDB_PostgresContext *pg, + const char *merchant_id, + const char *exchange_url, + char **tos_version); + +#endif