commit 31c610a7d4cf814b425b4f8e2605c0378a9bc386
parent 76fa63265e0b90a7e10120a7605d8a749b9e6230
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
Date: Sun, 7 Jan 2024 18:07:40 +0100
merge and add some json helpers
Diffstat:
51 files changed, 4820 insertions(+), 492 deletions(-)
diff --git a/doc/.gitignore b/doc/.gitignore
@@ -1,3 +1,4 @@
+*.bak
*.aux
*.dvi
*.log
diff --git a/po/POTFILES.in b/po/POTFILES.in
@@ -1,2 +1,2 @@
# List of source files which contain translatable strings.
-src/util/taler_error_codes.c
+#src/util/taler_error_codes.c
diff --git a/src/donau/Makefile.am b/src/donau/Makefile.am
@@ -27,7 +27,6 @@ donau_httpd_LDADD = \
-lmicrohttpd \
-ltalermhd \
-ltalerutil \
- -ltalertemplating \
-lgnunetcurl \
-lgnunetutil \
-lgnunetjson \
@@ -38,8 +37,12 @@ donau_httpd_LDADD = \
donau_httpd_SOURCES = \
donau-httpd.c donau-httpd.h \
+ donau-httpd_metrics.c donau-httpd_metrics.h \
+ donau-httpd_db.c donau-httpd_db.h \
donau-httpd_keys.c donau-httpd_keys.h \
- donau-httpd_config.c donau-httpd_config.h
+ donau-httpd_config.c donau-httpd_config.h \
+ donau-httpd_get-charities.c donau_httpd_charity.h \
+ donau-httpd_get-charity.c donau-httpd_post-charity.c
# Testcases
diff --git a/src/donau/donau-httpd.c b/src/donau/donau-httpd.c
@@ -35,6 +35,7 @@
#include "donau_util.h"
#include "donau-httpd_config.h"
#include "donau-httpd_keys.h"
+#include "donau-httpd_charity.h"
/**
* Backlog for listen operation on unix domain sockets.
@@ -176,15 +177,15 @@ typedef MHD_RESULT
* @param connection where to send the reply on
* @param details details for the error message, can be NULL
*/
-static MHD_RESULT
-r404 (struct MHD_Connection *connection,
- const char *details)
-{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
- details);
-}
+// static MHD_RESULT
+// r404 (struct MHD_Connection *connection,
+// const char *details)
+// {
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_NOT_FOUND,
+// TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
+// details);
+// }
/**
@@ -387,31 +388,6 @@ proceed_with_handler (struct DH_RequestContext *rc,
/**
- * Handle a GET "/management" request.
- *
- * @param rc request context
- * @param args array of additional options (must be [0] == "keys")
- * @return MHD result code
- */
-static MHD_RESULT
-handle_get_management (struct DH_RequestContext *rc,
- const char *const args[2])
-{
- if ( (NULL != args[0]) &&
- (0 == strcmp (args[0],
- "keys")) &&
- (NULL == args[1]) )
- {
- return DH_keys_management_get_keys_handler (rc->rh,
- rc->connection);
- }
- GNUNET_break_op (0);
- return r404 (rc->connection,
- "/management/*");
-}
-
-
-/**
* Handle incoming HTTP request.
*
* @param cls closure for MHD daemon (unused)
@@ -450,13 +426,25 @@ handle_mhd_request (void *cls,
.method = MHD_HTTP_METHOD_GET,
.handler.get = &DH_handler_config
},
- /* GET management endpoints (we only really have "/management/keys") */
+ /* GET keys endpoints (we only really have "/keys") */
{
- .url = "management",
+ .url = "keys",
.method = MHD_HTTP_METHOD_GET,
- .handler.get = &handle_get_management,
- .nargs = 1
+ .handler.get = &DH_keys_get_handler// ,
+ // .nargs = 1
},
+ /* GET charities */
+ {
+ .url = "charities",
+ .method = MHD_HTTP_METHOD_GET,
+ .handler.get = &DH_handler_charities_get
+ },
+ /**
+ etc
+
+ Add routes here (also make sure to add the
+ corresponding lines in the makefile)
+ */
/* mark end of list */
{
.url = NULL
diff --git a/src/donau/donau-httpd_charity.h b/src/donau/donau-httpd_charity.h
@@ -0,0 +1,66 @@
+/*
+ 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file donau-httpd_charity.h
+ * @brief Handle /charity requests
+ * @author Johannes Casaburi
+ */
+#ifndef DONAU_HTTPD_CHARITY_H
+#define DONAU_HTTPD_CHARITY_H
+
+#include <microhttpd.h>
+#include "donau-httpd.h"
+
+
+/**
+ * Handle a POST "/charity" request.
+ *
+ * @param connection the MHD connection to handle
+ * @param root uploaded JSON data
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_charity_post (
+ struct MHD_Connection *connection,
+ const json_t *root);
+
+
+/**
+ * Handle a GET "/charity" request.
+ *
+ * @param rc request context
+ * @param args GET arguments (should be one)
+ * @return MHD result code
+ */
+MHD_RESULT
+DH_handler_charity_get (
+ struct DH_RequestContext *rc,
+ const char *const args[]);
+
+
+/**
+ * Handle a GET "/charities" request.
+ *
+ * @param rc request context
+ * @param args GET arguments (should be one)
+ * @return MHD result code
+ */
+MHD_RESULT
+DH_handler_charities_get (
+ struct DH_RequestContext *rc,
+ const char *const args[]);
+
+#endif
diff --git a/src/donau/donau-httpd_db.c b/src/donau/donau-httpd_db.c
@@ -26,7 +26,7 @@
#include "taler/taler_mhd_lib.h"
#include "donaudb_lib.h"
#include "donau-httpd_db.h"
-#include "donau-httpd_responses.h"
+// #include "donau-httpd_responses.h"
enum GNUNET_GenericReturnValue
@@ -39,17 +39,17 @@ DH_DB_run_transaction (struct MHD_Connection *connection,
{
if (NULL != mhd_ret)
*mhd_ret = -1; /* set to invalid value, to help detect bugs */
- // if (GNUNET_OK !=
- // DH_plugin->preflight (DH_plugin->cls))
- // {
- // GNUNET_break (0);
- // if (NULL != mhd_ret)
- // *mhd_ret = TALER_MHD_reply_with_error (connection,
- // MHD_HTTP_INTERNAL_SERVER_ERROR,
- // TALER_EC_GENERIC_DB_SETUP_FAILED,
- // NULL);
- // return GNUNET_SYSERR;
- // }
+ if (GNUNET_OK !=
+ DH_plugin->preflight (DH_plugin->cls))
+ {
+ GNUNET_break (0);
+ if (NULL != mhd_ret)
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_SETUP_FAILED,
+ NULL);
+ return GNUNET_SYSERR;
+ }
GNUNET_assert (mt < DH_MT_REQUEST_COUNT);
DH_METRICS_num_requests[mt]++;
for (unsigned int retries = 0;
@@ -58,43 +58,46 @@ DH_DB_run_transaction (struct MHD_Connection *connection,
{
enum GNUNET_DB_QueryStatus qs;
- // if (GNUNET_OK !=
- // DH_plugin->start (DH_plugin->cls,
- // name))
- // {
- // GNUNET_break (0);
- // if (NULL != mhd_ret)
- // *mhd_ret = TALER_MHD_reply_with_error (connection,
- // MHD_HTTP_INTERNAL_SERVER_ERROR,
- // TALER_EC_GENERIC_DB_START_FAILED,
- // NULL);
- // return GNUNET_SYSERR;
- // }
+ if (GNUNET_OK !=
+ DH_plugin->start (DH_plugin->cls,
+ name))
+ {
+ GNUNET_break (0);
+ if (NULL != mhd_ret)
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_START_FAILED,
+ NULL);
+ return GNUNET_SYSERR;
+ }
qs = cb (cb_cls,
connection,
mhd_ret);
- // if (0 > qs)
- // {
- // DH_plugin->rollback (DH_plugin->cls);
- // if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- // return GNUNET_SYSERR;
- // }
- // else
- // {
- // qs = DH_plugin->commit (DH_plugin->cls);
- // if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- // {
- // DH_plugin->rollback (DH_plugin->cls);
- // if (NULL != mhd_ret)
- // *mhd_ret = TALER_MHD_reply_with_error (connection,
- // MHD_HTTP_INTERNAL_SERVER_ERROR,
- // TALER_EC_GENERIC_DB_COMMIT_FAILED,
- // NULL);
- // return GNUNET_SYSERR;
- // }
- // if (0 > qs)
- // DH_plugin->rollback (DH_plugin->cls);
- // }
+ if (0 > qs)
+ {
+ DH_plugin->rollback (DH_plugin->cls);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ return GNUNET_SYSERR;
+ }
+ else
+ {
+ qs = DH_plugin->commit (DH_plugin->cls);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ DH_plugin->rollback (DH_plugin->cls);
+ if (NULL != mhd_ret)
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_COMMIT_FAILED,
+ NULL);
+ return GNUNET_SYSERR;
+ }
+ if (0 > qs)
+ DH_plugin->rollback (DH_plugin->cls);
+ }
+ /* make sure callback did not violate invariants! */
+ GNUNET_assert ( (NULL == mhd_ret) ||
+ (-1 == (int) *mhd_ret) );
if (0 <= qs)
return GNUNET_OK;
DH_METRICS_num_conflict[mt]++;
diff --git a/src/donau/donau-httpd_get-charities.c b/src/donau/donau-httpd_get-charities.c
@@ -0,0 +1,119 @@
+/*
+ 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file donau-httpd_get-charities.c
+ * @brief Return charities
+ * @author Johannes Casaburi
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler/taler_json_lib.h"
+#include "taler/taler_mhd_lib.h"
+#include "taler/taler_signatures.h"
+#include "donau-httpd.h"
+#include "donaudb_plugin.h"
+#include "donau-httpd_charity.h"
+// #include "taler-exchange-httpd_metrics.h"
+
+
+/**
+ * Maximum number of charities we return per request.
+ */
+#define MAX_RECORDS 1024
+
+/**
+ * Return charities information.
+ *
+ * @param cls closure
+ */
+static void
+charities_cb (
+ void *cls,
+ const char *charity_url,
+ const char *charity_name)
+{
+ json_t *charities = cls;
+
+ GNUNET_assert (
+ 0 ==
+ json_array_append (
+ charities,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("url",
+ charity_url),
+ GNUNET_JSON_pack_string ("name",
+ charity_name)
+ )));
+}
+
+
+MHD_RESULT
+DH_handler_charities_get (
+ struct DH_RequestContext *rc,
+ const char *const args[])
+{
+
+ if (NULL != args[1])
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+ args[1]);
+ }
+
+ {
+ json_t *charities;
+ enum GNUNET_DB_QueryStatus qs;
+
+ charities = json_array ();
+ GNUNET_assert (NULL != charities);
+ qs = DH_plugin->get_charities (DH_plugin->cls,
+ &charities_cb,
+ charities);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ json_decref (charities);
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ return TALER_MHD_reply_static (
+ rc->connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_array_steal ("charities",
+ charities));
+ }
+}
+
+
+/* end of donau-httpd_get-charities.c */
diff --git a/src/donau/donau-httpd_get-charity.c b/src/donau/donau-httpd_get-charity.c
@@ -18,7 +18,7 @@
* @brief Return summary information about AML decision
* @author Johannes Casaburi
*/
-#include "platform.h"
+#include "taler/platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <jansson.h>
#include <microhttpd.h>
@@ -26,10 +26,10 @@
#include "taler/taler_json_lib.h"
#include "taler/taler_mhd_lib.h"
#include "taler/taler_signatures.h"
-#include "donau-httpd.h"
#include "donaudb_plugin.h"
-#include "donau-httpd_aml-decision.h"
-#include "donau-httpd_metrics.h"
+#include "donau-httpd_charity.h"
+// #include "donau-httpd.h"
+// #include "donau-httpd_metrics.h"
/**
@@ -70,11 +70,10 @@ DH_handler_charity_get (
bool none = false;
MHD_RESULT result;
- GNUNET_assert (NULL != charity_info);
- qs = DH_plugin->select_charity_info (DH_plugin->cls,
- charity_id,
- &charity_url,
- &charity_name);
+ qs = DH_plugin->get_charity (DH_plugin->cls,
+ charity_id,
+ &charity_url,
+ &charity_name);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -100,9 +99,8 @@ DH_handler_charity_get (
}
result = TALER_MHD_REPLY_JSON_PACK (
- connection,
- http_status,
- TALER_MHD_PACK_EC (ec),
+ rc->connection,
+ MHD_HTTP_OK,
GNUNET_JSON_pack_string ("url",
charity_url),
GNUNET_JSON_pack_string ("name",
diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c
@@ -24,11 +24,9 @@
#include "taler/taler_mhd_lib.h"
#include "donau-httpd.h"
#include "donau-httpd_keys.h"
-// #include "donau-httpd_config.h"
-// #include "donau-httpd_responses.h"
+#include "donau-httpd_config.h"
#include "donaudb_plugin.h"
-
/**
* How many /keys request do we hold in suspension at
* most at any time?
@@ -36,6 +34,224 @@
#define SKR_LIMIT 32
/**
+ * When do we forcefully timeout a /keys request?
+ */
+#define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES
+
+/**
+ * Number of entries in the @e skr_head DLL.
+ */
+static unsigned int skr_size;
+
+/**
+ * Handle to a connection that should be force-resumed
+ * with a hard error due to @a skr_size hitting
+ * #SKR_LIMIT.
+ */
+static struct MHD_Connection *skr_connection;
+
+/**
+ * Entry of /keys requests that are currently suspended because we are
+ * waiting for /keys to become ready.
+ */
+struct SuspendedKeysRequests
+{
+ /**
+ * Kept in a DLL.
+ */
+ struct SuspendedKeysRequests *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct SuspendedKeysRequests *prev;
+
+ /**
+ * The suspended connection.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * When does this request timeout?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+};
+
+/**
+ * Head of DLL of suspended /keys requests.
+ */
+static struct SuspendedKeysRequests *skr_head;
+
+/**
+ * Tail of DLL of suspended /keys requests.
+ */
+static struct SuspendedKeysRequests *skr_tail;
+
+/**
+ * Task to force timeouts on /keys requests.
+ */
+static struct GNUNET_SCHEDULER_Task *keys_tt;
+
+/**
+ * Are we shutting down?
+ */
+static bool terminating;
+
+/**
+ * Function called to forcefully resume suspended keys requests.
+ *
+ * @param cls unused, NULL
+ */
+static void
+keys_timeout_cb (void *cls)
+{
+ struct SuspendedKeysRequests *skr;
+
+ (void) cls;
+ keys_tt = NULL;
+ while (NULL != (skr = skr_head))
+ {
+ if (GNUNET_TIME_absolute_is_future (skr->timeout))
+ break;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Resuming /keys request due to timeout\n");
+ GNUNET_CONTAINER_DLL_remove (skr_head,
+ skr_tail,
+ skr);
+ MHD_resume_connection (skr->connection);
+ TALER_MHD_daemon_trigger ();
+ GNUNET_free (skr);
+ }
+ if (NULL == skr)
+ return;
+ keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
+ &keys_timeout_cb,
+ NULL);
+}
+
+
+/**
+ * Suspend /keys request while we (hopefully) are waiting to be
+ * provisioned with key material.
+ *
+ * @param[in] connection to suspend
+ */
+static MHD_RESULT
+suspend_request (struct MHD_Connection *connection)
+{
+ struct SuspendedKeysRequests *skr;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Suspending /keys request until key material changes\n");
+ if (terminating)
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+ "Exchange terminating");
+ }
+ skr = GNUNET_new (struct SuspendedKeysRequests);
+ skr->connection = connection;
+ MHD_suspend_connection (connection);
+ GNUNET_CONTAINER_DLL_insert (skr_head,
+ skr_tail,
+ skr);
+ skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
+ if (NULL == keys_tt)
+ {
+ keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
+ &keys_timeout_cb,
+ NULL);
+ }
+ skr_size++;
+ if (skr_size > SKR_LIMIT)
+ {
+ skr = skr_tail;
+ GNUNET_CONTAINER_DLL_remove (skr_head,
+ skr_tail,
+ skr);
+ skr_size--;
+ skr_connection = skr->connection;
+ MHD_resume_connection (skr->connection);
+ TALER_MHD_daemon_trigger ();
+ GNUNET_free (skr);
+ }
+ return MHD_YES;
+}
+
+
+/**
+ * Information about a donation unit on offer by the donation unit helper.
+ */
+struct HelperDonationUnit
+{
+
+ /**
+ * When will the helper start to use this key for signing?
+ */
+ struct GNUNET_TIME_Timestamp start_time;
+
+ /**
+ * For how long will the helper allow signing? 0 if
+ * the key was revoked or purged.
+ */
+ struct GNUNET_TIME_Relative validity_duration;
+
+ /**
+ * Hash of the full donation unit key.
+ */
+ struct DONAU_DonationUnitHashP h_donation_unit_pub;
+
+ /**
+ * The (full) public key.
+ */
+ struct DONAU_DonationUnitPublicKey donation_unit_pub;
+
+ /**
+ * Details depend on the @e donation_unit_pub.cipher type.
+ */
+ union
+ {
+
+ /**
+ * Hash of the RSA key.
+ */
+ struct TALER_RsaPubHashP h_rsa;
+
+ /**
+ * Hash of the CS key.
+ */
+ struct TALER_CsPubHashP h_cs;
+
+ } h_details;
+
+ /**
+ * Name in configuration section for this donation unit type.
+ */
+ char *section_name;
+
+
+};
+
+/**
+ * Information about a signing key on offer by the sign helper.
+ */
+struct HelperSignkey
+{
+ /**
+ * When will the helper start to use this key for signing?
+ */
+ // struct GNUNET_TIME_Timestamp start_time;
+ int year;
+
+ /**
+ * The public key.
+ */
+ struct DONAU_DonauPublicKeyP donau_pub;
+
+};
+
+/**
* Counter incremented whenever we have a reason to re-build the keys because
* something external changed. See #DH_keys_get_state() and
* #DH_keys_update_states() for uses of this variable.
@@ -45,17 +261,17 @@ static uint64_t key_generation;
/**
* RSA security module public key, all zero if not known.
*/
-static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub;
+// static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub;
/**
* CS security module public key, all zero if not known.
*/
-static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub;
+// static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub;
/**
* EdDSA security module public key, all zero if not known.
*/
-static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
+// static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
/**
@@ -64,13 +280,6 @@ static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
#define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES
/**
- * Obtain the key state if we should NOT run finish_keys_response() because we
- * only need the state for the /management/keys API
- */
-struct DH_KeyStateHandle *
-DH_keys_get_state_for_management_only (void);
-
-/**
* Stores the latest generation of our key state.
*/
static struct DH_KeyStateHandle *key_state;
@@ -98,13 +307,13 @@ struct DH_KeyStateHandle
{
/**
- * Mapping from denomination keys to denomination key issue struct.
+ * Mapping from donation unit keys to donation unit key issue struct.
* Used to lookup the key by hash.
*/
struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
/**
- * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey`
+ * Map from `struct DONAU_DonauPublicKey` to `struct SigningKey`
* entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also
* an EdDSA public key.
*/
@@ -239,23 +448,18 @@ struct HelperState
};
/**
- * Closure for #add_denom_key_cb.
+ * Closure for #add_donation_unit_key_cb.
*/
-struct DenomKeyCtx
+struct DonationUnitKeyCtx
{
/**
- * Heap for sorting active denomination keys by start time.
+ * Heap for sorting active donation unit keys by start time.
*/
struct GNUNET_CONTAINER_Heap *heap;
/**
- * JSON array of revoked denomination keys.
- */
- json_t *recoup;
-
- /**
* What is the minimum key rotation frequency of
- * valid denomination keys?
+ * valid donation unit keys?
*/
struct GNUNET_TIME_Relative min_dk_frequency;
};
@@ -373,7 +577,7 @@ finish_keys_response (struct DH_KeyStateHandle *ksh)
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
json_t *recoup;
struct SignKeyCtx sctx;
- json_t *grouped_denominations = NULL;
+ json_t *grouped_donation_units = NULL;
struct GNUNET_TIME_Timestamp last_cherry_pick_date;
struct GNUNET_CONTAINER_Heap *heap;
struct GNUNET_HashContext *hash_context = NULL;
@@ -389,11 +593,10 @@ finish_keys_response (struct DH_KeyStateHandle *ksh)
GNUNET_assert (NULL != recoup);
heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
{
- struct DenomKeyCtx dkc = {
- .recoup = recoup,
- .heap = heap,
- .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
- };
+ // struct DonationUnitKeyCtx dkc = {
+ // .heap = heap,
+ // .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
+ // };
// GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
// &add_denom_key_cb,
@@ -405,8 +608,8 @@ finish_keys_response (struct DH_KeyStateHandle *ksh)
hash_context = GNUNET_CRYPTO_hash_context_start ();
- grouped_denominations = json_array ();
- GNUNET_assert (NULL != grouped_denominations);
+ grouped_donation_units = json_array ();
+ GNUNET_assert (NULL != grouped_donation_units);
last_cherry_pick_date = GNUNET_TIME_UNIT_ZERO_TS;
@@ -436,14 +639,14 @@ finish_keys_response (struct DH_KeyStateHandle *ksh)
else
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "No denomination keys available. Refusing to generate /keys response.\n");
+ "No donation unit keys available. Refusing to generate /keys response.\n");
GNUNET_CRYPTO_hash_context_abort (hash_context);
}
ret = GNUNET_OK;
-CLEANUP:
- json_decref (grouped_denominations);
+// CLEANUP:
+ json_decref (grouped_donation_units);
json_decref (sctx.signkeys);
json_decref (recoup);
return ret;
@@ -451,17 +654,17 @@ CLEANUP:
/**
- * Free denomination key data.
+ * Free donation unit key data.
*
* @param cls a `struct DH_KeyStateHandle`, unused
- * @param h_donation_unit_pub hash of the denomination public key, unused
+ * @param h_donation_unit_pub hash of the donation unit public key, unused
* @param value a `struct DH_DonationUnitKey` to free
* @return #GNUNET_OK (continue to iterate)
*/
static enum GNUNET_GenericReturnValue
-clear_denomination_cb (void *cls,
- const struct GNUNET_HashCode *h_donation_unit_pub,
- void *value)
+clear_donation_unit_cb (void *cls,
+ const struct GNUNET_HashCode *h_donation_unit_pub,
+ void *value)
{
struct DH_DonationUnitKey *dk = value;
@@ -474,7 +677,7 @@ clear_denomination_cb (void *cls,
/**
- * Free denomination key data.
+ * Free donation unit key data.
*
* @param cls a `struct DH_KeyStateHandle`, unused
* @param pid the online signing key (type-disguised), unused
@@ -594,7 +797,7 @@ destroy_key_state (struct DH_KeyStateHandle *ksh,
// GNUNET_free (gf);
// }
GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
- &clear_denomination_cb,
+ &clear_donation_unit_cb,
ksh);
GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map);
GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
@@ -677,11 +880,11 @@ setup_key_helpers (struct HelperState *hs)
* @return NULL on error (i.e. failed to access database)
*/
static struct DH_KeyStateHandle *
-build_key_state (struct HelperState *hs,
- bool management_only)
+build_key_state (struct HelperState *hs /*,
+ bool management_only*/)
{
struct DH_KeyStateHandle *ksh;
- enum GNUNET_DB_QueryStatus qs;
+ // enum GNUNET_DB_QueryStatus qs;
ksh = GNUNET_new (struct DH_KeyStateHandle);
ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS;
@@ -743,11 +946,11 @@ build_key_state (struct HelperState *hs,
// return NULL;
// }
- if (management_only)
- {
- ksh->management_only = true;
- return ksh;
- }
+ // if (management_only)
+ // {
+ // ksh->management_only = true;
+ // return ksh;
+ // }
if (GNUNET_OK !=
finish_keys_response (ksh))
@@ -781,14 +984,14 @@ DH_keys_update_states ()
static struct DH_KeyStateHandle *
-keys_get_state (bool management_only)
+DH_keys_get_state (/*bool management_only*/)
{
struct DH_KeyStateHandle *old_ksh;
struct DH_KeyStateHandle *ksh;
old_ksh = key_state;
if (NULL == old_ksh)
{
- // ksh = build_key_state (NULL, management_only);
+ ksh = build_key_state (NULL /*, management_only*/);
ksh = NULL;
if (NULL == ksh)
return NULL;
@@ -802,8 +1005,8 @@ keys_get_state (bool management_only)
"Rebuilding /keys, generation upgrade from %llu to %llu\n",
(unsigned long long) old_ksh->key_generation,
(unsigned long long) key_generation);
- ksh = build_key_state (old_ksh->helpers,
- management_only);
+ ksh = build_key_state (old_ksh->helpers /*,
+ management_only*/);
key_state = ksh;
old_ksh->helpers = NULL;
destroy_key_state (old_ksh,
@@ -815,92 +1018,375 @@ keys_get_state (bool management_only)
}
-struct DH_KeyStateHandle *
-DH_keys_get_state_for_management_only (void)
+/**
+ * Closure for #add_future_donation_unit_cb and #add_future_signkey_cb.
+ */
+struct FutureBuilderContext
+{
+ /**
+ * Our key state.
+ */
+ struct DH_KeyStateHandle *ksh;
+
+ /**
+ * Array of donation unit keys.
+ */
+ json_t *donation_units;
+
+ /**
+ * Array of signing keys.
+ */
+ json_t *signkeys;
+
+};
+
+// /**
+// * Function called on all of our current and future donation unit keys
+// * known to the helper process. Filters out those that are current
+// * and adds the remaining donation unit keys (with their configuration
+// * data) to the JSON array.
+// *
+// * @param cls the `struct FutureBuilderContext *`
+// * @param h_donation_unit_pub hash of the donation unit public key
+// * @param value a `struct HelperDenomination`
+// * @return #GNUNET_OK (continue to iterate)
+// */
+// static enum GNUNET_GenericReturnValue
+// add_donation_unitkey_cb (void *cls,
+// const struct GNUNET_HashCode *h_donation_unit_pub,
+// void *value)
+// {
+// struct FutureBuilderContext *fbc = cls;
+// struct HelperDonationUnit *helper_donation_unit = value;
+// struct DH_DonationUnitKey *donation_unit_key;
+// struct DONAUDB_DonationUnitKeyMetaData meta = {0};
+
+// donation_unit_key = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map,
+// h_donation_unit_pub);
+// if (NULL != donation_unit_key)
+// return GNUNET_OK; /* skip: this key is already active! */
+// // if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
+// // return GNUNET_OK; /* this key already expired! */
+
+// GNUNET_assert (
+// 0 ==
+// json_array_append_new (
+// fbc->donation_units,
+// GNUNET_JSON_PACK (
+// TALER_JSON_pack_amount ("value",
+// &meta.value),
+// GNUNET_JSON_pack_uint64 ("year",
+// meta.validity_year),
+// GNUNET_JSON_pack_data_auto ("donation_unit_pub",
+// &helper_donation_unit->donation_unit_pub)
+// // GNUNET_JSON_pack_string ("section_name",
+// // helper_donation_unit->section_name)
+// )));
+// return GNUNET_OK;
+// }
+
+
+// /**
+// * Function called on all of our current and future exchange signing keys
+// * known to the helper process. Filters out those that are current
+// * and adds the remaining signing keys (with their configuration
+// * data) to the JSON array.
+// *
+// * @param cls the `struct FutureBuilderContext *`
+// * @param pid actually the exchange public key (type disguised)
+// * @param value a `struct HelperDenomination`
+// * @return #GNUNET_OK (continue to iterate)
+// */
+// static enum GNUNET_GenericReturnValue
+// add_signkey_cb (void *cls,
+// const struct GNUNET_PeerIdentity *pid,
+// void *value)
+// {
+// struct FutureBuilderContext *fbc = cls;
+// struct HelperSignkey *hsk = value;
+// struct SigningKey *sk;
+// // struct GNUNET_TIME_Timestamp stamp_expire;
+// // struct GNUNET_TIME_Timestamp legal_end;
+
+// sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
+// pid);
+// if (NULL != sk)
+// return GNUNET_OK; /* skip: this key is already active */
+// // if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
+// // return GNUNET_OK; /* this key already expired! */
+// // stamp_expire = GNUNET_TIME_absolute_to_timestamp (
+// // GNUNET_TIME_absolute_add (hsk->start_time.abs_time,
+// // hsk->validity_duration));
+// // legal_end = GNUNET_TIME_absolute_to_timestamp (
+// // GNUNET_TIME_absolute_add (stamp_expire.abs_time,
+// // signkey_legal_duration));
+// GNUNET_assert (0 ==
+// json_array_append_new (
+// fbc->signkeys,
+// GNUNET_JSON_PACK (
+// GNUNET_JSON_pack_data_auto ("key",
+// &hsk->donau_pub),
+// // GNUNET_JSON_pack_timestamp ("stamp_end",
+// // legal_end),
+// GNUNET_JSON_pack_data_auto ("year",
+// &hsk->year)
+// // GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
+// // &hsk->sm_sig)
+// )));
+// return GNUNET_OK;
+// }
+
+
+// MHD_RESULT
+// DH_get_keys_handler (const struct DH_RequestHandler *rh,
+// struct MHD_Connection *connection)
+// {
+// struct DH_KeyStateHandle *ksh;
+// json_t *reply;
+
+// (void) rh;
+// ksh = keys_get_state (true);
+// if (NULL == ksh)
+// {
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_SERVICE_UNAVAILABLE,
+// TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+// "no key state");
+// }
+// sync_key_helpers (ksh->helpers);
+// if (NULL == ksh->management_keys_reply)
+// {
+// struct FutureBuilderContext fbc = {
+// .ksh = ksh,
+// .donation_units = json_array (),
+// .signkeys = json_array ()
+// };
+// if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) &&
+// (GNUNET_is_zero (&donation_unit_cs_sm_pub)) )
+// {
+// /* Either IPC failed, or neither helper had any donation_unit configured. */
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_BAD_GATEWAY,
+// TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
+// NULL);
+// }
+// if (GNUNET_is_zero (&esign_sm_pub))
+// {
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_BAD_GATEWAY,
+// TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
+// NULL);
+// }
+// GNUNET_assert (NULL != fbc.donation_units);
+// GNUNET_assert (NULL != fbc.signkeys);
+// GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->donation_unit_keys,
+// &add_donation_unitkey_cb,
+// &fbc);
+// GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
+// &add_signkey_cb,
+// &fbc);
+// reply = GNUNET_JSON_PACK (
+// GNUNET_JSON_pack_array_steal ("future_donation_units",
+// fbc.donation_units),
+// GNUNET_JSON_pack_array_steal ("future_signkeys",
+// fbc.signkeys),
+// GNUNET_JSON_pack_data_auto ("donation_unit_secmod_public_key",
+// &donation_unit_rsa_sm_pub),
+// GNUNET_JSON_pack_data_auto ("donation_unit_secmod_cs_public_key",
+// &donation_unit_cs_sm_pub),
+// GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
+// &esign_sm_pub));
+// GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+// "Returning GET /keys response:\n");
+// if (NULL == reply)
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_INTERNAL_SERVER_ERROR,
+// TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
+// NULL);
+// GNUNET_assert (NULL == ksh->management_keys_reply);
+// ksh->management_keys_reply = reply;
+// }
+// else
+// {
+// reply = ksh->management_keys_reply;
+// }
+// return TALER_MHD_reply_json (connection,
+// reply,
+// MHD_HTTP_OK);
+// }
+
+/**
+ * Comparator used for a binary search by cherry_pick_date for @a key in the
+ * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
+ *
+ * @param key pointer to a `struct GNUNET_TIME_Timestamp`
+ * @param value pointer to a `struct KeysResponseData` array entry
+ * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
+ */
+static int
+krd_search_comparator (const void *key,
+ const void *value)
+{
+ const struct GNUNET_TIME_Timestamp *kd = key;
+ const struct KeysResponseData *krd = value;
+
+ if (GNUNET_TIME_timestamp_cmp (*kd,
+ >,
+ krd->cherry_pick_date))
+ return -1;
+ if (GNUNET_TIME_timestamp_cmp (*kd,
+ <,
+ krd->cherry_pick_date))
+ return 1;
+ return 0;
+}
+
+
+/**
+ * Callback used to set headers in a response.
+ *
+ * @param cls closure
+ * @param[in,out] resp response to modify
+ */
+typedef void
+(*TEH_RESPONSE_SetHeaders)(void *cls,
+ struct MHD_Response *resp);
+
+
+MHD_RESULT
+DH_RESPONSE_reply_not_modified (
+ struct MHD_Connection *connection,
+ const char *etags,
+ TEH_RESPONSE_SetHeaders cb,
+ void *cb_cls)
{
- return keys_get_state (true);
+ MHD_RESULT ret;
+ struct MHD_Response *resp;
+
+ resp = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ cb (cb_cls,
+ resp);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_ETAG,
+ etags));
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_NOT_MODIFIED,
+ resp);
+ GNUNET_break (MHD_YES == ret);
+ MHD_destroy_response (resp);
+ return ret;
}
MHD_RESULT
-DH_keys_management_get_keys_handler (const struct DH_RequestHandler *rh,
- struct MHD_Connection *connection)
+DH_keys_get_handler (struct DH_RequestContext *rc,
+ const char *const args[])
{
- struct DH_KeyStateHandle *ksh;
- json_t *reply;
+ struct GNUNET_TIME_Timestamp last_issue_date;
+ const char *etag;
+
+ etag = MHD_lookup_connection_value (rc->connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_IF_NONE_MATCH);
+ (void) args;
+ // {
+ // const char *have_cherrypick;
+
+ // have_cherrypick = MHD_lookup_connection_value (rc->connection,
+ // MHD_GET_ARGUMENT_KIND,
+ // "last_issue_date");
+ // if (NULL != have_cherrypick)
+ // {
+ // unsigned long long cherrypickn;
+
+ // if (1 !=
+ // sscanf (have_cherrypick,
+ // "%llu",
+ // &cherrypickn))
+ // {
+ // GNUNET_break_op (0);
+ // return TALER_MHD_reply_with_error (rc->connection,
+ // MHD_HTTP_BAD_REQUEST,
+ // TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ // have_cherrypick);
+ // }
+ // /* The following multiplication may overflow; but this should not really
+ // be a problem, as giving back 'older' data than what the client asks for
+ // (given that the client asks for data in the distant future) is not
+ // problematic */
+ // last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn);
+ // }
+ // else
+ // {
+ // last_issue_date = GNUNET_TIME_UNIT_ZERO_TS;
+ // }
+ // }
- (void) rh;
- // ksh = DH_keys_get_state_for_management_only ();
- ksh = NULL;
- if (NULL == ksh)
- {
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- "no key state");
- }
- sync_key_helpers (ksh->helpers);
- if (NULL == ksh->management_keys_reply)
{
- // struct FutureBuilderContext fbc = {
- // .ksh = ksh,
- // .donation_units = json_array (),
- // .signkeys = json_array ()
- // };
- if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) &&
- (GNUNET_is_zero (&donation_unit_cs_sm_pub)) )
+ struct DH_KeyStateHandle *ksh;
+ const struct KeysResponseData *krd;
+
+ ksh = DH_keys_get_state ();
+ if ( (NULL == ksh) ||
+ (0 == ksh->krd_array_length) )
{
- /* Either IPC failed, or neither helper had any donation_unitinations configured. */
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_GATEWAY,
- TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
- NULL);
+ if ( ( (SKR_LIMIT == skr_size) &&
+ (rc->connection == skr_connection) ) ||
+ DH_suicide)
+ {
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+ DH_suicide
+ ? "server terminating"
+ : "too many connections suspended waiting on /keys");
+ }
+ return suspend_request (rc->connection);
}
- if (GNUNET_is_zero (&esign_sm_pub))
+ krd = bsearch (&last_issue_date,
+ ksh->krd_array,
+ ksh->krd_array_length,
+ sizeof (struct KeysResponseData),
+ &krd_search_comparator);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Filtering /keys by cherry pick date %s found entry %u/%u\n",
+ GNUNET_TIME_timestamp2s (last_issue_date),
+ (unsigned int) (krd - ksh->krd_array),
+ ksh->krd_array_length);
+ if ( (NULL == krd) &&
+ (ksh->krd_array_length > 0) )
{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_GATEWAY,
- TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
- NULL);
+ if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time))
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Client provided invalid cherry picking timestamp %s, returning full response\n",
+ GNUNET_TIME_timestamp2s (last_issue_date));
+ krd = &ksh->krd_array[ksh->krd_array_length - 1];
}
- // GNUNET_assert (NULL != fbc.donation_units);
- // GNUNET_assert (NULL != fbc.signkeys);
- // GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->donation_unit_keys,
- // &add_future_donation_unitkey_cb,
- // &fbc);
- // GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
- // &add_future_signkey_cb,
- // &fbc);
- reply = GNUNET_JSON_PACK (
- // GNUNET_JSON_pack_array_steal ("future_donation_units",
- // fbc.donation_units),
- // GNUNET_JSON_pack_array_steal ("future_signkeys",
- // fbc.signkeys),
- // GNUNET_JSON_pack_data_auto ("master_pub",
- // &DH_master_public_key),
- GNUNET_JSON_pack_data_auto ("donation_unit_secmod_public_key",
- &donation_unit_rsa_sm_pub),
- GNUNET_JSON_pack_data_auto ("donation_unit_secmod_cs_public_key",
- &donation_unit_cs_sm_pub),
- GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
- &esign_sm_pub));
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Returning GET /management/keys response:\n");
- if (NULL == reply)
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
- NULL);
- GNUNET_assert (NULL == ksh->management_keys_reply);
- ksh->management_keys_reply = reply;
- }
- else
- {
- reply = ksh->management_keys_reply;
+ if (NULL == krd)
+ {
+ /* Likely keys not ready *yet*.
+ Wait until they are. */
+ return suspend_request (rc->connection);
+ }
+ if ( (NULL != etag) &&
+ (0 == strcmp (etag,
+ krd->etag)) )
+ return DH_RESPONSE_reply_not_modified (rc->connection,
+ krd->etag,
+ &setup_general_response_headers,
+ ksh);
+
+ return MHD_queue_response (rc->connection,
+ MHD_HTTP_OK,
+ (MHD_YES ==
+ TALER_MHD_can_compress (rc->connection))
+ ? krd->response_compressed
+ : krd->response_uncompressed);
}
- return TALER_MHD_reply_json (connection,
- reply,
- MHD_HTTP_OK);
}
diff --git a/src/donau/donau-httpd_keys.h b/src/donau/donau-httpd_keys.h
@@ -57,16 +57,125 @@ struct DH_DonationUnitKey
};
/**
- * Function to call to handle requests to "/management/keys" by sending
- * back our future key material.
+ * Information needed to create a blind signature.
+ */
+// struct DH_CoinSignData
+// {
+/**
+ * Hash of key to sign with.
+ */
+// const struct TALER_DenominationHashP *h_denom_pub;
+
+/**
+ * Blinded planchet to sign over.
+ */
+// const struct TALER_BlindedPlanchet *bp;
+// };
+
+
+// /**
+// * Request to sign @a csds.
+// *
+// * @param csds array with data to blindly sign (and keys to sign with)
+// * @param csds_length length of @a csds array
+// * @param for_melt true if this is for a melt operation
+// * @param[out] bss array set to the blind signature on success; must be of length @a csds_length
+// * @return #TALER_EC_NONE on success
+// */
+// enum TALER_ErrorCode
+// TEH_keys_denomination_batch_sign (
+// unsigned int csds_length,
+// const struct TEH_CoinSignData csds[static csds_length],
+// bool for_melt,
+// struct TALER_BlindedDenominationSignature bss[static csds_length]);
+
+
+// /**
+// * Information needed to derive the CS r_pub.
+// */
+// struct TEH_CsDeriveData
+// {
+// /**
+// * Hash of key to sign with.
+// */
+// const struct TALER_DenominationHashP *h_denom_pub;
+
+// /**
+// * Nonce to use.
+// */
+// const struct GNUNET_CRYPTO_CsSessionNonce *nonce;
+// };
+
+
+// /**
+// * Request to derive CS @a r_pub using the denomination and nonce from @a cdd.
+// *
+// * @param cdd data to compute @a r_pub from
+// * @param for_melt true if this is for a melt operation
+// * @param[out] r_pub where to write the result
+// * @return #TALER_EC_NONE on success
+// */
+// enum TALER_ErrorCode
+// TEH_keys_denomination_cs_r_pub (
+// const struct TEH_CsDeriveData *cdd,
+// bool for_melt,
+// struct GNUNET_CRYPTO_CSPublicRPairP *r_pub);
+
+// /**
+// * Request to derive a bunch of CS @a r_pubs using the
+// * denominations and nonces from @a cdds.
+// *
+// * @param cdds array to compute @a r_pubs from
+// * @param cdds_length length of the @a cdds array
+// * @param for_melt true if this is for a melt operation
+// * @param[out] r_pubs array where to write the result; must be of length @a cdds_length
+// * @return #TALER_EC_NONE on success
+// */
+// enum TALER_ErrorCode
+// TEH_keys_denomination_cs_batch_r_pub (
+// unsigned int cdds_length,
+// const struct TEH_CsDeriveData cdds[static cdds_length],
+// bool for_melt,
+// struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length]);
+
+
+/**
+ * Fully clean up keys subsystem.
+ */
+void
+TEH_keys_finished (void);
+
+
+/**
+ * Resumes all suspended /keys requests, we may now have key material
+ * (or are shutting down).
*
- * @param rh context of the handler
- * @param connection the MHD connection to handle
+ * @param do_shutdown are we shutting down?
+ */
+void
+TEH_resume_keys_requests (bool do_shutdown);
+
+
+/**
+ * Function to call to handle requests to "/keys" by sending
+ * back our current key material.
+ *
+ * @param rc request context
+ * @param args array of additional options (must be empty for this function)
* @return MHD result code
*/
MHD_RESULT
-DH_keys_management_get_keys_handler (const struct DH_RequestHandler *rh,
- struct MHD_Connection *connection);
+DH_keys_get_handler (struct DH_RequestContext *rc,
+ const char *const args[]);
+
+
+/**
+ * Initialize keys subsystem.
+ *
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+TEH_keys_init (void);
#endif
diff --git a/src/donau/donau-httpd_metrics.c b/src/donau/donau-httpd_metrics.c
@@ -0,0 +1,165 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015-2021 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file donau-httpd_metrics.c
+ * @brief Handle /metrics requests
+ * @author Christian Grothoff
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_json_lib.h>
+#include "taler/taler_dbevents.h"
+// #include "donau-httpd_responses.h"
+#include "donau-httpd_keys.h"
+#include "donau-httpd_metrics.h"
+#include "taler/taler_json_lib.h"
+#include "taler/taler_mhd_lib.h"
+#include <jansson.h>
+
+
+unsigned long long DH_METRICS_num_requests[DH_MT_REQUEST_COUNT];
+
+unsigned long long DH_METRICS_batch_withdraw_num_coins;
+
+unsigned long long DH_METRICS_num_conflict[DH_MT_REQUEST_COUNT];
+
+unsigned long long DH_METRICS_num_signatures[DH_MT_SIGNATURE_COUNT];
+
+unsigned long long DH_METRICS_num_verifications[DH_MT_SIGNATURE_COUNT];
+
+unsigned long long DH_METRICS_num_keyexchanges[DH_MT_KEYX_COUNT];
+
+unsigned long long DH_METRICS_num_success[DH_MT_SUCCESS_COUNT];
+
+
+MHD_RESULT
+DH_handler_metrics (struct DH_RequestContext *rc,
+ const char *const args[])
+{
+ char *reply;
+ struct MHD_Response *resp;
+ MHD_RESULT ret;
+
+ (void) args;
+ GNUNET_asprintf (&reply,
+ "taler_exchange_success_transactions{type=\"%s\"} %llu\n"
+ "taler_exchange_success_transactions{type=\"%s\"} %llu\n"
+ "taler_exchange_success_transactions{type=\"%s\"} %llu\n"
+ "taler_exchange_success_transactions{type=\"%s\"} %llu\n"
+ "taler_exchange_success_transactions{type=\"%s\"} %llu\n"
+ "# HELP taler_exchange_serialization_failures "
+ " number of database serialization errors by type\n"
+ "# TYPE taler_exchange_serialization_failures counter\n"
+ "taler_exchange_serialization_failures{type=\"%s\"} %llu\n"
+ "taler_exchange_serialization_failures{type=\"%s\"} %llu\n"
+ "taler_exchange_serialization_failures{type=\"%s\"} %llu\n"
+ "taler_exchange_serialization_failures{type=\"%s\"} %llu\n"
+ "# HELP taler_exchange_received_requests "
+ " number of received requests by type\n"
+ "# TYPE taler_exchange_received_requests counter\n"
+ "taler_exchange_received_requests{type=\"%s\"} %llu\n"
+ "taler_exchange_received_requests{type=\"%s\"} %llu\n"
+ "taler_exchange_received_requests{type=\"%s\"} %llu\n"
+ "taler_exchange_received_requests{type=\"%s\"} %llu\n"
+ "taler_exchange_idempotent_requests{type=\"%s\"} %llu\n"
+#if NOT_YET_IMPLEMENTED
+ "taler_exchange_idempotent_requests{type=\"%s\"} %llu\n"
+ "taler_exchange_idempotent_requests{type=\"%s\"} %llu\n"
+#endif
+ "taler_exchange_idempotent_requests{type=\"%s\"} %llu\n"
+ "# HELP taler_exchange_num_signatures "
+ " number of signatures created by cipher\n"
+ "# TYPE taler_exchange_num_signatures counter\n"
+ "taler_exchange_num_signatures{type=\"%s\"} %llu\n"
+ "taler_exchange_num_signatures{type=\"%s\"} %llu\n"
+ "taler_exchange_num_signatures{type=\"%s\"} %llu\n"
+ "# HELP taler_exchange_num_signature_verifications "
+ " number of signatures verified by cipher\n"
+ "# TYPE taler_exchange_num_signature_verifications counter\n"
+ "taler_exchange_num_signature_verifications{type=\"%s\"} %llu\n"
+ "taler_exchange_num_signature_verifications{type=\"%s\"} %llu\n"
+ "taler_exchange_num_signature_verifications{type=\"%s\"} %llu\n"
+ "# HELP taler_exchange_num_keyexchanges "
+ " number of key exchanges done by cipher\n"
+ "# TYPE taler_exchange_num_keyexchanges counter\n"
+ "taler_exchange_num_keyexchanges{type=\"%s\"} %llu\n"
+ "# HELP taler_exchange_batch_withdraw_num_coins "
+ " number of coins withdrawn in a batch-withdraw request\n"
+ "# TYPE taler_exchange_batch_withdraw_num_coins counter\n"
+ "taler_exchange_batch_withdraw_num_coins{} %llu\n",
+ "deposit",
+ DH_METRICS_num_success[DH_MT_SUCCESS_DEPOSIT],
+ "withdraw",
+ DH_METRICS_num_success[DH_MT_SUCCESS_WITHDRAW],
+ "batch-withdraw",
+ DH_METRICS_num_success[DH_MT_SUCCESS_BATCH_WITHDRAW],
+ "melt",
+ DH_METRICS_num_success[DH_MT_SUCCESS_MELT],
+ "refresh-reveal",
+ DH_METRICS_num_success[DH_MT_SUCCESS_REFRESH_REVEAL],
+ "other",
+ DH_METRICS_num_conflict[DH_MT_REQUEST_OTHER],
+ "deposit",
+ DH_METRICS_num_conflict[DH_MT_REQUEST_DEPOSIT],
+ "withdraw",
+ DH_METRICS_num_conflict[DH_MT_REQUEST_WITHDRAW],
+ "melt",
+ DH_METRICS_num_conflict[DH_MT_REQUEST_MELT],
+ "other",
+ DH_METRICS_num_requests[DH_MT_REQUEST_OTHER],
+ "deposit",
+ DH_METRICS_num_requests[DH_MT_REQUEST_DEPOSIT],
+ "withdraw",
+ DH_METRICS_num_requests[DH_MT_REQUEST_WITHDRAW],
+ "melt",
+ DH_METRICS_num_requests[DH_MT_REQUEST_MELT],
+ "withdraw",
+ DH_METRICS_num_requests[DH_MT_REQUEST_IDEMPOTENT_WITHDRAW],
+#if NOT_YET_IMPLEMENTED
+ "deposit",
+ DH_METRICS_num_requests[DH_MT_REQUEST_IDEMPOTENT_DEPOSIT],
+ "melt",
+ DH_METRICS_num_requests[DH_MT_REQUEST_IDEMPOTENT_MELT],
+#endif
+ "batch-withdraw",
+ DH_METRICS_num_requests[
+ DH_MT_REQUEST_IDEMPOTENT_BATCH_WITHDRAW],
+ "rsa",
+ DH_METRICS_num_signatures[DH_MT_SIGNATURE_RSA],
+ "cs",
+ DH_METRICS_num_signatures[DH_MT_SIGNATURE_CS],
+ "eddsa",
+ DH_METRICS_num_signatures[DH_MT_SIGNATURE_EDDSA],
+ "rsa",
+ DH_METRICS_num_verifications[DH_MT_SIGNATURE_RSA],
+ "cs",
+ DH_METRICS_num_verifications[DH_MT_SIGNATURE_CS],
+ "eddsa",
+ DH_METRICS_num_verifications[DH_MT_SIGNATURE_EDDSA],
+ "ecdh",
+ DH_METRICS_num_keyexchanges[DH_MT_KEYX_ECDH],
+ DH_METRICS_batch_withdraw_num_coins);
+ resp = MHD_create_response_from_buffer (strlen (reply),
+ reply,
+ MHD_RESPMEM_MUST_FREE);
+ ret = MHD_queue_response (rc->connection,
+ MHD_HTTP_OK,
+ resp);
+ MHD_destroy_response (resp);
+ return ret;
+}
+
+
+/* end of donau-httpd_metrics.c */
diff --git a/src/donau/donau-httpd_metrics.h b/src/donau/donau-httpd_metrics.h
@@ -0,0 +1,136 @@
+/*
+ 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file donau-httpd_metrics.h
+ * @brief Handle /metrics requests
+ * @author Christian Grothoff
+ */
+#ifndef DONAU_HTTPD_METRICS_H
+#define DONAU_HTTPD_METRICS_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "donau-httpd.h"
+
+
+/**
+ * Request types for which we collect metrics.
+ */
+enum DH_MetricTypeRequest
+{
+ DH_MT_REQUEST_OTHER = 0,
+ DH_MT_REQUEST_DEPOSIT = 1,
+ DH_MT_REQUEST_WITHDRAW = 2,
+ DH_MT_REQUEST_AGE_WITHDRAW = 3,
+ DH_MT_REQUEST_MELT = 4,
+ DH_MT_REQUEST_PURSE_CREATE = 5,
+ DH_MT_REQUEST_PURSE_MERGE = 6,
+ DH_MT_REQUEST_RESERVE_PURSE = 7,
+ DH_MT_REQUEST_PURSE_DEPOSIT = 8,
+ DH_MT_REQUEST_IDEMPOTENT_DEPOSIT = 9,
+ DH_MT_REQUEST_IDEMPOTENT_WITHDRAW = 10,
+ DH_MT_REQUEST_IDEMPOTENT_AGE_WITHDRAW = 11,
+ DH_MT_REQUEST_IDEMPOTENT_MELT = 12,
+ DH_MT_REQUEST_IDEMPOTENT_BATCH_WITHDRAW = 13,
+ DH_MT_REQUEST_BATCH_DEPOSIT = 14,
+ DH_MT_REQUEST_POLICY_FULFILLMENT = 15,
+ DH_MT_REQUEST_COUNT = 16 /* MUST BE LAST! */
+};
+
+/**
+ * Success types for which we collect metrics.
+ */
+enum DH_MetricTypeSuccess
+{
+ DH_MT_SUCCESS_DEPOSIT = 0,
+ DH_MT_SUCCESS_WITHDRAW = 1,
+ DH_MT_SUCCESS_AGE_WITHDRAW = 2,
+ DH_MT_SUCCESS_BATCH_WITHDRAW = 3,
+ DH_MT_SUCCESS_MELT = 4,
+ DH_MT_SUCCESS_REFRESH_REVEAL = 5,
+ DH_MT_SUCCESS_AGE_WITHDRAW_REVEAL = 6,
+ DH_MT_SUCCESS_COUNT = 7 /* MUST BE LAST! */
+};
+
+/**
+ * Cipher types for which we collect signature metrics.
+ */
+enum DH_MetricTypeSignature
+{
+ DH_MT_SIGNATURE_RSA = 0,
+ DH_MT_SIGNATURE_CS = 1,
+ DH_MT_SIGNATURE_EDDSA = 2,
+ DH_MT_SIGNATURE_COUNT = 3
+};
+
+/**
+ * Cipher types for which we collect key exchange metrics.
+ */
+enum DH_MetricTypeKeyX
+{
+ DH_MT_KEYX_ECDH = 0,
+ DH_MT_KEYX_COUNT = 1
+};
+
+/**
+ * Number of requests handled of the respective type.
+ */
+extern unsigned long long DH_METRICS_num_requests[DH_MT_REQUEST_COUNT];
+
+/**
+ * Number of successful requests handled of the respective type.
+ */
+extern unsigned long long DH_METRICS_num_success[DH_MT_SUCCESS_COUNT];
+
+/**
+ * Number of coins withdrawn in a batch-withdraw request
+ */
+extern unsigned long long DH_METRICS_batch_withdraw_num_coins;
+
+/**
+ * Number of serialization errors encountered when
+ * handling requests of the respective type.
+ */
+extern unsigned long long DH_METRICS_num_conflict[DH_MT_REQUEST_COUNT];
+
+/**
+ * Number of signatures created by the respective cipher.
+ */
+extern unsigned long long DH_METRICS_num_signatures[DH_MT_SIGNATURE_COUNT];
+
+/**
+ * Number of signatures verified by the respective cipher.
+ */
+extern unsigned long long DH_METRICS_num_verifications[DH_MT_SIGNATURE_COUNT];
+
+/**
+ * Number of key exchanges done with the respective cipher.
+ */
+extern unsigned long long DH_METRICS_num_keyexchanges[DH_MT_KEYX_COUNT];
+
+/**
+ * Handle a "/metrics" request.
+ *
+ * @param rc request context
+ * @param args array of additional options (must be empty for this function)
+ * @return MHD result code
+ */
+MHD_RESULT
+DH_handler_metrics (struct DH_RequestContext *rc,
+ const char *const args[]);
+
+
+#endif
diff --git a/src/donau/donau-httpd_post-charity.c b/src/donau/donau-httpd_post-charity.c
@@ -0,0 +1,151 @@
+/*
+ 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file donau-httpd_post-charity.c
+ * @brief Handle request to insert a charity.
+ * @author Johannes Casaburi
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler/taler_json_lib.h"
+#include "taler/taler_mhd_lib.h"
+#include "taler/taler_signatures.h"
+#include "donaudb_plugin.h"
+#include "donau-httpd_charity.h"
+#include "donau-httpd_db.h"
+#include "donau-httpd_metrics.h"
+
+
+/**
+ * Closure for #insert_charity()
+ */
+struct InsertCharityContext
+{
+ /**
+ * Charity name
+ */
+ const char *charity_name;
+
+ /**
+ * Charity URL
+ */
+ const char *charity_url;
+
+};
+
+
+/**
+ * Function implementing insert charity transaction.
+ *
+ * Runs the transaction logic; IF it returns a non-error code, the
+ * transaction logic MUST NOT queue a MHD response. IF it returns an hard
+ * error, the transaction logic MUST queue a MHD response and set @a mhd_ret.
+ * IF it returns the soft error code, the function MAY be called again to
+ * retry and MUST not queue a MHD response.
+ *
+ * @param cls closure with a `struct InsertCharityContext`
+ * @param connection MHD request which triggered the transaction
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ * if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+insert_charity (void *cls,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret)
+{
+ struct InsertCharityContext *icc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = DH_plugin->insert_charity (DH_plugin->cls,
+ icc->charity_name,
+ icc->charity_url);
+ if (qs <= 0)
+ {
+ if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+ {
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "insert_charity");
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ return qs;
+ }
+
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+}
+
+
+MHD_RESULT
+DH_handler_charity_post (
+ struct MHD_Connection *connection,
+ const json_t *root)
+{
+ struct InsertCharityContext icc;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_array_const ("charity_url",
+ &icc.charity_url),
+ GNUNET_JSON_spec_array_const ("charity_name",
+ &icc.charity_name),
+ GNUNET_JSON_spec_end ()
+ };
+
+ {
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (connection,
+ root,
+ spec);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO; /* hard failure */
+ if (GNUNET_NO == res)
+ {
+ GNUNET_break_op (0);
+ return MHD_YES; /* failure */
+ }
+ }
+
+ {
+ MHD_RESULT mhd_ret;
+
+ if (GNUNET_OK !=
+ DH_DB_run_transaction (connection,
+ "insert_charity",
+ DH_MT_REQUEST_OTHER,
+ &mhd_ret,
+ &insert_charity,
+ &icc))
+ {
+ return mhd_ret;
+ }
+ }
+ return TALER_MHD_reply_static (
+ connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+}
+
+
+/* end of donau-httpd_post-charity.c */
diff --git a/src/donaudb/0002-donation_units.sql b/src/donaudb/0002-donation_units.sql
@@ -16,7 +16,7 @@
CREATE TABLE donation_units
(donation_unit_serial BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,donation_unit_pub_hash BYTEA PRIMARY KEY CHECK (LENGTH(donation_unit_pub_hash)=64)
+ ,donation_unit_hash BYTEA PRIMARY KEY CHECK (LENGTH(donation_unit_hash)=64)
,donation_unit_pub BYTEA NOT NULL
,validity_year INT4 NOT NULL
,donation_unit taler_amount NOT NULL
diff --git a/src/donaudb/0002-donau_charities.sql b/src/donaudb/0002-donau_charities.sql
@@ -16,8 +16,9 @@
CREATE TABLE charities
(charity_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,charity_name TEXT NOT NULL
,charity_pub BYTEA PRIMARY KEY CHECK (LENGTH(donau_pub)=32)
+ ,charity_name TEXT NOT NULL
+ ,charity_url TEXT NOT NULL
,max_per_year taler_amount NOT NULL
,receipts_to_date taler_amount NOT NULL DEFAULT (0,0)
,current_year INT8 NOT NULL
diff --git a/src/donaudb/Makefile.am b/src/donaudb/Makefile.am
@@ -57,8 +57,31 @@ plugin_LTLIBRARIES = \
libtaler_plugin_donaudb_postgres.la
endif
+
libtaler_plugin_donaudb_postgres_la_SOURCES = \
- plugin_donaudb_postgres.c pg_helper.h
+ plugin_donaudb_postgres.c pg_helper.h \
+ pg_preflight.h pg_preflight.c \
+ pg_commit.h pg_commit.c \
+ pg_drop_tables.h pg_drop_tables.c \
+ pg_create_tables.h pg_create_tables.c \
+ pg_event_listen.h pg_event_listen.c \
+ pg_event_listen_cancel.h pg_event_listen_cancel.c \
+ pg_event_notify.h pg_event_notify.c \
+ pg_start.h pg_start.c \
+ pg_rollback.h pg_rollback.c \
+ pg_start_read_committed.h pg_start_read_committed.c \
+ pg_start_read_only.h pg_start_read_only.c \
+ pg_activate_signing_key.c pg_activate_signing_key.h \
+ pg_lookup_signing_key.h pg_lookup_signing_key.c \
+ pg_add_donation_unit_key.c pg_add_donation_unit_key.h \
+ pg_lookup_donation_unit.c pg_lookup_donation_unit.h \
+ pg_get_charities.h pg_get_charities.c \
+ pg_insert_charity.h pg_insert_charity.c \
+ pg_lookup_charity.h pg_lookup_charity.c \
+ pg_insert_history_entry.h pg_insert_history_entry.c \
+ pg_insert_issued_receipt.h pg_insert_issued_receipt.c \
+ pg_insert_submitted_receipt.h pg_insert_submitted_receipt.c
+
libtaler_plugin_donaudb_postgres_la_LIBADD = \
$(LTLIBINTL)
libtaler_plugin_donaudb_postgres_la_LDFLAGS = \
diff --git a/src/donaudb/pg_activate_signing_key.c b/src/donaudb/pg_activate_signing_key.c
@@ -28,7 +28,7 @@
enum GNUNET_DB_QueryStatus
DH_PG_activate_signing_key (
void *cls,
- const struct DONAU_EddsaPublicKeyP *donau_pub,
+ const struct DONAU_DonauPublicKeyP *donau_pub,
const struct DONAUDB_SignkeyMetaData *meta)
{
struct PostgresClosure *pg = cls;
diff --git a/src/donaudb/pg_activate_signing_key.h b/src/donaudb/pg_activate_signing_key.h
@@ -36,7 +36,7 @@
enum GNUNET_DB_QueryStatus
DH_PG_activate_signing_key (
void *cls,
- const struct DONAU_EddsaPublicKeyP *donau_pub,
+ const struct DONAU_DonauPublicKeyP *donau_pub,
const struct DONAUDB_SignkeyMetaData *meta);
#endif
diff --git a/src/donaudb/pg_add_donation_unit_key.c b/src/donaudb/pg_add_donation_unit_key.c
@@ -34,17 +34,18 @@ DH_PG_add_donation_unit_key (
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam iparams[] = {
- GNUNET_PQ_query_param_auto_from_type (&meta->donation_unit_pub_hash),
- TALER_PQ_query_param_donation_unit_pub (donation_unit_pub),
+ GNUNET_PQ_query_param_auto_from_type (&meta->donation_unit_hash),
+ GNUNET_PQ_query_param_auto_from_type (donation_unit_pub),
GNUNET_PQ_query_param_uint64 (&meta->validity_year),
- TALER_PQ_query_param_amount (&meta->value),
+ TALER_PQ_query_param_amount (pg->conn,
+ &meta->value),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"donation_unit_insert",
"INSERT INTO donation_units "
- "(donation_unit_pub_hash"
+ "(donation_unit_hash"
",donation_unit_pub"
",validity_year"
",taler_amount"
diff --git a/src/donaudb/pg_add_donation_unit_key.h b/src/donaudb/pg_add_donation_unit_key.h
@@ -37,5 +37,6 @@ enum GNUNET_DB_QueryStatus
DH_PG_add_donation_unit_key (
void *cls,
const struct DONAU_DonationUnitPublicKey *donation_unit_pub,
- const struct DONAUDB_DonationUnitKeyMetaInfo *meta)
+ const struct DONAUDB_DonationUnitKeyMetaData *meta);
+
#endif
diff --git a/src/donaudb/pg_get_charities.c b/src/donaudb/pg_get_charities.c
@@ -0,0 +1,126 @@
+/*
+ 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 CHARITYABILITY 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 donaudb/pg_get_charities.c
+ * @brief Implementation of the lookup_donation_unit_key function for Postgres
+ * @author Johannes Casaburi
+ */
+#include "taler/platform.h"
+#include "taler/taler_error_codes.h"
+#include "taler/taler_dbevents.h"
+#include "taler/taler_pq_lib.h"
+#include "pg_get_charities.h"
+#include "pg_helper.h"
+
+
+/**
+ * Closure for #get_charities_cb().
+ */
+struct GetCharitiesContext
+{
+ /**
+ * Function to call per result.
+ */
+ DONAUDB_GetCharitiesCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Flag set to #GNUNET_OK as long as everything is fine.
+ */
+ enum GNUNET_GenericReturnValue status;
+
+};
+
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct MissingWireContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+get_charities_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct GetCharitiesContext *ctx = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ char *charity_name;
+ char *charity_url;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("charity_name",
+ &charity_name),
+ GNUNET_PQ_result_spec_string ("charity_url",
+ &charity_url),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->status = GNUNET_SYSERR;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ charity_name,
+ charity_url);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+DH_PG_get_charities (void *cls,
+ DONAUDB_GetCharitiesCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GetCharitiesContext ctx = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .status = GNUNET_OK
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "get_charities",
+ "SELECT"
+ " charity_name"
+ ",charity_url"
+ " FROM charities");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "get_charities",
+ params,
+ &get_charities_cb,
+ &ctx);
+ if (GNUNET_OK != ctx.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/donaudb/pg_get_charities.h b/src/donaudb/pg_get_charities.h
@@ -0,0 +1,39 @@
+/*
+ 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 CHARITYABILITY 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 donaudb/pg_get_charities.h
+ * @brief implementation of the get_charities function for Postgres
+ * @author Johannes Casaburi
+ */
+#ifndef PG_GET_CHARITIES_H
+#define PG_GET_CHARITIES_H
+
+#include "donaudb_plugin.h"
+
+/**
+ * Obtain information about the enabled wire accounts of the exchange.
+ *
+ * @param cls closure
+ * @param cb function to call on each account
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+DH_PG_get_charities (void *cls,
+ DONAUDB_GetCharitiesCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/donaudb/pg_get_donation_unit_info.c b/src/donaudb/pg_get_donation_unit_info.c
@@ -1,67 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2023 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 CHARITYABILITY 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 donaudb/pg_get_donation_unit_info.c
- * @brief Implementation of the get_donation_unit_info function for Postgres
- * @author Johannes Casaburi
- */
-#include "taler/platform.h"
-#include "taler/taler_error_codes.h"
-#include "taler/taler_dbevents.h"
-#include "taler/taler_pq_lib.h"
-#include "pg_get_donation_unit_info.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-DH_PG_get_donation_unit_info (
- void *cls,
- const struct DONAU_DonationUnitHashP *donation_unit_pub_hash,
- struct DONAUDB_DonationUnitKeyMetaData *meta)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("donation_unit_pub",
- &meta->donation_unit_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("value",
- &meta->donation_unit),
- GNUNET_PQ_result_spec_uint32 ("validity_year",
- &meta->validity_year),
- GNUNET_PQ_result_spec_end
- };
-
- PREPARE (pg,
- "donation_unit_get",
- "SELECT"
- ",donation_unit_pub"
- ",validity_year"
- ",value"
- " FROM donation_units"
- " WHERE donation_unit_pub_hash=$1;");
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "donation_unit_get",
- params,
- rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- return qs;
- meta->donation_unit_hash = *donation_unit_pub_hash;
- return qs;
-}
diff --git a/src/donaudb/pg_get_donation_unit_info.h b/src/donaudb/pg_get_donation_unit_info.h
@@ -1,41 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 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 CHARITYABILITY 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 donaudb/pg_get_donation_unit_info.h
- * @brief implementation of the get_donation_unit_info function for Postgres
- * @author Johannes Casaburi
- */
-#ifndef PG_GET_DONATION_UNIT_INFO_H
-#define PG_GET_DONATION_UNIT_INFO_H
-
-#include <taler/taler_util.h>
-#include "taler/taler_json_lib.h"
-#include "donaudb_plugin.h"
-/**
- * Fetch information about a donation unit key.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param donation_unit_pub_hash hash of the public key
- * @param[out] info information with value and other info about the coin
- * @return transaction status code
- */
-enum GNUNET_DB_QueryStatus
-DH_PG_get_donation_unit_info (
- void *cls,
- const struct DONAU_DonationUnitHashP *donation_unit_pub_hash,
- struct DONAUDB_DonationUnitKeyMetaData *meta);
-
-#endif
diff --git a/src/donaudb/pg_helper.h b/src/donaudb/pg_helper.h
@@ -60,6 +60,11 @@ struct PostgresClosure
*/
unsigned long long prep_gen;
+ /**
+ * Name of the current transaction, for debugging.
+ */
+ const char *transaction_name;
+
};
@@ -73,37 +78,37 @@ struct PostgresClosure
* @param sql actual SQL text
*/
#define PREPARE(pg,name,sql) \
- do { \
- static struct { \
- unsigned long long cnt; \
- struct PostgresClosure *pg; \
- } preps[2]; /* 2 ctrs for taler-auditor-sync*/ \
- unsigned int off = 0; \
+ do { \
+ static struct { \
+ unsigned long long cnt; \
+ struct PostgresClosure *pg; \
+ } preps[2]; /* 2 ctrs for taler-auditor-sync*/ \
+ unsigned int off = 0; \
\
- while ( (NULL != preps[off].pg) && \
- (pg != preps[off].pg) && \
- (off < sizeof(preps) / sizeof(*preps)) ) \
- off++; \
- GNUNET_assert (off < \
- sizeof(preps) / sizeof(*preps)); \
- if (preps[off].cnt < pg->prep_gen) \
- { \
- struct GNUNET_PQ_PreparedStatement ps[] = { \
- GNUNET_PQ_make_prepare (name, sql), \
- GNUNET_PQ_PREPARED_STATEMENT_END \
- }; \
+ while ( (NULL != preps[off].pg) && \
+ (pg != preps[off].pg) && \
+ (off < sizeof(preps) / sizeof(*preps)) ) \
+ off++; \
+ GNUNET_assert (off < \
+ sizeof(preps) / sizeof(*preps)); \
+ if (preps[off].cnt < pg->prep_gen) \
+ { \
+ struct GNUNET_PQ_PreparedStatement ps[] = { \
+ GNUNET_PQ_make_prepare (name, sql), \
+ GNUNET_PQ_PREPARED_STATEMENT_END \
+ }; \
\
- if (GNUNET_OK != \
- GNUNET_PQ_prepare_statements (pg->conn, \
- ps)) \
- { \
- GNUNET_break (0); \
- return GNUNET_DB_STATUS_HARD_ERROR; \
- } \
- preps[off].pg = pg; \
- preps[off].cnt = pg->prep_gen; \
- } \
- } while (0)
+ if (GNUNET_OK != \
+ GNUNET_PQ_prepare_statements (pg->conn, \
+ ps)) \
+ { \
+ GNUNET_break (0); \
+ return GNUNET_DB_STATUS_HARD_ERROR; \
+ } \
+ preps[off].pg = pg; \
+ preps[off].cnt = pg->prep_gen; \
+ } \
+ } while (0)
/**
@@ -115,7 +120,7 @@ struct PostgresClosure
*/
#define TALER_PQ_RESULT_SPEC_AMOUNT(field, \
amountp) TALER_PQ_result_spec_amount ( \
- field,pg->currency,amountp)
+ field,pg->currency,amountp)
#endif
diff --git a/src/donaudb/pg_insert_charity.c b/src/donaudb/pg_insert_charity.c
@@ -28,8 +28,9 @@
enum GNUNET_DB_QueryStatus
DH_PG_insert_charity (void *cls,
const struct DONAU_CharityPublicKeyP *charity_pub,
- const char *charity_url,
const char *charity_name,
+ const char *charity_url,
+ struct TALER_Amount *max_per_year,
struct TALER_Amount *receipts_to_date,
uint64_t current_year)
{
@@ -38,7 +39,10 @@ DH_PG_insert_charity (void *cls,
GNUNET_PQ_query_param_auto_from_type (charity_pub),
GNUNET_PQ_query_param_string (charity_name),
GNUNET_PQ_query_param_string (charity_url),
- TALER_PQ_query_param_amount (receipts_to_date),
+ TALER_PQ_query_param_amount (pg->conn,
+ max_per_year),
+ TALER_PQ_query_param_amount (pg->conn,
+ receipts_to_date),
GNUNET_PQ_query_param_uint64 (¤t_year),
GNUNET_PQ_query_param_end
};
@@ -49,10 +53,11 @@ DH_PG_insert_charity (void *cls,
"(charity_pub"
",charity_name"
",charity_url"
+ ",max_per_year"
",receipts_to_date"
",current_year"
") VALUES "
- "($1, $2, $3, $4, $5);");
+ "($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_charity",
params);
diff --git a/src/donaudb/pg_insert_charity.h b/src/donaudb/pg_insert_charity.h
@@ -32,6 +32,7 @@
* @param charity_pub charity public key
* @param charity_name name
* @param charity_url url
+ * @param max_per_year yearly donation limit
* @param receipts_to_date current amount of donations in the current year
* @param current_year current year
* @return transaction status code
@@ -39,9 +40,10 @@
enum GNUNET_DB_QueryStatus
DH_PG_insert_charity (
void *cls,
- const struct DONAU_CharityPublicKey *charity_pub,
+ const struct DONAU_CharityPublicKeyP *charity_pub,
const char *charity_name,
const char *charity_url,
+ struct TALER_Amount *max_per_year,
struct TALER_Amount *receipts_to_date,
uint64_t current_year);
diff --git a/src/donaudb/pg_insert_history_entry.c b/src/donaudb/pg_insert_history_entry.c
@@ -34,7 +34,8 @@ DH_PG_insert_history_entry (void *cls,
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (charity_id),
- GNUNET_PQ_query_param_amount (final_amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ final_amount),
GNUNET_PQ_query_param_uint64 (donation_year),
GNUNET_PQ_query_param_end
};
diff --git a/src/donaudb/pg_insert_issued_receipt.c b/src/donaudb/pg_insert_issued_receipt.c
@@ -24,12 +24,13 @@
#include "taler/taler_pq_lib.h"
#include "pg_insert_issued_receipt.h"
#include "pg_helper.h"
+#include "donau_service.h"
enum GNUNET_DB_QueryStatus
DH_PG_insert_issued_receipt (void *cls,
const struct DONAU_CharitySignatureP *charity_sig,
const uint64_t charity_id,
- const struct DONAU_DonationReceiptHashP h_receipt,
+ const struct DONAU_DonationReceiptHashP *h_receipt,
const struct TALER_Amount *amount)
{
struct PostgresClosure *pg = cls;
@@ -37,7 +38,8 @@ DH_PG_insert_issued_receipt (void *cls,
GNUNET_PQ_query_param_auto_from_type (charity_sig),
GNUNET_PQ_query_param_uint64 (charity_id),
GNUNET_PQ_query_param_auto_from_type (h_receipt),
- GNUNET_PQ_query_param_amount (amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ amount),
GNUNET_PQ_query_param_end
};
diff --git a/src/donaudb/pg_insert_issued_receipt.h b/src/donaudb/pg_insert_issued_receipt.h
@@ -39,8 +39,7 @@ enum GNUNET_DB_QueryStatus
DH_PG_insert_issued_receipt (void *cls,
const struct DONAU_CharitySignatureP *charity_sig,
const uint64_t charity_id,
- const struct
- DONAU_DonationReceiptHashP *h_receipt,
+ const struct DONAU_DonationReceiptHashP *h_receipt,
const struct TALER_Amount *amount);
#endif
diff --git a/src/donaudb/pg_insert_submitted_receipt.c b/src/donaudb/pg_insert_submitted_receipt.c
@@ -24,12 +24,13 @@
#include "taler/taler_pq_lib.h"
#include "pg_insert_submitted_receipt.h"
#include "pg_helper.h"
+#include "donau_service.h"
enum GNUNET_DB_QueryStatus
DH_PG_insert_submitted_receipt (void *cls,
- const struct
- TALER_TaxNumberHashP *h_tax_number,
- const struct TALER_CsNonce *nonce,
+ const struct DONAU_HashDonorTaxId *h_tax_number,
+ const union GNUNET_CRYPTO_BlindSessionNonce *
+ nonce,
const struct
DONAU_DonationUnitPublicKey *donation_unit_pub,
const struct TALER_DonauSignatureP *donau_sig,
diff --git a/src/donaudb/pg_insert_submitted_receipt.h b/src/donaudb/pg_insert_submitted_receipt.h
@@ -24,6 +24,7 @@
#include <taler/taler_util.h>
#include "taler/taler_json_lib.h"
#include "donaudb_plugin.h"
+#include "donau_service.h"
/**
* Insert submitted donation receipt from the donor.
@@ -38,9 +39,9 @@
*/
enum GNUNET_DB_QueryStatus
DH_PG_insert_submitted_receipt (void *cls,
- const struct
- TALER_TaxNumberHashP *h_tax_number,
- const struct TALER_CsNonce *nonce,
+ const struct DONAU_HashDonorTaxId *h_tax_number,
+ const union GNUNET_CRYPTO_BlindSessionNonce *
+ nonce,
const struct
DONAU_DonationUnitPublicKey *donation_unit_pub,
const struct TALER_DonauSignatureP *donau_sig,
diff --git a/src/donaudb/pg_lookup_charity.c b/src/donaudb/pg_lookup_charity.c
@@ -28,7 +28,8 @@
enum GNUNET_DB_QueryStatus
DH_PG_lookup_charity (
void *cls,
- struct DONAUDB_CharityMetaData *meta)
+ unsigned long long charity_id,
+ const struct DONAUDB_CharityMetaData *meta)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -36,9 +37,9 @@ DH_PG_lookup_charity (
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_query_param_string ("charity_url",
- &meta->charity_url),
- GNUNET_PQ_query_param_string ("charity_name",
+ GNUNET_PQ_result_spec_string ("charity_url",
+ &meta->charity_url),
+ GNUNET_PQ_result_spec_string ("charity_name",
&meta->charity_name),
GNUNET_PQ_result_spec_end
};
diff --git a/src/donaudb/pg_lookup_charity.h b/src/donaudb/pg_lookup_charity.h
@@ -28,13 +28,13 @@
* Fetch information about a donation unit key.
*
* @param cls the @e cls of this struct with the plugin-specific state
- * @param donation_unit_pub_hash hash of the public key
* @param[out] info information with value and other info about the coin
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
DH_PG_lookup_charity (
void *cls,
- struct DONAUDB_CharityMetaData *meta);
+ unsigned long long charity_id,
+ const struct DONAUDB_CharityMetaData *meta);
#endif
diff --git a/src/donaudb/pg_lookup_donation_unit.c b/src/donaudb/pg_lookup_donation_unit.c
@@ -0,0 +1,58 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 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 CHARITYABILITY 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 donaudb/pg_lookup_donation_unit_key.c
+ * @brief Implementation of the lookup_donation_unit_key function for Postgres
+ * @author Johannes Casaburi
+ */
+#include "taler/platform.h"
+#include "taler/taler_error_codes.h"
+#include "taler/taler_dbevents.h"
+#include "taler/taler_pq_lib.h"
+#include "pg_lookup_donation_unit.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+DH_PG_lookup_donation_unit_key (
+ void *cls,
+ const struct DONAU_DonationUnitHashP *h_donation_unit_pub,
+ struct DONAUDB_DonationUnitKeyMetaData *meta)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_donation_unit_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("validity_year",
+ &meta->validity_year),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+ &meta->value),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE (pg,
+ "lookup_donation_unit_key",
+ "SELECT"
+ " validity_year"
+ ",amount"
+ " FROM donation_units"
+ " WHERE donation_unit_hash=$1;");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_donation_unit_key",
+ params,
+ rs);
+}
diff --git a/src/donaudb/pg_lookup_donation_unit_key.h b/src/donaudb/pg_lookup_donation_unit.h
diff --git a/src/donaudb/pg_lookup_donation_unit_key.c b/src/donaudb/pg_lookup_donation_unit_key.c
@@ -1,61 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2023 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 CHARITYABILITY 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 donaudb/pg_lookup_donation_unit_key.c
- * @brief Implementation of the lookup_donation_unit_key function for Postgres
- * @author Johannes Casaburi
- */
-#include "taler/platform.h"
-#include "taler/taler_error_codes.h"
-#include "taler/taler_dbevents.h"
-#include "taler/taler_pq_lib.h"
-#include "pg_lookup_donation_unit_key.h"
-#include "pg_helper.h"
-
-enum GNUNET_DB_QueryStatus
-DH_PG_lookup_donation_unit_key (
- void *cls,
- const struct DONAU_DonationUnitHashP *h_donation_unit_pub,
- struct DONAUDB_DonationUnitKeyMetaData *meta)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_donation_unit_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("donation_unit_pub",
- &meta->donation_unit_pub),
- GNUNET_PQ_query_param_uint64 ("validity_year",
- &meta->validity_year),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &meta->value),
- GNUNET_PQ_result_spec_end
- };
-
- PREPARE (pg,
- "lookup_donation_unit_key",
- "SELECT"
- ",donation_unit_pub"
- " validity_year"
- ",amount"
- " FROM donation_units"
- " WHERE donation_unit_pub_hash=$1;");
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_donation_unit_key",
- params,
- rs);
-}
diff --git a/src/donaudb/pg_lookup_signing_key.c b/src/donaudb/pg_lookup_signing_key.c
@@ -29,7 +29,7 @@
enum GNUNET_DB_QueryStatus
DH_PG_lookup_signing_key (
void *cls,
- const struct DONAU_EddsaPublicKeyP *donau_pub,
+ const struct DONAU_DonauPublicKeyP *donau_pub,
struct DONAUDB_SignkeyMetaData *meta)
{
struct PostgresClosure *pg = cls;
diff --git a/src/donaudb/pg_lookup_signing_key.h b/src/donaudb/pg_lookup_signing_key.h
@@ -37,7 +37,7 @@
enum GNUNET_DB_QueryStatus
DH_PG_lookup_signing_key (
void *cls,
- const struct DONAU_EddsaPublicKeyP *donau_pub,
+ const struct DONAU_DonauPublicKeyP *donau_pub,
struct DONAUDB_SignkeyMetaData *meta);
#endif
diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h
@@ -31,6 +31,7 @@
#include <gnunet/gnunet_util_lib.h>
#include "taler/taler_error_codes.h"
+#include "taler/taler_util.h"
#include <gcrypt.h>
#include <jansson.h>
@@ -118,6 +119,7 @@ struct DONAU_DonationUnitHashP
};
/**
+<<<<<<< HEAD
* Compare two donation unit public keys.
*
* @param donation_unit1 first key
@@ -148,6 +150,18 @@ void
DONAU_donation_unit_pub_free (struct DONAU_DonationUnitPublicKey *donation_unit_pub);
/**
+ * Hash used to represent a Donation Receipt
+ */
+struct DONAU_DonationReceiptHashP
+{
+ /**
+ * Actual hash value.
+ */
+ struct GNUNET_HashCode hash;
+};
+
+
+/**
* Donor's hashed and salted unique donation identifier.
*/
struct DONAU_HashDonorTaxId
diff --git a/src/include/donau_json_lib.h b/src/include/donau_json_lib.h
@@ -0,0 +1,43 @@
+/*
+ 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 include/donau_json_lib.h
+ * @brief helper functions for JSON processing using libjansson
+ * @author Lukas Matyja
+ */
+#ifndef TALER_JSON_LIB_H_
+#define TALER_JSON_LIB_H_
+
+#include <jansson.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler/taler_util.h"
+#include "taler/taler_error_codes.h"
+
+/**
+ * Generate a parser specification for a donation unit public key of a given
+ * cipher.
+ *
+ * @param field name of the field
+ * @param cipher which cipher type to parse for
+ * @param[out] pk key to fill
+ * @return corresponding field spec
+ */
+struct GNUNET_JSON_Specification
+DONAU_JSON_spec_donation_unit_pub_cipher (
+ const char *field,
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
+ struct DONAU_DonationUnitPublicKey *pk);
+\ No newline at end of file
diff --git a/src/include/donau_service.h b/src/include/donau_service.h
@@ -42,7 +42,7 @@ struct DONAU_SigningPublicKeyAndValidity
/**
* The signing public key
*/
- struct DONAU_EddsaPublicKeyP key;
+ struct DONAU_DonauPublicKeyP key;
/**
* Tax year this key is valid for.
@@ -316,7 +316,7 @@ struct DONAU_GetKeysHandle *
DONAU_get_keys (
struct GNUNET_CURL_Context *ctx,
const char *url,
- //struct DONAU_Keys *last_keys, -> temporarily removed
+ // struct DONAU_Keys *last_keys, -> temporarily removed
DONAU_GetKeysCallback cert_cb,
void *cert_cb_cls);
@@ -373,7 +373,7 @@ DONAU_keys_decref (struct DONAU_Keys *keys);
/**
* Test if the given @a pub is a current signing key from the donau
- * according to @a keys.
+ * according to @a keys. (-> // always current, revocation not yet supported)
*
* @param keys the donau's key set
* @param pub claimed online signing key for the donau
@@ -381,10 +381,10 @@ DONAU_keys_decref (struct DONAU_Keys *keys);
* @return #GNUNET_OK if @a pub is (according to /keys and @a year) the corresponding signing key
*/
// enum GNUNET_GenericReturnValue
-// DONAU_test_signing_key ( // always current revocation not yet supported
+// DONAU_test_signing_key (
// const struct DONAU_Keys *keys,
// const unsigned int year,
-// const struct DONAU_EddsaPublicKeyP *pub);
+// const struct DONAU_DonauPublicKeyP *pub);
/**
@@ -426,7 +426,7 @@ DONAU_get_donation_unit_key_by_hash (
const struct DONAU_SigningPublicKeyAndValidity *
DONAU_get_signing_key_info (
const struct DONAU_Keys *keys,
- const struct DONAU_EddsaPublicKeyP *donau_pub);
+ const struct DONAU_DonauPublicKeyP *donau_pub);
/* ********************* POST / issue receipt *********************** */
@@ -552,6 +552,18 @@ struct TALER_DonationUnitSignature
};
/**
+ * Donau signature
+ */
+struct TALER_DonauSignatureP
+{
+ /**
+ * The signature
+ */
+ struct TALER_ExchangeSignatureP sig;
+
+};
+
+/**
* Donation Receipt
*/
struct DONAU_DonationReceipt
@@ -1062,7 +1074,7 @@ struct DONAU_CharityRequest
/**
* public key of the charity
*/
- struct DONAU_EddsaPublicKeyP charity_pub;
+ struct DONAU_DonauPublicKeyP charity_pub;
};
/**
diff --git a/src/include/donaudb_plugin.h b/src/include/donaudb_plugin.h
@@ -75,6 +75,39 @@ struct DONAUDB_SignkeyMetaData
};
/**
+ * Meta data about a charity.
+ */
+struct DONAUDB_CharityMetaData
+{
+ /**
+ * Charity public key
+ */
+ const struct DONAU_CharityPublicKeyP *charity_pub;
+
+ /**
+ * Charity name
+ */
+ const char *charity_name;
+
+ /**
+ * Charity url
+ */
+ const char *charity_url;
+
+ /**
+ * Charity yearly donation limit
+ */
+ struct TALER_Amount *max_per_year;
+
+ /**
+ * Charity donations received in the current year
+ */
+ struct TALER_Amount *receipts_to_date;
+
+};
+
+
+/**
* @brief All information about a donation unit key.
*/
struct DONAUDB_DonationUnitKey
@@ -124,6 +157,19 @@ typedef void
/**
+ * Return charities.
+ *
+ * @param cls closure
+ * @param charity_url
+ * @param charity_name
+ */
+typedef void
+(*DONAUDB_GetCharitiesCallback)(
+ void *cls,
+ const char *charity_name,
+ const char *charity_url);
+
+/**
* @brief The plugin API, returned from the plugin's "init" function.
* The argument given to "init" is simply a configuration handle.
*/
@@ -149,7 +195,7 @@ struct DONAUDB_Plugin
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
enum GNUNET_GenericReturnValue
- (*drop_tables)(void *cls);
+ (*drop_tables)(void *cls);
/**
* Create the necessary tables if they are not present
@@ -162,9 +208,9 @@ struct DONAUDB_Plugin
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
enum GNUNET_GenericReturnValue
- (*create_tables)(void *cls,
- bool support_partitions,
- uint32_t num_partitions);
+ (*create_tables)(void *cls,
+ bool support_partitions,
+ uint32_t num_partitions);
/**
@@ -176,8 +222,8 @@ struct DONAUDB_Plugin
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
- (*start)(void *cls,
- const char *name);
+ (*start)(void *cls,
+ const char *name);
/**
@@ -189,8 +235,8 @@ struct DONAUDB_Plugin
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
- (*start_read_committed)(void *cls,
- const char *name);
+ (*start_read_committed)(void *cls,
+ const char *name);
/**
* Start a READ ONLY serializable transaction.
@@ -201,8 +247,8 @@ struct DONAUDB_Plugin
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
- (*start_read_only)(void *cls,
- const char *name);
+ (*start_read_only)(void *cls,
+ const char *name);
/**
@@ -212,7 +258,7 @@ struct DONAUDB_Plugin
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*commit)(void *cls);
+ (*commit)(void *cls);
/**
@@ -226,7 +272,7 @@ struct DONAUDB_Plugin
* #GNUNET_SYSERR on hard errors
*/
enum GNUNET_GenericReturnValue
- (*preflight)(void *cls);
+ (*preflight)(void *cls);
/**
@@ -281,6 +327,50 @@ struct DONAUDB_Plugin
const void *extra,
size_t extra_size);
+ /**
+ * Get charity.
+ *
+ * @param cls closure
+ * @param charity_id
+ * @param charity_url
+ * @param charity_name
+ * @return database transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*get_charity)(
+ void *cls,
+ unsigned long long charity_id,
+ const char *charity_url,
+ const char *charity_name);
+
+/**
+ * Get charities.
+ *
+ * @param cls closure
+ * @param cb callback to invoke on each match
+ * @param cb_cls closure for @a cb
+ * @return database transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*get_charities)(
+ void *cls,
+ DONAUDB_GetCharitiesCallback cb,
+ void *cb_cls);
+
+ /**
+ * Insert Charity
+ *
+ * @param cls closure
+ * @param charity_name
+ * @param charity_url
+ * @return database transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*insert_charity)(
+ void *cls,
+ const char *charity_name,
+ const char *charity_url);
+
};
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
@@ -10,7 +10,10 @@ lib_LTLIBRARIES = \
libtalerjson.la
libtalerjson_la_SOURCES = \
- json.c
+ json.c \
+ json_helper.c \
+ json_pack.c
+
libtalerjson_la_LDFLAGS = \
-version-info 1:0:1 \
-no-undefined
diff --git a/src/json/donau_json.c b/src/json/donau_json.c
@@ -0,0 +1,138 @@
+/*
+ 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 json/donau_json.c
+ * @brief helper functions for JSON processing using libjansson
+ * @author Lukas Matyja
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler/taler_util.h"
+#include "taler/taler_json_lib.h"
+#include <unistr.h>
+#include "donau_json_lib.h"
+#include "donau_util.h"
+
+/**
+ * Parse given JSON object partially into a donation unit public key.
+ *
+ * Depending on the cipher in cls, it parses the corresponding public key type.
+ *
+ * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+ * @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_donation_unit_pub_cipher (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct DONAU_DonationUnitPublicKey *donation_unit_pub = spec->ptr;
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
+ (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
+ struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+ const char *emsg;
+ unsigned int eline;
+
+ bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+ bsign_pub->cipher = cipher;
+ bsign_pub->rc = 1;
+ switch (cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_public_key (
+ "rsa_pub",
+ &bsign_pub->details.rsa_public_key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ donation_unit_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed ("cs_pub",
+ &bsign_pub->details.cs_public_key,
+ sizeof (bsign_pub->details.cs_public_key)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ donation_unit_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+}
+
+/**
+ * Cleanup data left from parsing donation unit public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_donation_unit_pub (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct DONAU_DonationUnitPublicKey *donation_unit_pub = spec->ptr;
+
+ (void) cls;
+ DONAU_donation_unit_pub_free (donation_unit_pub);
+}
+
+struct GNUNET_JSON_Specification
+DONAU_JSON_spec_donation_unit_pub_cipher (const char *field,
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
+ struct DONAU_DonationUnitPublicKey *pk)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_donation_unit_pub_cipher,
+ .cleaner = &clean_donation_unit_pub,
+ .field = field,
+ .cls = (void *) cipher,
+ .ptr = pk
+ };
+
+ return ret;
+}
+\ No newline at end of file
diff --git a/src/json/json.c b/src/json/json.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2023 Taler Systems SA
+ 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
@@ -21,9 +21,768 @@
*/
#include "taler/platform.h"
#include <gnunet/gnunet_util_lib.h>
-#include <taler/taler_util.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_kdf (hc,
+ sizeof (*hc),
+ salt,
+ strlen (salt) + 1,
+ wire_enc,
+ len,
+ NULL,
+ 0))
+ {
+ 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)
+ {
+ 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++;
+
+ json_t *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) 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
@@ -0,0 +1,1621 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-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 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 "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler/taler_util.h"
+#include "taler/taler_json_lib.h"
+
+
+/**
+ * Convert string value to numeric cipher value.
+ *
+ * @param cipher_s input string
+ * @return numeric cipher value
+ */
+static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+string_to_cipher (const char *cipher_s)
+{
+ if ((0 == strcasecmp (cipher_s,
+ "RSA")) ||
+ (0 == strcasecmp (cipher_s,
+ "RSA+age_restricted")))
+ return GNUNET_CRYPTO_BSA_RSA;
+ if ((0 == strcasecmp (cipher_s,
+ "CS")) ||
+ (0 == strcasecmp (cipher_s,
+ "CS+age_restricted")))
+ return GNUNET_CRYPTO_BSA_CS;
+ return GNUNET_CRYPTO_BSA_INVALID;
+}
+
+
+json_t *
+TALER_JSON_from_amount (const struct TALER_Amount *amount)
+{
+ char *amount_str = TALER_amount_to_string (amount);
+
+ GNUNET_assert (NULL != amount_str);
+ {
+ json_t *j = json_string (amount_str);
+
+ GNUNET_free (amount_str);
+ return j;
+ }
+}
+
+
+/**
+ * Parse given JSON object to Amount
+ *
+ * @param cls closure, expected currency, or 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_amount (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ const char *currency = cls;
+ struct TALER_Amount *r_amount = spec->ptr;
+
+ (void) cls;
+ if (! json_is_string (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_string_to_amount (json_string_value (root),
+ r_amount))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (NULL != currency) &&
+ (0 !=
+ strcasecmp (currency,
+ r_amount->currency)) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Expected currency `%s', but amount used currency `%s' in field `%s'\n",
+ currency,
+ r_amount->currency,
+ spec->field);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount (const char *name,
+ const char *currency,
+ struct TALER_Amount *r_amount)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_amount,
+ .cleaner = NULL,
+ .cls = (void *) currency,
+ .field = name,
+ .ptr = r_amount,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+
+ GNUNET_assert (NULL != currency);
+ return ret;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount_any (const char *name,
+ struct TALER_Amount *r_amount)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_amount,
+ .cleaner = NULL,
+ .cls = NULL,
+ .field = name,
+ .ptr = r_amount,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to currency spec.
+ *
+ * @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_cspec (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_CurrencySpecification *r_cspec = spec->ptr;
+ const char *currency = spec->cls;
+ const char *name;
+ uint32_t fid;
+ uint32_t fnd;
+ uint32_t ftzd;
+ const json_t *map;
+ struct GNUNET_JSON_Specification gspec[] = {
+ GNUNET_JSON_spec_string ("name",
+ &name),
+ GNUNET_JSON_spec_uint32 ("num_fractional_input_digits",
+ &fid),
+ GNUNET_JSON_spec_uint32 ("num_fractional_normal_digits",
+ &fnd),
+ GNUNET_JSON_spec_uint32 ("num_fractional_trailing_zero_digits",
+ &ftzd),
+ GNUNET_JSON_spec_object_const ("alt_unit_names",
+ &map),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ memset (r_cspec->currency,
+ 0,
+ sizeof (r_cspec->currency));
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ gspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse %s at %u: %s\n",
+ spec[eline].field,
+ eline,
+ emsg);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (strlen (currency) >= TALER_CURRENCY_LEN)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (fid > TALER_AMOUNT_FRAC_LEN) ||
+ (fnd > TALER_AMOUNT_FRAC_LEN) ||
+ (ftzd > TALER_AMOUNT_FRAC_LEN) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_check_currency (currency))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ strcpy (r_cspec->currency,
+ currency);
+ if (GNUNET_OK !=
+ TALER_check_currency_scale_map (map))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ r_cspec->name = GNUNET_strdup (name);
+ r_cspec->map_alt_unit_names = json_incref ((json_t *) map);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing encrypted contract.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_cspec (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_CurrencySpecification *cspec = spec->ptr;
+
+ (void) cls;
+ GNUNET_free (cspec->name);
+ json_decref (cspec->map_alt_unit_names);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_currency_specification (
+ const char *name,
+ const char *currency,
+ struct TALER_CurrencySpecification *r_cspec)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_cspec,
+ .cleaner = &clean_cspec,
+ .cls = (void *) currency,
+ .field = name,
+ .ptr = r_cspec,
+ .ptr_size = sizeof (*r_cspec),
+ .size_ptr = NULL
+ };
+
+ memset (r_cspec,
+ 0,
+ sizeof (*r_cspec));
+ return ret;
+}
+
+
+static enum GNUNET_GenericReturnValue
+parse_denomination_group (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationGroup *group = spec->ptr;
+ const char *cipher;
+ const char *currency = cls;
+ bool age_mask_missing = false;
+ bool has_age_restricted_suffix = false;
+ struct GNUNET_JSON_Specification gspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ TALER_JSON_spec_amount ("value",
+ currency,
+ &group->value),
+ TALER_JSON_SPEC_DENOM_FEES ("fee",
+ currency,
+ &group->fees),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("age_mask",
+ &group->age_mask.bits),
+ &age_mask_missing),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ gspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse %s at %u: %s\n",
+ spec[eline].field,
+ eline,
+ emsg);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ group->cipher = string_to_cipher (cipher);
+ if (GNUNET_CRYPTO_BSA_INVALID == group->cipher)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* age_mask and suffix must be consistent */
+ has_age_restricted_suffix =
+ (NULL != strstr (cipher, "+age_restricted"));
+ if (has_age_restricted_suffix && age_mask_missing)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ if (age_mask_missing)
+ group->age_mask.bits = 0;
+
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denomination_group (const char *name,
+ const char *currency,
+ struct TALER_DenominationGroup *group)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .cls = (void *) currency,
+ .parser = &parse_denomination_group,
+ .field = name,
+ .ptr = group,
+ .ptr_size = sizeof(*group)
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to an encrypted contract.
+ *
+ * @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_econtract (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_EncryptedContract *econtract = spec->ptr;
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_varsize ("econtract",
+ &econtract->econtract,
+ &econtract->econtract_size),
+ GNUNET_JSON_spec_fixed_auto ("econtract_sig",
+ &econtract->econtract_sig),
+ GNUNET_JSON_spec_fixed_auto ("contract_pub",
+ &econtract->contract_pub),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing encrypted contract.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_econtract (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_EncryptedContract *econtract = spec->ptr;
+
+ (void) cls;
+ GNUNET_free (econtract->econtract);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_econtract (const char *name,
+ struct TALER_EncryptedContract *econtract)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_econtract,
+ .cleaner = &clean_econtract,
+ .field = name,
+ .ptr = econtract
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to an age commitmnet
+ *
+ * @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_age_commitment (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_AgeCommitment *age_commitment = spec->ptr;
+ json_t *pk;
+ unsigned int idx;
+ size_t num;
+
+ (void) cls;
+ if ( (NULL == root) ||
+ (! json_is_array (root)))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ num = json_array_size (root);
+ if (32 <= num || 0 == num)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ age_commitment->num = num;
+ age_commitment->keys =
+ GNUNET_new_array (num,
+ struct TALER_AgeCommitmentPublicKeyP);
+
+ json_array_foreach (root, idx, pk) {
+ const char *emsg;
+ unsigned int eline;
+ struct GNUNET_JSON_Specification pkspec[] = {
+ GNUNET_JSON_spec_fixed_auto (
+ NULL,
+ &age_commitment->keys[idx].pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (pk,
+ pkspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ };
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing age commitment
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_age_commitment (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_AgeCommitment *age_commitment = spec->ptr;
+
+ (void) cls;
+
+ if (NULL == age_commitment ||
+ NULL == age_commitment->keys)
+ return;
+
+ age_commitment->num = 0;
+ GNUNET_free (age_commitment->keys);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_age_commitment (const char *name,
+ struct TALER_AgeCommitment *age_commitment)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_age_commitment,
+ .cleaner = &clean_age_commitment,
+ .field = name,
+ .ptr = age_commitment
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to denomination public key.
+ *
+ * @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_denom_pub (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+ struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+ const char *cipher;
+ bool age_mask_missing = false;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("age_mask",
+ &denom_pub->age_mask.bits),
+ &age_mask_missing),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ if (age_mask_missing)
+ denom_pub->age_mask.bits = 0;
+ bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+ bsign_pub->rc = 1;
+ bsign_pub->cipher = string_to_cipher (cipher);
+ switch (bsign_pub->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_public_key (
+ "rsa_public_key",
+ &bsign_pub->details.rsa_public_key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ denom_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed ("cs_public_key",
+ &bsign_pub->details.cs_public_key,
+ sizeof (bsign_pub->details.cs_public_key)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ denom_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_denom_pub (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+
+ (void) cls;
+ TALER_denom_pub_free (denom_pub);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_pub (const char *field,
+ struct TALER_DenominationPublicKey *pk)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_denom_pub,
+ .cleaner = &clean_denom_pub,
+ .field = field,
+ .ptr = pk
+ };
+
+ pk->bsign_pub_key = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object partially into a denomination public key.
+ *
+ * Depending on the cipher in cls, it parses the corresponding public key type.
+ *
+ * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+ * @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_denom_pub_cipher (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
+ (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
+ struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+ const char *emsg;
+ unsigned int eline;
+
+ bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+ bsign_pub->cipher = cipher;
+ bsign_pub->rc = 1;
+ switch (cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_public_key (
+ "rsa_pub",
+ &bsign_pub->details.rsa_public_key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ denom_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed ("cs_pub",
+ &bsign_pub->details.cs_public_key,
+ sizeof (bsign_pub->details.cs_public_key)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ denom_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_pub_cipher (const char *field,
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+ cipher,
+ struct TALER_DenominationPublicKey *pk)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_denom_pub_cipher,
+ .cleaner = &clean_denom_pub,
+ .field = field,
+ .cls = (void *) cipher,
+ .ptr = pk
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to denomination signature.
+ *
+ * @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_denom_sig (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationSignature *denom_sig = spec->ptr;
+ struct GNUNET_CRYPTO_UnblindedSignature *unblinded_sig;
+ const char *cipher;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ unblinded_sig = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
+ unblinded_sig->cipher = string_to_cipher (cipher);
+ unblinded_sig->rc = 1;
+ switch (unblinded_sig->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_signature (
+ "rsa_signature",
+ &unblinded_sig->details.rsa_signature),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (unblinded_sig);
+ return GNUNET_SYSERR;
+ }
+ denom_sig->unblinded_sig = unblinded_sig;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed_auto ("cs_signature_r",
+ &unblinded_sig->details.cs_signature.
+ r_point),
+ GNUNET_JSON_spec_fixed_auto ("cs_signature_s",
+ &unblinded_sig->details.cs_signature.
+ s_scalar),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (unblinded_sig);
+ return GNUNET_SYSERR;
+ }
+ denom_sig->unblinded_sig = unblinded_sig;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (unblinded_sig);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_denom_sig (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationSignature *denom_sig = spec->ptr;
+
+ (void) cls;
+ TALER_denom_sig_free (denom_sig);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_sig (const char *field,
+ struct TALER_DenominationSignature *sig)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_denom_sig,
+ .cleaner = &clean_denom_sig,
+ .field = field,
+ .ptr = sig
+ };
+
+ sig->unblinded_sig = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to blinded denomination signature.
+ *
+ * @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_blinded_denom_sig (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
+ struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
+ const char *cipher;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+ blinded_sig->cipher = string_to_cipher (cipher);
+ blinded_sig->rc = 1;
+ switch (blinded_sig->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_signature (
+ "blinded_rsa_signature",
+ &blinded_sig->details.blinded_rsa_signature),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_sig);
+ return GNUNET_SYSERR;
+ }
+ denom_sig->blinded_sig = blinded_sig;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_uint32 ("b",
+ &blinded_sig->details.blinded_cs_answer.b),
+ GNUNET_JSON_spec_fixed_auto ("s",
+ &blinded_sig->details.blinded_cs_answer.
+ s_scalar),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_sig);
+ return GNUNET_SYSERR;
+ }
+ denom_sig->blinded_sig = blinded_sig;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_sig);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_blinded_denom_sig (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
+
+ (void) cls;
+ TALER_blinded_denom_sig_free (denom_sig);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_blinded_denom_sig (
+ const char *field,
+ struct TALER_BlindedDenominationSignature *sig)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_blinded_denom_sig,
+ .cleaner = &clean_blinded_denom_sig,
+ .field = field,
+ .ptr = sig
+ };
+
+ sig->blinded_sig = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to blinded planchet.
+ *
+ * @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_blinded_planchet (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+ struct GNUNET_CRYPTO_BlindedMessage *blinded_message;
+ const char *cipher;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+ blinded_message->rc = 1;
+ blinded_message->cipher = string_to_cipher (cipher);
+ switch (blinded_message->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_varsize (
+ "rsa_blinded_planchet",
+ &blinded_message->details.rsa_blinded_message.blinded_msg,
+ &blinded_message->details.rsa_blinded_message.blinded_msg_size),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+ }
+ blinded_planchet->blinded_message = blinded_message;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_nonce",
+ &blinded_message->details.cs_blinded_message.nonce),
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_blinded_c0",
+ &blinded_message->details.cs_blinded_message.c[0]),
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_blinded_c1",
+ &blinded_message->details.cs_blinded_message.c[1]),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+ }
+ blinded_planchet->blinded_message = blinded_message;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing blinded planchet.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_blinded_planchet (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+
+ (void) cls;
+ TALER_blinded_planchet_free (blinded_planchet);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_blinded_planchet (const char *field,
+ struct TALER_BlindedPlanchet *blinded_planchet)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_blinded_planchet,
+ .cleaner = &clean_blinded_planchet,
+ .field = field,
+ .ptr = blinded_planchet
+ };
+
+ blinded_planchet->blinded_message = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to exchange withdraw values (/csr).
+ *
+ * @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_exchange_withdraw_values (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_ExchangeWithdrawValues *ewv = spec->ptr;
+ struct GNUNET_CRYPTO_BlindingInputValues *bi;
+ const char *cipher;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ ci = string_to_cipher (cipher);
+ switch (ci)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs;
+ return GNUNET_OK;
+ case GNUNET_CRYPTO_BSA_CS:
+ bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
+ bi->cipher = GNUNET_CRYPTO_BSA_CS;
+ bi->rc = 1;
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed (
+ "r_pub_0",
+ &bi->details.cs_values.r_pub[0],
+ sizeof (struct GNUNET_CRYPTO_CsRPublic)),
+ GNUNET_JSON_spec_fixed (
+ "r_pub_1",
+ &bi->details.cs_values.r_pub[1],
+ sizeof (struct GNUNET_CRYPTO_CsRPublic)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bi);
+ return GNUNET_SYSERR;
+ }
+ ewv->blinding_inputs = bi;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing withdraw values
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_exchange_withdraw_values (
+ void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_ExchangeWithdrawValues *ewv = spec->ptr;
+
+ (void) cls;
+ TALER_denom_ewv_free (ewv);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_exchange_withdraw_values (
+ const char *field,
+ struct TALER_ExchangeWithdrawValues *ewv)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_exchange_withdraw_values,
+ .cleaner = &clean_exchange_withdraw_values,
+ .field = field,
+ .ptr = ewv
+ };
+
+ ewv->blinding_inputs = NULL;
+ return ret;
+}
+
+
+/**
+ * Closure for #parse_i18n_string.
+ */
+struct I18nContext
+{
+ /**
+ * Language pattern to match.
+ */
+ char *lp;
+
+ /**
+ * Name of the field to match.
+ */
+ const char *field;
+};
+
+
+/**
+ * Parse given JSON object to internationalized string.
+ *
+ * @param cls closure, our `struct I18nContext *`
+ * @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_i18n_string (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct I18nContext *ctx = cls;
+ json_t *i18n;
+ json_t *val;
+
+ {
+ char *i18nf;
+
+ GNUNET_asprintf (&i18nf,
+ "%s_i18n",
+ ctx->field);
+ i18n = json_object_get (root,
+ i18nf);
+ GNUNET_free (i18nf);
+ }
+
+ val = json_object_get (root,
+ ctx->field);
+ if ( (NULL != i18n) &&
+ (NULL != ctx->lp) )
+ {
+ double best = 0.0;
+ json_t *pos;
+ const char *lang;
+
+ json_object_foreach (i18n, lang, pos)
+ {
+ double score;
+
+ score = TALER_language_matches (ctx->lp,
+ lang);
+ if (score > best)
+ {
+ best = score;
+ val = pos;
+ }
+ }
+ }
+
+ {
+ const char *str;
+
+ str = json_string_value (val);
+ *(const char **) spec->ptr = str;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to clean up data from earlier parsing.
+ *
+ * @param cls closure
+ * @param spec our specification entry with data to clean.
+ */
+static void
+i18n_cleaner (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct I18nContext *ctx = cls;
+
+ (void) spec;
+ if (NULL != ctx)
+ {
+ GNUNET_free (ctx->lp);
+ GNUNET_free (ctx);
+ }
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_i18n_string (const char *name,
+ const char *language_pattern,
+ const char **strptr)
+{
+ struct I18nContext *ctx = GNUNET_new (struct I18nContext);
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_i18n_string,
+ .cleaner = &i18n_cleaner,
+ .cls = ctx,
+ .field = NULL, /* we want the main object */
+ .ptr = strptr,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+
+ ctx->lp = (NULL != language_pattern)
+ ? GNUNET_strdup (language_pattern)
+ : NULL;
+ ctx->field = name;
+ *strptr = NULL;
+ return ret;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_i18n_str (const char *name,
+ const char **strptr)
+{
+ const char *lang = getenv ("LANG");
+ char *dot;
+ char *l;
+ struct GNUNET_JSON_Specification ret;
+
+ if (NULL != lang)
+ {
+ dot = strchr (lang,
+ '.');
+ if (NULL == dot)
+ l = GNUNET_strdup (lang);
+ else
+ l = GNUNET_strndup (lang,
+ dot - lang);
+ }
+ else
+ {
+ l = NULL;
+ }
+ ret = TALER_JSON_spec_i18n_string (name,
+ l,
+ strptr);
+ GNUNET_free (l);
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object with Taler error code.
+ *
+ * @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_ec (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ enum TALER_ErrorCode *ec = spec->ptr;
+ json_int_t num;
+
+ (void) cls;
+ if (! json_is_integer (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ num = json_integer_value (root);
+ if (num < 0)
+ {
+ GNUNET_break_op (0);
+ *ec = TALER_EC_INVALID;
+ return GNUNET_SYSERR;
+ }
+ *ec = (enum TALER_ErrorCode) num;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_ec (const char *field,
+ enum TALER_ErrorCode *ec)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_ec,
+ .field = field,
+ .ptr = ec
+ };
+
+ *ec = TALER_EC_NONE;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to web URL.
+ *
+ * @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_web_url (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_web_url (str))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ *(const char **) spec->ptr = str;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_web_url (const char *field,
+ const char **url)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_web_url,
+ .field = field,
+ .ptr = url
+ };
+
+ *url = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to payto:// URI.
+ *
+ * @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_payto_uri (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ const char *str;
+ char *err;
+
+ (void) cls;
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ err = TALER_payto_validate (str);
+ if (NULL != err)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (err);
+ return GNUNET_SYSERR;
+ }
+ *(const char **) spec->ptr = str;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_payto_uri (const char *field,
+ const char **payto_uri)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_payto_uri,
+ .field = field,
+ .ptr = payto_uri
+ };
+
+ *payto_uri = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object with protocol version.
+ *
+ * @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_protocol_version (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
+ const char *ver;
+ char dummy;
+
+ (void) cls;
+ if (! json_is_string (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ ver = json_string_value (root);
+ if (3 != sscanf (ver,
+ "%u:%u:%u%c",
+ &pv->current,
+ &pv->revision,
+ &pv->age,
+ &dummy))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_version (const char *field,
+ struct TALER_JSON_ProtocolVersion *ver)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_protocol_version,
+ .field = field,
+ .ptr = ver
+ };
+
+ return ret;
+}
+
+
+/* end of json/json_helper.c */
diff --git a/src/json/json_pack.c b/src/json/json_pack.c
@@ -0,0 +1,324 @@
+/*
+ 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 json/json_pack.c
+ * @brief helper functions for JSON object packing
+ * @author Christian Grothoff
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler/taler_util.h"
+#include "taler/taler_json_lib.h"
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_time_abs_human (const char *name,
+ struct GNUNET_TIME_Absolute at)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ .object = json_string (
+ GNUNET_STRINGS_absolute_time_to_string (at))
+ };
+
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_econtract (
+ const char *name,
+ const struct TALER_EncryptedContract *econtract)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == econtract)
+ return ps;
+ ps.object
+ = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_varsize ("econtract",
+ econtract->econtract,
+ econtract->econtract_size),
+ GNUNET_JSON_pack_data_auto ("econtract_sig",
+ &econtract->econtract_sig),
+ GNUNET_JSON_pack_data_auto ("contract_pub",
+ &econtract->contract_pub));
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_age_commitment (
+ const char *name,
+ const struct TALER_AgeCommitment *age_commitment)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+ json_t *keys;
+
+ if (NULL == age_commitment ||
+ 0 == age_commitment->num)
+ return ps;
+
+ GNUNET_assert (NULL !=
+ (keys = json_array ()));
+
+ for (size_t i = 0;
+ i < age_commitment->num;
+ i++)
+ {
+ json_t *val;
+ val = GNUNET_JSON_from_data (&age_commitment->keys[i],
+ sizeof(age_commitment->keys[i]));
+ GNUNET_assert (NULL != val);
+ GNUNET_assert (0 ==
+ json_array_append_new (keys, val));
+ }
+
+ ps.object = keys;
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_denom_pub (
+ const char *name,
+ const struct TALER_DenominationPublicKey *pk)
+{
+ const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == pk)
+ return ps;
+ bsp = pk->bsign_pub_key;
+ switch (bsp->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object
+ = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_uint64 ("age_mask",
+ pk->age_mask.bits),
+ GNUNET_JSON_pack_rsa_public_key ("rsa_public_key",
+ bsp->details.rsa_public_key));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object
+ = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_uint64 ("age_mask",
+ pk->age_mask.bits),
+ GNUNET_JSON_pack_data_varsize ("cs_public_key",
+ &bsp->details.cs_public_key,
+ sizeof (bsp->details.cs_public_key)));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_denom_sig (
+ const char *name,
+ const struct TALER_DenominationSignature *sig)
+{
+ const struct GNUNET_CRYPTO_UnblindedSignature *bs;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == sig)
+ return ps;
+ bs = sig->unblinded_sig;
+ switch (bs->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_rsa_signature ("rsa_signature",
+ bs->details.rsa_signature));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_data_auto ("cs_signature_r",
+ &bs->details.cs_signature.r_point),
+ GNUNET_JSON_pack_data_auto ("cs_signature_s",
+ &bs->details.cs_signature.s_scalar));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_exchange_withdraw_values (
+ const char *name,
+ const struct TALER_ExchangeWithdrawValues *ewv)
+{
+ const struct GNUNET_CRYPTO_BlindingInputValues *biv;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == ewv)
+ return ps;
+ biv = ewv->blinding_inputs;
+ switch (biv->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_data_varsize (
+ "r_pub_0",
+ &biv->details.cs_values.r_pub[0],
+ sizeof(struct GNUNET_CRYPTO_CsRPublic)),
+ GNUNET_JSON_pack_data_varsize (
+ "r_pub_1",
+ &biv->details.cs_values.r_pub[1],
+ sizeof(struct GNUNET_CRYPTO_CsRPublic))
+ );
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_blinded_denom_sig (
+ const char *name,
+ const struct TALER_BlindedDenominationSignature *sig)
+{
+ const struct GNUNET_CRYPTO_BlindedSignature *bs;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == sig)
+ return ps;
+ bs = sig->blinded_sig;
+ switch (bs->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
+ bs->details.blinded_rsa_signature));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_uint64 ("b",
+ bs->details.blinded_cs_answer.b),
+ GNUNET_JSON_pack_data_auto ("s",
+ &bs->details.blinded_cs_answer.s_scalar));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_blinded_planchet (
+ const char *name,
+ const struct TALER_BlindedPlanchet *blinded_planchet)
+{
+ const struct GNUNET_CRYPTO_BlindedMessage *bm;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == blinded_planchet)
+ return ps;
+ bm = blinded_planchet->blinded_message;
+ switch (bm->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_data_varsize (
+ "rsa_blinded_planchet",
+ bm->details.rsa_blinded_message.blinded_msg,
+ bm->details.rsa_blinded_message.blinded_msg_size));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_data_auto (
+ "cs_nonce",
+ &bm->details.cs_blinded_message.nonce),
+ GNUNET_JSON_pack_data_auto (
+ "cs_blinded_c0",
+ &bm->details.cs_blinded_message.c[0]),
+ GNUNET_JSON_pack_data_auto (
+ "cs_blinded_c1",
+ &bm->details.cs_blinded_message.c[1]));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_amount (const char *name,
+ const struct TALER_Amount *amount)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ .object = (NULL != amount)
+ ? TALER_JSON_from_amount (amount)
+ : NULL
+ };
+
+ return ps;
+}
+
+
+/* End of json/json_pack.c */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -13,8 +13,8 @@ endif
# Libraries
-lib_LTLIBRARIES = \
- libtalerdonau.la
+#lib_LTLIBRARIES = \
+# libtalerdonau.la
libdonau_la_LDFLAGS = \
-version-info 5:0:0 \
diff --git a/src/lib/donau_api_handle.c b/src/lib/donau_api_handle.c
@@ -384,9 +384,9 @@ decode_keys_json (const json_t *resp_obj,
bool found = false;
struct GNUNET_JSON_Specification kspec[] = {
- TALER_JSON_spec_denom_pub_cipher (NULL, // TODO write new JSON function
- group.cipher,
- &dk->key),
+ DONAU_JSON_spec_donation_unit_pub_cipher (NULL,
+ group.cipher,
+ &dk->key),
GNUNET_JSON_spec_end ()
};
diff --git a/src/util/donau_signatures.c b/src/util/donau_signatures.c
@@ -35,7 +35,7 @@ struct DONAU_DonationStatementConfirmationPS
{
/**
* Purpose must be #DONAU_SIGNATURE_DONAU_DONATION_STATEMENT. Signed
- * by a `struct DONAU_EddsaPublicKeyP` using EdDSA.
+ * by a `struct DONAU_DonauPublicKeyP` using EdDSA.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;