Compare commits

...

3 Commits

Author SHA1 Message Date
601c18caba
first steps for offline tool to handle extensions 2022-01-18 12:21:05 +01:00
6bfbe260c7
fix return value 2022-01-18 12:20:38 +01:00
f94f502a5e
fix TALER_parse_age_group_string
- parser works now also on string literals
- use GNUNET_GenericReturnValue
2022-01-18 11:04:57 +01:00
5 changed files with 303 additions and 57 deletions

View File

@ -20,8 +20,10 @@
*/
#include <platform.h>
#include <gnunet/gnunet_json_lib.h>
#include <gnunet/gnunet_util_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
#include "taler_extensions.h"
/**
* Name of the input for the 'sign' and 'show' operation.
@ -3314,6 +3316,265 @@ do_setup (char *const *args)
}
struct extension
{
char *name;
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);
};
static enum GNUNET_GenericReturnValue
age_restriction_parse_config (struct extension *this, const char *section)
{
char *age_groups;
struct TALER_AgeMask *mask = GNUNET_malloc (sizeof(struct TALER_AgeMask));
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg,
section,
"AGE_GROUPS",
&age_groups))
goto ERROR;
if (GNUNET_OK != TALER_parse_age_group_string (age_groups, mask))
goto ERROR;
this->config = mask;
return GNUNET_OK;
ERROR:
GNUNET_free (mask);
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
section,
"AGE_GROUPS");
test_shutdown ();
global_ret = EXIT_NOTCONFIGURED;
return GNUNET_SYSERR;
}
static json_t *
age_restriction_json (const struct extension *this)
{
char *groups = TALER_age_mask_to_string (this->config);
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_bool ("critical",
this->critical),
GNUNET_JSON_pack_string ("version",
this->version),
GNUNET_JSON_pack_string ("age_groups", groups)
);
}
static struct extension extensions[] = {
{
.name = "age-restriction",
.version = "1",
.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
show_extensions (void *cls, const char *section)
{
if (0 != global_ret)
{
return;
}
if (0 == strncasecmp (section,
"exchange-extension-",
sizeof("exchange-extension-") - 1))
{
const char *name = section + sizeof("exchange-extension-") - 1;
const struct extension *extension = get_extension (name);
enum GNUNET_GenericReturnValue ret;
if (NULL == extension)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unsupported extension `%s` (section [%s]).\n", name,
section);
test_shutdown ();
global_ret = EXIT_INVALIDARGUMENT;
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "found extension %s\n", name);
{
bool enabled = (GNUNET_YES ==
GNUNET_CONFIGURATION_get_value_yesno (
kcfg, section, "ENABLED"));
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"\textension is %s\n",
enabled?"ENABLED":"DISABLED");
if (! enabled)
return;
ret = extension->parse_config ((struct extension *) extension, section);
if (GNUNET_OK != ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Couldn't parse configuration for extension `%s` (section [%s]).\n",
name,
section);
test_shutdown ();
global_ret = EXIT_INVALIDARGUMENT;
return;
}
json_t *cfg = extension->config_json (extension);
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"\tconfig: %s\n",
json_dumps (cfg, JSON_INDENT (2)));
return;
}
}
}
static void
sign_extensions (void *cls, const char *section)
{
if (0 != global_ret)
{
return;
}
if (0 == strncasecmp (section,
"exchange-extension-",
sizeof("exchange-extension-") - 1))
{
const char *name = section + sizeof("exchange-extension-") - 1;
const struct extension *extension = get_extension (name);
if (NULL == extension)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unsupported extension `%s` (section [%s]).\n", name,
section);
test_shutdown ();
global_ret = EXIT_INVALIDARGUMENT;
return;
}
if (GNUNET_YES ==
GNUNET_CONFIGURATION_get_value_yesno (
kcfg, section, "ENABLED"))
{
// TODO
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "TODO signing extension %s\n",
name);
}
}
}
/*
* Print the current extensions as configured
*/
static void
do_extensions_show (char *const *args)
{
GNUNET_CONFIGURATION_iterate_sections (kcfg,
&show_extensions,
NULL);
}
static void
do_extensions_sign (char *const *args)
{
GNUNET_CONFIGURATION_iterate_sections (kcfg,
&sign_extensions,
NULL);
}
static void
do_work_extensions (char *const *args)
{
struct SubCommand cmds[] = {
{
.name = "show",
.help =
"show the extensions in the Taler-config and their configured parameters",
.cb = &do_extensions_show
},
{
.name = "sign",
.help =
"sign the configuration of the extensions and publish it with the exchange",
.cb = &do_extensions_sign
},
{
.name = NULL,
}
};
if (NULL == args[0])
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"You must provide a subcommand: `show` or `sign`.\n");
test_shutdown ();
global_ret = EXIT_INVALIDARGUMENT;
return;
}
nxt = NULL;
for (unsigned int i = 0; NULL != cmds[i].name; i++)
{
if (0 == strcasecmp (cmds[i].name,
args[0]))
{
cmds[i].cb (&args[1]);
return;
}
}
if (0 != strcasecmp ("help",
args[0]))
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Unexpected command `%s'\n",
args[0]);
global_ret = EXIT_INVALIDARGUMENT;
}
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Supported subcommands:\n");
for (unsigned int i = 0; NULL != cmds[i].name; i++)
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"- %s: %s\n",
cmds[i].name,
cmds[i].help);
}
}
static void
work (void *cls)
{
@ -3390,6 +3651,11 @@ work (void *cls)
"upload operation result to exchange (to be performed online!)",
.cb = &do_upload
},
{
.name = "extensions",
.help = "subcommands for extension handling",
.cb = &do_work_extensions
},
/* list terminator */
{
.name = NULL,

View File

@ -28,14 +28,6 @@
#define TALER_EXTENSION_SECTION_PREFIX "exchange-extension-"
enum TALER_Extension_ReturnValue
{
TALER_Extension_OK = 0,
TALER_Extension_ERROR_PARSING = 1,
TALER_Extension_ERROR_INVALID = 2,
TALER_Extension_ERROR_SYS = 3
};
enum TALER_Extension_Type
{
TALER_Extension_AgeRestriction = 0,
@ -109,7 +101,7 @@ TALER_extension_get_by_name (const char *name,
* @param[out] mask Mask representation for age restriction.
* @return Error, if age groups were invalid, OK otherwise.
*/
enum TALER_Extension_ReturnValue
enum GNUNET_GenericReturnValue
TALER_parse_age_group_string (const char *groups,
struct TALER_AgeMask *mask);
@ -133,7 +125,7 @@ TALER_age_mask_to_string (const struct TALER_AgeMask *mask);
* @return Error if extension for age restriction was set but age groups were
* invalid, OK otherwise.
*/
enum TALER_Extension_ReturnValue
enum GNUNET_GenericReturnValue
TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
struct TALER_AgeMask *mask);

View File

@ -831,7 +831,7 @@ decode_keys_json (const json_t *resp_obj,
return GNUNET_SYSERR;
}
if (TALER_Extension_OK !=
if (GNUNET_OK !=
TALER_parse_age_group_string (age_groups,
&key_data->age_mask))
{

View File

@ -77,9 +77,10 @@ WIRE_GATEWAY_URL = "http://localhost:9081/2/"
[bank]
HTTP_PORT = 9081
[exchange-extension-age_restriction]
# Enabled extensions
[exchange-extension-age-restriction]
ENABLED = YES
AGE_RESTRICTION = "8:14:16"
AGE_GROUPS = "8:10:12:14:16:18:21"
# Sections starting with "coin_" specify which denominations
# the exchange should support (and their respective fee structure)

View File

@ -30,12 +30,12 @@
* @return Error if extension for age restriction was set, but age groups were
* invalid, OK otherwise.
*/
enum TALER_Extension_ReturnValue
enum GNUNET_GenericReturnValue
TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
struct TALER_AgeMask *mask)
{
char *groups;
enum TALER_Extension_ReturnValue ret = TALER_Extension_ERROR_SYS;
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
if ((GNUNET_YES != GNUNET_CONFIGURATION_have_value (cfg,
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
@ -46,7 +46,7 @@ TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
{
/* Age restriction is not enabled */
mask->mask = 0;
return TALER_Extension_OK;
return GNUNET_OK;
}
/* Age restriction is enabled, extract age groups */
@ -56,13 +56,13 @@ TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
&groups))
{
/* FIXME: log error? */
return TALER_Extension_ERROR_SYS;
return GNUNET_SYSERR;
}
if (groups == NULL)
{
/* No groups defined in config, return default_age_mask */
mask->mask = TALER_EXTENSION_DEFAULT_AGE_MASK;
return TALER_Extension_OK;
return GNUNET_OK;
}
ret = TALER_parse_age_group_string (groups, mask);
@ -79,59 +79,46 @@ TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
* @param[out] mask Bit representation of the age groups.
* @return Error if string was invalid, OK otherwise.
*/
enum TALER_Extension_ReturnValue
enum GNUNET_GenericReturnValue
TALER_parse_age_group_string (const char *groups,
struct TALER_AgeMask *mask)
{
enum TALER_Extension_ReturnValue ret = TALER_Extension_ERROR_SYS;
char *pos;
const char *end = groups + strlen (groups);
const char *pos = groups;
unsigned int prev = 0;
unsigned int val;
char dummy;
unsigned int val = 0;
while (1)
while (pos < end)
{
pos = strchr (groups, ':');
if (NULL != pos)
char c = *pos++;
if (':' == c)
{
*pos = 0;
}
if (prev >= val)
return GNUNET_SYSERR;
if (1 != sscanf (groups,
"%u%c",
&val,
&dummy))
mask->mask |= 1 << val;
prev = val;
val = 0;
}
else
{
/* Invalid input */
mask->mask = 0;
ret = TALER_Extension_ERROR_PARSING;
break;
}
else if ((0 >= val) || (32 <= val) || (prev >= val))
{
/* Invalid value */
mask->mask = 0;
ret = TALER_Extension_ERROR_INVALID;
break;
}
if ('0'>c || '9'<c)
return GNUNET_SYSERR;
/* Set the corresponding bit in the mask */
mask->mask |= 1 << val;
val = 10 * val + c - '0';
if (NULL == pos)
{
/* We reached the end. Mark zeroth age-group and exit. */
mask->mask |= 1;
ret = TALER_Extension_OK;
break;
if (0>=val || 32<=val)
return GNUNET_SYSERR;
}
prev = val;
*pos = ':';
groups = pos + 1;
}
return ret;
if (0>=val || 32<=val || prev>=val)
return GNUNET_SYSERR;
mask->mask |= 1 << val;
return GNUNET_OK;
}