diff options
Diffstat (limited to 'src/backend')
28 files changed, 1492 insertions, 812 deletions
diff --git a/src/backend/#taler-merchant-httpd_private-patch-templates-ID.c# b/src/backend/#taler-merchant-httpd_private-patch-templates-ID.c# deleted file mode 100644 index 6739c7a9..00000000 --- a/src/backend/#taler-merchant-httpd_private-patch-templates-ID.c# +++ /dev/null @@ -1,197 +0,0 @@ -/* - This file is part of TALER - (C) 2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation; either version 3, - or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-merchant-httpd_private-patch-templates-ID.c - * @brief implementing PATCH /templates/$ID request handling - * @author Priscilla HUANG - */ -#include "platform.h" -#include "taler-merchant-httpd_private-patch-templates-ID.h" -#include "taler-merchant-httpd_helper.h" -#include <taler/taler_json_lib.h> - - -/** - * How often do we retry the simple INSERT database transaction? - */ -#define MAX_RETRIES 3 - - -/** - * Determine the cause of the PATCH failure in more detail and report. - * - * @param connection connection to report on - * @param instance_id instance we are processing - * @param template_id ID of the product to patch - * @param tp template details we failed to set - */ -static MHD_RESULT -determine_cause (struct MHD_Connection *connection, - const char *instance_id, - const char *template_id, - const struct TALER_MERCHANTDB_TemplateDetails *tp) -{ - struct TALER_MERCHANTDB_TemplateDetails tpx; - enum GNUNET_DB_QueryStatus qs; - - qs = TMH_db->lookup_template (TMH_db->cls, - instance_id, - template_id, - &tpx); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - NULL); - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, - "unexpected serialization problem"); - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN, - template_id); - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; /* do below */ - } - - { - enum TALER_ErrorCode ec; - - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - TALER_MERCHANTDB_template_details_free (&tpx); - GNUNET_break (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE != ec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - ec, - NULL); - } -} - - -/** - * PATCH configuration of an existing instance, given its configuration. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @return MHD result code - */ -MHD_RESULT -TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - struct TMH_MerchantInstance *mi = hc->instance; - const char *template_id = hc->infix; - struct TALER_MERCHANTDB_TemplateDetails tp = {0}; - enum GNUNET_DB_QueryStatus qs; - uint32_t pos_algorithm; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("template_description", - (const char **) &tp.template_description), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_uint32 ("pos_algorithm", - &pos_algorithm), - 0), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("pos_key", - (const char **) &tp.pos_key), - NULL), - GNUNET_JSON_spec_json ("template_contract", - &tp.template_contract), - GNUNET_JSON_spec_end () - }; - - GNUNET_assert (NULL != mi); - GNUNET_assert (NULL != template_id); - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - hc->request_body, - spec); - if (GNUNET_OK != res) - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - } - - tp.pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos_algorithm; - if (! TMH_template_contract_valid (tp.template_contract)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "template_contract"); - } - - qs = TMH_db->update_template (TMH_db->cls, - mi->settings.id, - template_id, - &tp); - { - MHD_RESULT ret = MHD_NO; - - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - NULL); - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, - "unexpected serialization problem"); - break; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - ret = determine_cause (connection, - mi->settings.id, - template_id, - &tp); - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - ret = TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); - break; - } - GNUNET_JSON_parse_free (spec); - return ret; - } -} - - -/* end of taler-merchant-httpd_private-patch-templates-ID.c */ diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index fed9c0a2..ef5b67bb 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -44,6 +44,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-delete-products-ID.h \ taler-merchant-httpd_private-delete-orders-ID.c \ taler-merchant-httpd_private-delete-orders-ID.h \ + taler-merchant-httpd_private-delete-otp-devices-ID.c \ + taler-merchant-httpd_private-delete-otp-devices-ID.h \ taler-merchant-httpd_private-delete-reserves-ID.c \ taler-merchant-httpd_private-delete-reserves-ID.h \ taler-merchant-httpd_private-delete-templates-ID.c \ @@ -52,6 +54,10 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-delete-transfers-ID.h \ taler-merchant-httpd_private-delete-webhooks-ID.c \ taler-merchant-httpd_private-delete-webhooks-ID.h \ + taler-merchant-httpd_private-get-accounts.c \ + taler-merchant-httpd_private-get-accounts.h \ + taler-merchant-httpd_private-get-accounts-ID.c \ + taler-merchant-httpd_private-get-accounts-ID.h \ taler-merchant-httpd_private-get-instances.c \ taler-merchant-httpd_private-get-instances.h \ taler-merchant-httpd_private-get-instances-ID.c \ @@ -66,6 +72,10 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-get-orders.h \ taler-merchant-httpd_private-get-orders-ID.c \ taler-merchant-httpd_private-get-orders-ID.h \ + taler-merchant-httpd_private-get-otp-devices.c \ + taler-merchant-httpd_private-get-otp-devices.h \ + taler-merchant-httpd_private-get-otp-devices-ID.c \ + taler-merchant-httpd_private-get-otp-devices-ID.h \ taler-merchant-httpd_private-get-reserves.c \ taler-merchant-httpd_private-get-reserves.h \ taler-merchant-httpd_private-get-reserves-ID.c \ @@ -80,16 +90,20 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-get-webhooks.h \ taler-merchant-httpd_private-get-webhooks-ID.c \ taler-merchant-httpd_private-get-webhooks-ID.h \ - taler-merchant-httpd_private-patch-templates-ID.c \ - taler-merchant-httpd_private-patch-templates-ID.h \ - taler-merchant-httpd_private-patch-webhooks-ID.c \ - taler-merchant-httpd_private-patch-webhooks-ID.h \ + taler-merchant-httpd_private-patch-accounts-ID.c \ + taler-merchant-httpd_private-patch-accounts-ID.h \ taler-merchant-httpd_private-patch-instances-ID.c \ taler-merchant-httpd_private-patch-instances-ID.h \ taler-merchant-httpd_private-patch-orders-ID-forget.c \ taler-merchant-httpd_private-patch-orders-ID-forget.h \ + taler-merchant-httpd_private-patch-otp-devices-ID.c \ + taler-merchant-httpd_private-patch-otp-devices-ID.h \ taler-merchant-httpd_private-patch-products-ID.c \ taler-merchant-httpd_private-patch-products-ID.h \ + taler-merchant-httpd_private-patch-templates-ID.c \ + taler-merchant-httpd_private-patch-templates-ID.h \ + taler-merchant-httpd_private-patch-webhooks-ID.c \ + taler-merchant-httpd_private-patch-webhooks-ID.h \ taler-merchant-httpd_private-post-account.c \ taler-merchant-httpd_private-post-account.h \ taler-merchant-httpd_private-post-instances.c \ @@ -102,6 +116,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-post-orders.h \ taler-merchant-httpd_private-post-products.c \ taler-merchant-httpd_private-post-products.h \ + taler-merchant-httpd_private-post-otp-devices.c \ + taler-merchant-httpd_private-post-otp-devices.h \ taler-merchant-httpd_private-post-products-ID-lock.c \ taler-merchant-httpd_private-post-products-ID-lock.h \ taler-merchant-httpd_private-post-reserves.c \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index d8be1edc..9c543958 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -37,14 +37,13 @@ #include "taler-merchant-httpd_private-delete-instances-ID.h" #include "taler-merchant-httpd_private-delete-products-ID.h" #include "taler-merchant-httpd_private-delete-orders-ID.h" +#include "taler-merchant-httpd_private-delete-otp-devices-ID.h" #include "taler-merchant-httpd_private-delete-reserves-ID.h" #include "taler-merchant-httpd_private-delete-templates-ID.h" #include "taler-merchant-httpd_private-delete-transfers-ID.h" #include "taler-merchant-httpd_private-delete-webhooks-ID.h" -#include "taler-merchant-httpd_private-get-webhooks.h" -#include "taler-merchant-httpd_private-get-webhooks-ID.h" -#include "taler-merchant-httpd_private-get-templates.h" -#include "taler-merchant-httpd_private-get-templates-ID.h" +#include "taler-merchant-httpd_private-get-accounts.h" +#include "taler-merchant-httpd_private-get-accounts-ID.h" #include "taler-merchant-httpd_private-get-instances.h" #include "taler-merchant-httpd_private-get-instances-ID.h" #include "taler-merchant-httpd_private-get-instances-ID-kyc.h" @@ -52,19 +51,28 @@ #include "taler-merchant-httpd_private-get-products-ID.h" #include "taler-merchant-httpd_private-get-orders.h" #include "taler-merchant-httpd_private-get-orders-ID.h" +#include "taler-merchant-httpd_private-get-otp-devices.h" +#include "taler-merchant-httpd_private-get-otp-devices-ID.h" #include "taler-merchant-httpd_private-get-reserves.h" #include "taler-merchant-httpd_private-get-reserves-ID.h" #include "taler-merchant-httpd_private-get-rewards-ID.h" #include "taler-merchant-httpd_private-get-rewards.h" +#include "taler-merchant-httpd_private-get-templates.h" +#include "taler-merchant-httpd_private-get-templates-ID.h" #include "taler-merchant-httpd_private-get-transfers.h" -#include "taler-merchant-httpd_private-patch-webhooks-ID.h" -#include "taler-merchant-httpd_private-patch-templates-ID.h" +#include "taler-merchant-httpd_private-get-webhooks.h" +#include "taler-merchant-httpd_private-get-webhooks-ID.h" +#include "taler-merchant-httpd_private-patch-accounts-ID.h" #include "taler-merchant-httpd_private-patch-instances-ID.h" #include "taler-merchant-httpd_private-patch-orders-ID-forget.h" +#include "taler-merchant-httpd_private-patch-otp-devices-ID.h" #include "taler-merchant-httpd_private-patch-products-ID.h" +#include "taler-merchant-httpd_private-patch-templates-ID.h" +#include "taler-merchant-httpd_private-patch-webhooks-ID.h" #include "taler-merchant-httpd_private-post-account.h" #include "taler-merchant-httpd_private-post-instances.h" #include "taler-merchant-httpd_private-post-instances-ID-auth.h" +#include "taler-merchant-httpd_private-post-otp-devices.h" #include "taler-merchant-httpd_private-post-orders.h" #include "taler-merchant-httpd_private-post-orders-ID-refund.h" #include "taler-merchant-httpd_private-post-products.h" @@ -1041,6 +1049,39 @@ url_handler (void *cls, .allow_deleted_instance = true, .handler = &TMH_private_get_transfers }, + /* POST /otp-devices: */ + { + .url_prefix = "/otp-devices", + .method = MHD_HTTP_METHOD_POST, + .handler = &TMH_private_post_otp_devices + }, + /* GET /otp-devices: */ + { + .url_prefix = "/otp-devices", + .method = MHD_HTTP_METHOD_GET, + .handler = &TMH_private_get_otp_devices + }, + /* GET /otp-devices/$ID/: */ + { + .url_prefix = "/otp-devices/", + .method = MHD_HTTP_METHOD_GET, + .have_id_segment = true, + .handler = &TMH_private_get_otp_devices_ID + }, + /* DELETE /otp-devices/$ID/: */ + { + .url_prefix = "/otp-devices/", + .method = MHD_HTTP_METHOD_DELETE, + .have_id_segment = true, + .handler = &TMH_private_delete_otp_devices_ID + }, + /* PATCH /otp-devices/$ID/: */ + { + .url_prefix = "/otp-devices/", + .method = MHD_HTTP_METHOD_PATCH, + .have_id_segment = true, + .handler = &TMH_private_patch_otp_devices_ID + }, /* POST /templates: */ { .url_prefix = "/templates", @@ -1133,17 +1174,39 @@ url_handler (void *cls, in the code... */ .max_upload = 1024 * 1024 * 8 }, - /* POST /account: */ + /* POST /accounts: */ { - .url_prefix = "/account", + .url_prefix = "/accounts", .method = MHD_HTTP_METHOD_POST, .handler = &TMH_private_post_account, /* allow account details of up to 8 kb, that should be plenty */ .max_upload = 1024 * 8 }, - /* DELETE /account/$PAYTO: */ + /* PATCH /accounts/$H_WIRE: */ { - .url_prefix = "/account", + .url_prefix = "/accounts", + .method = MHD_HTTP_METHOD_PATCH, + .handler = &TMH_private_patch_accounts_ID, + .have_id_segment = true, + /* allow account details of up to 8 kb, that should be plenty */ + .max_upload = 1024 * 8 + }, + /* GET /accounts: */ + { + .url_prefix = "/accounts", + .method = MHD_HTTP_METHOD_GET, + .handler = &TMH_private_get_accounts + }, + /* GET /accounts/$H_WIRE: */ + { + .url_prefix = "/accounts", + .method = MHD_HTTP_METHOD_GET, + .have_id_segment = true, + .handler = &TMH_private_get_accounts_ID + }, + /* DELETE /accounts/$H_WIRE: */ + { + .url_prefix = "/accounts", .method = MHD_HTTP_METHOD_DELETE, .handler = &TMH_private_delete_account_ID, .have_id_segment = true @@ -1779,6 +1842,31 @@ url_handler (void *cls, /** + * Callback invoked with information about a bank account. + * + * @param cls closure with a `struct TMH_MerchantInstance *` + * @param ad details about the account + */ +static void +add_account_cb (void *cls, + const struct TALER_MERCHANTDB_AccountDetails *acc) +{ + struct TMH_MerchantInstance *mi = cls; + struct TMH_WireMethod *wm; + + wm = GNUNET_new (struct TMH_WireMethod); + wm->h_wire = acc->h_wire; + wm->payto_uri = GNUNET_strdup (acc->payto_uri); + wm->wire_salt = acc->salt; + wm->wire_method = TALER_payto_get_method (acc->payto_uri); + wm->active = acc->active; + GNUNET_CONTAINER_DLL_insert (mi->wm_head, + mi->wm_tail, + wm); +} + + +/** * Function called during startup to add all known instances to our * hash map in memory for faster lookups when we receive requests. * @@ -1787,20 +1875,17 @@ url_handler (void *cls, * @param merchant_priv private key of the instance, NULL if not available * @param is detailed configuration settings for the instance * @param ias authentication settings for the instance - * @param accounts_length length of the @a accounts array - * @param accounts list of accounts of the merchant */ static void add_instance_cb (void *cls, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantPrivateKeyP *merchant_priv, const struct TALER_MERCHANTDB_InstanceSettings *is, - const struct TALER_MERCHANTDB_InstanceAuthSettings *ias, - unsigned int accounts_length, - const struct TALER_MERCHANTDB_AccountDetails accounts[]) + const struct TALER_MERCHANTDB_InstanceAuthSettings *ias) { struct TMH_MerchantInstance *mi; - + enum GNUNET_DB_QueryStatus qs; + (void) cls; mi = TMH_lookup_instance (is->id); if (NULL != mi) @@ -1829,20 +1914,15 @@ add_instance_cb (void *cls, else mi->deleted = true; mi->merchant_pub = *merchant_pub; - for (unsigned int i = 0; i<accounts_length; i++) + qs = TMH_db->select_accounts (TMH_db->cls, + mi->settings.id, + &add_account_cb, + mi); + if (0 > qs) { - const struct TALER_MERCHANTDB_AccountDetails *acc = &accounts[i]; - struct TMH_WireMethod *wm; - - wm = GNUNET_new (struct TMH_WireMethod); - wm->h_wire = acc->h_wire; - wm->payto_uri = GNUNET_strdup (acc->payto_uri); - wm->wire_salt = acc->salt; - wm->wire_method = TALER_payto_get_method (acc->payto_uri); - wm->active = acc->active; - GNUNET_CONTAINER_DLL_insert (mi->wm_head, - mi->wm_tail, - wm); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error loading accounts of `%s' from database\n", + mi->settings.id); } GNUNET_assert (GNUNET_OK == TMH_add_instance (mi)); diff --git a/src/backend/taler-merchant-httpd_post-using-templates.c b/src/backend/taler-merchant-httpd_post-using-templates.c index 74eb0f44..67fc4b1e 100644 --- a/src/backend/taler-merchant-httpd_post-using-templates.c +++ b/src/backend/taler-merchant-httpd_post-using-templates.c @@ -73,7 +73,6 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh, struct TMH_HandlerContext *hc) { struct TMH_MerchantInstance *mi = hc->instance; - MHD_RESULT mret; const char *template_id = hc->infix; const char *summary = NULL; const char *fulfillment_url = NULL; @@ -252,6 +251,9 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh, } no_summary = (NULL == summary); fake_body = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("otp_id", + uc->etp.otp_id)), GNUNET_JSON_pack_object_steal ( "order", GNUNET_JSON_PACK ( @@ -276,11 +278,8 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh, } uc->ihc.request_body = fake_body; - mret = TMH_private_post_orders_with_pos_secrets ( + return TMH_private_post_orders ( NULL, /* not even used */ connection, - &uc->ihc, - uc->etp.pos_key, - uc->etp.pos_algorithm); - return mret; + &uc->ihc); } diff --git a/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c new file mode 100644 index 00000000..b147b84f --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.c @@ -0,0 +1,78 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-delete-otp-devices-ID.c + * @brief implement DELETE /otp-devices/$ID + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-delete-otp-devices-ID.h" +#include <taler/taler_json_lib.h> + + +/** + * Handle a DELETE "/otp-devices/$ID" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_delete_otp_devices_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + enum GNUNET_DB_QueryStatus qs; + + (void) rh; + GNUNET_assert (NULL != mi); + GNUNET_assert (NULL != hc->infix); + qs = TMH_db->delete_otp (TMH_db->cls, + mi->settings.id, + hc->infix); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "delete_otp"); + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "delete_otp (soft)"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN, + hc->infix); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); + } + GNUNET_assert (0); + return MHD_NO; +} + + +/* end of taler-merchant-httpd_private-delete-otp-devices-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.h b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.h new file mode 100644 index 00000000..cd129d0d --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-delete-otp-devices-ID.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-delete-otp-devices-ID.h + * @brief implement DELETE /otp-devices/$ID/ + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_DELETE_OTP_DEVICES_ID_H +#define TALER_MERCHANT_HTTPD_PRIVATE_DELETE_OTP_DEVICES_ID_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a DELETE "/otp-devices/$ID" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_delete_otp_devices_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-delete-otp-devices-ID.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-accounts-ID.c b/src/backend/taler-merchant-httpd_private-get-accounts-ID.c new file mode 100644 index 00000000..703beeca --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-accounts-ID.c @@ -0,0 +1,103 @@ +/* + This file is part of TALER + (C) 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-accounts-ID.c + * @brief implement GET /accounts/$ID + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-get-accounts-ID.h" +#include <taler/taler_json_lib.h> + + +/** + * Handle a GET "/accounts/$ID" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_accounts_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + const char *h_wire_s = hc->infix; + struct TALER_MerchantWireHashP h_wire; + struct TALER_MERCHANTDB_AccountDetails tp = { 0 }; + enum GNUNET_DB_QueryStatus qs; + + GNUNET_assert (NULL != mi); + GNUNET_assert (NULL != h_wire_s); + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (h_wire_s, + strlen (h_wire_s), + &h_wire, + sizeof (h_wire))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED, + h_wire_s); + } + qs = TMH_db->select_account (TMH_db->cls, + mi->settings.id, + &h_wire, + &tp); + if (0 > qs) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "lookup_account"); + } + if (0 == qs) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN, + hc->infix); + } + { + MHD_RESULT ret; + + ret = TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("payto_uri", + tp.payto_uri), + GNUNET_JSON_pack_data_auto ("h_wire", + &tp.h_wire), + GNUNET_JSON_pack_data_auto ("salt", + &tp.salt), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("credit_facade_url", + tp.credit_facade_url))); + /* We do not return the credentials, as they may + be sensitive */ + json_decref (tp.credit_facade_credentials); + GNUNET_free (tp.payto_uri); + GNUNET_free (tp.credit_facade_url); + return ret; + } +} + + +/* end of taler-merchant-httpd_private-get-accounts-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-accounts-ID.h b/src/backend/taler-merchant-httpd_private-get-accounts-ID.h new file mode 100644 index 00000000..da5cb729 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-accounts-ID.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-accounts-ID.h + * @brief implement GET /accounts/$ID/ + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_ID_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_ID_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a GET "/accounts/$ID" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_accounts_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-get-accounts-ID.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-accounts.c b/src/backend/taler-merchant-httpd_private-get-accounts.c new file mode 100644 index 00000000..92ebb368 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-accounts.c @@ -0,0 +1,78 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-accounts.c + * @brief implement GET /accounts + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-get-accounts.h" + + +/** + * Add account details to our JSON array. + * + * @param cls a `json_t *` JSON array to build + * @param ad details about the account + */ +static void +add_account (void *cls, + const struct TALER_MERCHANTDB_AccountDetails *ad) +{ + json_t *pa = cls; + + GNUNET_assert (0 == + json_array_append_new ( + pa, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("payto_uri", + ad->payto_uri), + GNUNET_JSON_pack_data_auto ("h_wire", + &ad->h_wire)))); +} + + +MHD_RESULT +TMH_private_get_accounts (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + json_t *pa; + enum GNUNET_DB_QueryStatus qs; + + pa = json_array (); + GNUNET_assert (NULL != pa); + qs = TMH_db->select_accounts (TMH_db->cls, + hc->instance->settings.id, + &add_account, + pa); + if (0 > qs) + { + GNUNET_break (0); + json_decref (pa); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + NULL); + } + return TALER_MHD_REPLY_JSON_PACK (connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("accounts", + pa)); +} + + +/* end of taler-merchant-httpd_private-get-accounts.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-accounts.h b/src/backend/taler-merchant-httpd_private-get-accounts.h new file mode 100644 index 00000000..0e9897cf --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-accounts.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-accounts.h + * @brief implement GET /accounts + * @author Priscilla HUANG + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_ACCOUNTS_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a GET "/accounts" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_accounts (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-get-accounts.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.c b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.c new file mode 100644 index 00000000..747e30cd --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.c @@ -0,0 +1,83 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-otp-devices-ID.c + * @brief implement GET /otp-devices/$ID + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-get-otp-devices-ID.h" +#include <taler/taler_json_lib.h> + + +/** + * Handle a GET "/otp-devices/$ID" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_otp_devices_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + struct TALER_MERCHANTDB_OtpDeviceDetails tp = { 0 }; + enum GNUNET_DB_QueryStatus qs; + + GNUNET_assert (NULL != mi); + qs = TMH_db->select_otp (TMH_db->cls, + mi->settings.id, + hc->infix, + &tp); + if (0 > qs) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "select_otp"); + } + if (0 == qs) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN, + hc->infix); + } + { + MHD_RESULT ret; + + /* Note: we deliberately (by design) do not return the otp_key */ + ret = TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("device_description", + tp.otp_description), + GNUNET_JSON_pack_uint64 ("otp_algorithm", + tp.otp_algorithm), + GNUNET_JSON_pack_uint64 ("otp_ctr", + tp.otp_ctr)); + GNUNET_free (tp.otp_description); + GNUNET_free (tp.otp_key); + return ret; + } +} + + +/* end of taler-merchant-httpd_private-get-otp-devices-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.h b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.h new file mode 100644 index 00000000..78834f67 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-otp-devices-ID.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-otp-devices-ID.h + * @brief implement GET /otp-devices/$ID/ + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_ID_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_ID_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a GET "/otp-devices/$ID" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_otp_devices_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-get-otp-devices-ID.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices.c b/src/backend/taler-merchant-httpd_private-get-otp-devices.c new file mode 100644 index 00000000..df86842b --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-otp-devices.c @@ -0,0 +1,80 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-otp-devices.c + * @brief implement GET /otp-devices + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-get-otp-devices.h" + + +/** + * Add OTP device details to our JSON array. + * + * @param cls a `json_t *` JSON array to build + * @param template_id ID of the template + * @param template_description human-readable description for the template + */ +static void +add_otp (void *cls, + const char *otp_id, + const char *otp_description) +{ + json_t *pa = cls; + + GNUNET_assert (0 == + json_array_append_new ( + pa, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("otp_device_id", + otp_id), + GNUNET_JSON_pack_string ("device_description", + otp_description)))); +} + + +MHD_RESULT +TMH_private_get_otp_devices (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + json_t *pa; + enum GNUNET_DB_QueryStatus qs; + + pa = json_array (); + GNUNET_assert (NULL != pa); + qs = TMH_db->lookup_otp_devices (TMH_db->cls, + hc->instance->settings.id, + &add_otp, + pa); + if (0 > qs) + { + GNUNET_break (0); + json_decref (pa); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + NULL); + } + return TALER_MHD_REPLY_JSON_PACK (connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("otp_devices", + pa)); +} + + +/* end of taler-merchant-httpd_private-get-otp-devices.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-otp-devices.h b/src/backend/taler-merchant-httpd_private-get-otp-devices.h new file mode 100644 index 00000000..a97ca179 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-get-otp-devices.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-merchant-httpd_private-get-otp-devices.h + * @brief implement GET /otp-devices + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_H +#define TALER_MERCHANT_HTTPD_PRIVATE_GET_OTP_DEVICES_H + +#include "taler-merchant-httpd.h" + + +/** + * Handle a GET "/otp-devices" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_get_otp_devices (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +/* end of taler-merchant-httpd_private-get-otp-devices.h */ +#endif diff --git a/src/backend/taler-merchant-httpd_private-get-templates-ID.c b/src/backend/taler-merchant-httpd_private-get-templates-ID.c index bdb1de9d..e9dfc00f 100644 --- a/src/backend/taler-merchant-httpd_private-get-templates-ID.c +++ b/src/backend/taler-merchant-httpd_private-get-templates-ID.c @@ -68,16 +68,13 @@ TMH_private_get_templates_ID (const struct TMH_RequestHandler *rh, MHD_HTTP_OK, GNUNET_JSON_pack_string ("template_description", tp.template_description), - GNUNET_JSON_pack_uint64 ("pos_algorithm", - tp.pos_algorithm), GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("pos_key", - tp.pos_key)), + GNUNET_JSON_pack_string ("otp_id", + tp.otp_id)), GNUNET_JSON_pack_object_steal ("template_contract", tp.template_contract)); GNUNET_free (tp.template_description); - GNUNET_free (tp.pos_key); - + GNUNET_free (tp.otp_id); return ret; } } diff --git a/src/backend/taler-merchant-httpd_private-patch-accounts-ID.c b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.c new file mode 100644 index 00000000..04fe4ce5 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.c @@ -0,0 +1,132 @@ +/* + This file is part of TALER + (C) 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-patch-accounts-ID.c + * @brief implementing PATCH /accounts/$ID request handling + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-patch-accounts-ID.h" +#include "taler-merchant-httpd_helper.h" +#include <taler/taler_json_lib.h> + + +/** + * PATCH configuration of an existing instance, given its configuration. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_patch_accounts_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + const char *h_wire_s = hc->infix; + enum GNUNET_DB_QueryStatus qs; + const json_t *cfc; + const char *cfu; + struct TALER_MerchantWireHashP h_wire; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("credit_facade_url", + (const char **) &cfu), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_object_const ("credit_facade_credentials", + &cfc), + NULL), + GNUNET_JSON_spec_end () + }; + + GNUNET_assert (NULL != mi); + GNUNET_assert (NULL != h_wire_s); + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (h_wire_s, + strlen (h_wire_s), + &h_wire, + sizeof (h_wire))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED, + h_wire_s); + } + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_OK != res) + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + + qs = TMH_db->update_account (TMH_db->cls, + mi->settings.id, + &h_wire, + cfu, + cfc); + { + MHD_RESULT ret = MHD_NO; + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "update_account"); + break; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "unexpected serialization problem"); + break; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN, + h_wire_s); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + ret = TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); + break; + } + GNUNET_JSON_parse_free (spec); + return ret; + } +} + + +/* end of taler-merchant-httpd_private-patch-accounts-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-patch-accounts-ID.h b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.h new file mode 100644 index 00000000..752fb958 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-patch-accounts-ID.h @@ -0,0 +1,43 @@ +/* + This file is part of TALER + (C) 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-patch-accounts-ID.h + * @brief implementing PATCH /accounts request handling + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_PATCH_ACCOUNTS_ID_H +#define TALER_MERCHANT_HTTPD_PRIVATE_PATCH_ACCOUNTS_ID_H +#include "taler-merchant-httpd.h" + + +/** + * PATCH configuration of an existing instance, given its configuration. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_patch_accounts_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +#endif diff --git a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c index bc6e3aae..027d5869 100644 --- a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c +++ b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c @@ -63,14 +63,11 @@ patch_instances_ID (struct TMH_MerchantInstance *mi, struct TMH_HandlerContext *hc) { struct TALER_MERCHANTDB_InstanceSettings is; - const json_t *accounts; const char *name; const char *uts = "business"; struct TMH_WireMethod *wm_head = NULL; struct TMH_WireMethod *wm_tail = NULL; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("accounts", - &accounts), GNUNET_JSON_spec_string ("name", &name), GNUNET_JSON_spec_mark_optional ( @@ -102,7 +99,6 @@ patch_instances_ID (struct TMH_MerchantInstance *mi, GNUNET_JSON_spec_end () }; enum GNUNET_DB_QueryStatus qs; - bool committed = false; GNUNET_assert (NULL != mi); memset (&is, @@ -162,14 +158,6 @@ patch_instances_ID (struct TMH_MerchantInstance *mi, "jurisdiction"); } - if (! TMH_accounts_array_valid (accounts)) - { - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PAYTO_URI_MALFORMED, - NULL); - } for (unsigned int retry = 0; retry<MAX_RETRIES; retry++) { /* Cleanup after earlier loops */ @@ -236,258 +224,13 @@ patch_instances_ID (struct TMH_MerchantInstance *mi, goto giveup; } } - - /* Check for changes in accounts */ - { - unsigned int len = json_array_size (accounts); - struct TMH_WireMethod *matches[GNUNET_NZL (len)]; - bool updated[GNUNET_NZL (len)]; - - memset (matches, - 0, - sizeof (matches)); - memset (updated, - 0, - sizeof (updated)); - for (struct TMH_WireMethod *wm = mi->wm_head; - NULL != wm; - wm = wm->next) - { - bool matched = false; - for (unsigned int i = 0; i<len; i++) - { - json_t *account = json_array_get (accounts, - i); - enum GNUNET_GenericReturnValue ret; - - ret = TMH_cmp_wire_account (account, - wm); - switch (ret) - { - case GNUNET_SYSERR: - continue; - case GNUNET_NO: - matched = true; - /* our own existing payto URIs should be unique, that is no - duplicates in the list, so we cannot match twice */ - GNUNET_assert (NULL == matches[i]); - matches[i] = wm; - updated[i] = true; - break; - case GNUNET_YES: - matched = true; - /* our own existing payto URIs should be unique, that is no - duplicates in the list, so we cannot match twice */ - GNUNET_assert (NULL == matches[i]); - matches[i] = wm; - break; - } - } - - /* delete unmatched (= removed) accounts */ - if ( (! matched) && - (wm->active) ) - { - /* Account was REMOVED */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Existing account `%s' not found, deactivating it.\n", - wm->payto_uri); - wm->deleting = true; - qs = TMH_db->inactivate_account (TMH_db->cls, - mi->settings.id, - &wm->h_wire); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto retry; - else - goto giveup; - } - } - } /* for (wm) */ - - /* handle updates */ - for (unsigned int i = 0; i<len; i++) - { - struct TMH_WireMethod *wm = matches[i]; - - if (! updated[i]) - continue; - GNUNET_assert (NULL != wm); - { - struct TALER_MERCHANTDB_AccountDetails ad = { - .payto_uri = wm->payto_uri, - .h_wire = wm->h_wire, - .salt = wm->wire_salt, - .credit_facade_url = wm->credit_facade_url, - .credit_facade_credentials = wm->credit_facade_credentials, - .active = true - }; - - qs = TMH_db->update_account (TMH_db->cls, - mi->settings.id, - &ad); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto retry; - else - goto giveup; - } - } /* ad scope */ - } /* for possible updates */ - - /* Find _new_ accounts or accounts to only enable */ - for (unsigned int i = 0; i<len; i++) - { - json_t *account = json_array_get (accounts, - i); - struct TMH_WireMethod *wm = matches[i]; - - if (NULL != wm) - { - if (updated[i]) - continue; /* handled above */ - if (! wm->active) - { - qs = TMH_db->activate_account (TMH_db->cls, - mi->settings.id, - &wm->h_wire); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto retry; - else - goto giveup; - } - } - wm->enabling = true; - continue; - } - - { - const char *credit_facade_url = NULL; - const json_t *credit_facade_credentials = NULL; - const char *uri; - struct GNUNET_JSON_Specification ispec[] = { - GNUNET_JSON_spec_string ("payto_uri", - &uri), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("credit_facade_url", - &credit_facade_url), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_object_const ("credit_facade_credentials", - &credit_facade_credentials), - NULL), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - account, - ispec); - if (GNUNET_OK != res) - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Adding NEW account `%s'\n", - uri); - wm = TMH_setup_wire_account (uri, - credit_facade_url, - credit_facade_credentials); - GNUNET_assert (NULL != wm); /* checked payto_uri validity earlier */ - GNUNET_CONTAINER_DLL_insert (wm_head, - wm_tail, - wm); - } /* ispec scope */ - - { - struct TALER_MERCHANTDB_AccountDetails ad = { - .payto_uri = wm->payto_uri, - .h_wire = wm->h_wire, - .salt = wm->wire_salt, - .credit_facade_url = wm->credit_facade_url, - .credit_facade_credentials = wm->credit_facade_credentials, - .active = true - }; - - qs = TMH_db->insert_account (TMH_db->cls, - mi->settings.id, - &ad); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - goto retry; - else - goto giveup; - } - } /* ad variable scope */ - } /* for (i) to find new accounts */ - } /* scope for checking for account changes */ - - { - struct GNUNET_DB_EventHeaderP es = { - .size = htons (sizeof (es)), - .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED) - }; - - TMH_db->event_notify (TMH_db->cls, - &es, - NULL, - 0); - } qs = TMH_db->commit (TMH_db->cls); retry: if (GNUNET_DB_STATUS_SOFT_ERROR == qs) continue; - if (qs >= 0) - committed = true; break; } /* for(... MAX_RETRIES) */ giveup: - /* Deactivate existing wire methods that were removed above */ - for (struct TMH_WireMethod *wm = mi->wm_head; - NULL != wm; - wm = wm->next) - { - /* We did not flip the 'active' bits earlier because the - DB transaction could still fail. Now it is time to update our - runtime state. */ - GNUNET_assert (! (wm->deleting & wm->enabling)); - if (committed) - { - if (wm->deleting) - wm->active = false; - if (wm->enabling) - wm->active = true; - } - wm->deleting = false; - wm->enabling = false; - } - if (! committed) - { - struct TMH_WireMethod *wm; - - while (NULL != (wm = wm_head)) - { - GNUNET_CONTAINER_DLL_remove (wm_head, - wm_tail, - wm); - free_wm (wm); - } - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_COMMIT_FAILED, - NULL); - } - /* Update our 'settings' */ GNUNET_free (mi->settings.name); GNUNET_free (mi->settings.email); @@ -508,23 +251,6 @@ giveup: if (NULL != is.logo) mi->settings.logo = GNUNET_strdup (is.logo); - /* Add 'new' wire methods to our list */ - { - struct TMH_WireMethod *wm; - - /* Note: this _could_ be done more efficiently if - someone wrote a GNUNET_CONTAINER_DLL_merge()... */ - while (NULL != (wm = wm_head)) - { - GNUNET_CONTAINER_DLL_remove (wm_head, - wm_tail, - wm); - GNUNET_CONTAINER_DLL_insert (mi->wm_head, - mi->wm_tail, - wm); - } - } - GNUNET_JSON_parse_free (spec); TMH_reload_instances (mi->settings.id); return TALER_MHD_reply_static (connection, diff --git a/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.c b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.c new file mode 100644 index 00000000..f0fc8b0b --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.c @@ -0,0 +1,122 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-patch-otp-devices-ID.c + * @brief implementing PATCH /otp-devices/$ID request handling + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-patch-otp-devices-ID.h" +#include "taler-merchant-httpd_helper.h" +#include <taler/taler_json_lib.h> + + +/** + * PATCH OTP device of an existing instance. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_patch_otp_devices_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + const char *device_id = hc->infix; + struct TALER_MERCHANTDB_OtpDeviceDetails tp = {0}; + enum GNUNET_DB_QueryStatus qs; + uint32_t otp_algorithm; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("otp_description", + (const char **) &tp.otp_description), + GNUNET_JSON_spec_uint32 ("otp_algorithm", + &otp_algorithm), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint64 ("otp_ctr", + &tp.otp_ctr), + NULL), + GNUNET_JSON_spec_string ("otp_key", + (const char **) &tp.otp_key), + GNUNET_JSON_spec_end () + }; + + GNUNET_assert (NULL != mi); + GNUNET_assert (NULL != device_id); + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_OK != res) + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + + tp.otp_algorithm = (enum TALER_MerchantConfirmationAlgorithm) otp_algorithm; + + qs = TMH_db->update_otp (TMH_db->cls, + mi->settings.id, + device_id, + &tp); + { + MHD_RESULT ret = MHD_NO; + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "update_pos"); + break; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "unexpected serialization problem"); + break; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN, + device_id); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + ret = TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); + break; + } + GNUNET_JSON_parse_free (spec); + return ret; + } +} + + +/* end of taler-merchant-httpd_private-patch-otp-devices-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.h b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.h new file mode 100644 index 00000000..eef1dd0a --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-patch-otp-devices-ID.h @@ -0,0 +1,44 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-patch-otp-devices-ID.h + * @brief implementing PATCH /otp-devices/$ID request handling + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_PATCH_OTP_DEVICES_ID_H +#define TALER_MERCHANT_HTTPD_PRIVATE_PATCH_OTP_DEVICES_ID_H + +#include "taler-merchant-httpd.h" + + +/** + * PATCH configuration of an existing instance, given its configuration. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_patch_otp_devices_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +#endif diff --git a/src/backend/taler-merchant-httpd_private-patch-templates-ID.c b/src/backend/taler-merchant-httpd_private-patch-templates-ID.c index b5938368..68e0a478 100644 --- a/src/backend/taler-merchant-httpd_private-patch-templates-ID.c +++ b/src/backend/taler-merchant-httpd_private-patch-templates-ID.c @@ -29,12 +29,6 @@ /** - * How often do we retry the simple INSERT database transaction? - */ -#define MAX_RETRIES 3 - - -/** * Determine the cause of the PATCH failure in more detail and report. * * @param connection connection to report on @@ -109,17 +103,12 @@ TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh, const char *template_id = hc->infix; struct TALER_MERCHANTDB_TemplateDetails tp = {0}; enum GNUNET_DB_QueryStatus qs; - uint32_t pos_algorithm; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("template_description", (const char **) &tp.template_description), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_uint32 ("pos_algorithm", - &pos_algorithm), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("pos_key", - (const char **) &tp.pos_key), + GNUNET_JSON_spec_string ("otp_id", + (const char **) &tp.otp_id), NULL), GNUNET_JSON_spec_json ("template_contract", &tp.template_contract), @@ -140,7 +129,6 @@ TMH_private_patch_templates_ID (const struct TMH_RequestHandler *rh, : MHD_NO; } - tp.pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos_algorithm; if (! TMH_template_contract_valid (tp.template_contract)) { GNUNET_break_op (0); diff --git a/src/backend/taler-merchant-httpd_private-post-account.c b/src/backend/taler-merchant-httpd_private-post-account.c index f9be253c..73abfe48 100644 --- a/src/backend/taler-merchant-httpd_private-post-account.c +++ b/src/backend/taler-merchant-httpd_private-post-account.c @@ -19,7 +19,7 @@ /** * @file taler-merchant-httpd_private-post-account.c - * @brief implementing POST /private/account request handling + * @brief implementing POST /private/accounts request handling * @author Christian Grothoff */ #include "platform.h" @@ -173,11 +173,12 @@ TMH_private_post_account (const struct TMH_RequestHandler *rh, /* Note: we may not need to do this, as we notified about the account change above. But also hardly hurts. */ TMH_reload_instances (mi->settings.id); - return TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); + return TALER_MHD_REPLY_JSON_PACK (connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_data_auto ("salt", + &wm->wire_salt), + GNUNET_JSON_pack_data_auto ("h_wire", + &wm->h_wire)); } diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c b/src/backend/taler-merchant-httpd_private-post-instances.c index 6c9727e9..398a846d 100644 --- a/src/backend/taler-merchant-httpd_private-post-instances.c +++ b/src/backend/taler-merchant-httpd_private-post-instances.c @@ -37,56 +37,6 @@ /** - * Check if the array of @a payto_uris contains exactly the same - * URIs as those already in @a mi (possibly in a different order). - * - * @param mi a merchant instance with accounts - * @param accounts a JSON array with accounts (presumably) - * @return true if they are 'equal', false if not or of payto_uris is not an array - */ -static bool -accounts_equal (const struct TMH_MerchantInstance *mi, - const json_t *accounts) -{ - if (! json_is_array (accounts)) - return false; - { - unsigned int len = json_array_size (accounts); - enum GNUNET_GenericReturnValue matches[GNUNET_NZL (len)]; - - for (unsigned int i = 0; i<len; i++) - matches[i] = GNUNET_SYSERR; - for (struct TMH_WireMethod *wm = mi->wm_head; - NULL != wm; - wm = wm->next) - { - for (unsigned int i = 0; i<len; i++) - { - json_t *account = json_array_get (accounts, - i); - enum GNUNET_GenericReturnValue ret; - - ret = TMH_cmp_wire_account (account, - wm); - if (GNUNET_SYSERR == ret) - continue; - if (GNUNET_SYSERR != matches[i]) - { - GNUNET_break (0); - return false; /* duplicate entry!? */ - } - matches[i] = ret; - } - } - for (unsigned int i = 0; i<len; i++) - if (GNUNET_YES != matches[i]) - return false; - } - return true; -} - - -/** * Generate an instance, given its configuration. * * @param rh context of the handler @@ -101,15 +51,12 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, { struct TALER_MERCHANTDB_InstanceSettings is; struct TALER_MERCHANTDB_InstanceAuthSettings ias; - const json_t *accounts; const char *auth_token = NULL; const char *uts = "business"; struct TMH_WireMethod *wm_head = NULL; struct TMH_WireMethod *wm_tail = NULL; const json_t *jauth; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_array_const ("accounts", - &accounts), GNUNET_JSON_spec_string ("id", (const char **) &is.id), GNUNET_JSON_spec_string ("name", @@ -179,16 +126,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; } - /* check accounts for well-formedness */ - if (! TMH_accounts_array_valid (accounts)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PAYTO_URI_MALFORMED, - NULL); - } - /* check 'id' well-formed */ { static bool once; @@ -292,9 +229,7 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, is.default_wire_transfer_delay)) && (GNUNET_TIME_relative_cmp (mi->settings.default_pay_delay, ==, - is.default_pay_delay)) && - (accounts_equal (mi, - accounts)) ) + is.default_pay_delay)) ) { return TALER_MHD_reply_static (connection, MHD_HTTP_NO_CONTENT, @@ -312,50 +247,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, } } - /* convert provided payto URIs into internal data structure with salts */ - { - unsigned int len = json_array_size (accounts); - - for (unsigned int i = 0; i<len; i++) - { - json_t *account = json_array_get (accounts, - i); - const char *credit_facade_url = NULL; - const json_t *credit_facade_credentials = NULL; - const char *uri; - struct TMH_WireMethod *wm; - struct GNUNET_JSON_Specification ispec[] = { - GNUNET_JSON_spec_string ("payto_uri", - &uri), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("credit_facade_url", - &credit_facade_url), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_object_const ("credit_facade_credentials", - &credit_facade_credentials), - NULL), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (connection, - account, - ispec); - if (GNUNET_OK != res) - return (GNUNET_NO == res) - ? MHD_YES - : MHD_NO; - wm = TMH_setup_wire_account (uri, - credit_facade_url, - credit_facade_credentials); - GNUNET_assert (NULL != wm); - GNUNET_CONTAINER_DLL_insert (wm_head, - wm_tail, - wm); - } - } - /* handle authentication token setup */ if (NULL == auth_token) { @@ -431,44 +322,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, TMH_instance_decref (mi); return ret; } - for (struct TMH_WireMethod *wm = wm_head; - NULL != wm; - wm = wm->next) - { - struct TALER_MERCHANTDB_AccountDetails ad = { - .payto_uri = wm->payto_uri, - .salt = wm->wire_salt, - .h_wire = wm->h_wire, - .credit_facade_url = wm->credit_facade_url, - .credit_facade_credentials = wm->credit_facade_credentials, - .active = wm->active - }; - - qs = TMH_db->insert_account (TMH_db->cls, - mi->settings.id, - &ad); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - break; - } - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - TMH_db->rollback (TMH_db->cls); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - break; - goto retry; - } - { - struct GNUNET_DB_EventHeaderP es = { - .size = htons (sizeof (es)), - .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED) - }; - - TMH_db->event_notify (TMH_db->cls, - &es, - NULL, - 0); - } qs = TMH_db->commit (TMH_db->cls); if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c index 1c888508..34fac6a0 100644 --- a/src/backend/taler-merchant-httpd_private-post-orders.c +++ b/src/backend/taler-merchant-httpd_private-post-orders.c @@ -1760,11 +1760,17 @@ merge_inventory (struct OrderContext *oc) } +/** + * Parse the basics of the client request. + * + * @param[in,out] oc order context to process + */ static void parse_order_request (struct OrderContext *oc) { const json_t *ip = NULL; const json_t *uuid = NULL; + const char *otp_id = NULL; bool create_token = true; /* default */ struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_json ("order", @@ -1789,6 +1795,10 @@ parse_order_request (struct OrderContext *oc) GNUNET_JSON_spec_bool ("create_token", &create_token), NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("otp_id", + &otp_id), + NULL), GNUNET_JSON_spec_end () }; enum GNUNET_GenericReturnValue ret; @@ -1808,6 +1818,43 @@ parse_order_request (struct OrderContext *oc) GNUNET_TIME_relative2s (oc->refund_delay, false)); TMH_db->expire_locks (TMH_db->cls); + if (NULL != otp_id) + { + struct TALER_MERCHANTDB_OtpDeviceDetails td; + enum GNUNET_DB_QueryStatus qs; + + qs = TMH_db->select_otp (TMH_db->cls, + oc->hc->instance->settings.id, + otp_id, + &td); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + reply_with_error (oc, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "select_otp"); + return; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + reply_with_error (oc, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_SOFT_FAILURE, + "select_otp"); + return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + reply_with_error (oc, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN, + otp_id); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + oc->pos_key = td.otp_key; + oc->pos_algorithm = td.otp_algorithm; + } if (create_token) { GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, @@ -1912,12 +1959,10 @@ parse_order_request (struct OrderContext *oc) MHD_RESULT -TMH_private_post_orders_with_pos_secrets ( +TMH_private_post_orders ( const struct TMH_RequestHandler *rh, struct MHD_Connection *connection, - struct TMH_HandlerContext *hc, - const char *pos_key, - enum TALER_MerchantConfirmationAlgorithm pos_algorithm) + struct TMH_HandlerContext *hc) { struct OrderContext *oc = hc->ctx; @@ -1928,8 +1973,6 @@ TMH_private_post_orders_with_pos_secrets ( hc->cc = &clean_order; oc->connection = connection; oc->hc = hc; - oc->pos_key = pos_key; - oc->pos_algorithm = pos_algorithm; } while (1) { @@ -1976,18 +2019,4 @@ TMH_private_post_orders_with_pos_secrets ( } -MHD_RESULT -TMH_private_post_orders ( - const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) -{ - return TMH_private_post_orders_with_pos_secrets (rh, - connection, - hc, - NULL, - TALER_MCA_NONE); -} - - /* end of taler-merchant-httpd_private-post-orders.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-orders.h b/src/backend/taler-merchant-httpd_private-post-orders.h index cbbb59c0..f1127bec 100644 --- a/src/backend/taler-merchant-httpd_private-post-orders.h +++ b/src/backend/taler-merchant-httpd_private-post-orders.h @@ -46,25 +46,5 @@ TMH_private_post_orders (const struct TMH_RequestHandler *rh, struct MHD_Connection *connection, struct TMH_HandlerContext *hc); -/** - * Generate an order. We add the fields 'exchanges', 'merchant_pub', and - * 'H_wire' to the order gotten from the frontend, as well as possibly other - * fields if the frontend did not provide them. Returns the order_id. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] hc context with further information about the request - * @param pos_key key identifying the POS, can be NULL - * @param pos_algorithm algorithm for computing the POS confirmation - * @return MHD result code - */ -MHD_RESULT -TMH_private_post_orders_with_pos_secrets ( - const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc, - const char *pos_key, - enum TALER_MerchantConfirmationAlgorithm pos_algorithm); - #endif diff --git a/src/backend/taler-merchant-httpd_private-post-otp-devices.c b/src/backend/taler-merchant-httpd_private-post-otp-devices.c new file mode 100644 index 00000000..5521ce97 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-otp-devices.c @@ -0,0 +1,201 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-post-otp-devices.c + * @brief implementing POST /otp-devices request handling + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_private-post-otp-devices.h" +#include "taler-merchant-httpd_helper.h" +#include <taler/taler_json_lib.h> + + +/** + * How often do we retry the simple INSERT database transaction? + */ +#define MAX_RETRIES 3 + + +/** + * Check if the two otp-devices are identical. + * + * @param t1 device to compare + * @param t2 other device to compare + * @return true if they are 'equal', false if not or of payto_uris is not an array + */ +static bool +otp_devices_equal (const struct TALER_MERCHANTDB_OtpDeviceDetails *t1, + const struct TALER_MERCHANTDB_OtpDeviceDetails *t2) +{ + return ( (0 == strcmp (t1->otp_description, + t2->otp_description)) && + (0 == strcmp (t1->otp_key, + t2->otp_key) ) && + (t1->otp_ctr == t2->otp_ctr) && + (t1->otp_algorithm == t2->otp_algorithm) ); +} + + +MHD_RESULT +TMH_private_post_otp_devices (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TMH_MerchantInstance *mi = hc->instance; + struct TALER_MERCHANTDB_OtpDeviceDetails tp = { 0 }; + const char *device_id; + enum GNUNET_DB_QueryStatus qs; + uint32_t otp_algorithm; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("otp_device_id", + &device_id), + GNUNET_JSON_spec_string ("otp_device_description", + (const char **) &tp.otp_description), + GNUNET_JSON_spec_uint32 ("otp_algorithm", + &otp_algorithm), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint64 ("otp_ctr", + &tp.otp_ctr), + NULL), + GNUNET_JSON_spec_string ("otp_key", + (const char **) &tp.otp_key), + GNUNET_JSON_spec_end () + }; + + GNUNET_assert (NULL != mi); + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + } + tp.otp_algorithm = (enum TALER_MerchantConfirmationAlgorithm) otp_algorithm; + + /* finally, interact with DB until no serialization error */ + for (unsigned int i = 0; i<MAX_RETRIES; i++) + { + /* Test if a OTP device of this id is known */ + struct TALER_MERCHANTDB_OtpDeviceDetails etp; + + if (GNUNET_OK != + TMH_db->start (TMH_db->cls, + "/post otp-devices")) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_START_FAILED, + NULL); + } + qs = TMH_db->select_otp (TMH_db->cls, + mi->settings.id, + device_id, + &etp); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + /* Clean up and fail hard */ + GNUNET_break (0); + TMH_db->rollback (TMH_db->cls); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + NULL); + case GNUNET_DB_STATUS_SOFT_ERROR: + /* restart transaction */ + goto retry; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* Good, we can proceed! */ + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* idempotency check: is etp == tp? */ + { + bool eq; + + eq = otp_devices_equal (&tp, + &etp); + GNUNET_free (etp.otp_description); + GNUNET_free (etp.otp_key); + TMH_db->rollback (TMH_db->cls); + GNUNET_JSON_parse_free (spec); + return eq + ? TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0) + : TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_POST_OTP_DEVICES_CONFLICT_OTP_DEVICE_EXISTS, + device_id); + } + } /* end switch (qs) */ + + qs = TMH_db->insert_otp (TMH_db->cls, + mi->settings.id, + device_id, + &tp); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + TMH_db->rollback (TMH_db->cls); + break; + } + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + { + qs = TMH_db->commit (TMH_db->cls); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } +retry: + GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs); + TMH_db->rollback (TMH_db->cls); + } /* for RETRIES loop */ + GNUNET_JSON_parse_free (spec); + if (qs < 0) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + (GNUNET_DB_STATUS_SOFT_ERROR == qs) + ? TALER_EC_GENERIC_DB_SOFT_FAILURE + : TALER_EC_GENERIC_DB_COMMIT_FAILED, + NULL); + } + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +/* end of taler-merchant-httpd_private-post-otp-devices.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-otp-devices.h b/src/backend/taler-merchant-httpd_private-post-otp-devices.h new file mode 100644 index 00000000..96564d08 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-otp-devices.h @@ -0,0 +1,44 @@ +/* + This file is part of TALER + (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-post-otp-devices.h + * @brief implementing POST /otp-devices request handling + * @author Christian Grothoff + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_OTP_DEVICES_H +#define TALER_MERCHANT_HTTPD_PRIVATE_POST_OTP_DEVICES_H + +#include "taler-merchant-httpd.h" + + +/** + * Generate an OTP device. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_post_otp_devices (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +#endif diff --git a/src/backend/taler-merchant-httpd_private-post-templates.c b/src/backend/taler-merchant-httpd_private-post-templates.c index 276e225f..4a5d8133 100644 --- a/src/backend/taler-merchant-httpd_private-post-templates.c +++ b/src/backend/taler-merchant-httpd_private-post-templates.c @@ -29,12 +29,6 @@ /** - * How often do we retry the simple INSERT database transaction? - */ -#define MAX_RETRIES 3 - - -/** * Check if the two templates are identical. * * @param t1 template to compare @@ -47,12 +41,12 @@ templates_equal (const struct TALER_MERCHANTDB_TemplateDetails *t1, { return ( (0 == strcmp (t1->template_description, t2->template_description)) && - ( ( (NULL == t1->pos_key) && - (NULL == t2->pos_key) ) || - ( (NULL != t1->pos_key) && - (NULL != t2->pos_key) && - (0 == strcmp (t1->pos_key, - t2->pos_key))) ) && + ( ( (NULL == t1->otp_id) && + (NULL == t2->otp_id) ) || + ( (NULL != t1->otp_id) && + (NULL != t2->otp_id) && + (0 == strcmp (t1->otp_id, + t2->otp_id))) ) && (1 == json_equal (t1->template_contract, t2->template_contract)) ); } @@ -67,24 +61,20 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh, struct TALER_MERCHANTDB_TemplateDetails tp = { 0 }; const char *template_id; enum GNUNET_DB_QueryStatus qs; - uint32_t pos_algorithm = 0; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("template_id", &template_id), GNUNET_JSON_spec_string ("template_description", (const char **) &tp.template_description), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_uint32 ("pos_algorithm", - &pos_algorithm), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("pos_key", - (const char **) &tp.pos_key), + GNUNET_JSON_spec_string ("otp_id", + (const char **) &tp.otp_id), NULL), GNUNET_JSON_spec_json ("template_contract", &tp.template_contract), GNUNET_JSON_spec_end () }; + uint64_t otp_serial = 0; GNUNET_assert (NULL != mi); { @@ -101,7 +91,6 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh, : MHD_NO; } } - tp.pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos_algorithm; if (! TMH_template_contract_valid (tp.template_contract)) { GNUNET_break_op (0); @@ -115,23 +104,63 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh, "template_contract"); } - /* finally, interact with DB until no serialization error */ - for (unsigned int i = 0; i<MAX_RETRIES; i++) + if (NULL != tp.otp_id) { - /* Test if a template of this id is known */ - struct TALER_MERCHANTDB_TemplateDetails etp; - - if (GNUNET_OK != - TMH_db->start (TMH_db->cls, - "/post templates")) + qs = TMH_db->select_otp_serial (TMH_db->cls, + mi->settings.id, + tp.otp_id, + &otp_serial); + switch (qs) { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_break (0); GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_START_FAILED, + TALER_EC_GENERIC_DB_STORE_FAILED, + "select_otp_serial"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN, NULL); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; } + } + + qs = TMH_db->insert_template (TMH_db->cls, + mi->settings.id, + template_id, + otp_serial, + &tp); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + NULL); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + break; + } + + { + /* Test if a template of this id is known */ + struct TALER_MERCHANTDB_TemplateDetails etp; + qs = TMH_db->lookup_template (TMH_db->cls, mi->settings.id, template_id, @@ -139,79 +168,45 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh, switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: /* Clean up and fail hard */ GNUNET_break (0); - TMH_db->rollback (TMH_db->cls); GNUNET_JSON_parse_free (spec); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, NULL); - case GNUNET_DB_STATUS_SOFT_ERROR: - /* restart transaction */ - goto retry; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* Good, we can proceed! */ - break; + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "logic error"); case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* idempotency check: is etp == tp? */ - { - bool eq; - - eq = templates_equal (&tp, - &etp); - TALER_MERCHANTDB_template_details_free (&etp); - TMH_db->rollback (TMH_db->cls); - GNUNET_JSON_parse_free (spec); - return eq - ? TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0) - : TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - TALER_EC_MERCHANT_PRIVATE_POST_TEMPLATES_CONFLICT_TEMPLATE_EXISTS, - template_id); - } - } /* end switch (qs) */ - - qs = TMH_db->insert_template (TMH_db->cls, - mi->settings.id, - template_id, - &tp); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - TMH_db->rollback (TMH_db->cls); break; } - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + /* idempotency check: is etp == tp? */ { - qs = TMH_db->commit (TMH_db->cls); - if (GNUNET_DB_STATUS_SOFT_ERROR != qs) - break; + bool eq; + + eq = templates_equal (&tp, + &etp); + TALER_MERCHANTDB_template_details_free (&etp); + TMH_db->rollback (TMH_db->cls); + GNUNET_JSON_parse_free (spec); + return eq + ? TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0) + : TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_POST_TEMPLATES_CONFLICT_TEMPLATE_EXISTS, + template_id); } -retry: - GNUNET_assert (GNUNET_DB_STATUS_SOFT_ERROR == qs); - TMH_db->rollback (TMH_db->cls); - } /* for RETRIES loop */ - GNUNET_JSON_parse_free (spec); - if (qs < 0) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - (GNUNET_DB_STATUS_SOFT_ERROR == qs) - ? TALER_EC_GENERIC_DB_SOFT_FAILURE - : TALER_EC_GENERIC_DB_COMMIT_FAILED, - NULL); } - return TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); } |