summaryrefslogtreecommitdiff
path: root/src/lib/merchant_api_get_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/merchant_api_get_config.c')
-rw-r--r--src/lib/merchant_api_get_config.c187
1 files changed, 140 insertions, 47 deletions
diff --git a/src/lib/merchant_api_get_config.c b/src/lib/merchant_api_get_config.c
index 088434c5..b4b700bd 100644
--- a/src/lib/merchant_api_get_config.c
+++ b/src/lib/merchant_api_get_config.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018, 2020 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -34,13 +34,22 @@
* Which version of the Taler protocol is implemented
* by this library? Used to determine compatibility.
*/
-#define MERCHANT_PROTOCOL_CURRENT 3
+#define MERCHANT_PROTOCOL_CURRENT 14
/**
- * How many configs are we backwards compatible with?
+ * How many configs are we backwards-compatible with?
*/
-#define MERCHANT_PROTOCOL_AGE 1
+#define MERCHANT_PROTOCOL_AGE 2
+/**
+ * How many exchanges do we allow at most per merchant?
+ */
+#define MAX_EXCHANGES 1024
+
+/**
+ * How many currency specs do we allow at most per merchant?
+ */
+#define MAX_CURRENCIES 1024
/**
* @brief A handle for /config operations
@@ -90,9 +99,9 @@ handle_config_finished (void *cls,
{
struct TALER_MERCHANT_ConfigGetHandle *vgh = cls;
const json_t *json = response;
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = (unsigned int) response_code,
- .reply = json
+ struct TALER_MERCHANT_ConfigResponse cr = {
+ .hr.http_status = (unsigned int) response_code,
+ .hr.reply = json
};
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -104,78 +113,162 @@ handle_config_finished (void *cls,
{
case MHD_HTTP_OK:
{
- struct TALER_MERCHANT_ConfigInformation vi;
- enum TALER_MERCHANT_VersionCompatibility vc =
- TALER_MERCHANT_VC_PROTOCOL_ERROR;
+ const json_t *jcs;
+ const json_t *exchanges = NULL;
+ struct TALER_MERCHANT_ExchangeConfigInfo *eci = NULL;
+ unsigned int num_eci = 0;
+ unsigned int nspec;
+ struct TALER_JSON_ProtocolVersion pv;
struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_object_const ("currencies",
+ &jcs),
+ /* Optional for v5 compatibility, remove
+ once we reduce age! */
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const ("exchanges",
+ &exchanges),
+ NULL),
GNUNET_JSON_spec_string ("currency",
- &vi.currency),
+ &cr.details.ok.ci.currency),
+ TALER_JSON_spec_version ("version",
+ &pv),
GNUNET_JSON_spec_string ("version",
- &vi.version),
+ &cr.details.ok.ci.version),
GNUNET_JSON_spec_end ()
};
+ cr.details.ok.compat = TALER_MERCHANT_VC_PROTOCOL_ERROR;
if (GNUNET_OK !=
GNUNET_JSON_parse (json,
spec,
NULL, NULL))
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ cr.details.ok.compat = TALER_MERCHANT_VC_MATCH;
+ if (MERCHANT_PROTOCOL_CURRENT < pv.current)
+ {
+ cr.details.ok.compat |= TALER_MERCHANT_VC_NEWER;
+ if (MERCHANT_PROTOCOL_CURRENT < pv.current - pv.age)
+ cr.details.ok.compat |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ }
+ if (MERCHANT_PROTOCOL_CURRENT > pv.current)
+ {
+ cr.details.ok.compat |= TALER_MERCHANT_VC_OLDER;
+ if (MERCHANT_PROTOCOL_CURRENT - MERCHANT_PROTOCOL_AGE > pv.current)
+ cr.details.ok.compat |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ }
+
+ nspec = (unsigned int) json_object_size (jcs);
+ if ( (nspec > MAX_CURRENCIES) ||
+ (json_object_size (jcs) != (size_t) nspec) )
{
- unsigned int age;
- unsigned int revision;
- unsigned int current;
-
- if (3 != sscanf (vi.version,
- "%u:%u:%u",
- &current,
- &revision,
- &age))
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ if (NULL != exchanges)
+ {
+ num_eci = (unsigned int) json_object_size (exchanges);
+ if ( (num_eci > MAX_EXCHANGES) ||
+ (json_object_size (exchanges) != (size_t) num_eci) )
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
}
- else
+ eci = GNUNET_new_array (num_eci,
+ struct TALER_MERCHANT_ExchangeConfigInfo);
+ for (unsigned int i = 0; i<num_eci; i++)
{
- vc = TALER_MERCHANT_VC_MATCH;
- if (MERCHANT_PROTOCOL_CURRENT < current)
+ struct TALER_MERCHANT_ExchangeConfigInfo *ei = &eci[i];
+ const json_t *ej = json_array_get (exchanges,
+ i);
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_string ("currency",
+ &ei->currency),
+ GNUNET_JSON_spec_string ("base_url",
+ &ei->base_url),
+ GNUNET_JSON_spec_fixed_auto ("master_pub",
+ &ei->master_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (ej,
+ ispec,
+ NULL, NULL))
{
- vc |= TALER_MERCHANT_VC_NEWER;
- if (MERCHANT_PROTOCOL_CURRENT < current - age)
- vc |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_free (eci);
+ break;
}
- if (MERCHANT_PROTOCOL_CURRENT > current)
+ }
+ }
+ {
+ struct TALER_CurrencySpecification *cspecs;
+ unsigned int off = 0;
+ json_t *obj;
+ const char *curr;
+
+ cspecs = GNUNET_new_array (nspec,
+ struct TALER_CurrencySpecification);
+ cr.details.ok.num_cspecs = nspec;
+ cr.details.ok.cspecs = cspecs;
+ cr.details.ok.num_exchanges = (unsigned int) num_eci;
+ cr.details.ok.exchanges = eci;
+ json_object_foreach ((json_t *) jcs, curr, obj)
+ {
+ struct TALER_CurrencySpecification *cs = &cspecs[off++];
+ struct GNUNET_JSON_Specification cspec[] = {
+ TALER_JSON_spec_currency_specification (curr,
+ curr,
+ cs),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (jcs,
+ cspec,
+ NULL, NULL))
{
- vc |= TALER_MERCHANT_VC_OLDER;
- if (MERCHANT_PROTOCOL_CURRENT - MERCHANT_PROTOCOL_AGE > current)
- vc |= TALER_MERCHANT_VC_INCOMPATIBLE;
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_free (eci);
+ TALER_CONFIG_free_currencies (off - 1,
+ cspecs);
+ break;
}
}
+ vgh->cb (vgh->cb_cls,
+ &cr);
+ GNUNET_free (eci);
+ TALER_CONFIG_free_currencies (nspec,
+ cspecs);
}
- vgh->cb (vgh->cb_cls,
- &hr,
- &vi,
- vc);
TALER_MERCHANT_config_get_cancel (vgh);
return;
}
default:
/* unexpected response code */
- hr.ec = TALER_JSON_get_error_code (json);
- hr.hint = TALER_JSON_get_error_hint (json);
+ cr.hr.ec = TALER_JSON_get_error_code (json);
+ cr.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d\n",
(unsigned int) response_code,
- (int) hr.ec);
- vgh->cb (vgh->cb_cls,
- &hr,
- NULL,
- TALER_MERCHANT_VC_PROTOCOL_ERROR);
+ (int) cr.hr.ec);
break;
}
+ vgh->cb (vgh->cb_cls,
+ &cr);
TALER_MERCHANT_config_get_cancel (vgh);
}