donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit eb5cb1b5d38b270113eec295000534a444e0c54c
parent f33fec0d4a34e539d211579984905f4d129cdf59
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon,  1 Jun 2026 16:48:04 +0200

DCE

Diffstat:
Dsrc/json/json.c | 788-------------------------------------------------------------------------------
Dsrc/json/json_helper.c | 29-----------------------------
Msrc/json/meson.build | 4+---
3 files changed, 1 insertion(+), 820 deletions(-)

diff --git a/src/json/json.c b/src/json/json.c @@ -1,788 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2024 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 donau/src/json/json.c - * @brief helper functions for JSON processing using libjansson - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "donau_config.h" -#include "donau_json_lib.h" -#include <gnunet/gnunet_util_lib.h> -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> -#include <unistr.h> - - -/** - * Check if @a json contains a 'real' value anywhere. - * - * @param json json to check - * @return true if a real is in it somewhere - */ -static bool -contains_real (const json_t *json) -{ - if (json_is_real (json)) - return true; - if (json_is_object (json)) - { - json_t *member; - const char *name; - - json_object_foreach ((json_t *) json, name, member) - if (contains_real (member)) - return true; - return false; - } - if (json_is_array (json)) - { - json_t *member; - size_t index; - - json_array_foreach ((json_t *) json, index, member) - if (contains_real (member)) - return true; - return false; - } - return false; -} - - -/** - * Dump the @a json to a string and hash it. - * - * @param json value to hash - * @param salt salt value to include when using HKDF, - * NULL to not use any salt and to use SHA512 - * @param[out] hc where to store the hash - * @return #GNUNET_OK on success, - * #GNUNET_NO if @a json was not hash-able - * #GNUNET_SYSERR on failure - */ -static enum GNUNET_GenericReturnValue -dump_and_hash (const json_t *json, - const char *salt, - struct GNUNET_HashCode *hc) -{ - char *wire_enc; - size_t len; - - if (NULL == json) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (contains_real (json)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (NULL == (wire_enc = json_dumps (json, - JSON_ENCODE_ANY - | JSON_COMPACT - | JSON_SORT_KEYS))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - len = TALER_rfc8785encode (&wire_enc); - if (NULL == salt) - { - GNUNET_CRYPTO_hash (wire_enc, - len, - hc); - } - else - { - if (GNUNET_YES != - GNUNET_CRYPTO_hkdf_gnunet (hc, - sizeof (*hc), - salt, - strlen (salt) + 1, - wire_enc, - len)) - { - GNUNET_break (0); - free (wire_enc); - return GNUNET_SYSERR; - } - } - free (wire_enc); - return GNUNET_OK; -} - - -/** - * Replace "forgettable" parts of a JSON object with their salted hash. - * - * @param[in] in some JSON value - * @param[out] out resulting JSON value - * @return #GNUNET_OK on success, - * #GNUNET_NO if @a json was not hash-able - * #GNUNET_SYSERR on failure - */ -static enum GNUNET_GenericReturnValue -forget (const json_t *in, - json_t **out) -{ - if (json_is_real (in)) - { - /* floating point is not allowed! */ - GNUNET_break_op (0); - return GNUNET_NO; - } - if (json_is_array (in)) - { - /* array is a JSON array */ - size_t index; - json_t *value; - json_t *ret; - - ret = json_array (); - if (NULL == ret) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - json_array_foreach (in, index, value) { - enum GNUNET_GenericReturnValue iret; - json_t *t; - - iret = forget (value, - &t); - if (GNUNET_OK != iret) - { - json_decref (ret); - return iret; - } - if (0 != json_array_append_new (ret, - t)) - { - GNUNET_break (0); - json_decref (ret); - return GNUNET_SYSERR; - } - } - *out = ret; - return GNUNET_OK; - } - if (json_is_object (in)) - { - json_t *ret; - const char *key; - json_t *value; - json_t *fg; - json_t *rx; - - fg = json_object_get (in, - "$forgettable"); - rx = json_object_get (in, - "$forgotten"); - if (NULL != rx) - { - rx = json_deep_copy (rx); /* should be shallow - by structure, but - deep copy is safer */ - if (NULL == rx) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - } - ret = json_object (); - if (NULL == ret) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - json_object_foreach ((json_t*) in, key, value) { - json_t *t; - json_t *salt; - enum GNUNET_GenericReturnValue iret; - - if (fg == value) - continue; /* skip! */ - if (rx == value) - continue; /* skip! */ - if ( (NULL != rx) && - (NULL != - json_object_get (rx, - key)) ) - { - (void) json_object_del (ret, - key); - continue; /* already forgotten earlier */ - } - iret = forget (value, - &t); - if (GNUNET_OK != iret) - { - json_decref (ret); - json_decref (rx); - return iret; - } - if ( (NULL != fg) && - (NULL != (salt = json_object_get (fg, - key))) ) - { - /* 't' is to be forgotten! */ - struct GNUNET_HashCode hc; - - if (! json_is_string (salt)) - { - GNUNET_break_op (0); - json_decref (ret); - json_decref (rx); - json_decref (t); - return GNUNET_NO; - } - iret = dump_and_hash (t, - json_string_value (salt), - &hc); - if (GNUNET_OK != iret) - { - json_decref (ret); - json_decref (rx); - json_decref (t); - return iret; - } - json_decref (t); - /* scrub salt */ - if (0 != - json_object_del (fg, - key)) - { - GNUNET_break_op (0); - json_decref (ret); - json_decref (rx); - return GNUNET_NO; - } - if (NULL == rx) - rx = json_object (); - if (NULL == rx) - { - GNUNET_break (0); - json_decref (ret); - return GNUNET_SYSERR; - } - if (0 != - json_object_set_new (rx, - key, - GNUNET_JSON_from_data_auto (&hc))) - { - GNUNET_break (0); - json_decref (ret); - json_decref (rx); - return GNUNET_SYSERR; - } - } - else - { - /* 't' to be used without 'forgetting' */ - if (0 != - json_object_set_new (ret, - key, - t)) - { - GNUNET_break (0); - json_decref (ret); - json_decref (rx); - return GNUNET_SYSERR; - } - } - } /* json_object_foreach */ - if ( (NULL != rx) && - (0 != - json_object_set_new (ret, - "$forgotten", - rx)) ) - { - GNUNET_break (0); - json_decref (ret); - return GNUNET_SYSERR; - } - *out = ret; - return GNUNET_OK; - } - *out = json_incref ((json_t *) in); - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_JSON_contract_hash (const json_t *json, - struct TALER_PrivateContractHashP *hc) -{ - enum GNUNET_GenericReturnValue ret; - json_t *cjson; - json_t *dc; - - dc = json_deep_copy (json); - ret = forget (dc, - &cjson); - json_decref (dc); - if (GNUNET_OK != ret) - return ret; - ret = dump_and_hash (cjson, - NULL, - &hc->hash); - json_decref (cjson); - return ret; -} - - -enum GNUNET_GenericReturnValue -TALER_JSON_contract_mark_forgettable (json_t *json, - const char *field) -{ - json_t *fg; - struct GNUNET_ShortHashCode salt; - - if (! json_is_object (json)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - /* check field name is legal for forgettable field */ - for (const char *f = field; '\0' != *f; f++) - { - char c = *f; - - if ( (c >= 'a') && (c <= 'z') ) - continue; - if ( (c >= 'A') && (c <= 'Z') ) - continue; - if ( (c >= '0') && (c <= '9') ) - continue; - if ('_' == c) - continue; - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (NULL == json_object_get (json, - field)) - { - /* field must exist */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - fg = json_object_get (json, - "$forgettable"); - if (NULL == fg) - { - fg = json_object (); - if (0 != - json_object_set_new (json, - "$forgettable", - fg)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - } - - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - &salt, - sizeof (salt)); - if (0 != - json_object_set_new (fg, - field, - GNUNET_JSON_from_data_auto (&salt))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_JSON_contract_part_forget (json_t *json, - const char *field) -{ - json_t *fg; - const json_t *part; - json_t *fp; - json_t *rx; - struct GNUNET_HashCode hc; - const char *salt; - enum GNUNET_GenericReturnValue ret; - - if (! json_is_object (json)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (NULL == (part = json_object_get (json, - field))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Did not find field `%s' we were asked to forget\n", - field); - return GNUNET_SYSERR; - } - fg = json_object_get (json, - "$forgettable"); - if (NULL == fg) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Did not find '$forgettable' attribute trying to forget field `%s'\n", - field); - return GNUNET_SYSERR; - } - rx = json_object_get (json, - "$forgotten"); - if (NULL == rx) - { - rx = json_object (); - if (0 != - json_object_set_new (json, - "$forgotten", - rx)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - } - if (NULL != - json_object_get (rx, - field)) - { - if (! json_is_null (json_object_get (json, - field))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Field `%s' market as forgotten, but still exists!\n", - field); - return GNUNET_SYSERR; - } - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Already forgot field `%s'\n", - field); - return GNUNET_NO; - } - salt = json_string_value (json_object_get (fg, - field)); - if (NULL == salt) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Did not find required salt to forget field `%s'\n", - field); - return GNUNET_SYSERR; - } - - /* need to recursively forget to compute 'hc' */ - ret = forget (part, - &fp); - if (GNUNET_OK != ret) - return ret; - if (GNUNET_OK != - dump_and_hash (fp, - salt, - &hc)) - { - json_decref (fp); - GNUNET_break (0); - return GNUNET_SYSERR; - } - json_decref (fp); - /* drop salt */ - if (0 != - json_object_del (fg, - field)) - { - json_decref (fp); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - /* remember field as 'forgotten' */ - if (0 != - json_object_set_new (rx, - field, - GNUNET_JSON_from_data_auto (&hc))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - /* finally, set 'forgotten' field to null */ - if (0 != - json_object_del (json, - field)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Parse a json path. - * - * @param obj the object that the path is relative to. - * @param prev the parent of @e obj. - * @param path the path to parse. - * @param cb the callback to call, if we get to the end of @e path. - * @param cb_cls the closure for the callback. - * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed. - */ -static enum GNUNET_GenericReturnValue -parse_path (json_t *obj, - json_t *prev, - const char *path, - TALER_JSON_ExpandPathCallback cb, - void *cb_cls) -{ - char *id = GNUNET_strdup (path); - char *next_id = strchr (id, - '.'); - char *next_path; - char *bracket; - json_t *next_obj = NULL; - char *next_dot; - - GNUNET_assert (NULL != id); /* make stupid compiler happy */ - if (NULL == next_id) - { - cb (cb_cls, - id, - prev); - GNUNET_free (id); - return GNUNET_OK; - } - bracket = strchr (next_id, - '['); - *next_id = '\0'; - next_id++; - next_path = GNUNET_strdup (next_id); - next_dot = strchr (next_id, - '.'); - if (NULL != next_dot) - *next_dot = '\0'; - /* If this is the first time this is called, make sure id is "$" */ - if ( (NULL == prev) && - (0 != strcmp (id, - "$"))) - { - GNUNET_free (id); - GNUNET_free (next_path); - return GNUNET_SYSERR; - } - - /* Check for bracketed indices */ - if (NULL != bracket) - { - json_t *array; - char *end_bracket = strchr (bracket, - ']'); - if (NULL == end_bracket) - { - GNUNET_free (id); - GNUNET_free (next_path); - return GNUNET_SYSERR; - } - *end_bracket = '\0'; - - *bracket = '\0'; - bracket++; - - array = json_object_get (obj, - next_id); - if (0 == strcmp (bracket, - "*")) - { - size_t index; - json_t *value; - int ret = GNUNET_OK; - - json_array_foreach (array, index, value) { - ret = parse_path (value, - obj, - next_path, - cb, - cb_cls); - if (GNUNET_OK != ret) - { - GNUNET_free (id); - GNUNET_free (next_path); - return ret; - } - } - } - else - { - unsigned int index; - char dummy; - - if (1 != sscanf (bracket, - "%u%c", - &index, - &dummy)) - { - GNUNET_free (id); - GNUNET_free (next_path); - return GNUNET_SYSERR; - } - next_obj = json_array_get (array, - index); - } - } - else - { - /* No brackets, so just fetch the object by name */ - next_obj = json_object_get (obj, - next_id); - } - - if (NULL != next_obj) - { - int ret = parse_path (next_obj, - obj, - next_path, - cb, - cb_cls); - GNUNET_free (id); - GNUNET_free (next_path); - return ret; - } - GNUNET_free (id); - GNUNET_free (next_path); - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_JSON_expand_path (json_t *json, - const char *path, - TALER_JSON_ExpandPathCallback cb, - void *cb_cls) -{ - return parse_path (json, - NULL, - path, - cb, - cb_cls); -} - - -enum TALER_ErrorCode -TALER_JSON_get_error_code (const json_t *json) -{ - const json_t *jc; - - if (NULL == json) - return TALER_EC_GENERIC_INVALID_RESPONSE; - jc = json_object_get (json, "code"); - /* The caller already knows that the JSON represents an error, - so we are dealing with a missing error code here. */ - if (NULL == jc) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Expected Taler error code `code' in JSON, but field does not exist!\n"); - return TALER_EC_INVALID; - } - if (json_is_integer (jc)) - return (enum TALER_ErrorCode) (int) json_integer_value (jc); - GNUNET_break_op (0); - return TALER_EC_INVALID; -} - - -const char * -TALER_JSON_get_error_hint (const json_t *json) -{ - const json_t *jc; - - if (NULL == json) - return NULL; - jc = json_object_get (json, - "hint"); - if (NULL == jc) - return NULL; /* no hint, is allowed */ - if (! json_is_string (jc)) - { - /* Hints must be strings */ - GNUNET_break_op (0); - return NULL; - } - return json_string_value (jc); -} - - -enum TALER_ErrorCode -TALER_JSON_get_error_code2 (const void *data, - size_t data_size) -{ - json_t *json; - enum TALER_ErrorCode ec; - json_error_t err; - - json = json_loadb (data, - data_size, - JSON_REJECT_DUPLICATES, - &err); - if (NULL == json) - return TALER_EC_INVALID; - ec = TALER_JSON_get_error_code (json); - json_decref (json); - if (ec == TALER_EC_NONE) - return TALER_EC_INVALID; - return ec; -} - - -void -TALER_deposit_policy_hash (const json_t *policy, - struct TALER_ExtensionPolicyHashP *ech) -{ - GNUNET_assert (GNUNET_OK == - dump_and_hash (policy, - "taler-extensions-policy", - &ech->hash)); -} - - -char * -TALER_JSON_canonicalize (const json_t *input) -{ - char *wire_enc; - - if (NULL == (wire_enc = json_dumps (input, - JSON_ENCODE_ANY - | JSON_COMPACT - | JSON_SORT_KEYS))) - { - GNUNET_break (0); - return NULL; - } - TALER_rfc8785encode (&wire_enc); - return wire_enc; -} - - -enum GNUNET_GenericReturnValue -TALER_JSON_extensions_manifests_hash (const json_t *manifests, - struct TALER_ExtensionManifestsHashP *ech) -{ - return dump_and_hash (manifests, - "taler-extensions-manifests", - &ech->hash); -} - - -/* End of json/json.c */ diff --git a/src/json/json_helper.c b/src/json/json_helper.c @@ -1,29 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2024 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 donau/src/json/json_helper.c - * @brief helper functions to generate specifications to parse - * Taler-specific JSON objects with libgnunetjson - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include <donau_config.h> -#include <gnunet/gnunet_util_lib.h> -#include <taler/taler_util.h> -#include <taler/taler_json_lib.h> - - -/* end of json/json_helper.c */ diff --git a/src/json/meson.build b/src/json/meson.build @@ -1,5 +1,5 @@ # This build file is in the public domain -libdonaujson_src = ['json.c', 'json_helper.c', 'json_pack.c', 'donau_json.c'] +libdonaujson_src = ['json_pack.c', 'donau_json.c'] libdonaujson = library( 'donaujson', @@ -27,5 +27,3 @@ pkg.generate( url: 'https://taler.net', description: 'GNU Taler donau utilities JSON library', ) - -