[age_restriction] progress 13/n
- major refactoring of extensions - extensions live now in a separate library, libtalerextensions - refactored all components using age_restriction accordingly - plumbing for plugin support for extensions roughly layed down
This commit is contained in:
parent
1962ed6b0b
commit
8684a9bfea
@ -541,6 +541,7 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/exchange/Makefile
|
src/exchange/Makefile
|
||||||
src/exchangedb/Makefile
|
src/exchangedb/Makefile
|
||||||
src/exchange-tools/Makefile
|
src/exchange-tools/Makefile
|
||||||
|
src/extensions/Makefile
|
||||||
src/lib/Makefile
|
src/lib/Makefile
|
||||||
src/testing/Makefile
|
src/testing/Makefile
|
||||||
src/benchmark/Makefile
|
src/benchmark/Makefile
|
||||||
|
@ -18,6 +18,7 @@ SUBDIRS = \
|
|||||||
include \
|
include \
|
||||||
util \
|
util \
|
||||||
json \
|
json \
|
||||||
|
extensions \
|
||||||
curl \
|
curl \
|
||||||
$(PQ_DIR) \
|
$(PQ_DIR) \
|
||||||
$(SQ_DIR) \
|
$(SQ_DIR) \
|
||||||
|
@ -54,6 +54,7 @@ taler_exchange_benchmark_LDADD = \
|
|||||||
$(top_builddir)/src/bank-lib/libtalerbank.la \
|
$(top_builddir)/src/bank-lib/libtalerbank.la \
|
||||||
$(top_builddir)/src/json/libtalerjson.la \
|
$(top_builddir)/src/json/libtalerjson.la \
|
||||||
$(top_builddir)/src/util/libtalerutil.la \
|
$(top_builddir)/src/util/libtalerutil.la \
|
||||||
|
$(top_builddir)/src/extensions/libtalerextensions.la \
|
||||||
-lgnunetjson \
|
-lgnunetjson \
|
||||||
-lgnunetcurl \
|
-lgnunetcurl \
|
||||||
-lgnunetutil \
|
-lgnunetutil \
|
||||||
|
@ -25,6 +25,7 @@ taler_exchange_offline_LDADD = \
|
|||||||
$(top_builddir)/src/lib/libtalerexchange.la \
|
$(top_builddir)/src/lib/libtalerexchange.la \
|
||||||
$(top_builddir)/src/json/libtalerjson.la \
|
$(top_builddir)/src/json/libtalerjson.la \
|
||||||
$(top_builddir)/src/util/libtalerutil.la \
|
$(top_builddir)/src/util/libtalerutil.la \
|
||||||
|
$(top_builddir)/src/extensions/libtalerextensions.la \
|
||||||
-lgnunetjson \
|
-lgnunetjson \
|
||||||
-lgnunetcurl \
|
-lgnunetcurl \
|
||||||
-ljansson \
|
-ljansson \
|
||||||
|
@ -1798,7 +1798,8 @@ upload_extensions (const char *exchange_url,
|
|||||||
{
|
{
|
||||||
struct TALER_ExtensionConfigHash h_config;
|
struct TALER_ExtensionConfigHash h_config;
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_extension_config_hash (extensions, &h_config))
|
if (GNUNET_OK !=
|
||||||
|
TALER_JSON_extensions_config_hash (extensions, &h_config))
|
||||||
{
|
{
|
||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
@ -3506,163 +3507,6 @@ do_setup (char *const *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct extension carries the information about an extension together with
|
|
||||||
* callbacks to parse the configuration and marshal it as JSON
|
|
||||||
*/
|
|
||||||
struct extension
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
bool enabled;
|
|
||||||
bool critical;
|
|
||||||
char *version;
|
|
||||||
void *config;
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue (*parse_config)(struct extension *this,
|
|
||||||
const char *section);
|
|
||||||
json_t *(*config_json)(const struct extension *this);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define EXT_PREFIX "exchange-extension-"
|
|
||||||
|
|
||||||
#define DEFAULT_AGE_GROUPS "8:10:12:14:16:18:21"
|
|
||||||
|
|
||||||
static enum GNUNET_GenericReturnValue
|
|
||||||
age_restriction_parse_config (struct extension *this, const char *section)
|
|
||||||
{
|
|
||||||
char *age_groups = NULL;
|
|
||||||
struct TALER_AgeMask mask = {0};
|
|
||||||
enum GNUNET_GenericReturnValue ret;
|
|
||||||
|
|
||||||
ret = GNUNET_CONFIGURATION_get_value_yesno (kcfg, section, "ENABLED");
|
|
||||||
|
|
||||||
this->enabled = (GNUNET_YES == ret);
|
|
||||||
|
|
||||||
if (! this->enabled)
|
|
||||||
return GNUNET_OK;
|
|
||||||
|
|
||||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg,
|
|
||||||
section,
|
|
||||||
"AGE_GROUPS",
|
|
||||||
&age_groups))
|
|
||||||
age_groups = DEFAULT_AGE_GROUPS;
|
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_parse_age_group_string (age_groups, &mask))
|
|
||||||
{
|
|
||||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
section,
|
|
||||||
"AGE_GROUPS");
|
|
||||||
test_shutdown ();
|
|
||||||
global_ret = EXIT_NOTCONFIGURED;
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't look here. We just store the mask in/as the pointer .*/
|
|
||||||
this->config = (void *) (size_t) mask.mask;
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static json_t *
|
|
||||||
age_restriction_json (const struct extension *this)
|
|
||||||
{
|
|
||||||
struct TALER_AgeMask mask;
|
|
||||||
json_t *conf;
|
|
||||||
|
|
||||||
if (! this->enabled)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Don't look here. We just restore the mask from/as the pointer .*/
|
|
||||||
mask.mask = (uint32_t) (size_t) this->config;
|
|
||||||
|
|
||||||
conf = GNUNET_JSON_PACK (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
"age_groups",
|
|
||||||
TALER_age_mask_to_string (&mask)));
|
|
||||||
|
|
||||||
return GNUNET_JSON_PACK (
|
|
||||||
GNUNET_JSON_pack_bool ("critical",
|
|
||||||
this->critical),
|
|
||||||
GNUNET_JSON_pack_string ("version",
|
|
||||||
this->version),
|
|
||||||
GNUNET_JSON_pack_object_steal ("config", conf));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct extension extensions[] = {
|
|
||||||
{
|
|
||||||
.name = "age_restriction",
|
|
||||||
.version = "1",
|
|
||||||
.config = 0,
|
|
||||||
.parse_config = &age_restriction_parse_config,
|
|
||||||
.config_json = &age_restriction_json,
|
|
||||||
},
|
|
||||||
/* TODO: add p2p here */
|
|
||||||
{0},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const struct extension*
|
|
||||||
get_extension (const char *extension)
|
|
||||||
{
|
|
||||||
for (const struct extension *known = extensions;
|
|
||||||
NULL != known->name;
|
|
||||||
known++)
|
|
||||||
{
|
|
||||||
if (0 == strncasecmp (extension,
|
|
||||||
known->name,
|
|
||||||
strlen (known->name)))
|
|
||||||
return known;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
collect_extensions (void *cls, const char *section)
|
|
||||||
{
|
|
||||||
json_t *obj = (json_t *) cls;
|
|
||||||
const char *name;
|
|
||||||
const struct extension *extension;
|
|
||||||
|
|
||||||
if (0 != global_ret)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (0 != strncasecmp (section,
|
|
||||||
EXT_PREFIX,
|
|
||||||
sizeof(EXT_PREFIX) - 1))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = section + sizeof(EXT_PREFIX) - 1;
|
|
||||||
|
|
||||||
if (NULL == (extension = get_extension (name)))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"Unsupported extension `%s` (section [%s]).\n", name,
|
|
||||||
section);
|
|
||||||
test_shutdown ();
|
|
||||||
global_ret = EXIT_NOTCONFIGURED;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GNUNET_OK != extension->parse_config ((struct extension *) extension,
|
|
||||||
section))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"Couldn't parse configuration for extension `%s` (section [%s]).\n",
|
|
||||||
name,
|
|
||||||
section);
|
|
||||||
test_shutdown ();
|
|
||||||
global_ret = EXIT_NOTCONFIGURED;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
json_object_set (obj, name, extension->config_json (extension));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print the current extensions as configured
|
* Print the current extensions as configured
|
||||||
*/
|
*/
|
||||||
@ -3672,10 +3516,21 @@ do_extensions_show (char *const *args)
|
|||||||
|
|
||||||
json_t *obj = json_object ();
|
json_t *obj = json_object ();
|
||||||
json_t *exts = json_object ();
|
json_t *exts = json_object ();
|
||||||
|
const struct TALER_Extension *it;
|
||||||
|
|
||||||
|
TALER_extensions_init ();
|
||||||
|
if (GNUNET_OK != TALER_extensions_load_taler_config (kcfg))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"error while loading taler config for extensions\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (it = TALER_extensions_get_head ();
|
||||||
|
NULL != it;
|
||||||
|
it = it->next)
|
||||||
|
json_object_set (exts, it->name, it->config_to_json (it));
|
||||||
|
|
||||||
GNUNET_CONFIGURATION_iterate_sections (kcfg,
|
|
||||||
&collect_extensions,
|
|
||||||
exts);
|
|
||||||
json_object_set (obj, "extensions", exts);
|
json_object_set (obj, "extensions", exts);
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "%s\n",
|
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "%s\n",
|
||||||
@ -3695,13 +3550,24 @@ do_extensions_sign (char *const *args)
|
|||||||
json_t *extensions = json_object ();
|
json_t *extensions = json_object ();
|
||||||
struct TALER_ExtensionConfigHash h_config;
|
struct TALER_ExtensionConfigHash h_config;
|
||||||
struct TALER_MasterSignatureP sig;
|
struct TALER_MasterSignatureP sig;
|
||||||
|
const struct TALER_Extension *it;
|
||||||
|
|
||||||
GNUNET_CONFIGURATION_iterate_sections (kcfg,
|
TALER_extensions_init ();
|
||||||
&collect_extensions,
|
|
||||||
extensions);
|
|
||||||
|
|
||||||
// TODO: check size of extensions?
|
if (GNUNET_OK != TALER_extensions_load_taler_config (kcfg))
|
||||||
if (GNUNET_OK != TALER_extension_config_hash (extensions, &h_config))
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"error while loading taler config for extensions\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (it = TALER_extensions_get_head ();
|
||||||
|
NULL != it;
|
||||||
|
it = it->next)
|
||||||
|
json_object_set (extensions, it->name, it->config_to_json (it));
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_JSON_extensions_config_hash (extensions, &h_config))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"error while hashing config for extensions\n");
|
"error while hashing config for extensions\n");
|
||||||
|
@ -119,6 +119,7 @@ taler_exchange_httpd_LDADD = \
|
|||||||
$(top_builddir)/src/json/libtalerjson.la \
|
$(top_builddir)/src/json/libtalerjson.la \
|
||||||
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
|
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
|
||||||
$(top_builddir)/src/util/libtalerutil.la \
|
$(top_builddir)/src/util/libtalerutil.la \
|
||||||
|
$(top_builddir)/src/extensions/libtalerextensions.la \
|
||||||
-lmicrohttpd \
|
-lmicrohttpd \
|
||||||
-lgnunetcurl \
|
-lgnunetcurl \
|
||||||
-lgnunetutil \
|
-lgnunetutil \
|
||||||
|
@ -147,11 +147,6 @@ int TEH_check_invariants_flag;
|
|||||||
*/
|
*/
|
||||||
bool TEH_suicide;
|
bool TEH_suicide;
|
||||||
|
|
||||||
/**
|
|
||||||
* Global register of extensions
|
|
||||||
*/
|
|
||||||
struct TALER_Extension **TEH_extensions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signature of the configuration of all enabled extensions,
|
* Signature of the configuration of all enabled extensions,
|
||||||
* signed by the exchange's offline master key with purpose
|
* signed by the exchange's offline master key with purpose
|
||||||
|
@ -201,21 +201,11 @@ extern volatile bool MHD_terminating;
|
|||||||
*/
|
*/
|
||||||
extern struct GNUNET_CURL_Context *TEH_curl_ctx;
|
extern struct GNUNET_CURL_Context *TEH_curl_ctx;
|
||||||
|
|
||||||
/**
|
|
||||||
* The manifest of the available extensions, NULL terminated
|
|
||||||
*/
|
|
||||||
extern struct TALER_Extension **TEH_extensions;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signature of the offline master key of all enabled extensions' configuration
|
* Signature of the offline master key of all enabled extensions' configuration
|
||||||
*/
|
*/
|
||||||
extern struct TALER_MasterSignatureP TEH_extensions_sig;
|
extern struct TALER_MasterSignatureP TEH_extensions_sig;
|
||||||
|
|
||||||
/* TODO: this will not work anymore, once we have plugable extensions */
|
|
||||||
#define TEH_extension_enabled(ext) (0 <= ext && TALER_Extension_MaxPredefined > \
|
|
||||||
ext && \
|
|
||||||
NULL != TEH_extensions[ext]->config)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Struct describing an URL and the handler for it.
|
* @brief Struct describing an URL and the handler for it.
|
||||||
*/
|
*/
|
||||||
|
@ -27,106 +27,6 @@
|
|||||||
#include "taler_extensions.h"
|
#include "taler_extensions.h"
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief implements the TALER_Extension.disable interface.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
age_restriction_disable (struct TALER_Extension *this)
|
|
||||||
{
|
|
||||||
if (NULL == this)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this->config = NULL;
|
|
||||||
|
|
||||||
if (NULL != this->config_json)
|
|
||||||
{
|
|
||||||
json_decref (this->config_json);
|
|
||||||
this->config_json = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief implements the TALER_Extension.parse_and_set_config interface.
|
|
||||||
* @param this if NULL, only tests the configuration
|
|
||||||
* @param config the configuration as json
|
|
||||||
*/
|
|
||||||
static enum GNUNET_GenericReturnValue
|
|
||||||
age_restriction_parse_and_set_config (struct TALER_Extension *this,
|
|
||||||
json_t *config)
|
|
||||||
{
|
|
||||||
struct TALER_AgeMask mask = {0};
|
|
||||||
enum GNUNET_GenericReturnValue ret;
|
|
||||||
|
|
||||||
ret = TALER_agemask_parse_json (config, &mask);
|
|
||||||
if (GNUNET_OK != ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* only testing the parser */
|
|
||||||
if (this == NULL)
|
|
||||||
return GNUNET_OK;
|
|
||||||
|
|
||||||
if (TALER_Extension_AgeRestriction != this->type)
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
|
|
||||||
if (NULL != this->config)
|
|
||||||
GNUNET_free (this->config);
|
|
||||||
|
|
||||||
this->config = GNUNET_malloc (sizeof(struct TALER_AgeMask));
|
|
||||||
GNUNET_memcpy (this->config, &mask, sizeof(struct TALER_AgeMask));
|
|
||||||
|
|
||||||
if (NULL != this->config_json)
|
|
||||||
json_decref (this->config_json);
|
|
||||||
|
|
||||||
this->config_json = config;
|
|
||||||
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief implements the TALER_Extension.test_config interface.
|
|
||||||
*/
|
|
||||||
static enum GNUNET_GenericReturnValue
|
|
||||||
age_restriction_test_config (const json_t *config)
|
|
||||||
{
|
|
||||||
struct TALER_AgeMask mask = {0};
|
|
||||||
|
|
||||||
return TALER_agemask_parse_json (config, &mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* The extension for age restriction */
|
|
||||||
static struct TALER_Extension extension_age_restriction = {
|
|
||||||
.type = TALER_Extension_AgeRestriction,
|
|
||||||
.name = "age_restriction",
|
|
||||||
.critical = false,
|
|
||||||
.version = "1",
|
|
||||||
.config = NULL, // disabled per default
|
|
||||||
.config_json = NULL,
|
|
||||||
.disable = &age_restriction_disable,
|
|
||||||
.test_config = &age_restriction_test_config,
|
|
||||||
.parse_and_set_config = &age_restriction_parse_and_set_config,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a list with the extensions for Age Restriction (and later Peer2Peer,
|
|
||||||
* ...)
|
|
||||||
*/
|
|
||||||
static struct TALER_Extension **
|
|
||||||
get_known_extensions ()
|
|
||||||
{
|
|
||||||
|
|
||||||
struct TALER_Extension **list = GNUNET_new_array (
|
|
||||||
TALER_Extension_MaxPredefined + 1,
|
|
||||||
struct TALER_Extension *);
|
|
||||||
list[TALER_Extension_AgeRestriction] = &extension_age_restriction;
|
|
||||||
list[TALER_Extension_MaxPredefined] = NULL;
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler listening for extensions updates by other exchange
|
* Handler listening for extensions updates by other exchange
|
||||||
* services.
|
* services.
|
||||||
@ -148,6 +48,7 @@ extension_update_event_cb (void *cls,
|
|||||||
{
|
{
|
||||||
(void) cls;
|
(void) cls;
|
||||||
enum TALER_Extension_Type type;
|
enum TALER_Extension_Type type;
|
||||||
|
const struct TALER_Extension *extension;
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Received extensions update event\n");
|
"Received extensions update event\n");
|
||||||
@ -161,12 +62,15 @@ extension_update_event_cb (void *cls,
|
|||||||
}
|
}
|
||||||
|
|
||||||
type = *(enum TALER_Extension_Type *) extra;
|
type = *(enum TALER_Extension_Type *) extra;
|
||||||
/* TODO: This check will not work once we have plugable extensions */
|
|
||||||
if (type <0 || type >= TALER_Extension_MaxPredefined)
|
|
||||||
|
/* Get the corresponding extension */
|
||||||
|
extension = TALER_extensions_get_by_type (type);
|
||||||
|
if (NULL == extension)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Oops, incorrect type for TALER_Extension_type\n");
|
"Oops, unknown extension type: %d\n", type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,13 +78,10 @@ extension_update_event_cb (void *cls,
|
|||||||
{
|
{
|
||||||
char *config_str = NULL;
|
char *config_str = NULL;
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
struct TALER_Extension *extension;
|
|
||||||
json_error_t err;
|
json_error_t err;
|
||||||
json_t *config;
|
json_t *config;
|
||||||
enum GNUNET_GenericReturnValue ret;
|
enum GNUNET_GenericReturnValue ret;
|
||||||
|
|
||||||
extension = TEH_extensions[type];
|
|
||||||
|
|
||||||
qs = TEH_plugin->get_extension_config (TEH_plugin->cls,
|
qs = TEH_plugin->get_extension_config (TEH_plugin->cls,
|
||||||
extension->name,
|
extension->name,
|
||||||
&config_str);
|
&config_str);
|
||||||
@ -193,10 +94,10 @@ extension_update_event_cb (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No config found -> extension is disabled
|
// No config found -> disable extension
|
||||||
if (NULL == config_str)
|
if (NULL == config_str)
|
||||||
{
|
{
|
||||||
extension->disable (extension);
|
extension->disable ((struct TALER_Extension *) extension);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +115,10 @@ extension_update_event_cb (void *cls,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call the parser for the extension
|
// Call the parser for the extension
|
||||||
ret = extension->parse_and_set_config (extension, config);
|
ret = extension->load_json_config (
|
||||||
|
(struct TALER_Extension *) extension,
|
||||||
|
config);
|
||||||
|
|
||||||
if (GNUNET_OK != ret)
|
if (GNUNET_OK != ret)
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
@ -229,8 +133,7 @@ extension_update_event_cb (void *cls,
|
|||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TEH_extensions_init ()
|
TEH_extensions_init ()
|
||||||
{
|
{
|
||||||
/* Populate the known extensions. */
|
TALER_extensions_init ();
|
||||||
TEH_extensions = get_known_extensions ();
|
|
||||||
|
|
||||||
/* Set the event handler for updates */
|
/* Set the event handler for updates */
|
||||||
struct GNUNET_DB_EventHeaderP ev = {
|
struct GNUNET_DB_EventHeaderP ev = {
|
||||||
@ -249,8 +152,10 @@ TEH_extensions_init ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Trigger the initial load of configuration from the db */
|
/* Trigger the initial load of configuration from the db */
|
||||||
for (struct TALER_Extension **it = TEH_extensions; NULL != *it; it++)
|
for (const struct TALER_Extension *it = TALER_extensions_get_head ();
|
||||||
extension_update_event_cb (NULL, &(*it)->type, sizeof((*it)->type));
|
NULL != it->next;
|
||||||
|
it = it->next)
|
||||||
|
extension_update_event_cb (NULL, &it->type, sizeof(it->type));
|
||||||
|
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
|
@ -744,14 +744,14 @@ load_age_mask (const char*section_name)
|
|||||||
{
|
{
|
||||||
static const struct TALER_AgeMask null_mask = {0};
|
static const struct TALER_AgeMask null_mask = {0};
|
||||||
struct TALER_AgeMask age_mask = {0};
|
struct TALER_AgeMask age_mask = {0};
|
||||||
|
/* TODO: optimize by putting this into global? */
|
||||||
const struct TALER_Extension *age_ext =
|
const struct TALER_Extension *age_ext =
|
||||||
TEH_extensions[TALER_Extension_AgeRestriction];
|
TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
|
||||||
|
|
||||||
// Get the age mask from the extension, if configured
|
// Get the age mask from the extension, if configured
|
||||||
if (NULL != age_ext->config)
|
/* TODO: optimize by putting this into global? */
|
||||||
{
|
if (TALER_extensions_is_enabled (age_ext))
|
||||||
age_mask = *(struct TALER_AgeMask *) age_ext->config;
|
age_mask = *(struct TALER_AgeMask *) age_ext->config;
|
||||||
}
|
|
||||||
|
|
||||||
if (age_mask.mask == 0)
|
if (age_mask.mask == 0)
|
||||||
{
|
{
|
||||||
@ -1706,14 +1706,14 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
|||||||
// Signal support for the configured, enabled extensions.
|
// Signal support for the configured, enabled extensions.
|
||||||
{
|
{
|
||||||
json_t *extensions = json_object ();
|
json_t *extensions = json_object ();
|
||||||
bool has_extensions;
|
bool has_extensions = false;
|
||||||
|
bool age_restriction_enabled = false;
|
||||||
|
|
||||||
/* Fill in the configurations of the enabled extensions */
|
/* Fill in the configurations of the enabled extensions */
|
||||||
for (struct TALER_Extension **it = TEH_extensions;
|
for (const struct TALER_Extension *extension = TALER_extensions_get_head ();
|
||||||
NULL != *it;
|
NULL != extension;
|
||||||
it++)
|
extension = extension->next)
|
||||||
{
|
{
|
||||||
const struct TALER_Extension *extension = *it;
|
|
||||||
json_t *ext;
|
json_t *ext;
|
||||||
json_t *config_json;
|
json_t *config_json;
|
||||||
int r;
|
int r;
|
||||||
@ -1722,7 +1722,10 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
|||||||
if (NULL == extension->config)
|
if (NULL == extension->config)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* flag our findings so far */
|
||||||
has_extensions = true;
|
has_extensions = true;
|
||||||
|
age_restriction_enabled = (extension->type ==
|
||||||
|
TALER_Extension_AgeRestriction);
|
||||||
|
|
||||||
GNUNET_assert (NULL != extension->config_json);
|
GNUNET_assert (NULL != extension->config_json);
|
||||||
|
|
||||||
@ -1743,7 +1746,6 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
|||||||
extensions,
|
extensions,
|
||||||
extension->name,
|
extension->name,
|
||||||
ext);
|
ext);
|
||||||
|
|
||||||
GNUNET_assert (0 == r);
|
GNUNET_assert (0 == r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1768,20 +1770,20 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
|||||||
r = json_object_update (keys, sig);
|
r = json_object_update (keys, sig);
|
||||||
GNUNET_assert (0 == r);
|
GNUNET_assert (0 == r);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Special case for age restrictions: if enabled, provide the lits of
|
||||||
|
// age-restricted denominations.
|
||||||
|
if (age_restriction_enabled &&
|
||||||
|
NULL != age_restricted_denoms)
|
||||||
|
{
|
||||||
|
GNUNET_assert (
|
||||||
|
0 ==
|
||||||
|
json_object_set_new (
|
||||||
|
keys,
|
||||||
|
"age_restricted_denoms",
|
||||||
|
age_restricted_denoms));
|
||||||
|
}
|
||||||
|
|
||||||
// Special case for age restrictions: if enabled, provide the lits of
|
|
||||||
// age-restricted denominations.
|
|
||||||
if (TEH_extension_enabled (TALER_Extension_AgeRestriction) &&
|
|
||||||
NULL != age_restricted_denoms)
|
|
||||||
{
|
|
||||||
GNUNET_assert (
|
|
||||||
0 ==
|
|
||||||
json_object_set_new (
|
|
||||||
keys,
|
|
||||||
"age_restricted_denoms",
|
|
||||||
age_restricted_denoms));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1884,7 +1886,8 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
|||||||
GNUNET_assert (NULL != denoms);
|
GNUNET_assert (NULL != denoms);
|
||||||
|
|
||||||
// If age restriction is enabled, initialize the array of age restricted denoms.
|
// If age restriction is enabled, initialize the array of age restricted denoms.
|
||||||
if (TEH_extension_enabled (TALER_Extension_AgeRestriction))
|
/* TODO: optimize by putting this into global? */
|
||||||
|
if (TALER_extensions_is_enabled_type (TALER_Extension_AgeRestriction))
|
||||||
{
|
{
|
||||||
age_restricted_denoms = json_array ();
|
age_restricted_denoms = json_array ();
|
||||||
GNUNET_assert (NULL != age_restricted_denoms);
|
GNUNET_assert (NULL != age_restricted_denoms);
|
||||||
|
@ -79,14 +79,14 @@ set_extensions (void *cls,
|
|||||||
for (uint32_t i = 0; i<sec->num_extensions; i++)
|
for (uint32_t i = 0; i<sec->num_extensions; i++)
|
||||||
{
|
{
|
||||||
struct Extension *ext = &sec->extensions[i];
|
struct Extension *ext = &sec->extensions[i];
|
||||||
|
const struct TALER_Extension *taler_ext;
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
char *config;
|
char *config;
|
||||||
|
|
||||||
/* Sanity check.
|
taler_ext = TALER_extensions_get_by_type (ext->type);
|
||||||
* TODO: This will not work anymore, once we have plugable extensions
|
if (NULL == taler_ext)
|
||||||
*/
|
|
||||||
if (0 > ext->type || TALER_Extension_MaxPredefined <= ext->type)
|
|
||||||
{
|
{
|
||||||
|
/* No such extension found */
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ set_extensions (void *cls,
|
|||||||
|
|
||||||
qs = TEH_plugin->set_extension_config (
|
qs = TEH_plugin->set_extension_config (
|
||||||
TEH_plugin->cls,
|
TEH_plugin->cls,
|
||||||
TEH_extensions[ext->type]->name,
|
taler_ext->name,
|
||||||
config);
|
config);
|
||||||
|
|
||||||
if (qs < 0)
|
if (qs < 0)
|
||||||
@ -183,17 +183,11 @@ TEH_handler_management_post_extensions (
|
|||||||
/* Verify the signature */
|
/* Verify the signature */
|
||||||
{
|
{
|
||||||
struct TALER_ExtensionConfigHash h_config;
|
struct TALER_ExtensionConfigHash h_config;
|
||||||
if (GNUNET_OK != TALER_extension_config_hash (extensions, &h_config))
|
|
||||||
{
|
|
||||||
GNUNET_JSON_parse_free (top_spec);
|
|
||||||
return TALER_MHD_reply_with_error (
|
|
||||||
connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
TALER_EC_GENERIC_PARAMETER_MALFORMED,
|
|
||||||
"invalid object, non-hashable");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_exchange_offline_extension_config_hash_verify (
|
if (GNUNET_OK !=
|
||||||
|
TALER_JSON_extensions_config_hash (extensions, &h_config) ||
|
||||||
|
GNUNET_OK !=
|
||||||
|
TALER_exchange_offline_extension_config_hash_verify (
|
||||||
&h_config,
|
&h_config,
|
||||||
&TEH_master_public_key,
|
&TEH_master_public_key,
|
||||||
&sec.extensions_sig))
|
&sec.extensions_sig))
|
||||||
@ -207,7 +201,6 @@ TEH_handler_management_post_extensions (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Received /management/extensions\n");
|
"Received /management/extensions\n");
|
||||||
|
|
||||||
@ -217,7 +210,7 @@ TEH_handler_management_post_extensions (
|
|||||||
|
|
||||||
/* Now parse individual extensions and signatures from those objects. */
|
/* Now parse individual extensions and signatures from those objects. */
|
||||||
{
|
{
|
||||||
const struct TALER_Extension *extension;
|
const struct TALER_Extension *extension = NULL;
|
||||||
const char *name;
|
const char *name;
|
||||||
json_t *config;
|
json_t *config;
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
@ -225,11 +218,8 @@ TEH_handler_management_post_extensions (
|
|||||||
json_object_foreach (extensions, name, config){
|
json_object_foreach (extensions, name, config){
|
||||||
|
|
||||||
/* 1. Make sure name refers to a supported extension */
|
/* 1. Make sure name refers to a supported extension */
|
||||||
if (GNUNET_OK != TALER_extension_get_by_name (name,
|
extension = TALER_extensions_get_by_name (name);
|
||||||
(const struct
|
if (NULL == extension)
|
||||||
TALER_Extension **)
|
|
||||||
TEH_extensions,
|
|
||||||
&extension))
|
|
||||||
{
|
{
|
||||||
ret = TALER_MHD_reply_with_error (
|
ret = TALER_MHD_reply_with_error (
|
||||||
connection,
|
connection,
|
||||||
@ -243,7 +233,9 @@ TEH_handler_management_post_extensions (
|
|||||||
sec.extensions[idx].type = extension->type;
|
sec.extensions[idx].type = extension->type;
|
||||||
|
|
||||||
/* 2. Make sure the config is sound */
|
/* 2. Make sure the config is sound */
|
||||||
if (GNUNET_OK != extension->test_config (sec.extensions[idx].config))
|
if (GNUNET_OK !=
|
||||||
|
extension->test_json_config (
|
||||||
|
sec.extensions[idx].config))
|
||||||
{
|
{
|
||||||
ret = TALER_MHD_reply_with_error (
|
ret = TALER_MHD_reply_with_error (
|
||||||
connection,
|
connection,
|
||||||
|
30
src/extensions/Makefile.am
Normal file
30
src/extensions/Makefile.am
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This Makefile.am is in the public domain
|
||||||
|
|
||||||
|
AM_CPPFLAGS = \
|
||||||
|
-I$(top_srcdir)/src/include \
|
||||||
|
$(LIBGCRYPT_CFLAGS) \
|
||||||
|
$(POSTGRESQL_CPPFLAGS)
|
||||||
|
|
||||||
|
if USE_COVERAGE
|
||||||
|
AM_CFLAGS = --coverage -O0
|
||||||
|
XLIB = -lgcov
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
|
||||||
|
lib_LTLIBRARIES = \
|
||||||
|
libtalerextensions.la
|
||||||
|
|
||||||
|
libtalerextensions_la_LDFLAGS = \
|
||||||
|
-version-info 0:0:0 \
|
||||||
|
-no-undefined
|
||||||
|
|
||||||
|
libtalerextensions_la_SOURCES = \
|
||||||
|
extensions.c \
|
||||||
|
extension_age_restriction.c
|
||||||
|
|
||||||
|
libtalerextensions_la_LIBADD = \
|
||||||
|
-lgnunetjson \
|
||||||
|
-ljansson \
|
||||||
|
$(XLIB)
|
321
src/extensions/extension_age_restriction.c
Normal file
321
src/extensions/extension_age_restriction.c
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2021-2022 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
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file extension_age_restriction.c
|
||||||
|
* @brief Utility functions regarding age restriction
|
||||||
|
* @author Özgür Kesim
|
||||||
|
*/
|
||||||
|
#include "platform.h"
|
||||||
|
#include "taler_util.h"
|
||||||
|
#include "taler_extensions.h"
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param groups String representation of the age groups. Must be of the form
|
||||||
|
* a:b:...:n:m
|
||||||
|
* with
|
||||||
|
* 0 < a < b <...< n < m < 32
|
||||||
|
* @param[out] mask Bit representation of the age groups.
|
||||||
|
* @return Error if string was invalid, OK otherwise.
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_parse_age_group_string (
|
||||||
|
const char *groups,
|
||||||
|
struct TALER_AgeMask *mask)
|
||||||
|
{
|
||||||
|
|
||||||
|
const char *pos = groups;
|
||||||
|
unsigned int prev = 0;
|
||||||
|
unsigned int val = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
while (*pos)
|
||||||
|
{
|
||||||
|
c = *pos++;
|
||||||
|
if (':' == c)
|
||||||
|
{
|
||||||
|
if (prev >= val)
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
mask->mask |= 1 << val;
|
||||||
|
prev = val;
|
||||||
|
val = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('0'>c || '9'<c)
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
val = 10 * val + c - '0';
|
||||||
|
|
||||||
|
if (0>=val || 32<=val)
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0>val || 32<=val || prev>=val)
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
mask->mask |= (1 << val);
|
||||||
|
mask->mask |= 1; // mark zeroth group, too
|
||||||
|
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the age mask into a string, like "8:10:12:14:16:18:21"
|
||||||
|
*
|
||||||
|
* @param mask Age mask
|
||||||
|
* @return String representation of the age mask, allocated by GNUNET_malloc.
|
||||||
|
* Can be used as value in the TALER config.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
TALER_age_mask_to_string (
|
||||||
|
const struct TALER_AgeMask *m)
|
||||||
|
{
|
||||||
|
uint32_t mask = m->mask;
|
||||||
|
unsigned int n = 0;
|
||||||
|
char *buf = GNUNET_malloc (32 * 3); // max characters possible
|
||||||
|
char *pos = buf;
|
||||||
|
|
||||||
|
if (NULL == buf)
|
||||||
|
{
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (mask != 0)
|
||||||
|
{
|
||||||
|
mask >>= 1;
|
||||||
|
n++;
|
||||||
|
if (0 == (mask & 1))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 9)
|
||||||
|
{
|
||||||
|
*(pos++) = '0' + n / 10;
|
||||||
|
}
|
||||||
|
*(pos++) = '0' + n % 10;
|
||||||
|
|
||||||
|
if (0 != (mask >> 1))
|
||||||
|
{
|
||||||
|
*(pos++) = ':';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ==================================================
|
||||||
|
*
|
||||||
|
* Age Restriction TALER_Extension imlementation
|
||||||
|
*
|
||||||
|
* ==================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief implements the TALER_Extension.disable interface.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
age_restriction_disable (
|
||||||
|
struct TALER_Extension *this)
|
||||||
|
{
|
||||||
|
if (NULL == this)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->config = NULL;
|
||||||
|
|
||||||
|
if (NULL != this->config_json)
|
||||||
|
{
|
||||||
|
json_decref (this->config_json);
|
||||||
|
this->config_json = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief implements the TALER_Extension.load_taler_config interface.
|
||||||
|
* @param cfg Handle to the GNUNET configuration
|
||||||
|
* @param[out] enabled Set to true if age restriction is enabled in the config, false otherwise.
|
||||||
|
* @param[out] mask Mask for age restriction. Will be 0 if age restriction was not enabled in the config.
|
||||||
|
* @return Error if extension for age restriction was set, but age groups were
|
||||||
|
* invalid, OK otherwise.
|
||||||
|
*/
|
||||||
|
static enum GNUNET_GenericReturnValue
|
||||||
|
age_restriction_load_taler_config (
|
||||||
|
struct TALER_Extension *this,
|
||||||
|
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||||
|
{
|
||||||
|
char *groups = NULL;
|
||||||
|
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
|
||||||
|
struct TALER_AgeMask mask = {0};
|
||||||
|
|
||||||
|
if ((GNUNET_YES !=
|
||||||
|
GNUNET_CONFIGURATION_have_value (cfg,
|
||||||
|
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||||
|
"ENABLED"))
|
||||||
|
||
|
||||||
|
(GNUNET_YES !=
|
||||||
|
GNUNET_CONFIGURATION_get_value_yesno (cfg,
|
||||||
|
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||||
|
"ENABLED")))
|
||||||
|
{
|
||||||
|
/* Age restriction is not enabled */
|
||||||
|
this->config = NULL;
|
||||||
|
this->config_json = NULL;
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Age restriction is enabled, extract age groups */
|
||||||
|
if ((GNUNET_YES ==
|
||||||
|
GNUNET_CONFIGURATION_have_value (cfg,
|
||||||
|
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||||
|
"AGE_GROUPS"))
|
||||||
|
&&
|
||||||
|
(GNUNET_YES !=
|
||||||
|
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||||
|
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||||
|
"AGE_GROUPS",
|
||||||
|
&groups)))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
|
||||||
|
mask.mask = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
|
||||||
|
|
||||||
|
ret = GNUNET_OK;
|
||||||
|
|
||||||
|
if (groups != NULL)
|
||||||
|
{
|
||||||
|
ret = TALER_parse_age_group_string (groups, &mask);
|
||||||
|
if (GNUNET_OK != ret)
|
||||||
|
mask.mask = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GNUNET_OK == ret)
|
||||||
|
this->config = (void *) (size_t) mask.mask;
|
||||||
|
|
||||||
|
GNUNET_free (groups);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief implements the TALER_Extension.load_json_config interface.
|
||||||
|
* @param this if NULL, only tests the configuration
|
||||||
|
* @param config the configuration as json
|
||||||
|
*/
|
||||||
|
static enum GNUNET_GenericReturnValue
|
||||||
|
age_restriction_load_json_config (
|
||||||
|
struct TALER_Extension *this,
|
||||||
|
json_t *config)
|
||||||
|
{
|
||||||
|
struct TALER_AgeMask mask = {0};
|
||||||
|
enum GNUNET_GenericReturnValue ret;
|
||||||
|
|
||||||
|
ret = TALER_JSON_parse_agemask (config, &mask);
|
||||||
|
if (GNUNET_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* only testing the parser */
|
||||||
|
if (this == NULL)
|
||||||
|
return GNUNET_OK;
|
||||||
|
|
||||||
|
if (TALER_Extension_AgeRestriction != this->type)
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
if (NULL != this->config)
|
||||||
|
GNUNET_free (this->config);
|
||||||
|
|
||||||
|
this->config = GNUNET_malloc (sizeof(struct TALER_AgeMask));
|
||||||
|
GNUNET_memcpy (this->config, &mask, sizeof(struct TALER_AgeMask));
|
||||||
|
|
||||||
|
if (NULL != this->config_json)
|
||||||
|
json_decref (this->config_json);
|
||||||
|
|
||||||
|
this->config_json = config;
|
||||||
|
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief implements the TALER_Extension.load_json_config interface.
|
||||||
|
* @param this if NULL, only tests the configuration
|
||||||
|
* @param config the configuration as json
|
||||||
|
*/
|
||||||
|
json_t *
|
||||||
|
age_restriction_config_to_json (
|
||||||
|
const struct TALER_Extension *this)
|
||||||
|
{
|
||||||
|
struct TALER_AgeMask mask;
|
||||||
|
char *mask_str;
|
||||||
|
json_t *conf;
|
||||||
|
|
||||||
|
GNUNET_assert (NULL != this);
|
||||||
|
GNUNET_assert (NULL != this->config);
|
||||||
|
|
||||||
|
if (NULL != this->config_json)
|
||||||
|
{
|
||||||
|
return json_copy (this->config_json);
|
||||||
|
}
|
||||||
|
|
||||||
|
mask.mask = (uint32_t) (size_t) this->config;
|
||||||
|
mask_str = TALER_age_mask_to_string (&mask);
|
||||||
|
conf = GNUNET_JSON_PACK (
|
||||||
|
GNUNET_JSON_pack_string ("age_groups", mask_str)
|
||||||
|
);
|
||||||
|
|
||||||
|
return GNUNET_JSON_PACK (
|
||||||
|
GNUNET_JSON_pack_bool ("critical", this->critical),
|
||||||
|
GNUNET_JSON_pack_string ("version", this->version),
|
||||||
|
GNUNET_JSON_pack_object_steal ("config", conf)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief implements the TALER_Extension.test_json_config interface.
|
||||||
|
*/
|
||||||
|
static enum GNUNET_GenericReturnValue
|
||||||
|
age_restriction_test_json_config (
|
||||||
|
const json_t *config)
|
||||||
|
{
|
||||||
|
struct TALER_AgeMask mask = {0};
|
||||||
|
|
||||||
|
return TALER_JSON_parse_agemask (config, &mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The extension for age restriction */
|
||||||
|
struct TALER_Extension _extension_age_restriction = {
|
||||||
|
.next = NULL,
|
||||||
|
.type = TALER_Extension_AgeRestriction,
|
||||||
|
.name = "age_restriction",
|
||||||
|
.critical = false,
|
||||||
|
.version = "1",
|
||||||
|
.config = NULL, // disabled per default
|
||||||
|
.config_json = NULL,
|
||||||
|
.disable = &age_restriction_disable,
|
||||||
|
.test_json_config = &age_restriction_test_json_config,
|
||||||
|
.load_json_config = &age_restriction_load_json_config,
|
||||||
|
.config_to_json = &age_restriction_config_to_json,
|
||||||
|
.load_taler_config = &age_restriction_load_taler_config,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* end of extension_age_restriction.c */
|
333
src/extensions/extensions.c
Normal file
333
src/extensions/extensions.c
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2021-2022 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
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file extensions.c
|
||||||
|
* @brief Utility functions for extensions
|
||||||
|
* @author Özgür Kesim
|
||||||
|
*/
|
||||||
|
#include "platform.h"
|
||||||
|
#include "taler_util.h"
|
||||||
|
#include "taler_signatures.h"
|
||||||
|
#include "taler_extensions.h"
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* head of the list of all registered extensions */
|
||||||
|
static struct TALER_Extension *_extensions = NULL;
|
||||||
|
static bool _initialized = false;
|
||||||
|
|
||||||
|
void
|
||||||
|
TALER_extensions_init ()
|
||||||
|
{
|
||||||
|
extern struct TALER_Extension _extension_age_restriction;
|
||||||
|
if (! _initialized)
|
||||||
|
_extensions = &_extension_age_restriction;
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const struct TALER_Extension *
|
||||||
|
TALER_extensions_get_head ()
|
||||||
|
{
|
||||||
|
return _extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_extensions_add (
|
||||||
|
const struct TALER_Extension *new)
|
||||||
|
{
|
||||||
|
struct TALER_Extension *ext;
|
||||||
|
|
||||||
|
if (_initialized)
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
GNUNET_assert (NULL != _extensions);
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
if (NULL == new ||
|
||||||
|
NULL == new->name ||
|
||||||
|
NULL == new->version ||
|
||||||
|
NULL == new->disable ||
|
||||||
|
NULL == new->test_json_config ||
|
||||||
|
NULL == new->load_json_config ||
|
||||||
|
NULL == new->config_to_json ||
|
||||||
|
NULL == new->load_taler_config ||
|
||||||
|
NULL == new->next)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid extension\n");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for collisions */
|
||||||
|
for (ext = _extensions; NULL != ext; ext = ext->next)
|
||||||
|
{
|
||||||
|
if (new->type == ext->type ||
|
||||||
|
0 == strcmp (new->name, ext->name))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "extension collision\n");
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No collisions found, so add this extension to the list */
|
||||||
|
ext->next = (struct TALER_Extension *) new;
|
||||||
|
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const struct TALER_Extension *
|
||||||
|
TALER_extensions_get_by_type (
|
||||||
|
enum TALER_Extension_Type type)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (const struct TALER_Extension *it = _extensions;
|
||||||
|
NULL != it;
|
||||||
|
it = it->next)
|
||||||
|
{
|
||||||
|
if (it->type == type)
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No extension found. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TALER_extensions_is_enabled_type (
|
||||||
|
enum TALER_Extension_Type type)
|
||||||
|
{
|
||||||
|
const struct TALER_Extension *ext =
|
||||||
|
TALER_extensions_get_by_type (type);
|
||||||
|
|
||||||
|
return (NULL != ext &&
|
||||||
|
TALER_extensions_is_enabled (ext));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const struct TALER_Extension *
|
||||||
|
TALER_extensions_get_by_name (
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
for (const struct TALER_Extension *it = _extensions;
|
||||||
|
NULL != it;
|
||||||
|
it = it->next)
|
||||||
|
{
|
||||||
|
if (0 == strcmp (name, it->name))
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
/* No extension found. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
config_hash_verify (
|
||||||
|
const struct TALER_ExtensionConfigHash *h_config,
|
||||||
|
const struct TALER_MasterPublicKeyP *master_pub,
|
||||||
|
const struct TALER_MasterSignatureP *master_sig
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct TALER_MasterExtensionConfigurationPS ec = {
|
||||||
|
.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION),
|
||||||
|
.purpose.size = htonl (sizeof(ec)),
|
||||||
|
.h_config = *h_config
|
||||||
|
};
|
||||||
|
|
||||||
|
return GNUNET_CRYPTO_eddsa_verify (
|
||||||
|
TALER_SIGNATURE_MASTER_EXTENSION,
|
||||||
|
&ec,
|
||||||
|
&master_sig->eddsa_signature,
|
||||||
|
&master_pub->eddsa_pub);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_extensions_verify_json_config_signature (
|
||||||
|
json_t *extensions,
|
||||||
|
struct TALER_MasterSignatureP *extensions_sig,
|
||||||
|
struct TALER_MasterPublicKeyP *master_pub)
|
||||||
|
{
|
||||||
|
struct TALER_ExtensionConfigHash h_config;
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_JSON_extensions_config_hash (extensions, &h_config))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
if (GNUNET_OK != config_hash_verify (
|
||||||
|
&h_config,
|
||||||
|
master_pub,
|
||||||
|
extensions_sig))
|
||||||
|
return GNUNET_NO;
|
||||||
|
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct load_conf_closure
|
||||||
|
{
|
||||||
|
const struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||||
|
enum GNUNET_GenericReturnValue error;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
collect_extensions (
|
||||||
|
void *cls,
|
||||||
|
const char *section)
|
||||||
|
{
|
||||||
|
struct load_conf_closure *col = cls;
|
||||||
|
const char *name;
|
||||||
|
const struct TALER_Extension *extension;
|
||||||
|
|
||||||
|
if (GNUNET_OK != col->error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (0 != strncasecmp (section,
|
||||||
|
TALER_EXTENSION_SECTION_PREFIX,
|
||||||
|
sizeof(TALER_EXTENSION_SECTION_PREFIX) - 1))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = section + sizeof(TALER_EXTENSION_SECTION_PREFIX) - 1;
|
||||||
|
|
||||||
|
if (NULL == (extension = TALER_extensions_get_by_name (name)))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Unsupported extension `%s` (section [%s]).\n", name,
|
||||||
|
section);
|
||||||
|
col->error = GNUNET_SYSERR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
extension->load_taler_config (
|
||||||
|
(struct TALER_Extension *) extension,
|
||||||
|
col->cfg))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Couldn't parse configuration for extension `%s` (section [%s]).\n",
|
||||||
|
name,
|
||||||
|
section);
|
||||||
|
col->error = GNUNET_SYSERR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_extensions_load_taler_config (
|
||||||
|
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||||
|
{
|
||||||
|
struct load_conf_closure col = {
|
||||||
|
.cfg = cfg,
|
||||||
|
.error = GNUNET_OK,
|
||||||
|
};
|
||||||
|
|
||||||
|
GNUNET_CONFIGURATION_iterate_sections (cfg,
|
||||||
|
&collect_extensions,
|
||||||
|
&col);
|
||||||
|
return col.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum GNUNET_GenericReturnValue
|
||||||
|
is_json_extension_config (
|
||||||
|
json_t *obj,
|
||||||
|
int *critical,
|
||||||
|
const char **version,
|
||||||
|
json_t **config)
|
||||||
|
{
|
||||||
|
enum GNUNET_GenericReturnValue ret;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_boolean ("critical",
|
||||||
|
critical),
|
||||||
|
GNUNET_JSON_spec_string ("version",
|
||||||
|
version),
|
||||||
|
GNUNET_JSON_spec_json ("config",
|
||||||
|
config),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = GNUNET_JSON_parse (obj, spec, NULL, NULL);
|
||||||
|
if (GNUNET_OK == ret)
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_extensions_load_json_config (
|
||||||
|
json_t *extensions)
|
||||||
|
{
|
||||||
|
const char*name;
|
||||||
|
json_t *blob;
|
||||||
|
|
||||||
|
GNUNET_assert (NULL != extensions);
|
||||||
|
GNUNET_assert (json_is_object (extensions));
|
||||||
|
|
||||||
|
json_object_foreach (extensions, name, blob)
|
||||||
|
{
|
||||||
|
int critical;
|
||||||
|
const char *version;
|
||||||
|
json_t *config;
|
||||||
|
const struct TALER_Extension *extension =
|
||||||
|
TALER_extensions_get_by_name (name);
|
||||||
|
|
||||||
|
if (NULL == extension)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"no such extension: %s\n", name);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load and verify criticality, version, etc. */
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
is_json_extension_config (
|
||||||
|
blob, &critical, &version, &config))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
if (critical != extension->critical
|
||||||
|
|| 0 != strcmp (version, extension->version) // TODO: libtool compare?
|
||||||
|
|| NULL == config
|
||||||
|
|| GNUNET_OK != extension->test_json_config (config))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
/* This _should_ work now */
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
extension->load_json_config ((struct TALER_Extension *) extension,
|
||||||
|
config))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure to disable all extensions that weren't mentioned in the json */
|
||||||
|
for (const struct TALER_Extension *it = TALER_extensions_get_head ();
|
||||||
|
NULL != it;
|
||||||
|
it = it->next)
|
||||||
|
{
|
||||||
|
if (NULL == json_object_get (extensions, it->name))
|
||||||
|
it->disable ((struct TALER_Extension *) it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* end of extensions.c */
|
@ -3159,5 +3159,4 @@ void
|
|||||||
TALER_EXCHANGE_add_auditor_denomination_cancel (
|
TALER_EXCHANGE_add_auditor_denomination_cancel (
|
||||||
struct TALER_EXCHANGE_AuditorAddDenominationHandle *ah);
|
struct TALER_EXCHANGE_AuditorAddDenominationHandle *ah);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _TALER_EXCHANGE_SERVICE_H */
|
#endif /* _TALER_EXCHANGE_SERVICE_H */
|
||||||
|
@ -40,6 +40,9 @@ enum TALER_Extension_Type
|
|||||||
*/
|
*/
|
||||||
struct TALER_Extension
|
struct TALER_Extension
|
||||||
{
|
{
|
||||||
|
/* simple linked list */
|
||||||
|
struct TALER_Extension *next;
|
||||||
|
|
||||||
enum TALER_Extension_Type type;
|
enum TALER_Extension_Type type;
|
||||||
char *name;
|
char *name;
|
||||||
bool critical;
|
bool critical;
|
||||||
@ -48,28 +51,125 @@ struct TALER_Extension
|
|||||||
json_t *config_json;
|
json_t *config_json;
|
||||||
|
|
||||||
void (*disable)(struct TALER_Extension *this);
|
void (*disable)(struct TALER_Extension *this);
|
||||||
enum GNUNET_GenericReturnValue (*test_config)(const json_t *config);
|
|
||||||
enum GNUNET_GenericReturnValue (*parse_and_set_config)(struct
|
enum GNUNET_GenericReturnValue (*test_json_config)(
|
||||||
TALER_Extension *this,
|
const json_t *config);
|
||||||
json_t *config);
|
|
||||||
|
enum GNUNET_GenericReturnValue (*load_json_config)(
|
||||||
|
struct TALER_Extension *this,
|
||||||
|
json_t *config);
|
||||||
|
|
||||||
|
json_t *(*config_to_json)(
|
||||||
|
const struct TALER_Extension *this);
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue (*load_taler_config)(
|
||||||
|
struct TALER_Extension *this,
|
||||||
|
const struct GNUNET_CONFIGURATION_Handle *cfg);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic functions for extensions
|
* Generic functions for extensions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
TALER_extensions_init ();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the configuration of the extensions from the given TALER configuration
|
||||||
|
*
|
||||||
|
* @param cfg Handle to the TALER configuration
|
||||||
|
* @return GNUNET_OK on success, GNUNET_SYSERR if unknown extensions were found
|
||||||
|
* or any particular configuration couldn't be parsed.
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_extensions_load_taler_config (
|
||||||
|
const struct GNUNET_CONFIGURATION_Handle *cfg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the head of the linked list of extensions
|
||||||
|
*/
|
||||||
|
const struct TALER_Extension *
|
||||||
|
TALER_extensions_get_head ();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds an extension to the linked list of extensions
|
||||||
|
*
|
||||||
|
* @param new_extension the new extension to be added
|
||||||
|
* @return GNUNET_OK on success, GNUNET_SYSERR if the extension is invalid
|
||||||
|
* (missing fields), GNUNET_NO if there is already an extension with that name
|
||||||
|
* or type.
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_extensions_add (
|
||||||
|
const struct TALER_Extension *new_extension);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and returns a supported extension by a given type.
|
||||||
|
*
|
||||||
|
* @param type type of the extension to lookup
|
||||||
|
* @return extension found, or NULL (should not happen!)
|
||||||
|
*/
|
||||||
|
const struct TALER_Extension *
|
||||||
|
TALER_extensions_get_by_type (
|
||||||
|
enum TALER_Extension_Type type);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds and returns a supported extension by a given name.
|
* Finds and returns a supported extension by a given name.
|
||||||
*
|
*
|
||||||
* @param name name of the extension to lookup
|
* @param name name of the extension to lookup
|
||||||
* @param extensions list of TALER_Extensions as haystack, terminated by a NULL-entry
|
* @return the extension, if found, NULL otherwise
|
||||||
* @param[out] ext set to the extension, if found, NULL otherwise
|
*/
|
||||||
* @return GNUNET_OK if extension was found, GNUNET_NO otherwise
|
const struct TALER_Extension *
|
||||||
|
TALER_extensions_get_by_name (
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
#define TALER_extensions_is_enabled(ext) (NULL != (ext)->config)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given type of an extension is enabled
|
||||||
|
*
|
||||||
|
* @param type type of to check
|
||||||
|
* @return true enabled, false if not enabled, will assert if type is not found.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
TALER_extensions_is_enabled_type (
|
||||||
|
enum TALER_Extension_Type type);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify the signature of a given JSON object for extensions with the master
|
||||||
|
* key of the exchange.
|
||||||
|
*
|
||||||
|
* The JSON object must be of type ExchangeKeysResponse as described in
|
||||||
|
* https://docs.taler.net/design-documents/006-extensions.html#exchange
|
||||||
|
*
|
||||||
|
* @param extensions JSON object with the extension configuration
|
||||||
|
* @param extensions_sig signature of the hash of the JSON object
|
||||||
|
* @param master_pub public key to verify the signature
|
||||||
|
* @return GNUNET_OK on success, GNUNET_SYSERR when hashing of the JSON fails
|
||||||
|
* and GNUNET_NO if the signature couldn't be verified.
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_extension_get_by_name (const char *name,
|
TALER_extensions_verify_json_config_signature (
|
||||||
const struct TALER_Extension **extensions,
|
json_t *extensions,
|
||||||
const struct TALER_Extension **ext);
|
struct TALER_MasterSignatureP *extensions_sig,
|
||||||
|
struct TALER_MasterPublicKeyP *master_pub);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the configuration of the extensions from a given JSON object.
|
||||||
|
*
|
||||||
|
* The JSON object must be of type ExchangeKeysResponse as described in
|
||||||
|
* https://docs.taler.net/design-documents/006-extensions.html#exchange
|
||||||
|
*
|
||||||
|
* @param cfg Handle to the TALER configuration
|
||||||
|
* @return GNUNET_OK on success, GNUNET_SYSERR if unknown extensions were found
|
||||||
|
* or any particular configuration couldn't be parsed.
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_extensions_load_json_config (
|
||||||
|
json_t *extensions);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TALER Age Restriction Extension
|
* TALER Age Restriction Extension
|
||||||
@ -82,9 +182,11 @@ TALER_extension_get_by_name (const char *name,
|
|||||||
* The default age mask represents the age groups
|
* The default age mask represents the age groups
|
||||||
* 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-20, 21-...
|
* 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-20, 21-...
|
||||||
*/
|
*/
|
||||||
#define TALER_EXTENSION_DEFAULT_AGE_MASK (1 | 1 << 8 | 1 << 10 | 1 << 12 | 1 \
|
#define TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK (1 | 1 << 8 | 1 << 10 \
|
||||||
<< 14 | 1 << 16 | 1 << 18 | 1 \
|
| 1 << 12 | 1 << 14 \
|
||||||
<< 21)
|
| 1 << 16 | 1 << 18 \
|
||||||
|
| 1 << 21)
|
||||||
|
#define TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_GROUPS "8:10:12:14:16:18:21"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parses a string as a list of age groups.
|
* @brief Parses a string as a list of age groups.
|
||||||
@ -104,8 +206,9 @@ TALER_extension_get_by_name (const char *name,
|
|||||||
* @return Error, if age groups were invalid, OK otherwise.
|
* @return Error, if age groups were invalid, OK otherwise.
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_parse_age_group_string (const char *groups,
|
TALER_parse_age_group_string (
|
||||||
struct TALER_AgeMask *mask);
|
const char *groups,
|
||||||
|
struct TALER_AgeMask *mask);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes the age mask into a string, like "8:10:12:14:16:18:21"
|
* Encodes the age mask into a string, like "8:10:12:14:16:18:21"
|
||||||
@ -115,21 +218,8 @@ TALER_parse_age_group_string (const char *groups,
|
|||||||
* Can be used as value in the TALER config.
|
* Can be used as value in the TALER config.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
TALER_age_mask_to_string (const struct TALER_AgeMask *mask);
|
TALER_age_mask_to_string (
|
||||||
|
const struct TALER_AgeMask *mask);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reads the age groups from the configuration and sets the
|
|
||||||
* corresponding age mask.
|
|
||||||
*
|
|
||||||
* @param cfg
|
|
||||||
* @param[out] mask for age restriction, will be set to 0 if age restriction is disabled.
|
|
||||||
* @return Error if extension for age restriction was set but age groups were
|
|
||||||
* invalid, OK otherwise.
|
|
||||||
*/
|
|
||||||
enum GNUNET_GenericReturnValue
|
|
||||||
TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
|
|
||||||
struct TALER_AgeMask *mask);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -549,8 +549,8 @@ TALER_deposit_extension_hash (const json_t *extensions,
|
|||||||
* @return GNUNET_OK on success, GNUNET_SYSERR on failure
|
* @return GNUNET_OK on success, GNUNET_SYSERR on failure
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_extension_config_hash (const json_t *config,
|
TALER_JSON_extensions_config_hash (const json_t *config,
|
||||||
struct TALER_ExtensionConfigHash *eh);
|
struct TALER_ExtensionConfigHash *eh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a JSON object { "extension": "age_restriction", "mask": <uint32> }.
|
* Parses a JSON object { "extension": "age_restriction", "mask": <uint32> }.
|
||||||
@ -560,7 +560,7 @@ TALER_extension_config_hash (const json_t *config,
|
|||||||
* @return #GNUNET_OK on success and #GNUNET_SYSERR on failure.
|
* @return #GNUNET_OK on success and #GNUNET_SYSERR on failure.
|
||||||
*/
|
*/
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_agemask_parse_json (const json_t *root,
|
TALER_JSON_parse_agemask (const json_t *root,
|
||||||
struct TALER_AgeMask *mask);
|
struct TALER_AgeMask *mask);
|
||||||
|
|
||||||
#endif /* TALER_JSON_LIB_H_ */
|
#endif /* TALER_JSON_LIB_H_ */
|
||||||
|
@ -1010,8 +1010,8 @@ TALER_deposit_extension_hash (const json_t *extensions,
|
|||||||
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_extension_config_hash (const json_t *config,
|
TALER_JSON_extensions_config_hash (const json_t *config,
|
||||||
struct TALER_ExtensionConfigHash *ech)
|
struct TALER_ExtensionConfigHash *ech)
|
||||||
{
|
{
|
||||||
return dump_and_hash (config,
|
return dump_and_hash (config,
|
||||||
"taler-extension-configuration",
|
"taler-extension-configuration",
|
||||||
|
@ -660,7 +660,7 @@ TALER_JSON_spec_i18n_str (const char *name,
|
|||||||
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_agemask_parse_json (const json_t *root,
|
TALER_JSON_parse_agemask (const json_t *root,
|
||||||
struct TALER_AgeMask *mask)
|
struct TALER_AgeMask *mask)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -57,6 +57,7 @@ libtalerexchange_la_LIBADD = \
|
|||||||
$(top_builddir)/src/json/libtalerjson.la \
|
$(top_builddir)/src/json/libtalerjson.la \
|
||||||
$(top_builddir)/src/curl/libtalercurl.la \
|
$(top_builddir)/src/curl/libtalercurl.la \
|
||||||
$(top_builddir)/src/util/libtalerutil.la \
|
$(top_builddir)/src/util/libtalerutil.la \
|
||||||
|
$(top_builddir)/src/extensions/libtalerextensions.la \
|
||||||
-lgnunetcurl \
|
-lgnunetcurl \
|
||||||
-lgnunetjson \
|
-lgnunetjson \
|
||||||
-lgnunetutil \
|
-lgnunetutil \
|
||||||
|
@ -795,50 +795,39 @@ decode_keys_json (const json_t *resp_obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the supported extension(s): age-restriction. */
|
/* Parse the supported extension(s): age-restriction. */
|
||||||
/* TODO: maybe lift this into a FP in TALER_Extension ? */
|
/* TODO: maybe lift all this into a FP in TALER_Extension ? */
|
||||||
{
|
{
|
||||||
json_t *age_restriction = json_object_get (resp_obj,
|
struct TALER_MasterSignatureP extensions_sig = {0};
|
||||||
"age_restriction");
|
json_t *extensions = NULL;
|
||||||
|
struct GNUNET_JSON_Specification ext_spec[] = {
|
||||||
|
GNUNET_JSON_spec_mark_optional (
|
||||||
|
GNUNET_JSON_spec_json ("extensions",
|
||||||
|
&extensions)),
|
||||||
|
GNUNET_JSON_spec_mark_optional (
|
||||||
|
GNUNET_JSON_spec_fixed_auto (
|
||||||
|
"extensions_sig",
|
||||||
|
&extensions_sig)),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
if (NULL != age_restriction)
|
/* 1. Search for extensions in the response to /keys */
|
||||||
|
EXITIF (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (resp_obj,
|
||||||
|
ext_spec,
|
||||||
|
NULL, NULL));
|
||||||
|
|
||||||
|
if (NULL != extensions)
|
||||||
{
|
{
|
||||||
bool critical;
|
/* 2. We have an extensions object. Verify its signature. */
|
||||||
const char *version;
|
EXITIF (GNUNET_OK !=
|
||||||
const char *age_groups;
|
TALER_extensions_verify_json_config_signature (
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
extensions,
|
||||||
GNUNET_JSON_spec_bool ("critical",
|
&extensions_sig,
|
||||||
&critical),
|
&key_data->master_pub));
|
||||||
GNUNET_JSON_spec_string ("version",
|
|
||||||
&version),
|
|
||||||
GNUNET_JSON_spec_string ("age_groups",
|
|
||||||
&age_groups),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
/* 3. Parse and set the the configuration of the extensions accordingly */
|
||||||
GNUNET_JSON_parse (age_restriction,
|
EXITIF (GNUNET_OK !=
|
||||||
spec,
|
TALER_extensions_load_json_config (extensions));
|
||||||
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 (GNUNET_OK !=
|
|
||||||
TALER_parse_age_group_string (age_groups,
|
|
||||||
&key_data->age_mask))
|
|
||||||
{
|
|
||||||
// TODO: print more specific error?
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +72,6 @@ libtalerutil_la_SOURCES = \
|
|||||||
crypto_wire.c \
|
crypto_wire.c \
|
||||||
denom.c \
|
denom.c \
|
||||||
exchange_signatures.c \
|
exchange_signatures.c \
|
||||||
extensions.c \
|
|
||||||
extension_age_restriction.c \
|
|
||||||
getopt.c \
|
getopt.c \
|
||||||
lang.c \
|
lang.c \
|
||||||
iban.c \
|
iban.c \
|
||||||
|
@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of TALER
|
|
||||||
Copyright (C) 2014-2020 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
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file extension_age_restriction.c
|
|
||||||
* @brief Utility functions regarding age restriction
|
|
||||||
* @author Özgür Kesim
|
|
||||||
*/
|
|
||||||
#include "platform.h"
|
|
||||||
#include "taler_util.h"
|
|
||||||
#include "taler_extensions.h"
|
|
||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param cfg Handle to the GNUNET configuration
|
|
||||||
* @param[out] Mask for age restriction. Will be 0 if age restriction was not enabled in the config.
|
|
||||||
* @return Error if extension for age restriction was set, but age groups were
|
|
||||||
* invalid, OK otherwise.
|
|
||||||
*/
|
|
||||||
enum GNUNET_GenericReturnValue
|
|
||||||
TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
|
|
||||||
struct TALER_AgeMask *mask)
|
|
||||||
{
|
|
||||||
char *groups;
|
|
||||||
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
|
|
||||||
|
|
||||||
if ((GNUNET_YES != GNUNET_CONFIGURATION_have_value (cfg,
|
|
||||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
|
||||||
"ENABLED")) ||
|
|
||||||
(GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (cfg,
|
|
||||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
|
||||||
"ENABLED")))
|
|
||||||
{
|
|
||||||
/* Age restriction is not enabled */
|
|
||||||
mask->mask = 0;
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Age restriction is enabled, extract age groups */
|
|
||||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
|
|
||||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
|
||||||
"AGE_GROUPS",
|
|
||||||
&groups))
|
|
||||||
{
|
|
||||||
/* FIXME: log error? */
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
if (groups == NULL)
|
|
||||||
{
|
|
||||||
/* No groups defined in config, return default_age_mask */
|
|
||||||
mask->mask = TALER_EXTENSION_DEFAULT_AGE_MASK;
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TALER_parse_age_group_string (groups, mask);
|
|
||||||
GNUNET_free (groups);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param groups String representation of the age groups. Must be of the form
|
|
||||||
* a:b:...:n:m
|
|
||||||
* with
|
|
||||||
* 0 < a < b <...< n < m < 32
|
|
||||||
* @param[out] mask Bit representation of the age groups.
|
|
||||||
* @return Error if string was invalid, OK otherwise.
|
|
||||||
*/
|
|
||||||
enum GNUNET_GenericReturnValue
|
|
||||||
TALER_parse_age_group_string (const char *groups,
|
|
||||||
struct TALER_AgeMask *mask)
|
|
||||||
{
|
|
||||||
|
|
||||||
const char *pos = groups;
|
|
||||||
unsigned int prev = 0;
|
|
||||||
unsigned int val = 0;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
while (*pos)
|
|
||||||
{
|
|
||||||
c = *pos++;
|
|
||||||
if (':' == c)
|
|
||||||
{
|
|
||||||
if (prev >= val)
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
|
|
||||||
mask->mask |= 1 << val;
|
|
||||||
prev = val;
|
|
||||||
val = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('0'>c || '9'<c)
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
|
|
||||||
val = 10 * val + c - '0';
|
|
||||||
|
|
||||||
if (0>=val || 32<=val)
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0>val || 32<=val || prev>=val)
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
|
|
||||||
mask->mask |= (1 << val);
|
|
||||||
mask->mask |= 1; // mark zeroth group, too
|
|
||||||
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes the age mask into a string, like "8:10:12:14:16:18:21"
|
|
||||||
*
|
|
||||||
* @param mask Age mask
|
|
||||||
* @return String representation of the age mask, allocated by GNUNET_malloc.
|
|
||||||
* Can be used as value in the TALER config.
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
TALER_age_mask_to_string (const struct TALER_AgeMask *m)
|
|
||||||
{
|
|
||||||
uint32_t mask = m->mask;
|
|
||||||
unsigned int n = 0;
|
|
||||||
char *buf = GNUNET_malloc (32 * 3); // max characters possible
|
|
||||||
char *pos = buf;
|
|
||||||
|
|
||||||
if (NULL == buf)
|
|
||||||
{
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (mask != 0)
|
|
||||||
{
|
|
||||||
mask >>= 1;
|
|
||||||
n++;
|
|
||||||
if (0 == (mask & 1))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n > 9)
|
|
||||||
{
|
|
||||||
*(pos++) = '0' + n / 10;
|
|
||||||
}
|
|
||||||
*(pos++) = '0' + n % 10;
|
|
||||||
|
|
||||||
if (0 != (mask >> 1))
|
|
||||||
{
|
|
||||||
*(pos++) = ':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* end of extension_age_restriction.c */
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of TALER
|
|
||||||
Copyright (C) 2014-2021 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
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file extensions.c
|
|
||||||
* @brief Utility functions for extensions
|
|
||||||
* @author Özgür Kesim
|
|
||||||
*/
|
|
||||||
#include "platform.h"
|
|
||||||
#include "taler_util.h"
|
|
||||||
#include "taler_extensions.h"
|
|
||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue
|
|
||||||
TALER_extension_get_by_name (const char *name,
|
|
||||||
const struct TALER_Extension **extensions,
|
|
||||||
const struct TALER_Extension **ext)
|
|
||||||
{
|
|
||||||
|
|
||||||
const struct TALER_Extension *it = *extensions;
|
|
||||||
|
|
||||||
for (; NULL != it; it++)
|
|
||||||
{
|
|
||||||
if (0 == strncmp (name,
|
|
||||||
it->name,
|
|
||||||
strlen (it->name)))
|
|
||||||
{
|
|
||||||
*ext = it;
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* end of extensions.c */
|
|
Loading…
Reference in New Issue
Block a user