commit eb5cb1b5d38b270113eec295000534a444e0c54c
parent f33fec0d4a34e539d211579984905f4d129cdf59
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 1 Jun 2026 16:48:04 +0200
DCE
Diffstat:
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',
)
-
-