aboutsummaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd_keys.c
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-07-14 09:25:43 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-07-14 09:25:43 +0200
commit34f44ccb279c655b5b948a42d576bac371d684a7 (patch)
tree274f1118419190442bc78a794b70ebdec8266c59 /src/exchange/taler-exchange-httpd_keys.c
parentc8250cae25573a74e5fd536ebc007d639fd85957 (diff)
parentde24415e17fbf32c8a145cf8e5dadf2070c29e08 (diff)
Merge branch 'master' into age-withdraw
Diffstat (limited to 'src/exchange/taler-exchange-httpd_keys.c')
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c710
1 files changed, 707 insertions, 3 deletions
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index 265b71fa..ff5d1f41 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -388,6 +388,117 @@ struct SuspendedKeysRequests
struct GNUNET_TIME_Absolute timeout;
};
+
+/**
+ * Information we track about wire fees.
+ */
+struct WireFeeSet
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct WireFeeSet *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct WireFeeSet *prev;
+
+ /**
+ * Actual fees.
+ */
+ struct TALER_WireFeeSet fees;
+
+ /**
+ * Start date of fee validity (inclusive).
+ */
+ struct GNUNET_TIME_Timestamp start_date;
+
+ /**
+ * End date of fee validity (exclusive).
+ */
+ struct GNUNET_TIME_Timestamp end_date;
+
+ /**
+ * Wire method the fees apply to.
+ */
+ char *method;
+};
+
+
+/**
+ * State we keep per thread to cache the /wire response.
+ */
+struct WireStateHandle
+{
+ /**
+ * Cached reply for /wire response.
+ */
+ struct MHD_Response *wire_reply;
+
+ /**
+ * JSON reply for /wire response.
+ */
+ json_t *json_reply;
+
+ /**
+ * ETag for this response (if any).
+ */
+ char *etag;
+
+ /**
+ * head of DLL of wire fees.
+ */
+ struct WireFeeSet *wfs_head;
+
+ /**
+ * Tail of DLL of wire fees.
+ */
+ struct WireFeeSet *wfs_tail;
+
+ /**
+ * Earliest timestamp of all the wire methods when we have no more fees.
+ */
+ struct GNUNET_TIME_Absolute cache_expiration;
+
+ /**
+ * @e cache_expiration time, formatted.
+ */
+ char dat[128];
+
+ /**
+ * For which (global) wire_generation was this data structure created?
+ * Used to check when we are outdated and need to be re-generated.
+ */
+ uint64_t wire_generation;
+
+ /**
+ * HTTP status to return with this response.
+ */
+ unsigned int http_status;
+
+};
+
+
+/**
+ * Stores the latest generation of our wire response.
+ */
+static struct WireStateHandle *wire_state;
+
+/**
+ * Handler listening for wire updates by other exchange
+ * services.
+ */
+static struct GNUNET_DB_EventHandler *wire_eh;
+
+/**
+ * Counter incremented whenever we have a reason to re-build the #wire_state
+ * because something external changed.
+ */
+static uint64_t wire_generation;
+
+
/**
* Stores the latest generation of our key state.
*/
@@ -466,6 +577,545 @@ static bool terminating;
/**
+ * Free memory associated with @a wsh
+ *
+ * @param[in] wsh wire state to destroy
+ */
+static void
+destroy_wire_state (struct WireStateHandle *wsh)
+{
+ struct WireFeeSet *wfs;
+
+ while (NULL != (wfs = wsh->wfs_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (wsh->wfs_head,
+ wsh->wfs_tail,
+ wfs);
+ GNUNET_free (wfs->method);
+ GNUNET_free (wfs);
+ }
+ MHD_destroy_response (wsh->wire_reply);
+ json_decref (wsh->json_reply);
+ GNUNET_free (wsh->etag);
+ GNUNET_free (wsh);
+}
+
+
+/**
+ * Function called whenever another exchange process has updated
+ * the wire data in the database.
+ *
+ * @param cls NULL
+ * @param extra unused
+ * @param extra_size number of bytes in @a extra unused
+ */
+static void
+wire_update_event_cb (void *cls,
+ const void *extra,
+ size_t extra_size)
+{
+ (void) cls;
+ (void) extra;
+ (void) extra_size;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received /wire update event\n");
+ TEH_check_invariants ();
+ wire_generation++;
+ key_generation++;
+ TEH_resume_keys_requests (false);
+}
+
+
+enum GNUNET_GenericReturnValue
+TEH_wire_init ()
+{
+ struct GNUNET_DB_EventHeaderP es = {
+ .size = htons (sizeof (es)),
+ .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
+ };
+
+ wire_eh = TEH_plugin->event_listen (TEH_plugin->cls,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &es,
+ &wire_update_event_cb,
+ NULL);
+ if (NULL == wire_eh)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+void
+TEH_wire_done ()
+{
+ if (NULL != wire_state)
+ {
+ destroy_wire_state (wire_state);
+ wire_state = NULL;
+ }
+ if (NULL != wire_eh)
+ {
+ TEH_plugin->event_listen_cancel (TEH_plugin->cls,
+ wire_eh);
+ wire_eh = NULL;
+ }
+}
+
+
+/**
+ * Add information about a wire account to @a cls.
+ *
+ * @param cls a `json_t *` object to expand with wire account details
+ * @param payto_uri the exchange bank account URI to add
+ * @param conversion_url URL of a conversion service, NULL if there is no conversion
+ * @param debit_restrictions JSON array with debit restrictions on the account
+ * @param credit_restrictions JSON array with credit restrictions on the account
+ * @param master_sig master key signature affirming that this is a bank
+ * account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS)
+ */
+static void
+add_wire_account (void *cls,
+ const char *payto_uri,
+ const char *conversion_url,
+ const json_t *debit_restrictions,
+ const json_t *credit_restrictions,
+ const struct TALER_MasterSignatureP *master_sig)
+{
+ json_t *a = cls;
+
+ if (0 !=
+ json_array_append_new (
+ a,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("payto_uri",
+ payto_uri),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("conversion_url",
+ conversion_url)),
+ GNUNET_JSON_pack_array_incref ("debit_restrictions",
+ (json_t *) debit_restrictions),
+ GNUNET_JSON_pack_array_incref ("credit_restrictions",
+ (json_t *) credit_restrictions),
+ GNUNET_JSON_pack_data_auto ("master_sig",
+ master_sig))))
+ {
+ GNUNET_break (0); /* out of memory!? */
+ return;
+ }
+}
+
+
+/**
+ * Closure for #add_wire_fee().
+ */
+struct AddContext
+{
+ /**
+ * Wire method the fees are for.
+ */
+ char *wire_method;
+
+ /**
+ * Wire state we are building.
+ */
+ struct WireStateHandle *wsh;
+
+ /**
+ * Array to append the fee to.
+ */
+ json_t *a;
+
+ /**
+ * Context we hash "everything" we add into. This is used
+ * to compute the etag. Technically, we only hash the
+ * master_sigs, as they imply the rest.
+ */
+ struct GNUNET_HashContext *hc;
+
+ /**
+ * Set to the maximum end-date seen.
+ */
+ struct GNUNET_TIME_Absolute max_seen;
+};
+
+
+/**
+ * Add information about a wire account to @a cls.
+ *
+ * @param cls a `struct AddContext`
+ * @param fees the wire fees we charge
+ * @param start_date from when are these fees valid (start date)
+ * @param end_date until when are these fees valid (end date, exclusive)
+ * @param master_sig master key signature affirming that this is the correct
+ * fee (of purpose #TALER_SIGNATURE_MASTER_WIRE_FEES)
+ */
+static void
+add_wire_fee (void *cls,
+ const struct TALER_WireFeeSet *fees,
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ const struct TALER_MasterSignatureP *master_sig)
+{
+ struct AddContext *ac = cls;
+ struct WireFeeSet *wfs;
+
+ GNUNET_CRYPTO_hash_context_read (ac->hc,
+ master_sig,
+ sizeof (*master_sig));
+ ac->max_seen = GNUNET_TIME_absolute_max (ac->max_seen,
+ end_date.abs_time);
+ wfs = GNUNET_new (struct WireFeeSet);
+ wfs->start_date = start_date;
+ wfs->end_date = end_date;
+ wfs->fees = *fees;
+ wfs->method = GNUNET_strdup (ac->wire_method);
+ GNUNET_CONTAINER_DLL_insert (ac->wsh->wfs_head,
+ ac->wsh->wfs_tail,
+ wfs);
+ if (0 !=
+ json_array_append_new (
+ ac->a,
+ GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("wire_fee",
+ &fees->wire),
+ TALER_JSON_pack_amount ("closing_fee",
+ &fees->closing),
+ GNUNET_JSON_pack_timestamp ("start_date",
+ start_date),
+ GNUNET_JSON_pack_timestamp ("end_date",
+ end_date),
+ GNUNET_JSON_pack_data_auto ("sig",
+ master_sig))))
+ {
+ GNUNET_break (0); /* out of memory!? */
+ return;
+ }
+}
+
+
+/**
+ * Create the /wire response from our database state.
+ *
+ * @return NULL on error
+ */
+static struct WireStateHandle *
+build_wire_state (void)
+{
+ json_t *wire_accounts_array;
+ json_t *wire_fee_object;
+ uint64_t wg = wire_generation; /* must be obtained FIRST */
+ enum GNUNET_DB_QueryStatus qs;
+ struct WireStateHandle *wsh;
+ struct GNUNET_HashContext *hc;
+ json_t *wads;
+
+ wsh = GNUNET_new (struct WireStateHandle);
+ wsh->wire_generation = wg;
+ wire_accounts_array = json_array ();
+ GNUNET_assert (NULL != wire_accounts_array);
+ qs = TEH_plugin->get_wire_accounts (TEH_plugin->cls,
+ &add_wire_account,
+ wire_accounts_array);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ json_decref (wire_accounts_array);
+ wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ wsh->wire_reply
+ = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "get_wire_accounts");
+ return wsh;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Build /wire data with %u accounts\n",
+ (unsigned int) json_array_size (wire_accounts_array));
+ wire_fee_object = json_object ();
+ GNUNET_assert (NULL != wire_fee_object);
+ wsh->cache_expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ {
+ json_t *account;
+ size_t index;
+
+ json_array_foreach (wire_accounts_array, index, account) {
+ char *wire_method;
+ const char *payto_uri = json_string_value (json_object_get (account,
+ "payto_uri"));
+
+ GNUNET_assert (NULL != payto_uri);
+ wire_method = TALER_payto_get_method (payto_uri);
+ if (NULL == wire_method)
+ {
+ wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ wsh->wire_reply
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_WIRE_INVALID_PAYTO_CONFIGURED,
+ payto_uri);
+ json_decref (wire_accounts_array);
+ json_decref (wire_fee_object);
+ GNUNET_CRYPTO_hash_context_abort (hc);
+ return wsh;
+ }
+ if (NULL == json_object_get (wire_fee_object,
+ wire_method))
+ {
+ struct AddContext ac = {
+ .wire_method = wire_method,
+ .wsh = wsh,
+ .a = json_array (),
+ .hc = hc
+ };
+
+ GNUNET_assert (NULL != ac.a);
+ qs = TEH_plugin->get_wire_fees (TEH_plugin->cls,
+ wire_method,
+ &add_wire_fee,
+ &ac);
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ json_decref (ac.a);
+ json_decref (wire_fee_object);
+ json_decref (wire_accounts_array);
+ GNUNET_free (wire_method);
+ wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ wsh->wire_reply
+ = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "get_wire_fees");
+ GNUNET_CRYPTO_hash_context_abort (hc);
+ return wsh;
+ }
+ if (0 == json_array_size (ac.a))
+ {
+ json_decref (ac.a);
+ json_decref (wire_accounts_array);
+ json_decref (wire_fee_object);
+ wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ wsh->wire_reply
+ = TALER_MHD_make_error (TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED,
+ wire_method);
+ GNUNET_free (wire_method);
+ GNUNET_CRYPTO_hash_context_abort (hc);
+ return wsh;
+ }
+ wsh->cache_expiration = GNUNET_TIME_absolute_min (ac.max_seen,
+ wsh->cache_expiration);
+ GNUNET_assert (0 ==
+ json_object_set_new (wire_fee_object,
+ wire_method,
+ ac.a));
+ }
+ GNUNET_free (wire_method);
+ }
+ }
+
+ wads = json_array (); /* #7271 */
+ GNUNET_assert (NULL != wads);
+ wsh->json_reply = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_array_incref ("accounts",
+ wire_accounts_array),
+ GNUNET_JSON_pack_array_incref ("wads",
+ wads),
+ GNUNET_JSON_pack_object_incref ("fees",
+ wire_fee_object));
+ wsh->wire_reply = TALER_MHD_MAKE_JSON_PACK (
+ GNUNET_JSON_pack_array_steal ("accounts",
+ wire_accounts_array),
+ GNUNET_JSON_pack_array_steal ("wads",
+ wads),
+ GNUNET_JSON_pack_object_steal ("fees",
+ wire_fee_object),
+ GNUNET_JSON_pack_data_auto ("master_public_key",
+ &TEH_master_public_key));
+ {
+ struct GNUNET_TIME_Timestamp m;
+
+ m = GNUNET_TIME_absolute_to_timestamp (wsh->cache_expiration);
+ TALER_MHD_get_date_string (m.abs_time,
+ wsh->dat);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Setting 'Expires' header for '/wire' to '%s'\n",
+ wsh->dat);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (wsh->wire_reply,
+ MHD_HTTP_HEADER_EXPIRES,
+ wsh->dat));
+ }
+ /* Set cache control headers: our response varies depending on these headers */
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (wsh->wire_reply,
+ MHD_HTTP_HEADER_VARY,
+ MHD_HTTP_HEADER_ACCEPT_ENCODING));
+ /* Information is always public, revalidate after 1 day */
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (wsh->wire_reply,
+ MHD_HTTP_HEADER_CACHE_CONTROL,
+ "public,max-age=86400"));
+
+ {
+ struct GNUNET_HashCode h;
+ char etag[sizeof (h) * 2];
+ char *end;
+
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &h);
+ end = GNUNET_STRINGS_data_to_string (&h,
+ sizeof (h),
+ etag,
+ sizeof (etag));
+ *end = '\0';
+ wsh->etag = GNUNET_strdup (etag);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (wsh->wire_reply,
+ MHD_HTTP_HEADER_ETAG,
+ etag));
+ }
+ wsh->http_status = MHD_HTTP_OK;
+ return wsh;
+}
+
+
+void
+TEH_wire_update_state (void)
+{
+ struct GNUNET_DB_EventHeaderP es = {
+ .size = htons (sizeof (es)),
+ .type = htons (TALER_DBEVENT_EXCHANGE_WIRE_UPDATED),
+ };
+
+ TEH_plugin->event_notify (TEH_plugin->cls,
+ &es,
+ NULL,
+ 0);
+ wire_generation++;
+ key_generation++;
+}
+
+
+/**
+ * Return the current key state for this thread. Possibly
+ * re-builds the key state if we have reason to believe
+ * that something changed.
+ *
+ * @return NULL on error
+ */
+struct WireStateHandle *
+get_wire_state (void)
+{
+ struct WireStateHandle *old_wsh;
+
+ old_wsh = wire_state;
+ if ( (NULL == old_wsh) ||
+ (old_wsh->wire_generation < wire_generation) )
+ {
+ struct WireStateHandle *wsh;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Rebuilding /wire, generation upgrade from %llu to %llu\n",
+ (unsigned long long) (NULL == old_wsh) ? 0LL :
+ old_wsh->wire_generation,
+ (unsigned long long) wire_generation);
+ TEH_check_invariants ();
+ wsh = build_wire_state ();
+ wire_state = wsh;
+ if (NULL != old_wsh)
+ destroy_wire_state (old_wsh);
+ TEH_check_invariants ();
+ return wsh;
+ }
+ return old_wsh;
+}
+
+
+MHD_RESULT
+TEH_handler_wire (struct TEH_RequestContext *rc,
+ const char *const args[])
+{
+ struct WireStateHandle *wsh;
+
+ (void) args;
+ wsh = get_wire_state ();
+ if (NULL == wsh)
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
+ NULL);
+ {
+ const char *etag;
+
+ etag = MHD_lookup_connection_value (rc->connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_IF_NONE_MATCH);
+ if ( (NULL != etag) &&
+ (MHD_HTTP_OK == wsh->http_status) &&
+ (NULL != wsh->etag) &&
+ (0 == strcmp (etag,
+ wsh->etag)) )
+ {
+ MHD_RESULT ret;
+ struct MHD_Response *resp;
+
+ resp = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ TALER_MHD_add_global_headers (resp);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_EXPIRES,
+ wsh->dat));
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_ETAG,
+ wsh->etag));
+ ret = MHD_queue_response (rc->connection,
+ MHD_HTTP_NOT_MODIFIED,
+ resp);
+ GNUNET_break (MHD_YES == ret);
+ MHD_destroy_response (resp);
+ return ret;
+ }
+ }
+ return MHD_queue_response (rc->connection,
+ wsh->http_status,
+ wsh->wire_reply);
+}
+
+
+const struct TALER_WireFeeSet *
+TEH_wire_fees_by_time (
+ struct GNUNET_TIME_Timestamp ts,
+ const char *method)
+{
+ struct WireStateHandle *wsh = get_wire_state ();
+
+ for (struct WireFeeSet *wfs = wsh->wfs_head;
+ NULL != wfs;
+ wfs = wfs->next)
+ {
+ if (0 != strcmp (method,
+ wfs->method))
+ continue;
+ if ( (GNUNET_TIME_timestamp_cmp (wfs->start_date,
+ >,
+ ts)) ||
+ (GNUNET_TIME_timestamp_cmp (ts,
+ >=,
+ wfs->end_date)) )
+ continue;
+ return &wfs->fees;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No wire fees for method `%s' at %s configured\n",
+ method,
+ GNUNET_TIME_timestamp2s (ts));
+ return NULL;
+}
+
+
+/**
* Function called to forcefully resume suspended keys requests.
*
* @param cls unused, NULL
@@ -1673,6 +2323,7 @@ add_denom_key_cb (void *cls,
*/
static enum GNUNET_GenericReturnValue
setup_general_response_headers (struct TEH_KeyStateHandle *ksh,
+ struct WireStateHandle *wsh,
struct MHD_Response *response)
{
char dat[128];
@@ -1692,12 +2343,17 @@ setup_general_response_headers (struct TEH_KeyStateHandle *ksh,
{
struct GNUNET_TIME_Relative r;
struct GNUNET_TIME_Absolute a;
+ struct GNUNET_TIME_Timestamp km;
struct GNUNET_TIME_Timestamp m;
+ struct GNUNET_TIME_Timestamp we;
r = GNUNET_TIME_relative_min (TEH_max_keys_caching,
ksh->rekey_frequency);
a = GNUNET_TIME_relative_to_absolute (r);
- m = GNUNET_TIME_absolute_to_timestamp (a);
+ km = GNUNET_TIME_absolute_to_timestamp (a);
+ we = GNUNET_TIME_absolute_to_timestamp (wsh->cache_expiration);
+ m = GNUNET_TIME_timestamp_min (we,
+ km);
TALER_MHD_get_date_string (m.abs_time,
dat);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -1777,8 +2433,10 @@ create_krd (struct TEH_KeyStateHandle *ksh,
struct TALER_ExchangeSignatureP exchange_sig;
struct TALER_ExchangePublicKeyP grouped_exchange_pub;
struct TALER_ExchangeSignatureP grouped_exchange_sig;
+ struct WireStateHandle *wsh;
json_t *keys;
+ wsh = get_wire_state ();
GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
last_cherry_pick_date.abs_time));
GNUNET_assert (NULL != signkeys);
@@ -1850,6 +2508,12 @@ create_krd (struct TEH_KeyStateHandle *ksh,
ksh->signature_expires);
}
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Build /keys data with %u wire accounts\n",
+ (unsigned int) json_array_size (
+ json_object_get (wsh->json_reply,
+ "accounts")));
+
keys = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("version",
EXCHANGE_PROTOCOL_VERSION),
@@ -1874,6 +2538,15 @@ create_krd (struct TEH_KeyStateHandle *ksh,
recoup),
GNUNET_JSON_pack_array_incref ("denoms",
denoms),
+ GNUNET_JSON_pack_array_incref ("wads",
+ json_object_get (wsh->json_reply,
+ "wads")),
+ GNUNET_JSON_pack_array_incref ("accounts",
+ json_object_get (wsh->json_reply,
+ "accounts")),
+ GNUNET_JSON_pack_object_incref ("wire_fees",
+ json_object_get (wsh->json_reply,
+ "fees")),
GNUNET_JSON_pack_array_incref ("denominations",
grouped_denominations),
GNUNET_JSON_pack_array_incref ("auditors",
@@ -2010,6 +2683,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
GNUNET_assert (NULL != krd.response_uncompressed);
GNUNET_assert (GNUNET_OK ==
setup_general_response_headers (ksh,
+ wsh,
krd.response_uncompressed));
GNUNET_break (MHD_YES ==
MHD_add_response_header (krd.response_uncompressed,
@@ -2032,7 +2706,18 @@ create_krd (struct TEH_KeyStateHandle *ksh,
"deflate")) );
GNUNET_assert (GNUNET_OK ==
setup_general_response_headers (ksh,
+ wsh,
krd.response_compressed));
+ /* Set cache control headers: our response varies depending on these headers */
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (wsh->wire_reply,
+ MHD_HTTP_HEADER_VARY,
+ MHD_HTTP_HEADER_ACCEPT_ENCODING));
+ /* Information is always public, revalidate after 1 day */
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (wsh->wire_reply,
+ MHD_HTTP_HEADER_CACHE_CONTROL,
+ "public,max-age=86400"));
GNUNET_break (MHD_YES ==
MHD_add_response_header (krd.response_compressed,
MHD_HTTP_HEADER_ETAG,
@@ -2290,8 +2975,18 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
/* Now that we have found/created the right group, add the
denomination to the list */
{
+ struct HelperDenomination *hd;
struct GNUNET_JSON_PackSpec key_spec;
-
+ bool private_key_lost;
+
+ hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ &dk->h_denom_pub.hash);
+ private_key_lost
+ = (NULL == hd) ||
+ GNUNET_TIME_absolute_is_past (
+ GNUNET_TIME_absolute_add (
+ hd->start_time.abs_time,
+ hd->validity_duration));
switch (meta.cipher)
{
case TALER_DENOMINATION_RSA:
@@ -2314,6 +3009,12 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
entry = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("master_sig",
&dk->master_sig),
+ GNUNET_JSON_pack_allow_null (
+ private_key_lost
+ ? GNUNET_JSON_pack_bool ("lost",
+ true)
+ : GNUNET_JSON_pack_string ("dummy",
+ NULL)),
GNUNET_JSON_pack_timestamp ("stamp_start",
dk->meta.start),
GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
@@ -2666,7 +3367,7 @@ keys_get_state (bool management_only)
if ( (old_ksh->key_generation < key_generation) ||
(GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) )
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Rebuilding /keys, generation upgrade from %llu to %llu\n",
(unsigned long long) old_ksh->key_generation,
(unsigned long long) key_generation);
@@ -3195,7 +3896,9 @@ TEH_keys_get_handler (struct TEH_RequestContext *rc,
{
struct GNUNET_TIME_Timestamp last_issue_date;
const char *etag;
+ struct WireStateHandle *wsh;
+ wsh = get_wire_state ();
etag = MHD_lookup_connection_value (rc->connection,
MHD_HEADER_KIND,
MHD_HTTP_HEADER_IF_NONE_MATCH);
@@ -3293,6 +3996,7 @@ TEH_keys_get_handler (struct TEH_RequestContext *rc,
TALER_MHD_add_global_headers (resp);
GNUNET_break (GNUNET_OK ==
setup_general_response_headers (ksh,
+ wsh,
resp));
GNUNET_break (MHD_YES ==
MHD_add_response_header (resp,