diff options
Diffstat (limited to 'src/lib/merchant_api_get_config.c')
-rw-r--r-- | src/lib/merchant_api_get_config.c | 187 |
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", - ¤t, - &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); } |