merchant

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

commit e5b2109c9d3996a849cb464e857b01254d1f7f18
parent e36697ce0c17ee364225901697700b70f2ef6a08
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed,  5 Aug 2026 22:33:11 +0200

fail on update if OTP device does not exist instead of silently unlinking

Diffstat:
Msrc/backend/taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.c | 33+++++++++++++++++++++++++++++++++
Msrc/testing/test_merchant_api.c | 31+++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.c b/src/backend/taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.c @@ -26,6 +26,7 @@ #include "taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.h" #include "taler-merchant-httpd_helper.h" #include <taler/taler_json_lib.h> +#include "merchant-database/get_otp_device_serial.h" #include "merchant-database/update_template.h" @@ -115,6 +116,38 @@ TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh, } } + if (NULL != tp.otp_id) + { + uint64_t otp_serial; + + /* Note: without this pre-check, an unknown @e otp_id would + simply resolve to NULL in the UPDATE and thus *silently* + remove the OTP device binding of the template. */ + qs = TALER_MERCHANTDB_get_otp_device_serial (TMH_db, + mi->settings.id, + tp.otp_id, + &otp_serial); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "get_otp_device_serial"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN, + tp.otp_id); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + } + qs = TALER_MERCHANTDB_update_template (TMH_db, mi->settings.id, template_id, diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c @@ -1819,6 +1819,37 @@ run (void *cls, GNUNET_JSON_pack_time_rel ("pay_duration", GNUNET_TIME_UNIT_MINUTES)), MHD_HTTP_NOT_FOUND), + /* Bind template-2 to an existing OTP device ... */ + TALER_TESTING_cmd_merchant_patch_template ( + "patch-templates-t2-otp", + merchant_url, + "template-2", + "a template with an OTP device", + "otp-dev", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("minimum_age", 0), + GNUNET_JSON_pack_time_rel ("pay_duration", + GNUNET_TIME_UNIT_MINUTES)), + MHD_HTTP_NO_CONTENT), + /* ... a PATCH naming an unknown OTP device must be refused + with 404 and must NOT clear the existing binding (#5) */ + TALER_TESTING_cmd_merchant_patch_template ( + "patch-templates-t2-otp-nx", + merchant_url, + "template-2", + "a template that must not be stored", + "otp-dev-nx", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("minimum_age", 0), + GNUNET_JSON_pack_time_rel ("pay_duration", + GNUNET_TIME_UNIT_MINUTES)), + MHD_HTTP_NOT_FOUND), + /* ... hence the template must still match the successful PATCH */ + TALER_TESTING_cmd_merchant_get_template ("get-template-t2-otp", + merchant_url, + "template-2", + MHD_HTTP_OK, + "patch-templates-t2-otp"), TALER_TESTING_cmd_merchant_post_templates2 ( "post-templates-t3-amount", merchant_url,