diff options
Diffstat (limited to 'src/util/config.c')
-rw-r--r-- | src/util/config.c | 346 |
1 files changed, 344 insertions, 2 deletions
diff --git a/src/util/config.c b/src/util/config.c index c00792469..f5accaad8 100644 --- a/src/util/config.c +++ b/src/util/config.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -21,7 +21,7 @@ */ #include "platform.h" #include "taler_util.h" - +#include <gnunet/gnunet_json_lib.h> enum GNUNET_GenericReturnValue TALER_config_get_amount (const struct GNUNET_CONFIGURATION_Handle *cfg, @@ -166,3 +166,345 @@ TALER_config_get_currency (const struct GNUNET_CONFIGURATION_Handle *cfg, } return GNUNET_OK; } + + +/** + * Closure for #parse_currencies_cb(). + */ +struct CurrencyParserContext +{ + /** + * Current offset in @e cspecs. + */ + unsigned int num_currencies; + + /** + * Length of the @e cspecs array. + */ + unsigned int len_cspecs; + + /** + * Array of currency specifications (see DD 51). + */ + struct TALER_CurrencySpecification *cspecs; + + /** + * Configuration we are parsing. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Set to true if the configuration was malformed. + */ + bool failure; +}; + + +/** + * Function to iterate over section. + * + * @param cls closure with a `struct CurrencyParserContext *` + * @param section name of the section + */ +static void +parse_currencies_cb (void *cls, + const char *section) +{ + struct CurrencyParserContext *cpc = cls; + struct TALER_CurrencySpecification *cspec; + unsigned long long num; + char *str; + + if (cpc->failure) + return; + if (0 != strncasecmp (section, + "currency-", + strlen ("currency-"))) + return; /* not interesting */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (cpc->cfg, + section, + "ENABLED")) + return; /* disabled */ + if (cpc->len_cspecs == cpc->num_currencies) + { + GNUNET_array_grow (cpc->cspecs, + cpc->len_cspecs, + cpc->len_cspecs * 2 + 4); + } + cspec = &cpc->cspecs[cpc->num_currencies++]; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cpc->cfg, + section, + "CODE", + &str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "CODE"); + cpc->failure = true; + return; + } + if (GNUNET_OK != + TALER_check_currency (str)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "CODE", + "Currency code name given is invalid"); + cpc->failure = true; + GNUNET_free (str); + return; + } + memset (cspec->currency, + 0, + sizeof (cspec->currency)); + /* Already checked in TALER_check_currency(), repeated here + just to make static analysis happy */ + GNUNET_assert (strlen (str) < TALER_CURRENCY_LEN); + strcpy (cspec->currency, + str); + GNUNET_free (str); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cpc->cfg, + section, + "NAME", + &str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "NAME"); + cpc->failure = true; + return; + } + cspec->name = str; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cpc->cfg, + section, + "FRACTIONAL_INPUT_DIGITS", + &num)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_INPUT_DIGITS"); + cpc->failure = true; + return; + } + if (num > TALER_AMOUNT_FRAC_LEN) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_INPUT_DIGITS", + "Number given is too big"); + cpc->failure = true; + return; + } + cspec->num_fractional_input_digits = num; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cpc->cfg, + section, + "FRACTIONAL_NORMAL_DIGITS", + &num)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_NORMAL_DIGITS"); + cpc->failure = true; + return; + } + if (num > TALER_AMOUNT_FRAC_LEN) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_NORMAL_DIGITS", + "Number given is too big"); + cpc->failure = true; + return; + } + cspec->num_fractional_normal_digits = num; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cpc->cfg, + section, + "FRACTIONAL_TRAILING_ZERO_DIGITS", + &num)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_TRAILING_ZERO_DIGITS"); + cpc->failure = true; + return; + } + if (num > TALER_AMOUNT_FRAC_LEN) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_TRAILING_ZERO_DIGITS", + "Number given is too big"); + cpc->failure = true; + return; + } + cspec->num_fractional_trailing_zero_digits = num; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cpc->cfg, + section, + "ALT_UNIT_NAMES", + &str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "ALT_UNIT_NAMES"); + cpc->failure = true; + return; + } + { + json_error_t err; + + cspec->map_alt_unit_names = json_loads (str, + JSON_REJECT_DUPLICATES, + &err); + GNUNET_free (str); + if (NULL == cspec->map_alt_unit_names) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "ALT_UNIT_NAMES", + err.text); + cpc->failure = true; + return; + } + } + if (GNUNET_OK != + TALER_check_currency_scale_map (cspec->map_alt_unit_names)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "ALT_UNIT_NAMES", + "invalid map entry detected"); + cpc->failure = true; + json_decref (cspec->map_alt_unit_names); + cspec->map_alt_unit_names = NULL; + return; + } +} + + +enum GNUNET_GenericReturnValue +TALER_check_currency_scale_map (const json_t *map) +{ + /* validate map only maps from decimal numbers to strings! */ + const char *str; + const json_t *val; + bool zf = false; + + if (! json_is_object (map)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Object required for currency scale map\n"); + return GNUNET_SYSERR; + } + json_object_foreach ((json_t *) map, str, val) + { + int idx; + char dummy; + + if ( (1 != sscanf (str, + "%d%c", + &idx, + &dummy)) || + (idx < -12) || + (idx > 24) || + (! json_is_string (val) ) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid entry `%s' in currency scale map\n", + str); + return GNUNET_SYSERR; + } + if (0 == idx) + zf = true; + } + if (! zf) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Entry for 0 missing in currency scale map\n"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +TALER_CONFIG_parse_currencies (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int *num_currencies, + struct TALER_CurrencySpecification **cspecs) +{ + struct CurrencyParserContext cpc = { + .cfg = cfg + }; + + GNUNET_CONFIGURATION_iterate_sections (cfg, + &parse_currencies_cb, + &cpc); + if (cpc.failure) + { + GNUNET_array_grow (cpc.cspecs, + cpc.len_cspecs, + 0); + return GNUNET_SYSERR; + } + GNUNET_array_grow (cpc.cspecs, + cpc.len_cspecs, + cpc.num_currencies); + *num_currencies = cpc.num_currencies; + *cspecs = cpc.cspecs; + if (0 == *num_currencies) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No currency formatting specification found! Please check your installation!\n"); + return GNUNET_NO; + } + return GNUNET_OK; +} + + +json_t * +TALER_CONFIG_currency_specs_to_json (const struct + TALER_CurrencySpecification *cspec) +{ + return GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("name", + cspec->name), + /* 'currency' is deprecated as of exchange v18 and merchant v6; + remove this line once current-age > 6*/ + GNUNET_JSON_pack_string ("currency", + cspec->currency), + GNUNET_JSON_pack_uint64 ("num_fractional_input_digits", + cspec->num_fractional_input_digits), + GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits", + cspec->num_fractional_normal_digits), + GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits", + cspec->num_fractional_trailing_zero_digits), + GNUNET_JSON_pack_object_incref ("alt_unit_names", + cspec->map_alt_unit_names)); +} + + +void +TALER_CONFIG_free_currencies ( + unsigned int num_currencies, + struct TALER_CurrencySpecification cspecs[static num_currencies]) +{ + for (unsigned int i = 0; i<num_currencies; i++) + { + struct TALER_CurrencySpecification *cspec = &cspecs[i]; + + GNUNET_free (cspec->name); + json_decref (cspec->map_alt_unit_names); + } + GNUNET_array_grow (cspecs, + num_currencies, + 0); +} |