summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-04-23 22:57:55 +0200
committerChristian Grothoff <christian@grothoff.org>2023-04-23 22:57:55 +0200
commit154f964aab5df00cbadaa015474c2b323161aa96 (patch)
tree084f300e664fb96d0693baf73434ed245ef56641 /src/backend
parent889595f986d922ffbcdcd746fdfad7f1a0e53595 (diff)
downloadmerchant-154f964aab5df00cbadaa015474c2b323161aa96.tar.gz
merchant-154f964aab5df00cbadaa015474c2b323161aa96.tar.bz2
merchant-154f964aab5df00cbadaa015474c2b323161aa96.zip
API change for #6363
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/Makefile.am1
-rw-r--r--src/backend/taler-merchant-httpd.c2
-rw-r--r--src/backend/taler-merchant-httpd.h12
-rw-r--r--src/backend/taler-merchant-httpd_helper.c223
-rw-r--r--src/backend/taler-merchant-httpd_helper.h44
-rw-r--r--src/backend/taler-merchant-httpd_private-delete-instances-ID.c12
-rw-r--r--src/backend/taler-merchant-httpd_private-get-instances-ID.c3
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-instances-ID.c197
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances.c169
-rw-r--r--src/backend/taler-merchant-wirewatch.c45
10 files changed, 513 insertions, 195 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 89fab12c..d5bcda16 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -135,6 +135,7 @@ taler_merchant_httpd_SOURCES = \
taler_merchant_httpd_LDADD = \
$(top_builddir)/src/backenddb/libtalermerchantdb.la \
+ $(top_builddir)/src/bank/libtalermerchantbank.la \
-ltalerexchange \
-ltalertemplating \
-ltalermhd \
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index bebe9f32..8f455f58 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -240,6 +240,8 @@ TMH_instance_decref (struct TMH_MerchantInstance *mi)
wm);
GNUNET_free (wm->payto_uri);
GNUNET_free (wm->wire_method);
+ GNUNET_free (wm->credit_facade_url);
+ json_decref (wm->credit_facade_credentials);
GNUNET_free (wm);
}
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index 391987ab..6f637934 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -25,6 +25,7 @@
#include "taler_merchantdb_lib.h"
#include <taler/taler_mhd_lib.h>
#include <gnunet/gnunet_mhd_compat.h>
+#include "taler_merchant_bank_lib.h"
/**
* Shorthand for exit jumps.
@@ -71,6 +72,17 @@ struct TMH_WireMethod
struct TALER_MerchantWireHashP h_wire;
/**
+ * Base URL of the credit facade.
+ */
+ char *credit_facade_url;
+
+ /**
+ * Authentication data to access the credit facade.
+ * May be uninitialized if not provided by the client.
+ */
+ json_t *credit_facade_credentials;
+
+ /**
* Is this wire method active (should it be included in new contracts)?
*/
bool active;
diff --git a/src/backend/taler-merchant-httpd_helper.c b/src/backend/taler-merchant-httpd_helper.c
index 149ff3c3..981f5937 100644
--- a/src/backend/taler-merchant-httpd_helper.c
+++ b/src/backend/taler-merchant-httpd_helper.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014--2021 Taler Systems SA
+ (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
@@ -27,68 +27,177 @@
#include <taler/taler_templating_lib.h>
#include <taler/taler_dbevents.h>
-/**
- * check @a payto_uris for well-formedness
- *
- * @param payto_uris JSON array of payto URIs (presumably)
- * @return true if they are all valid URIs (and this is an array of strings)
- */
+
+enum GNUNET_GenericReturnValue
+TMH_cmp_wire_account (
+ const json_t *account,
+ const struct TMH_WireMethod *wm)
+{
+ const char *credit_facade_url = NULL;
+ 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_json ("credit_facade_credentials",
+ &credit_facade_credentials),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+ const char *ename;
+ unsigned int eline;
+
+ res = GNUNET_JSON_parse (account,
+ ispec,
+ &ename,
+ &eline);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse account spec: %s (%u)\n",
+ ename,
+ eline);
+ return GNUNET_SYSERR;
+ }
+ if (0 !=
+ strcmp (wm->payto_uri,
+ uri))
+ {
+ GNUNET_JSON_parse_free (ispec);
+ return GNUNET_SYSERR;
+ }
+ if ( (NULL == credit_facade_url) !=
+ (NULL == wm->credit_facade_url) ||
+ (NULL == credit_facade_credentials) !=
+ (NULL == wm->credit_facade_credentials) )
+ {
+ GNUNET_JSON_parse_free (ispec);
+ return GNUNET_NO;
+ }
+ if ( (NULL != credit_facade_url) &&
+ (0 != strcmp (credit_facade_url,
+ wm->credit_facade_url)) )
+ {
+ GNUNET_JSON_parse_free (ispec);
+ return GNUNET_NO;
+ }
+ if ( (NULL != credit_facade_credentials) &&
+ (0 != json_equal (credit_facade_credentials,
+ wm->credit_facade_credentials)) )
+ {
+ GNUNET_JSON_parse_free (ispec);
+ return GNUNET_NO;
+ }
+ GNUNET_JSON_parse_free (ispec);
+ return GNUNET_YES;
+}
+
+
bool
-TMH_payto_uri_array_valid (const json_t *payto_uris)
+TMH_accounts_array_valid (const json_t *accounts)
{
- bool payto_ok = true;
+ unsigned int len;
- if (! json_is_array (payto_uris))
+ if (! json_is_array (accounts))
{
GNUNET_break_op (0);
- payto_ok = false;
+ return false;
}
- else
+ len = json_array_size (accounts);
+ for (unsigned int i = 0; i<len; i++)
{
- unsigned int len = json_array_size (payto_uris);
+ json_t *payto_uri = json_array_get (accounts,
+ i);
+ const char *credit_facade_url = NULL;
+ 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_json ("credit_facade_credentials",
+ &credit_facade_credentials),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+ const char *ename;
+ unsigned int eline;
+
+ res = GNUNET_JSON_parse (payto_uri,
+ ispec,
+ &ename,
+ &eline);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse account spec: %s (%u)\n",
+ ename,
+ eline);
+ return false;
+ }
- for (unsigned int i = 0; i<len; i++)
+ /* Test for the same payto:// URI being given twice */
+ for (unsigned int j = 0; j<i; j++)
{
- json_t *payto_uri = json_array_get (payto_uris,
- i);
- const char *uri;
-
- if (! json_is_string (payto_uri))
- payto_ok = false;
- uri = json_string_value (payto_uri);
- /* Test for the same payto:// URI being given twice */
- for (unsigned int j = 0; j<i; j++)
+ json_t *old_uri = json_array_get (accounts,
+ j);
+ if (0 == strcmp (uri,
+ json_string_value (
+ json_object_get (old_uri,
+ "payto_uri"))))
{
- json_t *old_uri = json_array_get (payto_uris,
- j);
- if (json_equal (payto_uri,
- old_uri))
- {
- GNUNET_break_op (0);
- payto_ok = false;
- break;
- }
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (ispec);
+ return false;
}
- if (! payto_ok)
- break;
+ }
+ {
+ char *err;
+
+ if (NULL !=
+ (err = TALER_payto_validate (uri)))
{
- char *err;
-
- if (NULL !=
- (err = TALER_payto_validate (uri)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Encountered invalid payto://-URI `%s': %s\n",
- uri,
- err);
- GNUNET_free (err);
- payto_ok = false;
- break;
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Encountered invalid payto://-URI `%s': %s\n",
+ uri,
+ err);
+ GNUNET_free (err);
+ GNUNET_JSON_parse_free (ispec);
+ return false;
}
}
+ if ( (NULL != credit_facade_url) ||
+ (NULL != credit_facade_credentials) )
+ {
+ struct TALER_MERCHANT_BANK_AuthenticationData auth;
+
+ if (GNUNET_OK !=
+ TALER_MERCHANT_BANK_auth_parse_json (credit_facade_credentials,
+ credit_facade_url,
+ &auth))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid credit facade URL or credentials `%s'\n",
+ credit_facade_url);
+ GNUNET_JSON_parse_free (ispec);
+ return false;
+ }
+ TALER_MERCHANT_BANK_auth_free (&auth);
+ }
+ GNUNET_JSON_parse_free (ispec);
}
- return payto_ok;
+ return true;
}
@@ -396,14 +505,17 @@ TMH_taxes_array_valid (const json_t *taxes)
struct TMH_WireMethod *
-TMH_setup_wire_account (const char *payto_uri)
+TMH_setup_wire_account (
+ const char *payto_uri,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials)
{
struct TMH_WireMethod *wm;
char *emsg;
if (NULL != (emsg = TALER_payto_validate (payto_uri)))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Invalid URI `%s': %s\n",
payto_uri,
emsg);
@@ -412,6 +524,12 @@ TMH_setup_wire_account (const char *payto_uri)
}
wm = GNUNET_new (struct TMH_WireMethod);
+ if (NULL != credit_facade_url)
+ wm->credit_facade_url
+ = GNUNET_strdup (credit_facade_url);
+ if (NULL != credit_facade_credentials)
+ wm->credit_facade_credentials
+ = json_incref ((json_t*) credit_facade_credentials);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&wm->wire_salt,
sizeof (wm->wire_salt));
@@ -472,8 +590,9 @@ TMH_check_auth_config (struct MHD_Connection *connection,
TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH,
- "bad authentication config")) ?
- GNUNET_NO : GNUNET_SYSERR;
+ "bad authentication config"))
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
}
return GNUNET_OK;
}
diff --git a/src/backend/taler-merchant-httpd_helper.h b/src/backend/taler-merchant-httpd_helper.h
index 5cee97cc..14156fce 100644
--- a/src/backend/taler-merchant-httpd_helper.h
+++ b/src/backend/taler-merchant-httpd_helper.h
@@ -28,13 +28,13 @@
#include "taler-merchant-httpd.h"
/**
- * check @a payto_uris for well-formedness
+ * check @a accounts for well-formedness
*
- * @param payto_uris JSON array of payto URIs (presumably)
- * @return true if they are all valid URIs (and this is an array of strings)
+ * @param accounts JSON array of merchant accounts (presumably)
+ * @return true if they are all valid accounts
*/
bool
-TMH_payto_uri_array_valid (const json_t *payto_uris);
+TMH_accounts_array_valid (const json_t *accounts);
/**
@@ -103,15 +103,45 @@ TMH_template_contract_valid (const json_t *template_contract);
* Setup new wire method for the given @ payto_uri.
*
* @param payto_uri already validated payto URI
+ * @param credit_facade_url where to download credit information for this account (can be NULL)
+ * @param credit_facade_credentials credentials for the @a credit_facade_url
* @return new wire method object, never fails
*/
struct TMH_WireMethod *
-TMH_setup_wire_account (const char *payto_uri);
+TMH_setup_wire_account (
+ const char *payto_uri,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials);
+
/**
- * FIXME: document
+ * Test if JSON spec @a account for a wire method is equal to the given @a wm.
+ *
+ * @param account JSON spec for a merchant account
+ * @param wm known wire method
+ * @return #GNUNET_YES if both specifications are equal
+ * #GNUNET_NO if the specifications are for
+ * the same account but differ in the credit facade
+ * #GNUNET_SYSERR if the specs are for different accounts
+ * or if @a account is malformed
*/
+enum GNUNET_GenericReturnValue
+TMH_cmp_wire_account (
+ const json_t *account,
+ const struct TMH_WireMethod *wm);
+
+/**
+ * Check that the provided authentication configuration
+ * is valid.
+ *
+ * @param connection connection to use for returning errors
+ * @param jauth JSON with authentication data
+ * @param[out] auth_token set to the authentication token
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if an error was returned on @a connection
+ * #GNUNET_SYSERR if we failed to return an error on @a connection
+ */
enum GNUNET_GenericReturnValue
TMH_check_auth_config (struct MHD_Connection *connection,
const json_t *jauth,
@@ -144,7 +174,6 @@ TMH_uuid_from_string (const char *uuids,
GNUNET_JSON_pack_object_incref ("exchange_reply", (json_t *) (hr)->reply))
-
/**
* TMH_trigger_webhook is a function that need to be use when someone
* pay. Merchant need to have a notification.
@@ -159,5 +188,4 @@ TMH_trigger_webhook (const char *instance,
const json_t *args);
-
#endif
diff --git a/src/backend/taler-merchant-httpd_private-delete-instances-ID.c b/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
index 2791d6d7..8862eadd 100644
--- a/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
@@ -21,6 +21,7 @@
#include "platform.h"
#include "taler-merchant-httpd_private-delete-instances-ID.h"
#include <taler/taler_json_lib.h>
+#include <taler/taler_dbevents.h>
/**
@@ -52,6 +53,17 @@ delete_instances_ID (struct TMH_MerchantInstance *mi,
else
qs = TMH_db->delete_instance_private_key (TMH_db->cls,
mi->settings.id);
+ {
+ 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);
+ }
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
diff --git a/src/backend/taler-merchant-httpd_private-get-instances-ID.c b/src/backend/taler-merchant-httpd_private-get-instances-ID.c
index c51d3de0..d2e3d937 100644
--- a/src/backend/taler-merchant-httpd_private-get-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-instances-ID.c
@@ -52,6 +52,9 @@ get_instances_ID (struct TMH_MerchantInstance *mi,
GNUNET_JSON_pack_string (
"payto_uri",
wm->payto_uri),
+ GNUNET_JSON_pack_string (
+ "credit_facade_url",
+ wm->credit_facade_url),
GNUNET_JSON_pack_data_auto ("h_wire",
&wm->h_wire),
GNUNET_JSON_pack_data_auto (
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 77a75da4..9241d069 100644
--- a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
@@ -26,6 +26,7 @@
#include "taler-merchant-httpd_private-patch-instances-ID.h"
#include "taler-merchant-httpd_helper.h"
#include <taler/taler_json_lib.h>
+#include <taler/taler_dbevents.h>
/**
@@ -62,14 +63,14 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
struct TMH_HandlerContext *hc)
{
struct TALER_MERCHANTDB_InstanceSettings is;
- json_t *payto_uris;
+ 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_json ("payto_uris",
- &payto_uris),
+ GNUNET_JSON_spec_json ("accounts",
+ &accounts),
GNUNET_JSON_spec_string ("name",
&name),
GNUNET_JSON_spec_mark_optional (
@@ -167,7 +168,7 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
"jurisdiction");
}
- if (! TMH_payto_uri_array_valid (payto_uris))
+ if (! TMH_accounts_array_valid (accounts))
{
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (connection,
@@ -175,7 +176,7 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
NULL);
}
- for (unsigned int i = 0; i<MAX_RETRIES; i++)
+ for (unsigned int retry = 0; retry<MAX_RETRIES; retry++)
{
/* Cleanup after earlier loops */
{
@@ -255,44 +256,59 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
/* Check for changes in accounts */
{
- unsigned int len = json_array_size (payto_uris);
+ unsigned int len = json_array_size (accounts);
struct TMH_WireMethod *matches[GNUNET_NZL (len)];
- bool matched;
+ 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)
{
- const char *uri = wm->payto_uri;
-
- GNUNET_assert (NULL != uri);
- matched = false;
+ bool matched = false;
for (unsigned int i = 0; i<len; i++)
{
- const char *str = json_string_value (json_array_get (payto_uris,
- i));
- if (0 == strcasecmp (uri,
- str))
+ 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, inactivating it.\n",
- uri);
+ "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,
@@ -306,16 +322,51 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
goto giveup;
}
}
- }
- /* Find _new_ accounts */
+ } /* for (wm) */
+
+ /* handle updates */
for (unsigned int i = 0; i<len; i++)
{
- struct TALER_MERCHANTDB_AccountDetails ad;
- struct TMH_WireMethod *wm;
+ struct TMH_WireMethod *wm = matches[i];
- if (NULL != matches[i])
+ if (! updated[i])
+ continue;
+ GNUNET_assert (NULL != wm);
{
- wm = matches[i];
+ 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,
@@ -333,34 +384,82 @@ patch_instances_ID (struct TMH_MerchantInstance *mi,
wm->enabling = true;
continue;
}
- ad.payto_uri = json_string_value (json_array_get (payto_uris,
- i));
- GNUNET_assert (NULL != ad.payto_uri);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Adding NEW account `%s'\n",
- ad.payto_uri);
- wm = TMH_setup_wire_account (ad.payto_uri);
- GNUNET_assert (NULL != wm); /* checked payto_uri validity earlier */
- GNUNET_CONTAINER_DLL_insert (wm_head,
- wm_tail,
- wm);
- ad.h_wire = wm->h_wire;
- ad.salt = wm->wire_salt;
- ad.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;
- }
- }
- }
+ const char *credit_facade_url = NULL;
+ 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_json ("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);
+ GNUNET_JSON_parse_free (ispec);
+ } /* 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)
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c b/src/backend/taler-merchant-httpd_private-post-instances.c
index 4d9320ba..c8f443cd 100644
--- a/src/backend/taler-merchant-httpd_private-post-instances.c
+++ b/src/backend/taler-merchant-httpd_private-post-instances.c
@@ -25,6 +25,8 @@
#include "platform.h"
#include "taler-merchant-httpd_private-post-instances.h"
#include "taler-merchant-httpd_helper.h"
+#include "taler_merchant_bank_lib.h"
+#include <taler/taler_dbevents.h>
#include <taler/taler_json_lib.h>
#include <regex.h>
@@ -39,51 +41,45 @@
* URIs as those already in @a mi (possibly in a different order).
*
* @param mi a merchant instance with accounts
- * @param payto_uris a JSON array with accounts (presumably)
+ * @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,
- json_t *payto_uris)
+ const json_t *accounts)
{
- if (! json_is_array (payto_uris))
+ if (! json_is_array (accounts))
return false;
{
- unsigned int len = json_array_size (payto_uris);
- bool matches[GNUNET_NZL (len)];
- struct TMH_WireMethod *wm;
+ unsigned int len = json_array_size (accounts);
+ enum GNUNET_GenericReturnValue matches[GNUNET_NZL (len)];
- memset (matches,
- 0,
- sizeof (matches));
- for (wm = mi->wm_head;
+ 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)
{
- const char *uri = wm->payto_uri;
-
- GNUNET_assert (NULL != uri);
for (unsigned int i = 0; i<len; i++)
{
- const char *str = json_string_value (json_array_get (payto_uris,
- i));
+ json_t *account = json_array_get (accounts,
+ i);
+ enum GNUNET_GenericReturnValue ret;
- GNUNET_assert (NULL != str);
- if (0 == strcasecmp (uri,
- str))
+ ret = TMH_cmp_wire_account (account,
+ wm);
+ if (GNUNET_SYSERR == ret)
+ continue;
+ if (GNUNET_SYSERR != matches[i])
{
- if (matches[i])
- {
- GNUNET_break (0);
- return false; /* duplicate entry!? */
- }
- matches[i] = true;
- break;
+ GNUNET_break (0);
+ return false; /* duplicate entry!? */
}
+ matches[i] = ret;
}
}
for (unsigned int i = 0; i<len; i++)
- if (! matches[i])
+ if (GNUNET_YES != matches[i])
return false;
}
return true;
@@ -91,48 +87,6 @@ accounts_equal (const struct TMH_MerchantInstance *mi,
/**
- * Free memory used by @a wm
- *
- * @param wm wire method to free
- */
-static void
-free_wm (struct TMH_WireMethod *wm)
-{
- GNUNET_free (wm->payto_uri);
- GNUNET_free (wm->wire_method);
- GNUNET_free (wm);
-}
-
-
-/**
- * Free memory used by @a mi.
- *
- * @param mi instance to free
- */
-static void
-free_mi (struct TMH_MerchantInstance *mi)
-{
- struct TMH_WireMethod *wm;
-
- while (NULL != (wm = mi->wm_head))
- {
- GNUNET_CONTAINER_DLL_remove (mi->wm_head,
- mi->wm_tail,
- wm);
- free_wm (wm);
- }
- GNUNET_free (mi->settings.id);
- GNUNET_free (mi->settings.name);
- GNUNET_free (mi->settings.website);
- GNUNET_free (mi->settings.email);
- GNUNET_free (mi->settings.logo);
- json_decref (mi->settings.address);
- json_decref (mi->settings.jurisdiction);
- GNUNET_free (mi);
-}
-
-
-/**
* Generate an instance, given its configuration.
*
* @param rh context of the handler
@@ -147,15 +101,15 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
{
struct TALER_MERCHANTDB_InstanceSettings is;
struct TALER_MERCHANTDB_InstanceAuthSettings ias;
- json_t *payto_uris;
+ json_t *accounts;
const char *auth_token = NULL;
const char *uts = "business";
struct TMH_WireMethod *wm_head = NULL;
struct TMH_WireMethod *wm_tail = NULL;
json_t *jauth;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("payto_uris",
- &payto_uris),
+ GNUNET_JSON_spec_json ("accounts",
+ &accounts),
GNUNET_JSON_spec_string ("id",
(const char **) &is.id),
GNUNET_JSON_spec_string ("name",
@@ -208,7 +162,6 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
? MHD_YES
: MHD_NO;
}
-
if (NULL == uts)
uts = "business";
if (GNUNET_OK !=
@@ -233,8 +186,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
}
- /* check payto_uris for well-formedness */
- if (! TMH_payto_uri_array_valid (payto_uris))
+ /* check accounts for well-formedness */
+ if (! TMH_accounts_array_valid (accounts))
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
@@ -341,12 +294,14 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
is.address)) &&
(1 == json_equal (mi->settings.jurisdiction,
is.jurisdiction)) &&
- (GNUNET_OK == TALER_amount_cmp_currency (
+ (GNUNET_OK ==
+ TALER_amount_cmp_currency (
&mi->settings.default_max_deposit_fee,
&is.default_max_deposit_fee)) &&
(0 == TALER_amount_cmp (&mi->settings.default_max_deposit_fee,
&is.default_max_deposit_fee)) &&
- (GNUNET_OK == TALER_amount_cmp_currency (
+ (GNUNET_OK ==
+ TALER_amount_cmp_currency (
&mi->settings.default_max_wire_fee,
&is.default_max_wire_fee)) &&
(0 == TALER_amount_cmp (&mi->settings.default_max_wire_fee,
@@ -360,7 +315,7 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
==,
is.default_pay_delay)) &&
(accounts_equal (mi,
- payto_uris)) )
+ accounts)) )
{
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_static (connection,
@@ -382,18 +337,46 @@ 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 (payto_uris);
+ unsigned int len = json_array_size (accounts);
for (unsigned int i = 0; i<len; i++)
{
- json_t *payto_uri = json_array_get (payto_uris,
- i);
+ json_t *account = json_array_get (accounts,
+ i);
+ const char *credit_facade_url = NULL;
+ json_t *credit_facade_credentials = NULL;
+ const char *uri;
struct TMH_WireMethod *wm;
-
- wm = TMH_setup_wire_account (json_string_value (payto_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_json ("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);
+ GNUNET_JSON_parse_free (ispec);
}
}
@@ -446,7 +429,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
"post /instances"))
{
GNUNET_JSON_parse_free (spec);
- free_mi (mi);
+ mi->rc = 1;
+ TMH_instance_decref (mi);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_START_FAILED,
@@ -469,7 +453,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_ALREADY_EXISTS,
is.id);
GNUNET_JSON_parse_free (spec);
- free_mi (mi);
+ mi->rc = 1;
+ TMH_instance_decref (mi);
return ret;
}
for (struct TMH_WireMethod *wm = wm_head;
@@ -480,6 +465,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
.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
};
@@ -497,6 +484,17 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh,
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;
@@ -507,7 +505,8 @@ retry:
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
GNUNET_JSON_parse_free (spec);
- free_mi (mi);
+ mi->rc = 1;
+ TMH_instance_decref (mi);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_COMMIT_FAILED,
diff --git a/src/backend/taler-merchant-wirewatch.c b/src/backend/taler-merchant-wirewatch.c
index 380bcc11..03e317b0 100644
--- a/src/backend/taler-merchant-wirewatch.c
+++ b/src/backend/taler-merchant-wirewatch.c
@@ -22,6 +22,7 @@
#include <gnunet/gnunet_util_lib.h>
#include <jansson.h>
#include <pthread.h>
+#include <taler/taler_dbevents.h>
#include "taler_merchant_bank_lib.h"
#include "taler_merchantdb_lib.h"
#include "taler_merchantdb_plugin.h"
@@ -123,6 +124,12 @@ static struct GNUNET_CURL_Context *ctx;
static struct GNUNET_CURL_RescheduleContext *rc;
/**
+ * Event handler to learn that the configuration changed
+ * and we should shutdown (to be restarted).
+ */
+static struct GNUNET_DB_EventHandler *eh;
+
+/**
* Value to return from main(). 0 on success, non-zero on errors.
*/
static int global_ret;
@@ -209,6 +216,11 @@ shutdown_task (void *cls)
save (w);
end_watch (w);
}
+ if (NULL != eh)
+ {
+ db_plugin->event_listen_cancel (eh);
+ eh = NULL;
+ }
TALER_MERCHANTDB_plugin_unload (db_plugin);
db_plugin = NULL;
cfg = NULL;
@@ -457,6 +469,26 @@ start_watch (
/**
+ * Function called on configuration change events received from Postgres. We
+ * shutdown (and systemd should restart us).
+ *
+ * @param cls closure (NULL)
+ * @param extra additional event data provided
+ * @param extra_size number of bytes in @a extra
+ */
+static void
+config_changed (void *cls,
+ const void *extra,
+ size_t extra_size)
+{
+ (void) cls;
+ (void) extra;
+ (void) extra_size;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
* First task.
*
* @param cls closure, NULL
@@ -501,7 +533,18 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- // FIXME: also add notification job!
+ {
+ struct GNUNET_DB_EventHeaderP es = {
+ .size = htons (sizeof (es)),
+ .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
+ };
+
+ eh = db_plugin->event_listen (db_plugin->cls,
+ &es,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &config_changed,
+ NULL);
+ }
{
enum GNUNET_DB_QueryStatus qs;