commit 17c00ab24e33118d269e3725c02501322b09de06
parent c75013d677ab16961ca0cd5ad4579e7d7787c269
Author: Christian Grothoff <christian@grothoff.org>
Date: Tue, 3 Mar 2026 22:31:06 +0100
modernize GET /keys API
Diffstat:
7 files changed, 229 insertions(+), 529 deletions(-)
diff --git a/src/exchange-tools/taler-auditor-offline.c b/src/exchange-tools/taler-auditor-offline.c
@@ -22,7 +22,15 @@
#include <gnunet/gnunet_json_lib.h>
#include <microhttpd.h>
#include "taler/taler_json_lib.h"
-#include "taler/taler_exchange_service.h"
+
+#define TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE \
+ char *const
+#include "taler/taler-exchange/get-keys.h"
+
+struct DenominationAddRequest;
+#define TALER_EXCHANGE_POST_AUDITORS_RESULT_CLOSURE \
+ struct DenominationAddRequest
+#include "taler/taler-exchange/post-auditors-AUDITOR_PUB-H_DENOM_PUB.h"
/**
* Name of the input of a denomination key signature for the 'upload' operation.
@@ -388,15 +396,14 @@ load_offline_key (int do_create)
* Function called with information about the post denomination (signature)
* add operation result.
*
- * @param cls closure with a `struct DenominationAddRequest`
+ * @param dar the add request
* @param adr response data
*/
static void
denomination_add_cb (
- void *cls,
+ struct DenominationAddRequest *dar,
const struct TALER_EXCHANGE_PostAuditorsResponse *adr)
{
- struct DenominationAddRequest *dar = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status)
@@ -647,18 +654,16 @@ do_upload (char *const *args)
* Function called with information about who is auditing
* a particular exchange and what keys the exchange is using.
*
- * @param cls closure with the `char **` remaining args
+ * @param args the remaining args
* @param kr response data
* @param keys key data from the exchange
*/
static void
keys_cb (
- void *cls,
+ char *const *args,
const struct TALER_EXCHANGE_KeysResponse *kr,
struct TALER_EXCHANGE_Keys *keys)
{
- char *const *args = cls;
-
exchange = NULL;
switch (kr->hr.http_status)
{
@@ -722,11 +727,11 @@ do_download (char *const *args)
global_ret = EXIT_NOTCONFIGURED;
return;
}
- exchange = TALER_EXCHANGE_get_keys (ctx,
- exchange_url,
- NULL,
- &keys_cb,
- (void *) args);
+ exchange = TALER_EXCHANGE_get_keys_create (ctx,
+ exchange_url);
+ TALER_EXCHANGE_get_keys_start (exchange,
+ &keys_cb,
+ args);
GNUNET_free (exchange_url);
}
diff --git a/src/include/taler/taler-exchange/get-keys.h b/src/include/taler/taler-exchange/get-keys.h
@@ -870,6 +870,90 @@ struct TALER_EXCHANGE_KeysResponse
/**
+ * Possible options we can set for the GET /keys request.
+ */
+enum TALER_EXCHANGE_GetKeysOption
+{
+ /**
+ * End of list of options.
+ */
+ TALER_EXCHANGE_GET_KEYS_OPTION_END = 0,
+
+ /**
+ * Perform incremental fetch using the given previous keys object.
+ * Defaults to NULL (no incremental fetch).
+ */
+ TALER_EXCHANGE_GET_KEYS_OPTION_LAST_KEYS
+
+};
+
+
+/**
+ * Value for an option for the GET /keys request.
+ */
+struct TALER_EXCHANGE_GetKeysOptionValue
+{
+ /**
+ * Type of the option being set.
+ */
+ enum TALER_EXCHANGE_GetKeysOption option;
+
+ /**
+ * Specific option value.
+ */
+ union
+ {
+ /**
+ * Value if @e option is TALER_EXCHANGE_GET_KEYS_OPTION_LAST_KEYS.
+ * Previous keys object for incremental fetch.
+ */
+ struct TALER_EXCHANGE_Keys *last_keys;
+
+ } details;
+
+};
+
+
+/**
+ * @brief Handle for a GET /keys request.
+ */
+struct TALER_EXCHANGE_GetKeysHandle;
+
+
+/**
+ * Terminate the list of options.
+ *
+ * @return the terminating object of struct TALER_EXCHANGE_GetKeysOptionValue
+ */
+#define TALER_EXCHANGE_get_keys_option_end_() \
+ (const struct TALER_EXCHANGE_GetKeysOptionValue) \
+ { \
+ .option = TALER_EXCHANGE_GET_KEYS_OPTION_END \
+ }
+
+/**
+ * Set previous keys for incremental fetch.
+ *
+ * @param k previous keys object (may be NULL to request full fetch)
+ * @return representation of the option as a struct TALER_EXCHANGE_GetKeysOptionValue
+ */
+#define TALER_EXCHANGE_get_keys_option_last_keys(k) \
+ (const struct TALER_EXCHANGE_GetKeysOptionValue) \
+ { \
+ .option = TALER_EXCHANGE_GET_KEYS_OPTION_LAST_KEYS, \
+ .details.last_keys = (k) \
+ }
+
+
+#ifndef TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE
+/**
+ * Type of the closure used by
+ * the #TALER_EXCHANGE_GetKeysCallback.
+ */
+#define TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE void
+#endif /* TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE */
+
+/**
* Function called with information about who is auditing
* a particular exchange and what keys the exchange is using.
* The ownership over the @a keys object is passed to
@@ -884,39 +968,85 @@ struct TALER_EXCHANGE_KeysResponse
*/
typedef void
(*TALER_EXCHANGE_GetKeysCallback) (
- void *cls,
+ TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE *cls,
const struct TALER_EXCHANGE_KeysResponse *kr,
struct TALER_EXCHANGE_Keys *keys);
/**
- * @brief Handle for a GET /keys request.
+ * Set up GET /keys operation.
+ * Note that you must explicitly start the operation after
+ * possibly setting options.
+ *
+ * @param ctx the context
+ * @param url HTTP base URL for the exchange
+ * @return handle to operation, NULL on error
*/
-struct TALER_EXCHANGE_GetKeysHandle;
+struct TALER_EXCHANGE_GetKeysHandle *
+TALER_EXCHANGE_get_keys_create (
+ struct GNUNET_CURL_Context *ctx,
+ const char *url);
/**
- * Fetch the main /keys resources from an exchange. Does an incremental
- * fetch if @a last_keys is given. The obtained information will be passed to
- * the @a cert_cb (possibly after first merging it with @a last_keys to
- * produce a full picture; expired keys (for deposit) will be removed from @a
- * last_keys if there are any).
+ * Set the requested options for the operation.
*
- * @param ctx the context
- * @param url HTTP base URL for the exchange
- * @param[in,out] last_keys previous keys object, NULL for none
- * @param cert_cb function to call with the exchange's certification information,
- * possibly called repeatedly if the information changes
+ * If any option fails, other options may or may not be applied.
+ *
+ * @param gkh the request to set the options for
+ * @param num_options length of the @a options array
+ * @param options an array of options
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO on failure,
+ * #GNUNET_SYSERR on internal error
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_get_keys_set_options_ (
+ struct TALER_EXCHANGE_GetKeysHandle *gkh,
+ unsigned int num_options,
+ const struct TALER_EXCHANGE_GetKeysOptionValue *options);
+
+
+/**
+ * Set the requested options for the operation.
+ *
+ * If any option fails, other options may or may not be applied.
+ *
+ * It should be used with helpers that create required options, for example:
+ *
+ * TALER_EXCHANGE_get_keys_set_options (
+ * gkh,
+ * TALER_EXCHANGE_get_keys_option_last_keys (prev_keys));
+ *
+ * @param gkh the request to set the options for
+ * @param ... the list of options, each created by a
+ * TALER_EXCHANGE_get_keys_option_NAME(VALUE) helper
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO on failure,
+ * #GNUNET_SYSERR on internal error
+ */
+#define TALER_EXCHANGE_get_keys_set_options(gkh,...) \
+ TALER_EXCHANGE_get_keys_set_options_ ( \
+ gkh, \
+ TALER_EXCHANGE_COMMON_OPTIONS_ARRAY_MAX_SIZE, \
+ ((const struct TALER_EXCHANGE_GetKeysOptionValue[]) \
+ {__VA_ARGS__, TALER_EXCHANGE_get_keys_option_end_ () } \
+ ))
+
+
+/**
+ * Start GET /keys operation.
+ *
+ * @param[in,out] gkh operation to start
+ * @param cert_cb function to call with the exchange's certification information
* @param cert_cb_cls closure for @a cert_cb
- * @return the exchange handle; NULL upon error
+ * @return status code, #TALER_EC_NONE on success
*/
-struct TALER_EXCHANGE_GetKeysHandle *
-TALER_EXCHANGE_get_keys (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- struct TALER_EXCHANGE_Keys *last_keys,
+enum TALER_ErrorCode
+TALER_EXCHANGE_get_keys_start (
+ struct TALER_EXCHANGE_GetKeysHandle *gkh,
TALER_EXCHANGE_GetKeysCallback cert_cb,
- void *cert_cb_cls);
+ TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE *cert_cb_cls);
/**
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -33,6 +33,7 @@ libtalerexchange_la_SOURCES = \
exchange_api_get-kyc-check-H_NORMALIZED_PAYTO.c \
exchange_api_get-kyc-info-ACCESS_TOKEN.c \
exchange_api_get-kyc-proof-PROVIDER_NAME.c \
+ exchange_api_get-keys.c \
exchange_api_get-management-keys.c \
exchange_api_get-purses-PURSE_PUB-merge.c \
exchange_api_get-reserves-attest-RESERVE_PUB.c \
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
@@ -64,66 +64,6 @@
#define LIFETIME_TOLERANCE GNUNET_TIME_UNIT_HOURS
/**
- * If the "Expire" cache control header is missing, for
- * how long do we assume the reply to be valid at least?
- */
-#define DEFAULT_EXPIRATION GNUNET_TIME_UNIT_HOURS
-
-/**
- * If the "Expire" cache control header is missing, for
- * how long do we assume the reply to be valid at least?
- */
-#define MINIMUM_EXPIRATION GNUNET_TIME_relative_multiply ( \
- GNUNET_TIME_UNIT_MINUTES, 2)
-
-
-/**
- * Handle for a GET /keys request.
- */
-struct TALER_EXCHANGE_GetKeysHandle
-{
-
- /**
- * The exchange base URL (i.e. "https://exchange.demo.taler.net/")
- */
- char *exchange_url;
-
- /**
- * The url for the /keys request.
- */
- char *url;
-
- /**
- * Previous /keys response, NULL for none.
- */
- struct TALER_EXCHANGE_Keys *prev_keys;
-
- /**
- * Entry for this request with the `struct GNUNET_CURL_Context`.
- */
- struct GNUNET_CURL_Job *job;
-
- /**
- * Expiration time according to "Expire:" header.
- * 0 if not provided by the server.
- */
- struct GNUNET_TIME_Timestamp expire;
-
- /**
- * Function to call with the exchange's certification data,
- * NULL if this has already been done.
- */
- TALER_EXCHANGE_GetKeysCallback cert_cb;
-
- /**
- * Closure to pass to @e cert_cb.
- */
- void *cert_cb_cls;
-
-};
-
-
-/**
* Element in the `struct SignatureContext` array.
*/
struct SignatureElement
@@ -355,7 +295,7 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub,
void
-TEAH_get_auditors_for_dc (
+TALER_EXCHANGE_get_auditors_for_dc_ (
struct TALER_EXCHANGE_Keys *keys,
TEAH_AuditorCallback ac,
void *ac_cls)
@@ -967,11 +907,12 @@ parse_wads (const json_t *wads_array,
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
* (malformed JSON)
*/
-static enum GNUNET_GenericReturnValue
-decode_keys_json (const json_t *resp_obj,
- bool check_sig,
- struct TALER_EXCHANGE_Keys *key_data,
- enum TALER_EXCHANGE_VersionCompatibility *vc)
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_decode_keys_json_ (
+ const json_t *resp_obj,
+ bool check_sig,
+ struct TALER_EXCHANGE_Keys *key_data,
+ enum TALER_EXCHANGE_VersionCompatibility *vc)
{
struct TALER_ExchangeSignatureP exchange_sig;
struct TALER_ExchangePublicKeyP exchange_pub;
@@ -1609,419 +1550,6 @@ EXITIF_exit:
}
-/**
- * Callback used when downloading the reply to a /keys request
- * is complete.
- *
- * @param cls the `struct KeysRequest`
- * @param response_code HTTP response code, 0 on error
- * @param resp_obj parsed JSON result, NULL on error
- */
-static void
-keys_completed_cb (void *cls,
- long response_code,
- const void *resp_obj)
-{
- struct TALER_EXCHANGE_GetKeysHandle *gkh = cls;
- const json_t *j = resp_obj;
- struct TALER_EXCHANGE_Keys *kd = NULL;
- struct TALER_EXCHANGE_KeysResponse kresp = {
- .hr.reply = j,
- .hr.http_status = (unsigned int) response_code,
- .details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR,
- };
-
- gkh->job = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Received keys from URL `%s' with status %ld and expiration %s.\n",
- gkh->url,
- response_code,
- GNUNET_TIME_timestamp2s (gkh->expire));
- if (GNUNET_TIME_absolute_is_past (gkh->expire.abs_time))
- {
- if (MHD_HTTP_OK == response_code)
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Exchange failed to give expiration time, assuming in %s\n",
- GNUNET_TIME_relative2s (DEFAULT_EXPIRATION,
- true));
- gkh->expire
- = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION));
- }
- switch (response_code)
- {
- case 0:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to receive /keys response from exchange %s\n",
- gkh->exchange_url);
- break;
- case MHD_HTTP_OK:
- if (NULL == j)
- {
- GNUNET_break (0);
- response_code = 0;
- break;
- }
- kd = GNUNET_new (struct TALER_EXCHANGE_Keys);
- kd->exchange_url = GNUNET_strdup (gkh->exchange_url);
- if (NULL != gkh->prev_keys)
- {
- const struct TALER_EXCHANGE_Keys *kd_old = gkh->prev_keys;
-
- /* We keep the denomination keys and auditor signatures from the
- previous iteration (/keys cherry picking) */
- kd->num_denom_keys
- = kd_old->num_denom_keys;
- kd->last_denom_issue_date
- = kd_old->last_denom_issue_date;
- GNUNET_array_grow (kd->denom_keys,
- kd->denom_keys_size,
- kd->num_denom_keys);
- /* First make a shallow copy, we then need another pass for the RSA key... */
- GNUNET_memcpy (kd->denom_keys,
- kd_old->denom_keys,
- kd_old->num_denom_keys
- * sizeof (struct TALER_EXCHANGE_DenomPublicKey));
- for (unsigned int i = 0; i<kd_old->num_denom_keys; i++)
- TALER_denom_pub_copy (&kd->denom_keys[i].key,
- &kd_old->denom_keys[i].key);
- kd->num_auditors = kd_old->num_auditors;
- kd->auditors
- = GNUNET_new_array (kd->num_auditors,
- struct TALER_EXCHANGE_AuditorInformation);
- /* Now the necessary deep copy... */
- for (unsigned int i = 0; i<kd_old->num_auditors; i++)
- {
- const struct TALER_EXCHANGE_AuditorInformation *aold =
- &kd_old->auditors[i];
- struct TALER_EXCHANGE_AuditorInformation *anew = &kd->auditors[i];
-
- anew->auditor_pub = aold->auditor_pub;
- anew->auditor_url = GNUNET_strdup (aold->auditor_url);
- anew->auditor_name = GNUNET_strdup (aold->auditor_name);
- GNUNET_array_grow (anew->denom_keys,
- anew->num_denom_keys,
- aold->num_denom_keys);
- GNUNET_memcpy (
- anew->denom_keys,
- aold->denom_keys,
- aold->num_denom_keys
- * sizeof (struct TALER_EXCHANGE_AuditorDenominationInfo));
- }
- }
- /* Now decode fresh /keys response */
- if (GNUNET_OK !=
- decode_keys_json (j,
- true,
- kd,
- &kresp.details.ok.compat))
- {
- TALER_LOG_ERROR ("Could not decode /keys response\n");
- kd->rc = 1;
- TALER_EXCHANGE_keys_decref (kd);
- kd = NULL;
- kresp.hr.http_status = 0;
- kresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- kd->rc = 1;
- kd->key_data_expiration = gkh->expire;
- if (GNUNET_TIME_relative_cmp (
- GNUNET_TIME_absolute_get_remaining (gkh->expire.abs_time),
- <,
- MINIMUM_EXPIRATION))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Exchange returned keys with expiration time below %s. Compensating.\n",
- GNUNET_TIME_relative2s (MINIMUM_EXPIRATION,
- true));
- kd->key_data_expiration
- = GNUNET_TIME_relative_to_timestamp (MINIMUM_EXPIRATION);
- }
-
- kresp.details.ok.keys = kd;
- break;
- case MHD_HTTP_BAD_REQUEST:
- case MHD_HTTP_UNAUTHORIZED:
- case MHD_HTTP_FORBIDDEN:
- case MHD_HTTP_NOT_FOUND:
- if (NULL == j)
- {
- kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
- }
- else
- {
- kresp.hr.ec = TALER_JSON_get_error_code (j);
- kresp.hr.hint = TALER_JSON_get_error_hint (j);
- }
- break;
- default:
- if (NULL == j)
- {
- kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
- kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
- }
- else
- {
- kresp.hr.ec = TALER_JSON_get_error_code (j);
- kresp.hr.hint = TALER_JSON_get_error_hint (j);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d\n",
- (unsigned int) response_code,
- (int) kresp.hr.ec);
- break;
- }
- gkh->cert_cb (gkh->cert_cb_cls,
- &kresp,
- kd);
- TALER_EXCHANGE_get_keys_cancel (gkh);
-}
-
-
-/**
- * Define a max length for the HTTP "Expire:" header
- */
-#define MAX_DATE_LINE_LEN 32
-
-
-/**
- * Parse HTTP timestamp.
- *
- * @param dateline header to parse header
- * @param[out] at where to write the result
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-parse_date_string (const char *dateline,
- struct GNUNET_TIME_Timestamp *at)
-{
- static const char *MONTHS[] =
- { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
- int year;
- int mon;
- int day;
- int hour;
- int min;
- int sec;
- char month[4];
- struct tm tm;
- time_t t;
-
- /* We recognize the three formats in RFC2616, section 3.3.1. Month
- names are always in English. The formats are:
- Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
- Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
- Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
- Note that the first is preferred.
- */
-
- if (strlen (dateline) > MAX_DATE_LINE_LEN)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- while (*dateline == ' ')
- ++dateline;
- while (*dateline && *dateline != ' ')
- ++dateline;
- while (*dateline == ' ')
- ++dateline;
- /* We just skipped over the day of the week. Now we have:*/
- if ( (sscanf (dateline,
- "%d %3s %d %d:%d:%d",
- &day, month, &year, &hour, &min, &sec) != 6) &&
- (sscanf (dateline,
- "%d-%3s-%d %d:%d:%d",
- &day, month, &year, &hour, &min, &sec) != 6) &&
- (sscanf (dateline,
- "%3s %d %d:%d:%d %d",
- month, &day, &hour, &min, &sec, &year) != 6) )
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- /* Two digit dates are defined to be relative to 1900; all other dates
- * are supposed to be represented as four digits. */
- if (year < 100)
- year += 1900;
-
- for (mon = 0; ; mon++)
- {
- if (! MONTHS[mon])
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (0 == strcasecmp (month,
- MONTHS[mon]))
- break;
- }
-
- memset (&tm, 0, sizeof(tm));
- tm.tm_year = year - 1900;
- tm.tm_mon = mon;
- tm.tm_mday = day;
- tm.tm_hour = hour;
- tm.tm_min = min;
- tm.tm_sec = sec;
-
- t = mktime (&tm);
- if (((time_t) -1) == t)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "mktime");
- return GNUNET_SYSERR;
- }
- if (t < 0)
- t = 0; /* can happen due to timezone issues if date was 1.1.1970 */
- *at = GNUNET_TIME_timestamp_from_s (t);
- return GNUNET_OK;
-}
-
-
-/**
- * Function called for each header in the HTTP /keys response.
- * Finds the "Expire:" header and parses it, storing the result
- * in the "expire" field of the keys request.
- *
- * @param buffer header data received
- * @param size size of an item in @a buffer
- * @param nitems number of items in @a buffer
- * @param userdata the `struct TALER_EXCHANGE_GetKeysHandle`
- * @return `size * nitems` on success (everything else aborts)
- */
-static size_t
-header_cb (char *buffer,
- size_t size,
- size_t nitems,
- void *userdata)
-{
- struct TALER_EXCHANGE_GetKeysHandle *kr = userdata;
- size_t total = size * nitems;
- char *val;
-
- if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
- return total;
- if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
- buffer,
- strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
- return total;
- val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
- total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Found %s header `%s'\n",
- MHD_HTTP_HEADER_EXPIRES,
- val);
- if (GNUNET_OK !=
- parse_date_string (val,
- &kr->expire))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to parse %s-header `%s'\n",
- MHD_HTTP_HEADER_EXPIRES,
- val);
- kr->expire = GNUNET_TIME_UNIT_ZERO_TS;
- }
- GNUNET_free (val);
- return total;
-}
-
-
-struct TALER_EXCHANGE_GetKeysHandle *
-TALER_EXCHANGE_get_keys (
- struct GNUNET_CURL_Context *ctx,
- const char *url,
- struct TALER_EXCHANGE_Keys *last_keys,
- TALER_EXCHANGE_GetKeysCallback cert_cb,
- void *cert_cb_cls)
-{
- struct TALER_EXCHANGE_GetKeysHandle *gkh;
- CURL *eh;
- char last_date[80] = { 0 };
-
- TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
- url);
- gkh = GNUNET_new (struct TALER_EXCHANGE_GetKeysHandle);
- gkh->exchange_url = GNUNET_strdup (url);
- gkh->cert_cb = cert_cb;
- gkh->cert_cb_cls = cert_cb_cls;
- if (NULL != last_keys)
- {
- gkh->prev_keys = TALER_EXCHANGE_keys_incref (last_keys);
- TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n",
- GNUNET_TIME_timestamp2s (
- last_keys->last_denom_issue_date));
- GNUNET_snprintf (last_date,
- sizeof (last_date),
- "%llu",
- (unsigned long long)
- last_keys->last_denom_issue_date.abs_time.abs_value_us
- / 1000000LLU);
- }
- gkh->url = TALER_url_join (url,
- "keys",
- (NULL != last_keys)
- ? "last_issue_date"
- : NULL,
- (NULL != last_keys)
- ? last_date
- : NULL,
- NULL);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Requesting keys with URL `%s'.\n",
- gkh->url);
- eh = TALER_EXCHANGE_curl_easy_get_ (gkh->url);
- if (NULL == eh)
- {
- GNUNET_break (0);
- GNUNET_free (gkh->exchange_url);
- GNUNET_free (gkh->url);
- GNUNET_free (gkh);
- return NULL;
- }
- GNUNET_break (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_VERBOSE,
- 0));
- GNUNET_break (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_TIMEOUT,
- 120 /* seconds */));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_HEADERFUNCTION,
- &header_cb));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_HEADERDATA,
- gkh));
- gkh->job = GNUNET_CURL_job_add_with_ct_json (ctx,
- eh,
- &keys_completed_cb,
- gkh);
- return gkh;
-}
-
-
-void
-TALER_EXCHANGE_get_keys_cancel (
- struct TALER_EXCHANGE_GetKeysHandle *gkh)
-{
- if (NULL != gkh->job)
- {
- GNUNET_CURL_job_cancel (gkh->job);
- gkh->job = NULL;
- }
- TALER_EXCHANGE_keys_decref (gkh->prev_keys);
- GNUNET_free (gkh->exchange_url);
- GNUNET_free (gkh->url);
- GNUNET_free (gkh);
-}
-
-
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_test_signing_key (
const struct TALER_EXCHANGE_Keys *keys,
@@ -2238,10 +1766,10 @@ TALER_EXCHANGE_keys_from_json (const json_t *j)
}
keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
if (GNUNET_OK !=
- decode_keys_json (jkeys,
- false,
- keys,
- &compat))
+ TALER_EXCHANGE_decode_keys_json_ (jkeys,
+ false,
+ keys,
+ &compat))
{
GNUNET_break (0);
return NULL;
diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h
@@ -54,11 +54,30 @@ typedef void
* @param ac_cls closure for @a ac
*/
void
-TEAH_get_auditors_for_dc (
+TALER_EXCHANGE_get_auditors_for_dc_ (
struct TALER_EXCHANGE_Keys *keys,
TEAH_AuditorCallback ac,
void *ac_cls);
+/**
+ * Decode the JSON in @a resp_obj from the /keys response
+ * and store the data in the @a key_data.
+ *
+ * @param[in] resp_obj JSON object to parse
+ * @param check_sig true if we should check the signature
+ * @param[out] key_data where to store the results we decoded
+ * @param[out] vc where to store version compatibility data
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ * (malformed JSON)
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_decode_keys_json_ (
+ const json_t *resp_obj,
+ bool check_sig,
+ struct TALER_EXCHANGE_Keys *key_data,
+ enum TALER_EXCHANGE_VersionCompatibility *vc);
+
+
/* end of exchange_api_handle.h */
#endif
diff --git a/src/lib/exchange_api_post-batch-deposit.c b/src/lib/exchange_api_post-batch-deposit.c
@@ -417,9 +417,9 @@ handle_deposit_finished (void *cls,
break;
}
}
- TEAH_get_auditors_for_dc (dh->keys,
- &auditor_cb,
- dh);
+ TALER_EXCHANGE_get_auditors_for_dc_ (dh->keys,
+ &auditor_cb,
+ dh);
}
dr->details.ok.exchange_sig = &dh->exchange_sig;
dr->details.ok.exchange_pub = &dh->exchange_pub;
diff --git a/src/testing/testing_api_cmd_get_exchange.c b/src/testing/testing_api_cmd_get_exchange.c
@@ -24,6 +24,8 @@
#include "taler/platform.h"
#include "taler/taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
+struct GetExchangeState;
+#define TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE struct GetExchangeState
#include "taler/taler_testing_lib.h"
@@ -85,16 +87,15 @@ struct GetExchangeState
* Function called with information about who is auditing
* a particular exchange and what keys the exchange is using.
*
- * @param cls closure
+ * @param ges our command state
* @param kr response from /keys
* @param[in] keys the keys of the exchange
*/
static void
-cert_cb (void *cls,
+cert_cb (struct GetExchangeState *ges,
const struct TALER_EXCHANGE_KeysResponse *kr,
struct TALER_EXCHANGE_Keys *keys)
{
- struct GetExchangeState *ges = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
struct TALER_TESTING_Interpreter *is = ges->is;
@@ -232,15 +233,31 @@ get_exchange_run (void *cls,
}
ges->is = is;
ges->exchange
- = TALER_EXCHANGE_get_keys (TALER_TESTING_interpreter_get_context (is),
- ges->exchange_url,
- xkeys,
- &cert_cb,
- ges);
- TALER_EXCHANGE_keys_decref (xkeys);
+ = TALER_EXCHANGE_get_keys_create (
+ TALER_TESTING_interpreter_get_context (is),
+ ges->exchange_url);
if (NULL == ges->exchange)
{
GNUNET_break (0);
+ TALER_EXCHANGE_keys_decref (xkeys);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL != xkeys)
+ {
+ TALER_EXCHANGE_get_keys_set_options (
+ ges->exchange,
+ TALER_EXCHANGE_get_keys_option_last_keys (xkeys));
+ }
+ TALER_EXCHANGE_keys_decref (xkeys);
+ if (TALER_EC_NONE !=
+ TALER_EXCHANGE_get_keys_start (ges->exchange,
+ &cert_cb,
+ ges))
+ {
+ GNUNET_break (0);
+ TALER_EXCHANGE_get_keys_cancel (ges->exchange);
+ ges->exchange = NULL;
TALER_TESTING_interpreter_fail (is);
return;
}