aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/#taler-merchant-httpd_private-patch-templates-ID.c#197
-rw-r--r--src/backend/Makefile.am24
-rw-r--r--src/backend/taler-merchant-httpd.c138
-rw-r--r--src/backend/taler-merchant-httpd_post-using-templates.c11
-rw-r--r--src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c78
-rw-r--r--src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.h41
-rw-r--r--src/backend/taler-merchant-httpd_private-get-accounts-ID.c103
-rw-r--r--src/backend/taler-merchant-httpd_private-get-accounts-ID.h41
-rw-r--r--src/backend/taler-merchant-httpd_private-get-accounts.c78
-rw-r--r--src/backend/taler-merchant-httpd_private-get-accounts.h41
-rw-r--r--src/backend/taler-merchant-httpd_private-get-otp-devices-ID.c83
-rw-r--r--src/backend/taler-merchant-httpd_private-get-otp-devices-ID.h41
-rw-r--r--src/backend/taler-merchant-httpd_private-get-otp-devices.c80
-rw-r--r--src/backend/taler-merchant-httpd_private-get-otp-devices.h41
-rw-r--r--src/backend/taler-merchant-httpd_private-get-templates-ID.c9
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-accounts-ID.c132
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-accounts-ID.h43
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-instances-ID.c274
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.c122
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.h44
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-templates-ID.c16
-rw-r--r--src/backend/taler-merchant-httpd_private-post-account.c13
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances.c149
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c69
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.h20
-rw-r--r--src/backend/taler-merchant-httpd_private-post-otp-devices.c201
-rw-r--r--src/backend/taler-merchant-httpd_private-post-otp-devices.h44
-rw-r--r--src/backend/taler-merchant-httpd_private-post-templates.c171
-rw-r--r--src/backenddb/Makefile.am13
-rw-r--r--src/backenddb/merchant-0001.sql35
-rw-r--r--src/backenddb/merchantdb_helper.c2
-rw-r--r--src/backenddb/pg_delete_otp.c55
-rw-r--r--src/backenddb/pg_delete_otp.h43
-rw-r--r--src/backenddb/pg_delete_template.c55
-rw-r--r--src/backenddb/pg_delete_template.h44
-rw-r--r--src/backenddb/pg_inactivate_account.c2
-rw-r--r--src/backenddb/pg_insert_otp.c74
-rw-r--r--src/backenddb/pg_insert_otp.h45
-rw-r--r--src/backenddb/pg_insert_template.c66
-rw-r--r--src/backenddb/pg_insert_template.h46
-rw-r--r--src/backenddb/pg_lookup_instances.c121
-rw-r--r--src/backenddb/pg_lookup_otp_devices.c133
-rw-r--r--src/backenddb/pg_lookup_otp_devices.h45
-rw-r--r--src/backenddb/pg_lookup_template.c98
-rw-r--r--src/backenddb/pg_lookup_template.h46
-rw-r--r--src/backenddb/pg_lookup_templates.c135
-rw-r--r--src/backenddb/pg_lookup_templates.h44
-rw-r--r--src/backenddb/pg_select_account.c79
-rw-r--r--src/backenddb/pg_select_account.h44
-rw-r--r--src/backenddb/pg_select_accounts.c158
-rw-r--r--src/backenddb/pg_select_accounts.h44
-rw-r--r--src/backenddb/pg_select_otp.c91
-rw-r--r--src/backenddb/pg_select_otp.h45
-rw-r--r--src/backenddb/pg_select_otp_serial.c61
-rw-r--r--src/backenddb/pg_select_otp_serial.h43
-rw-r--r--src/backenddb/pg_update_account.c16
-rw-r--r--src/backenddb/pg_update_account.h8
-rw-r--r--src/backenddb/pg_update_instance.c4
-rw-r--r--src/backenddb/pg_update_otp.c76
-rw-r--r--src/backenddb/pg_update_otp.h47
-rw-r--r--src/backenddb/pg_update_template.c85
-rw-r--r--src/backenddb/pg_update_template.h46
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c377
-rw-r--r--src/backenddb/test_merchantdb.c78
-rw-r--r--src/include/taler_merchant_service.h993
-rw-r--r--src/include/taler_merchant_testing_lib.h196
-rw-r--r--src/include/taler_merchantdb_plugin.h210
-rw-r--r--src/lib/Makefile.am8
-rw-r--r--src/lib/merchant_api_delete_otp_device.c184
-rw-r--r--src/lib/merchant_api_get_account.c211
-rw-r--r--src/lib/merchant_api_get_accounts.c234
-rw-r--r--src/lib/merchant_api_get_instance.c92
-rw-r--r--src/lib/merchant_api_get_otp_device.c204
-rw-r--r--src/lib/merchant_api_get_otp_devices.c234
-rw-r--r--src/lib/merchant_api_get_template.c9
-rw-r--r--src/lib/merchant_api_patch_account.c254
-rw-r--r--src/lib/merchant_api_patch_instance.c40
-rw-r--r--src/lib/merchant_api_patch_otp_device.c252
-rw-r--r--src/lib/merchant_api_patch_template.c9
-rw-r--r--src/lib/merchant_api_post_account.c62
-rw-r--r--src/lib/merchant_api_post_instances.c40
-rw-r--r--src/lib/merchant_api_post_otp_devices.c237
-rw-r--r--src/lib/merchant_api_post_templates.c9
-rw-r--r--src/merchant-tools/taler-merchant-benchmark.c22
-rw-r--r--src/testing/Makefile.am13
-rw-r--r--src/testing/test_kyc_api.c7
-rw-r--r--src/testing/test_merchant_api.c125
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/16928107041
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/16928107042
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/16928107041
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/16928107041
-rw-r--r--src/testing/test_merchant_api_twisted.c7
-rwxr-xr-xsrc/testing/test_merchant_instance_auth.sh17
-rwxr-xr-xsrc/testing/test_merchant_instance_creation.sh6
-rwxr-xr-xsrc/testing/test_merchant_instance_purge.sh4
-rwxr-xr-xsrc/testing/test_merchant_instance_response.sh4
-rwxr-xr-xsrc/testing/test_merchant_kyc.sh28
-rwxr-xr-xsrc/testing/test_merchant_order_autocleanup.sh14
-rwxr-xr-xsrc/testing/test_merchant_order_creation.sh57
-rwxr-xr-xsrc/testing/test_merchant_product_creation.sh14
-rwxr-xr-xsrc/testing/test_merchant_reserve_creation.sh16
-rwxr-xr-xsrc/testing/test_merchant_transfer_tracking.sh46
-rwxr-xr-xsrc/testing/test_merchant_wirewatch.sh15
-rw-r--r--src/testing/testing_api_cmd_delete_account.c56
-rw-r--r--src/testing/testing_api_cmd_delete_otp_device.c181
-rw-r--r--src/testing/testing_api_cmd_get_instance.c229
-rw-r--r--src/testing/testing_api_cmd_get_otp_device.c227
-rw-r--r--src/testing/testing_api_cmd_get_otp_devices.c238
-rw-r--r--src/testing/testing_api_cmd_get_template.c20
-rw-r--r--src/testing/testing_api_cmd_patch_instance.c69
-rw-r--r--src/testing/testing_api_cmd_patch_otp_device.c250
-rw-r--r--src/testing/testing_api_cmd_patch_template.c23
-rw-r--r--src/testing/testing_api_cmd_pay_order.c15
-rw-r--r--src/testing/testing_api_cmd_post_account.c55
-rw-r--r--src/testing/testing_api_cmd_post_instances.c73
-rw-r--r--src/testing/testing_api_cmd_post_otp_devices.c256
-rw-r--r--src/testing/testing_api_cmd_post_templates.c24
-rw-r--r--src/testing/testing_api_cmd_post_using_templates.c38
118 files changed, 7977 insertions, 2363 deletions
diff --git a/src/backend/#taler-merchant-httpd_private-patch-templates-ID.c# b/src/backend/#taler-merchant-httpd_private-patch-templates-ID.c#
deleted file mode 100644
index 6739c7a9..00000000
--- a/src/backend/#taler-merchant-httpd_private-patch-templates-ID.c#
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- This file is part of TALER
- (C) 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 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 taler-merchant-httpd_private-patch-templates-ID.c
- * @brief implementing PATCH /templates/$ID request handling
- * @author Priscilla HUANG
- */
-#include "platform.h"
-#include "taler-merchant-httpd_private-patch-templates-ID.h"
-#include "taler-merchant-httpd_helper.h"
-#include <taler/taler_json_lib.h>
-
-
-/**
- * How often do we retry the simple INSERT database transaction?
- */
-#define MAX_RETRIES 3
-
-
-/**
- * Determine the cause of the PATCH failure in more detail and report.
- *
- * @param connection connection to report on
- * @param instance_id instance we are processing
- * @param template_id ID of the product to patch
- * @param tp template details we failed to set
- */
-static MHD_RESULT
-determine_cause (struct MHD_Connection *connection,
- const char *instance_id,
- const char *template_id,
- const struct TALER_MERCHANTDB_TemplateDetails *tp)
-{
- struct TALER_MERCHANTDB_TemplateDetails tpx;
- enum GNUNET_DB_QueryStatus qs;
-
- qs = TMH_db->lookup_template (TMH_db->cls,
- instance_id,
- template_id,
- &tpx);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- NULL);
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "unexpected serialization problem");
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
- template_id);
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- break; /* do below */
- }
-
- {
- enum TALER_ErrorCode ec;
-
- ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
- TALER_MERCHANTDB_template_details_free (&tpx);
- GNUNET_break (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE != ec);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_CONFLICT,
- ec,
- NULL);
- }
-}
-
-
-/**
- * PATCH configuration of an existing instance, given its configuration.
- *
- * @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
- */
-MHD_RESULT
-TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc)
-{
- struct TMH_MerchantInstance *mi = hc->instance;
- const char *template_id = hc->infix;
- struct TALER_MERCHANTDB_TemplateDetails tp = {0};
- enum GNUNET_DB_QueryStatus qs;
- uint32_t pos_algorithm;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("template_description",
- (const char **) &tp.template_description),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("pos_algorithm",
- &pos_algorithm),
- 0),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("pos_key",
- (const char **) &tp.pos_key),
- NULL),
- GNUNET_JSON_spec_json ("template_contract",
- &tp.template_contract),
- GNUNET_JSON_spec_end ()
- };
-
- GNUNET_assert (NULL != mi);
- GNUNET_assert (NULL != template_id);
- {
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (connection,
- hc->request_body,
- spec);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res)
- ? MHD_YES
- : MHD_NO;
- }
-
- tp.pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos_algorithm;
- if (! TMH_template_contract_valid (tp.template_contract))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "template_contract");
- }
-
- qs = TMH_db->update_template (TMH_db->cls,
- mi->settings.id,
- template_id,
- &tp);
- {
- MHD_RESULT ret = MHD_NO;
-
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_STORE_FAILED,
- NULL);
- break;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "unexpected serialization problem");
- break;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- ret = determine_cause (connection,
- mi->settings.id,
- template_id,
- &tp);
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- ret = TALER_MHD_reply_static (connection,
- MHD_HTTP_NO_CONTENT,
- NULL,
- NULL,
- 0);
- break;
- }
- GNUNET_JSON_parse_free (spec);
- return ret;
- }
-}
-
-
-/* end of taler-merchant-httpd_private-patch-templates-ID.c */
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index fed9c0a2..ef5b67bb 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -44,6 +44,8 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_private-delete-products-ID.h \
taler-merchant-httpd_private-delete-orders-ID.c \
taler-merchant-httpd_private-delete-orders-ID.h \
+ taler-merchant-httpd_private-delete-otp-devices-ID.c \
+ taler-merchant-httpd_private-delete-otp-devices-ID.h \
taler-merchant-httpd_private-delete-reserves-ID.c \
taler-merchant-httpd_private-delete-reserves-ID.h \
taler-merchant-httpd_private-delete-templates-ID.c \
@@ -52,6 +54,10 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_private-delete-transfers-ID.h \
taler-merchant-httpd_private-delete-webhooks-ID.c \
taler-merchant-httpd_private-delete-webhooks-ID.h \
+ taler-merchant-httpd_private-get-accounts.c \
+ taler-merchant-httpd_private-get-accounts.h \
+ taler-merchant-httpd_private-get-accounts-ID.c \
+ taler-merchant-httpd_private-get-accounts-ID.h \
taler-merchant-httpd_private-get-instances.c \
taler-merchant-httpd_private-get-instances.h \
taler-merchant-httpd_private-get-instances-ID.c \
@@ -66,6 +72,10 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_private-get-orders.h \
taler-merchant-httpd_private-get-orders-ID.c \
taler-merchant-httpd_private-get-orders-ID.h \
+ taler-merchant-httpd_private-get-otp-devices.c \
+ taler-merchant-httpd_private-get-otp-devices.h \
+ taler-merchant-httpd_private-get-otp-devices-ID.c \
+ taler-merchant-httpd_private-get-otp-devices-ID.h \
taler-merchant-httpd_private-get-reserves.c \
taler-merchant-httpd_private-get-reserves.h \
taler-merchant-httpd_private-get-reserves-ID.c \
@@ -80,16 +90,20 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_private-get-webhooks.h \
taler-merchant-httpd_private-get-webhooks-ID.c \
taler-merchant-httpd_private-get-webhooks-ID.h \
- taler-merchant-httpd_private-patch-templates-ID.c \
- taler-merchant-httpd_private-patch-templates-ID.h \
- taler-merchant-httpd_private-patch-webhooks-ID.c \
- taler-merchant-httpd_private-patch-webhooks-ID.h \
+ taler-merchant-httpd_private-patch-accounts-ID.c \
+ taler-merchant-httpd_private-patch-accounts-ID.h \
taler-merchant-httpd_private-patch-instances-ID.c \
taler-merchant-httpd_private-patch-instances-ID.h \
taler-merchant-httpd_private-patch-orders-ID-forget.c \
taler-merchant-httpd_private-patch-orders-ID-forget.h \
+ taler-merchant-httpd_private-patch-otp-devices-ID.c \
+ taler-merchant-httpd_private-patch-otp-devices-ID.h \
taler-merchant-httpd_private-patch-products-ID.c \
taler-merchant-httpd_private-patch-products-ID.h \
+ taler-merchant-httpd_private-patch-templates-ID.c \
+ taler-merchant-httpd_private-patch-templates-ID.h \
+ taler-merchant-httpd_private-patch-webhooks-ID.c \
+ taler-merchant-httpd_private-patch-webhooks-ID.h \
taler-merchant-httpd_private-post-account.c \
taler-merchant-httpd_private-post-account.h \
taler-merchant-httpd_private-post-instances.c \
@@ -102,6 +116,8 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_private-post-orders.h \
taler-merchant-httpd_private-post-products.c \
taler-merchant-httpd_private-post-products.h \
+ taler-merchant-httpd_private-post-otp-devices.c \
+ taler-merchant-httpd_private-post-otp-devices.h \
taler-merchant-httpd_private-post-products-ID-lock.c \
taler-merchant-httpd_private-post-products-ID-lock.h \
taler-merchant-httpd_private-post-reserves.c \
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index d8be1edc..9c543958 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -37,14 +37,13 @@
#include "taler-merchant-httpd_private-delete-instances-ID.h"
#include "taler-merchant-httpd_private-delete-products-ID.h"
#include "taler-merchant-httpd_private-delete-orders-ID.h"
+#include "taler-merchant-httpd_private-delete-otp-devices-ID.h"
#include "taler-merchant-httpd_private-delete-reserves-ID.h"
#include "taler-merchant-httpd_private-delete-templates-ID.h"
#include "taler-merchant-httpd_private-delete-transfers-ID.h"
#include "taler-merchant-httpd_private-delete-webhooks-ID.h"
-#include "taler-merchant-httpd_private-get-webhooks.h"
-#include "taler-merchant-httpd_private-get-webhooks-ID.h"
-#include "taler-merchant-httpd_private-get-templates.h"
-#include "taler-merchant-httpd_private-get-templates-ID.h"
+#include "taler-merchant-httpd_private-get-accounts.h"
+#include "taler-merchant-httpd_private-get-accounts-ID.h"
#include "taler-merchant-httpd_private-get-instances.h"
#include "taler-merchant-httpd_private-get-instances-ID.h"
#include "taler-merchant-httpd_private-get-instances-ID-kyc.h"
@@ -52,19 +51,28 @@
#include "taler-merchant-httpd_private-get-products-ID.h"
#include "taler-merchant-httpd_private-get-orders.h"
#include "taler-merchant-httpd_private-get-orders-ID.h"
+#include "taler-merchant-httpd_private-get-otp-devices.h"
+#include "taler-merchant-httpd_private-get-otp-devices-ID.h"
#include "taler-merchant-httpd_private-get-reserves.h"
#include "taler-merchant-httpd_private-get-reserves-ID.h"
#include "taler-merchant-httpd_private-get-rewards-ID.h"
#include "taler-merchant-httpd_private-get-rewards.h"
+#include "taler-merchant-httpd_private-get-templates.h"
+#include "taler-merchant-httpd_private-get-templates-ID.h"
#include "taler-merchant-httpd_private-get-transfers.h"
-#include "taler-merchant-httpd_private-patch-webhooks-ID.h"
-#include "taler-merchant-httpd_private-patch-templates-ID.h"
+#include "taler-merchant-httpd_private-get-webhooks.h"
+#include "taler-merchant-httpd_private-get-webhooks-ID.h"
+#include "taler-merchant-httpd_private-patch-accounts-ID.h"
#include "taler-merchant-httpd_private-patch-instances-ID.h"
#include "taler-merchant-httpd_private-patch-orders-ID-forget.h"
+#include "taler-merchant-httpd_private-patch-otp-devices-ID.h"
#include "taler-merchant-httpd_private-patch-products-ID.h"
+#include "taler-merchant-httpd_private-patch-templates-ID.h"
+#include "taler-merchant-httpd_private-patch-webhooks-ID.h"
#include "taler-merchant-httpd_private-post-account.h"
#include "taler-merchant-httpd_private-post-instances.h"
#include "taler-merchant-httpd_private-post-instances-ID-auth.h"
+#include "taler-merchant-httpd_private-post-otp-devices.h"
#include "taler-merchant-httpd_private-post-orders.h"
#include "taler-merchant-httpd_private-post-orders-ID-refund.h"
#include "taler-merchant-httpd_private-post-products.h"
@@ -1041,6 +1049,39 @@ url_handler (void *cls,
.allow_deleted_instance = true,
.handler = &TMH_private_get_transfers
},
+ /* POST /otp-devices: */
+ {
+ .url_prefix = "/otp-devices",
+ .method = MHD_HTTP_METHOD_POST,
+ .handler = &TMH_private_post_otp_devices
+ },
+ /* GET /otp-devices: */
+ {
+ .url_prefix = "/otp-devices",
+ .method = MHD_HTTP_METHOD_GET,
+ .handler = &TMH_private_get_otp_devices
+ },
+ /* GET /otp-devices/$ID/: */
+ {
+ .url_prefix = "/otp-devices/",
+ .method = MHD_HTTP_METHOD_GET,
+ .have_id_segment = true,
+ .handler = &TMH_private_get_otp_devices_ID
+ },
+ /* DELETE /otp-devices/$ID/: */
+ {
+ .url_prefix = "/otp-devices/",
+ .method = MHD_HTTP_METHOD_DELETE,
+ .have_id_segment = true,
+ .handler = &TMH_private_delete_otp_devices_ID
+ },
+ /* PATCH /otp-devices/$ID/: */
+ {
+ .url_prefix = "/otp-devices/",
+ .method = MHD_HTTP_METHOD_PATCH,
+ .have_id_segment = true,
+ .handler = &TMH_private_patch_otp_devices_ID
+ },
/* POST /templates: */
{
.url_prefix = "/templates",
@@ -1133,17 +1174,39 @@ url_handler (void *cls,
in the code... */
.max_upload = 1024 * 1024 * 8
},
- /* POST /account: */
+ /* POST /accounts: */
{
- .url_prefix = "/account",
+ .url_prefix = "/accounts",
.method = MHD_HTTP_METHOD_POST,
.handler = &TMH_private_post_account,
/* allow account details of up to 8 kb, that should be plenty */
.max_upload = 1024 * 8
},
- /* DELETE /account/$PAYTO: */
+ /* PATCH /accounts/$H_WIRE: */
{
- .url_prefix = "/account",
+ .url_prefix = "/accounts",
+ .method = MHD_HTTP_METHOD_PATCH,
+ .handler = &TMH_private_patch_accounts_ID,
+ .have_id_segment = true,
+ /* allow account details of up to 8 kb, that should be plenty */
+ .max_upload = 1024 * 8
+ },
+ /* GET /accounts: */
+ {
+ .url_prefix = "/accounts",
+ .method = MHD_HTTP_METHOD_GET,
+ .handler = &TMH_private_get_accounts
+ },
+ /* GET /accounts/$H_WIRE: */
+ {
+ .url_prefix = "/accounts",
+ .method = MHD_HTTP_METHOD_GET,
+ .have_id_segment = true,
+ .handler = &TMH_private_get_accounts_ID
+ },
+ /* DELETE /accounts/$H_WIRE: */
+ {
+ .url_prefix = "/accounts",
.method = MHD_HTTP_METHOD_DELETE,
.handler = &TMH_private_delete_account_ID,
.have_id_segment = true
@@ -1779,6 +1842,31 @@ url_handler (void *cls,
/**
+ * Callback invoked with information about a bank account.
+ *
+ * @param cls closure with a `struct TMH_MerchantInstance *`
+ * @param ad details about the account
+ */
+static void
+add_account_cb (void *cls,
+ const struct TALER_MERCHANTDB_AccountDetails *acc)
+{
+ struct TMH_MerchantInstance *mi = cls;
+ struct TMH_WireMethod *wm;
+
+ wm = GNUNET_new (struct TMH_WireMethod);
+ wm->h_wire = acc->h_wire;
+ wm->payto_uri = GNUNET_strdup (acc->payto_uri);
+ wm->wire_salt = acc->salt;
+ wm->wire_method = TALER_payto_get_method (acc->payto_uri);
+ wm->active = acc->active;
+ GNUNET_CONTAINER_DLL_insert (mi->wm_head,
+ mi->wm_tail,
+ wm);
+}
+
+
+/**
* Function called during startup to add all known instances to our
* hash map in memory for faster lookups when we receive requests.
*
@@ -1787,20 +1875,17 @@ url_handler (void *cls,
* @param merchant_priv private key of the instance, NULL if not available
* @param is detailed configuration settings for the instance
* @param ias authentication settings for the instance
- * @param accounts_length length of the @a accounts array
- * @param accounts list of accounts of the merchant
*/
static void
add_instance_cb (void *cls,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *ias,
- unsigned int accounts_length,
- const struct TALER_MERCHANTDB_AccountDetails accounts[])
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
{
struct TMH_MerchantInstance *mi;
-
+ enum GNUNET_DB_QueryStatus qs;
+
(void) cls;
mi = TMH_lookup_instance (is->id);
if (NULL != mi)
@@ -1829,20 +1914,15 @@ add_instance_cb (void *cls,
else
mi->deleted = true;
mi->merchant_pub = *merchant_pub;
- for (unsigned int i = 0; i<accounts_length; i++)
+ qs = TMH_db->select_accounts (TMH_db->cls,
+ mi->settings.id,
+ &add_account_cb,
+ mi);
+ if (0 > qs)
{
- const struct TALER_MERCHANTDB_AccountDetails *acc = &accounts[i];
- struct TMH_WireMethod *wm;
-
- wm = GNUNET_new (struct TMH_WireMethod);
- wm->h_wire = acc->h_wire;
- wm->payto_uri = GNUNET_strdup (acc->payto_uri);
- wm->wire_salt = acc->salt;
- wm->wire_method = TALER_payto_get_method (acc->payto_uri);
- wm->active = acc->active;
- GNUNET_CONTAINER_DLL_insert (mi->wm_head,
- mi->wm_tail,
- wm);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error loading accounts of `%s' from database\n",
+ mi->settings.id);
}
GNUNET_assert (GNUNET_OK ==
TMH_add_instance (mi));
diff --git a/src/backend/taler-merchant-httpd_post-using-templates.c b/src/backend/taler-merchant-httpd_post-using-templates.c
index 74eb0f44..67fc4b1e 100644
--- a/src/backend/taler-merchant-httpd_post-using-templates.c
+++ b/src/backend/taler-merchant-httpd_post-using-templates.c
@@ -73,7 +73,6 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
struct TMH_HandlerContext *hc)
{
struct TMH_MerchantInstance *mi = hc->instance;
- MHD_RESULT mret;
const char *template_id = hc->infix;
const char *summary = NULL;
const char *fulfillment_url = NULL;
@@ -252,6 +251,9 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
}
no_summary = (NULL == summary);
fake_body = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("otp_id",
+ uc->etp.otp_id)),
GNUNET_JSON_pack_object_steal (
"order",
GNUNET_JSON_PACK (
@@ -276,11 +278,8 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
}
uc->ihc.request_body = fake_body;
- mret = TMH_private_post_orders_with_pos_secrets (
+ return TMH_private_post_orders (
NULL, /* not even used */
connection,
- &uc->ihc,
- uc->etp.pos_key,
- uc->etp.pos_algorithm);
- return mret;
+ &uc->ihc);
}
diff --git a/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c
new file mode 100644
index 00000000..b147b84f
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c
@@ -0,0 +1,78 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-delete-otp-devices-ID.c
+ * @brief implement DELETE /otp-devices/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-delete-otp-devices-ID.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Handle a DELETE "/otp-devices/$ID" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_delete_otp_devices_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ enum GNUNET_DB_QueryStatus qs;
+
+ (void) rh;
+ GNUNET_assert (NULL != mi);
+ GNUNET_assert (NULL != hc->infix);
+ qs = TMH_db->delete_otp (TMH_db->cls,
+ mi->settings.id,
+ hc->infix);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "delete_otp");
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "delete_otp (soft)");
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
+ hc->infix);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ return TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ }
+ GNUNET_assert (0);
+ return MHD_NO;
+}
+
+
+/* end of taler-merchant-httpd_private-delete-otp-devices-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.h b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.h
new file mode 100644
index 00000000..cd129d0d
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-delete-otp-devices-ID.h
+ * @brief implement DELETE /otp-devices/$ID/
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_DELETE_OTP_DEVICES_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_DELETE_OTP_DEVICES_ID_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a DELETE "/otp-devices/$ID" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_delete_otp_devices_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-delete-otp-devices-ID.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-get-accounts-ID.c b/src/backend/taler-merchant-httpd_private-get-accounts-ID.c
new file mode 100644
index 00000000..703beeca
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-accounts-ID.c
@@ -0,0 +1,103 @@
+/*
+ This file is part of TALER
+ (C) 2023 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 taler-merchant-httpd_private-get-accounts-ID.c
+ * @brief implement GET /accounts/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-get-accounts-ID.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Handle a GET "/accounts/$ID" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_get_accounts_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ const char *h_wire_s = hc->infix;
+ struct TALER_MerchantWireHashP h_wire;
+ struct TALER_MERCHANTDB_AccountDetails tp = { 0 };
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_assert (NULL != mi);
+ GNUNET_assert (NULL != h_wire_s);
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (h_wire_s,
+ strlen (h_wire_s),
+ &h_wire,
+ sizeof (h_wire)))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED,
+ h_wire_s);
+ }
+ qs = TMH_db->select_account (TMH_db->cls,
+ mi->settings.id,
+ &h_wire,
+ &tp);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "lookup_account");
+ }
+ if (0 == qs)
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN,
+ hc->infix);
+ }
+ {
+ MHD_RESULT ret;
+
+ ret = TALER_MHD_REPLY_JSON_PACK (
+ connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_string ("payto_uri",
+ tp.payto_uri),
+ GNUNET_JSON_pack_data_auto ("h_wire",
+ &tp.h_wire),
+ GNUNET_JSON_pack_data_auto ("salt",
+ &tp.salt),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("credit_facade_url",
+ tp.credit_facade_url)));
+ /* We do not return the credentials, as they may
+ be sensitive */
+ json_decref (tp.credit_facade_credentials);
+ GNUNET_free (tp.payto_uri);
+ GNUNET_free (tp.credit_facade_url);
+ return ret;
+ }
+}
+
+
+/* end of taler-merchant-httpd_private-get-accounts-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-get-accounts-ID.h b/src/backend/taler-merchant-httpd_private-get-accounts-ID.h
new file mode 100644
index 00000000..da5cb729
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-accounts-ID.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-get-accounts-ID.h
+ * @brief implement GET /accounts/$ID/
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_ID_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a GET "/accounts/$ID" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_get_accounts_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-get-accounts-ID.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-get-accounts.c b/src/backend/taler-merchant-httpd_private-get-accounts.c
new file mode 100644
index 00000000..92ebb368
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-accounts.c
@@ -0,0 +1,78 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-get-accounts.c
+ * @brief implement GET /accounts
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-get-accounts.h"
+
+
+/**
+ * Add account details to our JSON array.
+ *
+ * @param cls a `json_t *` JSON array to build
+ * @param ad details about the account
+ */
+static void
+add_account (void *cls,
+ const struct TALER_MERCHANTDB_AccountDetails *ad)
+{
+ json_t *pa = cls;
+
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ pa,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("payto_uri",
+ ad->payto_uri),
+ GNUNET_JSON_pack_data_auto ("h_wire",
+ &ad->h_wire))));
+}
+
+
+MHD_RESULT
+TMH_private_get_accounts (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ json_t *pa;
+ enum GNUNET_DB_QueryStatus qs;
+
+ pa = json_array ();
+ GNUNET_assert (NULL != pa);
+ qs = TMH_db->select_accounts (TMH_db->cls,
+ hc->instance->settings.id,
+ &add_account,
+ pa);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ json_decref (pa);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ }
+ return TALER_MHD_REPLY_JSON_PACK (connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_array_steal ("accounts",
+ pa));
+}
+
+
+/* end of taler-merchant-httpd_private-get-accounts.c */
diff --git a/src/backend/taler-merchant-httpd_private-get-accounts.h b/src/backend/taler-merchant-httpd_private-get-accounts.h
new file mode 100644
index 00000000..0e9897cf
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-accounts.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-get-accounts.h
+ * @brief implement GET /accounts
+ * @author Priscilla HUANG
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a GET "/accounts" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_get_accounts (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-get-accounts.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.c b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.c
new file mode 100644
index 00000000..747e30cd
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.c
@@ -0,0 +1,83 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-get-otp-devices-ID.c
+ * @brief implement GET /otp-devices/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-get-otp-devices-ID.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Handle a GET "/otp-devices/$ID" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_get_otp_devices_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ struct TALER_MERCHANTDB_OtpDeviceDetails tp = { 0 };
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_assert (NULL != mi);
+ qs = TMH_db->select_otp (TMH_db->cls,
+ mi->settings.id,
+ hc->infix,
+ &tp);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "select_otp");
+ }
+ if (0 == qs)
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
+ hc->infix);
+ }
+ {
+ MHD_RESULT ret;
+
+ /* Note: we deliberately (by design) do not return the otp_key */
+ ret = TALER_MHD_REPLY_JSON_PACK (
+ connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_string ("device_description",
+ tp.otp_description),
+ GNUNET_JSON_pack_uint64 ("otp_algorithm",
+ tp.otp_algorithm),
+ GNUNET_JSON_pack_uint64 ("otp_ctr",
+ tp.otp_ctr));
+ GNUNET_free (tp.otp_description);
+ GNUNET_free (tp.otp_key);
+ return ret;
+ }
+}
+
+
+/* end of taler-merchant-httpd_private-get-otp-devices-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.h b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.h
new file mode 100644
index 00000000..78834f67
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-get-otp-devices-ID.h
+ * @brief implement GET /otp-devices/$ID/
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_ID_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a GET "/otp-devices/$ID" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_get_otp_devices_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-get-otp-devices-ID.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices.c b/src/backend/taler-merchant-httpd_private-get-otp-devices.c
new file mode 100644
index 00000000..df86842b
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-otp-devices.c
@@ -0,0 +1,80 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-get-otp-devices.c
+ * @brief implement GET /otp-devices
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-get-otp-devices.h"
+
+
+/**
+ * Add OTP device details to our JSON array.
+ *
+ * @param cls a `json_t *` JSON array to build
+ * @param template_id ID of the template
+ * @param template_description human-readable description for the template
+ */
+static void
+add_otp (void *cls,
+ const char *otp_id,
+ const char *otp_description)
+{
+ json_t *pa = cls;
+
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ pa,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("otp_device_id",
+ otp_id),
+ GNUNET_JSON_pack_string ("device_description",
+ otp_description))));
+}
+
+
+MHD_RESULT
+TMH_private_get_otp_devices (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ json_t *pa;
+ enum GNUNET_DB_QueryStatus qs;
+
+ pa = json_array ();
+ GNUNET_assert (NULL != pa);
+ qs = TMH_db->lookup_otp_devices (TMH_db->cls,
+ hc->instance->settings.id,
+ &add_otp,
+ pa);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ json_decref (pa);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ }
+ return TALER_MHD_REPLY_JSON_PACK (connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_array_steal ("otp_devices",
+ pa));
+}
+
+
+/* end of taler-merchant-httpd_private-get-otp-devices.c */
diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices.h b/src/backend/taler-merchant-httpd_private-get-otp-devices.h
new file mode 100644
index 00000000..a97ca179
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-get-otp-devices.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-get-otp-devices.h
+ * @brief implement GET /otp-devices
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Handle a GET "/otp-devices" request.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_get_otp_devices (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+/* end of taler-merchant-httpd_private-get-otp-devices.h */
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-get-templates-ID.c b/src/backend/taler-merchant-httpd_private-get-templates-ID.c
index bdb1de9d..e9dfc00f 100644
--- a/src/backend/taler-merchant-httpd_private-get-templates-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-templates-ID.c
@@ -68,16 +68,13 @@ TMH_private_get_templates_ID (const struct TMH_RequestHandler *rh,
MHD_HTTP_OK,
GNUNET_JSON_pack_string ("template_description",
tp.template_description),
- GNUNET_JSON_pack_uint64 ("pos_algorithm",
- tp.pos_algorithm),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("pos_key",
- tp.pos_key)),
+ GNUNET_JSON_pack_string ("otp_id",
+ tp.otp_id)),
GNUNET_JSON_pack_object_steal ("template_contract",
tp.template_contract));
GNUNET_free (tp.template_description);
- GNUNET_free (tp.pos_key);
-
+ GNUNET_free (tp.otp_id);
return ret;
}
}
diff --git a/src/backend/taler-merchant-httpd_private-patch-accounts-ID.c b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.c
new file mode 100644
index 00000000..04fe4ce5
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.c
@@ -0,0 +1,132 @@
+/*
+ This file is part of TALER
+ (C) 2023 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 taler-merchant-httpd_private-patch-accounts-ID.c
+ * @brief implementing PATCH /accounts/$ID request handling
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-patch-accounts-ID.h"
+#include "taler-merchant-httpd_helper.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * PATCH configuration of an existing instance, given its configuration.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_patch_accounts_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ const char *h_wire_s = hc->infix;
+ enum GNUNET_DB_QueryStatus qs;
+ const json_t *cfc;
+ const char *cfu;
+ struct TALER_MerchantWireHashP h_wire;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("credit_facade_url",
+ (const char **) &cfu),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_object_const ("credit_facade_credentials",
+ &cfc),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ GNUNET_assert (NULL != mi);
+ GNUNET_assert (NULL != h_wire_s);
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (h_wire_s,
+ strlen (h_wire_s),
+ &h_wire,
+ sizeof (h_wire)))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED,
+ h_wire_s);
+ }
+ {
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (connection,
+ hc->request_body,
+ spec);
+ if (GNUNET_OK != res)
+ return (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO;
+ }
+
+ qs = TMH_db->update_account (TMH_db->cls,
+ mi->settings.id,
+ &h_wire,
+ cfu,
+ cfc);
+ {
+ MHD_RESULT ret = MHD_NO;
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "update_account");
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "unexpected serialization problem");
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN,
+ h_wire_s);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ ret = TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ break;
+ }
+ GNUNET_JSON_parse_free (spec);
+ return ret;
+ }
+}
+
+
+/* end of taler-merchant-httpd_private-patch-accounts-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-patch-accounts-ID.h b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.h
new file mode 100644
index 00000000..752fb958
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of TALER
+ (C) 2023 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 taler-merchant-httpd_private-patch-accounts-ID.h
+ * @brief implementing PATCH /accounts request handling
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_PATCH_ACCOUNTS_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_PATCH_ACCOUNTS_ID_H
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * PATCH configuration of an existing instance, given its configuration.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_patch_accounts_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
index bc6e3aae..027d5869 100644
--- a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
@@ -63,14 +63,11 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
struct TMH_HandlerContext *hc)
{
struct TALER_MERCHANTDB_InstanceSettings is;
- const json_t *accounts;
const char *name;
const char *uts = "business";
struct TMH_WireMethod *wm_head = NULL;
struct TMH_WireMethod *wm_tail = NULL;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_array_const ("accounts",
- &accounts),
GNUNET_JSON_spec_string ("name",
&name),
GNUNET_JSON_spec_mark_optional (
@@ -102,7 +99,6 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
GNUNET_JSON_spec_end ()
};
enum GNUNET_DB_QueryStatus qs;
- bool committed = false;
GNUNET_assert (NULL != mi);
memset (&is,
@@ -162,14 +158,6 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
"jurisdiction");
}
- if (! TMH_accounts_array_valid (accounts))
- {
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
- NULL);
- }
for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
{
/* Cleanup after earlier loops */
@@ -236,258 +224,13 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
goto giveup;
}
}
-
- /* Check for changes in accounts */
- {
- unsigned int len = json_array_size (accounts);
- struct TMH_WireMethod *matches[GNUNET_NZL (len)];
- bool updated[GNUNET_NZL (len)];
-
- memset (matches,
- 0,
- sizeof (matches));
- memset (updated,
- 0,
- sizeof (updated));
- for (struct TMH_WireMethod *wm = mi->wm_head;
- NULL != wm;
- wm = wm->next)
- {
- bool matched = false;
- for (unsigned int i = 0; i<len; i++)
- {
- json_t *account = json_array_get (accounts,
- i);
- enum GNUNET_GenericReturnValue ret;
-
- ret = TMH_cmp_wire_account (account,
- wm);
- switch (ret)
- {
- case GNUNET_SYSERR:
- continue;
- case GNUNET_NO:
- matched = true;
- /* our own existing payto URIs should be unique, that is no
- duplicates in the list, so we cannot match twice */
- GNUNET_assert (NULL == matches[i]);
- matches[i] = wm;
- updated[i] = true;
- break;
- case GNUNET_YES:
- matched = true;
- /* our own existing payto URIs should be unique, that is no
- duplicates in the list, so we cannot match twice */
- GNUNET_assert (NULL == matches[i]);
- matches[i] = wm;
- break;
- }
- }
-
- /* delete unmatched (= removed) accounts */
- if ( (! matched) &&
- (wm->active) )
- {
- /* Account was REMOVED */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Existing account `%s' not found, deactivating it.\n",
- wm->payto_uri);
- wm->deleting = true;
- qs = TMH_db->inactivate_account (TMH_db->cls,
- mi->settings.id,
- &wm->h_wire);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- TMH_db->rollback (TMH_db->cls);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto retry;
- else
- goto giveup;
- }
- }
- } /* for (wm) */
-
- /* handle updates */
- for (unsigned int i = 0; i<len; i++)
- {
- struct TMH_WireMethod *wm = matches[i];
-
- if (! updated[i])
- continue;
- GNUNET_assert (NULL != wm);
- {
- struct TALER_MERCHANTDB_AccountDetails ad = {
- .payto_uri = wm->payto_uri,
- .h_wire = wm->h_wire,
- .salt = wm->wire_salt,
- .credit_facade_url = wm->credit_facade_url,
- .credit_facade_credentials = wm->credit_facade_credentials,
- .active = true
- };
-
- qs = TMH_db->update_account (TMH_db->cls,
- mi->settings.id,
- &ad);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- TMH_db->rollback (TMH_db->cls);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto retry;
- else
- goto giveup;
- }
- } /* ad scope */
- } /* for possible updates */
-
- /* Find _new_ accounts or accounts to only enable */
- for (unsigned int i = 0; i<len; i++)
- {
- json_t *account = json_array_get (accounts,
- i);
- struct TMH_WireMethod *wm = matches[i];
-
- if (NULL != wm)
- {
- if (updated[i])
- continue; /* handled above */
- if (! wm->active)
- {
- qs = TMH_db->activate_account (TMH_db->cls,
- mi->settings.id,
- &wm->h_wire);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- TMH_db->rollback (TMH_db->cls);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto retry;
- else
- goto giveup;
- }
- }
- wm->enabling = true;
- continue;
- }
-
- {
- const char *credit_facade_url = NULL;
- const json_t *credit_facade_credentials = NULL;
- const char *uri;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("payto_uri",
- &uri),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("credit_facade_url",
- &credit_facade_url),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_const ("credit_facade_credentials",
- &credit_facade_credentials),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (connection,
- account,
- ispec);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res)
- ? MHD_YES
- : MHD_NO;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Adding NEW account `%s'\n",
- uri);
- wm = TMH_setup_wire_account (uri,
- credit_facade_url,
- credit_facade_credentials);
- GNUNET_assert (NULL != wm); /* checked payto_uri validity earlier */
- GNUNET_CONTAINER_DLL_insert (wm_head,
- wm_tail,
- wm);
- } /* ispec scope */
-
- {
- struct TALER_MERCHANTDB_AccountDetails ad = {
- .payto_uri = wm->payto_uri,
- .h_wire = wm->h_wire,
- .salt = wm->wire_salt,
- .credit_facade_url = wm->credit_facade_url,
- .credit_facade_credentials = wm->credit_facade_credentials,
- .active = true
- };
-
- qs = TMH_db->insert_account (TMH_db->cls,
- mi->settings.id,
- &ad);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- TMH_db->rollback (TMH_db->cls);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto retry;
- else
- goto giveup;
- }
- } /* ad variable scope */
- } /* for (i) to find new accounts */
- } /* scope for checking for account changes */
-
- {
- struct GNUNET_DB_EventHeaderP es = {
- .size = htons (sizeof (es)),
- .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
- };
-
- TMH_db->event_notify (TMH_db->cls,
- &es,
- NULL,
- 0);
- }
qs = TMH_db->commit (TMH_db->cls);
retry:
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
continue;
- if (qs >= 0)
- committed = true;
break;
} /* for(... MAX_RETRIES) */
giveup:
- /* Deactivate existing wire methods that were removed above */
- for (struct TMH_WireMethod *wm = mi->wm_head;
- NULL != wm;
- wm = wm->next)
- {
- /* We did not flip the 'active' bits earlier because the
- DB transaction could still fail. Now it is time to update our
- runtime state. */
- GNUNET_assert (! (wm->deleting & wm->enabling));
- if (committed)
- {
- if (wm->deleting)
- wm->active = false;
- if (wm->enabling)
- wm->active = true;
- }
- wm->deleting = false;
- wm->enabling = false;
- }
- if (! committed)
- {
- struct TMH_WireMethod *wm;
-
- while (NULL != (wm = wm_head))
- {
- GNUNET_CONTAINER_DLL_remove (wm_head,
- wm_tail,
- wm);
- free_wm (wm);
- }
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_COMMIT_FAILED,
- NULL);
- }
-
/* Update our 'settings' */
GNUNET_free (mi->settings.name);
GNUNET_free (mi->settings.email);
@@ -508,23 +251,6 @@ giveup:
if (NULL != is.logo)
mi->settings.logo = GNUNET_strdup (is.logo);
- /* Add 'new' wire methods to our list */
- {
- struct TMH_WireMethod *wm;
-
- /* Note: this _could_ be done more efficiently if
- someone wrote a GNUNET_CONTAINER_DLL_merge()... */
- while (NULL != (wm = wm_head))
- {
- GNUNET_CONTAINER_DLL_remove (wm_head,
- wm_tail,
- wm);
- GNUNET_CONTAINER_DLL_insert (mi->wm_head,
- mi->wm_tail,
- wm);
- }
- }
-
GNUNET_JSON_parse_free (spec);
TMH_reload_instances (mi->settings.id);
return TALER_MHD_reply_static (connection,
diff --git a/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.c b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.c
new file mode 100644
index 00000000..f0fc8b0b
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.c
@@ -0,0 +1,122 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-patch-otp-devices-ID.c
+ * @brief implementing PATCH /otp-devices/$ID request handling
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-patch-otp-devices-ID.h"
+#include "taler-merchant-httpd_helper.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * PATCH OTP device of an existing instance.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_patch_otp_devices_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ const char *device_id = hc->infix;
+ struct TALER_MERCHANTDB_OtpDeviceDetails tp = {0};
+ enum GNUNET_DB_QueryStatus qs;
+ uint32_t otp_algorithm;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("otp_description",
+ (const char **) &tp.otp_description),
+ GNUNET_JSON_spec_uint32 ("otp_algorithm",
+ &otp_algorithm),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("otp_ctr",
+ &tp.otp_ctr),
+ NULL),
+ GNUNET_JSON_spec_string ("otp_key",
+ (const char **) &tp.otp_key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ GNUNET_assert (NULL != mi);
+ GNUNET_assert (NULL != device_id);
+ {
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (connection,
+ hc->request_body,
+ spec);
+ if (GNUNET_OK != res)
+ return (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO;
+ }
+
+ tp.otp_algorithm = (enum TALER_MerchantConfirmationAlgorithm) otp_algorithm;
+
+ qs = TMH_db->update_otp (TMH_db->cls,
+ mi->settings.id,
+ device_id,
+ &tp);
+ {
+ MHD_RESULT ret = MHD_NO;
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "update_pos");
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "unexpected serialization problem");
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
+ device_id);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ ret = TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ break;
+ }
+ GNUNET_JSON_parse_free (spec);
+ return ret;
+ }
+}
+
+
+/* end of taler-merchant-httpd_private-patch-otp-devices-ID.c */
diff --git a/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.h b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.h
new file mode 100644
index 00000000..eef1dd0a
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-patch-otp-devices-ID.h
+ * @brief implementing PATCH /otp-devices/$ID request handling
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_PATCH_OTP_DEVICES_ID_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_PATCH_OTP_DEVICES_ID_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * PATCH configuration of an existing instance, given its configuration.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_patch_otp_devices_ID (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-patch-templates-ID.c b/src/backend/taler-merchant-httpd_private-patch-templates-ID.c
index b5938368..68e0a478 100644
--- a/src/backend/taler-merchant-httpd_private-patch-templates-ID.c
+++ b/src/backend/taler-merchant-httpd_private-patch-templates-ID.c
@@ -29,12 +29,6 @@
/**
- * How often do we retry the simple INSERT database transaction?
- */
-#define MAX_RETRIES 3
-
-
-/**
* Determine the cause of the PATCH failure in more detail and report.
*
* @param connection connection to report on
@@ -109,17 +103,12 @@ TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh,
const char *template_id = hc->infix;
struct TALER_MERCHANTDB_TemplateDetails tp = {0};
enum GNUNET_DB_QueryStatus qs;
- uint32_t pos_algorithm;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("template_description",
(const char **) &tp.template_description),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("pos_algorithm",
- &pos_algorithm),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("pos_key",
- (const char **) &tp.pos_key),
+ GNUNET_JSON_spec_string ("otp_id",
+ (const char **) &tp.otp_id),
NULL),
GNUNET_JSON_spec_json ("template_contract",
&tp.template_contract),
@@ -140,7 +129,6 @@ TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh,
: MHD_NO;
}
- tp.pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos_algorithm;
if (! TMH_template_contract_valid (tp.template_contract))
{
GNUNET_break_op (0);
diff --git a/src/backend/taler-merchant-httpd_private-post-account.c b/src/backend/taler-merchant-httpd_private-post-account.c
index f9be253c..73abfe48 100644
--- a/src/backend/taler-merchant-httpd_private-post-account.c
+++ b/src/backend/taler-merchant-httpd_private-post-account.c
@@ -19,7 +19,7 @@
/**
* @file taler-merchant-httpd_private-post-account.c
- * @brief implementing POST /private/account request handling
+ * @brief implementing POST /private/accounts request handling
* @author Christian Grothoff
*/
#include "platform.h"
@@ -173,11 +173,12 @@ TMH_private_post_account (const struct TMH_RequestHandler *rh,
/* Note: we may not need to do this, as we notified
about the account change above. But also hardly hurts. */
TMH_reload_instances (mi->settings.id);
- return TALER_MHD_reply_static (connection,
- MHD_HTTP_NO_CONTENT,
- NULL,
- NULL,
- 0);
+ return TALER_MHD_REPLY_JSON_PACK (connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_data_auto ("salt",
+ &wm->wire_salt),
+ GNUNET_JSON_pack_data_auto ("h_wire",
+ &wm->h_wire));
}
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c b/src/backend/taler-merchant-httpd_private-post-instances.c
index 6c9727e9..398a846d 100644
--- a/src/backend/taler-merchant-httpd_private-post-instances.c
+++ b/src/backend/taler-merchant-httpd_private-post-instances.c
@@ -37,56 +37,6 @@
/**
- * Check if the array of @a payto_uris contains exactly the same
- * URIs as those already in @a mi (possibly in a different order).
- *
- * @param mi a merchant instance with accounts
- * @param accounts a JSON array with accounts (presumably)
- * @return true if they are 'equal', false if not or of payto_uris is not an array
- */
-static bool
-accounts_equal (const struct TMH_MerchantInstance *mi,
- const json_t *accounts)
-{
- if (! json_is_array (accounts))
- return false;
- {
- unsigned int len = json_array_size (accounts);
- enum GNUNET_GenericReturnValue matches[GNUNET_NZL (len)];
-
- for (unsigned int i = 0; i<len; i++)
- matches[i] = GNUNET_SYSERR;
- for (struct TMH_WireMethod *wm = mi->wm_head;
- NULL != wm;
- wm = wm->next)
- {
- for (unsigned int i = 0; i<len; i++)
- {
- json_t *account = json_array_get (accounts,
- i);
- enum GNUNET_GenericReturnValue ret;
-
- ret = TMH_cmp_wire_account (account,
- wm);
- if (GNUNET_SYSERR == ret)
- continue;
- if (GNUNET_SYSERR != matches[i])
- {
- GNUNET_break (0);
- return false; /* duplicate entry!? */
- }
- matches[i] = ret;
- }
- }
- for (unsigned int i = 0; i<len; i++)
- if (GNUNET_YES != matches[i])
- return false;
- }
- return true;
-}
-
-
-/**
* Generate an instance, given its configuration.
*
* @param rh context of the handler
@@ -101,15 +51,12 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
{
struct TALER_MERCHANTDB_InstanceSettings is;
struct TALER_MERCHANTDB_InstanceAuthSettings ias;
- const json_t *accounts;
const char *auth_token = NULL;
const char *uts = "business";
struct TMH_WireMethod *wm_head = NULL;
struct TMH_WireMethod *wm_tail = NULL;
const json_t *jauth;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_array_const ("accounts",
- &accounts),
GNUNET_JSON_spec_string ("id",
(const char **) &is.id),
GNUNET_JSON_spec_string ("name",
@@ -179,16 +126,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
}
- /* check accounts for well-formedness */
- if (! TMH_accounts_array_valid (accounts))
- {
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
- NULL);
- }
-
/* check 'id' well-formed */
{
static bool once;
@@ -292,9 +229,7 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
is.default_wire_transfer_delay)) &&
(GNUNET_TIME_relative_cmp (mi->settings.default_pay_delay,
==,
- is.default_pay_delay)) &&
- (accounts_equal (mi,
- accounts)) )
+ is.default_pay_delay)) )
{
return TALER_MHD_reply_static (connection,
MHD_HTTP_NO_CONTENT,
@@ -312,50 +247,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
}
}
- /* convert provided payto URIs into internal data structure with salts */
- {
- unsigned int len = json_array_size (accounts);
-
- for (unsigned int i = 0; i<len; i++)
- {
- json_t *account = json_array_get (accounts,
- i);
- const char *credit_facade_url = NULL;
- const json_t *credit_facade_credentials = NULL;
- const char *uri;
- struct TMH_WireMethod *wm;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("payto_uri",
- &uri),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("credit_facade_url",
- &credit_facade_url),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_const ("credit_facade_credentials",
- &credit_facade_credentials),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (connection,
- account,
- ispec);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res)
- ? MHD_YES
- : MHD_NO;
- wm = TMH_setup_wire_account (uri,
- credit_facade_url,
- credit_facade_credentials);
- GNUNET_assert (NULL != wm);
- GNUNET_CONTAINER_DLL_insert (wm_head,
- wm_tail,
- wm);
- }
- }
-
/* handle authentication token setup */
if (NULL == auth_token)
{
@@ -431,44 +322,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
TMH_instance_decref (mi);
return ret;
}
- for (struct TMH_WireMethod *wm = wm_head;
- NULL != wm;
- wm = wm->next)
- {
- struct TALER_MERCHANTDB_AccountDetails ad = {
- .payto_uri = wm->payto_uri,
- .salt = wm->wire_salt,
- .h_wire = wm->h_wire,
- .credit_facade_url = wm->credit_facade_url,
- .credit_facade_credentials = wm->credit_facade_credentials,
- .active = wm->active
- };
-
- qs = TMH_db->insert_account (TMH_db->cls,
- mi->settings.id,
- &ad);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- break;
- }
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- TMH_db->rollback (TMH_db->cls);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- break;
- goto retry;
- }
- {
- struct GNUNET_DB_EventHeaderP es = {
- .size = htons (sizeof (es)),
- .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
- };
-
- TMH_db->event_notify (TMH_db->cls,
- &es,
- NULL,
- 0);
- }
qs = TMH_db->commit (TMH_db->cls);
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 1c888508..34fac6a0 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -1760,11 +1760,17 @@ merge_inventory (struct OrderContext *oc)
}
+/**
+ * Parse the basics of the client request.
+ *
+ * @param[in,out] oc order context to process
+ */
static void
parse_order_request (struct OrderContext *oc)
{
const json_t *ip = NULL;
const json_t *uuid = NULL;
+ const char *otp_id = NULL;
bool create_token = true; /* default */
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("order",
@@ -1789,6 +1795,10 @@ parse_order_request (struct OrderContext *oc)
GNUNET_JSON_spec_bool ("create_token",
&create_token),
NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("otp_id",
+ &otp_id),
+ NULL),
GNUNET_JSON_spec_end ()
};
enum GNUNET_GenericReturnValue ret;
@@ -1808,6 +1818,43 @@ parse_order_request (struct OrderContext *oc)
GNUNET_TIME_relative2s (oc->refund_delay,
false));
TMH_db->expire_locks (TMH_db->cls);
+ if (NULL != otp_id)
+ {
+ struct TALER_MERCHANTDB_OtpDeviceDetails td;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = TMH_db->select_otp (TMH_db->cls,
+ oc->hc->instance->settings.id,
+ otp_id,
+ &td);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ reply_with_error (oc,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "select_otp");
+ return;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ reply_with_error (oc,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_SOFT_FAILURE,
+ "select_otp");
+ return;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ reply_with_error (oc,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
+ otp_id);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ oc->pos_key = td.otp_key;
+ oc->pos_algorithm = td.otp_algorithm;
+ }
if (create_token)
{
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
@@ -1912,12 +1959,10 @@ parse_order_request (struct OrderContext *oc)
MHD_RESULT
-TMH_private_post_orders_with_pos_secrets (
+TMH_private_post_orders (
const struct TMH_RequestHandler *rh,
struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm pos_algorithm)
+ struct TMH_HandlerContext *hc)
{
struct OrderContext *oc = hc->ctx;
@@ -1928,8 +1973,6 @@ TMH_private_post_orders_with_pos_secrets (
hc->cc = &clean_order;
oc->connection = connection;
oc->hc = hc;
- oc->pos_key = pos_key;
- oc->pos_algorithm = pos_algorithm;
}
while (1)
{
@@ -1976,18 +2019,4 @@ TMH_private_post_orders_with_pos_secrets (
}
-MHD_RESULT
-TMH_private_post_orders (
- const struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc)
-{
- return TMH_private_post_orders_with_pos_secrets (rh,
- connection,
- hc,
- NULL,
- TALER_MCA_NONE);
-}
-
-
/* end of taler-merchant-httpd_private-post-orders.c */
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.h b/src/backend/taler-merchant-httpd_private-post-orders.h
index cbbb59c0..f1127bec 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.h
+++ b/src/backend/taler-merchant-httpd_private-post-orders.h
@@ -46,25 +46,5 @@ TMH_private_post_orders (const struct TMH_RequestHandler *rh,
struct MHD_Connection *connection,
struct TMH_HandlerContext *hc);
-/**
- * Generate an order. We add the fields 'exchanges', 'merchant_pub', and
- * 'H_wire' to the order gotten from the frontend, as well as possibly other
- * fields if the frontend did not provide them. Returns the order_id.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] hc context with further information about the request
- * @param pos_key key identifying the POS, can be NULL
- * @param pos_algorithm algorithm for computing the POS confirmation
- * @return MHD result code
- */
-MHD_RESULT
-TMH_private_post_orders_with_pos_secrets (
- const struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm pos_algorithm);
-
#endif
diff --git a/src/backend/taler-merchant-httpd_private-post-otp-devices.c b/src/backend/taler-merchant-httpd_private-post-otp-devices.c
new file mode 100644
index 00000000..5521ce97
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-otp-devices.c
@@ -0,0 +1,201 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-post-otp-devices.c
+ * @brief implementing POST /otp-devices request handling
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_private-post-otp-devices.h"
+#include "taler-merchant-httpd_helper.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
+
+
+/**
+ * Check if the two otp-devices are identical.
+ *
+ * @param t1 device to compare
+ * @param t2 other device to compare
+ * @return true if they are 'equal', false if not or of payto_uris is not an array
+ */
+static bool
+otp_devices_equal (const struct TALER_MERCHANTDB_OtpDeviceDetails *t1,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *t2)
+{
+ return ( (0 == strcmp (t1->otp_description,
+ t2->otp_description)) &&
+ (0 == strcmp (t1->otp_key,
+ t2->otp_key) ) &&
+ (t1->otp_ctr == t2->otp_ctr) &&
+ (t1->otp_algorithm == t2->otp_algorithm) );
+}
+
+
+MHD_RESULT
+TMH_private_post_otp_devices (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+ struct TALER_MERCHANTDB_OtpDeviceDetails tp = { 0 };
+ const char *device_id;
+ enum GNUNET_DB_QueryStatus qs;
+ uint32_t otp_algorithm;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("otp_device_id",
+ &device_id),
+ GNUNET_JSON_spec_string ("otp_device_description",
+ (const char **) &tp.otp_description),
+ GNUNET_JSON_spec_uint32 ("otp_algorithm",
+ &otp_algorithm),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("otp_ctr",
+ &tp.otp_ctr),
+ NULL),
+ GNUNET_JSON_spec_string ("otp_key",
+ (const char **) &tp.otp_key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ 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;
+ }
+ }
+ tp.otp_algorithm = (enum TALER_MerchantConfirmationAlgorithm) otp_algorithm;
+
+ /* finally, interact with DB until no serialization error */
+ for (unsigned int i = 0; i<MAX_RETRIES; i++)
+ {
+ /* Test if a OTP device of this id is known */
+ struct TALER_MERCHANTDB_OtpDeviceDetails etp;
+
+ if (GNUNET_OK !=
+ TMH_db->start (TMH_db->cls,
+ "/post otp-devices"))
+ {
+ GNUNET_break (0);
+ GNUNET_JSON_parse_free (spec);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_START_FAILED,
+ NULL);
+ }
+ qs = TMH_db->select_otp (TMH_db->cls,
+ mi->settings.id,
+ device_id,
+ &etp);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ /* Clean up and fail hard */
+ GNUNET_break (0);
+ TMH_db->rollback (TMH_db->cls);
+ GNUNET_JSON_parse_free (spec);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ /* restart transaction */
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ /* Good, we can proceed! */
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* idempotency check: is etp == tp? */
+ {
+ bool eq;
+
+ eq = otp_devices_equal (&tp,
+ &etp);
+ GNUNET_free (etp.otp_description);
+ GNUNET_free (etp.otp_key);
+ TMH_db->rollback (TMH_db->cls);
+ GNUNET_JSON_parse_free (spec);
+ return eq
+ ? TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0)
+ : TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_PRIVATE_POST_OTP_DEVICES_CONFLICT_OTP_DEVICE_EXISTS,
+ device_id);
+ }
+ } /* end switch (qs) */
+
+ qs = TMH_db->insert_otp (TMH_db->cls,
+ mi->settings.id,
+ device_id,
+ &tp);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ TMH_db->rollback (TMH_db->cls);
+ break;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ qs = TMH_db->commit (TMH_db->cls);
+ if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+ break;
+ }
+retry:
+ GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ TMH_db->rollback (TMH_db->cls);
+ } /* for RETRIES loop */
+ 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_COMMIT_FAILED,
+ NULL);
+ }
+ return TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+}
+
+
+/* end of taler-merchant-httpd_private-post-otp-devices.c */
diff --git a/src/backend/taler-merchant-httpd_private-post-otp-devices.h b/src/backend/taler-merchant-httpd_private-post-otp-devices.h
new file mode 100644
index 00000000..96564d08
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-otp-devices.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of TALER
+ (C) 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 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 taler-merchant-httpd_private-post-otp-devices.h
+ * @brief implementing POST /otp-devices request handling
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_OTP_DEVICES_H
+#define TALER_MERCHANT_HTTPD_PRIVATE_POST_OTP_DEVICES_H
+
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * Generate an OTP device.
+ *
+ * @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
+ */
+MHD_RESULT
+TMH_private_post_otp_devices (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc);
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_private-post-templates.c b/src/backend/taler-merchant-httpd_private-post-templates.c
index 276e225f..4a5d8133 100644
--- a/src/backend/taler-merchant-httpd_private-post-templates.c
+++ b/src/backend/taler-merchant-httpd_private-post-templates.c
@@ -29,12 +29,6 @@
/**
- * How often do we retry the simple INSERT database transaction?
- */
-#define MAX_RETRIES 3
-
-
-/**
* Check if the two templates are identical.
*
* @param t1 template to compare
@@ -47,12 +41,12 @@ templates_equal (const struct TALER_MERCHANTDB_TemplateDetails *t1,
{
return ( (0 == strcmp (t1->template_description,
t2->template_description)) &&
- ( ( (NULL == t1->pos_key) &&
- (NULL == t2->pos_key) ) ||
- ( (NULL != t1->pos_key) &&
- (NULL != t2->pos_key) &&
- (0 == strcmp (t1->pos_key,
- t2->pos_key))) ) &&
+ ( ( (NULL == t1->otp_id) &&
+ (NULL == t2->otp_id) ) ||
+ ( (NULL != t1->otp_id) &&
+ (NULL != t2->otp_id) &&
+ (0 == strcmp (t1->otp_id,
+ t2->otp_id))) ) &&
(1 == json_equal (t1->template_contract,
t2->template_contract)) );
}
@@ -67,24 +61,20 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh,
struct TALER_MERCHANTDB_TemplateDetails tp = { 0 };
const char *template_id;
enum GNUNET_DB_QueryStatus qs;
- uint32_t pos_algorithm = 0;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("template_id",
&template_id),
GNUNET_JSON_spec_string ("template_description",
(const char **) &tp.template_description),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("pos_algorithm",
- &pos_algorithm),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("pos_key",
- (const char **) &tp.pos_key),
+ GNUNET_JSON_spec_string ("otp_id",
+ (const char **) &tp.otp_id),
NULL),
GNUNET_JSON_spec_json ("template_contract",
&tp.template_contract),
GNUNET_JSON_spec_end ()
};
+ uint64_t otp_serial = 0;
GNUNET_assert (NULL != mi);
{
@@ -101,7 +91,6 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh,
: MHD_NO;
}
}
- tp.pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos_algorithm;
if (! TMH_template_contract_valid (tp.template_contract))
{
GNUNET_break_op (0);
@@ -115,23 +104,63 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh,
"template_contract");
}
- /* finally, interact with DB until no serialization error */
- for (unsigned int i = 0; i<MAX_RETRIES; i++)
+ if (NULL != tp.otp_id)
{
- /* Test if a template of this id is known */
- struct TALER_MERCHANTDB_TemplateDetails etp;
-
- if (GNUNET_OK !=
- TMH_db->start (TMH_db->cls,
- "/post templates"))
+ qs = TMH_db->select_otp_serial (TMH_db->cls,
+ 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_START_FAILED,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "select_otp_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,
NULL);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
}
+ }
+
+ qs = TMH_db->insert_template (TMH_db->cls,
+ mi->settings.id,
+ template_id,
+ otp_serial,
+ &tp);
+ 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_STORE_FAILED,
+ NULL);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ GNUNET_JSON_parse_free (spec);
+ return TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ break;
+ }
+
+ {
+ /* Test if a template of this id is known */
+ struct TALER_MERCHANTDB_TemplateDetails etp;
+
qs = TMH_db->lookup_template (TMH_db->cls,
mi->settings.id,
template_id,
@@ -139,79 +168,45 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh,
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
+ case GNUNET_DB_STATUS_SOFT_ERROR:
/* Clean up and fail hard */
GNUNET_break (0);
- TMH_db->rollback (TMH_db->cls);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
NULL);
- case GNUNET_DB_STATUS_SOFT_ERROR:
- /* restart transaction */
- goto retry;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* Good, we can proceed! */
- break;
+ 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,
+ "logic error");
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* idempotency check: is etp == tp? */
- {
- bool eq;
-
- eq = templates_equal (&tp,
- &etp);
- TALER_MERCHANTDB_template_details_free (&etp);
- TMH_db->rollback (TMH_db->cls);
- GNUNET_JSON_parse_free (spec);
- return eq
- ? TALER_MHD_reply_static (connection,
- MHD_HTTP_NO_CONTENT,
- NULL,
- NULL,
- 0)
- : TALER_MHD_reply_with_error (connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_PRIVATE_POST_TEMPLATES_CONFLICT_TEMPLATE_EXISTS,
- template_id);
- }
- } /* end switch (qs) */
-
- qs = TMH_db->insert_template (TMH_db->cls,
- mi->settings.id,
- template_id,
- &tp);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- TMH_db->rollback (TMH_db->cls);
break;
}
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ /* idempotency check: is etp == tp? */
{
- qs = TMH_db->commit (TMH_db->cls);
- if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
- break;
+ bool eq;
+
+ eq = templates_equal (&tp,
+ &etp);
+ TALER_MERCHANTDB_template_details_free (&etp);
+ TMH_db->rollback (TMH_db->cls);
+ GNUNET_JSON_parse_free (spec);
+ return eq
+ ? TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0)
+ : TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_PRIVATE_POST_TEMPLATES_CONFLICT_TEMPLATE_EXISTS,
+ template_id);
}
-retry:
- GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- TMH_db->rollback (TMH_db->cls);
- } /* for RETRIES loop */
- 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_COMMIT_FAILED,
- NULL);
}
- return TALER_MHD_reply_static (connection,
- MHD_HTTP_NO_CONTENT,
- NULL,
- NULL,
- 0);
}
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 3d7d7827..6081f722 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -84,6 +84,19 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \
pg_update_instance_auth.h pg_update_instance_auth.c \
pg_inactivate_account.h pg_inactivate_account.c \
pg_activate_account.h pg_activate_account.c \
+ pg_insert_otp.h pg_insert_otp.c \
+ pg_delete_otp.h pg_delete_otp.c \
+ pg_update_otp.h pg_update_otp.c \
+ pg_select_otp.h pg_select_otp.c \
+ pg_select_otp_serial.h pg_select_otp_serial.c \
+ pg_lookup_otp_devices.h pg_lookup_otp_devices.c \
+ pg_select_account.h pg_select_account.c \
+ pg_select_accounts.h pg_select_accounts.c \
+ pg_delete_template.h pg_delete_template.c \
+ pg_insert_template.h pg_insert_template.c \
+ pg_update_template.h pg_update_template.c \
+ pg_lookup_templates.h pg_lookup_templates.c \
+ pg_lookup_template.h pg_lookup_template.c \
pg_lookup_products.h pg_lookup_products.c \
pg_lookup_product.h pg_lookup_product.c \
pg_delete_product.h pg_delete_product.c \
diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql
index bbc97828..4d286db6 100644
--- a/src/backenddb/merchant-0001.sql
+++ b/src/backenddb/merchant-0001.sql
@@ -291,6 +291,7 @@ CREATE TABLE IF NOT EXISTS merchant_contract_terms
REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE
,order_id TEXT NOT NULL
,contract_terms BYTEA NOT NULL
+ ,wallet_data BYTEA DEFAULT NULL
,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)
,creation_time INT8 NOT NULL
,pay_deadline INT8 NOT NULL
@@ -313,6 +314,8 @@ COMMENT ON COLUMN merchant_contract_terms.merchant_serial
IS 'Identifies the instance offering the contract';
COMMENT ON COLUMN merchant_contract_terms.contract_terms
IS 'These contract terms include the wallet nonce';
+COMMENT ON COLUMN merchant_contract_terms.wallet_data
+ IS 'Data provided by the wallet when paying for the contract (subcontract selection, blinded tokens, etc.)';
COMMENT ON COLUMN merchant_contract_terms.h_contract_terms
IS 'Hash over contract_terms';
COMMENT ON COLUMN merchant_contract_terms.refund_deadline
@@ -643,14 +646,37 @@ COMMENT ON COLUMN merchant_kyc.exchange_url
IS 'Which exchange base URL is this KYC status valid for';
+CREATE TABLE IF NOT EXISTS merchant_otp_devices
+ (otp_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
+ ,merchant_serial BIGINT NOT NULL
+ REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE
+ ,otp_id TEXT NOT NULL
+ ,otp_description TEXT NOT NULL
+ ,otp_key TEXT DEFAULT NULL
+ ,otp_algorithm INT NOT NULL DEFAULT (0)
+ ,otp_ctr INT8 NOT NULL DEFAULT (0)
+ ,UNIQUE (merchant_serial, otp_id)
+ );
+COMMENT ON TABLE merchant_otp_devices
+ IS 'OTP device owned by a merchant';
+COMMENT ON COLUMN merchant_otp_devices.otp_description
+ IS 'Human-readable OTP device description';
+COMMENT ON COLUMN merchant_otp_devices.otp_key
+ IS 'A base64-encoded key of the point-of-sale. It will be use by the OTP device';
+COMMENT ON COLUMN merchant_otp_devices.otp_algorithm
+ IS 'algorithm to used to generate the confirmation code. It is linked with the otp_key and otp_ctr';
+COMMENT ON COLUMN merchant_otp_devices.otp_ctr
+ IS 'counter for counter-based OTP generators';
+
+
CREATE TABLE IF NOT EXISTS merchant_template
(template_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
,merchant_serial BIGINT NOT NULL
REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE
,template_id TEXT NOT NULL
,template_description TEXT NOT NULL
- ,pos_key TEXT DEFAULT NULL
- ,pos_algorithm INT NOT NULL DEFAULT (0)
+ ,otp_device_id BIGINT
+ REFERENCES merchant_otp_devices (otp_serial) ON DELETE SET NULL
,template_contract TEXT NOT NULL -- in JSON format
,UNIQUE (merchant_serial, template_id)
);
@@ -658,14 +684,11 @@ COMMENT ON TABLE merchant_template
IS 'template used by the merchant (may be incomplete, frontend can override)';
COMMENT ON COLUMN merchant_template.template_description
IS 'Human-readable template description';
-COMMENT ON COLUMN merchant_template.pos_key
- IS 'A base64-encoded key of the point-of-sale. It will be use by the TOTP';
-COMMENT ON COLUMN merchant_template.pos_algorithm
- IS 'algorithm to used to generate the confirmation code. It is link with the pos_key';
COMMENT ON COLUMN merchant_template.template_contract
IS 'The template contract will contains some additional information.';
+
CREATE TABLE IF NOT EXISTS merchant_webhook
(webhook_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
,merchant_serial BIGINT NOT NULL
diff --git a/src/backenddb/merchantdb_helper.c b/src/backenddb/merchantdb_helper.c
index ee52cccc..4ae75020 100644
--- a/src/backenddb/merchantdb_helper.c
+++ b/src/backenddb/merchantdb_helper.c
@@ -42,7 +42,7 @@ TALER_MERCHANTDB_template_details_free (
struct TALER_MERCHANTDB_TemplateDetails *tp)
{
GNUNET_free (tp->template_description);
- GNUNET_free (tp->pos_key);
+ GNUNET_free (tp->otp_id);
json_decref (tp->template_contract);
}
diff --git a/src/backenddb/pg_delete_otp.c b/src/backenddb/pg_delete_otp.c
new file mode 100644
index 00000000..7d32b3fb
--- /dev/null
+++ b/src/backenddb/pg_delete_otp.c
@@ -0,0 +1,55 @@
+/*
+ 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 backenddb/pg_delete_otp.c
+ * @brief Implementation of the delete_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_delete_otp.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (otp_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "delete_otp",
+ "DELETE"
+ " FROM merchant_otp_devices"
+ " WHERE merchant_otp_devices.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND merchant_otp_devices.template_id=$2");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_otp",
+ params);
+}
+
diff --git a/src/backenddb/pg_delete_otp.h b/src/backenddb/pg_delete_otp.h
new file mode 100644
index 00000000..40e67e8a
--- /dev/null
+++ b/src/backenddb/pg_delete_otp.h
@@ -0,0 +1,43 @@
+/*
+ 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 backenddb/pg_delete_otp.h
+ * @brief implementation of the delete_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_DELETE_OTP_H
+#define PG_DELETE_OTP_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Delete information about an OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete OTP device of
+ * @param otp_id otp device to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if template unknown.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id);
+
+#endif
diff --git a/src/backenddb/pg_delete_template.c b/src/backenddb/pg_delete_template.c
new file mode 100644
index 00000000..15531c6b
--- /dev/null
+++ b/src/backenddb/pg_delete_template.c
@@ -0,0 +1,55 @@
+/*
+ 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 backenddb/pg_delete_template.c
+ * @brief Implementation of the delete_template function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_delete_template.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_template (void *cls,
+ const char *instance_id,
+ const char *template_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (template_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "delete_template",
+ "DELETE"
+ " FROM merchant_template"
+ " WHERE merchant_template.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND merchant_template.template_id=$2");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_template",
+ params);
+}
+
diff --git a/src/backenddb/pg_delete_template.h b/src/backenddb/pg_delete_template.h
new file mode 100644
index 00000000..ed0e0cf0
--- /dev/null
+++ b/src/backenddb/pg_delete_template.h
@@ -0,0 +1,44 @@
+/*
+ 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 backenddb/pg_delete_template.h
+ * @brief implementation of the delete_template function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_DELETE_TEMPLATE_H
+#define PG_DELETE_TEMPLATE_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Delete information about a template.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete template of
+ * @param template_id template to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if template unknown.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_template (void *cls,
+ const char *instance_id,
+ const char *template_id);
+
+
+#endif
diff --git a/src/backenddb/pg_inactivate_account.c b/src/backenddb/pg_inactivate_account.c
index 67c39462..7e0d10ae 100644
--- a/src/backenddb/pg_inactivate_account.c
+++ b/src/backenddb/pg_inactivate_account.c
@@ -38,8 +38,6 @@ TMH_PG_inactivate_account (void *cls,
};
check_connection (pg);
- /* the merchant instance is implied from the random salt
- that is part of the h_wire calculation */
PREPARE (pg,
"inactivate_account",
"UPDATE merchant_accounts SET"
diff --git a/src/backenddb/pg_insert_otp.c b/src/backenddb/pg_insert_otp.c
new file mode 100644
index 00000000..feae2230
--- /dev/null
+++ b/src/backenddb/pg_insert_otp.c
@@ -0,0 +1,74 @@
+/*
+ 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 backenddb/pg_insert_otp.c
+ * @brief Implementation of the insert_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_otp.h"
+#include "pg_helper.h"
+
+
+/**
+ * Insert details about a particular OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to insert OTP device for
+ * @param otp_id otp identifier of OTP device to insert
+ * @param td the OTP device details to insert
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td)
+{
+ struct PostgresClosure *pg = cls;
+ uint32_t pos32 = (uint32_t) td->otp_algorithm;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (otp_id),
+ GNUNET_PQ_query_param_string (td->otp_description),
+ GNUNET_PQ_query_param_string (td->otp_key),
+ GNUNET_PQ_query_param_uint32 (&pos32),
+ GNUNET_PQ_query_param_uint64 (&td->otp_ctr),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "insert_otp",
+ "INSERT INTO merchant_otp_devices"
+ "(merchant_serial"
+ ",otp_id"
+ ",otp_description"
+ ",otp_key"
+ ",otp_algorithm"
+ ",otp_ctr"
+ ")"
+ " SELECT merchant_serial,"
+ " $2, $3, $4, $5, $6"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_otp",
+ params);
+}
diff --git a/src/backenddb/pg_insert_otp.h b/src/backenddb/pg_insert_otp.h
new file mode 100644
index 00000000..70267d37
--- /dev/null
+++ b/src/backenddb/pg_insert_otp.h
@@ -0,0 +1,45 @@
+/*
+ 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 backenddb/pg_insert_otp.h
+ * @brief implementation of the insert_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_INSERT_OTP_H
+#define PG_INSERT_OTP_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Insert details about a particular OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to insert OTP device for
+ * @param otp_id otp identifier of OTP device to insert
+ * @param td the OTP device details to insert
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+
+
+#endif
diff --git a/src/backenddb/pg_insert_template.c b/src/backenddb/pg_insert_template.c
new file mode 100644
index 00000000..5fc76a1d
--- /dev/null
+++ b/src/backenddb/pg_insert_template.c
@@ -0,0 +1,66 @@
+/*
+ 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 backenddb/pg_insert_template.c
+ * @brief Implementation of the insert_template function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_template.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_template (void *cls,
+ const char *instance_id,
+ const char *template_id,
+ uint64_t otp_serial_id,
+ const struct TALER_MERCHANTDB_TemplateDetails *td)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (template_id),
+ GNUNET_PQ_query_param_string (td->template_description),
+ (0 == otp_serial_id)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_uint64 (&otp_serial_id),
+ TALER_PQ_query_param_json (td->template_contract),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "insert_template",
+ "INSERT INTO merchant_template"
+ "(merchant_serial"
+ ",template_id"
+ ",template_description"
+ ",otp_device_id"
+ ",template_contract"
+ ")"
+ " SELECT merchant_serial,"
+ " $2, $3, $4, $5"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_template",
+ params);
+}
+
diff --git a/src/backenddb/pg_insert_template.h b/src/backenddb/pg_insert_template.h
new file mode 100644
index 00000000..fb9c3700
--- /dev/null
+++ b/src/backenddb/pg_insert_template.h
@@ -0,0 +1,46 @@
+/*
+ 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 backenddb/pg_insert_template.h
+ * @brief implementation of the insert_template function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_INSERT_TEMPLATE_H
+#define PG_INSERT_TEMPLATE_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Insert details about a particular template.
+ *
+ * @param cls closure
+ * @param instance_id instance to insert template for
+ * @param template_id template identifier of template to insert
+ * @param otp_serial_id 0 if no OTP device is associated
+ * @param td the template details to insert
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_template (void *cls,
+ const char *instance_id,
+ const char *template_id,
+ uint64_t otp_serial_id,
+ const struct TALER_MERCHANTDB_TemplateDetails *td);
+
+#endif
diff --git a/src/backenddb/pg_lookup_instances.c b/src/backenddb/pg_lookup_instances.c
index 15137518..323b1957 100644
--- a/src/backenddb/pg_lookup_instances.c
+++ b/src/backenddb/pg_lookup_instances.c
@@ -92,17 +92,6 @@ prepare (struct PostgresClosure *pg)
" merchant_priv"
" FROM merchant_keys"
" WHERE merchant_serial=$1");
- PREPARE (pg,
- "lookup_accounts",
- "SELECT"
- " h_wire"
- ",salt"
- ",payto_uri"
- ",credit_facade_url"
- ",credit_facade_credentials"
- ",active"
- " FROM merchant_accounts"
- " WHERE merchant_serial=$1");
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
@@ -112,13 +101,9 @@ prepare (struct PostgresClosure *pg)
* Find the private key if possible, and invoke the callback.
*
* @param lic context we are handling
- * @param num_accounts length of @a accounts array
- * @param accounts information about accounts of the instance in @a lic
*/
static void
-call_with_accounts (struct LookupInstancesContext *lic,
- unsigned int num_accounts,
- const struct TALER_MERCHANTDB_AccountDetails accounts[])
+call_cb (struct LookupInstancesContext *lic)
{
struct PostgresClosure *pg = lic->pg;
enum GNUNET_DB_QueryStatus qs;
@@ -157,91 +142,7 @@ call_with_accounts (struct LookupInstancesContext *lic,
&lic->merchant_pub,
(0 == qs) ? NULL : &merchant_priv,
&lic->is,
- &lic->ias,
- num_accounts,
- accounts);
-}
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param cls of type `struct LookupInstancesContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_accounts_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupInstancesContext *lic = cls;
- char *paytos[GNUNET_NZL (num_results)];
- char *facade_urls[GNUNET_NZL (num_results)];
- json_t *credentials[GNUNET_NZL (num_results)];
- struct TALER_MERCHANTDB_AccountDetails accounts[GNUNET_NZL (num_results)];
-
- memset (facade_urls,
- 0,
- sizeof (facade_urls));
- memset (credentials,
- 0,
- sizeof (credentials));
- /* Note: this memset is completely superfluous, but gcc-11 (and gcc-12) have
- a bug creating a warning without it! See #7585 */
- memset (accounts,
- 0,
- sizeof (accounts));
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_MERCHANTDB_AccountDetails *account = &accounts[i];
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &account->h_wire),
- GNUNET_PQ_result_spec_auto_from_type ("salt",
- &account->salt),
- GNUNET_PQ_result_spec_string ("payto_uri",
- &paytos[i]),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("credit_facade_url",
- &facade_urls[i]),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- TALER_PQ_result_spec_json ("credit_facade_credentials",
- &credentials[i]),
- NULL),
- GNUNET_PQ_result_spec_bool ("active",
- &account->active),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
- for (unsigned int j = 0; j < i; j++)
- {
- GNUNET_free (paytos[j]);
- GNUNET_free (facade_urls[j]);
- json_decref (credentials[j]);
- }
- return;
- }
- account->payto_uri = paytos[i];
- }
- call_with_accounts (lic,
- num_results,
- accounts);
- for (unsigned int i = 0; i < num_results; i++)
- {
- GNUNET_free (paytos[i]);
- GNUNET_free (facade_urls[i]);
- json_decref (credentials[i]);
- }
+ &lic->ias);
}
@@ -316,10 +217,6 @@ lookup_instances_cb (void *cls,
NULL),
GNUNET_PQ_result_spec_end
};
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&lic->instance_serial),
- GNUNET_PQ_query_param_end
- };
memset (&lic->ias.auth_salt,
0,
@@ -337,19 +234,7 @@ lookup_instances_cb (void *cls,
return;
}
lic->is.ut = (enum TALER_KYCLOGIC_KycUserType) ut32;
- lic->qs = GNUNET_PQ_eval_prepared_multi_select (lic->pg->conn,
- "lookup_accounts",
- params,
- &lookup_accounts_cb,
- lic);
- if (0 > lic->qs)
- {
- /* lookup_accounts_cb() did not run, still notify about the
- account-less instance! */
- call_with_accounts (lic,
- 0,
- NULL);
- }
+ call_cb (lic);
GNUNET_PQ_cleanup_result (rs);
if (0 > lic->qs)
break;
diff --git a/src/backenddb/pg_lookup_otp_devices.c b/src/backenddb/pg_lookup_otp_devices.c
new file mode 100644
index 00000000..b4a2b569
--- /dev/null
+++ b/src/backenddb/pg_lookup_otp_devices.c
@@ -0,0 +1,133 @@
+/*
+ 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 backenddb/pg_lookup_otp_devices.c
+ * @brief Implementation of the lookup_otp_devices function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_otp_devices.h"
+#include "pg_helper.h"
+
+
+/**
+ * Context used for TMH_PG_lookup_otp_devices().
+ */
+struct LookupOtpDeviceContext
+{
+ /**
+ * Function to call with the results.
+ */
+ TALER_MERCHANTDB_OtpDeviceCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Did database result extraction fail?
+ */
+ bool extract_failed;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about otp_device.
+ *
+ * @param[in,out] cls of type `struct LookupOtpDeviceContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lookup_otp_devices_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupOtpDeviceContext *tlc = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ char *otp_device_id;
+ char *otp_device_description;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("otp_id",
+ &otp_device_id),
+ GNUNET_PQ_result_spec_string ("otp_description",
+ &otp_device_description),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ tlc->extract_failed = true;
+ return;
+ }
+ tlc->cb (tlc->cb_cls,
+ otp_device_id,
+ otp_device_description);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_otp_devices (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_OtpDeviceCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct LookupOtpDeviceContext tlc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ /* Can be overwritten by the lookup_otp_device_cb */
+ .extract_failed = false,
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_otp_devices",
+ "SELECT"
+ " otp_id"
+ ",otp_description"
+ " FROM merchant_otp_devices"
+ " JOIN merchant_instances"
+ " USING (merchant_serial)"
+ " WHERE merchant_instances.merchant_id=$1");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "lookup_otp_devices",
+ params,
+ &lookup_otp_devices_cb,
+ &tlc);
+ /* If there was an error inside lookup_otp_device_cb, return a hard error. */
+ if (tlc.extract_failed)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/backenddb/pg_lookup_otp_devices.h b/src/backenddb/pg_lookup_otp_devices.h
new file mode 100644
index 00000000..bb58b70f
--- /dev/null
+++ b/src/backenddb/pg_lookup_otp_devices.h
@@ -0,0 +1,45 @@
+/*
+ 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 backenddb/pg_lookup_otp_devices.h
+ * @brief implementation of the lookup_otp_devices function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_LOOKUP_OTP_DEVICES_H
+#define PG_LOOKUP_OTP_DEVICES_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Lookup all of the OTP devices the given instance has configured.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup OTP devices for
+ * @param cb function to call on all OTP devices found
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_otp_devices (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_OtpDeviceCallback cb,
+ void *cb_cls);
+
+
+#endif
diff --git a/src/backenddb/pg_lookup_template.c b/src/backenddb/pg_lookup_template.c
new file mode 100644
index 00000000..a0326bc8
--- /dev/null
+++ b/src/backenddb/pg_lookup_template.c
@@ -0,0 +1,98 @@
+/*
+ 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 backenddb/pg_lookup_template.c
+ * @brief Implementation of the lookup_template function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_template.h"
+#include "pg_helper.h"
+
+
+/**
+ * Lookup details about a particular template.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param template_id template to lookup
+ * @param[out] td set to the template details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_template (void *cls,
+ const char *instance_id,
+ const char *template_id,
+ struct TALER_MERCHANTDB_TemplateDetails *td)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (template_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_template",
+ "SELECT"
+ " mt.template_description"
+ ",mod.otp_id"
+ ",mt.template_contract"
+ " FROM merchant_template mt"
+ " JOIN merchant_instances mi"
+ " ON (mi.merchant_serial = mt.merchant_serial)"
+ " LEFT JOIN merchant_otp_devices mod"
+ " ON (mod.otp_serial = mt.otp_device_id)"
+ " WHERE mi.merchant_id=$1"
+ " AND mt.template_id=$2");
+ if (NULL == td)
+ {
+ struct GNUNET_PQ_ResultSpec rs_null[] = {
+ GNUNET_PQ_result_spec_end
+ };
+
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_template",
+ params,
+ rs_null);
+ }
+ else
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("template_description",
+ &td->template_description),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("otp_id",
+ &td->otp_id),
+ NULL),
+ TALER_PQ_result_spec_json ("template_contract",
+ &td->template_contract),
+ GNUNET_PQ_result_spec_end
+ };
+
+ td->otp_id = NULL;
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_template",
+ params,
+ rs);
+ }
+}
+
diff --git a/src/backenddb/pg_lookup_template.h b/src/backenddb/pg_lookup_template.h
new file mode 100644
index 00000000..44e01b08
--- /dev/null
+++ b/src/backenddb/pg_lookup_template.h
@@ -0,0 +1,46 @@
+/*
+ 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 backenddb/pg_lookup_template.h
+ * @brief implementation of the lookup_template function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_LOOKUP_TEMPLATE_H
+#define PG_LOOKUP_TEMPLATE_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Lookup details about a particular template.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param template_id template to lookup
+ * @param[out] td set to the template details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_template (void *cls,
+ const char *instance_id,
+ const char *template_id,
+ struct TALER_MERCHANTDB_TemplateDetails *td);
+
+
+#endif
diff --git a/src/backenddb/pg_lookup_templates.c b/src/backenddb/pg_lookup_templates.c
new file mode 100644
index 00000000..59240994
--- /dev/null
+++ b/src/backenddb/pg_lookup_templates.c
@@ -0,0 +1,135 @@
+/*
+ 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 backenddb/pg_lookup_templates.c
+ * @brief Implementation of the lookup_templates function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_templates.h"
+#include "pg_helper.h"
+
+
+/**
+ * Context used for TMH_PG_lookup_templates().
+ */
+struct LookupTemplateContext
+{
+ /**
+ * Function to call with the results.
+ */
+ TALER_MERCHANTDB_TemplatesCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Did database result extraction fail?
+ */
+ bool extract_failed;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about template.
+ *
+ * @param[in,out] cls of type `struct LookupTemplateContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lookup_templates_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupTemplateContext *tlc = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ char *template_id;
+ char *template_description;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("template_id",
+ &template_id),
+ GNUNET_PQ_result_spec_string ("template_description",
+ &template_description),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ tlc->extract_failed = true;
+ return;
+ }
+ tlc->cb (tlc->cb_cls,
+ template_id,
+ template_description);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_templates (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_TemplatesCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct LookupTemplateContext tlc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ /* Can be overwritten by the lookup_template_cb */
+ .extract_failed = false,
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_templates",
+ "SELECT"
+ " template_id"
+ ",template_description"
+ " FROM merchant_template"
+ " JOIN merchant_instances"
+ " USING (merchant_serial)"
+ " WHERE merchant_instances.merchant_id=$1");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "lookup_templates",
+ params,
+ &lookup_templates_cb,
+ &tlc);
+ /* If there was an error inside lookup_template_cb, return a hard error. */
+ if (tlc.extract_failed)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
+
+
diff --git a/src/backenddb/pg_lookup_templates.h b/src/backenddb/pg_lookup_templates.h
new file mode 100644
index 00000000..eee5be7e
--- /dev/null
+++ b/src/backenddb/pg_lookup_templates.h
@@ -0,0 +1,44 @@
+/*
+ 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 backenddb/pg_lookup_templates.h
+ * @brief implementation of the lookup_templates function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_LOOKUP_TEMPLATES_H
+#define PG_LOOKUP_TEMPLATES_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Lookup all of the templates the given instance has configured.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param cb function to call on all template found
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_templates (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_TemplatesCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/backenddb/pg_select_account.c b/src/backenddb/pg_select_account.c
new file mode 100644
index 00000000..abf7e9a8
--- /dev/null
+++ b/src/backenddb/pg_select_account.c
@@ -0,0 +1,79 @@
+/*
+ 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 backenddb/pg_select_account.c
+ * @brief Implementation of the select_account function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_select_accounts.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_account (void *cls,
+ const char *id,
+ const struct TALER_MerchantWireHashP *h_wire,
+ struct TALER_MERCHANTDB_AccountDetails *ad)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (id),
+ GNUNET_PQ_query_param_auto_from_type (h_wire),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("salt",
+ &ad->salt),
+ GNUNET_PQ_result_spec_string ("payto_uri",
+ &ad->payto_uri),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("credit_facade_url",
+ &ad->credit_facade_url),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("credit_facade_credentials",
+ &ad->credit_facade_credentials),
+ NULL),
+ GNUNET_PQ_result_spec_bool ("active",
+ &ad->active),
+ GNUNET_PQ_result_spec_end
+ };
+
+ ad->h_wire = *h_wire;
+ check_connection (pg);
+ PREPARE (pg,
+ "select_account",
+ "SELECT"
+ " salt"
+ ",payto_uri"
+ ",credit_facade_url"
+ ",credit_facade_credentials"
+ ",active"
+ " FROM merchant_accounts"
+ " WHERE merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1) AND "
+ " h_wire=$2;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "select_account",
+ params,
+ rs);
+}
diff --git a/src/backenddb/pg_select_account.h b/src/backenddb/pg_select_account.h
new file mode 100644
index 00000000..d74eaf1e
--- /dev/null
+++ b/src/backenddb/pg_select_account.h
@@ -0,0 +1,44 @@
+/*
+ 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 backenddb/pg_select_account.h
+ * @brief implementation of the select_account function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_ACCOUNT_H
+#define PG_SELECT_ACCOUNT_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Obtain information about an instance's accounts.
+ *
+ * @param cls closure
+ * @param id identifier of the instance
+ * @param h_wire wire hash of the account
+ * @param[out] ad account details returned
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_account (void *cls,
+ const char *id,
+ const struct TALER_MerchantWireHashP *h_wire,
+ struct TALER_MERCHANTDB_AccountDetails *ad);
+
+#endif
diff --git a/src/backenddb/pg_select_accounts.c b/src/backenddb/pg_select_accounts.c
new file mode 100644
index 00000000..cf15a765
--- /dev/null
+++ b/src/backenddb/pg_select_accounts.c
@@ -0,0 +1,158 @@
+/*
+ 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 backenddb/pg_select_accounts.c
+ * @brief Implementation of the select_accounts function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_select_accounts.h"
+#include "pg_helper.h"
+
+
+/**
+ * Context for select_accounts().
+ */
+struct SelectAccountsContext
+{
+ /**
+ * Function to call with the results.
+ */
+ TALER_MERCHANTDB_AccountCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Database context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Set to the return value on errors.
+ */
+ enum GNUNET_DB_QueryStatus qs;
+
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about accounts.
+ *
+ * @param cls of type `struct SelectAccountsContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+select_account_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct SelectAccountsContext *lic = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ char *payto;
+ char *facade_url = NULL;
+ json_t *credential = NULL;
+ struct TALER_MERCHANTDB_AccountDetails acc;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+ &acc.h_wire),
+ GNUNET_PQ_result_spec_auto_from_type ("salt",
+ &acc.salt),
+ GNUNET_PQ_result_spec_string ("payto_uri",
+ &payto),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("credit_facade_url",
+ &facade_url),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("credit_facade_credentials",
+ &credential),
+ NULL),
+ GNUNET_PQ_result_spec_bool ("active",
+ &acc.active),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ acc.payto_uri = payto;
+ acc.credit_facade_url = facade_url;
+ acc.credit_facade_credentials = credential;
+ lic->cb (lic->cb_cls,
+ &acc);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_accounts (void *cls,
+ const char *id,
+ TALER_MERCHANTDB_AccountCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct SelectAccountsContext lic = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (id),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ PREPARE (pg,
+ "select_accounts",
+ "SELECT"
+ " h_wire"
+ ",salt"
+ ",payto_uri"
+ ",credit_facade_url"
+ ",credit_facade_credentials"
+ ",active"
+ " FROM merchant_accounts"
+ " WHERE merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1);");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "select_accounts",
+ params,
+ &select_account_cb,
+ &lic);
+ if (0 > lic.qs)
+ return lic.qs;
+ return qs;
+}
diff --git a/src/backenddb/pg_select_accounts.h b/src/backenddb/pg_select_accounts.h
new file mode 100644
index 00000000..935fada6
--- /dev/null
+++ b/src/backenddb/pg_select_accounts.h
@@ -0,0 +1,44 @@
+/*
+ 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 backenddb/pg_select_accounts.h
+ * @brief implementation of the select_accounts function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_ACCOUNTS_H
+#define PG_SELECT_ACCOUNTS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Obtain information about an instance's accounts.
+ *
+ * @param cls closure
+ * @param id identifier of the instance
+ * @param cb function to call on each account
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_accounts (void *cls,
+ const char *id,
+ TALER_MERCHANTDB_AccountCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/backenddb/pg_select_otp.c b/src/backenddb/pg_select_otp.c
new file mode 100644
index 00000000..f105488a
--- /dev/null
+++ b/src/backenddb/pg_select_otp.c
@@ -0,0 +1,91 @@
+/*
+ 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 backenddb/pg_select_otp.c
+ * @brief Implementation of the select_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_select_otp.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ struct TALER_MERCHANTDB_OtpDeviceDetails *td)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (otp_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "select_otp",
+ "SELECT"
+ " otp_description"
+ ",otp_ctr"
+ ",otp_key"
+ ",otp_algorithm"
+ " FROM merchant_otp_devices"
+ " JOIN merchant_instances"
+ " USING (merchant_serial)"
+ " WHERE merchant_instances.merchant_id=$1"
+ " AND merchant_otp_devices.otp_id=$2");
+ if (NULL == td)
+ {
+ struct GNUNET_PQ_ResultSpec rs_null[] = {
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "select_otp",
+ params,
+ rs_null);
+ }
+ else
+ {
+ uint32_t pos32;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("otp_description",
+ &td->otp_description),
+ GNUNET_PQ_result_spec_uint64 ("otp_ctr",
+ &td->otp_ctr),
+ GNUNET_PQ_result_spec_string ("otp_key",
+ &td->otp_key),
+ GNUNET_PQ_result_spec_uint32 ("otp_algorithm",
+ &pos32),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "select_otp",
+ params,
+ rs);
+ td->otp_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32;
+ return qs;
+ }
+}
+
diff --git a/src/backenddb/pg_select_otp.h b/src/backenddb/pg_select_otp.h
new file mode 100644
index 00000000..e015cf6b
--- /dev/null
+++ b/src/backenddb/pg_select_otp.h
@@ -0,0 +1,45 @@
+/*
+ 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 backenddb/pg_select_otp.h
+ * @brief implementation of the select_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_OTP_H
+#define PG_SELECT_OTP_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Lookup details about an OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param otp_id OTP device to lookup
+ * @param[out] td set to the OTP device details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+
+#endif
diff --git a/src/backenddb/pg_select_otp_serial.c b/src/backenddb/pg_select_otp_serial.c
new file mode 100644
index 00000000..c2011aad
--- /dev/null
+++ b/src/backenddb/pg_select_otp_serial.c
@@ -0,0 +1,61 @@
+/*
+ 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 backenddb/pg_select_otp_serial.c
+ * @brief Implementation of the select_otp_serial function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_select_otp_serial.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_otp_serial (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ uint64_t *serial)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (otp_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("otp_serial",
+ serial),
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "select_otp_serial",
+ "SELECT"
+ " otp_serial"
+ " FROM merchant_otp_devices"
+ " JOIN merchant_instances"
+ " USING (merchant_serial)"
+ " WHERE merchant_instances.merchant_id=$1"
+ " AND merchant_otp_devices.otp_id=$2");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "select_otp_serial",
+ params,
+ rs);
+}
diff --git a/src/backenddb/pg_select_otp_serial.h b/src/backenddb/pg_select_otp_serial.h
new file mode 100644
index 00000000..46d128ae
--- /dev/null
+++ b/src/backenddb/pg_select_otp_serial.h
@@ -0,0 +1,43 @@
+/*
+ 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 backenddb/pg_select_otp_serial.h
+ * @brief implementation of the select_otp_serial function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_OTP_SERIAL_H
+#define PG_SELECT_OTP_SERIAL_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Lookup serial number of an OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param otp_id OTP device to lookup
+ * @param[out] serial set to the OTP device serial number * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_otp_serial (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ uint64_t *serial);
+
+#endif
diff --git a/src/backenddb/pg_update_account.c b/src/backenddb/pg_update_account.c
index 3e36596d..7458c095 100644
--- a/src/backenddb/pg_update_account.c
+++ b/src/backenddb/pg_update_account.c
@@ -30,19 +30,20 @@ enum GNUNET_DB_QueryStatus
TMH_PG_update_account (
void *cls,
const char *id,
- const struct TALER_MERCHANTDB_AccountDetails *account_details)
+ const struct TALER_MerchantWireHashP *h_wire,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (id),
- GNUNET_PQ_query_param_auto_from_type (&account_details->h_wire),
- NULL ==account_details->credit_facade_url
+ GNUNET_PQ_query_param_auto_from_type (h_wire),
+ NULL == credit_facade_url
? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (account_details->credit_facade_url),
- NULL == account_details->credit_facade_credentials
+ : GNUNET_PQ_query_param_string (credit_facade_url),
+ NULL == credit_facade_credentials
? GNUNET_PQ_query_param_null ()
- : TALER_PQ_query_param_json (account_details->credit_facade_credentials),
- GNUNET_PQ_query_param_bool (account_details->active),
+ : TALER_PQ_query_param_json (credit_facade_credentials),
GNUNET_PQ_query_param_end
};
@@ -52,7 +53,6 @@ TMH_PG_update_account (
"UPDATE merchant_accounts SET"
" credit_facade_url=$3"
",credit_facade_credentials=COALESCE($4,credit_facade_credentials)"
- ",active=$5"
" WHERE h_wire=$2"
" AND merchant_serial="
" (SELECT merchant_serial"
diff --git a/src/backenddb/pg_update_account.h b/src/backenddb/pg_update_account.h
index 52b476d9..794b99d8 100644
--- a/src/backenddb/pg_update_account.h
+++ b/src/backenddb/pg_update_account.h
@@ -31,14 +31,18 @@
*
* @param cls closure
* @param id identifier of the instance
- * @param account_details details about the account
+ * @param h_wire which account to update
+ * @param credit_facade_url new facade URL, can be NULL
+ * @param credit_facade_credentials new credentials, can be NULL to keep previous credentials
* @return database result code
*/
enum GNUNET_DB_QueryStatus
TMH_PG_update_account (
void *cls,
const char *id,
- const struct TALER_MERCHANTDB_AccountDetails *account_details);
+ const struct TALER_MerchantWireHashP *h_wire,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials);
#endif
diff --git a/src/backenddb/pg_update_instance.c b/src/backenddb/pg_update_instance.c
index 0f44c833..228e2031 100644
--- a/src/backenddb/pg_update_instance.c
+++ b/src/backenddb/pg_update_instance.c
@@ -26,6 +26,7 @@
#include "pg_update_instance.h"
#include "pg_helper.h"
+
enum GNUNET_DB_QueryStatus
TMH_PG_update_instance (void *cls,
const struct TALER_MERCHANTDB_InstanceSettings *is)
@@ -40,7 +41,8 @@ TMH_PG_update_instance (void *cls,
GNUNET_PQ_query_param_bool (is->use_stefan),
GNUNET_PQ_query_param_relative_time (
&is->default_wire_transfer_delay),
- GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
+ GNUNET_PQ_query_param_relative_time (
+ &is->default_pay_delay),
(NULL == is->website)
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_string (is->website),
diff --git a/src/backenddb/pg_update_otp.c b/src/backenddb/pg_update_otp.c
new file mode 100644
index 00000000..8f6c7176
--- /dev/null
+++ b/src/backenddb/pg_update_otp.c
@@ -0,0 +1,76 @@
+/*
+ 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 backenddb/pg_update_otp.c
+ * @brief Implementation of the update_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_otp.h"
+#include "pg_helper.h"
+
+
+/**
+ * Update details about a particular OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to update OTP device for
+ * @param otp_id OTP device to update
+ * @param td update to the OTP device details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
+ * does not yet exist.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td)
+{
+ struct PostgresClosure *pg = cls;
+ uint32_t pos32 = (uint32_t) td->otp_algorithm;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (otp_id),
+ GNUNET_PQ_query_param_string (td->otp_description),
+ GNUNET_PQ_query_param_uint32 (&pos32),
+ GNUNET_PQ_query_param_uint64 (&td->otp_ctr),
+ GNUNET_PQ_query_param_string (td->otp_key),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "update_otp",
+ "UPDATE merchant_otp_devices SET"
+ " otp_description=$3"
+ ",otp_algorithm=$4"
+ ",otp_ctr=$5"
+ ",otp_key=$6"
+ " WHERE merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND otp_id=$2");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_otp",
+ params);
+}
+
+
diff --git a/src/backenddb/pg_update_otp.h b/src/backenddb/pg_update_otp.h
new file mode 100644
index 00000000..7568608b
--- /dev/null
+++ b/src/backenddb/pg_update_otp.h
@@ -0,0 +1,47 @@
+/*
+ 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 backenddb/pg_update_otp.h
+ * @brief implementation of the update_otp function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_UPDATE_OTP_H
+#define PG_UPDATE_OTP_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Update details about a particular OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to update OTP device for
+ * @param otp_id OTP device to update
+ * @param td update to the OTP device details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
+ * does not yet exist.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_otp (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+
+
+#endif
diff --git a/src/backenddb/pg_update_template.c b/src/backenddb/pg_update_template.c
new file mode 100644
index 00000000..9f7f37c3
--- /dev/null
+++ b/src/backenddb/pg_update_template.c
@@ -0,0 +1,85 @@
+/*
+ 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 backenddb/pg_update_template.c
+ * @brief Implementation of the update_template function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_template.h"
+#include "pg_helper.h"
+
+
+/**
+ * Update details about a particular template.
+ *
+ * @param cls closure
+ * @param instance_id instance to update template for
+ * @param template_id template to update
+ * @param td update to the template details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
+ * does not yet exist.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_template (void *cls,
+ const char *instance_id,
+ const char *template_id,
+ const struct TALER_MERCHANTDB_TemplateDetails *td)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (template_id),
+ GNUNET_PQ_query_param_string (td->template_description),
+ (NULL == td->otp_id)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (td->otp_id),
+ TALER_PQ_query_param_json (td->template_contract),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "update_template",
+ "WITH mid AS ("
+ " SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ ",otp AS ("
+ " SELECT otp_serial"
+ " FROM merchant_otp_devices"
+ " JOIN mid USING (merchant_serial)"
+ " WHERE otp_id=$4)"
+ "UPDATE merchant_template SET"
+ " template_description=$3"
+ ",otp_device_id="
+ " COALESCE((SELECT otp_serial"
+ " FROM otp), NULL)"
+ ",template_contract=$5"
+ " WHERE merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM mid)"
+ " AND template_id=$2");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_template",
+ params);
+}
+
+
diff --git a/src/backenddb/pg_update_template.h b/src/backenddb/pg_update_template.h
new file mode 100644
index 00000000..26b932a2
--- /dev/null
+++ b/src/backenddb/pg_update_template.h
@@ -0,0 +1,46 @@
+/*
+ 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 backenddb/pg_update_template.h
+ * @brief implementation of the update_template function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_UPDATE_TEMPLATE_H
+#define PG_UPDATE_TEMPLATE_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Update details about a particular template.
+ *
+ * @param cls closure
+ * @param instance_id instance to update template for
+ * @param template_id template to update
+ * @param td update to the template details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
+ * does not yet exist.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_template (void *cls,
+ const char *instance_id,
+ const char *template_id,
+ const struct TALER_MERCHANTDB_TemplateDetails *td);
+
+#endif
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 70a3e644..c4074c98 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -31,6 +31,11 @@
#include <taler/taler_mhd_lib.h>
#include "taler_merchantdb_plugin.h"
#include "pg_helper.h"
+#include "pg_insert_otp.h"
+#include "pg_delete_otp.h"
+#include "pg_update_otp.h"
+#include "pg_select_otp.h"
+#include "pg_select_otp_serial.h"
#include "pg_insert_account.h"
#include "pg_update_account.h"
#include "pg_lookup_instances.h"
@@ -43,6 +48,7 @@
#include "pg_insert_exchange_account.h"
#include "pg_lookup_reserves.h"
#include "pg_lookup_instance_auth.h"
+#include "pg_lookup_otp_devices.h"
#include "pg_update_transfer_status.h"
#include "pg_insert_instance.h"
#include "pg_account_kyc_set_status.h"
@@ -72,6 +78,11 @@
#include "pg_insert_contract_terms.h"
#include "pg_update_contract_terms.h"
#include "pg_delete_contract_terms.h"
+#include "pg_delete_template.h"
+#include "pg_insert_template.h"
+#include "pg_update_template.h"
+#include "pg_lookup_templates.h"
+#include "pg_lookup_template.h"
#include "pg_lookup_deposits.h"
#include "pg_insert_exchange_signkey.h"
#include "pg_insert_deposit.h"
@@ -86,6 +97,8 @@
#include "pg_select_exchange_keys.h"
#include "pg_insert_deposit_to_transfer.h"
#include "pg_increase_refund.h"
+#include "pg_select_account.h"
+#include "pg_select_accounts.h"
#include "pg_insert_transfer.h"
#include "pg_insert_transfer_details.h"
#include "pg_store_wire_fee_by_exchange.h"
@@ -2309,283 +2322,6 @@ postgres_insert_pickup_blind_signature (
/**
- * Delete information about a template.
- *
- * @param cls closure
- * @param instance_id instance to delete template of
- * @param template_id template to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if template unknown.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_template (void *cls,
- const char *instance_id,
- const char *template_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_template",
- params);
-}
-
-
-/**
- * Insert details about a particular template.
- *
- * @param cls closure
- * @param instance_id instance to insert template for
- * @param template_id template identifier of template to insert
- * @param td the template details to insert
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_template (void *cls,
- const char *instance_id,
- const char *template_id,
- const struct TALER_MERCHANTDB_TemplateDetails *td)
-{
- struct PostgresClosure *pg = cls;
- uint32_t pos32 = (uint32_t) td->pos_algorithm;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_string (td->template_description),
- (NULL == td->pos_key)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (td->pos_key),
- GNUNET_PQ_query_param_uint32 (&pos32),
- TALER_PQ_query_param_json (td->template_contract),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_template",
- params);
-}
-
-
-/**
- * Update details about a particular template.
- *
- * @param cls closure
- * @param instance_id instance to update template for
- * @param template_id template to update
- * @param td update to the template details on success, can be NULL
- * (in that case we only want to check if the template exists)
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
- * does not yet exist.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_template (void *cls,
- const char *instance_id,
- const char *template_id,
- const struct TALER_MERCHANTDB_TemplateDetails *td)
-{
- struct PostgresClosure *pg = cls;
- uint32_t pos32 = (uint32_t) td->pos_algorithm;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_string (td->template_description),
- (NULL == td->pos_key)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (td->pos_key),
- GNUNET_PQ_query_param_uint32 (&pos32),
- TALER_PQ_query_param_json (td->template_contract),
- GNUNET_PQ_query_param_end
- };
-
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_template",
- params);
-}
-
-
-/**
- * Context used for postgres_lookup_template().
- */
-struct LookupTemplateContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_TemplatesCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Did database result extraction fail?
- */
- bool extract_failed;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about template.
- *
- * @param[in,out] cls of type `struct LookupTemplateContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_templates_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTemplateContext *tlc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- char *template_id;
- char *template_description;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("template_id",
- &template_id),
- GNUNET_PQ_result_spec_string ("template_description",
- &template_description),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- tlc->extract_failed = true;
- return;
- }
- tlc->cb (tlc->cb_cls,
- template_id,
- template_description);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup all of the templates the given instance has configured.
- *
- * @param cls closure
- * @param instance_id instance to lookup template for
- * @param cb function to call on all template found
- * @param cb_cls closure for @a cb
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_templates (void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_TemplatesCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupTemplateContext tlc = {
- .cb = cb,
- .cb_cls = cb_cls,
- /* Can be overwritten by the lookup_template_cb */
- .extract_failed = false,
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_templates",
- params,
- &lookup_templates_cb,
- &tlc);
- /* If there was an error inside lookup_template_cb, return a hard error. */
- if (tlc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Lookup details about a particular template.
- *
- * @param cls closure
- * @param instance_id instance to lookup template for
- * @param template_id template to lookup
- * @param[out] td set to the template details on success, can be NULL
- * (in that case we only want to check if the template exists)
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_template (void *cls,
- const char *instance_id,
- const char *template_id,
- struct TALER_MERCHANTDB_TemplateDetails *td)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_end
- };
-
- if (NULL == td)
- {
- struct GNUNET_PQ_ResultSpec rs_null[] = {
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_template",
- params,
- rs_null);
- }
- else
- {
- uint32_t pos32;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("template_description",
- &td->template_description),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("pos_key",
- &td->pos_key),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_uint32 ("pos_algorithm",
- &pos32),
- NULL),
- TALER_PQ_result_spec_json ("template_contract",
- &td->template_contract),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- td->pos_key = NULL;
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_template",
- params,
- rs);
- td->pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32;
- return qs;
- }
-}
-
-
-/**
* Delete information about a webhook.
*
* @param cls closure
@@ -3747,62 +3483,6 @@ postgres_connect (void *cls)
" pickup_serial, $2, $3"
" FROM merchant_reward_pickups"
" WHERE pickup_id=$1"),
- /* for postgres_lookup_templates() */
- GNUNET_PQ_make_prepare ("lookup_templates",
- "SELECT"
- " template_id"
- ",template_description"
- " FROM merchant_template"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"),
- /* for postgres_lookup_template() */
- GNUNET_PQ_make_prepare ("lookup_template",
- "SELECT"
- " template_description"
- ",pos_key"
- ",pos_algorithm"
- ",template_contract"
- " FROM merchant_template"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"
- " AND merchant_template.template_id=$2"),
- /* for postgres_delete_template() */
- GNUNET_PQ_make_prepare ("delete_template",
- "DELETE"
- " FROM merchant_template"
- " WHERE merchant_template.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_template.template_id=$2"),
- /* for postgres_insert_template() */
- GNUNET_PQ_make_prepare ("insert_template",
- "INSERT INTO merchant_template"
- "(merchant_serial"
- ",template_id"
- ",template_description"
- ",pos_key"
- ",pos_algorithm"
- ",template_contract"
- ")"
- " SELECT merchant_serial,"
- " $2, $3, $4, $5, $6"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_update_template() */
- GNUNET_PQ_make_prepare ("update_template",
- "UPDATE merchant_template SET"
- " template_description=$3"
- ",pos_key=$4"
- ",pos_algorithm=$5"
- ",template_contract=$6"
- " WHERE merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND template_id=$2"),
/* for postgres_lookup_webhooks() */
GNUNET_PQ_make_prepare ("lookup_webhooks",
"SELECT"
@@ -4010,6 +3690,18 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_insert_instance;
plugin->insert_account
= &TMH_PG_insert_account;
+ plugin->lookup_otp_devices
+ = &TMH_PG_lookup_otp_devices;
+ plugin->delete_template
+ = &TMH_PG_delete_template;
+ plugin->insert_template
+ = &TMH_PG_insert_template;
+ plugin->update_template
+ = &TMH_PG_update_template;
+ plugin->lookup_templates
+ = &TMH_PG_lookup_templates;
+ plugin->lookup_template
+ = &TMH_PG_lookup_template;
plugin->update_account
= &TMH_PG_update_account;
plugin->account_kyc_set_status
@@ -4040,6 +3732,16 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_insert_product;
plugin->update_product
= &TMH_PG_update_product;
+ plugin->insert_otp
+ = &TMH_PG_insert_otp;
+ plugin->delete_otp
+ = &TMH_PG_delete_otp;
+ plugin->update_otp
+ = &TMH_PG_update_otp;
+ plugin->select_otp
+ = &TMH_PG_select_otp;
+ plugin->select_otp_serial
+ = &TMH_PG_select_otp_serial;
plugin->lock_product
= &TMH_PG_lock_product;
plugin->expire_locks
@@ -4117,6 +3819,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_update_wirewatch_progress;
plugin->select_wirewatch_accounts
= &TMH_PG_select_wirewatch_accounts;
+ plugin->select_account
+ = &TMH_PG_select_account;
+ plugin->select_accounts
+ = &TMH_PG_select_accounts;
plugin->lookup_reserves
= &TMH_PG_lookup_reserves;
plugin->lookup_pending_reserves = &postgres_lookup_pending_reserves;
@@ -4151,11 +3857,6 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_authorize_reward;
plugin->insert_pickup
= &TMH_PG_insert_pickup;
- plugin->lookup_templates = &postgres_lookup_templates;
- plugin->lookup_template = &postgres_lookup_template;
- plugin->delete_template = &postgres_delete_template;
- plugin->insert_template = &postgres_insert_template;
- plugin->update_template = &postgres_update_template;
plugin->lookup_webhooks = &postgres_lookup_webhooks;
plugin->lookup_webhook = &postgres_lookup_webhook;
plugin->delete_webhook = &postgres_delete_webhook;
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 58470786..214bd5f8 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -259,6 +259,19 @@ check_accounts_equal (const struct TALER_MERCHANTDB_AccountDetails *a,
}
+// FIXME: use this!
+void
+lookup_accounts_cb (void *cls,
+ const struct TALER_MERCHANTDB_AccountDetails *account)
+{
+ const struct TALER_MERCHANTDB_AccountDetails *want = cls;
+
+ GNUNET_assert (0 ==
+ check_accounts_equal (want,
+ account));
+}
+
+
/**
* Called after testing 'lookup_instances'.
*
@@ -267,54 +280,33 @@ check_accounts_equal (const struct TALER_MERCHANTDB_AccountDetails *a,
* @param merchant_priv private key of the instance, NULL if not available
* @param is general instance settings
* @param ias instance authentication settings
- * @param accounts_length length of the @a accounts array
- * @param accounts list of accounts of the merchant
*/
static void
lookup_instances_cb (void *cls,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *ias,
- unsigned int accounts_length,
- const struct TALER_MERCHANTDB_AccountDetails accounts[])
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
{
struct TestLookupInstances_Closure *cmp = cls;
+
if (NULL == cmp)
return;
cmp->results_length += 1;
/* Look through the closure and test each instance for equality */
for (unsigned int i = 0; cmp->instances_to_cmp_length > i; ++i)
{
- int accounts_matching[GNUNET_NZL (accounts_length)];
- bool accounts_match = true;
if (0 != check_instances_equal (cmp->instances_to_cmp[i].instance,
is))
continue;
- if (accounts_length != cmp->instances_to_cmp[i].accounts_length)
- continue;
- /* Count matches between the accounts found and accounts in cls */
- for (unsigned int j = 0; accounts_length > j; ++j)
- accounts_matching[j] = 0;
- for (unsigned int j = 0; accounts_length > j; ++j)
- {
- for (unsigned int k = 0; accounts_length > k; ++k)
- {
- if (0 == check_accounts_equal (&cmp->instances_to_cmp[i].accounts[j],
- &accounts[k]))
- accounts_matching[j] += 1;
- }
- }
- /* Each account from the lookup should match with one and only one from cls */
- for (unsigned int j = 0; accounts_length > j; ++j)
- if (1 != accounts_matching[j])
- accounts_match = false;
- if (true == accounts_match)
- cmp->results_matching[i] += 1;
+ cmp->results_matching[i] += 1;
}
}
+
+
+
/**
* Tests @e insert_instance.
*
@@ -6866,8 +6858,7 @@ make_template (const char *id,
{
template->id = id;
template->template.template_description = "This is a test template";
- template->template.pos_key = NULL;
- template->template.pos_algorithm = 0;
+ template->template.otp_id = NULL;
template->template.template_contract = json_array ();
GNUNET_assert (NULL != template->template.template_contract);
}
@@ -6881,7 +6872,7 @@ make_template (const char *id,
static void
free_template_data (struct TemplateData *template)
{
- GNUNET_free (template->template.pos_key);
+ GNUNET_free (template->template.otp_id);
json_decref (template->template.template_contract);
}
@@ -6899,9 +6890,10 @@ check_templates_equal (const struct TALER_MERCHANTDB_TemplateDetails *a,
{
if ((0 != strcmp (a->template_description,
b->template_description)) ||
- ( (NULL == a->pos_key) && (NULL != b->pos_key)) ||
- ( (NULL != a->pos_key) && (NULL == b->pos_key)) ||
- ( (NULL != a->pos_key) && (0 != strcmp (a->pos_key, b->pos_key))) ||
+ ( (NULL == a->otp_id) && (NULL != b->otp_id)) ||
+ ( (NULL != a->otp_id) && (NULL == b->otp_id)) ||
+ ( (NULL != a->otp_id) && (0 != strcmp (a->otp_id,
+ b->otp_id))) ||
(1 != json_equal (a->template_contract,
b->template_contract)))
return 1;
@@ -6967,6 +6959,7 @@ test_lookup_template (const struct InstanceData *instance,
const struct TemplateData *template)
{
struct TALER_MERCHANTDB_TemplateDetails lookup_result;
+
if (0 > plugin->lookup_template (plugin->cls,
instance->instance.id,
template->id,
@@ -7212,8 +7205,23 @@ run_test_templates (struct TestTemplates_Closure *cls)
/* Test template update */
cls->templates[0].template.template_description =
"This is a test template that has been updated!";
- GNUNET_free (cls->templates[0].template.pos_key);
- cls->templates[0].template.pos_key = GNUNET_strdup ("pos_key");
+ GNUNET_free (cls->templates[0].template.otp_id);
+ cls->templates[0].template.otp_id = GNUNET_strdup ("otp_id");
+ {
+ /* ensure OTP device exists */
+ struct TALER_MERCHANTDB_OtpDeviceDetails td = {
+ .otp_description = "my otp",
+ .otp_key = "my key",
+ .otp_algorithm = 1,
+ .otp_ctr = 42
+ };
+ GNUNET_assert (0 <=
+ plugin->insert_otp (plugin->cls,
+ cls->instance.instance.id,
+ "otp_id",
+ &td));
+ }
+
GNUNET_assert (0 ==
json_array_append_new (
cls->templates[0].template.template_contract,
diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h
index c41080be..e92ea3b8 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -524,37 +524,11 @@ typedef void
/**
- * Information about an account of the merchant.
- */
-struct TALER_MERCHANT_AccountConfig
-{
- /**
- * Payto URI of the account.
- */
- const char *payto_uri;
-
- /**
- * Optional credit facade for the account.
- * Can be NULL.
- */
- const char *credit_facade_url;
-
- /**
- * Credit facade credentials for the account.
- * Can be NULL.
- */
- json_t *credit_facade_credentials;
-
-};
-
-/**
* Setup an new instance in the backend.
*
* @param ctx the context
* @param backend_url HTTP base URL for the backend
* @param instance_id identity of the instance to get information about
- * @param accounts_length how many bank accounts this instance has
- * @param accounts the bank accounts of the merchant instance
* @param name name of the merchant instance
* @param ut user type of the merchant instance
* @param address physical address of the merchant instance
@@ -573,8 +547,6 @@ TALER_MERCHANT_instances_post (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
const char *instance_id,
- unsigned int accounts_length,
- const struct TALER_MERCHANT_AccountConfig accounts[],
const char *name,
enum TALER_KYCLOGIC_KycUserType ut,
const json_t *address,
@@ -599,126 +571,6 @@ TALER_MERCHANT_instances_post_cancel (
/**
- * Handle for a POST /instances/$ID/account operation.
- */
-struct TALER_MERCHANT_AccountPostHandle;
-
-
-/**
- * Response for a POST /instances/$ID/account operation.
- */
-struct TALER_MERCHANT_AccountPostResponse
-{
- /**
- * HTTP response data
- */
- struct TALER_MERCHANT_HttpResponse hr;
-};
-
-
-/**
- * Function called with the result of the POST /instances/$ID/account operation.
- *
- * @param cls closure
- * @param par response data
- */
-typedef void
-(*TALER_MERCHANT_AccountPostCallback)(
- void *cls,
- const struct TALER_MERCHANT_AccountPostResponse *par);
-
-
-/**
- * Setup an new account for an instance in the backend.
- *
- * @param ctx the context
- * @param backend_url HTTP base URL for the backend
- * @param account the bank accounts to add to the merchant instance
- * @param cb function to call with the response
- * @param cb_cls closure for @a config_cb
- * @return the instances handle; NULL upon error
- */
-struct TALER_MERCHANT_AccountPostHandle *
-TALER_MERCHANT_account_post (
- struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_MERCHANT_AccountConfig *account,
- TALER_MERCHANT_AccountPostCallback cb,
- void *cb_cls);
-
-
-/**
- * Cancel /account request. Must not be called by clients after
- * the callback was invoked.
- *
- * @param pah request to cancel.
- */
-void
-TALER_MERCHANT_account_post_cancel (
- struct TALER_MERCHANT_AccountPostHandle *pah);
-
-
-/**
- * Handle for a DELETE /instances/$ID/account/$H_WIRE operation.
- */
-struct TALER_MERCHANT_AccountDeleteHandle;
-
-
-/**
- * Response for a DELETE /instances/$ID/account operation.
- */
-struct TALER_MERCHANT_AccountDeleteResponse
-{
- /**
- * HTTP response data
- */
- struct TALER_MERCHANT_HttpResponse hr;
-};
-
-
-/**
- * Function called with the result of the DELETE /instances/$ID/account/$H_WIRE operation.
- *
- * @param cls closure
- * @param par response data
- */
-typedef void
-(*TALER_MERCHANT_AccountDeleteCallback)(
- void *cls,
- const struct TALER_MERCHANT_AccountDeleteResponse *par);
-
-
-/**
- * Remove bank account from an instance in the backend.
- *
- * @param ctx the context
- * @param backend_url HTTP base URL for the backend
- * @param h_wire wire hash of the bank accounts to delete
- * @param cb function to call with the response
- * @param cb_cls closure for @a config_cb
- * @return the instances handle; NULL upon error
- */
-struct TALER_MERCHANT_AccountDeleteHandle *
-TALER_MERCHANT_account_delete (
- struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_MerchantWireHashP *h_wire,
- TALER_MERCHANT_AccountDeleteCallback cb,
- void *cb_cls);
-
-
-/**
- * Cancel /account request. Must not be called by clients after
- * the callback was invoked.
- *
- * @param pah request to cancel.
- */
-void
-TALER_MERCHANT_account_delete_cancel (
- struct TALER_MERCHANT_AccountDeleteHandle *pah);
-
-
-/**
* Handle for a PATCH /instances/$ID operation.
*/
struct TALER_MERCHANT_InstancePatchHandle;
@@ -744,8 +596,6 @@ typedef void
* or base URL of an instance if @a instance_id is NULL)
* @param instance_id identity of the instance to modify information about; NULL
* if the instance is identified as part of the @a backend_url
- * @param accounts_length length of the @a accounts array
- * @param accounts the bank accounts of the merchant instance
* @param name name of the merchant instance
* @param ut user type of the merchant instance
* @param address physical address of the merchant instance
@@ -763,8 +613,6 @@ TALER_MERCHANT_instance_patch (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
const char *instance_id,
- unsigned int accounts_length,
- const struct TALER_MERCHANT_AccountConfig accounts[static accounts_length],
const char *name,
enum TALER_KYCLOGIC_KycUserType ut,
const json_t *address,
@@ -848,39 +696,6 @@ struct TALER_MERCHANT_InstanceGetHandle;
/**
- * Details about a merchant's bank account.
- */
-struct TALER_MERCHANT_Account
-{
- /**
- * salt used to compute h_wire
- */
- struct TALER_WireSaltP salt;
-
- /**
- * payto:// URI of the account.
- */
- const char *payto_uri;
-
- /**
- * Credit facade URL of the account.
- */
- const char *credit_facade_url;
-
- /**
- * Hash of @e payto_uri and @e salt.
- */
- struct TALER_MerchantWireHashP h_wire;
-
- /**
- * true if the account is active,
- * false if it is historic.
- */
- bool active;
-};
-
-
-/**
* Details about an instance.
*/
struct TALER_MERCHANT_InstanceDetails
@@ -944,16 +759,6 @@ struct TALER_MERCHANT_InstanceGetResponse
struct
{
/**
- * Length of the @e accounts array.
- */
- unsigned int accounts_length;
-
- /**
- * bank accounts of the merchant instance
- */
- const struct TALER_MERCHANT_Account *accounts;
-
- /**
* Details about the instance.
*/
struct TALER_MERCHANT_InstanceDetails details;
@@ -1093,6 +898,420 @@ TALER_MERCHANT_instance_delete_cancel (
TALER_MERCHANT_instance_delete_cancel (arg)
+/* *************** Accounts **************** */
+
+/**
+ * Handle for a POST /instances/$ID/accounts operation.
+ */
+struct TALER_MERCHANT_AccountsPostHandle;
+
+
+/**
+ * Response for a POST /instances/$ID/account operation.
+ */
+struct TALER_MERCHANT_AccountsPostResponse
+{
+ /**
+ * HTTP response data
+ */
+ struct TALER_MERCHANT_HttpResponse hr;
+
+ /**
+ * Details depending on HTTP status.
+ */
+ union {
+
+ /**
+ * Details returned on #MHD_HTTP_OK.
+ */
+ struct {
+
+ /**
+ * Hash of @e payto_uri and @e salt.
+ */
+ struct TALER_MerchantWireHashP h_wire;
+
+ /**
+ * salt used to compute h_wire
+ */
+ struct TALER_WireSaltP salt;
+ } ok;
+
+ } details;
+};
+
+
+/**
+ * Function called with the result of the POST /instances/$ID/accounts operation.
+ *
+ * @param cls closure
+ * @param par response data
+ */
+typedef void
+(*TALER_MERCHANT_AccountsPostCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_AccountsPostResponse *par);
+
+
+/**
+ * Setup an new account for an instance in the backend.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param payto_uri URI of the bank account as per RFC 8905
+ * @param credit_facade_url credit facade for the account, can be NULL
+ * @param credit_facade_credentials credentials for credit facade, can be NULL
+ * @param account the bank accounts to add to the merchant instance
+ * @param cb function to call with the response
+ * @param cb_cls closure for @a config_cb
+ * @return the instances handle; NULL upon error
+ */
+struct TALER_MERCHANT_AccountsPostHandle *
+TALER_MERCHANT_accounts_post (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *payto_uri,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials,
+ TALER_MERCHANT_AccountsPostCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel POST /accounts request. Must not be called by clients after
+ * the callback was invoked.
+ *
+ * @param pah request to cancel.
+ */
+void
+TALER_MERCHANT_accounts_post_cancel (
+ struct TALER_MERCHANT_AccountsPostHandle *pah);
+
+
+/**
+ * Handle for a GET /accounts/$ID operation.
+ */
+struct TALER_MERCHANT_AccountGetHandle;
+
+
+/**
+ * Details about a merchant's bank account.
+ */
+struct TALER_MERCHANT_AccountDetails
+{
+ /**
+ * salt used to compute h_wire
+ */
+ struct TALER_WireSaltP salt;
+
+ /**
+ * payto:// URI of the account.
+ */
+ const char *payto_uri;
+
+ /**
+ * Credit facade URL of the account.
+ */
+ const char *credit_facade_url;
+
+ /**
+ * Hash of @e payto_uri and @e salt.
+ */
+ struct TALER_MerchantWireHashP h_wire;
+
+ /**
+ * true if the account is active,
+ * false if it is historic.
+ */
+ bool active;
+};
+
+
+/**
+ * Response returned with details about an account.
+ */
+struct TALER_MERCHANT_AccountGetResponse
+{
+ /**
+ * HTTP response data
+ */
+ struct TALER_MERCHANT_HttpResponse hr;
+
+ union
+ {
+
+ /**
+ * Data returned on #MHD_HTTP_OK.
+ */
+ struct
+ {
+
+ /**
+ * bank accounts of the merchant instance
+ */
+ struct TALER_MERCHANT_AccountDetails ad;
+
+ } ok;
+ }
+ details;
+};
+
+
+/**
+ * Function called with the result of the GET /instances/$ID/accounts/$H_WIRE operation.
+ *
+ * @param cls closure
+ * @param igr response details
+ */
+typedef void
+(*TALER_MERCHANT_AccountGetCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_AccountGetResponse *igr);
+
+
+/**
+ * Get the details on one of the accounts of an instance. Will connect to the
+ * merchant backend and obtain information about the account. The respective
+ * information will be passed to the @a cb once available.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param instance_id identity of the instance to get information about
+ * @param h_wire hash of the wire details
+ * @param cb function to call with the
+ * backend's instances information
+ * @param cb_cls closure for @a config_cb
+ * @return the instances handle; NULL upon error
+ */
+struct TALER_MERCHANT_AccountGetHandle *
+TALER_MERCHANT_account_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *instance_id,
+ const struct TALER_MerchantWireHashP *h_wire,
+ TALER_MERCHANT_AccountGetCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel GET /accounts/$H_WIRE request. Must not be called by clients after
+ * the callback was invoked.
+ *
+ * @param igh request to cancel.
+ */
+void
+TALER_MERCHANT_account_get_cancel (
+ struct TALER_MERCHANT_AccountGetHandle *igh);
+
+
+/**
+ * Handle for a GET /accounts operation.
+ */
+struct TALER_MERCHANT_AccountsGetHandle;
+
+/**
+ * Individual account (minimal information
+ * returned via GET /accounts).
+ */
+struct TALER_MERCHANT_AccountEntry
+{
+ /**
+ * account payto URI.
+ */
+ const char *payto_uri;
+
+ /**
+ * Hash of @e payto_uri and salt.
+ */
+ struct TALER_MerchantWireHashP h_wire;
+
+};
+
+
+/**
+ * Response to a GET /accounts operation.
+ */
+struct TALER_MERCHANT_AccountsGetResponse
+{
+ /**
+ * HTTP response details
+ */
+ struct TALER_MERCHANT_HttpResponse hr;
+
+ /**
+ * Details depending on status.
+ */
+ union
+ {
+ /**
+ * Details if status is #MHD_HTTP_OK.
+ */
+ struct
+ {
+ /**
+ * length of the @e accounts array
+ */
+ unsigned int accounts_length;
+
+ /**
+ * array of accounts the requested instance offers
+ */
+ const struct TALER_MERCHANT_AccountEntry *accounts;
+ } ok;
+ } details;
+};
+
+
+/**
+ * Function called with the result of the GET /accounts operation.
+ *
+ * @param cls closure
+ * @param tgr response details
+ */
+typedef void
+(*TALER_MERCHANT_AccountsGetCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_AccountsGetResponse *tgr);
+
+
+/**
+ * Make a GET /accounts request.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param cb function to call with the backend information
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_AccountsGetHandle *
+TALER_MERCHANT_accounts_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ TALER_MERCHANT_AccountsGetCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel GET /accounts operation.
+ *
+ * @param tgh operation to cancel
+ */
+void
+TALER_MERCHANT_accounts_get_cancel (
+ struct TALER_MERCHANT_AccountsGetHandle *tgh);
+
+
+/**
+ * Handle for a PATCH /account operation.
+ */
+struct TALER_MERCHANT_AccountPatchHandle;
+
+
+/**
+ * Function called with the result of the PATCH /account operation.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ */
+typedef void
+(*TALER_MERCHANT_AccountPatchCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr);
+
+
+/**
+ * Make a PATCH /accounts/$H_WIRE request to update account details. Cannot be used to change the payto URI or the salt.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param h_wire identifies the account to patch
+ * @param credit_facade_url credit facade for the account, can be NULL
+ * @param credit_facade_credentials credentials for credit facade, can be NULL
+ * @param cb function to call with the backend's result
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_AccountPatchHandle *
+TALER_MERCHANT_account_patch (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const struct TALER_MerchantWireHashP *h_wire,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials,
+ TALER_MERCHANT_AccountPatchCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel PATCH /accounts/$H_WIRE operation.
+ *
+ * @param[in] tph operation to cancel
+ */
+void
+TALER_MERCHANT_account_patch_cancel (
+ struct TALER_MERCHANT_AccountPatchHandle *tph);
+
+
+/**
+ * Handle for a DELETE /instances/$ID/account/$H_WIRE operation.
+ */
+struct TALER_MERCHANT_AccountDeleteHandle;
+
+
+/**
+ * Response for a DELETE /instances/$ID/account operation.
+ */
+struct TALER_MERCHANT_AccountDeleteResponse
+{
+ /**
+ * HTTP response data
+ */
+ struct TALER_MERCHANT_HttpResponse hr;
+};
+
+
+/**
+ * Function called with the result of the DELETE /instances/$ID/account/$H_WIRE operation.
+ *
+ * @param cls closure
+ * @param par response data
+ */
+typedef void
+(*TALER_MERCHANT_AccountDeleteCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_AccountDeleteResponse *par);
+
+
+/**
+ * Remove bank account from an instance in the backend.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param h_wire wire hash of the bank accounts to delete
+ * @param cb function to call with the response
+ * @param cb_cls closure for @a config_cb
+ * @return the instances handle; NULL upon error
+ */
+struct TALER_MERCHANT_AccountDeleteHandle *
+TALER_MERCHANT_account_delete (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const struct TALER_MerchantWireHashP *h_wire,
+ TALER_MERCHANT_AccountDeleteCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel /account request. Must not be called by clients after
+ * the callback was invoked.
+ *
+ * @param pah request to cancel.
+ */
+void
+TALER_MERCHANT_account_delete_cancel (
+ struct TALER_MERCHANT_AccountDeleteHandle *pah);
+
+
/* ********************* /products *********************** */
@@ -4922,6 +5141,364 @@ TALER_MERCHANT_kyc_get_cancel (
struct TALER_MERCHANT_KycGetHandle *kyc);
+/* ********************* /otp-devices *********************** */
+
+
+/**
+ * Handle for a GET /otp-devices operation.
+ */
+struct TALER_MERCHANT_OtpDevicesGetHandle;
+
+/**
+ * Individual OTP device (minimal information
+ * returned via GET /otp-devices).
+ */
+struct TALER_MERCHANT_OtpDeviceEntry
+{
+ /**
+ * OTP device identifier.
+ */
+ const char *otp_device_id;
+
+ /**
+ * OTP device description.
+ */
+ const char *device_description;
+
+};
+
+
+/**
+ * Response to a GET /otp-devices operation.
+ */
+struct TALER_MERCHANT_OtpDevicesGetResponse
+{
+ /**
+ * HTTP response details
+ */
+ struct TALER_MERCHANT_HttpResponse hr;
+
+ /**
+ * Details depending on status.
+ */
+ union
+ {
+ /**
+ * Details if status is #MHD_HTTP_OK.
+ */
+ struct
+ {
+ /**
+ * length of the @e otp_devices array
+ */
+ unsigned int otp_devices_length;
+
+ /**
+ * array of otp_devices the requested instance offers
+ */
+ const struct TALER_MERCHANT_OtpDeviceEntry *otp_devices;
+ } ok;
+ } details;
+};
+
+
+/**
+ * Function called with the result of the GET /otp-devices operation.
+ *
+ * @param cls closure
+ * @param tgr response details
+ */
+typedef void
+(*TALER_MERCHANT_OtpDevicesGetCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_OtpDevicesGetResponse *tgr);
+
+
+/**
+ * Make a GET /otp-devices request.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param cb function to call with the backend information
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OtpDevicesGetHandle *
+TALER_MERCHANT_otp_devices_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ TALER_MERCHANT_OtpDevicesGetCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel GET /otp-devices operation.
+ *
+ * @param tgh operation to cancel
+ */
+void
+TALER_MERCHANT_otp_devices_get_cancel (
+ struct TALER_MERCHANT_OtpDevicesGetHandle *tgh);
+
+
+/**
+ * Handle for a GET /otp-device/$ID operation. Gets details
+ * about a single otp_device. Do not confused with a
+ * `struct TALER_MERCHANT_OtpDevicesGetHandle`, which
+ * obtains a list of all otp_devices.
+ */
+struct TALER_MERCHANT_OtpDeviceGetHandle;
+
+
+/**
+ * Details in a response to a GET /otp-devices request.
+ */
+struct TALER_MERCHANT_OtpDeviceGetResponse
+{
+ /**
+ * HTTP response details.
+ */
+ struct TALER_MERCHANT_HttpResponse hr;
+
+ /**
+ * Response details depending on the HTTP status.
+ */
+ union
+ {
+ /**
+ * Information returned if the status was #MHD_HTTP_OK.
+ */
+ struct
+ {
+
+ /**
+ * description of the otp_device
+ */
+ const char *otp_device_description;
+
+ /**
+ * OTP device key.
+ */
+ const char *otp_key;
+
+ /**
+ * current counter.
+ */
+ uint64_t otp_ctr;
+
+ /**
+ * OTP algorithm used.
+ */
+ enum TALER_MerchantConfirmationAlgorithm otp_alg;
+
+ } ok;
+
+ } details;
+
+};
+
+
+/**
+ * Function called with the result of the GET /otp-device/$ID operation.
+ *
+ * @param cls closure
+ * @param tgr HTTP response details
+ */
+typedef void
+(*TALER_MERCHANT_OtpDeviceGetCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_OtpDeviceGetResponse *tgr);
+
+
+/**
+ * Make a GET /otp-device/$ID request to get details about an
+ * individual OTP device.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param otp_device_id identifier of the otp_device to inquire about
+ * @param cb function to call with the backend's otp_device information
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OtpDeviceGetHandle *
+TALER_MERCHANT_otp_device_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_device_id,
+ TALER_MERCHANT_OtpDeviceGetCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel GET /otp-devices/$ID operation.
+ *
+ * @param tgh operation to cancel
+ */
+void
+TALER_MERCHANT_otp_device_get_cancel (
+ struct TALER_MERCHANT_OtpDeviceGetHandle *tgh);
+
+
+/**
+ * Handle for a POST /otp-devices operation.
+ */
+struct TALER_MERCHANT_OtpDevicesPostHandle;
+
+
+/**
+ * Function called with the result of the POST /otp-devices operation.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ */
+typedef void
+(*TALER_MERCHANT_OtpDevicesPostCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr);
+
+
+/**
+ * Make a POST /otp-devices request to add an OTP device
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param otp_id identifier to use for the OTP device
+ * @param otp_device_description description of the OTP device
+ * @param otp_key key of the OTP device
+ * @param otp_alg OTP algorithm used
+ * @param otp_ctr counter for counter-based OTP
+ * @param cb function to call with the backend's result
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OtpDevicesPostHandle *
+TALER_MERCHANT_otp_devices_post (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_id,
+ const char *otp_device_description,
+ const char *otp_key,
+ enum TALER_MerchantConfirmationAlgorithm otp_alg,
+ uint64_t otp_ctr,
+ TALER_MERCHANT_OtpDevicesPostCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel POST /otp-devices operation.
+ *
+ * @param[in] tph operation to cancel
+ */
+void
+TALER_MERCHANT_otp_devices_post_cancel (
+ struct TALER_MERCHANT_OtpDevicesPostHandle *tph);
+
+
+/**
+ * Handle for a PATCH /otp-device operation.
+ */
+struct TALER_MERCHANT_OtpDevicePatchHandle;
+
+
+/**
+ * Function called with the result of the PATCH /otp-device operation.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ */
+typedef void
+(*TALER_MERCHANT_OtpDevicePatchCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr);
+
+
+/**
+ * Make a PATCH /otp-device request to update OTP device details
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param otp_id identifier to use for the OTP device; the OTP device must exist,
+ * or the transaction will fail with a #MHD_HTTP_NOT_FOUND
+ * HTTP status code
+ * @param otp_device_description description of the otp_device
+ * @param otp_key key of the OTP device
+ * @param otp_alg OTP algorithm used
+ * @param otp_ctr counter for counter-based OTP
+ * @param cb function to call with the backend's result
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OtpDevicePatchHandle *
+TALER_MERCHANT_otp_device_patch (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_id,
+ const char *otp_device_description,
+ const char *otp_key,
+ enum TALER_MerchantConfirmationAlgorithm otp_alg,
+ uint64_t otp_ctr,
+ TALER_MERCHANT_OtpDevicePatchCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel PATCH /otp-device operation.
+ *
+ * @param[in] tph operation to cancel
+ */
+void
+TALER_MERCHANT_otp_device_patch_cancel (
+ struct TALER_MERCHANT_OtpDevicePatchHandle *tph);
+
+
+/**
+ * Handle for a DELETE /otp-device/$ID operation.
+ */
+struct TALER_MERCHANT_OtpDeviceDeleteHandle;
+
+
+/**
+ * Function called with the result of the DELETE /otp-device/$ID operation.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ */
+typedef void
+(*TALER_MERCHANT_OtpDeviceDeleteCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr);
+
+
+/**
+ * Make a DELETE /otp-device/$ID request to delete an OTP device.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param otp_device_id identifier of the OTP device
+ * @param cb function to call with the backend's deletion status
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OtpDeviceDeleteHandle *
+TALER_MERCHANT_otp_device_delete (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_device_id,
+ TALER_MERCHANT_OtpDeviceDeleteCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel DELETE /otp-device/$ID operation.
+ *
+ * @param[in] tdh operation to cancel
+ */
+void
+TALER_MERCHANT_otp_device_delete_cancel (
+ struct TALER_MERCHANT_OtpDeviceDeleteHandle *tdh);
+
+
/* ********************* /templates *********************** */
@@ -5053,25 +5630,15 @@ struct TALER_MERCHANT_TemplateGetResponse
const char *template_description;
/**
- * Shared key with the POS
+ * OTP device ID used by the POS, NULL if none.
*/
- const char *pos_key;
-
- /**
- * Option that add amount of the order
- */
- const enum TALER_MerchantConfirmationAlgorithm pos_alg;
+ const char *otp_id;
/**
* Template for the contract.
*/
const json_t *template_contract;
- /**
- * Algorithm used to generate confirmations for the merchant.
- */
- enum TALER_MerchantConfirmationAlgorithm mca;
-
} ok;
} details;
@@ -5146,8 +5713,7 @@ typedef void
* @param backend_url HTTP base URL for the backend
* @param template_id identifier to use for the template
* @param template_description description of the template
- * @param pos_key shared key with the POS
- * @param mca algorithm used to generate confirmations
+ * @param otp_id ID of the OTP device, or NULL if OTP is not used
* @param template_contract is the contract of the company
* @param cb function to call with the backend's result
* @param cb_cls closure for @a cb
@@ -5159,8 +5725,7 @@ TALER_MERCHANT_templates_post (
const char *backend_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm mca,
+ const char *otp_id,
const json_t *template_contract,
TALER_MERCHANT_TemplatesPostCallback cb,
void *cb_cls);
@@ -5203,8 +5768,7 @@ typedef void
* or the transaction will fail with a #MHD_HTTP_NOT_FOUND
* HTTP status code
* @param template_description description of the template
- * @param pos_key shared key with the POS
- * @param mca algorithm used to generate confirmations
+ * @param otp_id device ID of the OTP device, or NULL if OTP is not used
* @param template_contract is the contract of the company
* @param cb function to call with the backend's result
* @param cb_cls closure for @a cb
@@ -5216,8 +5780,7 @@ TALER_MERCHANT_template_patch (
const char *backend_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm mca,
+ const char *otp_id,
json_t *template_contract,
TALER_MERCHANT_TemplatePatchCallback cb,
void *cb_cls);
diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h
index bc888fa7..ded1ac5a 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -91,7 +91,6 @@ TALER_TESTING_cmd_merchant_get_instances (const char *label,
* @param merchant_url base URL of the merchant serving the
* POST /instances request.
* @param instance_id the ID of the instance to create
- * @param payto_uri payment URI to use
* @param http_status expected HTTP response code.
* @return the command.
*/
@@ -99,7 +98,6 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_instances (const char *label,
const char *merchant_url,
const char *instance_id,
- const char *payto_uri,
unsigned int http_status);
@@ -129,8 +127,6 @@ TALER_TESTING_cmd_merchant_post_instance_auth (const char *label,
* @param merchant_url base URL of the merchant serving the
* POST /instances request.
* @param instance_id the ID of the instance to query
- * @param accounts_length length of the @a payto_uris array
- * @param payto_uris URIs of the bank accounts of the merchant instance
* @param name name of the merchant instance
* @param address physical address of the merchant instance
* @param jurisdiction jurisdiction of the merchant instance
@@ -146,8 +142,6 @@ TALER_TESTING_cmd_merchant_post_instances2 (
const char *label,
const char *merchant_url,
const char *instance_id,
- unsigned int accounts_length,
- const char *payto_uris[],
const char *name,
json_t *address,
json_t *jurisdiction,
@@ -181,19 +175,39 @@ TALER_TESTING_cmd_merchant_post_account (
/**
+ * Define a "PATCH /account" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ * POST /instances request.
+ * @param create_account_ref reference to account setup command
+ * @param credit_facade_url credit facade URL to configure, can be NULL
+ * @param credit_facade_credentials credit facade credentials to use, can be NULL
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_patch_account (
+ const char *label,
+ const char *merchant_url,
+ const char *create_account_ref,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials,
+ unsigned int http_status);
+
+
+/**
* Define a "DELETE /account" CMD.
*
* @param label command label.
- * @param get_instance_ref reference to a GET instance command
- * @param payto_uri payto URI of the account to delete, must be in the response of the GET instance command
+ * @param create_account_ref reference to account setup command
* @param http_status expected HTTP response code.
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_account (
const char *label,
- const char *get_instance_ref,
- const char *payto_uri,
+ const char *create_account_ref,
unsigned int http_status);
@@ -220,8 +234,6 @@ TALER_TESTING_cmd_merchant_patch_instance (
const char *label,
const char *merchant_url,
const char *instance_id,
- unsigned int payto_uris_length,
- const char *payto_uris[],
const char *name,
json_t *address,
json_t *jurisdiction,
@@ -252,35 +264,6 @@ TALER_TESTING_cmd_merchant_get_instance (const char *label,
/**
- * Define a "GET instance" CMD that compares accounts returned.
- *
- * @param label command label.
- * @param merchant_url base URL of the merchant serving the
- * GET /instances/$ID request.
- * @param instance_id the ID of the instance to query
- * @param http_status expected HTTP response code.
- * @param instance_reference reference to a "POST /instances" or "PATCH /instances/$ID" CMD
- * that will provide what we expect the backend to return to us
- * @param active_accounts the accounts the merchant is actively using.
- * @param active_accounts_length length of @e active_accounts.
- * @param inactive_accounts the accounts the merchant is no longer using.
- * @param inactive_accounts_length length of @e inactive_accounts.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_merchant_get_instance2 (const char *label,
- const char *merchant_url,
- const char *instance_id,
- unsigned int http_status,
- const char *instance_reference,
- const char *active_accounts[],
- unsigned int active_accounts_length,
- const char *inactive_accounts[],
- unsigned int
- inactive_accounts_length);
-
-
-/**
* Define a "PURGE instance" CMD.
*
* @param label command label.
@@ -1511,6 +1494,117 @@ TALER_TESTING_cmd_merchant_kyc_get (
enum TALER_AmlDecisionState expected_aml_state);
+/* ****** OTP devices ******* */
+
+
+/**
+ * Define a "POST /otp-devices" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ * POST /otps request.
+ * @param otp_id the ID of the otp device to modify
+ * @param otp_description description of the otp device
+ * @param otp_key base32-encoded key to verify the payment
+ * @param otp_alg is an option that show the amount of the order. it is linked with the @a otp_key
+ * @param otp_ctr counter to use (if in counter mode)
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_post_otp_devices (
+ const char *label,
+ const char *merchant_url,
+ const char *otp_id,
+ const char *otp_description,
+ const char *otp_key,
+ enum TALER_MerchantConfirmationAlgorithm otp_alg,
+ uint64_t otp_ctr,
+ unsigned int http_status);
+
+
+/**
+ * Define a "PATCH /otp-devices/$ID" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ * PATCH /otp-devices request.
+ * @param otp_id the ID of the otp device to modify
+ * @param otp_description description of the otp device
+ * @param otp_key base32-encoded key to verify the payment
+ * @param otp_alg is an option that show the amount of the order. it is linked with the @a otp_key
+ * @param otp_ctr counter to use (if in counter mode)
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_patch_otp_device (
+ const char *label,
+ const char *merchant_url,
+ const char *otp_id,
+ const char *otp_description,
+ const char *otp_key,
+ enum TALER_MerchantConfirmationAlgorithm otp_alg,
+ uint64_t otp_ctr,
+ unsigned int http_status);
+
+
+/**
+ * Define a "GET /otp-devices" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ * GET /otp-devices request.
+ * @param http_status expected HTTP response code.
+ * @param ... NULL-terminated list of labels (const char *) of
+ * otp (commands) we expect to be returned in the list
+ * (assuming @a http_code is #MHD_HTTP_OK)
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_otp_devices (const char *label,
+ const char *merchant_url,
+ unsigned int http_status,
+ ...);
+
+
+/**
+ * Define a "GET otp device" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ * GET /otp-devices/$ID request.
+ * @param otp_id the ID of the otp to query
+ * @param http_status expected HTTP response code.
+ * @param otp_reference reference to a "POST /otp-devices" or "PATCH /otp-devices/$ID" CMD
+ * that will provide what we expect the backend to return to us
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_otp_device (const char *label,
+ const char *merchant_url,
+ const char *otp_id,
+ unsigned int http_status,
+ const char *otp_reference);
+
+
+/**
+ * Define a "DELETE otp device" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ * DELETE /otp-devices/$ID request.
+ * @param otp_id the ID of the otp to query
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_delete_otp_device (const char *label,
+ const char *merchant_url,
+ const char *otp_id,
+ unsigned int http_status);
+
+
/* ****** Templates ******* */
/**
@@ -1521,8 +1615,7 @@ TALER_TESTING_cmd_merchant_kyc_get (
* POST /templates request.
* @param template_id the ID of the template to query
* @param template_description description of the template
- * @param pos_key base32-encoded key to verify the payment
- * @param pos_alg is an option that show the amount of the order. it is linked with the pos_key
+ * @param otp_id OTP device ID, NULL for none
* @param template_contract where the contract of the company is
* @param http_status expected HTTP response code.
* @return the command.
@@ -1533,8 +1626,7 @@ TALER_TESTING_cmd_merchant_post_templates2 (
const char *merchant_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- const enum TALER_MerchantConfirmationAlgorithm pos_alg,
+ const char *otp_id,
json_t *template_contract,
unsigned int http_status);
@@ -1566,8 +1658,7 @@ TALER_TESTING_cmd_merchant_post_templates (const char *label,
* PATCH /template request.
* @param template_id the ID of the template to query
* @param template_description description of the template
- * @param pos_key base32-encoded key to verify the payment
- * @param pos_alg is an option that show the amount of the order. it is linked with the pos_key
+ * @param otp_id OTP device to use
* @param template_contract contract of the company
* @param http_status expected HTTP response code.
* @return the command.
@@ -1578,8 +1669,7 @@ TALER_TESTING_cmd_merchant_patch_template (
const char *merchant_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- const enum TALER_MerchantConfirmationAlgorithm pos_alg,
+ const char *otp_id,
json_t *template_contract,
unsigned int http_status);
@@ -1645,6 +1735,7 @@ TALER_TESTING_cmd_merchant_delete_template (const char *label,
*
* @param label command label.
* @param template_ref label of command that created the template to use
+ * @param otp_ref label of command that created OTP device we use (or NULL for no OTP)
* @param merchant_url base URL of the merchant serving the
* POST /using-templates request.
* @param using_template_id template ID to use
@@ -1659,6 +1750,7 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_using_templates (
const char *label,
const char *template_ref,
+ const char *otp_ref,
const char *merchant_url,
const char *using_template_id,
const char *summary,
@@ -1909,8 +2001,10 @@ TALER_TESTING_cmd_checkserver2 (const char *label,
op (h_wire, const struct TALER_MerchantWireHashP) \
op (proposal_reference, const char) \
op (template_description, const char) \
- op (template_pos_key, const char) \
- op (template_pos_alg, const enum TALER_MerchantConfirmationAlgorithm) \
+ op (otp_device_description, const char) \
+ op (otp_id, const char) \
+ op (otp_key, const char) \
+ op (otp_alg, const enum TALER_MerchantConfirmationAlgorithm) \
op (template_id, const char) \
op (template_contract, const json_t) \
op (event_type, const char) \
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 1c0cd37c..14dedce5 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -96,20 +96,20 @@ struct TALER_MERCHANTDB_AccountDetails
/**
* Actual account address as a payto://-URI.
*/
- const char *payto_uri;
+ char *payto_uri;
/**
* Where can the taler-merchant-wirewatch helper
* download information about incoming transfers?
* NULL if not available.
*/
- const char *credit_facade_url;
+ char *credit_facade_url;
/**
* JSON with credentials to use to access the
* @e credit_facade_url.
*/
- const json_t *credit_facade_credentials;
+ json_t *credit_facade_credentials;
/**
* Is the account set for active use in new contracts?
@@ -219,9 +219,20 @@ typedef void
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *ias,
- unsigned int accounts_length,
- const struct TALER_MERCHANTDB_AccountDetails accounts[]);
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
+
+
+/**
+ * Callback invoked with information about a bank account.
+ *
+ * @param cls closure
+ * @param ad details about the account
+ */
+typedef void
+(*TALER_MERCHANTDB_AccountCallback)(
+ void *cls,
+ const struct TALER_MERCHANTDB_AccountDetails *ad);
+
/**
* Typically called by `lookup_products`.
@@ -311,7 +322,7 @@ struct TALER_MERCHANTDB_ProductDetails
/**
* Typically called by `lookup_templates`.
*
- * @param cls a `json_t *` JSON array to build
+ * @param cls closure
* @param template_id ID of the template
* @param template_description description of the template
*/
@@ -322,6 +333,19 @@ typedef void
/**
+ * Typically called by `lookup_otp_devices`.
+ *
+ * @param cls closure
+ * @param otp_id ID of the OTP device
+ * @param otp_description description of the OTP device
+ */
+typedef void
+(*TALER_MERCHANTDB_OtpDeviceCallback)(void *cls,
+ const char *otp_id,
+ const char *otp_description);
+
+
+/**
* Details about a template.
*/
struct TALER_MERCHANTDB_TemplateDetails
@@ -332,19 +356,42 @@ struct TALER_MERCHANTDB_TemplateDetails
char *template_description;
/**
- * Base64-encoded key, or NULL.
+ * In this template contract, we can have additional information.
+ */
+ json_t *template_contract;
+
+ /**
+ * ID of the OTP device linked to the template, or NULL.
*/
- char *pos_key;
+ char *otp_id;
+};
+
+
+/**
+ * Details about an OTP device.
+ */
+struct TALER_MERCHANTDB_OtpDeviceDetails
+{
/**
- * In this template contract, we can have additional information.
+ * Description of the device.
*/
- json_t *template_contract;
+ char *otp_description;
+
+ /**
+ * Current usage counter value.
+ */
+ uint64_t otp_ctr;
+
+ /**
+ * Base64-encoded key.
+ */
+ char *otp_key;
/**
* Algorithm used to compute purchase confirmations.
*/
- enum TALER_MerchantConfirmationAlgorithm pos_algorithm;
+ enum TALER_MerchantConfirmationAlgorithm otp_algorithm;
};
@@ -1223,14 +1270,52 @@ struct TALER_MERCHANTDB_Plugin
*
* @param cls closure
* @param id identifier of the instance
- * @param account_details details about the account to update
+ * @param h_wire which account to update
+ * @param credit_facade_url new facade URL, can be NULL
+ * @param credit_facade_credentials new credentials, can be NULL
* @return database result code
*/
enum GNUNET_DB_QueryStatus
(*update_account)(
void *cls,
const char *id,
- const struct TALER_MERCHANTDB_AccountDetails *account_details);
+ const struct TALER_MerchantWireHashP *h_wire,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials);
+
+
+ /**
+ * Obtain information about an instance's accounts.
+ *
+ * @param cls closure
+ * @param id identifier of the instance
+ * @param cb function to call on each account
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_accounts)(
+ void *cls,
+ const char *id,
+ TALER_MERCHANTDB_AccountCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Obtain detailed information about an instance's account.
+ *
+ * @param cls closure
+ * @param id identifier of the instance
+ * @param h_wire wire hash of the account
+ * @param[out] ad account details returned
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_account)(
+ void *cls,
+ const char *id,
+ const struct TALER_MerchantWireHashP *h_wire,
+ struct TALER_MERCHANTDB_AccountDetails *ad);
/**
@@ -2867,6 +2952,7 @@ struct TALER_MERCHANTDB_Plugin
* @param cls closure
* @param instance_id instance to insert template for
* @param template_id template identifier of template to insert
+ * @param otp_serial_id 0 if no OTP device is associated
* @param td the template details to insert
* @return database result code
*/
@@ -2874,10 +2960,106 @@ struct TALER_MERCHANTDB_Plugin
(*insert_template)(void *cls,
const char *instance_id,
const char *template_id,
+ uint64_t otp_serial_id,
const struct TALER_MERCHANTDB_TemplateDetails *td);
/**
+ * Delete information about an OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete OTP device of
+ * @param otp_id otp device to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if template unknown.
+ */
+ enum GNUNET_DB_QueryStatus
+ (*delete_otp) (void *cls,
+ const char *instance_id,
+ const char *otp_id);
+
+ /**
+ * Insert details about a particular OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to insert OTP device for
+ * @param otp_id otp identifier of OTP device to insert
+ * @param td the OTP device details to insert
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*insert_otp) (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+
+
+ /**
+ * Update details about a particular OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to update OTP device for
+ * @param otp_id OTP device to update
+ * @param td update to the OTP device details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
+ * does not yet exist.
+ */
+ enum GNUNET_DB_QueryStatus
+ (*update_otp) (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ const struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+
+ /**
+ * Lookup all of the OTP devices the given instance has configured.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup OTP devices for
+ * @param cb function to call on all OTP devices found
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*lookup_otp_devices) (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_OtpDeviceCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Lookup details about an OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param otp_id OTP device to lookup
+ * @param[out] td set to the OTP device details on success, can be NULL
+ * (in that case we only want to check if the template exists)
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_otp) (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ struct TALER_MERCHANTDB_OtpDeviceDetails *td);
+
+
+ /**
+ * Lookup serial number of an OTP device.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup template for
+ * @param otp_id OTP device to lookup
+ * @param[out] serial set to the OTP device serial number * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_otp_serial) (void *cls,
+ const char *instance_id,
+ const char *otp_id,
+ uint64_t *serial);
+
+
+ /**
* Update details about a particular template.
*
* @param cls closure
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index a696f3ea..41cd6674 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -19,16 +19,21 @@ libtalermerchant_la_SOURCES = \
merchant_api_delete_account.c \
merchant_api_delete_instance.c \
merchant_api_delete_order.c \
+ merchant_api_delete_otp_device.c \
merchant_api_delete_product.c \
merchant_api_delete_reserve.c \
merchant_api_delete_template.c \
merchant_api_delete_transfer.c \
merchant_api_delete_webhook.c \
+ merchant_api_get_account.c \
+ merchant_api_get_accounts.c \
merchant_api_get_config.c \
merchant_api_get_instance.c \
merchant_api_get_instances.c \
merchant_api_get_kyc.c \
merchant_api_get_orders.c \
+ merchant_api_get_otp_device.c \
+ merchant_api_get_otp_devices.c \
merchant_api_get_product.c \
merchant_api_get_products.c \
merchant_api_get_reserve.c \
@@ -42,8 +47,10 @@ libtalermerchant_la_SOURCES = \
merchant_api_lock_product.c \
merchant_api_merchant_get_order.c \
merchant_api_merchant_get_reward.c \
+ merchant_api_patch_account.c \
merchant_api_patch_instance.c \
merchant_api_patch_order_forget.c \
+ merchant_api_patch_otp_device.c \
merchant_api_patch_product.c \
merchant_api_patch_template.c \
merchant_api_patch_webhook.c \
@@ -56,6 +63,7 @@ libtalermerchant_la_SOURCES = \
merchant_api_post_order_paid.c \
merchant_api_post_order_pay.c \
merchant_api_post_order_refund.c \
+ merchant_api_post_otp_devices.c \
merchant_api_post_products.c \
merchant_api_post_reserves.c \
merchant_api_post_transfers.c \
diff --git a/src/lib/merchant_api_delete_otp_device.c b/src/lib/merchant_api_delete_otp_device.c
new file mode 100644
index 00000000..5397606c
--- /dev/null
+++ b/src/lib/merchant_api_delete_otp_device.c
@@ -0,0 +1,184 @@
+/*
+ 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 Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1, 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ TALER; see the file COPYING.LGPL. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_delete_otp_device.c
+ * @brief Implementation of the DELETE /otp-devices/$ID request of the merchant's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+
+
+/**
+ * Handle for a DELETE /otp-devices/$ID operation.
+ */
+struct TALER_MERCHANT_OtpDeviceDeleteHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_OtpDeviceDeleteCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP GET /otp-devices/$ID request.
+ *
+ * @param cls the `struct TALER_MERCHANT_OtpDeviceDeleteHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_delete_otp_device_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_OtpDeviceDeleteHandle *tdh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = (unsigned int) response_code,
+ .reply = json
+ };
+
+ tdh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got DELETE /otp-devices/$ID response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_CONFLICT:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ default:
+ /* unexpected response code */
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) hr.ec);
+ break;
+ }
+ tdh->cb (tdh->cb_cls,
+ &hr);
+ TALER_MERCHANT_otp_device_delete_cancel (tdh);
+}
+
+
+struct TALER_MERCHANT_OtpDeviceDeleteHandle *
+TALER_MERCHANT_otp_device_delete (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_device_id,
+ TALER_MERCHANT_OtpDeviceDeleteCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_OtpDeviceDeleteHandle *tdh;
+
+ tdh = GNUNET_new (struct TALER_MERCHANT_OtpDeviceDeleteHandle);
+ tdh->ctx = ctx;
+ tdh->cb = cb;
+ tdh->cb_cls = cb_cls;
+ {
+ char *path;
+
+ GNUNET_asprintf (&path,
+ "private/otp-devices/%s",
+ otp_device_id);
+ tdh->url = TALER_url_join (backend_url,
+ path,
+ NULL);
+ GNUNET_free (path);
+ }
+ if (NULL == tdh->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (tdh);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ tdh->url);
+ {
+ CURL *eh;
+
+ eh = TALER_MERCHANT_curl_easy_get_ (tdh->url);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_CUSTOMREQUEST,
+ MHD_HTTP_METHOD_DELETE));
+ tdh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_delete_otp_device_finished,
+ tdh);
+ }
+ return tdh;
+}
+
+
+void
+TALER_MERCHANT_otp_device_delete_cancel (
+ struct TALER_MERCHANT_OtpDeviceDeleteHandle *tdh)
+{
+ if (NULL != tdh->job)
+ GNUNET_CURL_job_cancel (tdh->job);
+ GNUNET_free (tdh->url);
+ GNUNET_free (tdh);
+}
diff --git a/src/lib/merchant_api_get_account.c b/src/lib/merchant_api_get_account.c
new file mode 100644
index 00000000..e9a13b33
--- /dev/null
+++ b/src/lib/merchant_api_get_account.c
@@ -0,0 +1,211 @@
+/*
+ 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 Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1, 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ TALER; see the file COPYING.LGPL. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_get_account.c
+ * @brief Implementation of the GET /accounts/$ID request of the merchant's HTTP API
+ * @author Priscilla HUANG
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+
+
+/**
+ * Handle for a GET /accounts/$ID operation.
+ */
+struct TALER_MERCHANT_AccountGetHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_AccountGetCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP GET /accounts/$ID request.
+ *
+ * @param cls the `struct TALER_MERCHANT_AccountGetHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_get_account_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_AccountGetHandle *tgh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_AccountGetResponse tgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
+
+ tgh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /accounts/$ID response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("salt",
+ &tgr.details.ok.ad.salt),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("credit_facade_url",
+ &tgr.details.ok.ad.credit_facade_url),
+ NULL),
+ GNUNET_JSON_spec_string ("payto_uri",
+ &tgr.details.ok.ad.payto_uri),
+ GNUNET_JSON_spec_fixed_auto ("h_wire",
+ &tgr.details.ok.ad.h_wire),
+ GNUNET_JSON_spec_bool ("active",
+ &tgr.details.ok.ad.active),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK ==
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ tgh->cb (tgh->cb_cls,
+ &tgr);
+ TALER_MERCHANT_account_get_cancel (tgh);
+ return;
+ }
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ case MHD_HTTP_UNAUTHORIZED:
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ default:
+ /* unexpected response code */
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) tgr.hr.ec);
+ break;
+ }
+ tgh->cb (tgh->cb_cls,
+ &tgr);
+ TALER_MERCHANT_account_get_cancel (tgh);
+}
+
+
+struct TALER_MERCHANT_AccountGetHandle *
+TALER_MERCHANT_account_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *instance_id,
+ const struct TALER_MerchantWireHashP *h_wire,
+ TALER_MERCHANT_AccountGetCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_AccountGetHandle *tgh;
+ CURL *eh;
+
+ tgh = GNUNET_new (struct TALER_MERCHANT_AccountGetHandle);
+ tgh->ctx = ctx;
+ tgh->cb = cb;
+ tgh->cb_cls = cb_cls;
+ {
+ char w_str[sizeof (*h_wire) * 2];
+ char *path;
+ char *end;
+
+ end = GNUNET_STRINGS_data_to_string (h_wire,
+ sizeof (*h_wire),
+ w_str,
+ sizeof (w_str));
+ *end = '\0';
+ GNUNET_asprintf (&path,
+ "private/accounts/%s",
+ w_str);
+ tgh->url = TALER_url_join (backend_url,
+ path,
+ NULL);
+ GNUNET_free (path);
+ }
+ if (NULL == tgh->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (tgh);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ tgh->url);
+ eh = TALER_MERCHANT_curl_easy_get_ (tgh->url);
+ tgh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_get_account_finished,
+ tgh);
+ return tgh;
+}
+
+
+void
+TALER_MERCHANT_account_get_cancel (
+ struct TALER_MERCHANT_AccountGetHandle *tgh)
+{
+ if (NULL != tgh->job)
+ GNUNET_CURL_job_cancel (tgh->job);
+ GNUNET_free (tgh->url);
+ GNUNET_free (tgh);
+}
diff --git a/src/lib/merchant_api_get_accounts.c b/src/lib/merchant_api_get_accounts.c
new file mode 100644
index 00000000..9d09463b
--- /dev/null
+++ b/src/lib/merchant_api_get_accounts.c
@@ -0,0 +1,234 @@
+/*
+ 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 Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1, 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ TALER; see the file COPYING.LGPL. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_get_accounts.c
+ * @brief Implementation of the GET /accounts request of the merchant's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+
+
+/**
+ * Handle for a GET /accounts operation.
+ */
+struct TALER_MERCHANT_AccountsGetHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_AccountsGetCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+};
+
+
+/**
+ * Parse account information from @a ia.
+ *
+ * @param ia JSON array (or NULL!) with account data
+ * @param[in] tgr partially filled response
+ * @param tgh operation handle
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+parse_accounts (const json_t *ia,
+ struct TALER_MERCHANT_AccountsGetResponse *tgr,
+ struct TALER_MERCHANT_AccountsGetHandle *tgh)
+{
+ unsigned int tmpl_len = json_array_size (ia);
+ struct TALER_MERCHANT_AccountEntry tmpl[GNUNET_NZL (tmpl_len)];
+ size_t index;
+ json_t *value;
+
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_AccountEntry *ie = &tmpl[index];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("payto_uri",
+ &ie->payto_uri),
+ GNUNET_JSON_spec_fixed_auto ("h_wire",
+ &ie->h_wire),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ tgr->details.ok.accounts_length = tmpl_len;
+ tgr->details.ok.accounts = tmpl;
+ tgh->cb (tgh->cb_cls,
+ tgr);
+ tgh->cb = NULL; /* just to be sure */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /accounts request.
+ *
+ * @param cls the `struct TALER_MERCHANT_AccountsGetHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_get_accounts_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_AccountsGetHandle *tgh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_AccountsGetResponse tgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
+
+ tgh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /accounts response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ const json_t *accounts;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_array_const ("accounts",
+ &accounts),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ if (GNUNET_OK ==
+ parse_accounts (accounts,
+ &tgr,
+ tgh))
+ {
+ TALER_MERCHANT_accounts_get_cancel (tgh);
+ return;
+ }
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ case MHD_HTTP_UNAUTHORIZED:
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ default:
+ /* unexpected response code */
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) tgr.hr.ec);
+ break;
+ }
+ tgh->cb (tgh->cb_cls,
+ &tgr);
+ TALER_MERCHANT_accounts_get_cancel (tgh);
+}
+
+
+struct TALER_MERCHANT_AccountsGetHandle *
+TALER_MERCHANT_accounts_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ TALER_MERCHANT_AccountsGetCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_AccountsGetHandle *tgh;
+ CURL *eh;
+
+ tgh = GNUNET_new (struct TALER_MERCHANT_AccountsGetHandle);
+ tgh->ctx = ctx;
+ tgh->cb = cb;
+ tgh->cb_cls = cb_cls;
+ tgh->url = TALER_url_join (backend_url,
+ "private/accounts",
+ NULL);
+ if (NULL == tgh->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (tgh);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ tgh->url);
+ eh = TALER_MERCHANT_curl_easy_get_ (tgh->url);
+ tgh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_get_accounts_finished,
+ tgh);
+ return tgh;
+}
+
+
+void
+TALER_MERCHANT_accounts_get_cancel (
+ struct TALER_MERCHANT_AccountsGetHandle *tgh)
+{
+ if (NULL != tgh->job)
+ GNUNET_CURL_job_cancel (tgh->job);
+ GNUNET_free (tgh->url);
+ GNUNET_free (tgh);
+}
diff --git a/src/lib/merchant_api_get_instance.c b/src/lib/merchant_api_get_instance.c
index 9cfbcf83..eef95b84 100644
--- a/src/lib/merchant_api_get_instance.c
+++ b/src/lib/merchant_api_get_instance.c
@@ -93,14 +93,10 @@ handle_get_instance_finished (void *cls,
{
case MHD_HTTP_OK:
{
- const json_t *accounts;
const char *uts;
const json_t *address;
const json_t *jurisdiction;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_array_const (
- "accounts",
- &accounts),
GNUNET_JSON_spec_string (
"name",
&igr.details.ok.details.name),
@@ -128,78 +124,32 @@ handle_get_instance_finished (void *cls,
GNUNET_JSON_spec_end ()
};
- if (GNUNET_OK ==
+ if (GNUNET_OK !=
GNUNET_JSON_parse (json,
spec,
NULL, NULL))
{
- unsigned int accounts_length = json_array_size (accounts);
- struct TALER_MERCHANT_Account aa[GNUNET_NZL (accounts_length)];
- size_t index;
- json_t *value;
- int ret = GNUNET_OK;
-
- memset (aa,
- 0,
- sizeof (aa));
- json_array_foreach (accounts, index, value)
- {
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_fixed_auto ("salt",
- &aa[index].salt),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("credit_facade_url",
- &aa[index].credit_facade_url),
- NULL),
- GNUNET_JSON_spec_string ("payto_uri",
- &aa[index].payto_uri),
- GNUNET_JSON_spec_fixed_auto ("h_wire",
- &aa[index].h_wire),
- GNUNET_JSON_spec_bool ("active",
- &aa[index].active),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- ispec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- igr.hr.http_status = 0;
- igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- }
-
- if (GNUNET_OK == ret)
- {
- igr.details.ok.details.address = address;
- igr.details.ok.details.jurisdiction = jurisdiction;
- if (GNUNET_OK !=
- TALER_KYCLOGIC_kyc_user_type_from_string (
- uts,
- &igr.details.ok.details.ut))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- igr.hr.http_status = 0;
- igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- igr.details.ok.accounts_length = accounts_length;
- igr.details.ok.accounts = aa;
- igh->cb (igh->cb_cls,
- &igr);
- TALER_MERCHANT_instance_get_cancel (igh);
- return;
- }
+ GNUNET_break_op (0);
+ igr.hr.http_status = 0;
+ igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ igr.details.ok.details.address = address;
+ igr.details.ok.details.jurisdiction = jurisdiction;
+ if (GNUNET_OK !=
+ TALER_KYCLOGIC_kyc_user_type_from_string (
+ uts,
+ &igr.details.ok.details.ut))
+ {
+ GNUNET_break_op (0);
+ igr.hr.http_status = 0;
+ igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- GNUNET_break_op (0);
- igr.hr.http_status = 0;
- igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
+ igh->cb (igh->cb_cls,
+ &igr);
+ TALER_MERCHANT_instance_get_cancel (igh);
+ return;
}
case MHD_HTTP_UNAUTHORIZED:
igr.hr.ec = TALER_JSON_get_error_code (json);
diff --git a/src/lib/merchant_api_get_otp_device.c b/src/lib/merchant_api_get_otp_device.c
new file mode 100644
index 00000000..93e065af
--- /dev/null
+++ b/src/lib/merchant_api_get_otp_device.c
@@ -0,0 +1,204 @@
+/*
+ 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 Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1, 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ TALER; see the file COPYING.LGPL. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_get_otp_device.c
+ * @brief Implementation of the GET /otp-devices/$ID request of the merchant's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+
+
+/**
+ * Handle for a GET /otp-devices/$ID operation.
+ */
+struct TALER_MERCHANT_OtpDeviceGetHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_OtpDeviceGetCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP GET /otp-devices/$ID request.
+ *
+ * @param cls the `struct TALER_MERCHANT_OtpDeviceGetHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_get_otp_device_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_OtpDeviceGetHandle *tgh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_OtpDeviceGetResponse tgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
+
+ tgh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /otp-devices/$ID response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ uint32_t alg32;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("otp_device_description",
+ &tgr.details.ok.otp_device_description),
+ GNUNET_JSON_spec_uint32 ("otp_algorithm",
+ &alg32),
+ GNUNET_JSON_spec_string ("otp_key",
+ &tgr.details.ok.otp_key),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("otp_ctr",
+ &tgr.details.ok.otp_ctr),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK ==
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ tgr.details.ok.otp_alg =
+ (enum TALER_MerchantConfirmationAlgorithm) alg32;
+ tgh->cb (tgh->cb_cls,
+ &tgr);
+ TALER_MERCHANT_otp_device_get_cancel (tgh);
+ return;
+ }
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ case MHD_HTTP_UNAUTHORIZED:
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ default:
+ /* unexpected response code */
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) tgr.hr.ec);
+ break;
+ }
+ tgh->cb (tgh->cb_cls,
+ &tgr);
+ TALER_MERCHANT_otp_device_get_cancel (tgh);
+}
+
+
+struct TALER_MERCHANT_OtpDeviceGetHandle *
+TALER_MERCHANT_otp_device_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_device_id,
+ TALER_MERCHANT_OtpDeviceGetCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_OtpDeviceGetHandle *tgh;
+ CURL *eh;
+
+ tgh = GNUNET_new (struct TALER_MERCHANT_OtpDeviceGetHandle);
+ tgh->ctx = ctx;
+ tgh->cb = cb;
+ tgh->cb_cls = cb_cls;
+ {
+ char *path;
+
+ GNUNET_asprintf (&path,
+ "private/otp-devices/%s",
+ otp_device_id);
+ tgh->url = TALER_url_join (backend_url,
+ path,
+ NULL);
+ GNUNET_free (path);
+ }
+ if (NULL == tgh->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (tgh);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ tgh->url);
+ eh = TALER_MERCHANT_curl_easy_get_ (tgh->url);
+ tgh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_get_otp_device_finished,
+ tgh);
+ return tgh;
+}
+
+
+void
+TALER_MERCHANT_otp_device_get_cancel (
+ struct TALER_MERCHANT_OtpDeviceGetHandle *tgh)
+{
+ if (NULL != tgh->job)
+ GNUNET_CURL_job_cancel (tgh->job);
+ GNUNET_free (tgh->url);
+ GNUNET_free (tgh);
+}
diff --git a/src/lib/merchant_api_get_otp_devices.c b/src/lib/merchant_api_get_otp_devices.c
new file mode 100644
index 00000000..3e48486a
--- /dev/null
+++ b/src/lib/merchant_api_get_otp_devices.c
@@ -0,0 +1,234 @@
+/*
+ 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 Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1, 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ TALER; see the file COPYING.LGPL. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_get_otp_devices.c
+ * @brief Implementation of the GET /otp-devices request of the merchant's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+
+
+/**
+ * Handle for a GET /otp-devices operation.
+ */
+struct TALER_MERCHANT_OtpDevicesGetHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_OtpDevicesGetCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+};
+
+
+/**
+ * Parse OTP device information from @a ia.
+ *
+ * @param ia JSON array (or NULL!) with otp_device data
+ * @param[in] tgr partially filled response
+ * @param tgh operation handle
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+parse_otp_devices (const json_t *ia,
+ struct TALER_MERCHANT_OtpDevicesGetResponse *tgr,
+ struct TALER_MERCHANT_OtpDevicesGetHandle *tgh)
+{
+ unsigned int tmpl_len = json_array_size (ia);
+ struct TALER_MERCHANT_OtpDeviceEntry tmpl[GNUNET_NZL (tmpl_len)];
+ size_t index;
+ json_t *value;
+
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_OtpDeviceEntry *ie = &tmpl[index];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("otp_device_id",
+ &ie->otp_device_id),
+ GNUNET_JSON_spec_string ("device_description",
+ &ie->device_description),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ tgr->details.ok.otp_devices_length = tmpl_len;
+ tgr->details.ok.otp_devices = tmpl;
+ tgh->cb (tgh->cb_cls,
+ tgr);
+ tgh->cb = NULL; /* just to be sure */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /otp-devices request.
+ *
+ * @param cls the `struct TALER_MERCHANT_OtpDevicesGetHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_get_otp_devices_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_OtpDevicesGetHandle *tgh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_OtpDevicesGetResponse tgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
+
+ tgh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /otp-devices response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ const json_t *otp_devices;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_array_const ("otp_devices",
+ &otp_devices),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ if (GNUNET_OK ==
+ parse_otp_devices (otp_devices,
+ &tgr,
+ tgh))
+ {
+ TALER_MERCHANT_otp_devices_get_cancel (tgh);
+ return;
+ }
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ case MHD_HTTP_UNAUTHORIZED:
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ default:
+ /* unexpected response code */
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) tgr.hr.ec);
+ break;
+ }
+ tgh->cb (tgh->cb_cls,
+ &tgr);
+ TALER_MERCHANT_otp_devices_get_cancel (tgh);
+}
+
+
+struct TALER_MERCHANT_OtpDevicesGetHandle *
+TALER_MERCHANT_otp_devices_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ TALER_MERCHANT_OtpDevicesGetCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_OtpDevicesGetHandle *tgh;
+ CURL *eh;
+
+ tgh = GNUNET_new (struct TALER_MERCHANT_OtpDevicesGetHandle);
+ tgh->ctx = ctx;
+ tgh->cb = cb;
+ tgh->cb_cls = cb_cls;
+ tgh->url = TALER_url_join (backend_url,
+ "private/otp-devices",
+ NULL);
+ if (NULL == tgh->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (tgh);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ tgh->url);
+ eh = TALER_MERCHANT_curl_easy_get_ (tgh->url);
+ tgh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_get_otp_devices_finished,
+ tgh);
+ return tgh;
+}
+
+
+void
+TALER_MERCHANT_otp_devices_get_cancel (
+ struct TALER_MERCHANT_OtpDevicesGetHandle *tgh)
+{
+ if (NULL != tgh->job)
+ GNUNET_CURL_job_cancel (tgh->job);
+ GNUNET_free (tgh->url);
+ GNUNET_free (tgh);
+}
diff --git a/src/lib/merchant_api_get_template.c b/src/lib/merchant_api_get_template.c
index 3e4a23a8..9bbcc93a 100644
--- a/src/lib/merchant_api_get_template.c
+++ b/src/lib/merchant_api_get_template.c
@@ -92,16 +92,13 @@ handle_get_template_finished (void *cls,
{
case MHD_HTTP_OK:
{
- uint32_t alg32;
const json_t *contract;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("template_description",
&tgr.details.ok.template_description),
- GNUNET_JSON_spec_uint32 ("pos_algorithm",
- &alg32),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("pos_key",
- &tgr.details.ok.pos_key),
+ GNUNET_JSON_spec_string ("otp_id",
+ &tgr.details.ok.otp_id),
NULL),
GNUNET_JSON_spec_object_const ("template_contract",
&contract),
@@ -113,8 +110,6 @@ handle_get_template_finished (void *cls,
spec,
NULL, NULL))
{
- tgr.details.ok.mca =
- (enum TALER_MerchantConfirmationAlgorithm) alg32;
tgr.details.ok.template_contract = contract;
tgh->cb (tgh->cb_cls,
&tgr);
diff --git a/src/lib/merchant_api_patch_account.c b/src/lib/merchant_api_patch_account.c
new file mode 100644
index 00000000..ce0e74d4
--- /dev/null
+++ b/src/lib/merchant_api_patch_account.c
@@ -0,0 +1,254 @@
+/*
+ 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 Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1,
+ 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with TALER; see the file COPYING.LGPL.
+ If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_patch_account.c
+ * @brief Implementation of the PATCH /accounts/$ID request
+ * of the merchant's HTTP API
+ * @author Priscilla HUANG
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_common.h"
+#include "merchant_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_curl_lib.h>
+
+
+/**
+ * Handle for a PATCH /accounts/$ID operation.
+ */
+struct TALER_MERCHANT_AccountPatchHandle
+{
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_AccountPatchCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+ /**
+ * Minor context that holds body and headers.
+ */
+ struct TALER_CURL_PostContext post_ctx;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP PATCH /accounts/$ID request.
+ *
+ * @param cls the `struct TALER_MERCHANT_AccountPatchHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_patch_account_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_AccountPatchHandle *tph = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = (unsigned int) response_code,
+ .reply = json
+ };
+
+ tph->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "PATCH /accounts/$ID completed with response code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case 0:
+ hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_break_op (0);
+ /* This should never happen, either us
+ * or the merchant is buggy (or API version conflict);
+ * just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we tried to abort the payment
+ * after it was successful. We should pass the JSON reply to the
+ * application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_CONFLICT:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Server had an internal issue; we should retry,
+ but this API leaves this to the application */
+ break;
+ default:
+ TALER_MERCHANT_parse_error_details_ (json,
+ response_code,
+ &hr);
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) hr.ec);
+ GNUNET_break_op (0);
+ break;
+ }
+ tph->cb (tph->cb_cls,
+ &hr);
+ TALER_MERCHANT_account_patch_cancel (tph);
+}
+
+
+struct TALER_MERCHANT_AccountPatchHandle *
+TALER_MERCHANT_account_patch (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const struct TALER_MerchantWireHashP *h_wire,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials,
+ TALER_MERCHANT_AccountPatchCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_AccountPatchHandle *tph;
+ json_t *req_obj;
+
+ req_obj = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("credit_facade_url",
+ credit_facade_url)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("credit_facade_credentials",
+ (json_t *) credit_facade_credentials)));
+ tph = GNUNET_new (struct TALER_MERCHANT_AccountPatchHandle);
+ tph->ctx = ctx;
+ tph->cb = cb;
+ tph->cb_cls = cb_cls;
+ {
+ char w_str[sizeof (*h_wire) * 2];
+ char *path;
+ char *end;
+
+ end = GNUNET_STRINGS_data_to_string (h_wire,
+ sizeof (*h_wire),
+ w_str,
+ sizeof (w_str));
+ *end = '\0';
+ GNUNET_asprintf (&path,
+ "private/accounts/%s",
+ w_str);
+ tph->url = TALER_url_join (backend_url,
+ path,
+ NULL);
+ GNUNET_free (path);
+ }
+ if (NULL == tph->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ json_decref (req_obj);
+ GNUNET_free (tph);
+ return NULL;
+ }
+ {
+ CURL *eh;
+
+ eh = TALER_MERCHANT_curl_easy_get_ (tph->url);
+ if (GNUNET_OK !=
+ TALER_curl_easy_post (&tph->post_ctx,
+ eh,
+ req_obj))
+ {
+ GNUNET_break (0);
+ curl_easy_cleanup (eh);
+ json_decref (req_obj);
+ GNUNET_free (tph);
+ return NULL;
+ }
+ json_decref (req_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_CUSTOMREQUEST,
+ MHD_HTTP_METHOD_PATCH));
+ tph->job = GNUNET_CURL_job_add2 (ctx,
+ eh,
+ tph->post_ctx.headers,
+ &handle_patch_account_finished,
+ tph);
+ }
+ return tph;
+}
+
+
+void
+TALER_MERCHANT_account_patch_cancel (
+ struct TALER_MERCHANT_AccountPatchHandle *tph)
+{
+ if (NULL != tph->job)
+ {
+ GNUNET_CURL_job_cancel (tph->job);
+ tph->job = NULL;
+ }
+ TALER_curl_easy_post_finished (&tph->post_ctx);
+ GNUNET_free (tph->url);
+ GNUNET_free (tph);
+}
+
+
+/* end of merchant_api_patch_account.c */
diff --git a/src/lib/merchant_api_patch_instance.c b/src/lib/merchant_api_patch_instance.c
index 8b4b6205..420cd549 100644
--- a/src/lib/merchant_api_patch_instance.c
+++ b/src/lib/merchant_api_patch_instance.c
@@ -158,8 +158,6 @@ TALER_MERCHANT_instance_patch (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
const char *instance_id,
- unsigned int accounts_length,
- const struct TALER_MERCHANT_AccountConfig accounts[static accounts_length],
const char *name,
enum TALER_KYCLOGIC_KycUserType ut,
const json_t *address,
@@ -171,7 +169,6 @@ TALER_MERCHANT_instance_patch (
void *cb_cls)
{
struct TALER_MERCHANT_InstancePatchHandle *iph;
- json_t *jaccounts;
json_t *req_obj;
const char *uts;
@@ -181,44 +178,7 @@ TALER_MERCHANT_instance_patch (
GNUNET_break (0);
return NULL;
}
- jaccounts = json_array ();
- if (NULL == jaccounts)
- {
- GNUNET_break (0);
- return NULL;
- }
- for (unsigned int i = 0; i<accounts_length; i++)
- {
- const struct TALER_MERCHANT_AccountConfig *account = &accounts[i];
- json_t *jaccount;
-
- jaccount =
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string (
- "payto_uri",
- account->payto_uri),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string (
- "credit_facade_url",
- account->credit_facade_url)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref (
- "credit_facade_credentials",
- accounts->credit_facade_credentials))
- );
-
- if (0 !=
- json_array_append_new (jaccounts,
- jaccount))
- {
- GNUNET_break (0);
- json_decref (jaccounts);
- return NULL;
- }
- }
req_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("accounts",
- jaccounts),
GNUNET_JSON_pack_string ("name",
name),
GNUNET_JSON_pack_string ("user_type",
diff --git a/src/lib/merchant_api_patch_otp_device.c b/src/lib/merchant_api_patch_otp_device.c
new file mode 100644
index 00000000..322efe7b
--- /dev/null
+++ b/src/lib/merchant_api_patch_otp_device.c
@@ -0,0 +1,252 @@
+/*
+ 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 Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1,
+ 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with TALER; see the file COPYING.LGPL.
+ If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_patch_otp_device.c
+ * @brief Implementation of the PATCH /otp-devices/$ID request
+ * of the merchant's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_common.h"
+#include "merchant_api_curl_defaults.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_curl_lib.h>
+
+
+/**
+ * Handle for a PATCH /otp-devices/$ID operation.
+ */
+struct TALER_MERCHANT_OtpDevicePatchHandle
+{
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_OtpDevicePatchCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+ /**
+ * Minor context that holds body and headers.
+ */
+ struct TALER_CURL_PostContext post_ctx;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP PATCH /otp-devices/$ID request.
+ *
+ * @param cls the `struct TALER_MERCHANT_OtpDevicePatchHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_patch_otp_device_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_OtpDevicePatchHandle *tph = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = (unsigned int) response_code,
+ .reply = json
+ };
+
+ tph->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "PATCH /otp-devices/$ID completed with response code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case 0:
+ hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_break_op (0);
+ /* This should never happen, either us
+ * or the merchant is buggy (or API version conflict);
+ * just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we tried to abort the payment
+ * after it was successful. We should pass the JSON reply to the
+ * application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_CONFLICT:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Server had an internal issue; we should retry,
+ but this API leaves this to the application */
+ break;
+ default:
+ TALER_MERCHANT_parse_error_details_ (json,
+ response_code,
+ &hr);
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) hr.ec);
+ GNUNET_break_op (0);
+ break;
+ }
+ tph->cb (tph->cb_cls,
+ &hr);
+ TALER_MERCHANT_otp_device_patch_cancel (tph);
+}
+
+
+struct TALER_MERCHANT_OtpDevicePatchHandle *
+TALER_MERCHANT_otp_device_patch (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_device_id,
+ const char *otp_device_description,
+ const char *otp_key,
+ enum TALER_MerchantConfirmationAlgorithm mca,
+ uint64_t otp_ctr,
+ TALER_MERCHANT_OtpDevicePatchCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_OtpDevicePatchHandle *tph;
+ json_t *req_obj;
+
+ req_obj = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("otp_device_description",
+ otp_device_description),
+ GNUNET_JSON_pack_uint64 ("otp_algorithm",
+ (uint32_t) mca),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("otp_key",
+ otp_key)),
+ GNUNET_JSON_pack_uint64 ("otp_ctr",
+ otp_ctr));
+ tph = GNUNET_new (struct TALER_MERCHANT_OtpDevicePatchHandle);
+ tph->ctx = ctx;
+ tph->cb = cb;
+ tph->cb_cls = cb_cls;
+ {
+ char *path;
+
+ GNUNET_asprintf (&path,
+ "private/otp-devices/%s",
+ otp_device_id);
+ tph->url = TALER_url_join (backend_url,
+ path,
+ NULL);
+ GNUNET_free (path);
+ }
+ if (NULL == tph->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ json_decref (req_obj);
+ GNUNET_free (tph);
+ return NULL;
+ }
+ {
+ CURL *eh;
+
+ eh = TALER_MERCHANT_curl_easy_get_ (tph->url);
+ if (GNUNET_OK !=
+ TALER_curl_easy_post (&tph->post_ctx,
+ eh,
+ req_obj))
+ {
+ GNUNET_break (0);
+ curl_easy_cleanup (eh);
+ json_decref (req_obj);
+ GNUNET_free (tph);
+ return NULL;
+ }
+ json_decref (req_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_CUSTOMREQUEST,
+ MHD_HTTP_METHOD_PATCH));
+ tph->job = GNUNET_CURL_job_add2 (ctx,
+ eh,
+ tph->post_ctx.headers,
+ &handle_patch_otp_device_finished,
+ tph);
+ }
+ return tph;
+}
+
+
+void
+TALER_MERCHANT_otp_device_patch_cancel (
+ struct TALER_MERCHANT_OtpDevicePatchHandle *tph)
+{
+ if (NULL != tph->job)
+ {
+ GNUNET_CURL_job_cancel (tph->job);
+ tph->job = NULL;
+ }
+ TALER_curl_easy_post_finished (&tph->post_ctx);
+ GNUNET_free (tph->url);
+ GNUNET_free (tph);
+}
+
+
+/* end of merchant_api_patch_otp_device.c */
diff --git a/src/lib/merchant_api_patch_template.c b/src/lib/merchant_api_patch_template.c
index 0922586a..7dfebf9c 100644
--- a/src/lib/merchant_api_patch_template.c
+++ b/src/lib/merchant_api_patch_template.c
@@ -162,8 +162,7 @@ TALER_MERCHANT_template_patch (
const char *backend_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm mca,
+ const char *otp_id,
json_t *template_contract,
TALER_MERCHANT_TemplatePatchCallback cb,
void *cb_cls)
@@ -174,11 +173,9 @@ TALER_MERCHANT_template_patch (
req_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("template_description",
template_description),
- GNUNET_JSON_pack_uint64 ("pos_algorithm",
- (uint32_t) mca),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("pos_key",
- pos_key)),
+ GNUNET_JSON_pack_string ("otp_id",
+ otp_id)),
GNUNET_JSON_pack_object_incref ("template_contract",
(json_t *) template_contract));
tph = GNUNET_new (struct TALER_MERCHANT_TemplatePatchHandle);
diff --git a/src/lib/merchant_api_post_account.c b/src/lib/merchant_api_post_account.c
index 5ed3f3b3..690aef17 100644
--- a/src/lib/merchant_api_post_account.c
+++ b/src/lib/merchant_api_post_account.c
@@ -35,9 +35,9 @@
/**
- * Handle for a POST /private/account operation.
+ * Handle for a POST /private/accounts operation.
*/
-struct TALER_MERCHANT_AccountPostHandle
+struct TALER_MERCHANT_AccountsPostHandle
{
/**
@@ -53,7 +53,7 @@ struct TALER_MERCHANT_AccountPostHandle
/**
* Function to call with the result.
*/
- TALER_MERCHANT_AccountPostCallback cb;
+ TALER_MERCHANT_AccountsPostCallback cb;
/**
* Closure for @a cb.
@@ -86,23 +86,43 @@ handle_post_account_finished (void *cls,
long response_code,
const void *response)
{
- struct TALER_MERCHANT_AccountPostHandle *aph = cls;
+ struct TALER_MERCHANT_AccountsPostHandle *aph = cls;
const json_t *json = response;
- struct TALER_MERCHANT_AccountPostResponse apr = {
+ struct TALER_MERCHANT_AccountsPostResponse apr = {
.hr.http_status = (unsigned int) response_code,
.hr.reply = json
};
aph->job = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "POST /account completed with response code %u\n",
+ "POST /accounts completed with response code %u\n",
(unsigned int) response_code);
switch (response_code)
{
case 0:
apr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
- case MHD_HTTP_NO_CONTENT:
+ case MHD_HTTP_OK:
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("h_wire",
+ &apr.details.ok.h_wire),
+ GNUNET_JSON_spec_fixed_auto ("salt",
+ &apr.details.ok.salt),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ apr.hr.http_status = 0;
+ apr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ }
break;
case MHD_HTTP_BAD_REQUEST:
GNUNET_break_op (0);
@@ -147,40 +167,42 @@ handle_post_account_finished (void *cls,
}
aph->cb (aph->cb_cls,
&apr);
- TALER_MERCHANT_account_post_cancel (aph);
+ TALER_MERCHANT_accounts_post_cancel (aph);
}
-struct TALER_MERCHANT_AccountPostHandle *
-TALER_MERCHANT_account_post (
+struct TALER_MERCHANT_AccountsPostHandle *
+TALER_MERCHANT_accounts_post (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
- const struct TALER_MERCHANT_AccountConfig *account,
- TALER_MERCHANT_AccountPostCallback cb,
+ const char *payto_uri,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials,
+ TALER_MERCHANT_AccountsPostCallback cb,
void *cb_cls)
{
- struct TALER_MERCHANT_AccountPostHandle *aph;
+ struct TALER_MERCHANT_AccountsPostHandle *aph;
json_t *req_obj;
req_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string (
"payto_uri",
- account->payto_uri),
+ payto_uri),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string (
"credit_facade_url",
- account->credit_facade_url)),
+ credit_facade_url)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref (
"credit_facade_credentials",
- account->credit_facade_credentials))
+ (json_t *) credit_facade_credentials))
);
- aph = GNUNET_new (struct TALER_MERCHANT_AccountPostHandle);
+ aph = GNUNET_new (struct TALER_MERCHANT_AccountsPostHandle);
aph->ctx = ctx;
aph->cb = cb;
aph->cb_cls = cb_cls;
aph->url = TALER_url_join (backend_url,
- "private/account",
+ "private/accounts",
NULL);
if (NULL == aph->url)
{
@@ -211,8 +233,8 @@ TALER_MERCHANT_account_post (
void
-TALER_MERCHANT_account_post_cancel (
- struct TALER_MERCHANT_AccountPostHandle *aph)
+TALER_MERCHANT_accounts_post_cancel (
+ struct TALER_MERCHANT_AccountsPostHandle *aph)
{
if (NULL != aph->job)
{
diff --git a/src/lib/merchant_api_post_instances.c b/src/lib/merchant_api_post_instances.c
index 77336187..73d36369 100644
--- a/src/lib/merchant_api_post_instances.c
+++ b/src/lib/merchant_api_post_instances.c
@@ -164,8 +164,6 @@ TALER_MERCHANT_instances_post (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
const char *instance_id,
- unsigned int accounts_length,
- const struct TALER_MERCHANT_AccountConfig accounts[],
const char *name,
enum TALER_KYCLOGIC_KycUserType ut,
const json_t *address,
@@ -178,7 +176,6 @@ TALER_MERCHANT_instances_post (
void *cb_cls)
{
struct TALER_MERCHANT_InstancesPostHandle *iph;
- json_t *jaccounts;
json_t *req_obj;
json_t *auth_obj;
const char *uts;
@@ -217,44 +214,7 @@ TALER_MERCHANT_instances_post (
GNUNET_break (0);
return NULL;
}
- jaccounts = json_array ();
- if (NULL == jaccounts)
- {
- json_decref (auth_obj);
- GNUNET_break (0);
- return NULL;
- }
- for (unsigned int i = 0; i<accounts_length; i++)
- {
- const struct TALER_MERCHANT_AccountConfig *account = &accounts[i];
- json_t *jaccount =
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string (
- "payto_uri",
- account->payto_uri),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string (
- "credit_facade_url",
- account->credit_facade_url)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref (
- "credit_facade_credentials",
- account->credit_facade_credentials))
- );
-
- if (0 !=
- json_array_append_new (jaccounts,
- jaccount))
- {
- GNUNET_break (0);
- json_decref (auth_obj);
- json_decref (jaccounts);
- return NULL;
- }
- }
req_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("accounts",
- jaccounts),
GNUNET_JSON_pack_string ("id",
instance_id),
GNUNET_JSON_pack_string ("name",
diff --git a/src/lib/merchant_api_post_otp_devices.c b/src/lib/merchant_api_post_otp_devices.c
new file mode 100644
index 00000000..456abd09
--- /dev/null
+++ b/src/lib/merchant_api_post_otp_devices.c
@@ -0,0 +1,237 @@
+/*
+ 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 Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1,
+ 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with TALER; see the file COPYING.LGPL.
+ If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file merchant_api_post_otp_devices.c
+ * @brief Implementation of the POST /otp-devices request
+ * of the merchant's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_merchant_service.h"
+#include "merchant_api_curl_defaults.h"
+#include "merchant_api_common.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_curl_lib.h>
+
+
+/**
+ * Handle for a POST /otp-devices/$ID operation.
+ */
+struct TALER_MERCHANT_OtpDevicesPostHandle
+{
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_OtpDevicesPostCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+ /**
+ * Minor context that holds body and headers.
+ */
+ struct TALER_CURL_PostContext post_ctx;
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP POST /otp-devices request.
+ *
+ * @param cls the `struct TALER_MERCHANT_OtpDevicesPostHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_post_otp_devices_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_OtpDevicesPostHandle *tph = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = (unsigned int) response_code,
+ .reply = json
+ };
+
+ tph->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "POST /otp-devices completed with response code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case 0:
+ hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* This should never happen, either us
+ * or the merchant is buggy (or API version conflict);
+ * just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we tried to abort the payment
+ * after it was successful. We should pass the JSON reply to the
+ * application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the
+ application */
+ break;
+ case MHD_HTTP_CONFLICT:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ /* Server had an internal issue; we should retry,
+ but this API leaves this to the application */
+ break;
+ default:
+ TALER_MERCHANT_parse_error_details_ (json,
+ response_code,
+ &hr);
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) hr.ec);
+ GNUNET_break_op (0);
+ break;
+ }
+ tph->cb (tph->cb_cls,
+ &hr);
+ TALER_MERCHANT_otp_devices_post_cancel (tph);
+}
+
+
+struct TALER_MERCHANT_OtpDevicesPostHandle *
+TALER_MERCHANT_otp_devices_post (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *otp_device_id,
+ const char *otp_device_description,
+ const char *otp_key,
+ enum TALER_MerchantConfirmationAlgorithm otp_algorithm,
+ uint64_t otp_ctr,
+ TALER_MERCHANT_OtpDevicesPostCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_OtpDevicesPostHandle *tph;
+ json_t *req_obj;
+
+ req_obj = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("otp_device_id",
+ otp_device_id),
+ GNUNET_JSON_pack_string ("otp_device_description",
+ otp_device_description),
+ GNUNET_JSON_pack_uint64 ("otp_algorithm",
+ (uint32_t) otp_algorithm),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("otp_key",
+ otp_key)),
+ GNUNET_JSON_pack_uint64 ("otp_ctr",
+ otp_ctr));
+ tph = GNUNET_new (struct TALER_MERCHANT_OtpDevicesPostHandle);
+ tph->ctx = ctx;
+ tph->cb = cb;
+ tph->cb_cls = cb_cls;
+ tph->url = TALER_url_join (backend_url,
+ "private/otp-devices",
+ NULL);
+ if (NULL == tph->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ json_decref (req_obj);
+ GNUNET_free (tph);
+ return NULL;
+ }
+ {
+ CURL *eh;
+
+ eh = TALER_MERCHANT_curl_easy_get_ (tph->url);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_curl_easy_post (&tph->post_ctx,
+ eh,
+ req_obj));
+ json_decref (req_obj);
+ tph->job = GNUNET_CURL_job_add2 (ctx,
+ eh,
+ tph->post_ctx.headers,
+ &handle_post_otp_devices_finished,
+ tph);
+ GNUNET_assert (NULL != tph->job);
+ }
+ return tph;
+}
+
+
+void
+TALER_MERCHANT_otp_devices_post_cancel (
+ struct TALER_MERCHANT_OtpDevicesPostHandle *tph)
+{
+ if (NULL != tph->job)
+ {
+ GNUNET_CURL_job_cancel (tph->job);
+ tph->job = NULL;
+ }
+ TALER_curl_easy_post_finished (&tph->post_ctx);
+ GNUNET_free (tph->url);
+ GNUNET_free (tph);
+}
+
+
+/* end of merchant_api_post_otp_devices.c */
diff --git a/src/lib/merchant_api_post_templates.c b/src/lib/merchant_api_post_templates.c
index bdba52f9..3ab4320c 100644
--- a/src/lib/merchant_api_post_templates.c
+++ b/src/lib/merchant_api_post_templates.c
@@ -203,8 +203,7 @@ TALER_MERCHANT_templates_post (
const char *backend_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm pos_algorithm,
+ const char *otp_id,
const json_t *template_contract,
TALER_MERCHANT_TemplatesPostCallback cb,
void *cb_cls)
@@ -222,11 +221,9 @@ TALER_MERCHANT_templates_post (
template_id),
GNUNET_JSON_pack_string ("template_description",
template_description),
- GNUNET_JSON_pack_uint64 ("pos_algorithm",
- (uint32_t) pos_algorithm),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("pos_key",
- pos_key)),
+ GNUNET_JSON_pack_string ("otp_id",
+ otp_id)),
GNUNET_JSON_pack_object_incref ("template_contract",
(json_t *) template_contract));
tph = GNUNET_new (struct TALER_MERCHANT_TemplatesPostHandle);
diff --git a/src/merchant-tools/taler-merchant-benchmark.c b/src/merchant-tools/taler-merchant-benchmark.c
index ce4491e0..238b9f03 100644
--- a/src/merchant-tools/taler-merchant-benchmark.c
+++ b/src/merchant-tools/taler-merchant-benchmark.c
@@ -182,9 +182,13 @@ run (void *cls,
"instance-create-default",
merchant_url,
"default",
- cred.user42_payto,
MHD_HTTP_NO_CONTENT),
-
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-default-account",
+ merchant_url,
+ cred.user42_payto,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_admin_add_incoming (
"create-reserve-1",
CURRENCY_10_02,
@@ -259,14 +263,24 @@ run (void *cls,
"instance-create-default",
merchant_url,
"default",
- cred.user42_payto,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-default-account",
+ merchant_url,
+ cred.user42_payto,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_merchant_post_instances (
"instance-create-alt",
merchant_url,
alt_instance_id,
- cred.user42_payto,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-alt-account",
+ alt_instance_url,
+ cred.user42_payto,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_admin_add_incoming (
"create-reserve-1",
CURRENCY_5_01,
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index a2327ad7..d81e6da9 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -37,6 +37,8 @@ libtalermerchanttesting_la_SOURCES = \
testing_api_cmd_get_instance.c \
testing_api_cmd_get_instances.c \
testing_api_cmd_get_orders.c \
+ testing_api_cmd_get_otp_device.c \
+ testing_api_cmd_get_otp_devices.c \
testing_api_cmd_get_product.c \
testing_api_cmd_get_products.c \
testing_api_cmd_get_reserve.c \
@@ -50,6 +52,7 @@ libtalermerchanttesting_la_SOURCES = \
testing_api_cmd_delete_account.c \
testing_api_cmd_delete_instance.c \
testing_api_cmd_delete_order.c \
+ testing_api_cmd_delete_otp_device.c \
testing_api_cmd_delete_product.c \
testing_api_cmd_delete_template.c \
testing_api_cmd_delete_webhook.c \
@@ -61,21 +64,23 @@ libtalermerchanttesting_la_SOURCES = \
testing_api_cmd_instance_auth.c \
testing_api_cmd_merchant_get_order.c \
testing_api_cmd_merchant_get_reward.c \
+ testing_api_cmd_patch_instance.c \
+ testing_api_cmd_patch_otp_device.c \
+ testing_api_cmd_patch_product.c \
+ testing_api_cmd_patch_template.c \
+ testing_api_cmd_patch_webhook.c \
testing_api_cmd_pay_order.c \
testing_api_cmd_post_account.c \
testing_api_cmd_post_instances.c \
testing_api_cmd_post_orders_paid.c \
testing_api_cmd_post_orders.c \
+ testing_api_cmd_post_otp_devices.c \
testing_api_cmd_post_products.c \
testing_api_cmd_post_reserves.c \
testing_api_cmd_post_transfers.c \
testing_api_cmd_post_templates.c \
testing_api_cmd_post_using_templates.c \
testing_api_cmd_post_webhooks.c \
- testing_api_cmd_patch_instance.c \
- testing_api_cmd_patch_product.c \
- testing_api_cmd_patch_template.c \
- testing_api_cmd_patch_webhook.c \
testing_api_cmd_refund_order.c \
testing_api_cmd_reward_authorize.c \
testing_api_cmd_reward_pickup.c \
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index e26a1fd3..c8b683d8 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -395,8 +395,13 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_instances ("instance-create-default-setup",
merchant_url,
"default",
- merchant_payto,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-default-account",
+ merchant_url,
+ merchant_payto,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_batch ("pay",
pay),
TALER_TESTING_cmd_batch ("aml",
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index 32674332..a93ee179 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -120,15 +120,6 @@ static char *merchant_url_i1a;
*/
#define MERCHANT_ACCOUNT_NAME "3"
-/**
- * Payto URIs to use for testing accounts on the merchant.
- */
-static const char *payto_uris[] = {
- PAYTO_I1,
- "payto://iban/CH9300762011623852957?receiver-name=Test"
- /* Just for testing account inactivation. */
-};
-
static const char *order_1_transfers[] = {
"post-transfer-1",
NULL
@@ -223,8 +214,13 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_instances ("instance-create-default",
merchant_url,
"default",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-default-account",
+ merchant_url,
+ PAYTO_I1,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_merchant_kyc_get ("instance-create-kyc-0",
merchant_url,
NULL,
@@ -939,8 +935,13 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_instances ("instance-create-i1a",
merchant_url,
"i1a",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-i1a-account",
+ merchant_url_i1a,
+ PAYTO_I1,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_merchant_get_product ("get-nx-product-i1a-1",
merchant_url_i1a,
"nx-product",
@@ -1413,7 +1414,6 @@ run (void *cls,
"template-2",
"another template",
NULL,
- TALER_MCA_NONE,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("minimum_age", 0),
GNUNET_JSON_pack_time_rel ("pay_duration",
@@ -1429,13 +1429,21 @@ run (void *cls,
"template-nx",
MHD_HTTP_NOT_FOUND,
NULL),
+ TALER_TESTING_cmd_merchant_post_otp_devices (
+ "post-otp-device",
+ merchant_url,
+ "otp-dev",
+ "my OTP device",
+ "otp-key",
+ TALER_MCA_WITH_PRICE,
+ 0,
+ MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_patch_template (
"patch-templates-t3-nx",
merchant_url,
"template-3",
"updated template",
- NULL,
- TALER_MCA_WITH_PRICE,
+ "otp-dev",
GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("minimum_age", 0),
GNUNET_JSON_pack_time_rel ("pay_duration",
@@ -1446,8 +1454,7 @@ run (void *cls,
merchant_url,
"template-amount",
"a different template with an amount",
- NULL, /* pos_key */
- TALER_MCA_NONE,
+ NULL,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("minimum_age", 0),
GNUNET_JSON_pack_time_rel ("pay_duration",
@@ -1458,6 +1465,7 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_using_templates (
"using-templates-t1",
"post-templates-t1",
+ NULL,
merchant_url,
"1",
"summary-1",
@@ -1468,6 +1476,7 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_using_templates (
"using-templates-t1-amount-missing",
"post-templates-t1",
+ NULL,
merchant_url,
"2",
"summary-1",
@@ -1478,6 +1487,7 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_using_templates (
"using-templates-t1-summary-missing",
"post-templates-t1",
+ NULL,
merchant_url,
"3",
NULL,
@@ -1488,6 +1498,7 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_using_templates (
"using-templates-t1-amount-conflict",
"post-templates-t3-amount",
+ NULL,
merchant_url,
"4",
"summary-1",
@@ -1498,6 +1509,7 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_using_templates (
"using-templates-t1-amount-duplicate",
"post-templates-t3-amount",
+ NULL,
merchant_url,
"4",
"summary-1",
@@ -1524,6 +1536,7 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_using_templates (
"post-templates-t1-deleted",
"post-templates-t1",
+ NULL,
merchant_url,
"0",
"summary-1",
@@ -1531,13 +1544,21 @@ run (void *cls,
GNUNET_TIME_UNIT_ZERO_TS,
GNUNET_TIME_UNIT_FOREVER_TS,
MHD_HTTP_NOT_FOUND),
+ TALER_TESTING_cmd_merchant_post_otp_devices (
+ "post-otp-device",
+ merchant_url,
+ "otp-dev-2",
+ "my OTP device",
+ "secret",
+ TALER_MCA_WITH_PRICE,
+ 0,
+ MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_post_templates2 (
"post-templates-with-pos-key",
merchant_url,
"template-key",
"a different template with POS KEY",
- "secret", /* pos_key */
- TALER_MCA_WITH_PRICE,
+ "otp-dev-2",
GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("minimum_age", 0),
GNUNET_JSON_pack_time_rel ("pay_duration",
@@ -1547,6 +1568,7 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_using_templates (
"using-templates-pos-key",
"post-templates-with-pos-key",
+ "post-otp-device",
merchant_url,
"1",
"summary-1-pos",
@@ -1669,12 +1691,16 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_instances ("instance-create-default-setup",
merchant_url,
"default",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-default-account",
+ merchant_url,
+ PAYTO_I1,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_merchant_post_instances ("instance-create-i1",
merchant_url,
"i1",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_get_instances ("instances-get-i1",
merchant_url,
@@ -1690,8 +1716,6 @@ run (void *cls,
TALER_TESTING_cmd_merchant_patch_instance ("instance-patch-i1",
merchant_url,
"i1",
- 2,
- payto_uris,
"bob-the-merchant",
json_pack ("{s:s}",
"street",
@@ -1703,41 +1727,11 @@ run (void *cls,
GNUNET_TIME_UNIT_MINUTES,
GNUNET_TIME_UNIT_MINUTES,
MHD_HTTP_NO_CONTENT),
- TALER_TESTING_cmd_merchant_get_instance2 ("instances-get-i1-2",
- merchant_url,
- "i1",
- MHD_HTTP_OK,
- "instance-patch-i1",
- payto_uris,
- 2,
- NULL,
- 0),
- TALER_TESTING_cmd_merchant_patch_instance (
- "instance-patch-i1-inactivate-account",
- merchant_url,
- "i1",
- 1,
- payto_uris,
- "bob-the-merchant",
- json_pack ("{s:s}",
- "street",
- "bobstreet"),
- json_pack ("{s:s}",
- "street",
- "bobjuryst"),
- true,
- GNUNET_TIME_UNIT_MINUTES,
- GNUNET_TIME_UNIT_MINUTES,
- MHD_HTTP_NO_CONTENT),
- TALER_TESTING_cmd_merchant_get_instance2 ("instances-get-i1-3",
- merchant_url,
- "i1",
- MHD_HTTP_OK,
- "instance-patch-i1-inactivate-account",
- payto_uris,
- 1,
- &payto_uris[1],
- 1),
+ TALER_TESTING_cmd_merchant_get_instance ("instances-get-i1-2",
+ merchant_url,
+ "i1",
+ MHD_HTTP_OK,
+ "instance-patch-i1"),
TALER_TESTING_cmd_merchant_get_instance ("instances-get-i2-nx",
merchant_url,
"i2",
@@ -1746,7 +1740,6 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_instances2 ("instance-create-ACL",
merchant_url,
"i-acl",
- 0, NULL,
"controlled instance",
json_pack ("{s:s}", "city",
"shopcity"),
@@ -1763,8 +1756,6 @@ run (void *cls,
TALER_TESTING_cmd_merchant_patch_instance ("instance-patch-ACL",
merchant_url,
"i-acl",
- 1,
- payto_uris,
"controlled instance",
json_pack ("{s:s}",
"street",
@@ -1779,18 +1770,11 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_instances ("instance-create-i2",
merchant_url,
"i2",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_post_instances ("instance-create-i2-idem",
merchant_url,
"i2",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
- TALER_TESTING_cmd_merchant_post_instances ("instance-create-i2-non-idem",
- merchant_url,
- "i2",
- "payto://other-method/?receiver-name=X",
- MHD_HTTP_CONFLICT),
TALER_TESTING_cmd_merchant_delete_instance ("instance-delete-i2",
merchant_url,
"i2",
@@ -1824,8 +1808,13 @@ run (void *cls,
"instance-create-default-after-purge",
merchant_url,
"default",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-default-account-after-purge",
+ merchant_url,
+ PAYTO_I1,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_merchant_get_products ("get-products-empty",
merchant_url,
MHD_HTTP_OK,
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1692810704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1692810704
deleted file mode 100644
index 7fd4a991..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1692810704
+++ /dev/null
@@ -1 +0,0 @@
-­¼KÕ¯€H"r^Y³gÌn€Šˆ2²^ðЋÉ \ No newline at end of file
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1692810704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1692810704
deleted file mode 100644
index 609223fc..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1692810704
+++ /dev/null
@@ -1,2 +0,0 @@
-Âò€ äç6
-–‚M¦îð‡…ê€üRñO&4žÿg¢ \ No newline at end of file
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1692810704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1692810704
deleted file mode 100644
index a03556d9..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1692810704
+++ /dev/null
@@ -1 +0,0 @@
-0›b„ ‘úmÍqjÑËfÓŒÈêáöYP¥Z¨Ñø \ No newline at end of file
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1692810704 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1692810704
deleted file mode 100644
index d43290a6..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1692810704
+++ /dev/null
@@ -1 +0,0 @@
-ˆÌÿµyÌ\ö‘UúçB”Î6Òš±6Dê„„Ì é& \ No newline at end of file
diff --git a/src/testing/test_merchant_api_twisted.c b/src/testing/test_merchant_api_twisted.c
index b55388ab..71a6485b 100644
--- a/src/testing/test_merchant_api_twisted.c
+++ b/src/testing/test_merchant_api_twisted.c
@@ -337,8 +337,13 @@ run (void *cls,
TALER_TESTING_cmd_merchant_post_instances ("instance-create-default",
twister_merchant_url,
"default",
- PAYTO_I1,
MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_merchant_post_account (
+ "instance-create-default-account",
+ twister_merchant_url,
+ PAYTO_I1,
+ NULL, NULL,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_batch ("pay",
pay),
/* Malform the response from the exchange. */
diff --git a/src/testing/test_merchant_instance_auth.sh b/src/testing/test_merchant_instance_auth.sh
index 5cc4de92..8d6e347a 100755
--- a/src/testing/test_merchant_instance_auth.sh
+++ b/src/testing/test_merchant_instance_auth.sh
@@ -42,13 +42,26 @@ echo -n "Configuring 'default' instance ..." >&2
STATUS=$(curl -H "Content-Type: application/json" -X POST \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"token","token":"secret-token:new_value"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"token","token":"secret-token:new_value"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
then
exit_fail "Expected 204, instance created. got: $STATUS" >&2
fi
+
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:new_value' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/43"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+
echo " OK" >&2
# Kill merchant
@@ -115,7 +128,7 @@ echo -n "Configuring 'second' instance ..." >&2
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer '$NEW_SECRET \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"token","token":"secret-token:second"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"second","name":"second","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"token","token":"secret-token:second"},"id":"second","name":"second","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_instance_creation.sh b/src/testing/test_merchant_instance_creation.sh
index 8d81ab8b..c7eda54b 100755
--- a/src/testing/test_merchant_instance_creation.sh
+++ b/src/testing/test_merchant_instance_creation.sh
@@ -27,7 +27,7 @@ echo -n "Configuring a merchant instance before configuring the default instance
STATUS=$(curl -H "Content-Type: application/json" -X POST \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"first","name":"test","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"id":"first","name":"test","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
@@ -43,7 +43,7 @@ echo -n "Configuring default instance ..."
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "401" ]
@@ -58,7 +58,7 @@ echo -n "Configuring a second merchant instance ..."
STATUS=$(curl -H "Content-Type: application/json" -X POST \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"second","name":"test","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"id":"second","name":"test","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "401" ]
diff --git a/src/testing/test_merchant_instance_purge.sh b/src/testing/test_merchant_instance_purge.sh
index 0d8c0c2c..f3992495 100755
--- a/src/testing/test_merchant_instance_purge.sh
+++ b/src/testing/test_merchant_instance_purge.sh
@@ -27,7 +27,7 @@ echo -n "Configuring default instance ..." >&2
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
@@ -41,7 +41,7 @@ echo -n "Configuring merchant instance ..." >&2
STATUS=$(curl -H "Content-Type: application/json" -X POST \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"test","name":"test","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"id":"test","name":"test","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_instance_response.sh b/src/testing/test_merchant_instance_response.sh
index b2eee199..336c33cc 100755
--- a/src/testing/test_merchant_instance_response.sh
+++ b/src/testing/test_merchant_instance_response.sh
@@ -29,7 +29,7 @@ STATUS=$(curl -H "Content-Type: application/json" -X OPTIONS \
if [ "$STATUS" != "204" ]
then
- exit_fail "Expected 204 when default instance doest not exist yet. got: $STATUS"
+ exit_fail "Expected 204 when default instance does not exist yet. got: $STATUS"
fi
STATUS=$(curl -H "Content-Type: application/json" -X GET \
@@ -45,7 +45,7 @@ fi
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost/43"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
+ -d '{"auth":{"method":"token","token":"secret-token:other_secret"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
diff --git a/src/testing/test_merchant_kyc.sh b/src/testing/test_merchant_kyc.sh
index 2b3bb188..663590b1 100755
--- a/src/testing/test_merchant_kyc.sh
+++ b/src/testing/test_merchant_kyc.sh
@@ -24,12 +24,12 @@ set -eu
setup -c "test_template.conf" -m -u "exchange-account-1"
LAST_RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" test_response.conf-XXXXXX)
-echo -n "Configuring a merchant instance before configuring the default instance ..."
+echo -n "Configuring a merchant default instance ..."
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost:8082/43"},{"payto_uri":"payto://x-taler-bank/localhost:8082/44"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
@@ -37,6 +37,30 @@ then
exit_fail "Expected 204 ok, instance created. got: $STATUS"
fi
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/43"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"payto://x-taler-bank/localhost:8082/44"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+
echo " OK"
echo -n "Check the instance exists ..."
diff --git a/src/testing/test_merchant_order_autocleanup.sh b/src/testing/test_merchant_order_autocleanup.sh
index 08655d18..60ee19e0 100755
--- a/src/testing/test_merchant_order_autocleanup.sh
+++ b/src/testing/test_merchant_order_autocleanup.sh
@@ -83,11 +83,10 @@ else
FORTYTHREE=$(get_payto_uri fortythree x)
fi
-# create with 2 address
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
"http://localhost:9966/management/instances" \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$FORTYTHREE"'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
@@ -95,6 +94,17 @@ then
exit_fail "Expected 204, instance created. got: $STATUS"
fi
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"'"$FORTYTHREE"'"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected '200 OK' response. Got instead $STATUS"
+fi
+
NOW=$(date +%s)
IN_TEN_SECS=$(( NOW + 10 ))
diff --git a/src/testing/test_merchant_order_creation.sh b/src/testing/test_merchant_order_creation.sh
index 1461c005..f0355565 100755
--- a/src/testing/test_merchant_order_creation.sh
+++ b/src/testing/test_merchant_order_creation.sh
@@ -83,6 +83,20 @@ fi
echo -n "Configuring merchant instance ..."
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/management/instances \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "204" ]
+then
+ exit_fail "Expected '204 No content' response. Got instead $STATUS"
+fi
+echo "Ok"
+
+echo -n "Configuring merchant account ..."
+
if [ 1 = "$USE_FAKEBANK" ]
then
FORTYTHREE="payto://x-taler-bank/localhost/fortythree?receiver-name=fortythree"
@@ -92,26 +106,51 @@ fi
# create with 2 bank account addresses
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
- http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$FORTYTHREE"'"},{"payto_uri":"payto://iban/SANDBOXX/DE270744?receiver-name=Forty+Four"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"'"$FORTYTHREE"'"}' \
-w "%{http_code}" -s -o /dev/null)
-if [ "$STATUS" != "204" ]
+if [ "$STATUS" != "200" ]
then
- exit_fail "Expected '204 No content' response. Got instead $STATUS"
+ exit_fail "Expected '200 OK' response. Got instead $STATUS"
fi
-echo -n "."
-# remove one account address
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"payto://iban/SANDBOXX/DE270744?receiver-name=Forty+Four"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected '200 OK' response. Got instead $STATUS"
+fi
+
+echo "Ok"
+
+echo -n "Get accounts..."
+STATUS=$(curl http://localhost:9966/instances/default/private/accounts \
+ -w "%{http_code}" -s -o "$LAST_RESPONSE")
+PAY_URI=$(jq -r .accounts[1].payto_uri < "$LAST_RESPONSE")
+H_WIRE=$(jq -r .accounts[1].h_wire < "$LAST_RESPONSE")
+if [ "$PAY_URI" != "payto://iban/SANDBOXX/DE270744?receiver-name=Forty+Four" ]
+then
+ cat "$LAST_RESPONSE" >&2
+ exit_fail "Expected second payto URI. Got $PAY_URI"
+fi
+echo "OK"
+
+# remove one account address
+echo -n "Deleting one account ..."
STATUS=$(curl -H "Content-Type: application/json" -X PATCH \
-H 'Authorization: Bearer secret-token:super_secret' \
- http://localhost:9966/instances/default/private/ \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$FORTYTHREE"'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000000},"default_pay_delay":{"d_us": 60000000000}}' \
+ "http://localhost:9966/instances/default/private/accounts/${H_WIRE}" \
+ -X DELETE \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
then
- exit_fail "Expected '204 No content' response. Got instead: $STATUS"
+ exit_fail "Expected '204 No content' for deletion of ${H_WIRE}. Got instead: $STATUS"
fi
echo "OK"
diff --git a/src/testing/test_merchant_product_creation.sh b/src/testing/test_merchant_product_creation.sh
index dd3a60b5..6da5efa2 100755
--- a/src/testing/test_merchant_product_creation.sh
+++ b/src/testing/test_merchant_product_creation.sh
@@ -55,13 +55,25 @@ echo -n "Configuring merchant instance ..."
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
"http://localhost:9966/management/instances" \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$FORTYTHREE"'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
then
exit_fail "Expected 204 No content, instance created. Got $STATUS instead"
fi
+
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"'"$FORTYTHREE"'"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+
echo "OK"
RANDOM_IMG='data:image/png;base64,abcdefg'
diff --git a/src/testing/test_merchant_reserve_creation.sh b/src/testing/test_merchant_reserve_creation.sh
index e7ebf615..36e71e99 100755
--- a/src/testing/test_merchant_reserve_creation.sh
+++ b/src/testing/test_merchant_reserve_creation.sh
@@ -47,17 +47,29 @@ echo -n "Configuring merchant instance ..."
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"payto://x-taler-bank/localhost:18082/fortythree"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
then
exit_fail "Expected 204, instance created. Got instead: $STATUS"
fi
+echo "Ok"
+echo -n "Configuring merchant account ..."
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"payto://x-taler-bank/localhost:18082/fortythree"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+
echo "OK"
echo -n "Creating reserve ..."
-#bash
STATUS=$(curl 'http://localhost:9966/instances/default/private/reserves' \
-d '{"initial_balance":"TESTKUDOS:2","exchange_url":"http://localhost:8081/","wire_method":"'"$WIRE_METHOD"'"}' \
diff --git a/src/testing/test_merchant_transfer_tracking.sh b/src/testing/test_merchant_transfer_tracking.sh
index cba85d12..3a2a18a9 100755
--- a/src/testing/test_merchant_transfer_tracking.sh
+++ b/src/testing/test_merchant_transfer_tracking.sh
@@ -108,13 +108,35 @@ fi
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$TOR_PAYTO"'"},{"payto_uri":"'"$GNUNET_PAYTO"'"}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
then
exit_fail "Expected 204, instance created. got: $STATUS"
fi
+
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"'"$TOR_PAYTO"'"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"'"$GNUNET_PAYTO"'"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+
echo "OK"
echo -n "Configuring merchant test instance ..."
@@ -123,13 +145,33 @@ echo -n "Configuring merchant test instance ..."
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$SURVEY_PAYTO"'"},{"payto_uri":"'"$TUTORIAL_PAYTO"'"}],"id":"test","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+ -d '{"auth":{"method":"external"},"id":"test","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
then
exit_fail "Expected 204, instance created. got: $STATUS"
fi
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/test/private/accounts \
+ -d '{"payto_uri":"'"$SURVEY_PAYTO"'"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/test/private/accounts \
+ -d '{"payto_uri":"'"$TUTORIAL_PAYTO"'"}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
echo "OK"
# CREATE ORDER AND SELL IT
diff --git a/src/testing/test_merchant_wirewatch.sh b/src/testing/test_merchant_wirewatch.sh
index b8a37f2f..b4fdc66b 100755
--- a/src/testing/test_merchant_wirewatch.sh
+++ b/src/testing/test_merchant_wirewatch.sh
@@ -197,13 +197,26 @@ fi
STATUS=$(curl -H "Content-Type: application/json" -X POST \
-H 'Authorization: Bearer secret-token:super_secret' \
http://localhost:9966/management/instances \
- -d '{"auth":{"method":"external"},"accounts":[{"payto_uri":"'"$GNUNET_PAYTO"'","credit_facade_url":"'"${FACADE_URL}"'","credit_facade_credentials":{"type":"basic","username":"'"$FACADE_USERNAME"'","password":"'"$FACADE_PASSWORD"'"}}],"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
+ -d '{"auth":{"method":"external"},"id":"default","name":"default","user_type":"business","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 50000000},"default_pay_delay":{"d_us": 60000000}}' \
-w "%{http_code}" -s -o /dev/null)
if [ "$STATUS" != "204" ]
then
exit_fail "Expected 204 no content. Got: $STATUS"
fi
+echo "OK"
+
+echo -n "Configuring bank account..."
+STATUS=$(curl -H "Content-Type: application/json" -X POST \
+ -H 'Authorization: Bearer secret-token:super_secret' \
+ http://localhost:9966/instances/default/private/accounts \
+ -d '{"payto_uri":"'"$GNUNET_PAYTO"'","credit_facade_url":"'"${FACADE_URL}"'","credit_facade_credentials":{"type":"basic","username":"'"$FACADE_USERNAME"'","password":"'"$FACADE_PASSWORD"'"}}' \
+ -w "%{http_code}" -s -o /dev/null)
+
+if [ "$STATUS" != "200" ]
+then
+ exit_fail "Expected 200 OK. Got: $STATUS"
+fi
echo "OK"
diff --git a/src/testing/testing_api_cmd_delete_account.c b/src/testing/testing_api_cmd_delete_account.c
index 1490dc31..681faa3c 100644
--- a/src/testing/testing_api_cmd_delete_account.c
+++ b/src/testing/testing_api_cmd_delete_account.c
@@ -29,7 +29,7 @@
/**
- * State of a "DELETE /accounts/$ID" CMD.
+ * State of a "DELETE /accounts/$H_WIRE" CMD.
*/
struct DeleteAccountState
{
@@ -52,12 +52,7 @@ struct DeleteAccountState
/**
* ID of the command to get account details from.
*/
- const char *get_instance_ref;
-
- /**
- * Payto URI to extract h_wire from.
- */
- const char *payto_uri;
+ const char *create_account_ref;
/**
* Expected HTTP response code.
@@ -128,7 +123,7 @@ delete_account_run (void *cls,
das->is = is;
ref = TALER_TESTING_interpreter_lookup_command (is,
- das->get_instance_ref);
+ das->create_account_ref);
if (NULL == ref)
{
GNUNET_break (0);
@@ -141,45 +136,22 @@ delete_account_run (void *cls,
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Command %s lacked merchant base URL\n",
- das->get_instance_ref);
+ das->create_account_ref);
GNUNET_break (0);
TALER_TESTING_FAIL (is);
return;
}
- for (unsigned int i = 0; i<UINT_MAX; i++)
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_h_wires (ref,
+ 0,
+ &h_wire))
{
- const char *payto_uri;
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_payto_uris (ref,
- i,
- &payto_uri))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Command %s did not return payto URI %s\n",
- das->get_instance_ref,
- das->payto_uri);
- GNUNET_break (0);
- TALER_TESTING_FAIL (is);
- return;
- }
- if (0 != strcmp (payto_uri,
- das->payto_uri))
- continue; /* different account */
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_h_wires (ref,
- i,
- &h_wire))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Command %s had payto URI %s but lacked h_wire!?\n",
- das->get_instance_ref,
- das->payto_uri);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Command %s did not return H_WIRE\n",
+ das->create_account_ref);
GNUNET_break (0);
TALER_TESTING_FAIL (is);
return;
- }
- break;
}
GNUNET_assert (NULL != h_wire);
das->adh = TALER_MERCHANT_account_delete (
@@ -217,15 +189,13 @@ delete_account_cleanup (void *cls,
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_account (const char *label,
- const char *get_instance_ref,
- const char *payto_uri,
+ const char *create_account_ref,
unsigned int http_status)
{
struct DeleteAccountState *das;
das = GNUNET_new (struct DeleteAccountState);
- das->get_instance_ref = get_instance_ref;
- das->payto_uri = payto_uri;
+ das->create_account_ref = create_account_ref;
das->http_status = http_status;
{
struct TALER_TESTING_Command cmd = {
diff --git a/src/testing/testing_api_cmd_delete_otp_device.c b/src/testing/testing_api_cmd_delete_otp_device.c
new file mode 100644
index 00000000..3d15c645
--- /dev/null
+++ b/src/testing/testing_api_cmd_delete_otp_device.c
@@ -0,0 +1,181 @@
+/*
+ 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 testing_api_cmd_delete_otp_device.c
+ * @brief command to test DELETE /otp-devices/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "DELETE /otp-devices/$ID" CMD.
+ */
+struct DeleteOtpDeviceState
+{
+
+ /**
+ * Handle for a "DELETE otp_device" request.
+ */
+ struct TALER_MERCHANT_OtpDeviceDeleteHandle *tdh;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Base URL of the merchant serving the request.
+ */
+ const char *merchant_url;
+
+ /**
+ * ID of the otp_device to run DELETE for.
+ */
+ const char *otp_device_id;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a /delete/otp-devices/$ID operation.
+ *
+ * @param cls closure for this function
+ * @param hr response being processed
+ */
+static void
+delete_otp_device_cb (void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr)
+{
+ struct DeleteOtpDeviceState *dis = cls;
+
+ dis->tdh = NULL;
+ if (dis->http_status != hr->http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u (%d) to command %s\n",
+ hr->http_status,
+ (int) hr->ec,
+ TALER_TESTING_interpreter_get_current_label (dis->is));
+ TALER_TESTING_interpreter_fail (dis->is);
+ return;
+ }
+ switch (hr->http_status)
+ {
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ break;
+ case MHD_HTTP_CONFLICT:
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unhandled HTTP status %u for DELETE otp_device.\n",
+ hr->http_status);
+ }
+ TALER_TESTING_interpreter_next (dis->is);
+}
+
+
+/**
+ * Run the "DELETE otp_device" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+delete_otp_device_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct DeleteOtpDeviceState *dis = cls;
+
+ dis->is = is;
+ dis->tdh = TALER_MERCHANT_otp_device_delete (
+ TALER_TESTING_interpreter_get_context (is),
+ dis->merchant_url,
+ dis->otp_device_id,
+ &delete_otp_device_cb,
+ dis);
+ GNUNET_assert (NULL != dis->tdh);
+}
+
+
+/**
+ * Free the state of a "DELETE otp_device" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+delete_otp_device_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct DeleteOtpDeviceState *dis = cls;
+
+ if (NULL != dis->tdh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "DELETE /otp-devices/$ID operation did not complete\n");
+ TALER_MERCHANT_otp_device_delete_cancel (dis->tdh);
+ }
+ GNUNET_free (dis);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_delete_otp_device (const char *label,
+ const char *merchant_url,
+ const char *otp_device_id,
+ unsigned int http_status)
+{
+ struct DeleteOtpDeviceState *dis;
+
+ dis = GNUNET_new (struct DeleteOtpDeviceState);
+ dis->merchant_url = merchant_url;
+ dis->otp_device_id = otp_device_id;
+ dis->http_status = http_status;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = dis,
+ .label = label,
+ .run = &delete_otp_device_run,
+ .cleanup = &delete_otp_device_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_delete_otp_device.c */
diff --git a/src/testing/testing_api_cmd_get_instance.c b/src/testing/testing_api_cmd_get_instance.c
index e706f85b..c3199a7e 100644
--- a/src/testing/testing_api_cmd_get_instance.c
+++ b/src/testing/testing_api_cmd_get_instance.c
@@ -29,39 +29,6 @@
/**
- * Details about a merchant's bank account.
- */
-struct MERCHANT_Account
-{
- /**
- * salt used to compute h_wire
- */
- struct TALER_WireSaltP salt;
-
- /**
- * payto:// URI of the account.
- */
- char *payto_uri;
-
- /**
- * Credit facade URL of the account.
- */
- char *credit_facade_url;
-
- /**
- * Hash of @e payto_uri and @e salt.
- */
- struct TALER_MerchantWireHashP h_wire;
-
- /**
- * true if the account is active,
- * false if it is historic.
- */
- bool active;
-};
-
-
-/**
* State of a "GET instance" CMD.
*/
struct GetInstanceState
@@ -93,42 +60,6 @@ struct GetInstanceState
const char *instance_reference;
/**
- * Whether we should check the instance's accounts or not.
- */
- bool cmp_accounts;
-
- /**
- * The accounts of the merchant we expect to be active.
- */
- const char **active_accounts;
-
- /**
- * The length of @e active_accounts.
- */
- unsigned int active_accounts_length;
-
- /**
- * The accounts of the merchant we expect to be inactive.
- */
- const char **inactive_accounts;
-
- /**
- * Length of the @e accounts array.
- */
- unsigned int accounts_length;
-
- /**
- * Array of @e accounts_length bank accounts of the merchant instance as
- * returned by the request.
- */
- struct MERCHANT_Account *accounts;
-
- /**
- * The length of @e inactive_accounts.
- */
- unsigned int inactive_accounts_length;
-
- /**
* Expected HTTP response code.
*/
unsigned int http_status;
@@ -171,21 +102,6 @@ get_instance_cb (void *cls,
const struct TALER_MERCHANT_InstanceDetails *details =
&igr->details.ok.details;
- gis->accounts_length = igr->details.ok.accounts_length;
- gis->accounts = GNUNET_new_array (gis->accounts_length,
- struct MERCHANT_Account);
- for (unsigned int i = 0; i<gis->accounts_length; i++)
- {
- const struct TALER_MERCHANT_Account *src = &igr->details.ok.accounts[i];
- struct MERCHANT_Account *dst = &gis->accounts[i];
-
- dst->salt = src->salt;
- dst->payto_uri = GNUNET_strdup (src->payto_uri);
- if (NULL != src->credit_facade_url)
- dst->credit_facade_url = GNUNET_strdup (src->credit_facade_url);
- dst->h_wire = src->h_wire;
- dst->active = src->active;
- }
{
const char *name;
@@ -283,65 +199,6 @@ get_instance_cb (void *cls,
return;
}
}
- /* We aren't guaranteed an order for the accounts, so we just have to check
- that we can match each account returned with exactly one account
- expected. */
- if (gis->cmp_accounts)
- {
- unsigned int have_al = igr->details.ok.accounts_length;
- unsigned int expected_accounts_length =
- gis->active_accounts_length + gis->inactive_accounts_length;
- unsigned int matches[GNUNET_NZL (have_al)];
-
- if (have_al != expected_accounts_length)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Accounts length does not match\n");
- TALER_TESTING_interpreter_fail (gis->is);
- return;
- }
-
- memset (matches,
- 0,
- sizeof (matches));
-
- /* Compare the accounts */
- for (unsigned int i = 0; i < have_al; ++i)
- {
- const struct TALER_MERCHANT_Account *account
- = &igr->details.ok.accounts[i];
- for (unsigned int j = 0; j < gis->active_accounts_length; ++j)
- {
- if ((0 == strcasecmp (account->payto_uri,
- gis->active_accounts[j])) &&
- account->active)
- {
- matches[i] += 1;
- }
- }
- for (unsigned int j = 0; j < gis->inactive_accounts_length; ++j)
- {
- if ((0 == strcasecmp (account->payto_uri,
- gis->inactive_accounts[j])) &&
- (! account->active))
- {
- matches[i] += 1;
- }
- }
- }
-
- // Each account should have exactly one match.
- for (unsigned int i = 0; i < have_al; ++i)
- {
- if (1 != matches[i])
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Instance account does not match\n");
- TALER_TESTING_interpreter_fail (gis->is);
- return;
- }
- }
- }
}
break;
case MHD_HTTP_UNAUTHORIZED:
@@ -402,14 +259,6 @@ get_instance_cleanup (void *cls,
"GET /instances/$ID operation did not complete\n");
TALER_MERCHANT_instance_get_cancel (gis->igh);
}
- for (unsigned int i = 0; i<gis->accounts_length; i++)
- {
- struct MERCHANT_Account *acc = &gis->accounts[i];
-
- GNUNET_free (acc->payto_uri);
- GNUNET_free (acc->credit_facade_url);
- }
- GNUNET_free (gis->accounts);
GNUNET_free (gis);
}
@@ -431,37 +280,15 @@ get_instance_traits (void *cls,
unsigned int index)
{
struct GetInstanceState *pps = cls;
-
- if (index < pps->accounts_length)
- {
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_merchant_base_url (pps->merchant_url),
- TALER_TESTING_make_trait_h_wires (
- index,
- &pps->accounts[index].h_wire),
- TALER_TESTING_make_trait_payto_uris (
- index,
- pps->accounts[index].payto_uri),
- TALER_TESTING_trait_end (),
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
- }
- else
- {
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_merchant_base_url (pps->merchant_url),
- TALER_TESTING_trait_end (),
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
- }
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_merchant_base_url (pps->merchant_url),
+ TALER_TESTING_trait_end (),
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
}
@@ -479,44 +306,6 @@ TALER_TESTING_cmd_merchant_get_instance (const char *label,
gis->instance_id = instance_id;
gis->http_status = http_status;
gis->instance_reference = instance_reference;
- gis->cmp_accounts = false;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = gis,
- .label = label,
- .run = &get_instance_run,
- .cleanup = &get_instance_cleanup,
- .traits = &get_instance_traits
- };
-
- return cmd;
- }
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_merchant_get_instance2 (const char *label,
- const char *merchant_url,
- const char *instance_id,
- unsigned int http_status,
- const char *instance_reference,
- const char *active_accounts[],
- unsigned int active_accounts_length,
- const char *inactive_accounts[],
- unsigned int inactive_accounts_length)
-{
- struct GetInstanceState *gis;
-
- gis = GNUNET_new (struct GetInstanceState);
- gis->merchant_url = merchant_url;
- gis->instance_id = instance_id;
- gis->http_status = http_status;
- gis->instance_reference = instance_reference;
- gis->cmp_accounts = true;
- gis->active_accounts = active_accounts;
- gis->active_accounts_length = active_accounts_length;
- gis->inactive_accounts = inactive_accounts;
- gis->inactive_accounts_length = inactive_accounts_length;
{
struct TALER_TESTING_Command cmd = {
.cls = gis,
diff --git a/src/testing/testing_api_cmd_get_otp_device.c b/src/testing/testing_api_cmd_get_otp_device.c
new file mode 100644
index 00000000..272039af
--- /dev/null
+++ b/src/testing/testing_api_cmd_get_otp_device.c
@@ -0,0 +1,227 @@
+/*
+ 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 testing_api_cmd_get_otp_device.c
+ * @brief command to test GET /otp-devices/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "GET OTP device" CMD.
+ */
+struct GetOtpDeviceState
+{
+
+ /**
+ * Handle for a "GET /otp-device/$ID" request.
+ */
+ struct TALER_MERCHANT_OtpDeviceGetHandle *igh;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Base URL of the merchant serving the request.
+ */
+ const char *merchant_url;
+
+ /**
+ * ID of the otp_device to run GET for.
+ */
+ const char *otp_device_id;
+
+ /**
+ * Reference for a POST or PATCH /otp-devices CMD (optional).
+ */
+ const char *otp_device_reference;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a GET /otp-devices/$ID operation.
+ *
+ * @param cls closure for this function
+ * @param tgr HTTP response details
+ */
+static void
+get_otp_device_cb (void *cls,
+ const struct TALER_MERCHANT_OtpDeviceGetResponse *tgr)
+{
+ struct GetOtpDeviceState *gis = cls;
+ const struct TALER_TESTING_Command *otp_device_cmd;
+
+ gis->igh = NULL;
+ if (gis->http_status != tgr->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u (%d) to command %s\n",
+ tgr->hr.http_status,
+ (int) tgr->hr.ec,
+ TALER_TESTING_interpreter_get_current_label (gis->is));
+ TALER_TESTING_interpreter_fail (gis->is);
+ return;
+ }
+ switch (tgr->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ {
+ const char *expected_description;
+
+ otp_device_cmd = TALER_TESTING_interpreter_lookup_command (
+ gis->is,
+ gis->otp_device_reference);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_otp_device_description (otp_device_cmd,
+ &expected_description))
+ TALER_TESTING_interpreter_fail (gis->is);
+ if (0 != strcmp (tgr->details.ok.otp_device_description,
+ expected_description))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "OtpDevice description does not match\n");
+ TALER_TESTING_interpreter_fail (gis->is);
+ return;
+ }
+ }
+ {
+ const char *expected_otp_key;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_otp_key (otp_device_cmd,
+ &expected_otp_key))
+ TALER_TESTING_interpreter_fail (gis->is);
+ if ( ( (NULL == tgr->details.ok.otp_key) && (NULL != expected_otp_key)) ||
+ ( (NULL != tgr->details.ok.otp_key) && (NULL == expected_otp_key)) ||
+ ( (NULL != tgr->details.ok.otp_key) &&
+ (0 != strcmp (tgr->details.ok.otp_key,
+ expected_otp_key)) ) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "OtpDevice otp_key `%s' does not match `%s'\n",
+ tgr->details.ok.otp_key,
+ expected_otp_key);
+ TALER_TESTING_interpreter_fail (gis->is);
+ return;
+ }
+ }
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unhandled HTTP status.\n");
+ }
+ TALER_TESTING_interpreter_next (gis->is);
+}
+
+
+/**
+ * Run the "GET /otp-device/$ID" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+get_otp_device_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct GetOtpDeviceState *gis = cls;
+
+ gis->is = is;
+ gis->igh = TALER_MERCHANT_otp_device_get (
+ TALER_TESTING_interpreter_get_context (is),
+ gis->merchant_url,
+ gis->otp_device_id,
+ &get_otp_device_cb,
+ gis);
+ GNUNET_assert (NULL != gis->igh);
+}
+
+
+/**
+ * Free the state of a "GET /otp-device/$ID" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+get_otp_device_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct GetOtpDeviceState *gis = cls;
+
+ if (NULL != gis->igh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "GET /otp-devices/$ID operation did not complete\n");
+ TALER_MERCHANT_otp_device_get_cancel (gis->igh);
+ }
+ GNUNET_free (gis);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_otp_device (
+ const char *label,
+ const char *merchant_url,
+ const char *otp_device_id,
+ unsigned int http_status,
+ const char *otp_device_reference)
+{
+ struct GetOtpDeviceState *gis;
+
+ gis = GNUNET_new (struct GetOtpDeviceState);
+ gis->merchant_url = merchant_url;
+ gis->otp_device_id = otp_device_id;
+ gis->http_status = http_status;
+ gis->otp_device_reference = otp_device_reference;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = gis,
+ .label = label,
+ .run = &get_otp_device_run,
+ .cleanup = &get_otp_device_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_get_otp_device.c */
diff --git a/src/testing/testing_api_cmd_get_otp_devices.c b/src/testing/testing_api_cmd_get_otp_devices.c
new file mode 100644
index 00000000..b4f370c5
--- /dev/null
+++ b/src/testing/testing_api_cmd_get_otp_devices.c
@@ -0,0 +1,238 @@
+/*
+ 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 testing_api_cmd_get_otp_devices.c
+ * @brief command to test GET /otp-devices
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "GET /otp-devices" CMD.
+ */
+struct GetOtpDevicesState
+{
+
+ /**
+ * Handle for a "GET /otp-devices" request.
+ */
+ struct TALER_MERCHANT_OtpDevicesGetHandle *igh;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Base URL of the merchant serving the request.
+ */
+ const char *merchant_url;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int http_status;
+
+ /**
+ * The list of otp_device references.
+ */
+ const char **otp_devices;
+
+ /**
+ * Length of @e otp_devices.
+ */
+ unsigned int otp_devices_length;
+
+};
+
+
+/**
+ * Callback for a GET /otp-devices operation.
+ *
+ * @param cls closure for this function
+ * @param tgr response details
+ */
+static void
+get_otp_devices_cb (void *cls,
+ const struct TALER_MERCHANT_OtpDevicesGetResponse *tgr)
+{
+ struct GetOtpDevicesState *gis = cls;
+
+ gis->igh = NULL;
+ if (gis->http_status != tgr->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u (%d) to command %s\n",
+ tgr->hr.http_status,
+ (int) tgr->hr.ec,
+ TALER_TESTING_interpreter_get_current_label (gis->is));
+ TALER_TESTING_interpreter_fail (gis->is);
+ return;
+ }
+ switch (tgr->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ if (tgr->details.ok.otp_devices_length != gis->otp_devices_length)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Length of otp_devices found does not match\n");
+ TALER_TESTING_interpreter_fail (gis->is);
+ return;
+ }
+ for (unsigned int i = 0; i < gis->otp_devices_length; ++i)
+ {
+ const struct TALER_TESTING_Command *otp_device_cmd;
+
+ otp_device_cmd = TALER_TESTING_interpreter_lookup_command (
+ gis->is,
+ gis->otp_devices[i]);
+
+ {
+ const char *otp_device_id;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_otp_id (otp_device_cmd,
+ &otp_device_id))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not fetch otp_device id\n");
+ TALER_TESTING_interpreter_fail (gis->is);
+ return;
+ }
+ if (0 != strcmp (tgr->details.ok.otp_devices[i].otp_device_id,
+ otp_device_id))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "OtpDevice id does not match\n");
+ TALER_TESTING_interpreter_fail (gis->is);
+ return;
+ }
+ }
+ }
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* instance does not exist */
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unhandled HTTP status %u (%d).\n",
+ tgr->hr.http_status,
+ tgr->hr.ec);
+ break;
+ }
+ TALER_TESTING_interpreter_next (gis->is);
+}
+
+
+/**
+ * Run the "GET /otp-devices" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+get_otp_devices_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct GetOtpDevicesState *gis = cls;
+
+ gis->is = is;
+ gis->igh = TALER_MERCHANT_otp_devices_get (
+ TALER_TESTING_interpreter_get_context (is),
+ gis->merchant_url,
+ &get_otp_devices_cb,
+ gis);
+ GNUNET_assert (NULL != gis->igh);
+}
+
+
+/**
+ * Free the state of a "GET otp_device" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+get_otp_devices_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct GetOtpDevicesState *gis = cls;
+
+ if (NULL != gis->igh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "GET /otp-devices operation did not complete\n");
+ TALER_MERCHANT_otp_devices_get_cancel (gis->igh);
+ }
+ GNUNET_array_grow (gis->otp_devices,
+ gis->otp_devices_length,
+ 0);
+ GNUNET_free (gis);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_otp_devices (const char *label,
+ const char *merchant_url,
+ unsigned int http_status,
+ ...)
+{
+ struct GetOtpDevicesState *gis;
+
+ gis = GNUNET_new (struct GetOtpDevicesState);
+ gis->merchant_url = merchant_url;
+ gis->http_status = http_status;
+ {
+ const char *clabel;
+ va_list ap;
+
+ va_start (ap, http_status);
+ while (NULL != (clabel = va_arg (ap, const char *)))
+ {
+ GNUNET_array_append (gis->otp_devices,
+ gis->otp_devices_length,
+ clabel);
+ }
+ va_end (ap);
+ }
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = gis,
+ .label = label,
+ .run = &get_otp_devices_run,
+ .cleanup = &get_otp_devices_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_get_otp_devices.c */
diff --git a/src/testing/testing_api_cmd_get_template.c b/src/testing/testing_api_cmd_get_template.c
index 92888e6f..377ffe44 100644
--- a/src/testing/testing_api_cmd_get_template.c
+++ b/src/testing/testing_api_cmd_get_template.c
@@ -114,22 +114,22 @@ get_template_cb (void *cls,
}
}
{
- const char *expected_pos_key;
+ const char *expected_otp_id;
if (GNUNET_OK !=
- TALER_TESTING_get_trait_template_pos_key (template_cmd,
- &expected_pos_key))
+ TALER_TESTING_get_trait_otp_id (template_cmd,
+ &expected_otp_id))
TALER_TESTING_interpreter_fail (gis->is);
- if ( ( (NULL == tgr->details.ok.pos_key) && (NULL != expected_pos_key)) ||
- ( (NULL != tgr->details.ok.pos_key) && (NULL == expected_pos_key)) ||
- ( (NULL != tgr->details.ok.pos_key) &&
- (0 != strcmp (tgr->details.ok.pos_key,
- expected_pos_key)) ) )
+ if ( ( (NULL == tgr->details.ok.otp_id) && (NULL != expected_otp_id)) ||
+ ( (NULL != tgr->details.ok.otp_id) && (NULL == expected_otp_id)) ||
+ ( (NULL != tgr->details.ok.otp_id) &&
+ (0 != strcmp (tgr->details.ok.otp_id,
+ expected_otp_id)) ) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Template pos_key `%s' does not match `%s'\n",
- tgr->details.ok.pos_key,
- expected_pos_key);
+ tgr->details.ok.otp_id,
+ expected_otp_id);
TALER_TESTING_interpreter_fail (gis->is);
return;
}
diff --git a/src/testing/testing_api_cmd_patch_instance.c b/src/testing/testing_api_cmd_patch_instance.c
index 59dcac07..b3a2865c 100644
--- a/src/testing/testing_api_cmd_patch_instance.c
+++ b/src/testing/testing_api_cmd_patch_instance.c
@@ -55,16 +55,6 @@ struct PatchInstanceState
const char *instance_id;
/**
- * Length of the @payto_uris array
- */
- unsigned int payto_uris_length;
-
- /**
- * Array of payto URIs.
- */
- const char **payto_uris;
-
- /**
* Name of the instance.
*/
const char *name;
@@ -161,21 +151,12 @@ patch_instance_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct PatchInstanceState *pis = cls;
- struct TALER_MERCHANT_AccountConfig accounts[GNUNET_NZL (
- pis->payto_uris_length)];
-
- memset (accounts,
- 0,
- sizeof (accounts));
- for (unsigned int i = 0; i<pis->payto_uris_length; i++)
- accounts[i].payto_uri = pis->payto_uris[i];
+
pis->is = is;
pis->iph = TALER_MERCHANT_instance_patch (
TALER_TESTING_interpreter_get_context (is),
pis->merchant_url,
pis->instance_id,
- pis->payto_uris_length,
- accounts,
pis->name,
TALER_KYCLOGIC_KYC_UT_BUSINESS,
pis->address,
@@ -199,39 +180,23 @@ patch_instance_run (void *cls,
* @param index index number of the object to extract.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
patch_instance_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct PatchInstanceState *pis = cls;
- #define NUM_TRAITS (pis->payto_uris_length) + 9
- struct TALER_TESTING_Trait traits[NUM_TRAITS];
- traits[0] =
- TALER_TESTING_make_trait_instance_name (pis->name);
- traits[1] =
- TALER_TESTING_make_trait_instance_id (pis->instance_id);
- traits[2] =
- TALER_TESTING_make_trait_address (pis->address);
- traits[3] =
- TALER_TESTING_make_trait_jurisdiction (pis->jurisdiction);
- traits[4] =
- TALER_TESTING_make_trait_use_stefan (&pis->use_stefan);
- traits[5] =
- TALER_TESTING_make_trait_wire_delay (&pis->default_wire_transfer_delay);
- traits[6] =
- TALER_TESTING_make_trait_pay_delay (&pis->default_pay_delay);
- traits[7] =
- TALER_TESTING_make_trait_payto_length (&pis->payto_uris_length);
- traits[NUM_TRAITS - 1] =
- TALER_TESTING_trait_end ();
- for (unsigned int i = 0; i < pis->payto_uris_length; ++i)
- {
- traits[10 + i] =
- TALER_TESTING_make_trait_payto_uris (i,
- pis->payto_uris[i]);
- }
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_instance_name (pis->name),
+ TALER_TESTING_make_trait_instance_id (pis->instance_id),
+ TALER_TESTING_make_trait_address (pis->address),
+ TALER_TESTING_make_trait_jurisdiction (pis->jurisdiction),
+ TALER_TESTING_make_trait_use_stefan (&pis->use_stefan),
+ TALER_TESTING_make_trait_wire_delay (&pis->default_wire_transfer_delay),
+ TALER_TESTING_make_trait_pay_delay (&pis->default_pay_delay),
+ TALER_TESTING_trait_end ()
+ };
return TALER_TESTING_get_trait (traits,
ret,
@@ -259,9 +224,7 @@ patch_instance_cleanup (void *cls,
"PATCH /instance/$ID operation did not complete\n");
TALER_MERCHANT_instance_patch_cancel (pis->iph);
}
- json_decref (pis->address);
json_decref (pis->jurisdiction);
- GNUNET_free (pis->payto_uris);
GNUNET_free (pis);
}
@@ -271,8 +234,6 @@ TALER_TESTING_cmd_merchant_patch_instance (
const char *label,
const char *merchant_url,
const char *instance_id,
- unsigned int payto_uris_length,
- const char *payto_uris[],
const char *name,
json_t *address,
json_t *jurisdiction,
@@ -287,12 +248,6 @@ TALER_TESTING_cmd_merchant_patch_instance (
pis->merchant_url = merchant_url;
pis->instance_id = instance_id;
pis->http_status = http_status;
- pis->payto_uris_length = payto_uris_length;
- pis->payto_uris = GNUNET_new_array (payto_uris_length,
- const char *);
- GNUNET_memcpy (pis->payto_uris,
- payto_uris,
- sizeof (const char *) * payto_uris_length);
pis->name = name;
pis->address = address; /* ownership transfer! */
pis->jurisdiction = jurisdiction; /* ownership transfer! */
diff --git a/src/testing/testing_api_cmd_patch_otp_device.c b/src/testing/testing_api_cmd_patch_otp_device.c
new file mode 100644
index 00000000..ce263908
--- /dev/null
+++ b/src/testing/testing_api_cmd_patch_otp_device.c
@@ -0,0 +1,250 @@
+/*
+ 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 testing_api_cmd_patch_otp_device.c
+ * @brief command to test PATCH /otp-device
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "PATCH /otp-device" CMD.
+ */
+struct PatchOtpDeviceState
+{
+
+ /**
+ * Handle for a "GET otp_device" request.
+ */
+ struct TALER_MERCHANT_OtpDevicePatchHandle *iph;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Base URL of the merchant serving the request.
+ */
+ const char *merchant_url;
+
+ /**
+ * ID of the otp_device to run GET for.
+ */
+ const char *otp_device_id;
+
+ /**
+ * description of the otp_device
+ */
+ const char *otp_device_description;
+
+ /**
+ * base64-encoded key
+ */
+ char *otp_key;
+
+ /**
+ * Algorithm used by the OTP device
+ */
+ enum TALER_MerchantConfirmationAlgorithm otp_alg;
+
+ /**
+ * Counter of the device (if in counter mode).
+ */
+ uint64_t otp_ctr;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a PATCH /otp-devices/$ID operation.
+ *
+ * @param cls closure for this function
+ * @param hr response being processed
+ */
+static void
+patch_otp_device_cb (void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr)
+{
+ struct PatchOtpDeviceState *pis = cls;
+
+ pis->iph = NULL;
+ if (pis->http_status != hr->http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u (%d) to command %s\n",
+ hr->http_status,
+ (int) hr->ec,
+ TALER_TESTING_interpreter_get_current_label (pis->is));
+ TALER_TESTING_interpreter_fail (pis->is);
+ return;
+ }
+ switch (hr->http_status)
+ {
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ break;
+ case MHD_HTTP_CONFLICT:
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unhandled HTTP status %u for PATCH /otp-devices/ID.\n",
+ hr->http_status);
+ }
+ TALER_TESTING_interpreter_next (pis->is);
+}
+
+
+/**
+ * Run the "PATCH /otp-devices/$ID" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+patch_otp_device_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PatchOtpDeviceState *pis = cls;
+
+ pis->is = is;
+ pis->iph = TALER_MERCHANT_otp_device_patch (
+ TALER_TESTING_interpreter_get_context (is),
+ pis->merchant_url,
+ pis->otp_device_id,
+ pis->otp_device_description,
+ pis->otp_key,
+ pis->otp_alg,
+ pis->otp_ctr,
+ &patch_otp_device_cb,
+ pis);
+ GNUNET_assert (NULL != pis->iph);
+}
+
+
+/**
+ * Offers information from the PATCH /otp-devices CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+patch_otp_device_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct PatchOtpDeviceState *pts = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_otp_device_description (pts->otp_device_description),
+ TALER_TESTING_make_trait_otp_key (pts->otp_key),
+ TALER_TESTING_make_trait_otp_alg (&pts->otp_alg),
+ TALER_TESTING_make_trait_otp_id (pts->otp_device_id),
+ TALER_TESTING_trait_end (),
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Free the state of a "GET otp_device" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+patch_otp_device_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PatchOtpDeviceState *pis = cls;
+
+ if (NULL != pis->iph)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "PATCH /otp-devices/$ID operation did not complete\n");
+ TALER_MERCHANT_otp_device_patch_cancel (pis->iph);
+ }
+ GNUNET_free (pis->otp_key);
+ GNUNET_free (pis);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_patch_otp_device (
+ const char *label,
+ const char *merchant_url,
+ const char *otp_device_id,
+ const char *otp_device_description,
+ const char *otp_key,
+ const enum TALER_MerchantConfirmationAlgorithm otp_alg,
+ uint64_t otp_ctr,
+ unsigned int http_status)
+{
+ struct PatchOtpDeviceState *pis;
+
+ pis = GNUNET_new (struct PatchOtpDeviceState);
+ pis->merchant_url = merchant_url;
+ pis->otp_device_id = otp_device_id;
+ pis->http_status = http_status;
+ pis->otp_device_description = otp_device_description;
+ pis->otp_key = GNUNET_strdup (otp_key);
+ pis->otp_alg = otp_alg;
+ pis->otp_ctr = otp_ctr;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = pis,
+ .label = label,
+ .run = &patch_otp_device_run,
+ .cleanup = &patch_otp_device_cleanup,
+ .traits = &patch_otp_device_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_patch_otp_device.c */
diff --git a/src/testing/testing_api_cmd_patch_template.c b/src/testing/testing_api_cmd_patch_template.c
index caf3bf23..8ad9d9dc 100644
--- a/src/testing/testing_api_cmd_patch_template.c
+++ b/src/testing/testing_api_cmd_patch_template.c
@@ -60,14 +60,9 @@ struct PatchTemplateState
const char *template_description;
/**
- * base64-encoded key
+ * OTP device ID
*/
- char *pos_key;
-
- /**
- * Option that add amount of the order
- */
- enum TALER_MerchantConfirmationAlgorithm pos_alg;
+ char *otp_id;
/**
* Contract of the company
@@ -147,8 +142,7 @@ patch_template_run (void *cls,
pis->merchant_url,
pis->template_id,
pis->template_description,
- pis->pos_key,
- pis->pos_alg,
+ pis->otp_id,
pis->template_contract,
&patch_template_cb,
pis);
@@ -175,8 +169,7 @@ patch_template_traits (void *cls,
struct PatchTemplateState *pts = cls;
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_template_description (pts->template_description),
- TALER_TESTING_make_trait_template_pos_key (pts->pos_key),
- TALER_TESTING_make_trait_template_pos_alg (&pts->pos_alg),
+ TALER_TESTING_make_trait_otp_id (pts->otp_id),
TALER_TESTING_make_trait_template_contract (pts->template_contract),
TALER_TESTING_make_trait_template_id (pts->template_id),
TALER_TESTING_trait_end (),
@@ -208,7 +201,7 @@ patch_template_cleanup (void *cls,
"PATCH /templates/$ID operation did not complete\n");
TALER_MERCHANT_template_patch_cancel (pis->iph);
}
- GNUNET_free (pis->pos_key);
+ GNUNET_free (pis->otp_id);
json_decref (pis->template_contract);
GNUNET_free (pis);
}
@@ -220,8 +213,7 @@ TALER_TESTING_cmd_merchant_patch_template (
const char *merchant_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- const enum TALER_MerchantConfirmationAlgorithm pos_alg,
+ const char *otp_id,
json_t *template_contract,
unsigned int http_status)
{
@@ -232,8 +224,7 @@ TALER_TESTING_cmd_merchant_patch_template (
pis->template_id = template_id;
pis->http_status = http_status;
pis->template_description = template_description;
- pis->pos_key = (NULL == pos_key) ? NULL : GNUNET_strdup (pos_key);
- pis->pos_alg = pos_alg;
+ pis->otp_id = (NULL == otp_id) ? NULL : GNUNET_strdup (otp_id);
pis->template_contract = template_contract; /* ownership taken */
{
struct TALER_TESTING_Command cmd = {
diff --git a/src/testing/testing_api_cmd_pay_order.c b/src/testing/testing_api_cmd_pay_order.c
index b49dd716..efc94a80 100644
--- a/src/testing/testing_api_cmd_pay_order.c
+++ b/src/testing/testing_api_cmd_pay_order.c
@@ -349,12 +349,13 @@ pay_run (void *cls,
if (NULL == contract_terms)
TALER_TESTING_FAIL (is);
if (GNUNET_OK !=
- TALER_TESTING_get_trait_template_pos_key (proposal_cmd,
- &ps->pos_key))
+ TALER_TESTING_get_trait_otp_key (proposal_cmd,
+ &ps->pos_key))
ps->pos_key = NULL;
- if (GNUNET_OK ==
- TALER_TESTING_get_trait_template_pos_alg (proposal_cmd,
- &alg_ptr))
+ if ( (GNUNET_OK ==
+ TALER_TESTING_get_trait_otp_alg (proposal_cmd,
+ &alg_ptr)) &&
+ (NULL != alg_ptr) )
ps->pos_alg = *alg_ptr;
{
/* Get information that needs to be put verbatim in the
@@ -543,8 +544,8 @@ pay_traits (void *cls,
TALER_TESTING_make_trait_merchant_pub (merchant_pub),
TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
TALER_TESTING_make_trait_amount (&amount_with_fee),
- TALER_TESTING_make_trait_template_pos_key (ps->pos_key),
- TALER_TESTING_make_trait_template_pos_alg (&ps->pos_alg),
+ TALER_TESTING_make_trait_otp_key (ps->pos_key),
+ TALER_TESTING_make_trait_otp_alg (&ps->pos_alg),
TALER_TESTING_trait_end ()
};
diff --git a/src/testing/testing_api_cmd_post_account.c b/src/testing/testing_api_cmd_post_account.c
index 345e869f..8ddad94c 100644
--- a/src/testing/testing_api_cmd_post_account.c
+++ b/src/testing/testing_api_cmd_post_account.c
@@ -37,7 +37,7 @@ struct PostAccountState
/**
* Handle for a "GET product" request.
*/
- struct TALER_MERCHANT_AccountPostHandle *aph;
+ struct TALER_MERCHANT_AccountsPostHandle *aph;
/**
* The interpreter state.
@@ -50,9 +50,24 @@ struct PostAccountState
const char *merchant_url;
/**
- * Account configuration for the account to create.
+ * Wire hash of the created account, set on success.
*/
- struct TALER_MERCHANT_AccountConfig ac;
+ struct TALER_MerchantWireHashP h_wire;
+
+ /**
+ * RFC 8905 URI for the account to create.
+ */
+ char *payto_uri;
+
+ /**
+ * Credit facade URL for the account to create.
+ */
+ char *credit_facade_url;
+
+ /**
+ * Credit facade credentials for the account to create.
+ */
+ json_t *credit_facade_credentials;
/**
* Expected HTTP response code.
@@ -70,7 +85,7 @@ struct PostAccountState
*/
static void
post_account_cb (void *cls,
- const struct TALER_MERCHANT_AccountPostResponse *apr)
+ const struct TALER_MERCHANT_AccountsPostResponse *apr)
{
struct PostAccountState *pas = cls;
@@ -87,7 +102,8 @@ post_account_cb (void *cls,
}
switch (apr->hr.http_status)
{
- case MHD_HTTP_NO_CONTENT:
+ case MHD_HTTP_OK:
+ pas->h_wire = apr->details.ok.h_wire;
break;
case MHD_HTTP_UNAUTHORIZED:
break;
@@ -123,10 +139,12 @@ post_account_run (void *cls,
struct PostAccountState *pas = cls;
pas->is = is;
- pas->aph = TALER_MERCHANT_account_post (
+ pas->aph = TALER_MERCHANT_accounts_post (
TALER_TESTING_interpreter_get_context (is),
pas->merchant_url,
- &pas->ac,
+ pas->payto_uri,
+ pas->credit_facade_url,
+ pas->credit_facade_credentials,
&post_account_cb,
pas);
GNUNET_assert (NULL != pas->aph);
@@ -149,8 +167,16 @@ post_account_traits (void *cls,
const char *trait,
unsigned int index)
{
- /* struct PostAccountState *pps = cls; */
+ struct PostAccountState *pps = cls;
struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_h_wires (
+ 0,
+ &pps->h_wire),
+ TALER_TESTING_make_trait_payto_uris (
+ 0,
+ pps->payto_uri),
+ TALER_TESTING_make_trait_merchant_base_url (
+ pps->merchant_url),
TALER_TESTING_trait_end (),
};
@@ -178,9 +204,11 @@ post_account_cleanup (void *cls,
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"POST /account operation did not complete\n");
- TALER_MERCHANT_account_post_cancel (pas->aph);
+ TALER_MERCHANT_accounts_post_cancel (pas->aph);
}
- json_decref (pas->ac.credit_facade_credentials);
+ GNUNET_free (pas->payto_uri);
+ GNUNET_free (pas->credit_facade_url);
+ json_decref (pas->credit_facade_credentials);
GNUNET_free (pas);
}
@@ -198,10 +226,11 @@ TALER_TESTING_cmd_merchant_post_account (
pas = GNUNET_new (struct PostAccountState);
pas->merchant_url = merchant_url;
- pas->ac.payto_uri = payto_uri;
- pas->ac.credit_facade_url = credit_facade_url;
+ pas->payto_uri = GNUNET_strdup (payto_uri);
+ if (NULL != credit_facade_url)
+ pas->credit_facade_url = GNUNET_strdup (credit_facade_url);
if (NULL != credit_facade_credentials)
- pas->ac.credit_facade_credentials
+ pas->credit_facade_credentials
= json_incref ((json_t *) credit_facade_credentials);
pas->http_status = http_status;
{
diff --git a/src/testing/testing_api_cmd_post_instances.c b/src/testing/testing_api_cmd_post_instances.c
index f90aacaf..f1b81cbf 100644
--- a/src/testing/testing_api_cmd_post_instances.c
+++ b/src/testing/testing_api_cmd_post_instances.c
@@ -55,16 +55,6 @@ struct PostInstancesState
const char *instance_id;
/**
- * Length of the @payto_uris array
- */
- unsigned int payto_uris_length;
-
- /**
- * Array of payto URIs.
- */
- const char **payto_uris;
-
- /**
* Name of the instance.
*/
const char *name;
@@ -168,21 +158,12 @@ post_instances_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct PostInstancesState *pis = cls;
- struct TALER_MERCHANT_AccountConfig accounts[GNUNET_NZL (
- pis->payto_uris_length)];
-
- memset (accounts,
- 0,
- sizeof (accounts));
- for (unsigned int i = 0; i<pis->payto_uris_length; i++)
- accounts[i].payto_uri = pis->payto_uris[i];
+
pis->is = is;
pis->iph = TALER_MERCHANT_instances_post (
TALER_TESTING_interpreter_get_context (is),
pis->merchant_url,
pis->instance_id,
- pis->payto_uris_length,
- accounts,
pis->name,
TALER_KYCLOGIC_KYC_UT_BUSINESS,
pis->address,
@@ -219,32 +200,16 @@ post_instances_traits (void *cls,
unsigned int index)
{
struct PostInstancesState *pis = cls;
- #define NUM_TRAITS (pis->payto_uris_length) + 9
- struct TALER_TESTING_Trait traits[NUM_TRAITS];
- traits[0] =
- TALER_TESTING_make_trait_instance_name (pis->name);
- traits[1] =
- TALER_TESTING_make_trait_instance_id (pis->instance_id);
- traits[2] =
- TALER_TESTING_make_trait_address (pis->address);
- traits[3] =
- TALER_TESTING_make_trait_jurisdiction (pis->jurisdiction);
- traits[4] =
- TALER_TESTING_make_trait_use_stefan (&pis->use_stefan);
- traits[5] =
- TALER_TESTING_make_trait_wire_delay (&pis->default_wire_transfer_delay);
- traits[6] =
- TALER_TESTING_make_trait_pay_delay (&pis->default_pay_delay);
- traits[7] =
- TALER_TESTING_make_trait_payto_length (&pis->payto_uris_length);
- traits[NUM_TRAITS - 1] =
- TALER_TESTING_trait_end ();
- for (unsigned int i = 0; i < pis->payto_uris_length; ++i)
- {
- traits[10 + i] =
- TALER_TESTING_make_trait_payto_uris (i,
- pis->payto_uris[i]);
- }
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_instance_name (pis->name),
+ TALER_TESTING_make_trait_instance_id (pis->instance_id),
+ TALER_TESTING_make_trait_address (pis->address),
+ TALER_TESTING_make_trait_jurisdiction (pis->jurisdiction),
+ TALER_TESTING_make_trait_use_stefan (&pis->use_stefan),
+ TALER_TESTING_make_trait_wire_delay (&pis->default_wire_transfer_delay),
+ TALER_TESTING_make_trait_pay_delay (&pis->default_pay_delay),
+ TALER_TESTING_trait_end ()
+ };
return TALER_TESTING_get_trait (traits,
ret,
@@ -274,7 +239,6 @@ post_instances_cleanup (void *cls,
}
json_decref (pis->address);
json_decref (pis->jurisdiction);
- GNUNET_free (pis->payto_uris);
GNUNET_free (pis);
}
@@ -284,8 +248,6 @@ TALER_TESTING_cmd_merchant_post_instances2 (
const char *label,
const char *merchant_url,
const char *instance_id,
- unsigned int payto_uris_length,
- const char *payto_uris[],
const char *name,
json_t *address,
json_t *jurisdiction,
@@ -301,12 +263,6 @@ TALER_TESTING_cmd_merchant_post_instances2 (
pis->merchant_url = merchant_url;
pis->instance_id = instance_id;
pis->http_status = http_status;
- pis->payto_uris_length = payto_uris_length;
- pis->payto_uris = GNUNET_new_array (payto_uris_length,
- const char *);
- GNUNET_memcpy (pis->payto_uris,
- payto_uris,
- sizeof (const char *) * payto_uris_length);
pis->name = name;
pis->address = address; /* ownership transfer! */
pis->jurisdiction = jurisdiction; /* ownership transfer! */
@@ -332,19 +288,12 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_instances (const char *label,
const char *merchant_url,
const char *instance_id,
- const char *payto_uri,
unsigned int http_status)
{
- const char *payto_uris[] = {
- payto_uri
- };
-
return TALER_TESTING_cmd_merchant_post_instances2 (
label,
merchant_url,
instance_id,
- 1,
- payto_uris,
instance_id,
json_pack ("{s:s}", "city", "shopcity"),
json_pack ("{s:s}", "city", "lawyercity"),
diff --git a/src/testing/testing_api_cmd_post_otp_devices.c b/src/testing/testing_api_cmd_post_otp_devices.c
new file mode 100644
index 00000000..09358274
--- /dev/null
+++ b/src/testing/testing_api_cmd_post_otp_devices.c
@@ -0,0 +1,256 @@
+/*
+ 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 testing_api_cmd_post_otp_devices.c
+ * @brief command to test POST /otp-devices
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "POST /otp-devices" CMD.
+ */
+struct PostOtpDevicesState
+{
+
+ /**
+ * Handle for a "GET otp_device" request.
+ */
+ struct TALER_MERCHANT_OtpDevicesPostHandle *iph;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Base URL of the merchant serving the request.
+ */
+ const char *merchant_url;
+
+ /**
+ * ID of the otp_device to run POST for.
+ */
+ const char *otp_device_id;
+
+ /**
+ * description of the otp_device
+ */
+ const char *otp_device_description;
+
+ /**
+ * base64-encoded key
+ */
+ char *otp_key;
+
+ /**
+ * Option that add amount of the order
+ */
+ enum TALER_MerchantConfirmationAlgorithm otp_alg;
+
+ /**
+ * Counter at the OTP device.
+ */
+ uint64_t otp_ctr;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a POST /otp-devices operation.
+ *
+ * @param cls closure for this function
+ * @param hr response being processed
+ */
+static void
+post_otp_devices_cb (void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr)
+{
+ struct PostOtpDevicesState *tis = cls;
+
+ tis->iph = NULL;
+ if (tis->http_status != hr->http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u (%d) to command %s\n",
+ hr->http_status,
+ (int) hr->ec,
+ TALER_TESTING_interpreter_get_current_label (tis->is));
+ TALER_TESTING_interpreter_fail (tis->is);
+ return;
+ }
+ switch (hr->http_status)
+ {
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ break;
+ case MHD_HTTP_CONFLICT:
+ break;
+ default:
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unhandled HTTP status %u for POST /otp-devices.\n",
+ hr->http_status);
+ }
+ TALER_TESTING_interpreter_next (tis->is);
+}
+
+
+/**
+ * Run the "POST /otp-devices" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+post_otp_devices_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PostOtpDevicesState *tis = cls;
+
+ tis->is = is;
+ tis->iph = TALER_MERCHANT_otp_devices_post (
+ TALER_TESTING_interpreter_get_context (is),
+ tis->merchant_url,
+ tis->otp_device_id,
+ tis->otp_device_description,
+ tis->otp_key,
+ tis->otp_alg,
+ tis->otp_ctr,
+ &post_otp_devices_cb,
+ tis);
+ if (NULL == tis->iph)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tis->is);
+ return;
+ }
+}
+
+
+/**
+ * Offers information from the POST /otp-devices CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+post_otp_devices_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct PostOtpDevicesState *pts = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_otp_device_description (pts->otp_device_description),
+ TALER_TESTING_make_trait_otp_key (pts->otp_key),
+ TALER_TESTING_make_trait_otp_alg (&pts->otp_alg),
+ TALER_TESTING_make_trait_otp_id (pts->otp_device_id),
+ TALER_TESTING_trait_end (),
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Free the state of a "POST otp_device" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+post_otp_devices_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PostOtpDevicesState *tis = cls;
+
+ if (NULL != tis->iph)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "POST /otp-devices operation did not complete\n");
+ TALER_MERCHANT_otp_devices_post_cancel (tis->iph);
+ }
+ GNUNET_free (tis->otp_key);
+ GNUNET_free (tis);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_post_otp_devices (
+ const char *label,
+ const char *merchant_url,
+ const char *otp_device_id,
+ const char *otp_device_description,
+ const char *otp_key,
+ const enum TALER_MerchantConfirmationAlgorithm otp_alg,
+ uint64_t otp_ctr,
+ unsigned int http_status)
+{
+ struct PostOtpDevicesState *tis;
+
+ tis = GNUNET_new (struct PostOtpDevicesState);
+ tis->merchant_url = merchant_url;
+ tis->otp_device_id = otp_device_id;
+ tis->http_status = http_status;
+ tis->otp_device_description = otp_device_description;
+ tis->otp_key = GNUNET_strdup (otp_key);
+ tis->otp_alg = otp_alg;
+ tis->otp_ctr = otp_ctr;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = tis,
+ .label = label,
+ .run = &post_otp_devices_run,
+ .cleanup = &post_otp_devices_cleanup,
+ .traits = &post_otp_devices_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_post_otp_devices.c */
diff --git a/src/testing/testing_api_cmd_post_templates.c b/src/testing/testing_api_cmd_post_templates.c
index 13ffc24e..8c8cd8ca 100644
--- a/src/testing/testing_api_cmd_post_templates.c
+++ b/src/testing/testing_api_cmd_post_templates.c
@@ -60,14 +60,9 @@ struct PostTemplatesState
const char *template_description;
/**
- * base64-encoded key
+ * OTP device ID.
*/
- char *pos_key;
-
- /**
- * Option that add amount of the order
- */
- enum TALER_MerchantConfirmationAlgorithm pos_alg;
+ char *otp_id;
/**
* Contract of the company
@@ -148,8 +143,7 @@ post_templates_run (void *cls,
tis->merchant_url,
tis->template_id,
tis->template_description,
- tis->pos_key,
- tis->pos_alg,
+ tis->otp_id,
tis->template_contract,
&post_templates_cb,
tis);
@@ -181,8 +175,7 @@ post_templates_traits (void *cls,
struct PostTemplatesState *pts = cls;
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_template_description (pts->template_description),
- TALER_TESTING_make_trait_template_pos_key (pts->pos_key),
- TALER_TESTING_make_trait_template_pos_alg (&pts->pos_alg),
+ TALER_TESTING_make_trait_otp_id (pts->otp_id),
TALER_TESTING_make_trait_template_contract (pts->template_contract),
TALER_TESTING_make_trait_template_id (pts->template_id),
TALER_TESTING_trait_end (),
@@ -214,7 +207,7 @@ post_templates_cleanup (void *cls,
"POST /templates operation did not complete\n");
TALER_MERCHANT_templates_post_cancel (tis->iph);
}
- GNUNET_free (tis->pos_key);
+ GNUNET_free (tis->otp_id);
json_decref (tis->template_contract);
GNUNET_free (tis);
}
@@ -226,8 +219,7 @@ TALER_TESTING_cmd_merchant_post_templates2 (
const char *merchant_url,
const char *template_id,
const char *template_description,
- const char *pos_key,
- const enum TALER_MerchantConfirmationAlgorithm pos_alg,
+ const char *otp_id,
json_t *template_contract,
unsigned int http_status)
{
@@ -241,8 +233,7 @@ TALER_TESTING_cmd_merchant_post_templates2 (
tis->template_id = template_id;
tis->http_status = http_status;
tis->template_description = template_description;
- tis->pos_key = (NULL == pos_key) ? NULL : GNUNET_strdup (pos_key);
- tis->pos_alg = pos_alg;
+ tis->otp_id = (NULL == otp_id) ? NULL : GNUNET_strdup (otp_id);
tis->template_contract = template_contract;
{
struct TALER_TESTING_Command cmd = {
@@ -271,7 +262,6 @@ TALER_TESTING_cmd_merchant_post_templates (const char *label,
template_id,
template_description,
NULL,
- TALER_MCA_NONE,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("minimum_age", 0),
GNUNET_JSON_pack_time_rel ("pay_duration",
diff --git a/src/testing/testing_api_cmd_post_using_templates.c b/src/testing/testing_api_cmd_post_using_templates.c
index da45135b..7aeec33d 100644
--- a/src/testing/testing_api_cmd_post_using_templates.c
+++ b/src/testing/testing_api_cmd_post_using_templates.c
@@ -133,14 +133,19 @@ struct PostUsingTemplatesState
const char *duplicate_of;
/**
+ * Label of command creating/updating OTP device, or NULL.
+ */
+ const char *otp_ref;
+
+ /**
* Encoded key for the payment verification.
*/
- const char *template_pos_key;
+ const char *otp_key;
/**
* Option that add amount of the order
*/
- const enum TALER_MerchantConfirmationAlgorithm *template_pos_alg;
+ const enum TALER_MerchantConfirmationAlgorithm *otp_alg;
/**
* Expected HTTP response code.
@@ -358,16 +363,19 @@ post_using_templates_run (void *cls,
TALER_TESTING_get_trait_template_id (ref,
&template_id))
TALER_TESTING_FAIL (is);
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_template_pos_key (ref,
- &tis->template_pos_key))
- TALER_TESTING_FAIL (is);
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_template_pos_alg (ref,
- &tis->template_pos_alg))
- TALER_TESTING_FAIL (is);
+ if (NULL != tis->otp_ref)
+ {
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ tis->otp_ref);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_otp_key (ref,
+ &tis->otp_key))
+ TALER_TESTING_FAIL (is);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_otp_alg (ref,
+ &tis->otp_alg))
+ TALER_TESTING_FAIL (is);
+ }
tis->iph = TALER_MERCHANT_using_templates_post (
TALER_TESTING_interpreter_get_context (is),
tis->merchant_url,
@@ -408,8 +416,8 @@ post_using_templates_traits (void *cls,
TALER_TESTING_make_trait_merchant_pub (&pts->merchant_pub),
TALER_TESTING_make_trait_claim_nonce (&pts->nonce),
TALER_TESTING_make_trait_claim_token (&pts->claim_token),
- TALER_TESTING_make_trait_template_pos_key (pts->template_pos_key),
- TALER_TESTING_make_trait_template_pos_alg (pts->template_pos_alg),
+ TALER_TESTING_make_trait_otp_key (pts->otp_key),
+ TALER_TESTING_make_trait_otp_alg (pts->otp_alg),
TALER_TESTING_trait_end (),
};
@@ -554,6 +562,7 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_using_templates (
const char *label,
const char *template_ref,
+ const char *otp_ref,
const char *merchant_url,
const char *using_template_id,
const char *summary,
@@ -566,6 +575,7 @@ TALER_TESTING_cmd_merchant_post_using_templates (
tis = GNUNET_new (struct PostUsingTemplatesState);
tis->template_ref = template_ref;
+ tis->otp_ref = otp_ref;
tis->merchant_url = merchant_url;
tis->using_template_id = using_template_id;
tis->http_status = http_status;