summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/Makefile.am27
-rw-r--r--src/lib/merchant_api_common.c2
-rw-r--r--src/lib/merchant_api_curl_defaults.c15
-rw-r--r--src/lib/merchant_api_delete_account.c185
-rw-r--r--src/lib/merchant_api_delete_otp_device.c184
-rw-r--r--src/lib/merchant_api_delete_reserve.c239
-rw-r--r--src/lib/merchant_api_delete_template.c4
-rw-r--r--src/lib/merchant_api_get_account.c211
-rw-r--r--src/lib/merchant_api_get_accounts.c247
-rw-r--r--src/lib/merchant_api_get_config.c187
-rw-r--r--src/lib/merchant_api_get_instance.c176
-rw-r--r--src/lib/merchant_api_get_instances.c181
-rw-r--r--src/lib/merchant_api_get_kyc.c188
-rw-r--r--src/lib/merchant_api_get_orders.c233
-rw-r--r--src/lib/merchant_api_get_otp_device.c210
-rw-r--r--src/lib/merchant_api_get_otp_devices.c248
-rw-r--r--src/lib/merchant_api_get_product.c147
-rw-r--r--src/lib/merchant_api_get_products.c153
-rw-r--r--src/lib/merchant_api_get_reserve.c318
-rw-r--r--src/lib/merchant_api_get_reserves.c282
-rw-r--r--src/lib/merchant_api_get_template.c62
-rw-r--r--src/lib/merchant_api_get_templates.c130
-rw-r--r--src/lib/merchant_api_get_tips.c307
-rw-r--r--src/lib/merchant_api_get_tokenfamily.c210
-rw-r--r--src/lib/merchant_api_get_transfers.c72
-rw-r--r--src/lib/merchant_api_get_webhook.c2
-rw-r--r--src/lib/merchant_api_get_webhooks.c129
-rw-r--r--src/lib/merchant_api_merchant_get_order.c335
-rw-r--r--src/lib/merchant_api_merchant_get_tip.c302
-rw-r--r--src/lib/merchant_api_patch_account.c254
-rw-r--r--src/lib/merchant_api_patch_instance.c37
-rw-r--r--src/lib/merchant_api_patch_order_forget.c21
-rw-r--r--src/lib/merchant_api_patch_otp_device.c252
-rw-r--r--src/lib/merchant_api_patch_template.c6
-rw-r--r--src/lib/merchant_api_post_account.c250
-rw-r--r--src/lib/merchant_api_post_instances.c49
-rw-r--r--src/lib/merchant_api_post_order_abort.c120
-rw-r--r--src/lib/merchant_api_post_order_claim.c64
-rw-r--r--src/lib/merchant_api_post_order_paid.c62
-rw-r--r--src/lib/merchant_api_post_order_pay.c314
-rw-r--r--src/lib/merchant_api_post_order_refund.c65
-rw-r--r--src/lib/merchant_api_post_orders.c48
-rw-r--r--src/lib/merchant_api_post_otp_devices.c237
-rw-r--r--src/lib/merchant_api_post_products.c58
-rw-r--r--src/lib/merchant_api_post_reserves.c247
-rw-r--r--src/lib/merchant_api_post_templates.c10
-rw-r--r--src/lib/merchant_api_post_tokenfamilies.c246
-rw-r--r--src/lib/merchant_api_post_transfers.c156
-rw-r--r--src/lib/merchant_api_post_using_templates.c6
-rw-r--r--src/lib/merchant_api_tip_authorize.c376
-rw-r--r--src/lib/merchant_api_tip_pickup.c446
-rw-r--r--src/lib/merchant_api_tip_pickup2.c353
-rw-r--r--src/lib/merchant_api_wallet_get_order.c47
-rw-r--r--src/lib/merchant_api_wallet_get_template.c195
-rw-r--r--src/lib/merchant_api_wallet_get_tip.c227
-rw-r--r--src/lib/merchant_api_wallet_post_order_refund.c287
56 files changed, 4433 insertions, 4986 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 36e249ed..1e7430d4 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -10,29 +10,31 @@ lib_LTLIBRARIES = \
libtalermerchant.la
libtalermerchant_la_LDFLAGS = \
- -version-info 3:0:0 \
+ -version-info 5:2:0 \
-no-undefined
libtalermerchant_la_SOURCES = \
merchant_api_curl_defaults.c merchant_api_curl_defaults.h \
merchant_api_common.c merchant_api_common.h \
+ 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_transfer.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 \
- merchant_api_get_reserves.c \
- merchant_api_get_tips.c \
merchant_api_get_transfers.c \
merchant_api_get_template.c \
merchant_api_get_templates.c \
@@ -40,12 +42,14 @@ libtalermerchant_la_SOURCES = \
merchant_api_get_webhooks.c \
merchant_api_lock_product.c \
merchant_api_merchant_get_order.c \
- merchant_api_merchant_get_tip.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 \
+ merchant_api_post_account.c \
merchant_api_post_instance_auth.c \
merchant_api_post_instances.c \
merchant_api_post_orders.c \
@@ -54,23 +58,22 @@ 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 \
merchant_api_post_templates.c \
+ merchant_api_post_tokenfamilies.c \
merchant_api_post_using_templates.c \
merchant_api_post_webhooks.c \
- merchant_api_tip_authorize.c \
- merchant_api_tip_pickup.c \
- merchant_api_tip_pickup2.c \
- merchant_api_wallet_get_tip.c \
merchant_api_wallet_get_order.c \
+ merchant_api_wallet_get_template.c \
merchant_api_wallet_post_order_refund.c
libtalermerchant_la_LIBADD = \
-ltalerexchange \
-ltalercurl \
-ltalerjson \
+ -ltalerkyclogic \
-ltalerutil \
-lgnunetcurl \
-lgnunetjson \
diff --git a/src/lib/merchant_api_common.c b/src/lib/merchant_api_common.c
index 00e0358d..f5569ce3 100644
--- a/src/lib/merchant_api_common.c
+++ b/src/lib/merchant_api_common.c
@@ -245,7 +245,7 @@ TALER_MERCHANT_parse_pay_uri_free (
}
-int
+enum GNUNET_GenericReturnValue
TALER_MERCHANT_parse_refund_uri (
const char *refund_uri,
struct TALER_MERCHANT_RefundUriData *parse_data)
diff --git a/src/lib/merchant_api_curl_defaults.c b/src/lib/merchant_api_curl_defaults.c
index 34e4aad8..f3c4ee18 100644
--- a/src/lib/merchant_api_curl_defaults.c
+++ b/src/lib/merchant_api_curl_defaults.c
@@ -19,7 +19,8 @@
* @brief curl easy handle defaults
* @author Florian Dold
*/
-
+#include "platform.h"
+#include <taler/taler_curl_lib.h>
#include "merchant_api_curl_defaults.h"
@@ -38,22 +39,14 @@ TALER_MERCHANT_curl_easy_get_ (const char *url)
curl_easy_setopt (eh,
CURLOPT_URL,
url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_FOLLOWLOCATION,
- 1L));
+ TALER_curl_set_secure_redirect_policy (eh,
+ url);
/* Enable compression (using whatever curl likes), see
https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html */
GNUNET_break (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_ACCEPT_ENCODING,
""));
- /* limit MAXREDIRS to 5 as a simple security measure against
- a potential infinite loop caused by a malicious target */
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_MAXREDIRS,
- 5L));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_TCP_FASTOPEN,
diff --git a/src/lib/merchant_api_delete_account.c b/src/lib/merchant_api_delete_account.c
new file mode 100644
index 00000000..42d8bc5d
--- /dev/null
+++ b/src/lib/merchant_api_delete_account.c
@@ -0,0 +1,185 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 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_account.c
+ * @brief Implementation of the DELETE /private/account/$H_WIRE 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 /accounts/$ID operation.
+ */
+struct TALER_MERCHANT_AccountDeleteHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_AccountDeleteCallback 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 DELETE /accounts/$H_WIRE request.
+ *
+ * @param cls the `struct TALER_MERCHANT_AccountDeleteHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_delete_account_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_AccountDeleteHandle *adh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_AccountDeleteResponse adr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
+
+ adh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /accounts/$H_WIRE response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ adr.hr.ec = TALER_JSON_get_error_code (json);
+ adr.hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ break;
+ default:
+ /* unexpected response code */
+ adr.hr.ec = TALER_JSON_get_error_code (json);
+ adr.hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d for DELETE /account/ID\n",
+ (unsigned int) response_code,
+ (int) adr.hr.ec);
+ break;
+ }
+ adh->cb (adh->cb_cls,
+ &adr);
+ TALER_MERCHANT_account_delete_cancel (adh);
+}
+
+
+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)
+{
+ struct TALER_MERCHANT_AccountDeleteHandle *adh;
+
+ adh = GNUNET_new (struct TALER_MERCHANT_AccountDeleteHandle);
+ adh->ctx = ctx;
+ adh->cb = cb;
+ adh->cb_cls = cb_cls;
+ {
+ char h_wire_str[sizeof (*h_wire) * 2];
+ char *path;
+ char *end;
+
+ end = GNUNET_STRINGS_data_to_string (h_wire,
+ sizeof (*h_wire),
+ h_wire_str,
+ sizeof (h_wire_str));
+ *end = '\0';
+ GNUNET_asprintf (&path,
+ "private/account/%s",
+ h_wire_str);
+ adh->url = TALER_url_join (backend_url,
+ path,
+ NULL);
+ GNUNET_free (path);
+ }
+ if (NULL == adh->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (adh);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ adh->url);
+ {
+ CURL *eh;
+
+ eh = TALER_MERCHANT_curl_easy_get_ (adh->url);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_CUSTOMREQUEST,
+ MHD_HTTP_METHOD_DELETE));
+ adh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_delete_account_finished,
+ adh);
+ }
+ return adh;
+}
+
+
+void
+TALER_MERCHANT_account_delete_cancel (
+ struct TALER_MERCHANT_AccountDeleteHandle *adh)
+{
+ if (NULL != adh->job)
+ GNUNET_CURL_job_cancel (adh->job);
+ GNUNET_free (adh->url);
+ GNUNET_free (adh);
+}
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_delete_reserve.c b/src/lib/merchant_api_delete_reserve.c
deleted file mode 100644
index 8062d040..00000000
--- a/src/lib/merchant_api_delete_reserve.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2020 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_reserve.c
- * @brief Implementation of the DELETE /reserves/$RESERVE_PUB request of the merchant's HTTP API
- * @author Jonathan Buchanan
- */
-#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 /reserves/$RESERVE_PUB operation.
- */
-struct TALER_MERCHANT_ReserveDeleteHandle
-{
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_ReserveDeleteCallback 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 DELETE /reserves/$RESERVE_PUB request.
- *
- * @param cls the `struct TALER_MERCHANT_InstanceDeleteHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_delete_reserve_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_ReserveDeleteHandle *rdh = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
-
- rdh->job = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got /reserves/$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;
- 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;
- }
- rdh->cb (rdh->cb_cls,
- &hr);
- TALER_MERCHANT_reserve_delete_cancel (rdh);
-}
-
-
-/**
- * Delete the private key of a reserve.
- *
- * @param ctx the context
- * @param backend_url HTTP base URL for the backend
- * @param reserve_pub which reserve should be deleted
- * @param purge purge instead of just deleting
- * @param cb function to call with the backend's return
- * @param cb_cls closure for @a config_cb
- * @return the instances handle; NULL upon error
- */
-static struct TALER_MERCHANT_ReserveDeleteHandle *
-reserve_delete (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- bool purge,
- TALER_MERCHANT_ReserveDeleteCallback cb,
- void *cb_cls)
-{
- struct TALER_MERCHANT_ReserveDeleteHandle *rdh;
-
- rdh = GNUNET_new (struct TALER_MERCHANT_ReserveDeleteHandle);
- rdh->ctx = ctx;
- rdh->cb = cb;
- rdh->cb_cls = cb_cls;
- {
- char res_str[sizeof (*reserve_pub) * 2];
- char arg_str[sizeof (res_str) + 32];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (reserve_pub,
- sizeof (*reserve_pub),
- res_str,
- sizeof (res_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "private/reserves/%s",
- res_str);
- if (purge)
- rdh->url = TALER_url_join (backend_url,
- arg_str,
- "purge",
- "yes",
- NULL);
- else
- rdh->url = TALER_url_join (backend_url,
- arg_str,
- NULL);
- }
- if (NULL == rdh->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- GNUNET_free (rdh);
- return NULL;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting URL '%s'\n",
- rdh->url);
- {
- CURL *eh;
-
- eh = TALER_MERCHANT_curl_easy_get_ (rdh->url);
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_CUSTOMREQUEST,
- MHD_HTTP_METHOD_DELETE));
- rdh->job = GNUNET_CURL_job_add (ctx,
- eh,
- &handle_delete_reserve_finished,
- rdh);
- }
- return rdh;
-}
-
-
-struct TALER_MERCHANT_ReserveDeleteHandle *
-TALER_MERCHANT_reserve_delete (
- struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- TALER_MERCHANT_ReserveDeleteCallback cb,
- void *cb_cls)
-{
- return reserve_delete (ctx,
- backend_url,
- reserve_pub,
- false,
- cb,
- cb_cls);
-}
-
-
-struct TALER_MERCHANT_ReserveDeleteHandle *
-TALER_MERCHANT_reserve_purge (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- TALER_MERCHANT_ReserveDeleteCallback cb,
- void *cb_cls)
-{
- return reserve_delete (ctx,
- backend_url,
- reserve_pub,
- true,
- cb,
- cb_cls);
-}
-
-
-void
-TALER_MERCHANT_reserve_delete_cancel (
- struct TALER_MERCHANT_ReserveDeleteHandle *rdh)
-{
- if (NULL != rdh->job)
- GNUNET_CURL_job_cancel (rdh->job);
- GNUNET_free (rdh->url);
- GNUNET_free (rdh);
-}
diff --git a/src/lib/merchant_api_delete_template.c b/src/lib/merchant_api_delete_template.c
index 0a5924aa..b2083cc9 100644
--- a/src/lib/merchant_api_delete_template.c
+++ b/src/lib/merchant_api_delete_template.c
@@ -74,8 +74,8 @@ struct TALER_MERCHANT_TemplateDeleteHandle
*/
static void
handle_delete_template_finished (void *cls,
- long response_code,
- const void *response)
+ long response_code,
+ const void *response)
{
struct TALER_MERCHANT_TemplateDeleteHandle *tdh = cls;
const json_t *json = response;
diff --git a/src/lib/merchant_api_get_account.c b/src/lib/merchant_api_get_account.c
new file mode 100644
index 00000000..84595e80
--- /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 (
+ TALER_JSON_spec_web_url ("credit_facade_url",
+ &tgr.details.ok.ad.credit_facade_url),
+ NULL),
+ TALER_JSON_spec_payto_uri ("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..c08cd92d
--- /dev/null
+++ b/src/lib/merchant_api_get_accounts.c
@@ -0,0 +1,247 @@
+/*
+ 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>
+
+/**
+ * Maximum number of accounts permitted.
+ */
+#define MAX_ACCOUNTS 1024
+
+/**
+ * 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 = (unsigned int) json_array_size (ia);
+
+ if ( (json_array_size (ia) != (size_t) tmpl_len) ||
+ (tmpl_len > MAX_ACCOUNTS) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ {
+ 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[] = {
+ TALER_JSON_spec_payto_uri ("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_config.c b/src/lib/merchant_api_get_config.c
index 088434c5..b4b700bd 100644
--- a/src/lib/merchant_api_get_config.c
+++ b/src/lib/merchant_api_get_config.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018, 2020 Taler Systems SA
+ Copyright (C) 2014-2024 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
@@ -34,13 +34,22 @@
* Which version of the Taler protocol is implemented
* by this library? Used to determine compatibility.
*/
-#define MERCHANT_PROTOCOL_CURRENT 3
+#define MERCHANT_PROTOCOL_CURRENT 14
/**
- * How many configs are we backwards compatible with?
+ * How many configs are we backwards-compatible with?
*/
-#define MERCHANT_PROTOCOL_AGE 1
+#define MERCHANT_PROTOCOL_AGE 2
+/**
+ * How many exchanges do we allow at most per merchant?
+ */
+#define MAX_EXCHANGES 1024
+
+/**
+ * How many currency specs do we allow at most per merchant?
+ */
+#define MAX_CURRENCIES 1024
/**
* @brief A handle for /config operations
@@ -90,9 +99,9 @@ handle_config_finished (void *cls,
{
struct TALER_MERCHANT_ConfigGetHandle *vgh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_ConfigResponse cr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -104,78 +113,162 @@ handle_config_finished (void *cls,
{
case MHD_HTTP_OK:
{
- struct TALER_MERCHANT_ConfigInformation vi;
- enum TALER_MERCHANT_VersionCompatibility vc =
- TALER_MERCHANT_VC_PROTOCOL_ERROR;
+ const json_t *jcs;
+ const json_t *exchanges = NULL;
+ struct TALER_MERCHANT_ExchangeConfigInfo *eci = NULL;
+ unsigned int num_eci = 0;
+ unsigned int nspec;
+ struct TALER_JSON_ProtocolVersion pv;
struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_object_const ("currencies",
+ &jcs),
+ /* Optional for v5 compatibility, remove
+ once we reduce age! */
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const ("exchanges",
+ &exchanges),
+ NULL),
GNUNET_JSON_spec_string ("currency",
- &vi.currency),
+ &cr.details.ok.ci.currency),
+ TALER_JSON_spec_version ("version",
+ &pv),
GNUNET_JSON_spec_string ("version",
- &vi.version),
+ &cr.details.ok.ci.version),
GNUNET_JSON_spec_end ()
};
+ cr.details.ok.compat = TALER_MERCHANT_VC_PROTOCOL_ERROR;
if (GNUNET_OK !=
GNUNET_JSON_parse (json,
spec,
NULL, NULL))
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ cr.details.ok.compat = TALER_MERCHANT_VC_MATCH;
+ if (MERCHANT_PROTOCOL_CURRENT < pv.current)
+ {
+ cr.details.ok.compat |= TALER_MERCHANT_VC_NEWER;
+ if (MERCHANT_PROTOCOL_CURRENT < pv.current - pv.age)
+ cr.details.ok.compat |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ }
+ if (MERCHANT_PROTOCOL_CURRENT > pv.current)
+ {
+ cr.details.ok.compat |= TALER_MERCHANT_VC_OLDER;
+ if (MERCHANT_PROTOCOL_CURRENT - MERCHANT_PROTOCOL_AGE > pv.current)
+ cr.details.ok.compat |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ }
+
+ nspec = (unsigned int) json_object_size (jcs);
+ if ( (nspec > MAX_CURRENCIES) ||
+ (json_object_size (jcs) != (size_t) nspec) )
{
- unsigned int age;
- unsigned int revision;
- unsigned int current;
-
- if (3 != sscanf (vi.version,
- "%u:%u:%u",
- &current,
- &revision,
- &age))
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ if (NULL != exchanges)
+ {
+ num_eci = (unsigned int) json_object_size (exchanges);
+ if ( (num_eci > MAX_EXCHANGES) ||
+ (json_object_size (exchanges) != (size_t) num_eci) )
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ eci = GNUNET_new_array (num_eci,
+ struct TALER_MERCHANT_ExchangeConfigInfo);
+ for (unsigned int i = 0; i<num_eci; i++)
{
- vc = TALER_MERCHANT_VC_MATCH;
- if (MERCHANT_PROTOCOL_CURRENT < current)
+ struct TALER_MERCHANT_ExchangeConfigInfo *ei = &eci[i];
+ const json_t *ej = json_array_get (exchanges,
+ i);
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_string ("currency",
+ &ei->currency),
+ GNUNET_JSON_spec_string ("base_url",
+ &ei->base_url),
+ GNUNET_JSON_spec_fixed_auto ("master_pub",
+ &ei->master_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (ej,
+ ispec,
+ NULL, NULL))
{
- vc |= TALER_MERCHANT_VC_NEWER;
- if (MERCHANT_PROTOCOL_CURRENT < current - age)
- vc |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_free (eci);
+ break;
}
- if (MERCHANT_PROTOCOL_CURRENT > current)
+ }
+ }
+ {
+ struct TALER_CurrencySpecification *cspecs;
+ unsigned int off = 0;
+ json_t *obj;
+ const char *curr;
+
+ cspecs = GNUNET_new_array (nspec,
+ struct TALER_CurrencySpecification);
+ cr.details.ok.num_cspecs = nspec;
+ cr.details.ok.cspecs = cspecs;
+ cr.details.ok.num_exchanges = (unsigned int) num_eci;
+ cr.details.ok.exchanges = eci;
+ json_object_foreach ((json_t *) jcs, curr, obj)
+ {
+ struct TALER_CurrencySpecification *cs = &cspecs[off++];
+ struct GNUNET_JSON_Specification cspec[] = {
+ TALER_JSON_spec_currency_specification (curr,
+ curr,
+ cs),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (jcs,
+ cspec,
+ NULL, NULL))
{
- vc |= TALER_MERCHANT_VC_OLDER;
- if (MERCHANT_PROTOCOL_CURRENT - MERCHANT_PROTOCOL_AGE > current)
- vc |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_free (eci);
+ TALER_CONFIG_free_currencies (off - 1,
+ cspecs);
+ break;
}
}
+ vgh->cb (vgh->cb_cls,
+ &cr);
+ GNUNET_free (eci);
+ TALER_CONFIG_free_currencies (nspec,
+ cspecs);
}
- vgh->cb (vgh->cb_cls,
- &hr,
- &vi,
- vc);
TALER_MERCHANT_config_get_cancel (vgh);
return;
}
default:
/* unexpected response code */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ cr.hr.ec = TALER_JSON_get_error_code (json);
+ cr.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);
- vgh->cb (vgh->cb_cls,
- &hr,
- NULL,
- TALER_MERCHANT_VC_PROTOCOL_ERROR);
+ (int) cr.hr.ec);
break;
}
+ vgh->cb (vgh->cb_cls,
+ &cr);
TALER_MERCHANT_config_get_cancel (vgh);
}
diff --git a/src/lib/merchant_api_get_instance.c b/src/lib/merchant_api_get_instance.c
index bb71a1ed..eef95b84 100644
--- a/src/lib/merchant_api_get_instance.c
+++ b/src/lib/merchant_api_get_instance.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018, 2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -28,6 +28,7 @@
#include "taler_merchant_service.h"
#include "merchant_api_curl_defaults.h"
#include <taler/taler_json_lib.h>
+#include <taler/taler_kyclogic_lib.h>
#include <taler/taler_signatures.h>
@@ -79,9 +80,9 @@ handle_get_instance_finished (void *cls,
{
struct TALER_MERCHANT_InstanceGetHandle *igh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_InstanceGetResponse igr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
igh->job = NULL;
@@ -92,135 +93,86 @@ handle_get_instance_finished (void *cls,
{
case MHD_HTTP_OK:
{
- json_t *accounts;
- const char *name;
- struct TALER_MerchantPublicKeyP merchant_pub;
- json_t *address;
- json_t *jurisdiction;
- struct TALER_Amount default_max_wire_fee;
- uint32_t default_wire_fee_amortization;
- struct TALER_Amount default_max_deposit_fee;
- struct GNUNET_TIME_Relative default_wire_transfer_delay;
- struct GNUNET_TIME_Relative default_pay_delay;
+ const char *uts;
+ const json_t *address;
+ const json_t *jurisdiction;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("accounts",
- &accounts),
- GNUNET_JSON_spec_string ("name",
- &name),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub",
- &merchant_pub),
- GNUNET_JSON_spec_json ("address",
- &address),
- GNUNET_JSON_spec_json ("jurisdiction",
- &jurisdiction),
- TALER_JSON_spec_amount_any ("default_max_wire_fee",
- &default_max_wire_fee),
- GNUNET_JSON_spec_uint32 ("default_wire_fee_amortization",
- &default_wire_fee_amortization),
- TALER_JSON_spec_amount_any ("default_max_deposit_fee",
- &default_max_deposit_fee),
- GNUNET_JSON_spec_relative_time ("default_wire_transfer_delay",
- &default_wire_transfer_delay),
- GNUNET_JSON_spec_relative_time ("default_pay_delay",
- &default_pay_delay),
+ GNUNET_JSON_spec_string (
+ "name",
+ &igr.details.ok.details.name),
+ GNUNET_JSON_spec_string (
+ "user_type",
+ &uts),
+ GNUNET_JSON_spec_fixed_auto (
+ "merchant_pub",
+ &igr.details.ok.details.merchant_pub),
+ GNUNET_JSON_spec_object_const (
+ "address",
+ &address),
+ GNUNET_JSON_spec_object_const (
+ "jurisdiction",
+ &jurisdiction),
+ GNUNET_JSON_spec_bool (
+ "use_stefan",
+ &igr.details.ok.details.use_stefan),
+ GNUNET_JSON_spec_relative_time (
+ "default_wire_transfer_delay",
+ &igr.details.ok.details.default_wire_transfer_delay),
+ GNUNET_JSON_spec_relative_time (
+ "default_pay_delay",
+ &igr.details.ok.details.default_pay_delay),
GNUNET_JSON_spec_end ()
};
- if ( (GNUNET_OK ==
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL)) &&
- (json_is_array (accounts)) )
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
{
- unsigned int accounts_length = json_array_size (accounts);
- struct TALER_MERCHANT_Account aa[accounts_length];
- const char *payto_uris[accounts_length];
- size_t index;
- json_t *value;
- int ret = GNUNET_OK;
-
- memset (payto_uris, 0, sizeof (payto_uris));
- json_array_foreach (accounts, index, value)
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("salt",
- &aa[index].salt),
- GNUNET_JSON_spec_string ("payto_uri",
- &payto_uris[index]),
- 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,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- break;
- }
- aa[index].payto_uri = payto_uris[index];
- }
-
- if (GNUNET_OK == ret)
- {
- struct TALER_MERCHANT_InstanceDetails details = {
- .name = name,
- .merchant_pub = &merchant_pub,
- .address = address,
- .jurisdiction = jurisdiction,
- .default_max_wire_fee = &default_max_wire_fee,
- .default_wire_fee_amortization = default_wire_fee_amortization,
- .default_max_deposit_fee = &default_max_deposit_fee,
- .default_wire_transfer_delay = default_wire_transfer_delay,
- .default_pay_delay = default_pay_delay
- };
-
- igh->cb (igh->cb_cls,
- &hr,
- accounts_length,
- aa,
- &details);
- GNUNET_JSON_parse_free (spec);
- 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);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- GNUNET_JSON_parse_free (spec);
- break;
+ igh->cb (igh->cb_cls,
+ &igr);
+ TALER_MERCHANT_instance_get_cancel (igh);
+ return;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ igr.hr.ec = TALER_JSON_get_error_code (json);
+ igr.hr.hint = TALER_JSON_get_error_hint (json);
/* Nothing really to verify, merchant says we need to authenticate. */
break;
case MHD_HTTP_NOT_FOUND:
/* instance does not exist */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ igr.hr.ec = TALER_JSON_get_error_code (json);
+ igr.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);
+ igr.hr.ec = TALER_JSON_get_error_code (json);
+ igr.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);
+ (int) igr.hr.ec);
break;
}
igh->cb (igh->cb_cls,
- &hr,
- 0,
- NULL,
- NULL);
+ &igr);
TALER_MERCHANT_instance_get_cancel (igh);
}
diff --git a/src/lib/merchant_api_get_instances.c b/src/lib/merchant_api_get_instances.c
index 52a462b9..b2f99853 100644
--- a/src/lib/merchant_api_get_instances.c
+++ b/src/lib/merchant_api_get_instances.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018, 2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -32,6 +32,11 @@
/**
+ * Maximum number of instances permitted.
+ */
+#define MAX_INSTANCES 1024
+
+/**
* Handle for a GET /instances operation.
*/
struct TALER_MERCHANT_InstancesGetHandle
@@ -67,79 +72,82 @@ struct TALER_MERCHANT_InstancesGetHandle
/**
* Parse instance information from @a ia.
*
+ * @param json overall reply body
* @param ia JSON array (or NULL!) with instance data
* @param igh operation handle
* @return #GNUNET_OK on success
*/
-static int
-parse_instances (const json_t *ia,
+static enum GNUNET_GenericReturnValue
+parse_instances (const json_t *json,
+ const json_t *ia,
struct TALER_MERCHANT_InstancesGetHandle *igh)
{
- unsigned int iis_len = json_array_size (ia);
- struct TALER_MERCHANT_InstanceInformation iis[iis_len];
- size_t index;
- json_t *value;
- int ret;
+ unsigned int iis_len = (unsigned int) json_array_size (ia);
- ret = GNUNET_OK;
- json_array_foreach (ia, index, value) {
- struct TALER_MERCHANT_InstanceInformation *ii = &iis[index];
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("name",
- &ii->name),
- GNUNET_JSON_spec_string ("id",
- &ii->id),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub",
- &ii->merchant_pub),
- GNUNET_JSON_spec_json ("payment_targets",
- &ii->payment_targets),
- GNUNET_JSON_spec_end ()
+ if ( (json_array_size (ia) != (size_t) iis_len) ||
+ (iis_len > MAX_INSTANCES) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ {
+ struct TALER_MERCHANT_InstanceInformation iis[GNUNET_NZL (iis_len)];
+ size_t index;
+ json_t *value;
+ struct TALER_MERCHANT_InstancesGetResponse igr = {
+ .hr.http_status = MHD_HTTP_OK,
+ .hr.reply = json,
+ .details.ok.iis_length = iis_len,
+ .details.ok.iis = iis
};
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- continue;
- }
- if (! json_is_array (ii->payment_targets))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- break;
- }
- for (unsigned int i = 0; i<json_array_size (ii->payment_targets); i++)
- {
- if (! json_is_string (json_array_get (ii->payment_targets,
- i)))
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_InstanceInformation *ii = &iis[index];
+ const char *uts;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("name",
+ &ii->name),
+ GNUNET_JSON_spec_string ("user_type",
+ &uts),
+ GNUNET_JSON_spec_string ("id",
+ &ii->id),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub",
+ &ii->merchant_pub),
+ GNUNET_JSON_spec_array_const ("payment_targets",
+ &ii->payment_targets),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
{
GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- break;
+ return GNUNET_SYSERR;
}
- }
- if (GNUNET_SYSERR == ret)
- break;
- }
- if (GNUNET_OK == ret)
- {
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK
- };
-
+ if (GNUNET_OK !=
+ TALER_KYCLOGIC_kyc_user_type_from_string (uts,
+ &ii->ut))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ for (size_t i = 0; i<json_array_size (ii->payment_targets); i++)
+ {
+ if (! json_is_string (json_array_get (ii->payment_targets,
+ i)))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ } /* for all instances */
igh->cb (igh->cb_cls,
- &hr,
- iis_len,
- iis);
+ &igr);
igh->cb = NULL; /* just to be sure */
}
- for (unsigned int i = 0; i<iis_len; i++)
- if (NULL != iis[i].payment_targets)
- json_decref (iis[i].payment_targets);
- return ret;
+ return GNUNET_OK;
}
@@ -158,9 +166,9 @@ handle_instances_finished (void *cls,
{
struct TALER_MERCHANT_InstancesGetHandle *igh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_InstancesGetResponse igr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
igh->job = NULL;
@@ -171,10 +179,10 @@ handle_instances_finished (void *cls,
{
case MHD_HTTP_OK:
{
- json_t *instances;
+ const json_t *instances;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("instances",
- &instances),
+ GNUNET_JSON_spec_array_const ("instances",
+ &instances),
GNUNET_JSON_spec_end ()
};
@@ -183,47 +191,38 @@ handle_instances_finished (void *cls,
spec,
NULL, NULL))
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ igr.hr.http_status = 0;
+ igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ if (GNUNET_OK ==
+ parse_instances (json,
+ instances,
+ igh))
{
- if ( (! json_is_array (instances)) ||
- (GNUNET_OK ==
- parse_instances (instances,
- igh)) )
- {
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_instances_get_cancel (igh);
- return;
- }
- else
- {
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
+ TALER_MERCHANT_instances_get_cancel (igh);
+ return;
}
- GNUNET_JSON_parse_free (spec);
+ igr.hr.http_status = 0;
+ igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ igr.hr.ec = TALER_JSON_get_error_code (json);
+ igr.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);
+ igr.hr.ec = TALER_JSON_get_error_code (json);
+ igr.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);
+ (int) igr.hr.ec);
break;
}
igh->cb (igh->cb_cls,
- &hr,
- 0,
- NULL);
+ &igr);
TALER_MERCHANT_instances_get_cancel (igh);
}
diff --git a/src/lib/merchant_api_get_kyc.c b/src/lib/merchant_api_get_kyc.c
index bc688eed..d2a819ea 100644
--- a/src/lib/merchant_api_get_kyc.c
+++ b/src/lib/merchant_api_get_kyc.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2021 Taler Systems SA
+ Copyright (C) 2023 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
@@ -32,6 +32,11 @@
/**
+ * Maximum length of the KYC arrays supported.
+ */
+#define MAX_KYC 1024
+
+/**
* Handle for a GET /kyc operation.
*/
struct TALER_MERCHANT_KycGetHandle
@@ -76,70 +81,91 @@ struct TALER_MERCHANT_KycGetHandle
static enum GNUNET_GenericReturnValue
parse_kyc (struct TALER_MERCHANT_KycGetHandle *kyc,
struct TALER_MERCHANT_KycResponse *kr,
- json_t *pends,
- json_t *touts)
+ const json_t *pends,
+ const json_t *touts)
{
- unsigned int num_pends = json_array_size (pends);
- unsigned int num_touts = json_array_size (touts);
- struct TALER_MERCHANT_AccountKycRedirectDetail pending_kycs[GNUNET_NZL (
- num_pends)];
- struct TALER_MERCHANT_ExchangeKycFailureDetail timeout_kycs[GNUNET_NZL (
- num_touts)];
-
- for (unsigned int i = 0; i<num_pends; i++)
+ unsigned int num_pends = (unsigned int) json_array_size (pends);
+ unsigned int num_touts = (unsigned int) json_array_size (touts);
+
+ if ( (json_array_size (pends) != (size_t) num_pends) ||
+ (num_pends > MAX_KYC) )
{
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("kyc_url",
- &pending_kycs[i].kyc_url),
- GNUNET_JSON_spec_string ("exchange_url",
- &pending_kycs[i].exchange_url),
- GNUNET_JSON_spec_string ("payto_uri",
- &pending_kycs[i].payto_uri),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json_array_get (pends,
- i),
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (json_array_size (touts) != (size_t) num_touts) ||
+ (num_touts > MAX_KYC) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- for (unsigned int i = 0; i<num_touts; i++)
+
{
- uint32_t hs;
- uint32_t ec;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("exchange_url",
- &timeout_kycs[i].exchange_url),
- GNUNET_JSON_spec_uint32 ("exchange_code",
- &ec),
- GNUNET_JSON_spec_uint32 ("exchange_http_status",
- &hs),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json_array_get (touts,
- i),
- spec,
- NULL, NULL))
+ struct TALER_MERCHANT_AccountKycRedirectDetail pending_kycs[
+ GNUNET_NZL (num_pends)];
+ struct TALER_MERCHANT_ExchangeKycFailureDetail timeout_kycs[
+ GNUNET_NZL (num_touts)];
+
+ memset (pending_kycs,
+ 0,
+ sizeof (pending_kycs));
+ for (unsigned int i = 0; i<num_pends; i++)
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_web_url ("kyc_url",
+ &pending_kycs[i].kyc_url),
+ NULL),
+ TALER_JSON_spec_aml_decision ("aml_status",
+ &pending_kycs[i].aml_status),
+ TALER_JSON_spec_web_url ("exchange_url",
+ &pending_kycs[i].exchange_url),
+ TALER_JSON_spec_payto_uri ("payto_uri",
+ &pending_kycs[i].payto_uri),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json_array_get (pends,
+ i),
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ for (unsigned int i = 0; i<num_touts; i++)
{
- GNUNET_break (0);
- return GNUNET_SYSERR;
+ uint32_t hs;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_web_url ("exchange_url",
+ &timeout_kycs[i].exchange_url),
+ TALER_JSON_spec_ec ("exchange_code",
+ &timeout_kycs[i].exchange_code),
+ GNUNET_JSON_spec_uint32 ("exchange_http_status",
+ &hs),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json_array_get (touts,
+ i),
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ timeout_kycs[i].exchange_http_status = (unsigned int) hs;
}
- timeout_kycs[i].exchange_http_status = (unsigned int) hs;
- timeout_kycs[i].exchange_code = (enum TALER_ErrorCode) ec;
+ kr->details.kyc_status.pending_kycs = pending_kycs;
+ kr->details.kyc_status.timeout_kycs = timeout_kycs;
+ kr->details.kyc_status.pending_kycs_length = num_pends;
+ kr->details.kyc_status.timeout_kycs_length = num_touts;
+ kyc->cb (kyc->cb_cls,
+ kr);
}
- kr->details.kyc_status.pending_kycs = pending_kycs;
- kr->details.kyc_status.timeout_kycs = timeout_kycs;
- kr->details.kyc_status.pending_kycs_length = num_pends;
- kr->details.kyc_status.timeout_kycs_length = num_touts;
- kyc->cb (kyc->cb_cls,
- kr);
return GNUNET_OK;
}
@@ -176,13 +202,13 @@ handle_get_kyc_finished (void *cls,
case MHD_HTTP_BAD_GATEWAY:
case MHD_HTTP_GATEWAY_TIMEOUT:
{
- json_t *pends;
- json_t *touts;
+ const json_t *pends;
+ const json_t *touts;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("pending_kycs",
- &pends),
- GNUNET_JSON_spec_json ("timeout_kycs",
- &touts),
+ GNUNET_JSON_spec_array_const ("pending_kycs",
+ &pends),
+ GNUNET_JSON_spec_array_const ("timeout_kycs",
+ &touts),
GNUNET_JSON_spec_end ()
};
@@ -195,20 +221,17 @@ handle_get_kyc_finished (void *cls,
kr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
- if ( (! json_is_array (pends)) ||
- (! json_is_array (touts)) ||
- (GNUNET_OK !=
- parse_kyc (kyc,
- &kr,
- pends,
- touts)) )
+ if (GNUNET_OK !=
+ parse_kyc (kyc,
+ &kr,
+ pends,
+ touts))
{
kr.hr.http_status = 0;
kr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
/* parse_kyc called the continuation already */
- GNUNET_JSON_parse_free (spec);
TALER_MERCHANT_kyc_get_cancel (kyc);
return;
}
@@ -260,17 +283,19 @@ kyc_get (struct GNUNET_CURL_Context *ctx,
struct TALER_MERCHANT_KycGetHandle *kyc;
CURL *eh;
char timeout_ms[32];
+ unsigned int tms;
kyc = GNUNET_new (struct TALER_MERCHANT_KycGetHandle);
kyc->ctx = ctx;
kyc->cb = cb;
kyc->cb_cls = cb_cls;
+ tms = (unsigned int) (timeout.rel_value_us
+ / GNUNET_TIME_UNIT_MILLISECONDS.
+ rel_value_us);
GNUNET_snprintf (timeout_ms,
sizeof (timeout_ms),
- "%llu",
- (unsigned long long) (timeout.rel_value_us
- / GNUNET_TIME_UNIT_MILLISECONDS.
- rel_value_us));
+ "%u",
+ tms);
kyc->url = TALER_url_join (url,
"kyc",
"h_wire",
@@ -298,6 +323,13 @@ kyc_get (struct GNUNET_CURL_Context *ctx,
"Requesting URL '%s'\n",
kyc->url);
eh = TALER_MERCHANT_curl_easy_get_ (kyc->url);
+ if (0 != tms)
+ {
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_TIMEOUT_MS,
+ (long) (tms + 100L)));
+ }
kyc->job = GNUNET_CURL_job_add (ctx,
eh,
&handle_get_kyc_finished,
@@ -321,7 +353,7 @@ TALER_MERCHANT_kyc_get (struct GNUNET_CURL_Context *ctx,
"%sprivate/",
backend_url);
return kyc_get (ctx,
- url,
+ url, /* consumed! */
h_wire,
exchange_url,
timeout,
@@ -347,7 +379,7 @@ TALER_MERCHANT_management_kyc_get (struct GNUNET_CURL_Context *ctx,
backend_url,
instance_id);
return kyc_get (ctx,
- url,
+ url, /* consumed! */
h_wire,
exchange_url,
timeout,
diff --git a/src/lib/merchant_api_get_orders.c b/src/lib/merchant_api_get_orders.c
index 7f08acb6..459409fd 100644
--- a/src/lib/merchant_api_get_orders.c
+++ b/src/lib/merchant_api_get_orders.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018, 2020, 2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -30,6 +30,10 @@
#include <taler/taler_json_lib.h>
#include <taler/taler_signatures.h>
+/**
+ * Maximum number of orders we return.
+ */
+#define MAX_ORDERS 1024
/**
* Handle for a GET /orders operation.
@@ -68,65 +72,64 @@ struct TALER_MERCHANT_OrdersGetHandle
* Parse order information from @a ia.
*
* @param ia JSON array (or NULL!) with order data
+ * @param[in] ogr response to fill
* @param ogh operation handle
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
parse_orders (const json_t *ia,
+ struct TALER_MERCHANT_OrdersGetResponse *ogr,
struct TALER_MERCHANT_OrdersGetHandle *ogh)
{
- unsigned int oes_len = json_array_size (ia);
- struct TALER_MERCHANT_OrderEntry oes[oes_len];
- size_t index;
- json_t *value;
- int ret;
-
- ret = GNUNET_OK;
- json_array_foreach (ia, index, value) {
- struct TALER_MERCHANT_OrderEntry *ie = &oes[index];
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("order_id",
- &ie->order_id),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &ie->timestamp),
- GNUNET_JSON_spec_uint64 ("row_id",
- &ie->order_serial),
- TALER_JSON_spec_amount_any ("amount",
- &ie->amount),
- GNUNET_JSON_spec_string ("summary",
- &ie->summary),
- GNUNET_JSON_spec_bool ("refundable",
- &ie->refundable),
- GNUNET_JSON_spec_bool ("paid",
- &ie->paid),
- GNUNET_JSON_spec_end ()
- };
+ unsigned int oes_len = (unsigned int) json_array_size (ia);
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- continue;
- }
- if (GNUNET_SYSERR == ret)
- break;
+ if ( (json_array_size (ia) != (size_t) oes_len) ||
+ (oes_len > MAX_ORDERS) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- if (GNUNET_OK == ret)
{
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK
- };
+ struct TALER_MERCHANT_OrderEntry oes[GNUNET_NZL (oes_len)];
+ size_t index;
+ json_t *value;
+
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_OrderEntry *ie = &oes[index];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("order_id",
+ &ie->order_id),
+ GNUNET_JSON_spec_timestamp ("timestamp",
+ &ie->timestamp),
+ GNUNET_JSON_spec_uint64 ("row_id",
+ &ie->order_serial),
+ TALER_JSON_spec_amount_any ("amount",
+ &ie->amount),
+ GNUNET_JSON_spec_string ("summary",
+ &ie->summary),
+ GNUNET_JSON_spec_bool ("refundable",
+ &ie->refundable),
+ GNUNET_JSON_spec_bool ("paid",
+ &ie->paid),
+ GNUNET_JSON_spec_end ()
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ ogr->details.ok.orders_length = oes_len;
+ ogr->details.ok.orders = oes;
ogh->cb (ogh->cb_cls,
- &hr,
- oes_len,
- oes);
+ ogr);
ogh->cb = NULL; /* just to be sure */
}
- return ret;
+ return GNUNET_OK;
}
@@ -145,9 +148,9 @@ handle_get_orders_finished (void *cls,
{
struct TALER_MERCHANT_OrdersGetHandle *ogh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_OrdersGetResponse ogr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
ogh->job = NULL;
@@ -158,10 +161,10 @@ handle_get_orders_finished (void *cls,
{
case MHD_HTTP_OK:
{
- json_t *orders;
+ const json_t *orders;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("orders",
- &orders),
+ GNUNET_JSON_spec_array_const ("orders",
+ &orders),
GNUNET_JSON_spec_end ()
};
@@ -170,52 +173,43 @@ handle_get_orders_finished (void *cls,
spec,
NULL, NULL))
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ ogr.hr.http_status = 0;
+ ogr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ if (GNUNET_OK ==
+ parse_orders (orders,
+ &ogr,
+ ogh))
{
- if ( (! json_is_array (orders)) ||
- (GNUNET_OK ==
- parse_orders (orders,
- ogh)) )
- {
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_orders_get_cancel (ogh);
- return;
- }
- else
- {
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
+ TALER_MERCHANT_orders_get_cancel (ogh);
+ return;
}
- GNUNET_JSON_parse_free (spec);
+ ogr.hr.http_status = 0;
+ ogr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ogr.hr.ec = TALER_JSON_get_error_code (json);
+ ogr.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);
+ ogr.hr.ec = TALER_JSON_get_error_code (json);
+ ogr.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);
+ ogr.hr.ec = TALER_JSON_get_error_code (json);
+ ogr.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);
+ (int) ogr.hr.ec);
break;
}
ogh->cb (ogh->cb_cls,
- &hr,
- 0,
- NULL);
+ &ogr);
TALER_MERCHANT_orders_get_cancel (ogh);
}
@@ -255,12 +249,51 @@ TALER_MERCHANT_orders_get2 (
TALER_MERCHANT_OrdersGetCallback cb,
void *cb_cls)
{
+ return TALER_MERCHANT_orders_get3 (
+ ctx,
+ backend_url,
+ paid,
+ refunded,
+ wired,
+ NULL,
+ NULL,
+ date,
+ start_row,
+ delta,
+ timeout,
+ cb,
+ cb_cls);
+}
+
+
+struct TALER_MERCHANT_OrdersGetHandle *
+TALER_MERCHANT_orders_get3 (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ enum TALER_EXCHANGE_YesNoAll paid,
+ enum TALER_EXCHANGE_YesNoAll refunded,
+ enum TALER_EXCHANGE_YesNoAll wired,
+ const char *session_id,
+ const char *fulfillment_url,
+ struct GNUNET_TIME_Timestamp date,
+ uint64_t start_row,
+ int64_t delta,
+ struct GNUNET_TIME_Relative timeout,
+ TALER_MERCHANT_OrdersGetCallback cb,
+ void *cb_cls)
+{
struct TALER_MERCHANT_OrdersGetHandle *ogh;
CURL *eh;
- unsigned int timeout_ms = timeout.rel_value_us
- / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
+ unsigned int tms = timeout.rel_value_us
+ / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
GNUNET_assert (NULL != backend_url);
+ if ( (delta > MAX_ORDERS) ||
+ (delta < -MAX_ORDERS) )
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
if (0 == delta)
{
GNUNET_break (0);
@@ -274,6 +307,8 @@ TALER_MERCHANT_orders_get2 (
/* build ogh->url with the various optional arguments */
{
char *dstr;
+ char *fec = NULL;
+ char *sid = NULL;
bool have_date;
bool have_srow;
char cbuf[30];
@@ -282,8 +317,8 @@ TALER_MERCHANT_orders_get2 (
GNUNET_snprintf (tbuf,
sizeof (tbuf),
- "%llu",
- (unsigned long long) timeout_ms);
+ "%u",
+ tms);
GNUNET_snprintf (dbuf,
sizeof (dbuf),
"%lld",
@@ -292,6 +327,14 @@ TALER_MERCHANT_orders_get2 (
sizeof (cbuf),
"%llu",
(unsigned long long) start_row);
+ if (NULL != session_id)
+ (void) GNUNET_STRINGS_urlencode (strlen (session_id),
+ session_id,
+ &sid);
+ if (NULL != fulfillment_url)
+ (void) GNUNET_STRINGS_urlencode (strlen (fulfillment_url),
+ fulfillment_url,
+ &fec);
dstr = GNUNET_strdup (GNUNET_TIME_timestamp2s (date));
if (delta > 0)
{
@@ -330,11 +373,17 @@ TALER_MERCHANT_orders_get2 (
? dbuf
: NULL,
"timeout_ms",
- (0 != timeout_ms)
+ (0 != tms)
? tbuf
: NULL,
+ "session_id",
+ sid,
+ "fulfillment_url",
+ fec,
NULL);
GNUNET_free (dstr);
+ GNUNET_free (sid);
+ GNUNET_free (fec);
}
if (NULL == ogh->url)
{
@@ -347,6 +396,20 @@ TALER_MERCHANT_orders_get2 (
"Requesting URL '%s'\n",
ogh->url);
eh = TALER_MERCHANT_curl_easy_get_ (ogh->url);
+ if (NULL == eh)
+ {
+ GNUNET_break (0);
+ GNUNET_free (ogh->url);
+ GNUNET_free (ogh);
+ return NULL;
+ }
+ if (0 != tms)
+ {
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_TIMEOUT_MS,
+ (long) (tms + 100L)));
+ }
ogh->job = GNUNET_CURL_job_add (ctx,
eh,
&handle_get_orders_finished,
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..65950af8
--- /dev/null
+++ b/src/lib/merchant_api_get_otp_device.c
@@ -0,0 +1,210 @@
+/*
+ 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_mark_optional (
+ GNUNET_JSON_spec_uint64 ("otp_ctr",
+ &tgr.details.ok.otp_ctr),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("otp_timestamp",
+ &tgr.details.ok.otp_timestamp_s),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("otp_code",
+ &tgr.details.ok.otp_code),
+ 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..4737944c
--- /dev/null
+++ b/src/lib/merchant_api_get_otp_devices.c
@@ -0,0 +1,248 @@
+/*
+ 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>
+
+/**
+ * Maximum number of OTP devices we return.
+ */
+#define MAX_OTP 1024
+
+
+/**
+ * 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 otp_len = (unsigned int) json_array_size (ia);
+
+ if ( (json_array_size (ia) != (size_t) otp_len) ||
+ (otp_len > MAX_OTP) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ {
+ struct TALER_MERCHANT_OtpDeviceEntry otp[GNUNET_NZL (otp_len)];
+ size_t index;
+ json_t *value;
+
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_OtpDeviceEntry *ie = &otp[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 = otp_len;
+ tgr->details.ok.otp_devices = otp;
+ 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_product.c b/src/lib/merchant_api_get_product.c
index 94d38ec7..3f026bf3 100644
--- a/src/lib/merchant_api_get_product.c
+++ b/src/lib/merchant_api_get_product.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018, 2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -79,9 +79,9 @@ handle_get_product_finished (void *cls,
{
struct TALER_MERCHANT_ProductGetHandle *pgh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_ProductGetResponse pgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
pgh->job = NULL;
@@ -92,121 +92,80 @@ handle_get_product_finished (void *cls,
{
case MHD_HTTP_OK:
{
- const char *description;
- json_t *description_i18n;
- const char *unit;
- struct TALER_Amount price;
- const char *image;
- json_t *taxes;
- int64_t total_stock;
- uint64_t total_sold;
- uint64_t total_lost;
- json_t *address;
- bool rst_ok = true;
- struct GNUNET_TIME_Timestamp next_restock
- = GNUNET_TIME_UNIT_ZERO_TS;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("description",
- &description),
- GNUNET_JSON_spec_json ("description_i18n",
- &description_i18n),
- GNUNET_JSON_spec_string ("unit",
- &unit),
- TALER_JSON_spec_amount_any ("price",
- &price),
- GNUNET_JSON_spec_string ("image",
- &image),
- GNUNET_JSON_spec_json ("taxes",
- &taxes),
- GNUNET_JSON_spec_int64 ("total_stock",
- &total_stock),
- GNUNET_JSON_spec_uint64 ("total_sold",
- &total_sold),
- GNUNET_JSON_spec_uint64 ("total_lost",
- &total_lost),
- GNUNET_JSON_spec_json ("address",
- &address),
+ GNUNET_JSON_spec_string (
+ "description",
+ &pgr.details.ok.description),
+ GNUNET_JSON_spec_object_const (
+ "description_i18n",
+ &pgr.details.ok.description_i18n),
+ GNUNET_JSON_spec_string (
+ "unit",
+ &pgr.details.ok.unit),
+ TALER_JSON_spec_amount_any (
+ "price",
+ &pgr.details.ok.price),
+ GNUNET_JSON_spec_string (
+ "image",
+ &pgr.details.ok.image),
+ GNUNET_JSON_spec_array_const (
+ "taxes",
+ &pgr.details.ok.taxes),
+ GNUNET_JSON_spec_int64 (
+ "total_stock",
+ &pgr.details.ok.total_stock),
+ GNUNET_JSON_spec_uint64 (
+ "total_sold",
+ &pgr.details.ok.total_sold),
+ GNUNET_JSON_spec_uint64 (
+ "total_lost",
+ &pgr.details.ok.total_lost),
+ GNUNET_JSON_spec_object_const (
+ "address",
+ &pgr.details.ok.location),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_timestamp ("next_restock",
+ &pgr.details.ok.next_restock),
+ NULL),
GNUNET_JSON_spec_end ()
};
- if (NULL !=
- json_object_get (json,
- "next_restock"))
- {
- struct GNUNET_JSON_Specification spect[] = {
- GNUNET_JSON_spec_timestamp ("next_restock",
- &next_restock),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spect,
- NULL, NULL))
- rst_ok = false;
- }
-
-
- if ( (rst_ok) &&
- (GNUNET_OK ==
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL)) )
+ if (GNUNET_OK ==
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
{
pgh->cb (pgh->cb_cls,
- &hr,
- description,
- description_i18n,
- unit,
- &price,
- image,
- taxes,
- total_stock,
- total_sold,
- total_lost,
- address,
- next_restock);
+ &pgr);
GNUNET_JSON_parse_free (spec);
TALER_MERCHANT_product_get_cancel (pgh);
return;
}
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- GNUNET_JSON_parse_free (spec);
+ pgr.hr.http_status = 0;
+ pgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ pgr.hr.ec = TALER_JSON_get_error_code (json);
+ pgr.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);
+ pgr.hr.ec = TALER_JSON_get_error_code (json);
+ pgr.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);
+ pgr.hr.ec = TALER_JSON_get_error_code (json);
+ pgr.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);
+ (int) pgr.hr.ec);
break;
}
pgh->cb (pgh->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- 0,
- 0,
- NULL,
- GNUNET_TIME_UNIT_FOREVER_TS);
+ &pgr);
TALER_MERCHANT_product_get_cancel (pgh);
}
diff --git a/src/lib/merchant_api_get_products.c b/src/lib/merchant_api_get_products.c
index c3cc30e7..c33e24c9 100644
--- a/src/lib/merchant_api_get_products.c
+++ b/src/lib/merchant_api_get_products.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018, 2020 Taler Systems SA
+ Copyright (C) 2014-2024 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
@@ -32,6 +32,12 @@
/**
+ * Maximum number of products we return.
+ */
+#define MAX_PRODUCTS 1024
+
+
+/**
* Handle for a GET /products operation.
*/
struct TALER_MERCHANT_ProductsGetHandle
@@ -67,54 +73,68 @@ struct TALER_MERCHANT_ProductsGetHandle
/**
* Parse product information from @a ia.
*
+ * @param json overall JSON reply
* @param ia JSON array (or NULL!) with product data
* @param pgh operation handle
* @return #GNUNET_OK on success
*/
-static int
-parse_products (const json_t *ia,
+static enum GNUNET_GenericReturnValue
+parse_products (const json_t *json,
+ const json_t *ia,
struct TALER_MERCHANT_ProductsGetHandle *pgh)
{
unsigned int ies_len = json_array_size (ia);
- struct TALER_MERCHANT_InventoryEntry ies[ies_len];
- size_t index;
- json_t *value;
- int ret;
-
- ret = GNUNET_OK;
- json_array_foreach (ia, index, value) {
- struct TALER_MERCHANT_InventoryEntry *ie = &ies[index];
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("product_id",
- &ie->product_id),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- continue;
- }
- if (GNUNET_SYSERR == ret)
- break;
+
+ if ( (json_array_size (ia) != (size_t) ies_len) ||
+ (ies_len > MAX_PRODUCTS) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- if (GNUNET_OK == ret)
{
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK
- };
-
- pgh->cb (pgh->cb_cls,
- &hr,
- ies_len,
- ies);
- pgh->cb = NULL; /* just to be sure */
+ struct TALER_MERCHANT_InventoryEntry ies[GNUNET_NZL (ies_len)];
+ size_t index;
+ json_t *value;
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = GNUNET_OK;
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_InventoryEntry *ie = &ies[index];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("product_id",
+ &ie->product_id),
+ GNUNET_JSON_spec_uint64 ("product_serial",
+ &ie->product_serial),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ ret = GNUNET_SYSERR;
+ continue;
+ }
+ if (GNUNET_SYSERR == ret)
+ break;
+ }
+ if (GNUNET_OK == ret)
+ {
+ struct TALER_MERCHANT_GetProductsResponse gpr = {
+ .hr.http_status = MHD_HTTP_OK,
+ .hr.reply = json,
+ .details.ok.products_length = ies_len,
+ .details.ok.products = ies
+ };
+
+ pgh->cb (pgh->cb_cls,
+ &gpr);
+ pgh->cb = NULL; /* just to be sure */
+ }
+ return ret;
}
- return ret;
}
@@ -133,9 +153,9 @@ handle_get_products_finished (void *cls,
{
struct TALER_MERCHANT_ProductsGetHandle *pgh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_GetProductsResponse gpr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
pgh->job = NULL;
@@ -146,10 +166,10 @@ handle_get_products_finished (void *cls,
{
case MHD_HTTP_OK:
{
- json_t *products;
+ const json_t *products;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("products",
- &products),
+ GNUNET_JSON_spec_array_const ("products",
+ &products),
GNUNET_JSON_spec_end ()
};
@@ -158,48 +178,39 @@ handle_get_products_finished (void *cls,
spec,
NULL, NULL))
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ gpr.hr.http_status = 0;
+ gpr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ if (GNUNET_OK ==
+ parse_products (json,
+ products,
+ pgh))
{
- if ( (! json_is_array (products)) ||
- (GNUNET_OK ==
- parse_products (products,
- pgh)) )
- {
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_products_get_cancel (pgh);
- return;
- }
- else
- {
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
+ TALER_MERCHANT_products_get_cancel (pgh);
+ return;
}
- GNUNET_JSON_parse_free (spec);
+ gpr.hr.http_status = 0;
+ gpr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ gpr.hr.ec = TALER_JSON_get_error_code (json);
+ gpr.hr.hint = TALER_JSON_get_error_hint (json);
/* Nothing really to verify, merchant says we need to authenticate. */
break;
default:
/* unexpected response code */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ gpr.hr.ec = TALER_JSON_get_error_code (json);
+ gpr.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);
+ (int) gpr.hr.ec);
break;
}
pgh->cb (pgh->cb_cls,
- &hr,
- 0,
- NULL);
+ &gpr);
TALER_MERCHANT_products_get_cancel (pgh);
}
diff --git a/src/lib/merchant_api_get_reserve.c b/src/lib/merchant_api_get_reserve.c
deleted file mode 100644
index 6c970db8..00000000
--- a/src/lib/merchant_api_get_reserve.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2021 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_reserve.c
- * @brief Implementation of the GET /reserve request of the merchant's HTTP API
- * @author Marcello Stanisci
- * @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_common.h"
-#include "merchant_api_curl_defaults.h"
-#include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-
-
-/**
- * @brief A Handle for tracking wire reserve.
- */
-struct TALER_MERCHANT_ReserveGetHandle
-{
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_ReserveGetCallback 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 /reserve request.
- *
- * @param cls the `struct TALER_MERCHANT_ReserveGetHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_reserve_get_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_ReserveGetHandle *rgh = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
- bool active;
-
- rgh->job = NULL;
- switch (response_code)
- {
- case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- case MHD_HTTP_OK:
- {
- struct TALER_MERCHANT_ReserveSummary rs;
- const json_t *tips;
- const char *exchange_url = NULL;
- const char *payto_uri = NULL;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_timestamp ("creation_time",
- &rs.creation_time),
- GNUNET_JSON_spec_timestamp ("expiration_time",
- &rs.expiration_time),
- GNUNET_JSON_spec_bool ("active",
- &active),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("exchange_url",
- &exchange_url),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("payto_uri",
- &payto_uri),
- NULL),
- TALER_JSON_spec_amount_any ("merchant_initial_amount",
- &rs.merchant_initial_amount),
- TALER_JSON_spec_amount_any ("exchange_initial_amount",
- &rs.exchange_initial_amount),
- TALER_JSON_spec_amount_any ("pickup_amount",
- &rs.pickup_amount),
- TALER_JSON_spec_amount_any ("committed_amount",
- &rs.committed_amount),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
-
- tips = json_object_get (json,
- "tips");
- if ((NULL == tips) ||
- json_is_null (tips))
- {
- rgh->cb (rgh->cb_cls,
- &hr,
- &rs,
- false,
- NULL,
- NULL,
- 0,
- NULL);
- TALER_MERCHANT_reserve_get_cancel (rgh);
- return;
- }
- if (! json_is_array (tips))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- {
- size_t tds_length;
- json_t *tip;
- struct TALER_MERCHANT_TipDetails *tds;
- unsigned int i;
- bool ok;
-
- tds_length = json_array_size (tips);
- tds = GNUNET_new_array (tds_length,
- struct TALER_MERCHANT_TipDetails);
- ok = true;
- json_array_foreach (tips, i, tip) {
- struct TALER_MERCHANT_TipDetails *td = &tds[i];
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_fixed_auto ("tip_id",
- &td->tip_id),
- TALER_JSON_spec_amount_any ("total_amount",
- &td->amount),
- GNUNET_JSON_spec_string ("reason",
- &td->reason),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (tip,
- ispec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ok = false;
- break;
- }
- }
-
- if (! ok)
- {
- GNUNET_break_op (0);
- GNUNET_free (tds);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- rgh->cb (rgh->cb_cls,
- &hr,
- &rs,
- active,
- exchange_url,
- payto_uri,
- tds_length,
- tds);
- GNUNET_free (tds);
- TALER_MERCHANT_reserve_get_cancel (rgh);
- return;
- }
- }
- 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_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) hr.ec);
- response_code = 0;
- break;
- }
- rgh->cb (rgh->cb_cls,
- &hr,
- NULL,
- false,
- NULL,
- NULL,
- 0,
- NULL);
- TALER_MERCHANT_reserve_get_cancel (rgh);
-}
-
-
-struct TALER_MERCHANT_ReserveGetHandle *
-TALER_MERCHANT_reserve_get (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- bool fetch_tips,
- TALER_MERCHANT_ReserveGetCallback cb,
- void *cb_cls)
-{
- struct TALER_MERCHANT_ReserveGetHandle *rgh;
- CURL *eh;
-
- rgh = GNUNET_new (struct TALER_MERCHANT_ReserveGetHandle);
- rgh->ctx = ctx;
- rgh->cb = cb;
- rgh->cb_cls = cb_cls;
- {
- char res_str[sizeof (*reserve_pub) * 2];
- char arg_str[sizeof (res_str) + 32];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (reserve_pub,
- sizeof (*reserve_pub),
- res_str,
- sizeof (res_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "private/reserves/%s",
- res_str);
- rgh->url = TALER_url_join (backend_url,
- arg_str,
- "tips",
- fetch_tips ? "yes" : "no",
- NULL);
- }
- if (NULL == rgh->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- GNUNET_free (rgh);
- return NULL;
- }
- eh = TALER_MERCHANT_curl_easy_get_ (rgh->url);
- rgh->job = GNUNET_CURL_job_add (ctx,
- eh,
- &handle_reserve_get_finished,
- rgh);
- return rgh;
-}
-
-
-void
-TALER_MERCHANT_reserve_get_cancel (
- struct TALER_MERCHANT_ReserveGetHandle *rgh)
-{
- if (NULL != rgh->job)
- {
- GNUNET_CURL_job_cancel (rgh->job);
- rgh->job = NULL;
- }
- GNUNET_free (rgh->url);
- GNUNET_free (rgh);
-}
-
-
-/* end of merchant_api_get_reserve.c */
diff --git a/src/lib/merchant_api_get_reserves.c b/src/lib/merchant_api_get_reserves.c
deleted file mode 100644
index 9b3b45e9..00000000
--- a/src/lib/merchant_api_get_reserves.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2017, 2020 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_reserves.c
- * @brief Implementation of the GET /reserves request of the merchant's HTTP API
- * @author Marcello Stanisci
- * @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_common.h"
-#include "merchant_api_curl_defaults.h"
-#include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-
-
-/**
- * @brief A Handle for tracking wire reserves.
- */
-struct TALER_MERCHANT_ReservesGetHandle
-{
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_ReservesGetCallback 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 /reserves request.
- *
- * @param cls the `struct TALER_MERCHANT_ReservesGetHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_reserves_get_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_ReservesGetHandle *rgh = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
-
- rgh->job = NULL;
- switch (response_code)
- {
- case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- case MHD_HTTP_OK:
- {
- json_t *reserves;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("reserves",
- &reserves),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- else
- {
- size_t rds_length;
- struct TALER_MERCHANT_ReserveSummary *rds;
- json_t *reserve;
- unsigned int i;
- bool ok;
-
- if (! json_is_array (reserves))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- rds_length = json_array_size (reserves);
- rds = GNUNET_new_array (rds_length,
- struct TALER_MERCHANT_ReserveSummary);
- ok = true;
- json_array_foreach (reserves, i, reserve) {
- struct TALER_MERCHANT_ReserveSummary *rd = &rds[i];
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_fixed_auto ("reserve_pub",
- &rd->reserve_pub),
- GNUNET_JSON_spec_timestamp ("creation_time",
- &rd->creation_time),
- GNUNET_JSON_spec_timestamp ("expiration_time",
- &rd->expiration_time),
- TALER_JSON_spec_amount_any ("merchant_initial_amount",
- &rd->merchant_initial_amount),
- TALER_JSON_spec_amount_any ("exchange_initial_amount",
- &rd->exchange_initial_amount),
- TALER_JSON_spec_amount_any ("pickup_amount",
- &rd->pickup_amount),
- TALER_JSON_spec_amount_any ("committed_amount",
- &rd->committed_amount),
- GNUNET_JSON_spec_bool ("active",
- &rd->active),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (reserve,
- ispec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ok = false;
- break;
- }
- }
-
- if (! ok)
- {
- GNUNET_break_op (0);
- GNUNET_free (rds);
- GNUNET_JSON_parse_free (spec);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- rgh->cb (rgh->cb_cls,
- &hr,
- rds_length,
- rds);
- GNUNET_free (rds);
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_reserves_get_cancel (rgh);
- return;
- }
- }
- 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_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) hr.ec);
- response_code = 0;
- break;
- }
- rgh->cb (rgh->cb_cls,
- &hr,
- 0,
- NULL);
- TALER_MERCHANT_reserves_get_cancel (rgh);
-}
-
-
-struct TALER_MERCHANT_ReservesGetHandle *
-TALER_MERCHANT_reserves_get (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- struct GNUNET_TIME_Timestamp after,
- enum TALER_EXCHANGE_YesNoAll active,
- enum TALER_EXCHANGE_YesNoAll failures,
- TALER_MERCHANT_ReservesGetCallback cb,
- void *cb_cls)
-{
- struct TALER_MERCHANT_ReservesGetHandle *rgh;
- CURL *eh;
- const char *active_s = NULL;
- const char *failures_s = NULL;
- char *after_s;
-
- rgh = GNUNET_new (struct TALER_MERCHANT_ReservesGetHandle);
- rgh->ctx = ctx;
- rgh->cb = cb;
- rgh->cb_cls = cb_cls;
- active_s = TALER_yna_to_string (active);
- failures_s = TALER_yna_to_string (failures);
- after_s = GNUNET_strdup (GNUNET_TIME_timestamp2s (after));
- rgh->url = TALER_url_join (backend_url,
- "private/reserves",
- "active",
- active_s,
- "failures",
- failures_s,
- "after",
- GNUNET_TIME_absolute_is_zero (after.abs_time)
- ? NULL
- : after_s,
- NULL);
- GNUNET_free (after_s);
- if (NULL == rgh->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- GNUNET_free (rgh);
- return NULL;
- }
- eh = TALER_MERCHANT_curl_easy_get_ (rgh->url);
- rgh->job = GNUNET_CURL_job_add (ctx,
- eh,
- &handle_reserves_get_finished,
- rgh);
- return rgh;
-}
-
-
-void
-TALER_MERCHANT_reserves_get_cancel (
- struct TALER_MERCHANT_ReservesGetHandle *rgh)
-{
- if (NULL != rgh->job)
- {
- GNUNET_CURL_job_cancel (rgh->job);
- rgh->job = NULL;
- }
- GNUNET_free (rgh->url);
- GNUNET_free (rgh);
-}
-
-
-/* end of merchant_api_get_reserves.c */
diff --git a/src/lib/merchant_api_get_template.c b/src/lib/merchant_api_get_template.c
index 920333b6..9bbcc93a 100644
--- a/src/lib/merchant_api_get_template.c
+++ b/src/lib/merchant_api_get_template.c
@@ -79,9 +79,9 @@ handle_get_template_finished (void *cls,
{
struct TALER_MERCHANT_TemplateGetHandle *tgh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_TemplateGetResponse tgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
tgh->job = NULL;
@@ -92,67 +92,55 @@ handle_get_template_finished (void *cls,
{
case MHD_HTTP_OK:
{
- const char *template_description;
- const char *image;
- json_t *template_contract;
- bool rst_ok = true;
+ const json_t *contract;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("template_description",
- &template_description),
+ &tgr.details.ok.template_description),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("image",
- &image),
+ GNUNET_JSON_spec_string ("otp_id",
+ &tgr.details.ok.otp_id),
NULL),
- GNUNET_JSON_spec_json ("template_contract",
- &template_contract),
+ GNUNET_JSON_spec_object_const ("template_contract",
+ &contract),
GNUNET_JSON_spec_end ()
};
-
- if ( (rst_ok) &&
- (GNUNET_OK ==
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL)) )
+ if (GNUNET_OK ==
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
{
+ tgr.details.ok.template_contract = contract;
tgh->cb (tgh->cb_cls,
- &hr,
- template_description,
- image,
- template_contract);
- GNUNET_JSON_parse_free (spec);
+ &tgr);
TALER_MERCHANT_template_get_cancel (tgh);
return;
}
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- GNUNET_JSON_parse_free (spec);
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ 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:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ tgr.hr.ec = TALER_JSON_get_error_code (json);
+ tgr.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);
+ 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) hr.ec);
+ (int) tgr.hr.ec);
break;
}
tgh->cb (tgh->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL);
+ &tgr);
TALER_MERCHANT_template_get_cancel (tgh);
}
diff --git a/src/lib/merchant_api_get_templates.c b/src/lib/merchant_api_get_templates.c
index 030d80cb..f1f973b5 100644
--- a/src/lib/merchant_api_get_templates.c
+++ b/src/lib/merchant_api_get_templates.c
@@ -32,6 +32,12 @@
/**
+ * Maximum number of templates we return.
+ */
+#define MAX_TEMPLATES 1024
+
+
+/**
* Handle for a GET /templates operation.
*/
struct TALER_MERCHANT_TemplatesGetHandle
@@ -68,53 +74,52 @@ struct TALER_MERCHANT_TemplatesGetHandle
* Parse template information from @a ia.
*
* @param ia JSON array (or NULL!) with template data
+ * @param[in] tgr partially filled response
* @param tgh operation handle
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_templates (const json_t *ia,
+ struct TALER_MERCHANT_TemplatesGetResponse *tgr,
struct TALER_MERCHANT_TemplatesGetHandle *tgh)
{
- unsigned int ies_len = json_array_size (ia);
- struct TALER_MERCHANT_TemplateEntry ies[ies_len];
- size_t index;
- json_t *value;
- int ret;
-
- ret = GNUNET_OK;
- json_array_foreach (ia, index, value) {
- struct TALER_MERCHANT_TemplateEntry *ie = &ies[index];
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("template_id",
- &ie->template_id),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- continue;
- }
- if (GNUNET_SYSERR == ret)
- break;
+ unsigned int tmpl_len = (unsigned int) json_array_size (ia);
+
+ if ( (json_array_size (ia) != (size_t) tmpl_len) ||
+ (tmpl_len > MAX_TEMPLATES) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- if (GNUNET_OK == ret)
{
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK
- };
+ struct TALER_MERCHANT_TemplateEntry tmpl[GNUNET_NZL (tmpl_len)];
+ size_t index;
+ json_t *value;
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_TemplateEntry *ie = &tmpl[index];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("template_id",
+ &ie->template_id),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ tgr->details.ok.templates_length = tmpl_len;
+ tgr->details.ok.templates = tmpl;
tgh->cb (tgh->cb_cls,
- &hr,
- ies_len,
- ies);
+ tgr);
tgh->cb = NULL; /* just to be sure */
}
- return ret;
+ return GNUNET_OK;
}
@@ -133,9 +138,9 @@ handle_get_templates_finished (void *cls,
{
struct TALER_MERCHANT_TemplatesGetHandle *tgh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_TemplatesGetResponse tgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
tgh->job = NULL;
@@ -146,10 +151,10 @@ handle_get_templates_finished (void *cls,
{
case MHD_HTTP_OK:
{
- json_t *templates;
+ const json_t *templates;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("templates",
- &templates),
+ GNUNET_JSON_spec_array_const ("templates",
+ &templates),
GNUNET_JSON_spec_end ()
};
@@ -158,48 +163,39 @@ handle_get_templates_finished (void *cls,
spec,
NULL, NULL))
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ if (GNUNET_OK ==
+ parse_templates (templates,
+ &tgr,
+ tgh))
{
- if ( (! json_is_array (templates)) ||
- (GNUNET_OK ==
- parse_templates (templates,
- tgh)) )
- {
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_templates_get_cancel (tgh);
- return;
- }
- else
- {
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
+ TALER_MERCHANT_templates_get_cancel (tgh);
+ return;
}
- GNUNET_JSON_parse_free (spec);
+ tgr.hr.http_status = 0;
+ tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ 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 */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ 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) hr.ec);
+ (int) tgr.hr.ec);
break;
}
tgh->cb (tgh->cb_cls,
- &hr,
- 0,
- NULL);
+ &tgr);
TALER_MERCHANT_templates_get_cancel (tgh);
}
diff --git a/src/lib/merchant_api_get_tips.c b/src/lib/merchant_api_get_tips.c
deleted file mode 100644
index 7af6936b..00000000
--- a/src/lib/merchant_api_get_tips.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2020 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_tips.c
- * @brief Implementation of the GET /private/tips request of the merchant's HTTP API
- * @author Jonathan Buchanan
- */
-#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 /private/tips operation.
- */
-struct TALER_MERCHANT_TipsGetHandle
-{
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_TipsGetCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Reference to the execution context.
- */
- struct GNUNET_CURL_Context *ctx;
-
-};
-
-
-/**
- * Parse tip information from @a ia.
- *
- * @param ia JSON array (or NULL!) tip order data
- * @param tgh operation handle
- * @return #GNUNET_OK on success
- */
-static int
-parse_tips (const json_t *ia,
- struct TALER_MERCHANT_TipsGetHandle *tgh)
-{
- unsigned int tes_len = json_array_size (ia);
- struct TALER_MERCHANT_TipEntry tes[tes_len];
- size_t index;
- json_t *value;
- int ret;
-
- ret = GNUNET_OK;
- json_array_foreach (ia, index, value) {
- struct TALER_MERCHANT_TipEntry *ie = &tes[index];
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_uint64 ("row_id",
- &ie->row_id),
- GNUNET_JSON_spec_fixed_auto ("tip_id",
- &ie->tip_id),
- TALER_JSON_spec_amount_any ("tip_amount",
- &ie->tip_amount),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- continue;
- }
- if (GNUNET_SYSERR == ret)
- break;
- }
- if (GNUNET_OK == ret)
- {
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK
- };
-
- tgh->cb (tgh->cb_cls,
- &hr,
- tes_len,
- tes);
- tgh->cb = NULL; /* just to be sure */
- }
- return ret;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP GET /private/tips request.
- *
- * @param cls the `struct TALER_MERCHANT_TipsGetHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_get_tips_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_TipsGetHandle *tgh = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
-
- tgh->job = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got /private/tips response with status code %u\n",
- (unsigned int) response_code);
- switch (response_code)
- {
- case MHD_HTTP_OK:
- {
- json_t *tips;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("tips",
- &tips),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
- else
- {
- if ( (! json_is_array (tips)) ||
- (GNUNET_OK ==
- parse_tips (tips,
- tgh)) )
- {
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_tips_get_cancel (tgh);
- return;
- }
- else
- {
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
- }
- GNUNET_JSON_parse_free (spec);
- 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;
- 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;
- }
- tgh->cb (tgh->cb_cls,
- &hr,
- 0,
- NULL);
- TALER_MERCHANT_tips_get_cancel (tgh);
-}
-
-
-struct TALER_MERCHANT_TipsGetHandle *
-TALER_MERCHANT_tips_get (
- struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- TALER_MERCHANT_TipsGetCallback cb,
- void *cb_cls)
-{
- return TALER_MERCHANT_tips_get2 (ctx,
- backend_url,
- TALER_EXCHANGE_YNA_NO,
- -20,
- UINT64_MAX,
- cb,
- cb_cls);
-}
-
-
-struct TALER_MERCHANT_TipsGetHandle *
-TALER_MERCHANT_tips_get2 (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- enum TALER_EXCHANGE_YesNoAll expired,
- int64_t limit,
- uint64_t offset,
- TALER_MERCHANT_TipsGetCallback cb,
- void *cb_cls)
-{
- struct TALER_MERCHANT_TipsGetHandle *tgh;
- CURL *eh;
-
- GNUNET_assert (NULL != backend_url);
- if (0 == limit)
- {
- GNUNET_break (0);
- return NULL;
- }
- tgh = GNUNET_new (struct TALER_MERCHANT_TipsGetHandle);
- tgh->ctx = ctx;
- tgh->cb = cb;
- tgh->cb_cls = cb_cls;
-
- /* build tgh->url with the various optional arguments */
- {
- char cbuf[30];
- char lbuf[30];
- bool have_offset;
-
- GNUNET_snprintf (lbuf,
- sizeof (lbuf),
- "%lld",
- (long long) limit);
-
- if (limit > 0)
- have_offset = (0 != offset);
- else
- have_offset = (UINT64_MAX != offset);
- GNUNET_snprintf (cbuf,
- sizeof (cbuf),
- "%llu",
- (unsigned long long) offset);
- tgh->url = TALER_url_join (backend_url,
- "private/tips",
- "expired",
- (TALER_EXCHANGE_YNA_ALL != expired)
- ? TALER_yna_to_string (expired)
- : NULL,
- "offset", (have_offset) ? cbuf : NULL,
- "limit", (-20 != limit) ? lbuf : NULL,
- 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_tips_finished,
- tgh);
- return tgh;
-}
-
-
-void
-TALER_MERCHANT_tips_get_cancel (
- struct TALER_MERCHANT_TipsGetHandle *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_tokenfamily.c b/src/lib/merchant_api_get_tokenfamily.c
new file mode 100644
index 00000000..d7e6b06e
--- /dev/null
+++ b/src/lib/merchant_api_get_tokenfamily.c
@@ -0,0 +1,210 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2023 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_tokenfamily.c
+ * @brief Implementation of the GET /tokenfamily/$ID request of the merchant's HTTP API
+ * @author Christian Blättler
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_json_lib.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 /tokenfamilies/$SLUG operation.
+ */
+struct TALER_MERCHANT_TokenFamilyGetHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_TokenFamilyGetCallback 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 /tokenfamilies/$ID request.
+ *
+ * @param cls the `struct TALER_MERCHANT_TokenFamilyGetHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_get_token_family_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_TokenFamilyGetHandle *handle = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_TokenFamilyGetResponse res = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
+
+ handle->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /tokenfamilies/$ID response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ // Parse token family response
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("slug",
+ &res.details.ok.slug),
+ GNUNET_JSON_spec_string ("name",
+ &res.details.ok.name),
+ GNUNET_JSON_spec_string ("description",
+ &res.details.ok.description),
+ GNUNET_JSON_spec_object_const ("description_i18n",
+ &res.details.ok.description_i18n),
+ GNUNET_JSON_spec_timestamp ("valid_after",
+ &res.details.ok.valid_after),
+ GNUNET_JSON_spec_timestamp ("valid_before",
+ &res.details.ok.valid_before),
+ GNUNET_JSON_spec_relative_time ("duation",
+ &res.details.ok.duration),
+ GNUNET_JSON_spec_string ("kind",
+ &res.details.ok.kind),
+ GNUNET_JSON_spec_uint64 ("issued",
+ &res.details.ok.issued),
+ GNUNET_JSON_spec_uint64 ("redeemed",
+ &res.details.ok.redeemed),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK ==
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ handle->cb (handle->cb_cls,
+ &res);
+ GNUNET_JSON_parse_free (spec);
+ TALER_MERCHANT_token_family_get_cancel (handle);
+ return;
+ }
+ res.hr.http_status = 0;
+ res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ case MHD_HTTP_UNAUTHORIZED:
+ res.hr.ec = TALER_JSON_get_error_code (json);
+ res.hr.hint = TALER_JSON_get_error_hint (json);
+ /* Nothing really to verify, merchant says we need to authenticate. */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ res.hr.ec = TALER_JSON_get_error_code (json);
+ res.hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ default:
+ /* unexpected response code */
+ res.hr.ec = TALER_JSON_get_error_code (json);
+ res.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) res.hr.ec);
+ break;
+ }
+}
+
+struct TALER_MERCHANT_TokenFamilyGetHandle *
+TALER_MERCHANT_token_family_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *token_family_slug,
+ TALER_MERCHANT_TokenFamilyGetCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_TokenFamilyGetHandle *handle;
+ CURL *eh;
+
+ handle = GNUNET_new (struct TALER_MERCHANT_TokenFamilyGetHandle);
+ handle->ctx = ctx;
+ handle->cb = cb;
+ handle->cb_cls = cb_cls;
+ {
+ char *path;
+
+ GNUNET_asprintf (&path,
+ "private/tokenfamilies/%s",
+ token_family_slug);
+ handle->url = TALER_url_join (backend_url,
+ path,
+ NULL);
+ GNUNET_free (path);
+ }
+ if (NULL == handle->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (handle);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ handle->url);
+ eh = TALER_MERCHANT_curl_easy_get_ (handle->url);
+ handle->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_get_token_family_finished,
+ handle);
+ return handle;
+}
+
+void
+TALER_MERCHANT_token_family_get_cancel (
+ struct TALER_MERCHANT_TokenFamilyGetHandle *handle)
+{
+ if (NULL != handle->job)
+ GNUNET_CURL_job_cancel (handle->job);
+ GNUNET_free (handle->url);
+ GNUNET_free (handle);
+} \ No newline at end of file
diff --git a/src/lib/merchant_api_get_transfers.c b/src/lib/merchant_api_get_transfers.c
index f2f1186d..6116a54f 100644
--- a/src/lib/merchant_api_get_transfers.c
+++ b/src/lib/merchant_api_get_transfers.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2017, 2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -81,23 +81,23 @@ handle_transfers_get_finished (void *cls,
{
struct TALER_MERCHANT_GetTransfersHandle *gth = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_GetTransfersResponse gtr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
gth->job = NULL;
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ gtr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
- json_t *transfers;
+ const json_t *transfers;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("transfers",
- &transfers),
+ GNUNET_JSON_spec_array_const ("transfers",
+ &transfers),
GNUNET_JSON_spec_end ()
};
@@ -107,26 +107,18 @@ handle_transfers_get_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ gtr.hr.http_status = 0;
+ gtr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
- else
+
{
size_t tds_length;
struct TALER_MERCHANT_TransferData *tds;
json_t *transfer;
- unsigned int i;
+ size_t i;
bool ok;
- if (! json_is_array (transfers))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
tds_length = json_array_size (transfers);
tds = GNUNET_new_array (tds_length,
struct TALER_MERCHANT_TransferData);
@@ -138,9 +130,9 @@ handle_transfers_get_finished (void *cls,
&td->credit_amount),
GNUNET_JSON_spec_fixed_auto ("wtid",
&td->wtid),
- GNUNET_JSON_spec_string ("payto_uri",
- &td->payto_uri),
- GNUNET_JSON_spec_string ("exchange_url",
+ TALER_JSON_spec_payto_uri ("payto_uri",
+ &td->payto_uri),
+ TALER_JSON_spec_web_url ("exchange_url",
&td->exchange_url),
GNUNET_JSON_spec_uint64 ("transfer_serial_id",
&td->credit_serial),
@@ -174,55 +166,51 @@ handle_transfers_get_finished (void *cls,
{
GNUNET_break_op (0);
GNUNET_free (tds);
- GNUNET_JSON_parse_free (spec);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ gtr.hr.http_status = 0;
+ gtr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
+ gtr.details.ok.transfers = tds;
+ gtr.details.ok.transfers_length = tds_length;
gth->cb (gth->cb_cls,
- &hr,
- tds_length,
- tds);
+ &gtr);
GNUNET_free (tds);
- GNUNET_JSON_parse_free (spec);
TALER_MERCHANT_transfers_get_cancel (gth);
return;
}
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ gtr.hr.ec = TALER_JSON_get_error_code (json);
+ gtr.hr.hint = TALER_JSON_get_error_hint (json);
/* Nothing really to verify, merchant says we need to authenticate. */
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ gtr.hr.ec = TALER_JSON_get_error_code (json);
+ gtr.hr.hint = TALER_JSON_get_error_hint (json);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ gtr.hr.ec = TALER_JSON_get_error_code (json);
+ gtr.hr.hint = TALER_JSON_get_error_hint (json);
break;
default:
/* unexpected response code */
GNUNET_break_op (0);
TALER_MERCHANT_parse_error_details_ (json,
response_code,
- &hr);
+ &gtr.hr);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d\n",
(unsigned int) response_code,
- (int) hr.ec);
- response_code = 0;
+ (int) gtr.hr.ec);
+ gtr.hr.http_status = 0;
break;
}
gth->cb (gth->cb_cls,
- &hr,
- 0,
- NULL);
+ &gtr);
TALER_MERCHANT_transfers_get_cancel (gth);
}
diff --git a/src/lib/merchant_api_get_webhook.c b/src/lib/merchant_api_get_webhook.c
index 0e9abc6f..551aa915 100644
--- a/src/lib/merchant_api_get_webhook.c
+++ b/src/lib/merchant_api_get_webhook.c
@@ -101,7 +101,7 @@ handle_get_webhook_finished (void *cls,
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("event_type",
&event_type),
- GNUNET_JSON_spec_string ("url",
+ TALER_JSON_spec_web_url ("url",
&url),
GNUNET_JSON_spec_string ("http_method",
&http_method),
diff --git a/src/lib/merchant_api_get_webhooks.c b/src/lib/merchant_api_get_webhooks.c
index f5ba6f41..e702baac 100644
--- a/src/lib/merchant_api_get_webhooks.c
+++ b/src/lib/merchant_api_get_webhooks.c
@@ -32,6 +32,11 @@
/**
+ * Maximum number of webhooks we return.
+ */
+#define MAX_WEBHOOKS 1024
+
+/**
* Handle for a GET /webhooks operation.
*/
struct TALER_MERCHANT_WebhooksGetHandle
@@ -68,53 +73,52 @@ struct TALER_MERCHANT_WebhooksGetHandle
* Parse webhook information from @a ia.
*
* @param ia JSON array (or NULL!) with webhook data
+ * @param[in] wgr partially filled webhook response
* @param wgh operation handle
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_webhooks (const json_t *ia,
+ struct TALER_MERCHANT_WebhooksGetResponse *wgr,
struct TALER_MERCHANT_WebhooksGetHandle *wgh)
{
- unsigned int ies_len = json_array_size (ia);
- struct TALER_MERCHANT_WebhookEntry ies[ies_len];
- size_t index;
- json_t *value;
- int ret;
-
- ret = GNUNET_OK;
- json_array_foreach (ia, index, value) {
- struct TALER_MERCHANT_WebhookEntry *ie = &ies[index];
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("webhook_id",
- &ie->webhook_id),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- continue;
- }
- if (GNUNET_SYSERR == ret)
- break;
+ unsigned int whook_len = (unsigned int) json_array_size (ia);
+
+ if ( (json_array_size (ia) != (size_t) whook_len) ||
+ (whook_len > MAX_WEBHOOKS) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- if (GNUNET_OK == ret)
{
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK
- };
+ struct TALER_MERCHANT_WebhookEntry whook[GNUNET_NZL (whook_len)];
+ size_t index;
+ json_t *value;
+
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_WebhookEntry *ie = &whook[index];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("webhook_id",
+ &ie->webhook_id),
+ GNUNET_JSON_spec_end ()
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ wgr->details.ok.webhooks_length = whook_len;
+ wgr->details.ok.webhooks = whook;
wgh->cb (wgh->cb_cls,
- &hr,
- ies_len,
- ies);
+ wgr);
wgh->cb = NULL; /* just to be sure */
}
- return ret;
+ return GNUNET_OK;
}
@@ -133,9 +137,9 @@ handle_get_webhooks_finished (void *cls,
{
struct TALER_MERCHANT_WebhooksGetHandle *wgh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_WebhooksGetResponse wgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
wgh->job = NULL;
@@ -146,10 +150,10 @@ handle_get_webhooks_finished (void *cls,
{
case MHD_HTTP_OK:
{
- json_t *webhooks;
+ const json_t *webhooks;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("webhooks",
- &webhooks),
+ GNUNET_JSON_spec_array_const ("webhooks",
+ &webhooks),
GNUNET_JSON_spec_end ()
};
@@ -158,48 +162,39 @@ handle_get_webhooks_finished (void *cls,
spec,
NULL, NULL))
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ wgr.hr.http_status = 0;
+ wgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ if (GNUNET_OK ==
+ parse_webhooks (webhooks,
+ &wgr,
+ wgh))
{
- if ( (! json_is_array (webhooks)) ||
- (GNUNET_OK ==
- parse_webhooks (webhooks,
- wgh)) )
- {
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_webhooks_get_cancel (wgh);
- return;
- }
- else
- {
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
+ TALER_MERCHANT_webhooks_get_cancel (wgh);
+ return;
}
- GNUNET_JSON_parse_free (spec);
+ wgr.hr.http_status = 0;
+ wgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ wgr.hr.ec = TALER_JSON_get_error_code (json);
+ wgr.hr.hint = TALER_JSON_get_error_hint (json);
/* Nothing really to verify, merchant says we need to authenticate. */
break;
default:
/* unexpected response code */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ wgr.hr.ec = TALER_JSON_get_error_code (json);
+ wgr.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);
+ (int) wgr.hr.ec);
break;
}
wgh->cb (wgh->cb_cls,
- &hr,
- 0,
- NULL);
+ &wgr);
TALER_MERCHANT_webhooks_get_cancel (wgh);
}
diff --git a/src/lib/merchant_api_merchant_get_order.c b/src/lib/merchant_api_merchant_get_order.c
index 0e6b53bf..3bd4003b 100644
--- a/src/lib/merchant_api_merchant_get_order.c
+++ b/src/lib/merchant_api_merchant_get_order.c
@@ -34,6 +34,17 @@
/**
+ * Maximum number of refund details we return.
+ */
+#define MAX_REFUND_DETAILS 1024
+
+/**
+ * Maximum number of wire details we return.
+ */
+#define MAX_WIRE_DETAILS 1024
+
+
+/**
* @brief A GET /private/orders/$ORDER handle
*/
struct TALER_MERCHANT_OrderMerchantGetHandle
@@ -81,21 +92,21 @@ handle_unpaid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh,
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any (
"total_amount",
- &osr->details.success.details.unpaid.contract_amount),
+ &osr->details.ok.details.unpaid.contract_amount),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string (
"already_paid_order_id",
- &osr->details.success.details.unpaid.already_paid_order_id),
+ &osr->details.ok.details.unpaid.already_paid_order_id),
NULL),
GNUNET_JSON_spec_string (
"taler_pay_uri",
- &osr->details.success.details.unpaid.taler_pay_uri),
+ &osr->details.ok.details.unpaid.taler_pay_uri),
GNUNET_JSON_spec_string (
"summary",
- &osr->details.success.details.unpaid.summary),
+ &osr->details.ok.details.unpaid.summary),
GNUNET_JSON_spec_timestamp (
"creation_time",
- &osr->details.success.details.unpaid.creation_time),
+ &osr->details.ok.details.unpaid.creation_time),
GNUNET_JSON_spec_end ()
};
@@ -111,7 +122,7 @@ handle_unpaid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh,
osr);
return;
}
- osr->details.success.status = TALER_MERCHANT_OSC_UNPAID;
+ osr->details.ok.status = TALER_MERCHANT_OSC_UNPAID;
omgh->cb (omgh->cb_cls,
osr);
}
@@ -130,9 +141,9 @@ handle_claimed (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh,
struct TALER_MERCHANT_OrderStatusResponse *osr)
{
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("contract_terms",
- (json_t **) &osr->details.success.details.claimed.
- contract_terms),
+ GNUNET_JSON_spec_object_const (
+ "contract_terms",
+ &osr->details.ok.details.claimed.contract_terms),
GNUNET_JSON_spec_end ()
};
@@ -148,10 +159,9 @@ handle_claimed (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh,
osr);
return;
}
- osr->details.success.status = TALER_MERCHANT_OSC_CLAIMED;
+ osr->details.ok.status = TALER_MERCHANT_OSC_CLAIMED;
omgh->cb (omgh->cb_cls,
osr);
- GNUNET_JSON_parse_free (spec);
}
@@ -167,35 +177,36 @@ static void
handle_paid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh,
struct TALER_MERCHANT_OrderStatusResponse *osr)
{
- uint32_t ec32;
uint32_t hc32;
- json_t *wire_details;
- json_t *wire_reports;
- json_t *refund_details;
+ const json_t *wire_details;
+ const json_t *refund_details;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_bool ("refunded",
- &osr->details.success.details.paid.refunded),
+ &osr->details.ok.details.paid.refunded),
GNUNET_JSON_spec_bool ("refund_pending",
- &osr->details.success.details.paid.refund_pending),
+ &osr->details.ok.details.paid.refund_pending),
GNUNET_JSON_spec_bool ("wired",
- &osr->details.success.details.paid.wired),
+ &osr->details.ok.details.paid.wired),
TALER_JSON_spec_amount_any ("deposit_total",
- &osr->details.success.details.paid.deposit_total),
- GNUNET_JSON_spec_uint32 ("exchange_code",
- &ec32),
+ &osr->details.ok.details.paid.deposit_total),
+ TALER_JSON_spec_ec ("exchange_code",
+ &osr->details.ok.details.paid.exchange_ec),
GNUNET_JSON_spec_uint32 ("exchange_http_status",
&hc32),
TALER_JSON_spec_amount_any ("refund_amount",
- &osr->details.success.details.paid.refund_amount),
- GNUNET_JSON_spec_json (
+ &osr->details.ok.details.paid.refund_amount),
+ GNUNET_JSON_spec_object_const (
"contract_terms",
- (json_t **) &osr->details.success.details.paid.contract_terms),
- GNUNET_JSON_spec_json ("wire_details",
- &wire_details),
- GNUNET_JSON_spec_json ("wire_reports",
- &wire_reports),
- GNUNET_JSON_spec_json ("refund_details",
- &refund_details),
+ &osr->details.ok.details.paid.contract_terms),
+ GNUNET_JSON_spec_array_const ("wire_details",
+ &wire_details),
+ GNUNET_JSON_spec_array_const ("refund_details",
+ &refund_details),
+ /* Only available since **v14** */
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_timestamp ("last_payment",
+ &osr->details.ok.details.paid.last_payment),
+ NULL),
GNUNET_JSON_spec_end ()
};
@@ -211,143 +222,107 @@ handle_paid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh,
osr);
return;
}
- if (! (json_is_array (wire_details) &&
- json_is_array (wire_reports) &&
- json_is_array (refund_details) &&
- json_is_object (osr->details.success.details.paid.contract_terms)) )
- {
- GNUNET_break_op (0);
- osr->hr.http_status = 0;
- osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- omgh->cb (omgh->cb_cls,
- osr);
- GNUNET_JSON_parse_free (spec);
- return;
- }
- osr->details.success.status = TALER_MERCHANT_OSC_PAID;
- osr->details.success.details.paid.exchange_ec = (enum TALER_ErrorCode) ec32;
- osr->details.success.details.paid.exchange_hc = (unsigned int) hc32;
+ osr->details.ok.status = TALER_MERCHANT_OSC_PAID;
+
+ osr->details.ok.details.paid.exchange_hc = (unsigned int) hc32;
{
- unsigned int wts_len = json_array_size (wire_details);
- unsigned int wrs_len = json_array_size (wire_reports);
- unsigned int ref_len = json_array_size (refund_details);
- struct TALER_MERCHANT_WireTransfer wts[wts_len];
- struct TALER_MERCHANT_WireReport wrs[wrs_len];
- struct TALER_MERCHANT_RefundOrderDetail ref[ref_len];
-
- for (unsigned int i = 0; i<wts_len; i++)
+ unsigned int wts_len = (unsigned int) json_array_size (wire_details);
+ unsigned int ref_len = (unsigned int) json_array_size (refund_details);
+
+ if ( (json_array_size (wire_details) != (size_t) wts_len) ||
+ (wts_len > MAX_WIRE_DETAILS) )
{
- struct TALER_MERCHANT_WireTransfer *wt = &wts[i];
- const json_t *w = json_array_get (wire_details,
- i);
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("exchange_url",
- &wt->exchange_url),
- GNUNET_JSON_spec_fixed_auto ("wtid",
- &wt->wtid),
- GNUNET_JSON_spec_timestamp ("execution_time",
- &wt->execution_time),
- TALER_JSON_spec_amount_any ("amount",
- &wt->total_amount),
- GNUNET_JSON_spec_bool ("confirmed",
- &wt->confirmed),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (w,
- ispec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- osr->hr.http_status = 0;
- osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- omgh->cb (omgh->cb_cls,
- osr);
- GNUNET_JSON_parse_free (spec);
- return;
- }
+ GNUNET_break (0);
+ osr->hr.http_status = 0;
+ osr->hr.ec = TALER_EC_GENERIC_ALLOCATION_FAILURE;
+ omgh->cb (omgh->cb_cls,
+ osr);
+ return;
+ }
+ if ( (json_array_size (refund_details) != (size_t) ref_len) ||
+ (ref_len > MAX_REFUND_DETAILS) )
+ {
+ GNUNET_break (0);
+ osr->hr.http_status = 0;
+ osr->hr.ec = TALER_EC_GENERIC_ALLOCATION_FAILURE;
+ omgh->cb (omgh->cb_cls,
+ osr);
+ return;
}
-
- for (unsigned int i = 0; i<wrs_len; i++)
{
- struct TALER_MERCHANT_WireReport *wr = &wrs[i];
- const json_t *w = json_array_get (wire_reports, i);
- uint32_t c32;
- uint32_t eec32;
- uint32_t ehs32;
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_uint32 ("code",
- &c32),
- GNUNET_JSON_spec_string ("hint",
- &wr->hint),
- GNUNET_JSON_spec_uint32 ("exchange_code",
- &eec32),
- GNUNET_JSON_spec_uint32 ("exchange_http_status",
- &ehs32),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &wr->coin_pub),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (w,
- ispec,
- NULL, NULL))
+ struct TALER_MERCHANT_WireTransfer wts[GNUNET_NZL (wts_len)];
+ struct TALER_MERCHANT_RefundOrderDetail ref[GNUNET_NZL (ref_len)];
+
+ for (unsigned int i = 0; i<wts_len; i++)
{
- GNUNET_break_op (0);
- osr->hr.http_status = 0;
- osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- omgh->cb (omgh->cb_cls,
- osr);
- GNUNET_JSON_parse_free (spec);
- return;
+ struct TALER_MERCHANT_WireTransfer *wt = &wts[i];
+ const json_t *w = json_array_get (wire_details,
+ i);
+ struct GNUNET_JSON_Specification ispec[] = {
+ TALER_JSON_spec_web_url ("exchange_url",
+ &wt->exchange_url),
+ GNUNET_JSON_spec_fixed_auto ("wtid",
+ &wt->wtid),
+ GNUNET_JSON_spec_timestamp ("execution_time",
+ &wt->execution_time),
+ TALER_JSON_spec_amount_any ("amount",
+ &wt->total_amount),
+ GNUNET_JSON_spec_bool ("confirmed",
+ &wt->confirmed),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (w,
+ ispec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ osr->hr.http_status = 0;
+ osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ omgh->cb (omgh->cb_cls,
+ osr);
+ return;
+ }
}
- wr->code = (enum TALER_ErrorCode) c32;
- wr->hr.ec = (enum TALER_ErrorCode) eec32;
- wr->hr.http_status = (unsigned int) ehs32;
- }
- for (unsigned int i = 0; i<ref_len; i++)
- {
- struct TALER_MERCHANT_RefundOrderDetail *ro = &ref[i];
- const json_t *w = json_array_get (refund_details,
- i);
- struct GNUNET_JSON_Specification ispec[] = {
- TALER_JSON_spec_amount_any ("amount",
- &ro->refund_amount),
- GNUNET_JSON_spec_string ("reason",
- &ro->reason),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &ro->refund_time),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (w,
- ispec,
- NULL, NULL))
+ for (unsigned int i = 0; i<ref_len; i++)
{
- GNUNET_break_op (0);
- osr->hr.http_status = 0;
- osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- omgh->cb (omgh->cb_cls,
- osr);
- GNUNET_JSON_parse_free (spec);
- return;
+ struct TALER_MERCHANT_RefundOrderDetail *ro = &ref[i];
+ const json_t *w = json_array_get (refund_details,
+ i);
+ struct GNUNET_JSON_Specification ispec[] = {
+ TALER_JSON_spec_amount_any ("amount",
+ &ro->refund_amount),
+ GNUNET_JSON_spec_string ("reason",
+ &ro->reason),
+ GNUNET_JSON_spec_timestamp ("timestamp",
+ &ro->refund_time),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (w,
+ ispec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ osr->hr.http_status = 0;
+ osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ omgh->cb (omgh->cb_cls,
+ osr);
+ return;
+ }
}
- }
- osr->details.success.details.paid.wts = wts;
- osr->details.success.details.paid.wts_len = wts_len;
- osr->details.success.details.paid.wrs = wrs;
- osr->details.success.details.paid.wrs_len = wrs_len;
- osr->details.success.details.paid.refunds = ref;
- osr->details.success.details.paid.refunds_len = ref_len;
- omgh->cb (omgh->cb_cls,
- osr);
+ osr->details.ok.details.paid.wts = wts;
+ osr->details.ok.details.paid.wts_len = wts_len;
+ osr->details.ok.details.paid.refunds = ref;
+ osr->details.ok.details.paid.refunds_len = ref_len;
+ omgh->cb (omgh->cb_cls,
+ osr);
+ }
}
- GNUNET_JSON_parse_free (spec);
}
@@ -464,27 +439,20 @@ handle_merchant_order_get_finished (void *cls,
struct TALER_MERCHANT_OrderMerchantGetHandle *
-TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const char *order_id,
- const char *session_id,
- bool transfer,
- struct GNUNET_TIME_Relative timeout,
- TALER_MERCHANT_OrderMerchantGetCallback cb,
- void *cb_cls)
+TALER_MERCHANT_merchant_order_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *order_id,
+ const char *session_id,
+ struct GNUNET_TIME_Relative timeout,
+ TALER_MERCHANT_OrderMerchantGetCallback cb,
+ void *cb_cls)
{
struct TALER_MERCHANT_OrderMerchantGetHandle *omgh;
- unsigned long long tms;
- long tlong;
-
- tms = (unsigned long long) (timeout.rel_value_us
- / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
- /* set curl timeout to *our* long poll timeout plus one minute
- (for network latency and processing delays) */
- tlong = (long) (GNUNET_TIME_relative_add (timeout,
- GNUNET_TIME_UNIT_MINUTES).
- rel_value_us
- / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
+ unsigned int tms;
+
+ tms = (unsigned int) (timeout.rel_value_us
+ / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
omgh = GNUNET_new (struct TALER_MERCHANT_OrderMerchantGetHandle);
omgh->ctx = ctx;
omgh->cb = cb;
@@ -495,7 +463,7 @@ TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx,
GNUNET_snprintf (timeout_ms,
sizeof (timeout_ms),
- "%llu",
+ "%u",
tms);
GNUNET_asprintf (&path,
"private/orders/%s",
@@ -503,7 +471,6 @@ TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx,
omgh->url = TALER_url_join (backend_url,
path,
"session_id", session_id,
- "transfer", transfer ? "YES" : "NO",
"timeout_ms", (0 != tms) ? timeout_ms : NULL,
NULL);
GNUNET_free (path);
@@ -527,16 +494,12 @@ TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx,
GNUNET_free (omgh);
return NULL;
}
- if (CURLE_OK !=
- curl_easy_setopt (eh,
- CURLOPT_TIMEOUT_MS,
- tlong))
+ if (0 != tms)
{
- GNUNET_break (0);
- curl_easy_cleanup (eh);
- GNUNET_free (omgh->url);
- GNUNET_free (omgh);
- return NULL;
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_TIMEOUT_MS,
+ (long) (tms + 100L)));
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
diff --git a/src/lib/merchant_api_merchant_get_tip.c b/src/lib/merchant_api_merchant_get_tip.c
deleted file mode 100644
index 7466fccc..00000000
--- a/src/lib/merchant_api_merchant_get_tip.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2020 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_merchant_get_tip.c
- * @brief Implementation of the GET /private/tips/$TIP_ID request of the merchant's HTTP API
- * @author Jonathan Buchanan
- */
-#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_common.h"
-#include "merchant_api_curl_defaults.h"
-#include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-
-
-struct TALER_MERCHANT_TipMerchantGetHandle
-{
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_TipMerchantGetCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Reference to the execution context.
- */
- struct GNUNET_CURL_Context *ctx;
-};
-
-
-static enum GNUNET_GenericReturnValue
-parse_pickups (const json_t *pa,
- struct TALER_MERCHANT_TipStatusResponse *tsr,
- struct TALER_MERCHANT_TipMerchantGetHandle *tgh)
-{
- unsigned int pa_len = json_array_size (pa);
- struct TALER_MERCHANT_PickupDetail pickups[pa_len];
- size_t index;
- json_t *value;
-
- json_array_foreach (pa, index, value)
- {
- struct TALER_MERCHANT_PickupDetail *pickup = &pickups[index];
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("pickup_id",
- &pickup->pickup_id),
- GNUNET_JSON_spec_uint64 ("num_planchets",
- &pickup->num_planchets),
- TALER_JSON_spec_amount_any ("requested_amount",
- &pickup->requested_amount),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- NULL,
- NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
- tsr->details.success.pickups_length = pa_len;
- tsr->details.success.pickups = pickups;
- tgh->cb (tgh->cb_cls,
- tsr);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * GET /private/tips/$TIP_ID request.
- *
- * @param cls the `struct TALER_MERCHANT_TipMerchantGetHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_merchant_tip_get_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_TipMerchantGetHandle *tgh = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_TipStatusResponse tsr = {
- .hr.http_status = (unsigned int) response_code,
- .hr.reply = json
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got /private/tips/$TIP_ID response with status code %u\n",
- (unsigned int) response_code);
- tgh->job = NULL;
- switch (response_code)
- {
- case MHD_HTTP_OK:
- {
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("total_authorized",
- &tsr.details.success.total_authorized),
- TALER_JSON_spec_amount_any ("total_picked_up",
- &tsr.details.success.total_picked_up),
- GNUNET_JSON_spec_string ("reason",
- &tsr.details.success.reason),
- GNUNET_JSON_spec_timestamp ("expiration",
- &tsr.details.success.expiration),
- GNUNET_JSON_spec_fixed_auto ("reserve_pub",
- &tsr.details.success.reserve_pub),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- tsr.hr.http_status = 0;
- tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
- else
- {
- json_t *pickups = json_object_get (json,
- "pickups");
- if (! json_is_array (pickups))
- {
- tgh->cb (tgh->cb_cls,
- &tsr);
- TALER_MERCHANT_merchant_tip_get_cancel (tgh);
- return;
- }
- if (GNUNET_OK ==
- parse_pickups (pickups,
- &tsr,
- tgh))
- {
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_merchant_tip_get_cancel (tgh);
- return;
- }
- tsr.hr.http_status = 0;
- tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
- GNUNET_JSON_parse_free (spec);
- break;
- }
- case MHD_HTTP_UNAUTHORIZED:
- tsr.hr.ec = TALER_JSON_get_error_code (json);
- tsr.hr.hint = TALER_JSON_get_error_hint (json);
- /* Nothing really to verify, merchant says we need to authenticate. */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* legal, can happen if instance or tip reserve is unknown */
- tsr.hr.ec = TALER_JSON_get_error_code (json);
- tsr.hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- tsr.hr.ec = TALER_JSON_get_error_code (json);
- tsr.hr.hint = TALER_JSON_get_error_hint (json);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &tsr.hr);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) tsr.hr.ec);
- break;
- }
- tgh->cb (tgh->cb_cls,
- &tsr);
- TALER_MERCHANT_merchant_tip_get_cancel (tgh);
-}
-
-
-struct TALER_MERCHANT_TipMerchantGetHandle *
-TALER_MERCHANT_merchant_tip_get (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_TipIdentifierP *tip_id,
- const struct TALER_Amount *min_pick_up,
- struct GNUNET_TIME_Relative lp_timeout,
- bool pickups,
- TALER_MERCHANT_TipMerchantGetCallback cb,
- void *cb_cls)
-{
- struct TALER_MERCHANT_TipMerchantGetHandle *tgh;
- CURL *eh;
-
- GNUNET_assert (NULL != backend_url);
- tgh = GNUNET_new (struct TALER_MERCHANT_TipMerchantGetHandle);
- tgh->ctx = ctx;
- tgh->cb = cb;
- tgh->cb_cls = cb_cls;
-
- {
- char res_str[sizeof (*tip_id) * 2];
- char arg_str[sizeof (res_str) + 48];
- char timeout_str[32];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (tip_id,
- sizeof (*tip_id),
- res_str,
- sizeof (res_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "private/tips/%s",
- res_str);
- GNUNET_snprintf (timeout_str,
- sizeof (timeout_str),
- "%llu",
- ((unsigned long long)
- lp_timeout.rel_value_us
- / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us));
- tgh->url = TALER_url_join (backend_url,
- arg_str,
- "pickups",
- pickups
- ? "yes"
- : NULL,
- "min_amount",
- min_pick_up
- ? TALER_amount2s (min_pick_up)
- : NULL,
- "timeout_ms",
- GNUNET_TIME_relative_is_zero (lp_timeout)
- ? NULL
- : timeout_str,
- NULL);
- }
- if (NULL == tgh->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- GNUNET_free (tgh);
- return NULL;
- }
-
- eh = TALER_MERCHANT_curl_easy_get_ (tgh->url);
- tgh->job = GNUNET_CURL_job_add (ctx,
- eh,
- &handle_merchant_tip_get_finished,
- tgh);
- return tgh;
-}
-
-
-void
-TALER_MERCHANT_merchant_tip_get_cancel (
- struct TALER_MERCHANT_TipMerchantGetHandle *tgh)
-{
- if (NULL != tgh->job)
- {
- GNUNET_CURL_job_cancel (tgh->job);
- tgh->job = NULL;
- }
- GNUNET_free (tgh->url);
- GNUNET_free (tgh);
-}
-
-
-/* end of merchant_api_merchant_get_tip.c */
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 0613a852..420cd549 100644
--- a/src/lib/merchant_api_patch_instance.c
+++ b/src/lib/merchant_api_patch_instance.c
@@ -31,6 +31,7 @@
#include "merchant_api_curl_defaults.h"
#include "merchant_api_common.h"
#include <taler/taler_json_lib.h>
+#include <taler/taler_kyclogic_lib.h>
#include <taler/taler_curl_lib.h>
@@ -157,55 +158,37 @@ TALER_MERCHANT_instance_patch (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
const char *instance_id,
- unsigned int accounts_length,
- const char *payto_uris[],
const char *name,
+ enum TALER_KYCLOGIC_KycUserType ut,
const json_t *address,
const json_t *jurisdiction,
- const struct TALER_Amount *default_max_wire_fee,
- uint32_t default_wire_fee_amortization,
- const struct TALER_Amount *default_max_deposit_fee,
+ bool use_stefan,
struct GNUNET_TIME_Relative default_wire_transfer_delay,
struct GNUNET_TIME_Relative default_pay_delay,
TALER_MERCHANT_InstancePatchCallback cb,
void *cb_cls)
{
struct TALER_MERCHANT_InstancePatchHandle *iph;
- json_t *jpayto_uris;
json_t *req_obj;
+ const char *uts;
- jpayto_uris = json_array ();
- if (NULL == jpayto_uris)
+ uts = TALER_KYCLOGIC_kyc_user_type2s (ut);
+ if (NULL == uts)
{
GNUNET_break (0);
return NULL;
}
- for (unsigned int i = 0; i<accounts_length; i++)
- {
- if (0 !=
- json_array_append_new (jpayto_uris,
- json_string (payto_uris[i])))
- {
- GNUNET_break (0);
- json_decref (jpayto_uris);
- return NULL;
- }
- }
req_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("payto_uris",
- jpayto_uris),
GNUNET_JSON_pack_string ("name",
name),
+ GNUNET_JSON_pack_string ("user_type",
+ uts),
GNUNET_JSON_pack_object_incref ("address",
(json_t *) address),
GNUNET_JSON_pack_object_incref ("jurisdiction",
(json_t *) jurisdiction),
- TALER_JSON_pack_amount ("default_max_wire_fee",
- default_max_wire_fee),
- GNUNET_JSON_pack_uint64 ("default_wire_fee_amortization",
- default_wire_fee_amortization),
- TALER_JSON_pack_amount ("default_max_deposit_fee",
- default_max_deposit_fee),
+ GNUNET_JSON_pack_bool ("use_stefan",
+ use_stefan),
GNUNET_JSON_pack_time_rel ("default_wire_transfer_delay",
default_wire_transfer_delay),
GNUNET_JSON_pack_time_rel ("default_pay_delay",
diff --git a/src/lib/merchant_api_patch_order_forget.c b/src/lib/merchant_api_patch_order_forget.c
index 572f00e6..118655db 100644
--- a/src/lib/merchant_api_patch_order_forget.c
+++ b/src/lib/merchant_api_patch_order_forget.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020, 2021 Taler Systems SA
+ Copyright (C) 2020, 2021, 2023 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
@@ -150,13 +150,14 @@ handle_forget_finished (void *cls,
struct TALER_MERCHANT_OrderForgetHandle *
-TALER_MERCHANT_order_forget (struct GNUNET_CURL_Context *ctx,
- const char *merchant_url,
- const char *order_id,
- unsigned int fields_length,
- const char *fields[],
- TALER_MERCHANT_ForgetCallback cb,
- void *cb_cls)
+TALER_MERCHANT_order_forget (
+ struct GNUNET_CURL_Context *ctx,
+ const char *merchant_url,
+ const char *order_id,
+ unsigned int fields_length,
+ const char *fields[static fields_length],
+ TALER_MERCHANT_ForgetCallback cb,
+ void *cb_cls)
{
struct TALER_MERCHANT_OrderForgetHandle *ofh;
json_t *req_fields;
@@ -236,8 +237,8 @@ TALER_MERCHANT_order_forget (struct GNUNET_CURL_Context *ctx,
void
-TALER_MERCHANT_order_forget_cancel (struct
- TALER_MERCHANT_OrderForgetHandle *ofh)
+TALER_MERCHANT_order_forget_cancel (
+ struct TALER_MERCHANT_OrderForgetHandle *ofh)
{
if (NULL != ofh->job)
{
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 44357cc0..7dfebf9c 100644
--- a/src/lib/merchant_api_patch_template.c
+++ b/src/lib/merchant_api_patch_template.c
@@ -162,7 +162,7 @@ TALER_MERCHANT_template_patch (
const char *backend_url,
const char *template_id,
const char *template_description,
- const char *image,
+ const char *otp_id,
json_t *template_contract,
TALER_MERCHANT_TemplatePatchCallback cb,
void *cb_cls)
@@ -174,8 +174,8 @@ TALER_MERCHANT_template_patch (
GNUNET_JSON_pack_string ("template_description",
template_description),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("image",
- image)),
+ 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
new file mode 100644
index 00000000..690aef17
--- /dev/null
+++ b/src/lib/merchant_api_post_account.c
@@ -0,0 +1,250 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 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_account.c
+ * @brief Implementation of the POST /account 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 /private/accounts operation.
+ */
+struct TALER_MERCHANT_AccountsPostHandle
+{
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_AccountsPostCallback 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 /account request.
+ *
+ * @param cls the `struct TALER_MERCHANT_AccountPostHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_post_account_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_AccountsPostHandle *aph = cls;
+ const json_t *json = response;
+ 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 /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_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);
+ apr.hr.ec = TALER_JSON_get_error_code (json);
+ apr.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_FORBIDDEN:
+ apr.hr.ec = TALER_JSON_get_error_code (json);
+ apr.hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ apr.hr.ec = TALER_JSON_get_error_code (json);
+ apr.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:
+ apr.hr.ec = TALER_JSON_get_error_code (json);
+ apr.hr.hint = TALER_JSON_get_error_hint (json);
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ apr.hr.ec = TALER_JSON_get_error_code (json);
+ apr.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,
+ &apr.hr);
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) apr.hr.ec);
+ GNUNET_break_op (0);
+ break;
+ }
+ aph->cb (aph->cb_cls,
+ &apr);
+ TALER_MERCHANT_accounts_post_cancel (aph);
+}
+
+
+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)
+{
+ struct TALER_MERCHANT_AccountsPostHandle *aph;
+ json_t *req_obj;
+
+ req_obj = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string (
+ "payto_uri",
+ payto_uri),
+ 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))
+ );
+ 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/accounts",
+ NULL);
+ if (NULL == aph->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ json_decref (req_obj);
+ GNUNET_free (aph);
+ return NULL;
+ }
+ {
+ CURL *eh;
+
+ eh = TALER_MERCHANT_curl_easy_get_ (aph->url);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_curl_easy_post (&aph->post_ctx,
+ eh,
+ req_obj));
+ json_decref (req_obj);
+ aph->job = GNUNET_CURL_job_add2 (ctx,
+ eh,
+ aph->post_ctx.headers,
+ &handle_post_account_finished,
+ aph);
+ GNUNET_assert (NULL != aph->job);
+ }
+ return aph;
+}
+
+
+void
+TALER_MERCHANT_accounts_post_cancel (
+ struct TALER_MERCHANT_AccountsPostHandle *aph)
+{
+ if (NULL != aph->job)
+ {
+ GNUNET_CURL_job_cancel (aph->job);
+ aph->job = NULL;
+ }
+ TALER_curl_easy_post_finished (&aph->post_ctx);
+ GNUNET_free (aph->url);
+ GNUNET_free (aph);
+}
+
+
+/* end of merchant_api_post_account.c */
diff --git a/src/lib/merchant_api_post_instances.c b/src/lib/merchant_api_post_instances.c
index 183b3400..73d36369 100644
--- a/src/lib/merchant_api_post_instances.c
+++ b/src/lib/merchant_api_post_instances.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020 Taler Systems SA
+ Copyright (C) 2020-2023 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
@@ -32,6 +32,7 @@
#include "merchant_api_common.h"
#include <taler/taler_json_lib.h>
#include <taler/taler_curl_lib.h>
+#include <taler/taler_kyclogic_lib.h>
/**
@@ -163,14 +164,11 @@ TALER_MERCHANT_instances_post (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
const char *instance_id,
- unsigned int accounts_length,
- const char *payto_uris[],
const char *name,
+ enum TALER_KYCLOGIC_KycUserType ut,
const json_t *address,
const json_t *jurisdiction,
- const struct TALER_Amount *default_max_wire_fee,
- uint32_t default_wire_fee_amortization,
- const struct TALER_Amount *default_max_deposit_fee,
+ bool use_stefan,
struct GNUNET_TIME_Relative default_wire_transfer_delay,
struct GNUNET_TIME_Relative default_pay_delay,
const char *auth_token,
@@ -178,10 +176,16 @@ TALER_MERCHANT_instances_post (
void *cb_cls)
{
struct TALER_MERCHANT_InstancesPostHandle *iph;
- json_t *jpayto_uris;
json_t *req_obj;
json_t *auth_obj;
+ const char *uts;
+ uts = TALER_KYCLOGIC_kyc_user_type2s (ut);
+ if (NULL == uts)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
if (NULL != auth_token)
{
if (0 != strncasecmp (RFC_8959_PREFIX,
@@ -210,42 +214,19 @@ TALER_MERCHANT_instances_post (
GNUNET_break (0);
return NULL;
}
- jpayto_uris = json_array ();
- if (NULL == jpayto_uris)
- {
- json_decref (auth_obj);
- GNUNET_break (0);
- return NULL;
- }
- for (unsigned int i = 0; i<accounts_length; i++)
- {
- if (0 !=
- json_array_append_new (jpayto_uris,
- json_string (payto_uris[i])))
- {
- GNUNET_break (0);
- json_decref (auth_obj);
- json_decref (jpayto_uris);
- return NULL;
- }
- }
req_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("payto_uris",
- jpayto_uris),
GNUNET_JSON_pack_string ("id",
instance_id),
GNUNET_JSON_pack_string ("name",
name),
+ GNUNET_JSON_pack_string ("user_type",
+ uts),
GNUNET_JSON_pack_object_incref ("address",
(json_t *) address),
GNUNET_JSON_pack_object_incref ("jurisdiction",
(json_t *) jurisdiction),
- TALER_JSON_pack_amount ("default_max_wire_fee",
- default_max_wire_fee),
- GNUNET_JSON_pack_uint64 ("default_wire_fee_amortization",
- default_wire_fee_amortization),
- TALER_JSON_pack_amount ("default_max_deposit_fee",
- default_max_deposit_fee),
+ GNUNET_JSON_pack_bool ("use_stefan",
+ use_stefan),
GNUNET_JSON_pack_time_rel ("default_wire_transfer_delay",
default_wire_transfer_delay),
GNUNET_JSON_pack_time_rel ("default_pay_delay",
diff --git a/src/lib/merchant_api_post_order_abort.c b/src/lib/merchant_api_post_order_abort.c
index b5a7a00b..270ceb7e 100644
--- a/src/lib/merchant_api_post_order_abort.c
+++ b/src/lib/merchant_api_post_order_abort.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -39,6 +39,12 @@
/**
+ * Maximum number of refunds we return.
+ */
+#define MAX_REFUNDS 1024
+
+
+/**
* @brief An abort Handle
*/
struct TALER_MERCHANT_OrderAbortHandle
@@ -102,17 +108,20 @@ struct TALER_MERCHANT_OrderAbortHandle
* OK. Otherwise returns #GNUNET_SYSERR.
*
* @param oah handle to operation that created the reply
+ * @param[in] ar abort response, partially initialized
* @param json the reply to parse
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
check_abort_refund (struct TALER_MERCHANT_OrderAbortHandle *oah,
+ struct TALER_MERCHANT_AbortResponse *ar,
const json_t *json)
{
- json_t *refunds;
+ const json_t *refunds;
unsigned int num_refunds;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("refunds", &refunds),
+ GNUNET_JSON_spec_array_const ("refunds",
+ &refunds),
GNUNET_JSON_spec_end ()
};
@@ -124,13 +133,14 @@ check_abort_refund (struct TALER_MERCHANT_OrderAbortHandle *oah,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- if (! json_is_array (refunds))
+ num_refunds = (unsigned int) json_array_size (refunds);
+ if ( (json_array_size (refunds) != (size_t) num_refunds) ||
+ (num_refunds > MAX_REFUNDS) )
{
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
+ GNUNET_break (0);
return GNUNET_SYSERR;
}
- num_refunds = json_array_size (refunds);
+
{
struct TALER_MERCHANT_AbortedCoin res[GNUNET_NZL (num_refunds)];
@@ -150,7 +160,6 @@ check_abort_refund (struct TALER_MERCHANT_OrderAbortHandle *oah,
NULL, NULL))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
if (MHD_HTTP_OK == exchange_status)
@@ -169,7 +178,6 @@ check_abort_refund (struct TALER_MERCHANT_OrderAbortHandle *oah,
NULL, NULL))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
@@ -184,26 +192,17 @@ check_abort_refund (struct TALER_MERCHANT_OrderAbortHandle *oah,
&res[i].exchange_sig))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
}
}
- {
- struct TALER_MERCHANT_HttpResponse hr = {
- .reply = json,
- .http_status = MHD_HTTP_OK
- };
-
- oah->abort_cb (oah->abort_cb_cls,
- &hr,
- &oah->merchant_pub,
- num_refunds,
- res);
- }
+ ar->details.ok.merchant_pub = &oah->merchant_pub;
+ ar->details.ok.num_aborts = num_refunds;
+ ar->details.ok.aborts = res;
+ oah->abort_cb (oah->abort_cb_cls,
+ ar);
oah->abort_cb = NULL;
}
- GNUNET_JSON_parse_free (spec);
return GNUNET_OK;
}
@@ -223,9 +222,9 @@ handle_abort_finished (void *cls,
{
struct TALER_MERCHANT_OrderAbortHandle *oah = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_AbortResponse ar = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
oah->job = NULL;
@@ -235,40 +234,41 @@ handle_abort_finished (void *cls,
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ ar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
if (GNUNET_OK ==
check_abort_refund (oah,
+ &ar,
json))
{
TALER_MERCHANT_order_abort_cancel (oah);
return;
}
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ ar.hr.http_status = 0;
+ ar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_BAD_REQUEST:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ar.hr.ec = TALER_JSON_get_error_code (json);
+ ar.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_FORBIDDEN:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ar.hr.ec = TALER_JSON_get_error_code (json);
+ ar.hr.hint = TALER_JSON_get_error_hint (json);
break;
case MHD_HTTP_NOT_FOUND:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ar.hr.ec = TALER_JSON_get_error_code (json);
+ ar.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_REQUEST_TIMEOUT:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ar.hr.ec = TALER_JSON_get_error_code (json);
+ ar.hr.hint = TALER_JSON_get_error_hint (json);
/* Nothing really to verify, merchant says one of
the signatures is invalid; as we checked them,
this should never happen, we should pass the JSON
@@ -276,19 +276,19 @@ handle_abort_finished (void *cls,
break;
case MHD_HTTP_PRECONDITION_FAILED:
/* Our *payment* already succeeded fully. */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ar.hr.ec = TALER_JSON_get_error_code (json);
+ ar.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);
+ ar.hr.ec = TALER_JSON_get_error_code (json);
+ ar.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;
case MHD_HTTP_BAD_GATEWAY:
TALER_MERCHANT_parse_error_details_ (json,
response_code,
- &hr);
+ &ar.hr);
/* Nothing really to verify, the merchant is blaming the exchange.
We should pass the JSON reply to the application */
break;
@@ -296,33 +296,31 @@ handle_abort_finished (void *cls,
/* unexpected response code */
TALER_MERCHANT_parse_error_details_ (json,
response_code,
- &hr);
+ &ar.hr);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d\n",
(unsigned int) response_code,
- (int) hr.ec);
+ (int) ar.hr.ec);
GNUNET_break_op (0);
break;
}
oah->abort_cb (oah->abort_cb_cls,
- &hr,
- NULL,
- 0,
- NULL);
+ &ar);
TALER_MERCHANT_order_abort_cancel (oah);
}
struct TALER_MERCHANT_OrderAbortHandle *
-TALER_MERCHANT_order_abort (struct GNUNET_CURL_Context *ctx,
- const char *merchant_url,
- const char *order_id,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_PrivateContractHashP *h_contract,
- unsigned int num_coins,
- const struct TALER_MERCHANT_AbortCoin coins[],
- TALER_MERCHANT_AbortCallback cb,
- void *cb_cls)
+TALER_MERCHANT_order_abort (
+ struct GNUNET_CURL_Context *ctx,
+ const char *merchant_url,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_PrivateContractHashP *h_contract,
+ unsigned int num_coins,
+ const struct TALER_MERCHANT_AbortCoin coins[static num_coins],
+ TALER_MERCHANT_AbortCallback cb,
+ void *cb_cls)
{
struct TALER_MERCHANT_OrderAbortHandle *oah;
json_t *abort_obj;
@@ -389,9 +387,9 @@ TALER_MERCHANT_order_abort (struct GNUNET_CURL_Context *ctx,
oah->num_coins = num_coins;
oah->coins = GNUNET_new_array (num_coins,
struct TALER_MERCHANT_AbortCoin);
- memcpy (oah->coins,
- coins,
- num_coins * sizeof (struct TALER_MERCHANT_AbortCoin));
+ GNUNET_memcpy (oah->coins,
+ coins,
+ num_coins * sizeof (struct TALER_MERCHANT_AbortCoin));
{
CURL *eh;
diff --git a/src/lib/merchant_api_post_order_claim.c b/src/lib/merchant_api_post_order_claim.c
index 66e58c2a..76802ea5 100644
--- a/src/lib/merchant_api_post_order_claim.c
+++ b/src/lib/merchant_api_post_order_claim.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -86,40 +86,36 @@ handle_post_order_claim_finished (void *cls,
const void *response)
{
struct TALER_MERCHANT_OrderClaimHandle *och = cls;
- json_t *contract_terms;
- struct TALER_MerchantSignatureP sig;
- struct TALER_PrivateContractHashP hash;
const json_t *json = response;
+ struct TALER_MERCHANT_OrderClaimResponse ocr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("contract_terms",
- &contract_terms),
- GNUNET_JSON_spec_fixed_auto ("sig",
- &sig),
+ GNUNET_JSON_spec_object_const (
+ "contract_terms",
+ &ocr.details.ok.contract_terms),
+ GNUNET_JSON_spec_fixed_auto (
+ "sig",
+ &ocr.details.ok.sig),
GNUNET_JSON_spec_end ()
};
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
och->job = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Order claimed with status %u\n",
(unsigned int) response_code);
if (MHD_HTTP_OK != response_code)
{
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ocr.hr.ec = TALER_JSON_get_error_code (json);
+ ocr.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Proposal lookup failed with HTTP status code %u/%d\n",
(unsigned int) response_code,
- (int) hr.ec);
+ (int) ocr.hr.ec);
och->cb (och->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL);
+ &ocr);
TALER_MERCHANT_order_claim_cancel (och);
return;
}
@@ -132,39 +128,29 @@ handle_post_order_claim_finished (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Claiming order failed: could not parse JSON response\n");
GNUNET_break_op (0);
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- hr.http_status = 0;
+ ocr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ ocr.hr.http_status = 0;
och->cb (och->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL);
+ &ocr);
TALER_MERCHANT_order_claim_cancel (och);
return;
}
if (GNUNET_OK !=
- TALER_JSON_contract_hash (contract_terms,
- &hash))
+ TALER_JSON_contract_hash (ocr.details.ok.contract_terms,
+ &ocr.details.ok.h_contract_terms))
{
GNUNET_break (0);
- hr.ec = TALER_EC_MERCHANT_POST_ORDERS_ID_CLAIM_CLIENT_INTERNAL_FAILURE;
- hr.http_status = 0;
+ ocr.hr.ec = TALER_EC_MERCHANT_POST_ORDERS_ID_CLAIM_CLIENT_INTERNAL_FAILURE;
+ ocr.hr.http_status = 0;
GNUNET_JSON_parse_free (spec);
och->cb (och->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL);
+ &ocr);
TALER_MERCHANT_order_claim_cancel (och);
return;
}
-
och->cb (och->cb_cls,
- &hr,
- contract_terms,
- &sig,
- &hash);
+ &ocr);
GNUNET_JSON_parse_free (spec);
TALER_MERCHANT_order_claim_cancel (och);
}
diff --git a/src/lib/merchant_api_post_order_paid.c b/src/lib/merchant_api_post_order_paid.c
index a42b1255..785d956f 100644
--- a/src/lib/merchant_api_post_order_paid.c
+++ b/src/lib/merchant_api_post_order_paid.c
@@ -90,9 +90,9 @@ handle_paid_finished (void *cls,
{
struct TALER_MERCHANT_OrderPaidHandle *oph = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_OrderPaidResponse opr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
oph->job = NULL;
@@ -102,61 +102,81 @@ handle_paid_finished (void *cls,
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ opr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
- case MHD_HTTP_NO_CONTENT:
+ case MHD_HTTP_OK:
+ {
+ bool refunded;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_bool ("refunded",
+ &refunded),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (opr.hr.reply,
+ spec,
+ NULL,
+ NULL))
+ {
+ GNUNET_break_op (0);
+ opr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ break;
+ }
break;
case MHD_HTTP_BAD_REQUEST:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ opr.hr.ec = TALER_JSON_get_error_code (json);
+ opr.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_FORBIDDEN:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ opr.hr.ec = TALER_JSON_get_error_code (json);
+ opr.hr.hint = TALER_JSON_get_error_hint (json);
/* The signature provided was invalid */
break;
case MHD_HTTP_NOT_FOUND:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ opr.hr.ec = TALER_JSON_get_error_code (json);
+ opr.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);
+ opr.hr.ec = TALER_JSON_get_error_code (json);
+ opr.hr.hint = TALER_JSON_get_error_hint (json);
/* The hashed contract terms don't match with the order_id. */
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ opr.hr.ec = TALER_JSON_get_error_code (json);
+ opr.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;
case MHD_HTTP_SERVICE_UNAVAILABLE:
TALER_MERCHANT_parse_error_details_ (json,
response_code,
- &hr);
+ &opr.hr);
/* Exchange couldn't respond properly; the retry is
left to the application */
break;
default:
TALER_MERCHANT_parse_error_details_ (json,
response_code,
- &hr);
+ &opr.hr);
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d\n",
(unsigned int) response_code,
- (int) hr.ec);
+ (int) opr.hr.ec);
GNUNET_break_op (0);
break;
}
oph->paid_cb (oph->paid_cb_cls,
- &hr);
+ &opr);
TALER_MERCHANT_order_paid_cancel (oph);
}
@@ -168,6 +188,7 @@ TALER_MERCHANT_order_paid (
const char *order_id,
const char *session_id,
const struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct GNUNET_HashCode *wallet_data_hash,
const struct TALER_MerchantSignatureP *merchant_sig,
TALER_MERCHANT_OrderPaidCallback paid_cb,
void *paid_cb_cls)
@@ -180,6 +201,9 @@ TALER_MERCHANT_order_paid (
merchant_sig),
GNUNET_JSON_pack_data_auto ("h_contract",
h_contract_terms),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_data_auto ("wallet_data_hash",
+ wallet_data_hash)),
GNUNET_JSON_pack_string ("session_id",
session_id));
oph = GNUNET_new (struct TALER_MERCHANT_OrderPaidHandle);
diff --git a/src/lib/merchant_api_post_order_pay.c b/src/lib/merchant_api_post_order_pay.c
index 765ca1a6..57c85565 100644
--- a/src/lib/merchant_api_post_order_pay.c
+++ b/src/lib/merchant_api_post_order_pay.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -109,12 +109,6 @@ struct TALER_MERCHANT_OrderPayHandle
json_t *error_history;
/**
- * Handle to the exchange that issued a problematic
- * coin (if any).
- */
- struct TALER_EXCHANGE_Handle *exchange;
-
- /**
* Number of @e coins we are paying with.
*/
unsigned int num_coins;
@@ -129,248 +123,6 @@ struct TALER_MERCHANT_OrderPayHandle
/**
- * We got a 409 response back from the exchange (or the merchant).
- * Now we need to check the provided cryptographic proof that the
- * coin was actually already spent!
- *
- * @param oph operation handle
- * @param keys key data from the exchange
- * @return #GNUNET_OK if conflict is valid
- */
-static enum GNUNET_GenericReturnValue
-check_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
- const struct TALER_EXCHANGE_Keys *keys)
-{
- struct TALER_Amount spent;
- struct TALER_Amount spent_plus_contrib;
- struct TALER_DenominationHashP h_denom_pub_pc;
- const struct TALER_EXCHANGE_DenomPublicKey *dpk;
-
- TALER_denom_pub_hash (&oph->error_pc->denom_pub,
- &h_denom_pub_pc);
- dpk = TALER_EXCHANGE_get_denomination_key_by_hash (
- keys,
- &h_denom_pub_pc);
- if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (dpk,
- &oph->error_pc->coin_pub,
- oph->error_history,
- &spent))
- {
- /* Exchange's history fails to verify */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (0 >
- TALER_amount_add (&spent_plus_contrib,
- &spent,
- &oph->error_pc->amount_with_fee))
- {
- /* We got an integer overflow? Bad application! */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (-1 != TALER_amount_cmp (&oph->error_pc->denom_value,
- &spent_plus_contrib))
- {
- /* according to our calculations, the transaction should
- have still worked, AND we did not get any proof of
- coin public key re-use; hence: exchange error! */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Accepting proof of double-spending (or coin public key re-use)\n");
- return GNUNET_OK;
-}
-
-
-/**
- * We got the fee structure from the exchange. Now
- * validate the conflict error.
- *
- * @param cls a `struct TALER_MERCHANT_OrderPayHandle`
- * @param ehr reply from the exchange
- * @param keys the key structure
- * @param compat protocol compatibility indication
- */
-static void
-cert_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *ehr,
- const struct TALER_EXCHANGE_Keys *keys,
- enum TALER_EXCHANGE_VersionCompatibility compat)
-{
- struct TALER_MERCHANT_OrderPayHandle *oph = cls;
-
- if (TALER_EXCHANGE_VC_INCOMPATIBLE & compat)
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = MHD_HTTP_CONFLICT,
- .hr.exchange_http_status = 0,
- .hr.ec = TALER_EC_WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE,
- .hr.reply = oph->full_reply,
- .hr.exchange_reply = ehr->reply,
- .hr.hint = "could not check error: incompatible exchange version"
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- return;
- }
- if ( (MHD_HTTP_OK != ehr->http_status) ||
- (NULL == keys) )
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = MHD_HTTP_CONFLICT,
- .hr.exchange_http_status = ehr->http_status,
- .hr.ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- .hr.reply = oph->full_reply,
- .hr.exchange_reply = ehr->reply,
- .hr.hint = "failed to download /keys from the exchange"
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- return;
- }
-
- if (GNUNET_OK !=
- check_conflict (oph,
- keys))
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = 0,
- .hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE,
- .hr.reply = oph->full_reply
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- return;
- }
-
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = MHD_HTTP_CONFLICT,
- .hr.ec = TALER_JSON_get_error_code (oph->full_reply),
- .hr.reply = oph->full_reply
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- }
-}
-
-
-/**
- * We got a 409 response back from the exchange (or the merchant).
- * Now we need to check the provided cryptograophic proof that the
- * coin was actually already spent!
- *
- * @param[in,out] oph handle of the original pay operation
- * @param[in,out] pr response to modify if #GNUNET_OK is returned
- * @param json cryptograophic proof returned by the
- * exchange/merchant
- * @return #GNUNET_OK if proof checks out,
- * #GNUNET_SYSERR if it is wrong,
- * #GNUNET_NO if checking continues asynchronously
- */
-static enum GNUNET_GenericReturnValue
-parse_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
- struct TALER_MERCHANT_PayResponse *pr,
- const json_t *json)
-{
- json_t *ereply;
- const char *exchange_url;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("exchange_reply",
- &ereply),
- GNUNET_JSON_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_JSON_Specification hspec[] = {
- GNUNET_JSON_spec_json ("history",
- &oph->error_history),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &coin_pub),
- GNUNET_JSON_spec_end ()
- };
- enum TALER_ErrorCode ec = TALER_JSON_get_error_code (json);
-
- switch (ec)
- {
- case TALER_EC_GENERIC_CURRENCY_MISMATCH:
- /* no proof to check, still very strange, as we
- should have checked that the currency matches */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- MHD_HTTP_CONFLICT,
- &pr->hr);
- return GNUNET_OK;
- case TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID:
- /* We can only be happy and accept the result;
- FIXME: parse the refunds... */
- TALER_MERCHANT_parse_error_details_ (json,
- MHD_HTTP_CONFLICT,
- &pr->hr);
- return GNUNET_OK;
- case TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_FUNDS:
- /* main case, handled below */
- break;
- default:
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_JSON_parse (ereply,
- hspec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return GNUNET_SYSERR;
- }
- GNUNET_JSON_parse_free (spec);
-
- for (unsigned int i = 0; i<oph->num_coins; i++)
- {
- if (0 ==
- GNUNET_memcmp (&oph->coins[i].coin_pub,
- &coin_pub))
- {
- oph->error_pc = &oph->coins[i];
- oph->full_reply = json_incref ((json_t *) json);
- oph->exchange = TALER_EXCHANGE_connect (oph->ctx,
- oph->error_pc->exchange_url,
- &cert_cb,
- oph,
- TALER_EXCHANGE_OPTION_END);
- return GNUNET_NO;
- }
- }
- GNUNET_break_op (0); /* complaint is not about any of the coins
- that we actually paid with... */
- GNUNET_JSON_parse_free (hspec);
- return GNUNET_SYSERR;
-}
-
-
-/**
* Function called when we're done processing the
* HTTP /pay request.
*
@@ -406,7 +158,12 @@ handle_pay_finished (void *cls,
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto (
"sig",
- &pr.details.success.merchant_sig),
+ &pr.details.ok.merchant_sig),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string (
+ "pos_confirmation",
+ &pr.details.ok.pos_confirmation),
+ NULL),
GNUNET_JSON_spec_end ()
};
@@ -425,7 +182,7 @@ handle_pay_finished (void *cls,
if (GNUNET_OK !=
TALER_merchant_pay_verify (&oph->h_contract_terms,
&oph->merchant_pub,
- &pr.details.success.merchant_sig))
+ &pr.details.ok.merchant_sig))
{
GNUNET_break_op (0);
pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
@@ -475,27 +232,10 @@ handle_pay_finished (void *cls,
Pass on to application. */
break;
case MHD_HTTP_CONFLICT:
- {
- enum GNUNET_GenericReturnValue ret;
-
- ret = parse_conflict (oph,
- &pr,
- json);
- switch (ret)
- {
- case GNUNET_OK:
- /* continued below, 'pr' was modified */
- break;
- case GNUNET_NO:
- /* handled asynchronously! */
- return; /* ! */
- case GNUNET_SYSERR:
- GNUNET_break_op (0);
- response_code = 0;
- break;
- }
- break;
- }
+ TALER_MERCHANT_parse_error_details_ (json,
+ MHD_HTTP_CONFLICT,
+ &pr.hr);
+ break;
case MHD_HTTP_GONE:
TALER_MERCHANT_parse_error_details_ (json,
response_code,
@@ -565,8 +305,9 @@ TALER_MERCHANT_order_pay_frontend (
const char *merchant_url,
const char *order_id,
const char *session_id,
+ const json_t *wallet_data,
unsigned int num_coins,
- const struct TALER_MERCHANT_PaidCoin coins[],
+ const struct TALER_MERCHANT_PaidCoin coins[static num_coins],
TALER_MERCHANT_OrderPayCallback pay_cb,
void *pay_cb_cls)
{
@@ -655,6 +396,9 @@ TALER_MERCHANT_order_pay_frontend (
GNUNET_JSON_pack_array_steal ("coins",
j_coins),
GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("wallet_data",
+ (json_t *) wallet_data)),
+ GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("session_id",
session_id)));
@@ -684,9 +428,9 @@ TALER_MERCHANT_order_pay_frontend (
oph->num_coins = num_coins;
oph->coins = GNUNET_new_array (num_coins,
struct TALER_MERCHANT_PaidCoin);
- memcpy (oph->coins,
- coins,
- num_coins * sizeof (struct TALER_MERCHANT_PaidCoin));
+ GNUNET_memcpy (oph->coins,
+ coins,
+ num_coins * sizeof (struct TALER_MERCHANT_PaidCoin));
eh = TALER_MERCHANT_curl_easy_get_ (oph->url);
if (GNUNET_OK !=
@@ -717,6 +461,7 @@ TALER_MERCHANT_order_pay (
const char *merchant_url,
const char *session_id,
const struct TALER_PrivateContractHashP *h_contract_terms,
+ const json_t *wallet_data,
const struct TALER_Amount *amount,
const struct TALER_Amount *max_fee,
const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -727,10 +472,12 @@ TALER_MERCHANT_order_pay (
const struct TALER_MerchantWireHashP *h_wire,
const char *order_id,
unsigned int num_coins,
- const struct TALER_MERCHANT_PayCoin coins[],
+ const struct TALER_MERCHANT_PayCoin coins[static num_coins],
TALER_MERCHANT_OrderPayCallback pay_cb,
void *pay_cb_cls)
{
+ struct GNUNET_HashCode wallet_data_hash;
+
if (GNUNET_YES !=
TALER_amount_cmp_currency (amount,
max_fee))
@@ -738,7 +485,9 @@ TALER_MERCHANT_order_pay (
GNUNET_break (0);
return NULL;
}
-
+ if (NULL != wallet_data)
+ TALER_json_hash (wallet_data,
+ &wallet_data_hash);
{
struct TALER_MERCHANT_PaidCoin pc[num_coins];
@@ -765,6 +514,9 @@ TALER_MERCHANT_order_pay (
&fee,
h_wire,
h_contract_terms,
+ (NULL != wallet_data)
+ ? &wallet_data_hash
+ : NULL,
coin->h_age_commitment,
NULL /* h_extensions! */,
&h_denom_pub,
@@ -789,6 +541,7 @@ TALER_MERCHANT_order_pay (
merchant_url,
order_id,
session_id,
+ wallet_data,
num_coins,
pc,
pay_cb,
@@ -812,11 +565,6 @@ TALER_MERCHANT_order_pay_cancel (struct TALER_MERCHANT_OrderPayHandle *oph)
GNUNET_CURL_job_cancel (oph->job);
oph->job = NULL;
}
- if (NULL != oph->exchange)
- {
- TALER_EXCHANGE_disconnect (oph->exchange);
- oph->exchange = NULL;
- }
TALER_curl_easy_post_finished (&oph->post_ctx);
json_decref (oph->error_history);
json_decref (oph->full_reply);
diff --git a/src/lib/merchant_api_post_order_refund.c b/src/lib/merchant_api_post_order_refund.c
index be996dc2..4414bd86 100644
--- a/src/lib/merchant_api_post_order_refund.c
+++ b/src/lib/merchant_api_post_order_refund.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -85,30 +85,26 @@ handle_refund_finished (void *cls,
{
struct TALER_MERCHANT_OrderRefundHandle *orh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_RefundResponse rr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
orh->job = NULL;
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL);
+ rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
- const char *taler_refund_uri;
- struct TALER_PrivateContractHashP h_contract;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("taler_refund_uri",
- &taler_refund_uri),
- GNUNET_JSON_spec_fixed_auto ("h_contract",
- &h_contract),
+ GNUNET_JSON_spec_string (
+ "taler_refund_uri",
+ &rr.details.ok.taler_refund_uri),
+ GNUNET_JSON_spec_fixed_auto (
+ "h_contract",
+ &rr.details.ok.h_contract),
GNUNET_JSON_spec_end ()
};
@@ -118,51 +114,36 @@ handle_refund_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL);
+ rr.hr.http_status = 0;
+ rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
- orh->cb (orh->cb_cls,
- &hr,
- taler_refund_uri,
- &h_contract);
- GNUNET_JSON_parse_free (spec);
+ break;
}
- break;
case MHD_HTTP_UNAUTHORIZED:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ rr.hr.ec = TALER_JSON_get_error_code (json);
+ rr.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);
+ rr.hr.ec = TALER_JSON_get_error_code (json);
+ rr.hr.hint = TALER_JSON_get_error_hint (json);
/* Nothing really to verify, merchant says we need to authenticate. */
break;
case MHD_HTTP_NOT_FOUND:
case MHD_HTTP_CONFLICT:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL);
+ rr.hr.ec = TALER_JSON_get_error_code (json);
+ rr.hr.hint = TALER_JSON_get_error_hint (json);
break;
default:
GNUNET_break_op (0); /* unexpected status code */
TALER_MERCHANT_parse_error_details_ (json,
response_code,
- &hr);
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL);
+ &rr.hr);
break;
}
+ orh->cb (orh->cb_cls,
+ &rr);
TALER_MERCHANT_post_order_refund_cancel (orh);
}
diff --git a/src/lib/merchant_api_post_orders.c b/src/lib/merchant_api_post_orders.c
index c0fd5fcb..56881133 100644
--- a/src/lib/merchant_api_post_orders.c
+++ b/src/lib/merchant_api_post_orders.c
@@ -92,9 +92,9 @@ handle_post_order_finished (void *cls,
po->job = NULL;
TALER_MERCHANT_handle_order_creation_response_ (po->cb,
- po->cb_cls,
- response_code,
- json);
+ po->cb_cls,
+ response_code,
+ json);
TALER_MERCHANT_orders_post_cancel (po);
}
@@ -107,6 +107,8 @@ TALER_MERCHANT_orders_post (struct GNUNET_CURL_Context *ctx,
TALER_MERCHANT_PostOrdersCallback cb,
void *cb_cls)
{
+ static const char *no_uuids[GNUNET_NZL (0)];
+
return TALER_MERCHANT_orders_post2 (ctx,
backend_url,
order,
@@ -115,7 +117,7 @@ TALER_MERCHANT_orders_post (struct GNUNET_CURL_Context *ctx,
0,
NULL,
0,
- NULL,
+ no_uuids,
true,
cb,
cb_cls);
@@ -132,7 +134,40 @@ TALER_MERCHANT_orders_post2 (
unsigned int inventory_products_length,
const struct TALER_MERCHANT_InventoryProduct inventory_products[],
unsigned int uuids_length,
- const char *uuids[],
+ const char *uuids[static uuids_length],
+ bool create_token,
+ TALER_MERCHANT_PostOrdersCallback cb,
+ void *cb_cls)
+{
+ return TALER_MERCHANT_orders_post3 (
+ ctx,
+ backend_url,
+ order,
+ NULL, /* session ID */
+ refund_delay,
+ payment_target,
+ inventory_products_length,
+ inventory_products,
+ uuids_length,
+ uuids,
+ create_token,
+ cb,
+ cb_cls);
+}
+
+
+struct TALER_MERCHANT_PostOrdersHandle *
+TALER_MERCHANT_orders_post3 (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const json_t *order,
+ const char *session_id,
+ struct GNUNET_TIME_Relative refund_delay,
+ const char *payment_target,
+ unsigned int inventory_products_length,
+ const struct TALER_MERCHANT_InventoryProduct inventory_products[],
+ unsigned int uuids_length,
+ const char *uuids[static uuids_length],
bool create_token,
TALER_MERCHANT_PostOrdersCallback cb,
void *cb_cls)
@@ -152,6 +187,9 @@ TALER_MERCHANT_orders_post2 (
GNUNET_JSON_pack_object_incref ("order",
(json_t *) order),
GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("session_id",
+ session_id)),
+ GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("payment_target",
payment_target)));
if (0 != refund_delay.rel_value_us)
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_products.c b/src/lib/merchant_api_post_products.c
index 2a5b9a9b..0f09f397 100644
--- a/src/lib/merchant_api_post_products.c
+++ b/src/lib/merchant_api_post_products.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020-2021 Taler Systems SA
+ Copyright (C) 2020-2024 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
@@ -159,7 +159,7 @@ handle_post_products_finished (void *cls,
struct TALER_MERCHANT_ProductsPostHandle *
-TALER_MERCHANT_products_post (
+TALER_MERCHANT_products_post2 (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
const char *product_id,
@@ -172,6 +172,7 @@ TALER_MERCHANT_products_post (
int64_t total_stock,
const json_t *address,
struct GNUNET_TIME_Timestamp next_restock,
+ uint32_t minimum_age,
TALER_MERCHANT_ProductsPostCallback cb,
void *cb_cls)
{
@@ -183,20 +184,26 @@ TALER_MERCHANT_products_post (
product_id),
GNUNET_JSON_pack_string ("description",
description),
- GNUNET_JSON_pack_object_incref ("description_i18n",
- (json_t *) description_i18n),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("description_i18n",
+ (json_t *) description_i18n)),
GNUNET_JSON_pack_string ("unit",
unit),
TALER_JSON_pack_amount ("price",
price),
GNUNET_JSON_pack_string ("image",
image),
- GNUNET_JSON_pack_array_incref ("taxes",
- (json_t *) taxes),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_array_incref ("taxes",
+ (json_t *) taxes)),
GNUNET_JSON_pack_uint64 ("total_stock",
total_stock),
- GNUNET_JSON_pack_object_incref ("address",
- (json_t *) address),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_uint64 ("minimum_age",
+ minimum_age)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("address",
+ (json_t *) address)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_timestamp ("next_restock",
next_restock)));
@@ -235,6 +242,41 @@ TALER_MERCHANT_products_post (
}
+struct TALER_MERCHANT_ProductsPostHandle *
+TALER_MERCHANT_products_post (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *product_id,
+ const char *description,
+ const json_t *description_i18n,
+ const char *unit,
+ const struct TALER_Amount *price,
+ const char *image,
+ const json_t *taxes,
+ int64_t total_stock,
+ const json_t *address,
+ struct GNUNET_TIME_Timestamp next_restock,
+ TALER_MERCHANT_ProductsPostCallback cb,
+ void *cb_cls)
+{
+ return TALER_MERCHANT_products_post2 (ctx,
+ backend_url,
+ product_id,
+ description,
+ description_i18n,
+ unit,
+ price,
+ image,
+ taxes,
+ total_stock,
+ address,
+ next_restock,
+ 0,
+ cb,
+ cb_cls);
+}
+
+
void
TALER_MERCHANT_products_post_cancel (
struct TALER_MERCHANT_ProductsPostHandle *pph)
diff --git a/src/lib/merchant_api_post_reserves.c b/src/lib/merchant_api_post_reserves.c
deleted file mode 100644
index 65239dfb..00000000
--- a/src/lib/merchant_api_post_reserves.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015, 2016, 2020 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_reserves.c
- * @brief Implementation of the POST /reserves request of the merchant's HTTP API
- * @author Marcello Stanisci
- * @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_curl_lib.h>
-#include <taler/taler_json_lib.h>
-
-
-/**
- * @brief A handle for POSTing reserve data.
- */
-struct TALER_MERCHANT_PostReservesHandle
-{
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_PostReservesCallback 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 /reserves request.
- *
- * @param cls the `struct TALER_MERCHANT_PostReservesHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_post_reserves_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_PostReservesHandle *prh = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
-
- prh->job = NULL;
- switch (response_code)
- {
- case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- case MHD_HTTP_OK:
- {
- const char *payto_uri;
- struct TALER_ReservePublicKeyP reserve_pub;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("reserve_pub",
- &reserve_pub),
- GNUNET_JSON_spec_string ("payto_uri",
- &payto_uri),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- else
- {
- prh->cb (prh->cb_cls,
- &hr,
- &reserve_pub,
- payto_uri);
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_reserves_post_cancel (prh);
- return;
- }
- }
- case MHD_HTTP_ACCEPTED:
- 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:
- /* Nothing really to verify, this should never
- happen, we should pass the JSON reply to the application */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Did not find any data\n");
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) hr.ec);
- break;
- }
- prh->cb (prh->cb_cls,
- &hr,
- NULL,
- NULL);
- TALER_MERCHANT_reserves_post_cancel (prh);
-}
-
-
-struct TALER_MERCHANT_PostReservesHandle *
-TALER_MERCHANT_reserves_post (
- struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_Amount *initial_balance,
- const char *exchange_url,
- const char *wire_method,
- TALER_MERCHANT_PostReservesCallback cb,
- void *cb_cls)
-{
- struct TALER_MERCHANT_PostReservesHandle *prh;
- CURL *eh;
- json_t *req;
-
- prh = GNUNET_new (struct TALER_MERCHANT_PostReservesHandle);
- prh->ctx = ctx;
- prh->cb = cb;
- prh->cb_cls = cb_cls;
- prh->url = TALER_url_join (backend_url,
- "private/reserves",
- NULL);
- if (NULL == prh->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- GNUNET_free (prh);
- return NULL;
- }
- req = GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("initial_balance",
- initial_balance),
- GNUNET_JSON_pack_string ("wire_method",
- wire_method),
- GNUNET_JSON_pack_string ("exchange_url",
- exchange_url));
- eh = TALER_MERCHANT_curl_easy_get_ (prh->url);
- if (GNUNET_OK !=
- TALER_curl_easy_post (&prh->post_ctx,
- eh,
- req))
- {
- GNUNET_break (0);
- curl_easy_cleanup (eh);
- json_decref (req);
- GNUNET_free (prh->url);
- GNUNET_free (prh);
- return NULL;
- }
- json_decref (req);
- prh->job = GNUNET_CURL_job_add2 (ctx,
- eh,
- prh->post_ctx.headers,
- &handle_post_reserves_finished,
- prh);
- return prh;
-}
-
-
-void
-TALER_MERCHANT_reserves_post_cancel (
- struct TALER_MERCHANT_PostReservesHandle *prh)
-{
- if (NULL != prh->job)
- {
- GNUNET_CURL_job_cancel (prh->job);
- prh->job = NULL;
- }
- GNUNET_free (prh->url);
- TALER_curl_easy_post_finished (&prh->post_ctx);
- GNUNET_free (prh);
-}
-
-
-/* end of merchant_api_post_reserves.c */
diff --git a/src/lib/merchant_api_post_templates.c b/src/lib/merchant_api_post_templates.c
index 9592a5e3..3ab4320c 100644
--- a/src/lib/merchant_api_post_templates.c
+++ b/src/lib/merchant_api_post_templates.c
@@ -129,6 +129,10 @@ handle_post_templates_finished (void *cls,
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);
@@ -199,7 +203,7 @@ TALER_MERCHANT_templates_post (
const char *backend_url,
const char *template_id,
const char *template_description,
- const char *image,
+ const char *otp_id,
const json_t *template_contract,
TALER_MERCHANT_TemplatesPostCallback cb,
void *cb_cls)
@@ -218,8 +222,8 @@ TALER_MERCHANT_templates_post (
GNUNET_JSON_pack_string ("template_description",
template_description),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("image",
- image)),
+ 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/lib/merchant_api_post_tokenfamilies.c b/src/lib/merchant_api_post_tokenfamilies.c
new file mode 100644
index 00000000..0c5e18c2
--- /dev/null
+++ b/src/lib/merchant_api_post_tokenfamilies.c
@@ -0,0 +1,246 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020-2024 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_tokenfamilies.c
+ * @brief Implementation of the POST /tokenfamilies request
+ * of the merchant's HTTP API
+ * @author Christian Blättler
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <gnunet/gnunet_time_lib.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 /tokenfamilies operation.
+ */
+struct TALER_MERCHANT_TokenFamiliesPostHandle
+{
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_TokenFamiliesPostCallback 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 /tokenfamilies request.
+ *
+ * @param cls the `struct TALER_MERCHANT_TokenFamiliesPostHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_post_token_families_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_TokenFamiliesPostHandle *handle = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = (unsigned int) response_code,
+ .reply = json
+ };
+
+ handle->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "POST /tokenfamilies 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;
+ }
+ handle->cb (handle->cb_cls,
+ &hr);
+ TALER_MERCHANT_token_families_post_cancel (handle);
+}
+
+struct TALER_MERCHANT_TokenFamiliesPostHandle *
+TALER_MERCHANT_token_families_post (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *slug,
+ const char *name,
+ const char *description,
+ const json_t *description_i18n,
+ struct GNUNET_TIME_Timestamp valid_after,
+ struct GNUNET_TIME_Timestamp valid_before,
+ struct GNUNET_TIME_Relative duration,
+ const char *kind,
+ TALER_MERCHANT_TokenFamiliesPostCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_TokenFamiliesPostHandle *handle;
+ json_t *req_obj;
+
+ req_obj = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("slug",
+ slug),
+ GNUNET_JSON_pack_string ("name",
+ name),
+ GNUNET_JSON_pack_string ("description",
+ description),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("description_i18n",
+ (json_t *) description_i18n)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_timestamp ("valid_after",
+ valid_after)),
+ GNUNET_JSON_pack_timestamp ("valid_before",
+ valid_before),
+ GNUNET_JSON_pack_time_rel ("duration",
+ duration),
+ GNUNET_JSON_pack_string ("kind",
+ kind));
+ handle = GNUNET_new (struct TALER_MERCHANT_TokenFamiliesPostHandle);
+ handle->ctx = ctx;
+ handle->cb = cb;
+ handle->cb_cls = cb_cls;
+ handle->url = TALER_url_join (backend_url,
+ "private/tokenfamilies",
+ NULL);
+ if (NULL == handle->url)
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ json_decref (req_obj);
+ GNUNET_free (handle);
+ return NULL;
+ }
+ {
+ CURL *eh;
+
+ eh = TALER_MERCHANT_curl_easy_get_ (handle->url);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_curl_easy_post (&handle->post_ctx,
+ eh,
+ req_obj));
+ json_decref (req_obj);
+ handle->job = GNUNET_CURL_job_add2 (ctx,
+ eh,
+ handle->post_ctx.headers,
+ &handle_post_token_families_finished,
+ handle);
+ GNUNET_assert (NULL != handle->job);
+ }
+ return handle;
+}
+
+
+void
+TALER_MERCHANT_token_families_post_cancel (
+ struct TALER_MERCHANT_TokenFamiliesPostHandle *pph)
+{
+ if (NULL != pph->job)
+ {
+ GNUNET_CURL_job_cancel (pph->job);
+ pph->job = NULL;
+ }
+ TALER_curl_easy_post_finished (&pph->post_ctx);
+ GNUNET_free (pph->url);
+ GNUNET_free (pph);
+}
diff --git a/src/lib/merchant_api_post_transfers.c b/src/lib/merchant_api_post_transfers.c
index 450b46d9..615453fa 100644
--- a/src/lib/merchant_api_post_transfers.c
+++ b/src/lib/merchant_api_post_transfers.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -85,116 +85,22 @@ handle_post_transfers_finished (void *cls,
const void *response)
{
struct TALER_MERCHANT_PostTransfersHandle *pth = cls;
- const json_t *json = response;
- json_t *deposit_sum = NULL;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_PostTransfersResponse ptr = {
+ .hr.reply = response,
+ .hr.http_status = (unsigned int) response_code
};
pth->job = NULL;
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ ptr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
- case MHD_HTTP_OK:
- {
- struct TALER_Amount total;
- struct TALER_Amount wire_fee;
- struct GNUNET_TIME_Timestamp execution_time;
- json_t *deposit_sums;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("total",
- &total),
- TALER_JSON_spec_amount_any ("wire_fee",
- &wire_fee),
- GNUNET_JSON_spec_timestamp ("execution_time",
- &execution_time),
- GNUNET_JSON_spec_json ("deposit_sums",
- &deposit_sums),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- else
- {
- size_t deposit_sums_length;
- struct TALER_MERCHANT_TrackTransferDetail *details;
- unsigned int i;
- bool ok;
-
- if (! json_is_array (deposit_sums))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- deposit_sums_length = json_array_size (deposit_sums);
- details = GNUNET_new_array (deposit_sums_length,
- struct TALER_MERCHANT_TrackTransferDetail);
- ok = true;
- json_array_foreach (deposit_sums, i, deposit_sum) {
- struct TALER_MERCHANT_TrackTransferDetail *d = &details[i];
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_string ("order_id",
- &d->order_id),
- TALER_JSON_spec_amount_any ("deposit_value",
- &d->deposit_value),
- TALER_JSON_spec_amount_any ("deposit_fee",
- &d->deposit_fee),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (deposit_sum,
- ispec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- ok = false;
- break;
- }
- }
-
- if (! ok)
- {
- GNUNET_break_op (0);
- GNUNET_free (details);
- GNUNET_JSON_parse_free (spec);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- pth->cb (pth->cb_cls,
- &hr,
- execution_time,
- &total,
- &wire_fee,
- deposit_sums_length,
- details);
- GNUNET_free (details);
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_transfers_post_cancel (pth);
- return;
- }
- }
- case MHD_HTTP_ACCEPTED:
+ 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);
+ ptr.hr.ec = TALER_JSON_get_error_code (ptr.hr.reply);
+ ptr.hr.hint = TALER_JSON_get_error_hint (ptr.hr.reply);
/* Nothing really to verify, merchant says we need to authenticate. */
break;
case MHD_HTTP_NOT_FOUND:
@@ -202,44 +108,47 @@ handle_post_transfers_finished (void *cls,
happen, we should pass the JSON reply to the application */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Did not find any data\n");
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ptr.hr.ec = TALER_JSON_get_error_code (ptr.hr.reply);
+ ptr.hr.hint = TALER_JSON_get_error_hint (ptr.hr.reply);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ptr.hr.ec = TALER_JSON_get_error_code (ptr.hr.reply);
+ ptr.hr.hint = TALER_JSON_get_error_hint (ptr.hr.reply);
break;
case MHD_HTTP_BAD_GATEWAY:
/* Exchange had an issue; we should retry, but this API
leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ptr.hr.ec = TALER_JSON_get_error_code (ptr.hr.reply);
+ ptr.hr.hint = TALER_JSON_get_error_hint (ptr.hr.reply);
{
- uint32_t eec;
uint32_t ehc;
struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_uint32 ("exchange_code",
- &eec),
+ TALER_JSON_spec_ec ("exchange_code",
+ &ptr.details.bad_gateway.exchange_ec),
GNUNET_JSON_spec_uint32 ("exchange_http_status",
&ehc),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
- GNUNET_JSON_parse (deposit_sum,
+ GNUNET_JSON_parse (ptr.hr.reply,
ispec,
NULL, NULL))
{
GNUNET_break_op (0);
+ ptr.details.bad_gateway.exchange_http_status = 0;
+ ptr.details.bad_gateway.exchange_ec = TALER_EC_NONE;
break;
}
else
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ ptr.details.bad_gateway.exchange_http_status
+ = (unsigned int) ehc;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Exchange returned %u/%u\n",
- (unsigned int) eec,
+ (unsigned int) ptr.details.bad_gateway.exchange_ec,
(unsigned int) ehc);
}
}
@@ -247,28 +156,23 @@ handle_post_transfers_finished (void *cls,
case MHD_HTTP_GATEWAY_TIMEOUT:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ ptr.hr.ec = TALER_JSON_get_error_code (ptr.hr.reply);
+ ptr.hr.hint = TALER_JSON_get_error_hint (ptr.hr.reply);
break;
default:
/* unexpected response code */
GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
+ TALER_MERCHANT_parse_error_details_ (ptr.hr.reply,
response_code,
- &hr);
+ &ptr.hr);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) hr.ec);
+ (unsigned int) ptr.hr.http_status,
+ (int) ptr.hr.ec);
break;
}
pth->cb (pth->cb_cls,
- &hr,
- GNUNET_TIME_UNIT_FOREVER_TS,
- NULL,
- NULL,
- 0,
- NULL);
+ &ptr);
TALER_MERCHANT_transfers_post_cancel (pth);
}
diff --git a/src/lib/merchant_api_post_using_templates.c b/src/lib/merchant_api_post_using_templates.c
index d72768f3..f09c34cb 100644
--- a/src/lib/merchant_api_post_using_templates.c
+++ b/src/lib/merchant_api_post_using_templates.c
@@ -89,9 +89,9 @@ handle_post_using_templates_finished (void *cls,
utph->job = NULL;
TALER_MERCHANT_handle_order_creation_response_ (utph->cb,
- utph->cb_cls,
- response_code,
- json);
+ utph->cb_cls,
+ response_code,
+ json);
TALER_MERCHANT_using_templates_post_cancel (utph);
}
diff --git a/src/lib/merchant_api_tip_authorize.c b/src/lib/merchant_api_tip_authorize.c
deleted file mode 100644
index 036d40af..00000000
--- a/src/lib/merchant_api_tip_authorize.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2017, 2020, 2021 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_tip_authorize.c
- * @brief Implementation of the /tip-authorize request of the merchant's HTTP API
- * @author Marcello Stanisci
- * @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 "merchant_api_common.h"
-#include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_curl_lib.h>
-
-
-/**
- * @brief A handle for tip authorizations.
- */
-struct TALER_MERCHANT_TipAuthorizeHandle
-{
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_TipAuthorizeCallback 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;
-};
-
-
-/**
- * We got a 200 response back from the exchange (or the merchant).
- * Now we need to parse the response and if it is well-formed,
- * call the callback (and set it to NULL afterwards).
- *
- * @param tao handle of the original authorization operation
- * @param json cryptographic proof returned by the exchange/merchant
- * @return #GNUNET_OK if response is valid
- */
-static int
-check_ok (struct TALER_MERCHANT_TipAuthorizeHandle *tao,
- const json_t *json)
-{
- const char *tip_status_url;
- const char *taler_tip_uri;
- struct TALER_TipIdentifierP tip_id;
- struct GNUNET_TIME_Timestamp expiration_time;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("tip_status_url", &tip_status_url),
- GNUNET_JSON_spec_string ("taler_tip_uri", &taler_tip_uri),
- GNUNET_JSON_spec_timestamp ("tip_expiration", &expiration_time),
- GNUNET_JSON_spec_fixed_auto ("tip_id", &tip_id),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK,
- .reply = json
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- char *log;
-
- GNUNET_break_op (0);
- log = json_dumps (json,
- 0);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "JSON %s\n",
- log);
- free (log);
- return GNUNET_SYSERR;
- }
- tao->cb (tao->cb_cls,
- &hr,
- &tip_id,
- taler_tip_uri,
- expiration_time);
- tao->cb = NULL; /* do not call twice */
- GNUNET_JSON_parse_free (spec);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /reservers/$TIP_ID/tip-authorize request.
- *
- * @param cls the `struct TALER_MERCHANT_TipAuthorizeHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_tip_authorize_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_TipAuthorizeHandle *tao = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
-
- tao->job = NULL;
- switch (response_code)
- {
- case MHD_HTTP_OK:
- if (GNUNET_OK ==
- check_ok (tao,
- json))
- {
- TALER_MERCHANT_tip_authorize_cancel (tao);
- return;
- }
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- 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:
- /* Well-defined status code, pass on to application! */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_PRECONDITION_FAILED:
- /* Well-defined status code, pass on to application! */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_SERVICE_UNAVAILABLE:
- /* Server had an unclear (internal or external) issue; we should retry,
- but this API leaves this to the application */
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) hr.ec);
- break;
- }
- if (NULL != tao->cb)
- tao->cb (tao->cb_cls,
- &hr,
- NULL,
- NULL,
- GNUNET_TIME_UNIT_ZERO_TS);
- TALER_MERCHANT_tip_authorize_cancel (tao);
-}
-
-
-struct TALER_MERCHANT_TipAuthorizeHandle *
-TALER_MERCHANT_tip_authorize2 (
- struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const char *next_url,
- const struct TALER_Amount *amount,
- const char *justification,
- TALER_MERCHANT_TipAuthorizeCallback authorize_cb,
- void *authorize_cb_cls)
-{
- struct TALER_MERCHANT_TipAuthorizeHandle *tao;
- CURL *eh;
- json_t *te_obj;
-
- tao = GNUNET_new (struct TALER_MERCHANT_TipAuthorizeHandle);
- tao->ctx = ctx;
- tao->cb = authorize_cb;
- tao->cb_cls = authorize_cb_cls;
-
- {
- char res_str[sizeof (*reserve_pub) * 2];
- char arg_str[sizeof (res_str) + 48];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (reserve_pub,
- sizeof (*reserve_pub),
- res_str,
- sizeof (res_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "private/reserves/%s/authorize-tip",
- res_str);
- tao->url = TALER_url_join (backend_url,
- arg_str,
- NULL);
- }
- if (NULL == tao->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- GNUNET_free (tao);
- return NULL;
- }
- te_obj = GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("amount",
- amount),
- GNUNET_JSON_pack_string ("justification",
- justification),
- GNUNET_JSON_pack_string ("next_url",
- next_url));
- eh = curl_easy_init ();
- GNUNET_assert (NULL != eh);
- if (GNUNET_OK !=
- TALER_curl_easy_post (&tao->post_ctx,
- eh,
- te_obj))
- {
- GNUNET_break (0);
- curl_easy_cleanup (eh);
- json_decref (te_obj);
- GNUNET_free (tao->url);
- GNUNET_free (tao);
- return NULL;
- }
-
- json_decref (te_obj);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting URL '%s'\n",
- tao->url);
- GNUNET_assert (CURLE_OK == curl_easy_setopt (eh,
- CURLOPT_URL,
- tao->url));
-
- tao->job = GNUNET_CURL_job_add2 (ctx,
- eh,
- tao->post_ctx.headers,
- &handle_tip_authorize_finished,
- tao);
- return tao;
-}
-
-
-struct TALER_MERCHANT_TipAuthorizeHandle *
-TALER_MERCHANT_tip_authorize (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const char *next_url,
- const struct TALER_Amount *amount,
- const char *justification,
- TALER_MERCHANT_TipAuthorizeCallback authorize_cb,
- void *authorize_cb_cls)
-{
- struct TALER_MERCHANT_TipAuthorizeHandle *tao;
- CURL *eh;
- json_t *te_obj;
-
- tao = GNUNET_new (struct TALER_MERCHANT_TipAuthorizeHandle);
- tao->ctx = ctx;
- tao->cb = authorize_cb;
- tao->cb_cls = authorize_cb_cls;
-
- tao->url = TALER_url_join (backend_url,
- "private/tips",
- NULL);
- if (NULL == tao->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- GNUNET_free (tao);
- return NULL;
- }
- te_obj = GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("amount",
- amount),
- GNUNET_JSON_pack_string ("justification",
- justification),
- GNUNET_JSON_pack_string ("next_url",
- next_url));
- eh = TALER_MERCHANT_curl_easy_get_ (tao->url);
- if (GNUNET_OK !=
- TALER_curl_easy_post (&tao->post_ctx,
- eh,
- te_obj))
- {
- GNUNET_break (0);
- curl_easy_cleanup (eh);
- json_decref (te_obj);
- GNUNET_free (tao->url);
- GNUNET_free (tao);
- return NULL;
- }
- json_decref (te_obj);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting URL '%s'\n",
- tao->url);
- tao->job = GNUNET_CURL_job_add2 (ctx,
- eh,
- tao->post_ctx.headers,
- &handle_tip_authorize_finished,
- tao);
- return tao;
-}
-
-
-void
-TALER_MERCHANT_tip_authorize_cancel (
- struct TALER_MERCHANT_TipAuthorizeHandle *tao)
-{
- if (NULL != tao->job)
- {
- GNUNET_CURL_job_cancel (tao->job);
- tao->job = NULL;
- }
- TALER_curl_easy_post_finished (&tao->post_ctx);
- GNUNET_free (tao->url);
- GNUNET_free (tao);
-}
-
-
-/* end of merchant_api_tip_authorize.c */
diff --git a/src/lib/merchant_api_tip_pickup.c b/src/lib/merchant_api_tip_pickup.c
deleted file mode 100644
index 593efa43..00000000
--- a/src/lib/merchant_api_tip_pickup.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-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_tip_pickup.c
- * @brief Implementation of the /tip-pickup request of the merchant's HTTP API
- * @author Marcello Stanisci
- * @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 <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_curl_lib.h>
-
-
-/**
- * Data we keep per planchet.
- */
-struct PlanchetData
-{
- /**
- * Secrets of the planchet.
- */
- struct TALER_PlanchetMasterSecretP ps;
-
- /**
- * Denomination key we are withdrawing.
- */
- struct TALER_EXCHANGE_DenomPublicKey pk;
-
- /**
- * Hash of the public key of the coin we are signing.
- */
- struct TALER_CoinPubHashP c_hash;
-
- /**
- * Nonce used for @e csr request, if any.
- */
- struct TALER_CsNonce nonce;
-
- /**
- * Handle for a /csr request we may optionally need
- * to trigger.
- */
- struct TALER_EXCHANGE_CsRWithdrawHandle *csr;
-
- /**
- * Handle for the /tip-pickup operation we are part of.
- */
- struct TALER_MERCHANT_TipPickupHandle *tp;
-
- /**
- * Offset of this entry in the array.
- */
- unsigned int off;
-};
-
-
-/**
- * Handle for a /tip-pickup operation.
- */
-struct TALER_MERCHANT_TipPickupHandle
-{
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_TipPickupCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Handle for the actual (internal) withdraw operation.
- */
- struct TALER_MERCHANT_TipPickup2Handle *tpo2;
-
- /**
- * Array of length @e num_planchets.
- */
- struct PlanchetData *planchets;
-
- /**
- * Array of length @e num_planchets.
- */
- struct TALER_EXCHANGE_PrivateCoinDetails *pcds;
-
- /**
- * Context for making HTTP requests.
- */
- struct GNUNET_CURL_Context *ctx;
-
- /**
- * URL of the merchant backend.
- */
- char *backend_url;
-
- /**
- * ID of the tip we are picking up.
- */
- struct TALER_TipIdentifierP tip_id;
-
- /**
- * Number of planchets/coins used for this operation.
- */
- unsigned int num_planchets;
-
- /**
- * Number of remaining active /csr-withdraw requests.
- */
- unsigned int csr_active;
-};
-
-
-/**
- * Fail the pickup operation @a tp, returning @a ec.
- * Also cancels @a tp.
- *
- * @param[in] tp operation to fail
- * @param ec reason for the failure
- */
-static void
-fail_pickup (struct TALER_MERCHANT_TipPickupHandle *tp,
- enum TALER_ErrorCode ec)
-{
- struct TALER_MERCHANT_PickupDetails pd = {
- .hr.ec = ec
- };
-
- tp->cb (tp->cb_cls,
- &pd);
- TALER_MERCHANT_tip_pickup_cancel (tp);
-}
-
-
-/**
- * Callback for a /tip-pickup request. Returns the result of the operation.
- * Note that the client MUST still do the unblinding of the @a blind_sigs.
- *
- * @param cls closure, a `struct TALER_MERCHANT_TipPickupHandle *`
- * @param hr HTTP response details
- * @param num_blind_sigs length of the @a reserve_sigs array, 0 on error
- * @param blind_sigs array of blind signatures over the planchets, NULL on error
- */
-static void
-pickup_done_cb (void *cls,
- const struct TALER_MERCHANT_HttpResponse *hr,
- unsigned int num_blind_sigs,
- const struct TALER_BlindedDenominationSignature *blind_sigs)
-{
- struct TALER_MERCHANT_TipPickupHandle *tp = cls;
- struct TALER_MERCHANT_PickupDetails pd = {
- .hr = *hr
- };
-
- tp->tpo2 = NULL;
- if (NULL == blind_sigs)
- {
- tp->cb (tp->cb_cls,
- &pd);
- TALER_MERCHANT_tip_pickup_cancel (tp);
- return;
- }
- {
- enum GNUNET_GenericReturnValue ok = GNUNET_OK;
-
- for (unsigned int i = 0; i<num_blind_sigs; i++)
- {
- struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
- struct TALER_FreshCoin fc;
-
- if (GNUNET_OK !=
- TALER_planchet_to_coin (&tp->planchets[i].pk.key,
- &blind_sigs[i],
- &pcd->bks,
- &pcd->coin_priv,
- NULL,
- &tp->planchets[i].c_hash,
- &pcd->exchange_vals,
- &fc))
- {
- ok = GNUNET_SYSERR;
- break;
- }
- pcd->sig = fc.sig;
- }
- if (GNUNET_OK != ok)
- {
- struct TALER_MERCHANT_HttpResponse hrx = {
- .reply = hr->reply,
- .ec = TALER_EC_MERCHANT_TIP_PICKUP_UNBLIND_FAILURE
- };
-
- pd.hr = hrx;
- tp->cb (tp->cb_cls,
- &pd);
- }
- else
- {
- pd.details.success.num_sigs = num_blind_sigs;
- pd.details.success.pcds = tp->pcds;
- tp->cb (tp->cb_cls,
- &pd);
- }
- }
- TALER_MERCHANT_tip_pickup_cancel (tp);
-}
-
-
-/**
- * We have obtained all of the exchange inputs. Continue the pickup.
- *
- * @param[in,out] tp operation to continue
- */
-static void
-pickup_post_csr (struct TALER_MERCHANT_TipPickupHandle *tp)
-{
- struct TALER_PlanchetDetail details[tp->num_planchets];
-
- for (unsigned int i = 0; i<tp->num_planchets; i++)
- {
- const struct PlanchetData *pd = &tp->planchets[i];
- struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
-
- TALER_planchet_setup_coin_priv (&pd->ps,
- &pcd->exchange_vals,
- &pcd->coin_priv);
- TALER_planchet_blinding_secret_create (&pd->ps,
- &pcd->exchange_vals,
- &pcd->bks);
- if (TALER_DENOMINATION_CS == pcd->exchange_vals.cipher)
- {
- details[i].blinded_planchet.details.cs_blinded_planchet.nonce
- = pd->nonce;
- }
- if (GNUNET_OK !=
- TALER_planchet_prepare (&pd->pk.key,
- &pcd->exchange_vals,
- &pcd->bks,
- &pcd->coin_priv,
- NULL,
- &tp->planchets[i].c_hash,
- &details[i]))
- {
- GNUNET_break (0);
- for (unsigned int j = 0; j<i; j++)
- TALER_planchet_detail_free (&details[j]);
- fail_pickup (tp,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
- return;
- }
- }
- tp->tpo2 = TALER_MERCHANT_tip_pickup2 (tp->ctx,
- tp->backend_url,
- &tp->tip_id,
- tp->num_planchets,
- details,
- &pickup_done_cb,
- tp);
- for (unsigned int j = 0; j<tp->num_planchets; j++)
- TALER_planchet_detail_free (&details[j]);
- if (NULL == tp->tpo2)
- {
- GNUNET_break (0);
- fail_pickup (tp,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
- return;
- }
-}
-
-
-/**
- * Callbacks of this type are used to serve the result of submitting a
- * CS R request to a exchange.
- *
- * @param cls a `struct TALER_MERCHANT_TipPickupHandle`
- * @param csrr response details
- */
-static void
-csr_cb (void *cls,
- const struct TALER_EXCHANGE_CsRWithdrawResponse *csrr)
-{
- struct PlanchetData *pd = cls;
- struct TALER_MERCHANT_TipPickupHandle *tp = pd->tp;
-
- pd->csr = NULL;
- tp->csr_active--;
- switch (csrr->hr.http_status)
- {
- case MHD_HTTP_OK:
- {
- struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[pd->off];
-
- pcd->exchange_vals = csrr->details.success.alg_values;
- }
- if (0 != tp->csr_active)
- return;
- pickup_post_csr (tp);
- return;
- default:
- {
- struct TALER_MERCHANT_PickupDetails pd = {
- .hr.hint = "/csr-withdraw failed",
- .hr.exchange_http_status = csrr->hr.http_status
- };
-
- tp->cb (tp->cb_cls,
- &pd);
- TALER_MERCHANT_tip_pickup_cancel (tp);
- return;
- }
- }
-}
-
-
-struct TALER_MERCHANT_TipPickupHandle *
-TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
- struct TALER_EXCHANGE_Handle *exchange,
- const char *backend_url,
- const struct TALER_TipIdentifierP *tip_id,
- unsigned int num_planchets,
- const struct TALER_MERCHANT_PlanchetData *pds,
- TALER_MERCHANT_TipPickupCallback pickup_cb,
- void *pickup_cb_cls)
-{
- struct TALER_MERCHANT_TipPickupHandle *tp;
-
- if (0 == num_planchets)
- {
- GNUNET_break (0);
- return NULL;
- }
- tp = GNUNET_new (struct TALER_MERCHANT_TipPickupHandle);
- tp->cb = pickup_cb;
- tp->cb_cls = pickup_cb_cls;
- tp->ctx = ctx;
- tp->backend_url = GNUNET_strdup (backend_url);
- tp->tip_id = *tip_id;
- tp->num_planchets = num_planchets;
- tp->planchets = GNUNET_new_array (num_planchets,
- struct PlanchetData);
- tp->pcds = GNUNET_new_array (num_planchets,
- struct TALER_EXCHANGE_PrivateCoinDetails);
- for (unsigned int i = 0; i<num_planchets; i++)
- {
- const struct TALER_MERCHANT_PlanchetData *mpd = &pds[i];
- const struct TALER_EXCHANGE_DenomPublicKey *pk = mpd->pk;
- struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
- struct PlanchetData *pd = &tp->planchets[i];
-
- pd->off = i;
- pd->tp = tp;
- tp->planchets[i].ps = mpd->ps;
- tp->planchets[i].pk = *pds[i].pk;
- TALER_denom_pub_deep_copy (&tp->planchets[i].pk.key,
- &pds[i].pk->key);
- switch (pk->key.cipher)
- {
- case TALER_DENOMINATION_RSA:
- pcd->exchange_vals.cipher = TALER_DENOMINATION_RSA;
- break;
- case TALER_DENOMINATION_CS:
- {
- TALER_cs_withdraw_nonce_derive (&pd->ps,
- &pd->nonce);
- pd->csr = TALER_EXCHANGE_csr_withdraw (exchange,
- &pd->pk,
- &pd->nonce,
- &csr_cb,
- pd);
- if (NULL == pd->csr)
- {
- GNUNET_break (0);
- TALER_MERCHANT_tip_pickup_cancel (tp);
- return NULL;
- }
- tp->csr_active++;
- break;
- }
- default:
- GNUNET_break (0);
- TALER_MERCHANT_tip_pickup_cancel (tp);
- return NULL;
- }
- }
- if (0 == tp->csr_active)
- {
- pickup_post_csr (tp);
- return tp;
- }
- return tp;
-}
-
-
-void
-TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupHandle *tp)
-{
- for (unsigned int i = 0; i<tp->num_planchets; i++)
- {
- struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
- struct PlanchetData *pd = &tp->planchets[i];
-
- TALER_denom_sig_free (&pcd->sig);
- TALER_denom_pub_free (&tp->planchets[i].pk.key);
- if (NULL != pd->csr)
- {
- TALER_EXCHANGE_csr_withdraw_cancel (pd->csr);
- pd->csr = NULL;
- }
- }
- GNUNET_array_grow (tp->planchets,
- tp->num_planchets,
- 0);
- if (NULL != tp->tpo2)
- {
- TALER_MERCHANT_tip_pickup2_cancel (tp->tpo2);
- tp->tpo2 = NULL;
- }
- GNUNET_free (tp->backend_url);
- GNUNET_free (tp->pcds);
- GNUNET_free (tp);
-}
-
-
-/* end of merchant_api_tip_pickup.c */
diff --git a/src/lib/merchant_api_tip_pickup2.c b/src/lib/merchant_api_tip_pickup2.c
deleted file mode 100644
index 33457024..00000000
--- a/src/lib/merchant_api_tip_pickup2.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2021 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_tip_pickup2.c
- * @brief Implementation of the /tip-pickup request of the merchant's HTTP API
- * @author Marcello Stanisci
- * @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 "merchant_api_common.h"
-#include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_curl_lib.h>
-
-
-/**
- * @brief A handle for tracking transactions.
- */
-struct TALER_MERCHANT_TipPickup2Handle
-{
-
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Minor context that holds body and headers.
- */
- struct TALER_CURL_PostContext post_ctx;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_TipPickup2Callback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Reference to the execution context.
- */
- struct GNUNET_CURL_Context *ctx;
-
- /**
- * Expected number of planchets.
- */
- unsigned int num_planchets;
-};
-
-
-/**
- * We got a 200 response back from the exchange (or the merchant).
- * Now we need to parse the response and if it is well-formed,
- * call the callback (and set it to NULL afterwards).
- *
- * @param tpo handle of the original authorization operation
- * @param json cryptographic proof returned by the exchange/merchant
- * @return #GNUNET_OK if response is valid
- */
-static int
-check_ok (struct TALER_MERCHANT_TipPickup2Handle *tpo,
- const json_t *json)
-{
- json_t *ja;
- unsigned int ja_len;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("blind_sigs", &ja),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK,
- .reply = json
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- ja_len = json_array_size (ja);
- if (ja_len != tpo->num_planchets)
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return GNUNET_SYSERR;
- }
- {
- struct TALER_BlindedDenominationSignature mblind_sigs[ja_len];
-
- for (unsigned int i = 0; i<ja_len; i++)
- {
- json_t *pj = json_array_get (ja, i);
- struct GNUNET_JSON_Specification ispec[] = {
- TALER_JSON_spec_blinded_denom_sig ("blind_sig",
- &mblind_sigs[i]),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (pj,
- ispec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return GNUNET_SYSERR;
- }
- }
- tpo->cb (tpo->cb_cls,
- &hr,
- ja_len,
- mblind_sigs);
- for (unsigned int i = 0; i<ja_len; i++)
- TALER_blinded_denom_sig_free (&mblind_sigs[i]);
- tpo->cb = NULL; /* do not call twice */
- }
- GNUNET_JSON_parse_free (spec);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /track/transaction request.
- *
- * @param cls the `struct TALER_MERCHANT_TipPickupHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_tip_pickup_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_TipPickup2Handle *tpo = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
-
- tpo->job = NULL;
- switch (response_code)
- {
- case MHD_HTTP_OK:
- if (GNUNET_OK != check_ok (tpo,
- json))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- }
- break;
- case MHD_HTTP_BAD_REQUEST:
- /* Can happen if we pickup an amount that exceeds the tip... */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- GNUNET_break (TALER_EC_MERCHANT_TIP_PICKUP_AMOUNT_EXCEEDS_TIP_REMAINING ==
- hr.ec);
- break;
- case MHD_HTTP_CONFLICT:
- /* legal, can happen if we pickup a tip twice... */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_NOT_FOUND:
- /* legal, can happen if tip ID is unknown */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) hr.ec);
- break;
- }
- if (NULL != tpo->cb)
- {
- tpo->cb (tpo->cb_cls,
- &hr,
- 0,
- NULL);
- tpo->cb = NULL;
- }
- TALER_MERCHANT_tip_pickup2_cancel (tpo);
-}
-
-
-struct TALER_MERCHANT_TipPickup2Handle *
-TALER_MERCHANT_tip_pickup2 (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_TipIdentifierP *tip_id,
- unsigned int num_planchets,
- const struct TALER_PlanchetDetail planchets[],
- TALER_MERCHANT_TipPickup2Callback pickup_cb,
- void *pickup_cb_cls)
-{
- struct TALER_MERCHANT_TipPickup2Handle *tpo;
- CURL *eh;
- json_t *pa;
- json_t *tp_obj;
-
- if (0 == num_planchets)
- {
- GNUNET_break (0);
- return NULL;
- }
- pa = json_array ();
- for (unsigned int i = 0; i<num_planchets; i++)
- {
- const struct TALER_PlanchetDetail *planchet = &planchets[i];
- json_t *p;
-
- p = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("denom_pub_hash",
- &planchet->denom_pub_hash),
- TALER_JSON_pack_blinded_planchet ("coin_ev",
- &planchet->blinded_planchet));
- if (0 !=
- json_array_append_new (pa,
- p))
- {
- GNUNET_break (0);
- json_decref (pa);
- return NULL;
- }
- }
- tp_obj = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("planchets",
- pa));
- tpo = GNUNET_new (struct TALER_MERCHANT_TipPickup2Handle);
- tpo->num_planchets = num_planchets;
- tpo->ctx = ctx;
- tpo->cb = pickup_cb;
- tpo->cb_cls = pickup_cb_cls;
-
- {
- char tip_str[sizeof (*tip_id) * 2];
- char arg_str[sizeof (tip_str) + 32];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (tip_id,
- sizeof (*tip_id),
- tip_str,
- sizeof (tip_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "tips/%s/pickup",
- tip_str);
- tpo->url = TALER_url_join (backend_url,
- arg_str,
- NULL);
- }
- if (NULL == tpo->url)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not construct request URL.\n");
- json_decref (tp_obj);
- GNUNET_free (tpo);
- return NULL;
- }
- eh = TALER_MERCHANT_curl_easy_get_ (tpo->url);
- if (GNUNET_OK !=
- TALER_curl_easy_post (&tpo->post_ctx,
- eh,
- tp_obj))
- {
- GNUNET_break (0);
- json_decref (tp_obj);
- curl_easy_cleanup (eh);
- GNUNET_free (tpo->url);
- GNUNET_free (tpo);
- return NULL;
- }
- json_decref (tp_obj);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting URL '%s'\n",
- tpo->url);
- tpo->job = GNUNET_CURL_job_add2 (ctx,
- eh,
- tpo->post_ctx.headers,
- &handle_tip_pickup_finished,
- tpo);
- if (NULL == tpo->job)
- {
- TALER_MERCHANT_tip_pickup2_cancel (tpo);
- return NULL;
- }
- return tpo;
-}
-
-
-void
-TALER_MERCHANT_tip_pickup2_cancel (
- struct TALER_MERCHANT_TipPickup2Handle *tpo)
-{
- if (NULL != tpo->job)
- {
- GNUNET_CURL_job_cancel (tpo->job);
- tpo->job = NULL;
- }
- TALER_curl_easy_post_finished (&tpo->post_ctx);
- GNUNET_free (tpo->url);
- GNUNET_free (tpo);
-}
-
-
-/* end of merchant_api_tip_pickup2.c */
diff --git a/src/lib/merchant_api_wallet_get_order.c b/src/lib/merchant_api_wallet_get_order.c
index 61bed534..763b2c83 100644
--- a/src/lib/merchant_api_wallet_get_order.c
+++ b/src/lib/merchant_api_wallet_get_order.c
@@ -116,11 +116,11 @@ handle_wallet_get_order_finished (void *cls,
};
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_bool ("refunded",
- &owgr.details.success.refunded),
+ &owgr.details.ok.refunded),
GNUNET_JSON_spec_bool ("refund_pending",
- &owgr.details.success.refund_pending),
+ &owgr.details.ok.refund_pending),
TALER_JSON_spec_amount_any ("refund_amount",
- &owgr.details.success.refund_amount),
+ &owgr.details.ok.refund_amount),
GNUNET_JSON_spec_end ()
};
@@ -205,8 +205,7 @@ TALER_MERCHANT_wallet_order_get (
void *cb_cls)
{
struct TALER_MERCHANT_OrderWalletGetHandle *owgh;
- unsigned long long tms;
- long tlong;
+ unsigned int tms;
GNUNET_assert (NULL != backend_url);
GNUNET_assert (NULL != order_id);
@@ -214,14 +213,8 @@ TALER_MERCHANT_wallet_order_get (
owgh->ctx = ctx;
owgh->cb = cb;
owgh->cb_cls = cb_cls;
- tms = (unsigned long long) (timeout.rel_value_us
- / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
- /* set curl timeout to *our* long poll timeout plus one minute
- (for network latency and processing delays) */
- tlong = (long) (GNUNET_TIME_relative_add (timeout,
- GNUNET_TIME_UNIT_MINUTES).
- rel_value_us
- / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
+ tms = (unsigned int) (timeout.rel_value_us
+ / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
{
char timeout_ms[32];
struct GNUNET_CRYPTO_HashAsciiEncoded h_contract_s;
@@ -231,7 +224,7 @@ TALER_MERCHANT_wallet_order_get (
&h_contract_s);
GNUNET_snprintf (timeout_ms,
sizeof (timeout_ms),
- "%llu",
+ "%u",
tms);
GNUNET_asprintf (&path,
"orders/%s",
@@ -271,28 +264,10 @@ TALER_MERCHANT_wallet_order_get (
eh = TALER_MERCHANT_curl_easy_get_ (owgh->url);
if (0 != tms)
{
- if (CURLE_OK !=
- curl_easy_setopt (eh,
- CURLOPT_TIMEOUT_MS,
- (long) tms))
- {
- GNUNET_break (0);
- curl_easy_cleanup (eh);
- GNUNET_free (owgh->url);
- GNUNET_free (owgh);
- return NULL;
- }
- }
- if (CURLE_OK !=
- curl_easy_setopt (eh,
- CURLOPT_TIMEOUT_MS,
- tlong))
- {
- GNUNET_break (0);
- curl_easy_cleanup (eh);
- GNUNET_free (owgh->url);
- GNUNET_free (owgh);
- return NULL;
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_TIMEOUT_MS,
+ (long) (tms + 100L)));
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
diff --git a/src/lib/merchant_api_wallet_get_template.c b/src/lib/merchant_api_wallet_get_template.c
new file mode 100644
index 00000000..d9ca95bc
--- /dev/null
+++ b/src/lib/merchant_api_wallet_get_template.c
@@ -0,0 +1,195 @@
+/*
+ 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_wallet_get_template.c
+ * @brief Implementation of the GET /templates/$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 /templates/$ID operation.
+ */
+struct TALER_MERCHANT_WalletTemplateGetHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_WalletTemplateGetCallback 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 /templates/$ID request.
+ *
+ * @param cls the `struct TALER_MERCHANT_TemplateGetHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response response body, NULL if not in JSON
+ */
+static void
+handle_get_template_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_WalletTemplateGetHandle *tgh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_WalletTemplateGetResponse tgr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
+ };
+
+ tgh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /templates/$ID response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ const json_t *contract;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_object_const ("template_contract",
+ &contract),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK ==
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ tgr.details.ok.template_contract = contract;
+ tgh->cb (tgh->cb_cls,
+ &tgr);
+ TALER_MERCHANT_wallet_template_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_wallet_template_get_cancel (tgh);
+}
+
+
+struct TALER_MERCHANT_WalletTemplateGetHandle *
+TALER_MERCHANT_wallet_template_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ const char *template_id,
+ TALER_MERCHANT_WalletTemplateGetCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_WalletTemplateGetHandle *tgh;
+ CURL *eh;
+
+ tgh = GNUNET_new (struct TALER_MERCHANT_WalletTemplateGetHandle);
+ tgh->ctx = ctx;
+ tgh->cb = cb;
+ tgh->cb_cls = cb_cls;
+ {
+ char *path;
+
+ GNUNET_asprintf (&path,
+ "templates/%s",
+ template_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_template_finished,
+ tgh);
+ return tgh;
+}
+
+
+void
+TALER_MERCHANT_wallet_template_get_cancel (
+ struct TALER_MERCHANT_WalletTemplateGetHandle *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_wallet_get_tip.c b/src/lib/merchant_api_wallet_get_tip.c
deleted file mode 100644
index 49e507d0..00000000
--- a/src/lib/merchant_api_wallet_get_tip.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2018, 2020 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_wallet_get_tip.c
- * @brief Implementation of the GET /tips/$TIP_ID request of the merchant's HTTP API
- * @author Florian Dold
- */
-#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 "merchant_api_common.h"
-#include <taler/taler_json_lib.h>
-#include <taler/taler_signatures.h>
-
-
-/**
- * @brief A handle for tracking /tip-get operations
- */
-struct TALER_MERCHANT_TipWalletGetHandle
-{
- /**
- * The url for this request.
- */
- char *url;
-
- /**
- * Handle for the request.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Function to call with the result.
- */
- TALER_MERCHANT_TipWalletGetCallback 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 /track/transaction request.
- *
- * @param cls the `struct TALER_MERCHANT_TipGetHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response response body, NULL if not in JSON
- */
-static void
-handle_wallet_tip_get_finished (void *cls,
- long response_code,
- const void *response)
-{
- struct TALER_MERCHANT_TipWalletGetHandle *tgh = cls;
- const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got /tip/$TIP_ID response with status code %u\n",
- (unsigned int) response_code);
-
- tgh->job = NULL;
- switch (response_code)
- {
- case MHD_HTTP_OK:
- {
- const char *exchange_url;
- struct TALER_Amount amount_remaining;
- struct GNUNET_TIME_Timestamp expiration;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_timestamp ("expiration",
- &expiration),
- GNUNET_JSON_spec_string ("exchange_url",
- &exchange_url),
- TALER_JSON_spec_amount_any ("tip_amount",
- &amount_remaining),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- break;
- }
- tgh->cb (tgh->cb_cls,
- &hr,
- expiration,
- exchange_url,
- &amount_remaining);
- TALER_MERCHANT_wallet_tip_get_cancel (tgh);
- return;
- }
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- /* Server had an internal issue; we should retry, but this API
- leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- case MHD_HTTP_NOT_FOUND:
- /* legal, can happen if instance or tip reserve is unknown */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- break;
- default:
- /* unexpected response code */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) hr.ec);
- break;
- }
- tgh->cb (tgh->cb_cls,
- &hr,
- GNUNET_TIME_UNIT_ZERO_TS,
- NULL,
- NULL);
- TALER_MERCHANT_wallet_tip_get_cancel (tgh);
-}
-
-
-struct TALER_MERCHANT_TipWalletGetHandle *
-TALER_MERCHANT_wallet_tip_get (struct GNUNET_CURL_Context *ctx,
- const char *backend_url,
- const struct TALER_TipIdentifierP *tip_id,
- TALER_MERCHANT_TipWalletGetCallback cb,
- void *cb_cls)
-{
- struct TALER_MERCHANT_TipWalletGetHandle *tgh;
- CURL *eh;
-
- tgh = GNUNET_new (struct TALER_MERCHANT_TipWalletGetHandle);
- tgh->ctx = ctx;
- tgh->cb = cb;
- tgh->cb_cls = cb_cls;
- {
- char res_str[sizeof (*tip_id) * 2];
- char arg_str[sizeof (res_str) + 48];
- char *end;
-
- end = GNUNET_STRINGS_data_to_string (tip_id,
- sizeof (*tip_id),
- res_str,
- sizeof (res_str));
- *end = '\0';
- GNUNET_snprintf (arg_str,
- sizeof (arg_str),
- "tips/%s",
- res_str);
- tgh->url = TALER_url_join (backend_url,
- arg_str,
- 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_INFO,
- "Requesting URL '%s'\n",
- tgh->url);
- eh = TALER_MERCHANT_curl_easy_get_ (tgh->url);
- tgh->job = GNUNET_CURL_job_add (ctx,
- eh,
- &handle_wallet_tip_get_finished,
- tgh);
- return tgh;
-}
-
-
-void
-TALER_MERCHANT_wallet_tip_get_cancel (
- struct TALER_MERCHANT_TipWalletGetHandle *tgh)
-{
- if (NULL != tgh->job)
- {
- GNUNET_CURL_job_cancel (tgh->job);
- tgh->job = NULL;
- }
- GNUNET_free (tgh->url);
- GNUNET_free (tgh);
-}
-
-
-/* end of merchant_api_wallet_get_tip.c */
diff --git a/src/lib/merchant_api_wallet_post_order_refund.c b/src/lib/merchant_api_wallet_post_order_refund.c
index fc4b0abd..e72982f3 100644
--- a/src/lib/merchant_api_wallet_post_order_refund.c
+++ b/src/lib/merchant_api_wallet_post_order_refund.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020 Taler Systems SA
+ Copyright (C) 2020-2023 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
@@ -32,6 +32,10 @@
#include <taler/taler_signatures.h>
#include <taler/taler_curl_lib.h>
+/**
+ * Maximum number of refunds we return.
+ */
+#define MAX_REFUNDS 1024
/**
* Handle for a (public) POST /orders/ID/refund operation.
@@ -71,33 +75,6 @@ struct TALER_MERCHANT_WalletOrderRefundHandle
/**
- * Convenience function to call the callback in @a owgh with an error code of
- * @a ec and the exchange body being set to @a reply.
- *
- * @param orh handle providing callback
- * @param ec error code to return to application
- * @param reply JSON reply we got from the exchange, can be NULL
- */
-static void
-cb_failure (struct TALER_MERCHANT_WalletOrderRefundHandle *orh,
- enum TALER_ErrorCode ec,
- const json_t *reply)
-{
- struct TALER_MERCHANT_HttpResponse hr = {
- .ec = ec,
- .reply = reply
- };
-
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL,
- 0);
-}
-
-
-/**
* Callback to process (public) POST /orders/ID/refund response
*
* @param cls the `struct TALER_MERCHANT_OrderRefundHandle`
@@ -111,37 +88,31 @@ handle_refund_finished (void *cls,
{
struct TALER_MERCHANT_WalletOrderRefundHandle *orh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_WalletRefundResponse wrr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
orh->job = NULL;
-
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL,
- 0);
+ wrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
- struct TALER_Amount refund_amount;
- json_t *refunds;
- struct TALER_MerchantPublicKeyP merchant_pub;
+ const json_t *refunds;
unsigned int refund_len;
struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("refund_amount",
- &refund_amount),
- GNUNET_JSON_spec_json ("refunds",
- &refunds),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub",
- &merchant_pub),
+ TALER_JSON_spec_amount_any (
+ "refund_amount",
+ &wrr.details.ok.refund_amount),
+ GNUNET_JSON_spec_array_const (
+ "refunds",
+ &refunds),
+ GNUNET_JSON_spec_fixed_auto (
+ "merchant_pub",
+ &wrr.details.ok.merchant_pub),
GNUNET_JSON_spec_end ()
};
@@ -151,27 +122,21 @@ handle_refund_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- cb_failure (orh,
- TALER_EC_GENERIC_REPLY_MALFORMED,
- json);
- TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
- return;
+ wrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ wrr.hr.http_status = 0;
+ break;
}
-
- if (! json_is_array (refunds))
+ refund_len = json_array_size (refunds);
+ if ( (json_array_size (refunds) != (size_t) refund_len) ||
+ (refund_len > MAX_REFUNDS) )
{
- GNUNET_break_op (0);
- cb_failure (orh,
- TALER_EC_GENERIC_REPLY_MALFORMED,
- json);
- GNUNET_JSON_parse_free (spec);
- TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
- return;
+ GNUNET_break (0);
+ wrr.hr.ec = TALER_EC_GENERIC_ALLOCATION_FAILURE;
+ wrr.hr.http_status = 0;
+ break;
}
-
- refund_len = json_array_size (refunds);
{
- struct TALER_MERCHANT_RefundDetail rds[refund_len];
+ struct TALER_MERCHANT_RefundDetail rds[GNUNET_NZL (refund_len)];
memset (rds,
0,
@@ -183,10 +148,26 @@ handle_refund_finished (void *cls,
i);
const char *refund_status_type;
uint32_t exchange_status;
- int ret;
+ uint32_t eec = 0;
struct GNUNET_JSON_Specification espec[] = {
+ GNUNET_JSON_spec_string ("type",
+ &refund_status_type),
GNUNET_JSON_spec_uint32 ("exchange_status",
&exchange_status),
+ GNUNET_JSON_spec_uint64 ("rtransaction_id",
+ &rd->rtransaction_id),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub",
+ &rd->coin_pub),
+ TALER_JSON_spec_amount_any ("refund_amount",
+ &rd->refund_amount),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_object_const ("exchange_reply",
+ &rd->hr.reply),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("exchange_code",
+ &eec),
+ NULL),
GNUNET_JSON_spec_end ()
};
@@ -196,151 +177,85 @@ handle_refund_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- cb_failure (orh,
- TALER_EC_GENERIC_REPLY_MALFORMED,
- json);
- TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
- return;
+ wrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ wrr.hr.http_status = 0;
+ goto finish;
}
- if (MHD_HTTP_OK == exchange_status)
+ rd->hr.http_status = exchange_status;
+ rd->hr.ec = (enum TALER_ErrorCode) eec;
+ switch (exchange_status)
{
- struct GNUNET_JSON_Specification rspec[] = {
- GNUNET_JSON_spec_string ("type",
- &refund_status_type),
- GNUNET_JSON_spec_fixed_auto ("exchange_sig",
- &rd->exchange_sig),
- GNUNET_JSON_spec_fixed_auto ("exchange_pub",
- &rd->exchange_pub),
- GNUNET_JSON_spec_uint64 ("rtransaction_id",
- &rd->rtransaction_id),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &rd->coin_pub),
- TALER_JSON_spec_amount_any ("refund_amount",
- &rd->refund_amount),
- GNUNET_JSON_spec_end ()
- };
-
- ret = GNUNET_JSON_parse (jrefund,
- rspec,
- NULL, NULL);
- if (GNUNET_OK == ret)
+ case MHD_HTTP_OK:
{
- /* check that type field is correct */
- if (0 != strcmp ("success", refund_status_type))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- }
- }
- }
- else
- {
- struct GNUNET_JSON_Specification rspec[] = {
- GNUNET_JSON_spec_string ("type",
- &refund_status_type),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &rd->coin_pub),
- GNUNET_JSON_spec_uint64 ("rtransaction_id",
- &rd->rtransaction_id),
- TALER_JSON_spec_amount_any ("refund_amount",
- &rd->refund_amount),
- GNUNET_JSON_spec_end ()
- };
-
- ret = GNUNET_JSON_parse (jrefund,
+ struct GNUNET_JSON_Specification rspec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &rd->details.ok.exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &rd->details.ok.exchange_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (jrefund,
rspec,
- NULL, NULL);
- if (GNUNET_OK == ret)
- {
- /* parse optional arguments */
- json_t *jec;
-
- jec = json_object_get (jrefund,
- "exchange_code");
- if (NULL != jec)
+ NULL,
+ NULL))
{
- if (! json_is_integer (jec))
- {
- GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
- }
- else
- {
- rd->hr.ec = (enum TALER_ErrorCode) json_integer_value (jec);
- }
+ GNUNET_break_op (0);
+ wrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ wrr.hr.http_status = 0;
+ goto finish;
}
- rd->hr.reply = json_object_get (jrefund,
- "exchange_reply");
/* check that type field is correct */
- if (0 != strcmp ("failure", refund_status_type))
+ if (0 != strcmp ("success",
+ refund_status_type))
{
GNUNET_break_op (0);
- ret = GNUNET_SYSERR;
+ wrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ wrr.hr.http_status = 0;
+ goto finish;
}
}
- }
- if (GNUNET_OK != ret)
- {
- GNUNET_break_op (0);
- cb_failure (orh,
- TALER_EC_GENERIC_REPLY_MALFORMED,
- json);
- TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
- return;
- }
- rd->hr.http_status = exchange_status;
- }
-
- {
- struct TALER_MERCHANT_HttpResponse hr = {
- .reply = json,
- .http_status = MHD_HTTP_OK
- };
+ break; /* end MHD_HTTP_OK */
+ default:
+ if (0 != strcmp ("failure",
+ refund_status_type))
+ {
+ GNUNET_break_op (0);
+ wrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ wrr.hr.http_status = 0;
+ goto finish;
+ }
+ } /* switch on exchange status code */
+ } /* for all refunds */
- orh->cb (orh->cb_cls,
- &hr,
- &refund_amount,
- &merchant_pub,
- rds,
- refund_len);
- }
- }
- GNUNET_JSON_parse_free (spec);
- }
+ wrr.details.ok.refunds = rds;
+ wrr.details.ok.refunds_length = refund_len;
+ orh->cb (orh->cb_cls,
+ &wrr);
+ TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
+ return;
+ } /* end 'rds' scope */
+ } /* case MHD_HTTP_OK */
break;
case MHD_HTTP_NO_CONTENT:
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL,
- 0);
break;
case MHD_HTTP_CONFLICT:
case MHD_HTTP_NOT_FOUND:
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL,
- 0);
+ wrr.hr.ec = TALER_JSON_get_error_code (json);
+ wrr.hr.hint = TALER_JSON_get_error_hint (json);
break;
default:
GNUNET_break_op (0); /* unexpected status code */
TALER_MERCHANT_parse_error_details_ (json,
response_code,
- &hr);
- orh->cb (orh->cb_cls,
- &hr,
- NULL,
- NULL,
- NULL,
- 0);
+ &wrr.hr);
break;
}
+finish:
+ orh->cb (orh->cb_cls,
+ &wrr);
TALER_MERCHANT_wallet_post_order_refund_cancel (orh);
}