diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index f1fccd70a..6976293cb 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -287,6 +287,11 @@ struct TALER_EXCHANGE_Keys */ struct GNUNET_TIME_Timestamp last_denom_issue_date; + /** + * If age restriction is enabled on the exchange, we get an non-zero age_mask + */ + struct TALER_AgeMask age_mask; + /** * Length of the @e sign_keys array (number of valid entries). */ diff --git a/src/include/taler_extensions.h b/src/include/taler_extensions.h index 199776eb7..243811eb5 100644 --- a/src/include/taler_extensions.h +++ b/src/include/taler_extensions.h @@ -110,7 +110,7 @@ TALER_extension_get_by_name (const char *name, * @return Error, if age groups were invalid, OK otherwise. */ enum TALER_Extension_ReturnValue -TALER_parse_age_group_string (char *groups, +TALER_parse_age_group_string (const char *groups, struct TALER_AgeMask *mask); /** diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 8919ae601..ac0e0584f 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -30,6 +30,7 @@ #include "taler_exchange_service.h" #include "taler_auditor_service.h" #include "taler_signatures.h" +#include "taler_extensions.h" #include "exchange_api_handle.h" #include "exchange_api_curl_defaults.h" #include "backoff.h" @@ -762,6 +763,7 @@ decode_keys_json (const json_t *resp_obj, return GNUNET_SYSERR; } } + /* parse the master public key and issue date of the response */ if (check_sig) hash_context = GNUNET_CRYPTO_hash_context_start (); @@ -792,36 +794,89 @@ decode_keys_json (const json_t *resp_obj, } } + /* Parse the supported extension(s): age-restriction. */ + /* TODO: maybe lift this into a FP in TALER_Extension ? */ + { + json_t *age_restriction = json_object_get (resp_obj, + "age_restriction"); + + if (NULL != age_restriction) + { + bool critical; + const char *version; + const char *age_groups; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_bool ("critical", + &critical), + GNUNET_JSON_spec_string ("version", + &version), + GNUNET_JSON_spec_string ("age_groups", + &age_groups), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (age_restriction, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + if (critical || // do we care? + 0 != strncmp (version, "1", 1) ) /* TODO: better compatibility check */ + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + if (TALER_Extension_OK != + TALER_parse_age_group_string (age_groups, + &key_data->age_mask)) + { + // TODO: print more specific error? + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } + } + /* parse the denomination keys, merging with the possibly EXISTING array as required (/keys cherry picking) */ { + /* The denominations can be in "denoms" and (optionally) in + * "age_restricted_denoms" + */ struct - { - char *name; - bool is_optional_age_restriction; - } section[2] = { - /* The denominations can be in "denoms" or in - * "age_restricted_denoms", the later being optional */ - { "denoms", false }, - { "age_restricted_denoms", true}, + { char *name; + bool is_optional_age_restriction;} hive[2] = { + { "denoms", false }, + { "age_restricted_denoms", true }, }; - for (size_t s = 0; s < sizeof(section) / sizeof(section[0]); s++) + for (size_t s = 0; s < sizeof(hive) / sizeof(hive[0]); s++) { json_t *denom_keys_array; json_t *denom_key_obj; unsigned int index; denom_keys_array = json_object_get (resp_obj, - section[s].name); + hive[s].name); EXITIF (NULL == denom_keys_array && - ! section[s].is_optional_age_restriction); + ! hive[s].is_optional_age_restriction); if (NULL == denom_keys_array && - section[s].is_optional_age_restriction) + hive[s].is_optional_age_restriction) continue; + /* if "age_restricted_denoms" exists, age-restriction better be enabled + * (that is: mask non-zero) */ + EXITIF (NULL != denom_keys_array && + hive[s].is_optional_age_restriction && + 0 == key_data->age_mask.mask); + EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); json_array_foreach (denom_keys_array, index, denom_key_obj) { @@ -840,7 +895,7 @@ decode_keys_json (const json_t *resp_obj, /* Mark age restriction according where we got this denomination from, * "denoms" or "age_restricted_denoms" */ - if (section[s].is_optional_age_restriction) + if (hive[s].is_optional_age_restriction) dk.age_restricted = true; for (unsigned int j = 0; diff --git a/src/util/extension_age_restriction.c b/src/util/extension_age_restriction.c index 42a58b2e9..b29a8ca88 100644 --- a/src/util/extension_age_restriction.c +++ b/src/util/extension_age_restriction.c @@ -80,7 +80,7 @@ TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg, * @return Error if string was invalid, OK otherwise. */ enum TALER_Extension_ReturnValue -TALER_parse_age_group_string (char *groups, +TALER_parse_age_group_string (const char *groups, struct TALER_AgeMask *mask) { enum TALER_Extension_ReturnValue ret = TALER_Extension_ERROR_SYS;