exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 55b7ddabb83475cc954a0ffa9f141d2b6d0abaf8
parent b00b4468dd51dc1c9b80b6dc687e3dbde744cdf0
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 21 May 2026 22:11:09 +0200

add slug-validation in JSON spec parser"

Diffstat:
Mmeson.build | 2+-
Msrc/include/taler/taler_json_lib.h | 12++++++++++++
Msrc/include/taler/taler_util.h | 24++++++++++++++++++++++++
Msrc/json/json_helper.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/util/util.c | 37+++++++++++++++++++++++++++++++++++++
5 files changed, 121 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build @@ -305,7 +305,7 @@ if not get_option('only-doc') libltversions = [ ['libtalerutil', '12:0:2'], - ['libtalerjson', '6:0:2'], + ['libtalerjson', '7:0:3'], ['libtalerextensions', '0:0:0'], ['libtalercurl', '0:1:0'], ['libtalerpq', '0:1:0'], diff --git a/src/include/taler/taler_json_lib.h b/src/include/taler/taler_json_lib.h @@ -601,6 +601,18 @@ TALER_JSON_spec_web_url (const char *field, /** + * Generate line in parser specification for slugs (URL-safe identifiers). + * + * @param field name of the field + * @param[out] slug string to initialize + * @return corresponding field spec + */ +struct GNUNET_JSON_Specification +TALER_JSON_spec_slug (const char *field, + const char **slug); + + +/** * Generate line in parser specification for full * "payto://" URIs. * diff --git a/src/include/taler/taler_util.h b/src/include/taler/taler_util.h @@ -439,6 +439,30 @@ TALER_is_web_url (const char *url); /** + * Test if the URL is a valid slug (URL-safe string). + * + * Allowed characters: + * - ASCII letters: a-z A-Z + * - Digits: 0-9 + * - Hyphen: - + * - Underscore: _ + * - Period: . + * - Tilde: ~ + * + * Additional restrictions: + * - must not be empty + * - must not be "." or ".." + * - must not contain '/' + * - must not contain percent-encoding '%' + * + * @param slug a string to test if it could be a valid slug + * @return true if @a slug is well-formed + */ +bool +TALER_is_slug (const char *slug); + + +/** * Check if @a lang matches the @a language_pattern, and if so with * which preference. * See also: https://tools.ietf.org/html/rfc7231#section-5.3.1 diff --git a/src/json/json_helper.c b/src/json/json_helper.c @@ -1478,6 +1478,53 @@ TALER_JSON_spec_web_url (const char *field, /** + * Parse given JSON object to slug. + * + * @param cls closure, NULL + * @param root the json object representing data + * @param[out] spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static enum GNUNET_GenericReturnValue +parse_slug (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + const char *str; + + (void) cls; + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! TALER_is_slug (str)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + *(const char **) spec->ptr = str; + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_slug (const char *field, + const char **slug) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_slug, + .field = field, + .ptr = slug + }; + + *slug = NULL; + return ret; +} + + +/** * Parse given JSON object to payto:// URI. * * @param cls closure, NULL diff --git a/src/util/util.c b/src/util/util.c @@ -460,6 +460,43 @@ TALER_words_destroy (char **args) } +bool +TALER_is_slug (const char *slug) +{ + const unsigned char *p; + + if ('\0' == slug[0]) + return false; + + /* Reject special path components */ + if (0 == strcmp (slug, ".") || + 0 == strcmp (slug, "..")) + return false; + + for (p = (const unsigned char *) slug; '\0' != *p; p++) + { + unsigned char c = *p; + + if (isalnum (c)) + continue; + + switch (c) + { + case '-': + case '_': + case '.': + case ':': + /* Note: could also allow '~' in principle, is on safe list! */ + continue; + default: + return false; + } + } + + return true; +} + + #ifdef __APPLE__ char * strchrnul (const char *s,