From e30989c9303105770504f1bdbf26d843adf19468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zg=C3=BCr=20Kesim?= Date: Mon, 10 Jan 2022 00:04:23 +0100 Subject: [age restriction] progress 11/n Parse age restriction information from "/keys" - parse "age_restriction" extension, extract mask for age groups - parse denominations from "age_restricted_denoms", too, if available --- src/lib/exchange_api_handle.c | 178 ++++++++++++++++++++++++++++++------------ 1 file changed, 130 insertions(+), 48 deletions(-) (limited to 'src/lib/exchange_api_handle.c') diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index df501f0b7..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" @@ -345,6 +346,7 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, GNUNET_JSON_spec_end () }; + if (GNUNET_OK != GNUNET_JSON_parse (denom_key_obj, spec, @@ -761,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 (); @@ -791,63 +794,142 @@ decode_keys_json (const json_t *resp_obj, } } - /* parse the denomination keys, merging with the - possibly EXISTING array as required (/keys cherry picking) */ + /* Parse the supported extension(s): age-restriction. */ + /* TODO: maybe lift this into a FP in TALER_Extension ? */ { - json_t *denom_keys_array; - json_t *denom_key_obj; - unsigned int index; + json_t *age_restriction = json_object_get (resp_obj, + "age_restriction"); - EXITIF (NULL == (denom_keys_array = - json_object_get (resp_obj, - "denoms"))); - EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); + 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 () + }; - json_array_foreach (denom_keys_array, index, denom_key_obj) { - struct TALER_EXCHANGE_DenomPublicKey dk; - bool found = false; + if (GNUNET_OK != + GNUNET_JSON_parse (age_restriction, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } - memset (&dk, - 0, - sizeof (dk)); - EXITIF (GNUNET_SYSERR == - parse_json_denomkey (&dk, - check_sig, - denom_key_obj, - &key_data->master_pub, - hash_context)); - - for (unsigned int j = 0; - jnum_denom_keys; - j++) + if (critical || // do we care? + 0 != strncmp (version, "1", 1) ) /* TODO: better compatibility check */ { - if (0 == denoms_cmp (&dk, - &key_data->denom_keys[j])) - { - found = true; - break; - } + GNUNET_break_op (0); + return GNUNET_SYSERR; } - if (found) + + if (TALER_Extension_OK != + TALER_parse_age_group_string (age_groups, + &key_data->age_mask)) { - /* 0:0:0 did not support /keys cherry picking */ - TALER_LOG_DEBUG ("Skipping denomination key: already know it\n"); - TALER_denom_pub_free (&dk.key); - continue; + // TODO: print more specific error? + GNUNET_break_op (0); + return GNUNET_SYSERR; } - if (key_data->denom_keys_size == key_data->num_denom_keys) - GNUNET_array_grow (key_data->denom_keys, - key_data->denom_keys_size, - key_data->denom_keys_size * 2 + 2); - key_data->denom_keys[key_data->num_denom_keys++] = dk; - - /* Update "last_denom_issue_date" */ - TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n", - GNUNET_TIME_timestamp2s (dk.valid_from)); - key_data->last_denom_issue_date - = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date, - dk.valid_from); + } + } + + /* 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;} hive[2] = { + { "denoms", false }, + { "age_restricted_denoms", true }, }; + + 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, + hive[s].name); + + EXITIF (NULL == denom_keys_array && + ! hive[s].is_optional_age_restriction); + + if (NULL == denom_keys_array && + 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) { + struct TALER_EXCHANGE_DenomPublicKey dk; + bool found = false; + + memset (&dk, + 0, + sizeof (dk)); + EXITIF (GNUNET_SYSERR == + parse_json_denomkey (&dk, + check_sig, + denom_key_obj, + &key_data->master_pub, + hash_context)); + + /* Mark age restriction according where we got this denomination from, + * "denoms" or "age_restricted_denoms" */ + if (hive[s].is_optional_age_restriction) + dk.age_restricted = true; + + for (unsigned int j = 0; + jnum_denom_keys; + j++) + { + if (0 == denoms_cmp (&dk, + &key_data->denom_keys[j])) + { + found = true; + break; + } + } + if (found) + { + /* 0:0:0 did not support /keys cherry picking */ + TALER_LOG_DEBUG ("Skipping denomination key: already know it\n"); + TALER_denom_pub_free (&dk.key); + continue; + } + if (key_data->denom_keys_size == key_data->num_denom_keys) + GNUNET_array_grow (key_data->denom_keys, + key_data->denom_keys_size, + key_data->denom_keys_size * 2 + 2); + key_data->denom_keys[key_data->num_denom_keys++] = dk; + + /* Update "last_denom_issue_date" */ + TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n", + GNUNET_TIME_timestamp2s (dk.valid_from)); + key_data->last_denom_issue_date + = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date, + dk.valid_from); + }; + } } /* parse the auditor information */ -- cgit v1.2.3