diff --git a/src/exchange-tools/taler-auditor-offline.c b/src/exchange-tools/taler-auditor-offline.c index 39495311c..38260abc2 100644 --- a/src/exchange-tools/taler-auditor-offline.c +++ b/src/exchange-tools/taler-auditor-offline.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020-2021 Taler Systems SA + Copyright (C) 2020-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 @@ -174,7 +174,7 @@ static struct DenominationAddRequest *dar_tail; /** * Handle to the exchange, used to request /keys. */ -static struct TALER_EXCHANGE_Handle *exchange; +static struct TALER_EXCHANGE_GetKeysHandle *exchange; /** @@ -219,7 +219,7 @@ do_shutdown (void *cls) } if (NULL != exchange) { - TALER_EXCHANGE_disconnect (exchange); + TALER_EXCHANGE_get_keys_cancel (exchange); exchange = NULL; } if (NULL != nxt) @@ -646,22 +646,23 @@ do_upload (char *const *args) * * @param cls closure with the `char **` remaining args * @param kr response data + * @param keys key data from the exchange */ static void keys_cb ( void *cls, - const struct TALER_EXCHANGE_KeysResponse *kr) + const struct TALER_EXCHANGE_KeysResponse *kr, + struct TALER_EXCHANGE_Keys *keys) { char *const *args = cls; + exchange = NULL; switch (kr->hr.http_status) { case MHD_HTTP_OK: - if (! json_is_object (kr->hr.reply)) + if (NULL == kr->hr.reply) { GNUNET_break (0); - TALER_EXCHANGE_disconnect (exchange); - exchange = NULL; test_shutdown (); global_ret = EXIT_FAILURE; return; @@ -673,8 +674,6 @@ keys_cb ( kr->hr.hint, kr->hr.http_status, (unsigned int) kr->hr.ec); - TALER_EXCHANGE_disconnect (exchange); - exchange = NULL; test_shutdown (); global_ret = EXIT_FAILURE; return; @@ -692,9 +691,8 @@ keys_cb ( json_decref (in); in = NULL; } - TALER_EXCHANGE_disconnect (exchange); - exchange = NULL; next (args); + TALER_EXCHANGE_keys_decref (keys); } @@ -721,11 +719,11 @@ do_download (char *const *args) global_ret = EXIT_NOTCONFIGURED; return; } - exchange = TALER_EXCHANGE_connect (ctx, - exchange_url, - &keys_cb, - (void *) args, - TALER_EXCHANGE_OPTION_END); + exchange = TALER_EXCHANGE_get_keys (ctx, + exchange_url, + NULL, + &keys_cb, + (void *) args); GNUNET_free (exchange_url); } diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index dbc591a6f..35a688726 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -32,27 +32,6 @@ /* ********************* /keys *********************** */ -/** - * List of possible options to be passed to - * #TALER_EXCHANGE_connect(). - */ -enum TALER_EXCHANGE_Option -{ - /** - * Terminator (end of option list). - */ - TALER_EXCHANGE_OPTION_END = 0, - - /** - * Followed by a "const json_t *" that was previously returned for - * this exchange URL by #TALER_EXCHANGE_serialize_data(). Used to - * resume a connection to an exchange without having to re-download - * /keys data (or at least only download the deltas). - */ - TALER_EXCHANGE_OPTION_DATA - -}; - /** * @brief Exchange's signature key @@ -294,11 +273,18 @@ struct TALER_EXCHANGE_Keys char *currency; /** - * How long after a reserve went idle will the exchange close it? - * This is an approximate number, not cryptographically signed by - * the exchange (advisory-only, may change anytime). + * What is the base URL of the exchange that returned + * these keys? */ - struct GNUNET_TIME_Relative reserve_closing_delay; + char *exchange_url; + + /** + * Asset type used by the exchange. Typical values + * are "fiat" or "crypto" or "regional" or "stock". + * Wallets should adjust their UI/UX based on this + * value. + */ + char *asset_type; /** * Array of amounts a wallet is allowed to hold from @@ -307,16 +293,22 @@ struct TALER_EXCHANGE_Keys struct TALER_Amount *wallet_balance_limit_without_kyc; /** - * Length of the @e wallet_balance_limit_without_kyc - * array. + * How long after a reserve went idle will the exchange close it? + * This is an approximate number, not cryptographically signed by + * the exchange (advisory-only, may change anytime). */ - unsigned int wblwk_length; + struct GNUNET_TIME_Relative reserve_closing_delay; /** * Timestamp indicating the /keys generation. */ struct GNUNET_TIME_Timestamp list_issue_date; + /** + * When does this keys data expire? + */ + struct GNUNET_TIME_Timestamp key_data_expiration; + /** * Timestamp indicating the creation time of the last * denomination key in /keys. @@ -329,6 +321,12 @@ struct TALER_EXCHANGE_Keys */ struct TALER_AgeMask age_mask; + /** + * Length of the @e wallet_balance_limit_without_kyc + * array. + */ + unsigned int wblwk_length; + /** * Length of the @e global_fees array. */ @@ -360,12 +358,10 @@ struct TALER_EXCHANGE_Keys unsigned int denom_keys_size; /** - * Asset type used by the exchange. Typical values - * are "fiat" or "crypto" or "regional" or "stock". - * Wallets should adjust their UI/UX based on this - * value. + * Reference counter for this structure. + * Freed when it reaches 0. */ - char *asset_type; + unsigned int rc; /** * Set to true if tipping is allowed at this exchange. @@ -505,77 +501,82 @@ struct TALER_EXCHANGE_KeysResponse /** * 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 + * the callee, thus it is given explicitly and not + * (only) via @a kr. * * @param cls closure * @param kr response from /keys + * @param[in] keys keys object passed to callback with + * reference counter of 1. Must be freed by callee + * using #TALER_EXCHANGE_keys_decref(). NULL on failure. */ typedef void -(*TALER_EXCHANGE_CertificationCallback) ( +(*TALER_EXCHANGE_GetKeysCallback) ( void *cls, - const struct TALER_EXCHANGE_KeysResponse *kr); + const struct TALER_EXCHANGE_KeysResponse *kr, + struct TALER_EXCHANGE_Keys *keys); /** - * @brief Handle to the exchange. This is where we interact with - * a particular exchange and keep the per-exchange information. + * @brief Handle for a GET /keys request. */ -struct TALER_EXCHANGE_Handle; +struct TALER_EXCHANGE_GetKeysHandle; /** - * Initialise a connection to the exchange. Will connect to the - * exchange and obtain information about the exchange's master public - * key and the exchange's auditor. The respective information will - * be passed to the @a cert_cb once available, and all future - * interactions with the exchange will be checked to be signed - * (where appropriate) by the respective master key. + * Fetch the main /keys resources from ane 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). * * @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 * @param cert_cb_cls closure for @a cert_cb - * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END. * @return the exchange handle; NULL upon error */ -struct TALER_EXCHANGE_Handle * -TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx, - const char *url, - TALER_EXCHANGE_CertificationCallback cert_cb, - void *cert_cb_cls, - ...); +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); /** - * Serialize the latest key data from @a exchange to be persisted - * on disk (to be used with #TALER_EXCHANGE_OPTION_DATA to more - * efficiently recover the state). + * Serialize the latest data from @a keys to be persisted + * (for example, to be used as @a last_keys later). * - * @param exchange which exchange's key and wire data should be serialized - * @return NULL on error (i.e. no current data available); otherwise - * json object owned by the caller + * @param kd the key data to serialize + * @return NULL on error; otherwise JSON object owned by the caller */ json_t * -TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange); +TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd); /** - * Disconnect from the exchange. + * Deserialize keys data stored in @a j. * - * @param exchange the exchange handle - */ -void -TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange); - - -/** - * Obtain the keys from the exchange. - * - * @param exchange the exchange handle - * @return the exchange's key set + * @param j JSON keys data previously returned from #TALER_EXCHANGE_keys_to_json() + * @return NULL on error (i.e. invalid JSON); otherwise + * keys object with reference counter 1 owned by the caller */ struct TALER_EXCHANGE_Keys * -TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange); +TALER_EXCHANGE_keys_from_json (const json_t *j); + + +/** + * Cancel GET /keys operation. + * + * @param[in] gkh the GET /keys handle + */ +void +TALER_EXCHANGE_get_keys_cancel (struct TALER_EXCHANGE_GetKeysHandle *gkh); /** @@ -598,90 +599,6 @@ void TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys); -/** - * Let the user set the last valid denomination time manually. - * - * @param exchange the exchange handle. - * @param last_denom_new new last denomination time. - */ -void -TALER_EXCHANGE_set_last_denom ( - struct TALER_EXCHANGE_Handle *exchange, - struct GNUNET_TIME_Timestamp last_denom_new); - - -/** - * Flags for #TALER_EXCHANGE_check_keys_current(). - */ -enum TALER_EXCHANGE_CheckKeysFlags -{ - /** - * No special options. - */ - TALER_EXCHANGE_CKF_NONE, - - /** - * Force downloading /keys now, even if /keys is still valid - * (that is, the period advertised by the exchange for re-downloads - * has not yet expired). - */ - TALER_EXCHANGE_CKF_FORCE_DOWNLOAD = 1, - - /** - * Pull all keys again, resetting the client state to the original state. - * Using this flag disables the incremental download, and also prevents using - * the context until the re-download has completed. - */ - TALER_EXCHANGE_CKF_PULL_ALL_KEYS = 2, - - /** - * Force downloading all keys now. - */ - TALER_EXCHANGE_CKF_FORCE_ALL_NOW = TALER_EXCHANGE_CKF_FORCE_DOWNLOAD - | TALER_EXCHANGE_CKF_PULL_ALL_KEYS - -}; - - -/** - * Check if our current response for /keys is valid, and if - * not, trigger /keys download. If @a cb is given, changes - * the @a exchange callback for the /keys response. - * - * @param exchange exchange to check keys for - * @param flags options controlling when to download what - * @param cb function to call with the /keys response, can be NULL - * @param cb_cls closure for @a cb - * @return until when the existing response is current, 0 if we are re-downloading now - */ -struct GNUNET_TIME_Timestamp -TALER_EXCHANGE_check_keys_current ( - struct TALER_EXCHANGE_Handle *exchange, - enum TALER_EXCHANGE_CheckKeysFlags flags, - TALER_EXCHANGE_CertificationCallback cb, - void *cb_cls); - - -/** - * Obtain the keys from the exchange in the raw JSON format. - * - * @param exchange the exchange handle - * @return the exchange's keys in raw JSON - */ -json_t * -TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange); - - -/** - * Obtain the keys from the exchange in the raw JSON format. - * - * @param keys the keys structure - * @return the keys in raw JSON - */ -json_t * -TALER_EXCHANGE_keys_to_json (struct TALER_EXCHANGE_Keys *keys); - - /** * Test if the given @a pub is a the current signing key from the exchange * according to @a keys. @@ -691,18 +608,9 @@ TALER_EXCHANGE_keys_to_json (struct TALER_EXCHANGE_Keys *keys); * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key */ enum GNUNET_GenericReturnValue -TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_ExchangePublicKeyP *pub); - - -/** - * Get exchange's base URL. - * - * @param exchange exchange handle. - * @return the base URL from the handle. - */ -const char * -TALER_EXCHANGE_get_base_url (const struct TALER_EXCHANGE_Handle *exchange); +TALER_EXCHANGE_test_signing_key ( + const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_ExchangePublicKeyP *pub); /** @@ -736,7 +644,8 @@ TALER_EXCHANGE_get_global_fee ( * Create a copy of a denomination public key. * * @param key key to copy - * @returns a copy, must be freed with #TALER_EXCHANGE_destroy_denomination_key + * @returns a copy, must be freed with #TALER_EXCHANGE_destroy_denomination_key() + * @deprecated */ struct TALER_EXCHANGE_DenomPublicKey * TALER_EXCHANGE_copy_denomination_key ( @@ -745,9 +654,10 @@ TALER_EXCHANGE_copy_denomination_key ( /** * Destroy a denomination public key. - * Should only be called with keys created by #TALER_EXCHANGE_copy_denomination_key. + * Should only be called with keys created by #TALER_EXCHANGE_copy_denomination_key(). * * @param key key to destroy. + * @deprecated */ void TALER_EXCHANGE_destroy_denomination_key ( diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 8950e71ba..332c3a347 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -1797,17 +1797,6 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_check_keys (const char *label); -/** - * Make a "check keys" command that forcedly does NOT cherry pick; - * just redownload the whole /keys. - * - * @param label command label - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label); - - /** * Make a "check keys" command. It lets the user set a last denom issue date to be * used in the request for /keys. @@ -2703,7 +2692,6 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, op (fresh_coins, const struct TALER_TESTING_FreshCoinData *) \ op (claim_token, const struct TALER_ClaimTokenP) \ op (relative_time, const struct GNUNET_TIME_Relative) \ - op (exchange, struct TALER_EXCHANGE_Handle) \ op (fakebank, struct TALER_FAKEBANK_Handle) \ op (keys, struct TALER_EXCHANGE_Keys) \ op (process, struct GNUNET_OS_Process *) @@ -2742,16 +2730,6 @@ TALER_TESTING_INDEXED_TRAITS (TALER_TESTING_MAKE_DECL_INDEXED_TRAIT) /* ****************** convenience functions ************** */ -/** - * Get exchange handle from interpreter. Convenience function. - * - * @param is interpreter state. - * @return the exchange handle, or NULL on error - */ -struct TALER_EXCHANGE_Handle * -TALER_TESTING_get_exchange (struct TALER_TESTING_Interpreter *is); - - /** * Get exchange URL from interpreter. Convenience function. * diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 0bb3c2085..7fcb590a3 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -47,6 +47,11 @@ */ #define EXCHANGE_PROTOCOL_AGE 0 +/** + * Set to 1 for extra debug logging. + */ +#define DEBUG 0 + /** * Current version for (local) JSON serialization of persisted * /keys data. @@ -64,85 +69,28 @@ */ #define DEFAULT_EXPIRATION GNUNET_TIME_UNIT_HOURS -/** - * Set to 1 for extra debug logging. - */ -#define DEBUG 0 /** - * Log error related to CURL operations. - * - * @param type log level - * @param function which function failed to run - * @param code what was the curl error code + * Handle for a GET /keys request. */ -#define CURL_STRERROR(type, function, code) \ - GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \ - function, __FILE__, __LINE__, curl_easy_strerror (code)); - - -/** - * Data for the request to get the /keys of a exchange. - */ -struct KeysRequest; - - -/** - * Entry in DLL of auditors used by an exchange. - */ -struct TEAH_AuditorListEntry +struct TALER_EXCHANGE_GetKeysHandle { + /** - * Next pointer of DLL. + * The exchange base URL (i.e. "http://exchange.taler.net/") */ - struct TEAH_AuditorListEntry *next; + char *exchange_url; /** - * Prev pointer of DLL. - */ - struct TEAH_AuditorListEntry *prev; - - /** - * Base URL of the auditor. - */ - char *auditor_url; - - /** - * Handle to the auditor. - */ - struct TALER_AUDITOR_GetConfigHandle *ah; - - /** - * Public key of the auditor. - */ - struct TALER_AuditorPublicKeyP auditor_pub; - - /** - * Flag indicating that the auditor is available and that protocol - * version compatibility is given. - */ - bool is_up; - -}; - - -/* ***************** Internal /keys fetching ************* */ - -/** - * Data for the request to get the /keys of a exchange. - */ -struct KeysRequest -{ - /** - * The connection to exchange this request handle will use - */ - struct TALER_EXCHANGE_Handle *exchange; - - /** - * The url for this handle + * 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`. */ @@ -154,13 +102,25 @@ struct KeysRequest */ 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; + }; void -TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys, - TEAH_AuditorCallback ac, - void *ac_cls) +TEAH_get_auditors_for_dc ( + struct TALER_EXCHANGE_Keys *keys, + TEAH_AuditorCallback ac, + void *ac_cls) { if (0 == keys->num_auditors) { @@ -180,20 +140,6 @@ TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys, } -/** - * Release memory occupied by a keys request. Note that this does not - * cancel the request itself. - * - * @param kr request to free - */ -static void -free_keys_request (struct KeysRequest *kr) -{ - GNUNET_free (kr->url); - GNUNET_free (kr); -} - - #define EXITIF(cond) \ do { \ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ @@ -205,21 +151,20 @@ free_keys_request (struct KeysRequest *kr) * * @param[out] sign_key where to return the result * @param check_sigs should we check signatures? - * @param[in] sign_key_obj json to parse + * @param sign_key_obj json to parse * @param master_key master key to use to verify signature * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is - * invalid or the json malformed. + * invalid or the @a sign_key_obj is malformed. */ static enum GNUNET_GenericReturnValue parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, bool check_sigs, - json_t *sign_key_obj, + const json_t *sign_key_obj, const struct TALER_MasterPublicKeyP *master_key) { - struct TALER_MasterSignatureP sign_key_issue_sig; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("master_sig", - &sign_key_issue_sig), + &sign_key->master_sig), GNUNET_JSON_spec_fixed_auto ("key", &sign_key->key), GNUNET_JSON_spec_timestamp ("stamp_start", @@ -239,7 +184,6 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, GNUNET_break_op (0); return GNUNET_SYSERR; } - if (! check_sigs) return GNUNET_OK; if (GNUNET_OK != @@ -249,12 +193,11 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, sign_key->valid_until, sign_key->valid_legal, master_key, - &sign_key_issue_sig)) + &sign_key->master_sig)) { GNUNET_break_op (0); return GNUNET_SYSERR; } - sign_key->master_sig = sign_key_issue_sig; return GNUNET_OK; } @@ -270,9 +213,9 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, * @param[out] denom_key where to return the result * @param cipher cipher type to parse * @param check_sigs should we check signatures? - * @param[in] denom_key_obj json to parse + * @param denom_key_obj json to parse * @param master_key master key to use to verify signature - * @param hash_xor where to accumulate data for signature verification via XOR + * @param[in,out] hash_xor where to accumulate data for signature verification via XOR * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is * invalid or the json malformed. */ @@ -281,7 +224,7 @@ parse_json_denomkey_partially ( struct TALER_EXCHANGE_DenomPublicKey *denom_key, enum TALER_DenominationCipher cipher, bool check_sigs, - json_t *denom_key_obj, + const json_t *denom_key_obj, struct TALER_MasterPublicKeyP *master_key, struct GNUNET_HashCode *hash_xor) { @@ -316,7 +259,6 @@ parse_json_denomkey_partially ( GNUNET_CRYPTO_hash_xor (&denom_key->h_key.hash, hash_xor, hash_xor); - if (! check_sigs) return GNUNET_OK; EXITIF (GNUNET_SYSERR == @@ -346,7 +288,7 @@ EXITIF_exit: * * @param[out] auditor where to return the result * @param check_sigs should we check signatures - * @param[in] auditor_obj json to parse + * @param auditor_obj json to parse * @param key_data information about denomination keys * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is * invalid or the json malformed. @@ -354,14 +296,12 @@ EXITIF_exit: static enum GNUNET_GenericReturnValue parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, bool check_sigs, - json_t *auditor_obj, + const json_t *auditor_obj, const struct TALER_EXCHANGE_Keys *key_data) { const json_t *keys; json_t *key; - unsigned int len; unsigned int off; - unsigned int i; const char *auditor_url; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("auditor_pub", @@ -387,16 +327,15 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, return GNUNET_SYSERR; } auditor->auditor_url = GNUNET_strdup (auditor_url); - len = json_array_size (keys); - auditor->denom_keys = GNUNET_new_array (len, - struct - TALER_EXCHANGE_AuditorDenominationInfo); - off = 0; - json_array_foreach (keys, i, key) { + auditor->denom_keys + = GNUNET_new_array (json_array_size (keys), + struct TALER_EXCHANGE_AuditorDenominationInfo); + + json_array_foreach (keys, off, key) { struct TALER_AuditorSignatureP auditor_sig; struct TALER_DenominationHashP denom_h; - const struct TALER_EXCHANGE_DenomPublicKey *dk; - unsigned int dk_off; + const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL; + unsigned int dk_off = UINT_MAX; struct GNUNET_JSON_Specification kspec[] = { GNUNET_JSON_spec_fixed_auto ("auditor_sig", &auditor_sig), @@ -413,8 +352,6 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, GNUNET_break_op (0); continue; } - dk = NULL; - dk_off = UINT_MAX; for (unsigned int j = 0; jnum_denom_keys; j++) { if (0 == GNUNET_memcmp (&denom_h, @@ -454,7 +391,6 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, } auditor->denom_keys[off].denom_key_offset = dk_off; auditor->denom_keys[off].auditor_sig = auditor_sig; - off++; } auditor->num_denom_keys = off; return GNUNET_OK; @@ -466,7 +402,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, * * @param[out] gf where to return the result * @param check_sigs should we check signatures - * @param[in] fee_obj json to parse + * @param fee_obj json to parse * @param key_data already parsed information about the exchange * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is * invalid or the json malformed. @@ -474,7 +410,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, static enum GNUNET_GenericReturnValue parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf, bool check_sigs, - json_t *fee_obj, + const json_t *fee_obj, const struct TALER_EXCHANGE_Keys *key_data) { struct GNUNET_JSON_Specification spec[] = { @@ -531,104 +467,6 @@ parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf, } -/** - * Function called with information about the auditor. Marks an - * auditor as 'up'. - * - * @param cls closure, a `struct TEAH_AuditorListEntry *` - * @param vr response from the auditor - */ -static void -auditor_config_cb ( - void *cls, - const struct TALER_AUDITOR_ConfigResponse *vr) -{ - struct TEAH_AuditorListEntry *ale = cls; - enum TALER_AUDITOR_VersionCompatibility compat; - - ale->ah = NULL; - if (MHD_HTTP_OK != vr->hr.http_status) - { - /* In this case, we don't mark the auditor as 'up' */ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Auditor `%s' gave unexpected version response.\n", - ale->auditor_url); - return; - } - compat = vr->details.ok.compat; - if (0 != (TALER_AUDITOR_VC_INCOMPATIBLE & compat)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Auditor `%s' runs incompatible protocol version!\n", - ale->auditor_url); - if (0 != (TALER_AUDITOR_VC_OLDER & compat)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Auditor `%s' runs outdated protocol version!\n", - ale->auditor_url); - } - if (0 != (TALER_AUDITOR_VC_NEWER & compat)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Auditor `%s' runs more recent incompatible version. We should upgrade!\n", - ale->auditor_url); - } - return; - } - ale->is_up = true; -} - - -/** - * Recalculate our auditor list, we got /keys and it may have - * changed. - * - * @param exchange exchange for which to update the list. - */ -static void -update_auditors (struct TALER_EXCHANGE_Handle *exchange) -{ - struct TALER_EXCHANGE_Keys *kd = &exchange->key_data; - - TALER_LOG_DEBUG ("Updating auditors\n"); - for (unsigned int i = 0; inum_auditors; i++) - { - /* Compare auditor data from /keys with auditor data - * from owned exchange structures. */ - struct TALER_EXCHANGE_AuditorInformation *auditor = &kd->auditors[i]; - struct TEAH_AuditorListEntry *ale = NULL; - - for (struct TEAH_AuditorListEntry *a = exchange->auditors_head; - NULL != a; - a = a->next) - { - if (0 == GNUNET_memcmp (&auditor->auditor_pub, - &a->auditor_pub)) - { - ale = a; - break; - } - } - if (NULL != ale) - continue; /* found, no need to add */ - - /* new auditor, add */ - TALER_LOG_DEBUG ("Found new auditor %s!\n", - auditor->auditor_url); - ale = GNUNET_new (struct TEAH_AuditorListEntry); - ale->auditor_pub = auditor->auditor_pub; - ale->auditor_url = GNUNET_strdup (auditor->auditor_url); - GNUNET_CONTAINER_DLL_insert (exchange->auditors_head, - exchange->auditors_tail, - ale); - ale->ah = TALER_AUDITOR_get_config (exchange->ctx, - ale->auditor_url, - &auditor_config_cb, - ale); - } -} - - /** * Compare two denomination keys. Ignores revocation data. * @@ -683,35 +521,16 @@ decode_keys_json (const json_t *resp_obj, struct TALER_ExchangeSignatureP denominations_sig; struct GNUNET_HashCode hash_xor = {0}; struct TALER_ExchangePublicKeyP pub; - const char *currency; - const char *asset_type; - bool tipping_allowed = true; const json_t *wblwk = NULL; - struct GNUNET_JSON_Specification mspec[] = { - GNUNET_JSON_spec_fixed_auto ("denominations_sig", - &denominations_sig), - GNUNET_JSON_spec_fixed_auto ("eddsa_pub", - &pub), - GNUNET_JSON_spec_fixed_auto ("master_public_key", - &key_data->master_pub), - GNUNET_JSON_spec_timestamp ("list_issue_date", - &key_data->list_issue_date), - GNUNET_JSON_spec_relative_time ("reserve_closing_delay", - &key_data->reserve_closing_delay), - GNUNET_JSON_spec_string ("currency", - ¤cy), - GNUNET_JSON_spec_string ("asset_type", - &asset_type), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_bool ("tipping_allowed", - &tipping_allowed), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_array_const ("wallet_balance_limit_without_kyc", - &wblwk), - NULL), - GNUNET_JSON_spec_end () - }; + const json_t *global_fees; + const json_t *sign_keys_array; + const json_t *denominations_by_group; + const json_t *auditors_array; + const json_t *recoup_array = NULL; + struct TALER_MasterSignatureP extensions_sig = {0}; + const json_t *manifests = NULL; + bool no_extensions = false; + bool no_signature = false; if (JSON_OBJECT != json_typeof (resp_obj)) { @@ -770,63 +589,116 @@ decode_keys_json (const json_t *resp_obj, key_data->version = GNUNET_strdup (ver); } - EXITIF (GNUNET_OK != - GNUNET_JSON_parse (resp_obj, - (check_sig) ? mspec : &mspec[2], - NULL, NULL)); - key_data->currency = GNUNET_strdup (currency); - key_data->asset_type = GNUNET_strdup (asset_type); - key_data->tipping_allowed = tipping_allowed; + { + const char *currency; + const char *asset_type; + struct GNUNET_JSON_Specification mspec[] = { + GNUNET_JSON_spec_fixed_auto ( + "denominations_sig", + &denominations_sig), + GNUNET_JSON_spec_fixed_auto ( + "eddsa_pub", + &pub), + GNUNET_JSON_spec_fixed_auto ( + "master_public_key", + &key_data->master_pub), + GNUNET_JSON_spec_timestamp ( + "list_issue_date", + &key_data->list_issue_date), + GNUNET_JSON_spec_relative_time ( + "reserve_closing_delay", + &key_data->reserve_closing_delay), + GNUNET_JSON_spec_string ( + "currency", + ¤cy), + GNUNET_JSON_spec_string ( + "asset_type", + &asset_type), + GNUNET_JSON_spec_array_const ( + "global_fees", + &global_fees), + GNUNET_JSON_spec_array_const ( + "signkeys", + &sign_keys_array), + GNUNET_JSON_spec_array_const ( + "denominations", + &denominations_by_group), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_array_const ( + "recoup", + &recoup_array), + NULL), + GNUNET_JSON_spec_array_const ( + "auditors", + &auditors_array), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_bool ( + "tipping_allowed", + &key_data->tipping_allowed), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_object_const ("extensions", + &manifests), + &no_extensions), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ( + "extensions_sig", + &extensions_sig), + &no_signature), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_array_const ( + "wallet_balance_limit_without_kyc", + &wblwk), + NULL), + GNUNET_JSON_spec_end () + }; + + EXITIF (GNUNET_OK != + GNUNET_JSON_parse (resp_obj, + (check_sig) ? mspec : &mspec[2], + NULL, NULL)); + key_data->currency = GNUNET_strdup (currency); + key_data->asset_type = GNUNET_strdup (asset_type); + } /* parse the global fees */ + key_data->num_global_fees + = json_array_size (global_fees); + if (0 != key_data->num_global_fees) { - json_t *global_fees; json_t *global_fee; unsigned int index; - EXITIF (NULL == (global_fees = - json_object_get (resp_obj, - "global_fees"))); - EXITIF (! json_is_array (global_fees)); - if (0 != (key_data->num_global_fees = - json_array_size (global_fees))) + key_data->global_fees + = GNUNET_new_array (key_data->num_global_fees, + struct TALER_EXCHANGE_GlobalFee); + json_array_foreach (global_fees, index, global_fee) { - key_data->global_fees - = GNUNET_new_array (key_data->num_global_fees, - struct TALER_EXCHANGE_GlobalFee); - json_array_foreach (global_fees, index, global_fee) { - EXITIF (GNUNET_SYSERR == - parse_global_fee (&key_data->global_fees[index], - check_sig, - global_fee, - key_data)); - } + EXITIF (GNUNET_SYSERR == + parse_global_fee (&key_data->global_fees[index], + check_sig, + global_fee, + key_data)); } } /* parse the signing keys */ + key_data->num_sign_keys + = json_array_size (sign_keys_array); + if (0 != key_data->num_sign_keys) { - json_t *sign_keys_array; json_t *sign_key_obj; unsigned int index; - EXITIF (NULL == (sign_keys_array = - json_object_get (resp_obj, - "signkeys"))); - EXITIF (! json_is_array (sign_keys_array)); - if (0 != (key_data->num_sign_keys = - json_array_size (sign_keys_array))) - { - key_data->sign_keys - = GNUNET_new_array (key_data->num_sign_keys, - struct TALER_EXCHANGE_SigningPublicKey); - json_array_foreach (sign_keys_array, index, sign_key_obj) { - EXITIF (GNUNET_SYSERR == - parse_json_signkey (&key_data->sign_keys[index], - check_sig, - sign_key_obj, - &key_data->master_pub)); - } + key_data->sign_keys + = GNUNET_new_array (key_data->num_sign_keys, + struct TALER_EXCHANGE_SigningPublicKey); + json_array_foreach (sign_keys_array, index, sign_key_obj) { + EXITIF (GNUNET_SYSERR == + parse_json_signkey (&key_data->sign_keys[index], + check_sig, + sign_key_obj, + &key_data->master_pub)); } } @@ -844,7 +716,7 @@ decode_keys_json (const json_t *resp_obj, i); struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount (NULL, - currency, + key_data->currency, a), GNUNET_JSON_spec_end () }; @@ -858,51 +730,28 @@ decode_keys_json (const json_t *resp_obj, /* Parse the supported extension(s): age-restriction. */ /* TODO: maybe lift all this into a FP in TALER_Extension ? */ + if (! no_extensions) { - struct TALER_MasterSignatureP extensions_sig = {0}; - const json_t *manifests = NULL; - bool no_extensions = false; - bool no_signature = false; - - struct GNUNET_JSON_Specification ext_spec[] = { - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_object_const ("extensions", - &manifests), - &no_extensions), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ( - "extensions_sig", - &extensions_sig), - &no_signature), - GNUNET_JSON_spec_end () - }; - - /* 1. Search for extensions in the response to /keys */ - EXITIF (GNUNET_OK != - GNUNET_JSON_parse (resp_obj, - ext_spec, - NULL, NULL)); - - - if (! no_extensions && no_signature) + if (no_signature) + { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "found extensions without signature\n"); - - if (! no_extensions && ! no_signature) + } + else { - /* 2. We have an extensions object. Verify its signature. */ + /* We have an extensions object. Verify its signature. */ EXITIF (GNUNET_OK != TALER_extensions_verify_manifests_signature ( manifests, &extensions_sig, &key_data->master_pub)); - /* 3. Parse and set the the configuration of the extensions accordingly */ + /* Parse and set the the configuration of the extensions accordingly */ EXITIF (GNUNET_OK != TALER_extensions_load_manifests (manifests)); } - /* 4. assuming we might have now a new value for age_mask, set it in key_data */ + /* Assuming we might have now a new value for age_mask, set it in key_data */ key_data->age_mask = TALER_extensions_get_age_restriction_mask (); } @@ -912,21 +761,13 @@ decode_keys_json (const json_t *resp_obj, * * The denominations are grouped by common values of * {cipher, value, fee, age_mask}. - **/ + */ { - json_t *denominations_by_group; json_t *group_obj; unsigned int group_idx; - denominations_by_group = - json_object_get ( - resp_obj, - "denominations"); - - EXITIF (JSON_ARRAY != - json_typeof (denominations_by_group)); - - json_array_foreach (denominations_by_group, group_idx, group_obj) { + json_array_foreach (denominations_by_group, group_idx, group_obj) + { /* Running XOR of each SHA512 hash of the denominations' public key in this group. Used to compare against group.hash after all keys have been parsed. */ @@ -935,9 +776,13 @@ decode_keys_json (const json_t *resp_obj, /* First, parse { cipher, fees, value, age_mask, hash } of the current group. */ struct TALER_DenominationGroup group = {0}; + const json_t *denom_keys_array; struct GNUNET_JSON_Specification group_spec[] = { TALER_JSON_spec_denomination_group (NULL, - currency, &group), + key_data->currency, + &group), + GNUNET_JSON_spec_array_const ("denoms", + &denom_keys_array), GNUNET_JSON_spec_end () }; EXITIF (GNUNET_SYSERR == @@ -948,25 +793,21 @@ decode_keys_json (const json_t *resp_obj, /* Now, parse the individual denominations */ { - json_t *denom_keys_array; json_t *denom_key_obj; unsigned int index; - denom_keys_array = json_object_get (group_obj, "denoms"); - EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); - - json_array_foreach (denom_keys_array, index, denom_key_obj) { - struct TALER_EXCHANGE_DenomPublicKey dk = {0}; - bool found = false; - - memset (&dk, 0, sizeof (dk)); + json_array_foreach (denom_keys_array, index, denom_key_obj) + { /* Set the common fields from the group for this particular denomination. Required to make the validity check inside parse_json_denomkey_partially pass */ - dk.key.cipher = group.cipher; - dk.value = group.value; - dk.fees = group.fees; - dk.key.age_mask = group.age_mask; + struct TALER_EXCHANGE_DenomPublicKey dk = { + .key.cipher = group.cipher, + .value = group.value, + .fees = group.fees, + .key.age_mask = group.age_mask + }; + bool found = false; EXITIF (GNUNET_SYSERR == parse_json_denomkey_partially (&dk, @@ -979,7 +820,9 @@ decode_keys_json (const json_t *resp_obj, /* Build the running xor of the SHA512-hash of the public keys */ { struct TALER_DenominationHashP hc = {0}; - TALER_denom_pub_hash (&dk.key, &hc); + + TALER_denom_pub_hash (&dk.key, + &hc); GNUNET_CRYPTO_hash_xor (&hc.hash, &group_hash_xor, &group_hash_xor); @@ -1017,30 +860,26 @@ decode_keys_json (const json_t *resp_obj, key_data->last_denom_issue_date = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date, dk.valid_from); - }; // json_array_foreach over denominations + }; /* end of json_array_foreach over denominations */ - // The calculated group_hash_xor must be the same as group.hash from - // the json. + /* The calculated group_hash_xor must be the same as group.hash from + the JSON. */ EXITIF (0 != - GNUNET_CRYPTO_hash_cmp (&group_hash_xor, &group.hash)); + GNUNET_CRYPTO_hash_cmp (&group_hash_xor, + &group.hash)); - } // block for parsing individual denominations - }; // json_array_foreach over groups of denominations + } /* end of block for parsing individual denominations */ + } /* end of json_array_foreach over groups of denominations */ } /* parse the auditor information */ { - json_t *auditors_array; json_t *auditor_info; unsigned int index; - EXITIF (NULL == (auditors_array = - json_object_get (resp_obj, - "auditors"))); - EXITIF (JSON_ARRAY != json_typeof (auditors_array)); - /* Merge with the existing auditor information we have (/keys cherry picking) */ - json_array_foreach (auditors_array, index, auditor_info) { + json_array_foreach (auditors_array, index, auditor_info) + { struct TALER_EXCHANGE_AuditorInformation ai; bool found = false; @@ -1105,41 +944,35 @@ decode_keys_json (const json_t *resp_obj, } /* parse the revocation/recoup information */ + if (NULL != recoup_array) { - json_t *recoup_array; json_t *recoup_info; unsigned int index; - if (NULL != (recoup_array = - json_object_get (resp_obj, - "recoup"))) + json_array_foreach (recoup_array, index, recoup_info) { - EXITIF (JSON_ARRAY != json_typeof (recoup_array)); - - json_array_foreach (recoup_array, index, recoup_info) { - struct TALER_DenominationHashP h_denom_pub; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("h_denom_pub", - &h_denom_pub), - GNUNET_JSON_spec_end () - }; - - EXITIF (GNUNET_OK != - GNUNET_JSON_parse (recoup_info, - spec, - NULL, NULL)); - for (unsigned int j = 0; - jnum_denom_keys; - j++) - { - if (0 == GNUNET_memcmp (&h_denom_pub, - &key_data->denom_keys[j].h_key)) - { - key_data->denom_keys[j].revoked = GNUNET_YES; - break; - } - } + struct TALER_DenominationHashP h_denom_pub; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("h_denom_pub", + &h_denom_pub), + GNUNET_JSON_spec_end () }; + + EXITIF (GNUNET_OK != + GNUNET_JSON_parse (recoup_info, + spec, + NULL, NULL)); + for (unsigned int j = 0; + jnum_denom_keys; + j++) + { + if (0 == GNUNET_memcmp (&h_denom_pub, + &key_data->denom_keys[j].h_key)) + { + key_data->denom_keys[j].revoked = true; + break; + } + } } } @@ -1148,7 +981,6 @@ decode_keys_json (const json_t *resp_obj, EXITIF (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_data, &pub)); - EXITIF (GNUNET_OK != TALER_exchange_online_key_set_verify ( key_data->list_issue_date, @@ -1156,7 +988,6 @@ decode_keys_json (const json_t *resp_obj, &pub, &denominations_sig)); } - return GNUNET_OK; EXITIF_exit: @@ -1165,101 +996,6 @@ EXITIF_exit: } -/** - * Free key data object. - * - * @param key_data data to free (pointer itself excluded) - */ -static void -free_key_data (struct TALER_EXCHANGE_Keys *key_data) -{ - GNUNET_array_grow (key_data->sign_keys, - key_data->num_sign_keys, - 0); - for (unsigned int i = 0; inum_denom_keys; i++) - TALER_denom_pub_free (&key_data->denom_keys[i].key); - - GNUNET_array_grow (key_data->denom_keys, - key_data->denom_keys_size, - 0); - for (unsigned int i = 0; inum_auditors; i++) - { - GNUNET_array_grow (key_data->auditors[i].denom_keys, - key_data->auditors[i].num_denom_keys, - 0); - GNUNET_free (key_data->auditors[i].auditor_url); - } - GNUNET_array_grow (key_data->auditors, - key_data->auditors_size, - 0); - GNUNET_free (key_data->wallet_balance_limit_without_kyc); - GNUNET_free (key_data->version); - GNUNET_free (key_data->currency); - GNUNET_free (key_data->asset_type); - GNUNET_free (key_data->global_fees); -} - - -/** - * Initiate download of /keys from the exchange. - * - * @param cls exchange where to download /keys from - */ -static void -request_keys (void *cls); - - -void -TALER_EXCHANGE_set_last_denom (struct TALER_EXCHANGE_Handle *exchange, - struct GNUNET_TIME_Timestamp last_denom_new) -{ - TALER_LOG_DEBUG ( - "Application explicitly set last denomination validity to %s\n", - GNUNET_TIME_timestamp2s (last_denom_new)); - exchange->key_data.last_denom_issue_date = last_denom_new; -} - - -struct GNUNET_TIME_Timestamp -TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange, - enum TALER_EXCHANGE_CheckKeysFlags flags, - TALER_EXCHANGE_CertificationCallback cb, - void *cb_cls) -{ - bool force_download = 0 != (flags & TALER_EXCHANGE_CKF_FORCE_DOWNLOAD); - bool pull_all_keys = 0 != (flags & TALER_EXCHANGE_CKF_PULL_ALL_KEYS); - - GNUNET_assert (NULL != exchange); - - if ( (NULL != cb) && - ( (exchange->cert_cb != cb) || - (exchange->cert_cb_cls != cb_cls) ) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Changing target of exchange certification callback\n"); - exchange->cert_cb = cb; - exchange->cert_cb_cls = cb_cls; - } - if (NULL != exchange->kr) - return GNUNET_TIME_UNIT_ZERO_TS; - if (pull_all_keys) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Forcing re-download of all exchange keys\n"); - GNUNET_break (force_download); - exchange->state = MHS_INIT; - } - if ( (! force_download) && - (GNUNET_TIME_absolute_is_future ( - exchange->key_data_expiration.abs_time)) ) - return exchange->key_data_expiration; - if (NULL == exchange->retry_task) - exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys, - exchange); - return GNUNET_TIME_UNIT_ZERO_TS; -} - - /** * Callback used when downloading the reply to a /keys request * is complete. @@ -1273,133 +1009,107 @@ keys_completed_cb (void *cls, long response_code, const void *resp_obj) { - struct KeysRequest *kr = cls; - struct TALER_EXCHANGE_Handle *exchange = kr->exchange; - struct TALER_EXCHANGE_Keys kd_old; + struct TALER_EXCHANGE_GetKeysHandle *gkh = cls; const json_t *j = resp_obj; - struct TALER_EXCHANGE_Keys kd; + 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, }; - memset (&kd, - 0, - sizeof (kd)); + gkh->job = NULL; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received keys from URL `%s' with status %ld and expiration %s.\n", - kr->url, + gkh->url, response_code, - GNUNET_TIME_timestamp2s (kr->expire)); - if (GNUNET_TIME_absolute_is_past (kr->expire.abs_time)) + GNUNET_TIME_timestamp2s (gkh->expire)); + if (GNUNET_TIME_absolute_is_past (gkh->expire.abs_time)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Exchange failed to give expiration time, assuming in %s\n", GNUNET_TIME_relative2s (DEFAULT_EXPIRATION, true)); - kr->expire + gkh->expire = GNUNET_TIME_absolute_to_timestamp ( GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION)); } - kd_old = exchange->key_data; switch (response_code) { case 0: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to receive /keys response from exchange %s\n", - exchange->url); - free_keys_request (kr); - exchange->keys_error_count++; - exchange->kr = NULL; - GNUNET_assert (NULL == exchange->retry_task); - exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay); - exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay, - &request_keys, - exchange); - return; + gkh->exchange_url); + break; case MHD_HTTP_OK: - exchange->keys_error_count = 0; if (NULL == j) { + GNUNET_break (0); response_code = 0; break; } - /* 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; iexchange_url = GNUNET_strdup (gkh->exchange_url); + if (NULL != gkh->prev_keys) { - const struct TALER_EXCHANGE_AuditorInformation *aold = - &kd_old.auditors[i]; - struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i]; + const struct TALER_EXCHANGE_Keys *kd_old = gkh->prev_keys; - anew->auditor_pub = aold->auditor_pub; - GNUNET_assert (NULL != aold->auditor_url); - anew->auditor_url = GNUNET_strdup (aold->auditor_url); - 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)); + /* 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; inum_denom_keys; i++) + TALER_denom_pub_deep_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; inum_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); + 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)); + } } - - /* Old auditors got just copied into new ones. */ + /* Now decode fresh /keys response */ if (GNUNET_OK != decode_keys_json (j, true, - &kd, + 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; - for (unsigned int i = 0; idenom_keys, - anew->num_denom_keys, - 0); - GNUNET_free (anew->auditor_url); - } - GNUNET_free (kd.auditors); - kd.auditors = NULL; - kd.num_auditors = 0; - for (unsigned int i = 0; ikey_data_raw); - exchange->key_data_raw = json_deep_copy (j); - exchange->retry_delay = GNUNET_TIME_UNIT_ZERO; + kd->rc = 1; + kresp.details.ok.keys = kd; break; case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_UNAUTHORIZED: @@ -1417,8 +1127,6 @@ keys_completed_cb (void *cls, } break; default: - if (MHD_HTTP_GATEWAY_TIMEOUT == response_code) - exchange->keys_error_count++; if (NULL == j) { kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; @@ -1435,78 +1143,10 @@ keys_completed_cb (void *cls, (int) kresp.hr.ec); break; } - exchange->key_data = kd; - if (GNUNET_TIME_absolute_is_past ( - exchange->key_data.last_denom_issue_date.abs_time)) - TALER_LOG_WARNING ("Last DK issue date from exchange is in the past: %s\n", - GNUNET_TIME_timestamp2s ( - exchange->key_data.last_denom_issue_date)); - else - TALER_LOG_DEBUG ("Last DK issue date updated to: %s\n", - GNUNET_TIME_timestamp2s ( - exchange->key_data.last_denom_issue_date)); - - - if (MHD_HTTP_OK != response_code) - { - exchange->kr = NULL; - free_keys_request (kr); - exchange->state = MHS_FAILED; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Exchange keys download failed\n"); - if (NULL != exchange->key_data_raw) - { - json_decref (exchange->key_data_raw); - exchange->key_data_raw = NULL; - } - free_key_data (&kd_old); - /* notify application that we failed */ - exchange->cert_cb (exchange->cert_cb_cls, - &kresp); - return; - } - - exchange->kr = NULL; - exchange->key_data_expiration = kr->expire; - free_keys_request (kr); - exchange->state = MHS_CERT; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Successfully downloaded exchange's keys\n"); - update_auditors (exchange); - kresp.details.ok.keys = &exchange->key_data; - - /* notify application about the key information */ - exchange->cert_cb (exchange->cert_cb_cls, - &kresp); - free_key_data (&kd_old); -} - - -/* ********************* library internal API ********* */ - - -struct GNUNET_CURL_Context * -TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h) -{ - return h->ctx; -} - - -enum GNUNET_GenericReturnValue -TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h) -{ - return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO; -} - - -char * -TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h, - const char *path) -{ - GNUNET_assert ('/' == path[0]); - return TALER_url_join (h->url, - path + 1, - NULL); + gkh->cert_cb (gkh->cert_cb_cls, + &kresp, + kd); + TALER_EXCHANGE_get_keys_cancel (gkh); } @@ -1520,7 +1160,7 @@ TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h, * Parse HTTP timestamp. * * @param dateline header to parse header - * @param at where to write the result + * @param[out] at where to write the result * @return #GNUNET_OK on success */ static enum GNUNET_GenericReturnValue @@ -1620,7 +1260,7 @@ parse_date_string (const char *dateline, * @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 KeysRequest` + * @param userdata the `struct TALER_EXCHANGE_GetKeysHandle` * @return `size * nitems` on success (everything else aborts) */ static size_t @@ -1629,7 +1269,7 @@ header_cb (char *buffer, size_t nitems, void *userdata) { - struct KeysRequest *kr = userdata; + struct TALER_EXCHANGE_GetKeysHandle *kr = userdata; size_t total = size * nitems; char *val; @@ -1656,22 +1296,249 @@ header_cb (char *buffer, } -/* ********************* public API ******************* */ - - -/** - * Deserialize the key data and use it to bootstrap @a exchange to - * more efficiently recover the state. Errors in @a data must be - * tolerated (i.e. by re-downloading instead). - * - * @param exchange which exchange's key and wire data should be deserialized - * @param data the data to deserialize - */ -static void -deserialize_data (struct TALER_EXCHANGE_Handle *exchange, - const json_t *data) +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) { - const json_t *keys; + 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) + { + 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_DEBUG, + "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, + const struct TALER_ExchangePublicKeyP *pub) +{ + struct GNUNET_TIME_Absolute now; + + /* we will check using a tolerance of 1h for the time */ + now = GNUNET_TIME_absolute_get (); + for (unsigned int i = 0; inum_sign_keys; i++) + if ( (GNUNET_TIME_absolute_cmp ( + keys->sign_keys[i].valid_from.abs_time, + <=, + GNUNET_TIME_absolute_add (now, + LIFETIME_TOLERANCE))) && + (GNUNET_TIME_absolute_cmp ( + keys->sign_keys[i].valid_until.abs_time, + >, + GNUNET_TIME_absolute_subtract (now, + LIFETIME_TOLERANCE))) && + (0 == GNUNET_memcmp (pub, + &keys->sign_keys[i].key)) ) + return GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Signing key not valid at time %s\n", + GNUNET_TIME_absolute2s (now)); + return GNUNET_SYSERR; +} + + +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_EXCHANGE_get_denomination_key ( + const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_DenominationPublicKey *pk) +{ + for (unsigned int i = 0; inum_denom_keys; i++) + if (0 == + TALER_denom_pub_cmp (pk, + &keys->denom_keys[i].key)) + return &keys->denom_keys[i]; + return NULL; +} + + +const struct TALER_EXCHANGE_GlobalFee * +TALER_EXCHANGE_get_global_fee ( + const struct TALER_EXCHANGE_Keys *keys, + struct GNUNET_TIME_Timestamp ts) +{ + for (unsigned int i = 0; inum_global_fees; i++) + { + const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i]; + + if (GNUNET_TIME_timestamp_cmp (ts, + >=, + gf->start_date) && + GNUNET_TIME_timestamp_cmp (ts, + <, + gf->end_date)) + return gf; + } + return NULL; +} + + +struct TALER_EXCHANGE_DenomPublicKey * +TALER_EXCHANGE_copy_denomination_key ( + const struct TALER_EXCHANGE_DenomPublicKey *key) +{ + struct TALER_EXCHANGE_DenomPublicKey *copy; + + copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey); + *copy = *key; + TALER_denom_pub_deep_copy (©->key, + &key->key); + return copy; +} + + +void +TALER_EXCHANGE_destroy_denomination_key ( + struct TALER_EXCHANGE_DenomPublicKey *key) +{ + TALER_denom_pub_free (&key->key); + GNUNET_free (key); +} + + +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_EXCHANGE_get_denomination_key_by_hash ( + const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_DenominationHashP *hc) +{ + for (unsigned int i = 0; inum_denom_keys; i++) + if (0 == GNUNET_memcmp (hc, + &keys->denom_keys[i].h_key)) + return &keys->denom_keys[i]; + return NULL; +} + + +struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys) +{ + GNUNET_assert (keys->rc < UINT_MAX); + keys->rc++; + return keys; +} + + +void +TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys) +{ + if (NULL == keys) + return; + GNUNET_assert (0 < keys->rc); + keys->rc--; + if (0 != keys->rc) + return; + GNUNET_array_grow (keys->sign_keys, + keys->num_sign_keys, + 0); + for (unsigned int i = 0; inum_denom_keys; i++) + TALER_denom_pub_free (&keys->denom_keys[i].key); + + GNUNET_array_grow (keys->denom_keys, + keys->denom_keys_size, + 0); + for (unsigned int i = 0; inum_auditors; i++) + { + GNUNET_array_grow (keys->auditors[i].denom_keys, + keys->auditors[i].num_denom_keys, + 0); + GNUNET_free (keys->auditors[i].auditor_url); + } + GNUNET_array_grow (keys->auditors, + keys->auditors_size, + 0); + GNUNET_free (keys->wallet_balance_limit_without_kyc); + GNUNET_free (keys->version); + GNUNET_free (keys->currency); + GNUNET_free (keys->asset_type); + GNUNET_free (keys->global_fees); + GNUNET_free (keys->exchange_url); + GNUNET_free (keys); +} + + +struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_keys_from_json (const json_t *j) +{ + const json_t *jkeys; const char *url; uint32_t version; struct GNUNET_TIME_Timestamp expire; @@ -1679,72 +1546,50 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange, GNUNET_JSON_spec_uint32 ("version", &version), GNUNET_JSON_spec_array_const ("keys", - &keys), + &jkeys), GNUNET_JSON_spec_string ("exchange_url", &url), GNUNET_JSON_spec_timestamp ("expire", &expire), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_Keys key_data; - struct TALER_EXCHANGE_KeysResponse kresp = { - .hr.ec = TALER_EC_NONE, - .hr.http_status = MHD_HTTP_OK, - .hr.reply = data, - .details.ok.keys = &exchange->key_data - }; + struct TALER_EXCHANGE_Keys *keys; + enum TALER_EXCHANGE_VersionCompatibility compat; - if (NULL == data) - return; + if (NULL == j) + return NULL; if (GNUNET_OK != - GNUNET_JSON_parse (data, + GNUNET_JSON_parse (j, spec, NULL, NULL)) { GNUNET_break_op (0); - return; + return NULL; } if (0 != version) { - return; /* unsupported version */ + return NULL; /* unsupported version */ } - if (0 != strcmp (url, - exchange->url)) - { - GNUNET_break (0); - return; - } - memset (&key_data, - 0, - sizeof (struct TALER_EXCHANGE_Keys)); + keys = GNUNET_new (struct TALER_EXCHANGE_Keys); if (GNUNET_OK != - decode_keys_json (keys, + decode_keys_json (jkeys, false, - &key_data, - &kresp.details.ok.compat)) + keys, + &compat)) { GNUNET_break (0); - return; + return NULL; } - /* decode successful, initialize with the result */ - GNUNET_assert (NULL == exchange->key_data_raw); - exchange->key_data_raw = json_deep_copy (keys); - exchange->key_data = key_data; - exchange->key_data_expiration = expire; - exchange->state = MHS_CERT; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Successfully loaded exchange's keys via deserialization\n"); - update_auditors (exchange); - /* notify application about the key information */ - exchange->cert_cb (exchange->cert_cb_cls, - &kresp); + keys->rc = 1; + keys->key_data_expiration = expire; + keys->exchange_url = GNUNET_strdup (url); + return keys; } json_t * -TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange) +TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd) { - const struct TALER_EXCHANGE_Keys *kd = &exchange->key_data; struct GNUNET_TIME_Timestamp now; json_t *keys; json_t *signkeys; @@ -1903,371 +1748,12 @@ TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange) GNUNET_JSON_pack_uint64 ("version", EXCHANGE_SERIALIZATION_FORMAT_VERSION), GNUNET_JSON_pack_timestamp ("expire", - exchange->key_data_expiration), + kd->key_data_expiration), GNUNET_JSON_pack_string ("exchange_url", - exchange->url), + kd->exchange_url), GNUNET_JSON_pack_object_steal ("keys", keys)); } -struct TALER_EXCHANGE_Handle * -TALER_EXCHANGE_connect ( - struct GNUNET_CURL_Context *ctx, - const char *url, - TALER_EXCHANGE_CertificationCallback cert_cb, - void *cert_cb_cls, - ...) -{ - struct TALER_EXCHANGE_Handle *exchange; - va_list ap; - enum TALER_EXCHANGE_Option opt; - - TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n", - url); - /* Disable 100 continue processing */ - GNUNET_break (GNUNET_OK == - GNUNET_CURL_append_header (ctx, - MHD_HTTP_HEADER_EXPECT ":")); - exchange = GNUNET_new (struct TALER_EXCHANGE_Handle); - exchange->ctx = ctx; - exchange->url = GNUNET_strdup (url); - exchange->cert_cb = cert_cb; - exchange->cert_cb_cls = cert_cb_cls; - exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys, - exchange); - va_start (ap, cert_cb_cls); - while (TALER_EXCHANGE_OPTION_END != - (opt = va_arg (ap, int))) - { - switch (opt) - { - case TALER_EXCHANGE_OPTION_END: - GNUNET_assert (0); - break; - case TALER_EXCHANGE_OPTION_DATA: - { - const json_t *data = va_arg (ap, const json_t *); - - deserialize_data (exchange, - data); - break; - } - default: - GNUNET_assert (0); - break; - } - } - va_end (ap); - return exchange; -} - - -/** - * Compute the network timeout for the next request to /keys. - * - * @param exchange the exchange handle - * @returns the timeout in seconds (for use by CURL) - */ -static long -get_keys_timeout_seconds (struct TALER_EXCHANGE_Handle *exchange) -{ - unsigned int kec; - - /* if retry counter >= 8, do not bother to go further, we - stop the exponential back-off at 128 anyway. */ - kec = GNUNET_MIN (7, - exchange->keys_error_count); - return GNUNET_MIN (120, - 5 + (1L << kec)); -} - - -/** - * Initiate download of /keys from the exchange. - * - * @param cls exchange where to download /keys from - */ -static void -request_keys (void *cls) -{ - struct TALER_EXCHANGE_Handle *exchange = cls; - struct KeysRequest *kr; - CURL *eh; - char url[200] = "/keys?"; - - exchange->retry_task = NULL; - GNUNET_assert (NULL == exchange->kr); - kr = GNUNET_new (struct KeysRequest); - kr->exchange = exchange; - - if (GNUNET_YES == TEAH_handle_is_ready (exchange)) - { - TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n", - GNUNET_TIME_timestamp2s ( - exchange->key_data.last_denom_issue_date)); - sprintf (&url[strlen (url)], - "last_issue_date=%llu&", - (unsigned long long) - exchange->key_data.last_denom_issue_date.abs_time.abs_value_us - / 1000000LLU); - } - - /* Clean the last '&'/'?' sign that we optimistically put. */ - url[strlen (url) - 1] = '\0'; - kr->url = TEAH_path_to_url (exchange, - url); - if (NULL == kr->url) - { - struct TALER_EXCHANGE_KeysResponse kresp = { - .hr.ec = TALER_EC_GENERIC_CONFIGURATION_INVALID, - /* Next line is technically unnecessary, as the - http status we set is 0 */ - .details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR - }; - - GNUNET_free (kr); - exchange->keys_error_count++; - exchange->state = MHS_FAILED; - exchange->cert_cb (exchange->cert_cb_cls, - &kresp); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Requesting keys with URL `%s'.\n", - kr->url); - eh = TALER_EXCHANGE_curl_easy_get_ (kr->url); - if (NULL == eh) - { - GNUNET_free (kr->url); - GNUNET_free (kr); - exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay); - exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay, - &request_keys, - exchange); - return; - } - GNUNET_break (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_VERBOSE, - 0)); - GNUNET_break (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_TIMEOUT, - get_keys_timeout_seconds (exchange))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HEADERFUNCTION, - &header_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HEADERDATA, - kr)); - kr->job = GNUNET_CURL_job_add_with_ct_json (exchange->ctx, - eh, - &keys_completed_cb, - kr); - exchange->kr = kr; -} - - -void -TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) -{ - struct TEAH_AuditorListEntry *ale; - - while (NULL != (ale = exchange->auditors_head)) - { - GNUNET_CONTAINER_DLL_remove (exchange->auditors_head, - exchange->auditors_tail, - ale); - if (NULL != ale->ah) - { - TALER_AUDITOR_get_config_cancel (ale->ah); - ale->ah = NULL; - } - GNUNET_free (ale->auditor_url); - GNUNET_free (ale); - } - if (NULL != exchange->kr) - { - GNUNET_CURL_job_cancel (exchange->kr->job); - free_keys_request (exchange->kr); - exchange->kr = NULL; - } - free_key_data (&exchange->key_data); - if (NULL != exchange->key_data_raw) - { - json_decref (exchange->key_data_raw); - exchange->key_data_raw = NULL; - } - if (NULL != exchange->retry_task) - { - GNUNET_SCHEDULER_cancel (exchange->retry_task); - exchange->retry_task = NULL; - } - GNUNET_free (exchange->url); - GNUNET_free (exchange); -} - - -enum GNUNET_GenericReturnValue -TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_ExchangePublicKeyP *pub) -{ - struct GNUNET_TIME_Absolute now; - - /* we will check using a tolerance of 1h for the time */ - now = GNUNET_TIME_absolute_get (); - for (unsigned int i = 0; inum_sign_keys; i++) - if ( (GNUNET_TIME_absolute_cmp ( - keys->sign_keys[i].valid_from.abs_time, - <=, - GNUNET_TIME_absolute_add (now, - LIFETIME_TOLERANCE))) && - (GNUNET_TIME_absolute_cmp ( - keys->sign_keys[i].valid_until.abs_time, - >, - GNUNET_TIME_absolute_subtract (now, - LIFETIME_TOLERANCE))) && - (0 == GNUNET_memcmp (pub, - &keys->sign_keys[i].key)) ) - return GNUNET_OK; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Signing key not valid at time %s\n", - GNUNET_TIME_absolute2s (now)); - return GNUNET_SYSERR; -} - - -const char * -TALER_EXCHANGE_get_base_url (const struct TALER_EXCHANGE_Handle *exchange) -{ - return exchange->url; -} - - -const struct TALER_EXCHANGE_DenomPublicKey * -TALER_EXCHANGE_get_denomination_key ( - const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_DenominationPublicKey *pk) -{ - for (unsigned int i = 0; inum_denom_keys; i++) - if (0 == - TALER_denom_pub_cmp (pk, - &keys->denom_keys[i].key)) - return &keys->denom_keys[i]; - return NULL; -} - - -const struct TALER_EXCHANGE_GlobalFee * -TALER_EXCHANGE_get_global_fee ( - const struct TALER_EXCHANGE_Keys *keys, - struct GNUNET_TIME_Timestamp ts) -{ - for (unsigned int i = 0; inum_global_fees; i++) - { - const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i]; - - if (GNUNET_TIME_timestamp_cmp (ts, - >=, - gf->start_date) && - GNUNET_TIME_timestamp_cmp (ts, - <, - gf->end_date)) - return gf; - } - return NULL; -} - - -struct TALER_EXCHANGE_DenomPublicKey * -TALER_EXCHANGE_copy_denomination_key ( - const struct TALER_EXCHANGE_DenomPublicKey *key) -{ - struct TALER_EXCHANGE_DenomPublicKey *copy; - - copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey); - *copy = *key; - TALER_denom_pub_deep_copy (©->key, - &key->key); - return copy; -} - - -void -TALER_EXCHANGE_destroy_denomination_key ( - struct TALER_EXCHANGE_DenomPublicKey *key) -{ - TALER_denom_pub_free (&key->key); - GNUNET_free (key); -} - - -const struct TALER_EXCHANGE_DenomPublicKey * -TALER_EXCHANGE_get_denomination_key_by_hash ( - const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_DenominationHashP *hc) -{ - for (unsigned int i = 0; inum_denom_keys; i++) - if (0 == GNUNET_memcmp (hc, - &keys->denom_keys[i].h_key)) - return &keys->denom_keys[i]; - return NULL; -} - - -struct TALER_EXCHANGE_Keys * -TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange) -{ - (void) TALER_EXCHANGE_check_keys_current (exchange, - TALER_EXCHANGE_CKF_NONE, - NULL, - NULL); - return &exchange->key_data; -} - - -json_t * -TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange) -{ - (void) TALER_EXCHANGE_check_keys_current (exchange, - TALER_EXCHANGE_CKF_NONE, - NULL, - NULL); - return json_deep_copy (exchange->key_data_raw); -} - - -/** - * Obtain the keys from the exchange in the raw JSON format. - * - * @param keys the keys structure - * @return the keys in raw JSON - */ -json_t * -TALER_EXCHANGE_keys_to_json (struct TALER_EXCHANGE_Keys *keys) -{ - // FIXME! - return NULL; -} - - -struct TALER_EXCHANGE_Keys * -TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys) -{ - // FIXME - return keys; -} - - -void -TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys) -{ - // FIXME -} - - /* end of exchange_api_handle.c */ diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h index 6b96e21eb..7c01b9a9f 100644 --- a/src/lib/exchange_api_handle.h +++ b/src/lib/exchange_api_handle.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015 Taler Systems SA + Copyright (C) 2014, 2015, 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 @@ -28,124 +28,6 @@ #include "taler_util.h" #include "taler_curl_lib.h" -/** - * Entry in DLL of auditors used by an exchange. - */ -struct TEAH_AuditorListEntry; - - -/** - * Stages of initialization for the `struct TALER_EXCHANGE_Handle` - */ -enum ExchangeHandleState -{ - /** - * Just allocated. - */ - MHS_INIT = 0, - - /** - * Obtained the exchange's certification data and keys. - */ - MHS_CERT = 1, - - /** - * Failed to initialize (fatal). - */ - MHS_FAILED = 2 -}; - - -/** - * Handle to the exchange - */ -struct TALER_EXCHANGE_Handle -{ - /** - * The context of this handle - */ - struct GNUNET_CURL_Context *ctx; - - /** - * The URL of the exchange (i.e. "http://exchange.taler.net/") - */ - char *url; - - /** - * Function to call with the exchange's certification data, - * NULL if this has already been done. - */ - TALER_EXCHANGE_CertificationCallback cert_cb; - - /** - * Closure to pass to @e cert_cb. - */ - void *cert_cb_cls; - - /** - * Data for the request to get the /keys of a exchange, - * NULL once we are past stage #MHS_INIT. - */ - struct KeysRequest *kr; - - /** - * Task for retrying /keys request. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * Raw key data of the exchange, only valid if - * @e handshake_complete is past stage #MHS_CERT. - */ - json_t *key_data_raw; - - /** - * Head of DLL of auditors of this exchange. - */ - struct TEAH_AuditorListEntry *auditors_head; - - /** - * Tail of DLL of auditors of this exchange. - */ - struct TEAH_AuditorListEntry *auditors_tail; - - /** - * Key data of the exchange, only valid if - * @e handshake_complete is past stage #MHS_CERT. - */ - struct TALER_EXCHANGE_Keys key_data; - - /** - * Retry /keys frequency. - */ - struct GNUNET_TIME_Relative retry_delay; - - /** - * When does @e key_data expire? - */ - struct GNUNET_TIME_Timestamp key_data_expiration; - - /** - * Number of subsequent failed requests to /keys. - * - * Used to compute the CURL timeout for the request. - */ - unsigned int keys_error_count; - - /** - * Number of subsequent failed requests to /wire. - * - * Used to compute the CURL timeout for the request. - */ - unsigned int wire_error_count; - - /** - * Stage of the exchange's initialization routines. - */ - enum ExchangeHandleState state; - -}; - /** * Function called for each auditor to give us a chance to possibly @@ -156,9 +38,10 @@ struct TALER_EXCHANGE_Handle * @param auditor_pub public key of the auditor */ typedef void -(*TEAH_AuditorCallback)(void *cls, - const char *auditor_url, - const struct TALER_AuditorPublicKeyP *auditor_pub); +(*TEAH_AuditorCallback)( + void *cls, + const char *auditor_url, + const struct TALER_AuditorPublicKeyP *auditor_pub); /** @@ -171,50 +54,11 @@ typedef void * @param ac_cls closure for @a ac */ void -TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys, - TEAH_AuditorCallback ac, - void *ac_cls); +TEAH_get_auditors_for_dc ( + struct TALER_EXCHANGE_Keys *keys, + TEAH_AuditorCallback ac, + void *ac_cls); -/** - * Get the context of a exchange. - * - * @param h the exchange handle to query - * @return ctx context to execute jobs in - */ -struct GNUNET_CURL_Context * -TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h); - - -/** - * Check if the handle is ready to process requests. - * - * @param h the exchange handle to query - * @return #GNUNET_YES if we are ready, #GNUNET_NO if not - */ -enum GNUNET_GenericReturnValue -TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h); - -/** - * Check if the handle is ready to process requests. - * - * @param h the exchange handle to query - * @return #GNUNET_YES if we are ready, #GNUNET_NO if not - */ -enum GNUNET_GenericReturnValue -TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h); - - -/** - * Obtain the URL to use for an API request. - * - * @param h the exchange handle to query - * @param path Taler API path (i.e. "/reserve/withdraw") - * @return the full URL to use with cURL - */ -char * -TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h, - const char *path); - /* end of exchange_api_handle.h */ #endif diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c index 4e643f176..b5d6df0c4 100644 --- a/src/testing/test_auditor_api.c +++ b/src/testing/test_auditor_api.c @@ -658,7 +658,7 @@ run (void *cls, TALER_TESTING_cmd_get_auditor ("get-auditor", cred.cfg, true), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_exec_auditor_offline ("auditor-offline", config_file), CMD_RUN_AUDITOR ("virgin-auditor"), diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c index eb131d65e..e8cc6659f 100644 --- a/src/testing/test_exchange_api.c +++ b/src/testing/test_exchange_api.c @@ -1238,7 +1238,7 @@ run (void *cls, cred.cfg, true, true), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_batch ("wire", wire), TALER_TESTING_cmd_batch ("withdraw", diff --git a/src/testing/test_exchange_api_keys_cherry_picking.c b/src/testing/test_exchange_api_keys_cherry_picking.c index b463eea8f..11e18e5cb 100644 --- a/src/testing/test_exchange_api_keys_cherry_picking.c +++ b/src/testing/test_exchange_api_keys_cherry_picking.c @@ -67,7 +67,7 @@ run (void *cls, cred.cfg, true, true), - TALER_TESTING_cmd_check_keys_pull_all_keys ("initial-/keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("initial-/keys"), TALER_TESTING_cmd_sleep ("sleep", 6 /* seconds */), TALER_TESTING_cmd_check_keys ("check-keys-1"), diff --git a/src/testing/test_exchange_api_overlapping_keys_bug.c b/src/testing/test_exchange_api_overlapping_keys_bug.c index 7cbdd9b80..3f7353b91 100644 --- a/src/testing/test_exchange_api_overlapping_keys_bug.c +++ b/src/testing/test_exchange_api_overlapping_keys_bug.c @@ -71,7 +71,7 @@ run (void *cls, cred.cfg, true, true), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_check_keys ("first-download"), /* Causes GET /keys?last_denom_issue=0 */ TALER_TESTING_cmd_check_keys_with_last_denom ("second-download", diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c index c1c1b3190..1cb544dad 100644 --- a/src/testing/test_exchange_api_revocation.c +++ b/src/testing/test_exchange_api_revocation.c @@ -80,7 +80,7 @@ run (void *cls, TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", config_file), #endif - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), /** * Fill reserve with EUR:10.02, as withdraw fee is 1 ct per * config. diff --git a/src/testing/test_exchange_management_api.c b/src/testing/test_exchange_management_api.c index cabddcdef..fded3f037 100644 --- a/src/testing/test_exchange_management_api.c +++ b/src/testing/test_exchange_management_api.c @@ -145,7 +145,7 @@ run (void *cls, false), TALER_TESTING_cmd_exec_offline_sign_keys ("download-future-keys", config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_end () }; diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c index f5b11f608..689d2460e 100644 --- a/src/testing/test_exchange_p2p.c +++ b/src/testing/test_exchange_p2p.c @@ -506,7 +506,7 @@ run (void *cls, cred.cfg, true, true), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_batch ("withdraw", withdraw), TALER_TESTING_cmd_batch ("push", diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c index eb66d9c85..733a5e2f7 100644 --- a/src/testing/test_kyc_api.c +++ b/src/testing/test_kyc_api.c @@ -525,7 +525,7 @@ run (void *cls, cred.cfg, true, true), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_batch ("withdraw", withdraw), TALER_TESTING_cmd_batch ("spend", diff --git a/src/testing/test_taler_exchange_wirewatch.c b/src/testing/test_taler_exchange_wirewatch.c index 86e104f4a..54d258879 100644 --- a/src/testing/test_taler_exchange_wirewatch.c +++ b/src/testing/test_taler_exchange_wirewatch.c @@ -89,7 +89,7 @@ run (void *cls, cred.cfg, true, true), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), + // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty"), TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty", diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c index 5c7b76a31..252e8f522 100644 --- a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c +++ b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c @@ -211,12 +211,8 @@ deposit_confirmation_run (void *cls, const struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_SigningPublicKey *spk; const char *auditor_url; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); (void) cmd; - if (NULL == exchange) - return; dcs->is = is; GNUNET_assert (NULL != dcs->deposit_reference); { @@ -267,7 +263,7 @@ deposit_confirmation_run (void *cls, dcs->coin_index, &wire_deadline)); GNUNET_assert (NULL != exchange_timestamp); - keys = TALER_EXCHANGE_get_keys (exchange); + keys = TALER_TESTING_get_keys (is); GNUNET_assert (NULL != keys); spk = TALER_EXCHANGE_get_signing_key_info (keys, exchange_pub); diff --git a/src/testing/testing_api_cmd_batch_withdraw.c b/src/testing/testing_api_cmd_batch_withdraw.c index 56af70b14..7f6809492 100644 --- a/src/testing/testing_api_cmd_batch_withdraw.c +++ b/src/testing/testing_api_cmd_batch_withdraw.c @@ -253,12 +253,8 @@ batch_withdraw_run (void *cls, const struct TALER_TESTING_Command *create_reserve; const struct TALER_EXCHANGE_DenomPublicKey *dpk; struct TALER_EXCHANGE_WithdrawCoinInput wcis[ws->num_coins]; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); (void) cmd; - if (NULL == exchange) - return; ws->is = is; create_reserve = TALER_TESTING_interpreter_lookup_command ( @@ -281,7 +277,7 @@ batch_withdraw_run (void *cls, } if (NULL == ws->exchange_url) ws->exchange_url - = GNUNET_strdup (TALER_EXCHANGE_get_base_url (exchange)); + = GNUNET_strdup (TALER_TESTING_get_exchange_url (is)); ws->reserve_priv = *rp; GNUNET_CRYPTO_eddsa_key_get_public (&ws->reserve_priv.eddsa_priv, &ws->reserve_pub.eddsa_pub); @@ -295,7 +291,7 @@ batch_withdraw_run (void *cls, struct TALER_EXCHANGE_WithdrawCoinInput *wci = &wcis[i]; TALER_planchet_master_setup_random (&cs->ps); - dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (exchange), + dpk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (is), &cs->amount, ws->age > 0); if (NULL == dpk) diff --git a/src/testing/testing_api_cmd_check_keys.c b/src/testing/testing_api_cmd_check_keys.c index f4ea126e6..bb26d10a4 100644 --- a/src/testing/testing_api_cmd_check_keys.c +++ b/src/testing/testing_api_cmd_check_keys.c @@ -27,6 +27,8 @@ #include #include "taler_testing_lib.h" +// FIXME: duplicated with testing_api_cmd_connect_with_state +// FIXME: this is now duplicated with testing_api_cmd_get_exchange! /** * State for a "check keys" CMD. @@ -34,14 +36,9 @@ struct CheckKeysState { - /** - * If this value is true, then the "cherry picking" facility is turned off; - * whole /keys is downloaded. - */ - bool pull_all_keys; - /** * Label of a command to use to derive the "last_denom_issue" date to use. + * FIXME: actually use this! */ const char *last_denom_date_ref; @@ -50,6 +47,11 @@ struct CheckKeysState */ struct TALER_TESTING_Interpreter *is; + /** + * Our get keys operation. + */ + struct TALER_EXCHANGE_GetKeysHandle *gkh; + /** * Last denomination date we received when doing this request. */ @@ -66,7 +68,8 @@ struct CheckKeysState */ static void keys_cb (void *cls, - const struct TALER_EXCHANGE_KeysResponse *kr) + const struct TALER_EXCHANGE_KeysResponse *kr, + struct TALER_EXCHANGE_Keys *keys) { struct CheckKeysState *cks = cls; @@ -77,6 +80,8 @@ keys_cb (void *cls, return; } cks->my_denom_date = kr->details.ok.keys->last_denom_issue_date; + /* FIXME: expose keys (and exchange_url) via trait! */ + TALER_EXCHANGE_keys_decref (keys); TALER_TESTING_interpreter_next (cks->is); } @@ -94,64 +99,19 @@ check_keys_run (void *cls, struct TALER_TESTING_Interpreter *is) { struct CheckKeysState *cks = cls; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); - struct GNUNET_TIME_Timestamp rdate; + const char *exchange_url + = TALER_TESTING_get_exchange_url (is); - (void) cmd; cks->is = is; - if (NULL == exchange) - return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Triggering GET /keys, cmd `%s'\n", cmd->label); - if (NULL != cks->last_denom_date_ref) - { - if (0 == strcmp ("zero", - cks->last_denom_date_ref)) - { - TALER_LOG_DEBUG ("Forcing last_denom_date URL argument set to zero\n"); - TALER_EXCHANGE_set_last_denom (exchange, - GNUNET_TIME_UNIT_ZERO_TS); - } - else - { - const struct GNUNET_TIME_Timestamp *last_denom_date; - const struct TALER_TESTING_Command *ref; - - ref = TALER_TESTING_interpreter_lookup_command (is, - cks->last_denom_date_ref); - if (NULL == ref) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_timestamp (ref, - 0, - &last_denom_date)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - TALER_LOG_DEBUG ("Forcing last_denom_date URL argument\n"); - TALER_EXCHANGE_set_last_denom (exchange, - *last_denom_date); - } - } - - rdate = TALER_EXCHANGE_check_keys_current ( - exchange, - cks->pull_all_keys - ? TALER_EXCHANGE_CKF_FORCE_ALL_NOW - : TALER_EXCHANGE_CKF_FORCE_DOWNLOAD, + cks->gkh = TALER_EXCHANGE_get_keys ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + NULL, /* FIXME: get form last_denom_date_ref! */ &keys_cb, cks); - /* Redownload /keys. */ - GNUNET_break (GNUNET_TIME_absolute_is_zero (rdate.abs_time)); } @@ -168,6 +128,11 @@ check_keys_cleanup (void *cls, struct CheckKeysState *cks = cls; (void) cmd; + if (NULL != cks->gkh) + { + TALER_EXCHANGE_get_keys_cancel (cks->gkh); + cks->gkh = NULL; + } GNUNET_free (cks); } @@ -204,10 +169,21 @@ check_keys_traits (void *cls, struct TALER_TESTING_Command TALER_TESTING_cmd_check_keys (const char *label) +{ + return TALER_TESTING_cmd_check_keys_with_last_denom (label, + NULL); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_keys_with_last_denom ( + const char *label, + const char *last_denom_date_ref) { struct CheckKeysState *cks; cks = GNUNET_new (struct CheckKeysState); + cks->last_denom_date_ref = last_denom_date_ref; { struct TALER_TESTING_Command cmd = { .cls = cks, @@ -222,30 +198,4 @@ TALER_TESTING_cmd_check_keys (const char *label) } -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label) -{ - struct TALER_TESTING_Command cmd - = TALER_TESTING_cmd_check_keys (label); - struct CheckKeysState *cks = cmd.cls; - - cks->pull_all_keys = true; - return cmd; -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_with_last_denom ( - const char *label, - const char *last_denom_date_ref) -{ - struct TALER_TESTING_Command cmd - = TALER_TESTING_cmd_check_keys (label); - struct CheckKeysState *cks = cmd.cls; - - cks->last_denom_date_ref = last_denom_date_ref; - return cmd; -} - - /* end of testing_api_cmd_check_keys.c */ diff --git a/src/testing/testing_api_cmd_connect_with_state.c b/src/testing/testing_api_cmd_connect_with_state.c index 95e860f17..81587248d 100644 --- a/src/testing/testing_api_cmd_connect_with_state.c +++ b/src/testing/testing_api_cmd_connect_with_state.c @@ -26,6 +26,9 @@ #include "taler_testing_lib.h" +// FIXME: this is now duplicated with testing_api_cmd_check_keys! +// FIXME: this is now duplicated with testing_api_cmd_get_exchange! + /** * Internal state for a connect-with-state CMD. */ @@ -46,13 +49,19 @@ struct ConnectWithStateState /** * New exchange handle. */ - struct TALER_EXCHANGE_Handle *exchange; + struct TALER_EXCHANGE_GetKeysHandle *exchange; + + /** + * Keys handle. + */ + struct TALER_EXCHANGE_Keys *keys; }; static void cert_cb (void *cls, - const struct TALER_EXCHANGE_KeysResponse *kr) + const struct TALER_EXCHANGE_KeysResponse *kr, + struct TALER_EXCHANGE_Keys *keys) { struct ConnectWithStateState *cwss = cls; struct TALER_TESTING_Interpreter *is = cwss->is; @@ -72,6 +81,7 @@ cert_cb (void *cls, TALER_TESTING_interpreter_fail (is); return; } + cwss->keys = keys; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %d DK from /keys\n", kr->details.ok.keys->num_denom_keys); @@ -113,14 +123,12 @@ connect_with_state_run (void *cls, TALER_TESTING_get_trait_exchange_url (state_cmd, &exchange_url)); cwss->exchange - = TALER_EXCHANGE_connect ( + = TALER_EXCHANGE_get_keys ( TALER_TESTING_interpreter_get_context (is), exchange_url, + TALER_EXCHANGE_keys_from_json (serialized_keys), &cert_cb, - cwss, - TALER_EXCHANGE_OPTION_DATA, - serialized_keys, - TALER_EXCHANGE_OPTION_END); + cwss); } @@ -141,7 +149,8 @@ connect_with_state_traits (void *cls, { struct ConnectWithStateState *cwss = cls; struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_exchange (cwss->exchange), + TALER_TESTING_make_trait_keys (cwss->keys), + // FIXME: also expose exchange_url as trait TALER_TESTING_trait_end () }; @@ -165,6 +174,13 @@ connect_with_state_cleanup (void *cls, { struct ConnectWithStateState *cwss = cls; + TALER_EXCHANGE_keys_decref (cwss->keys); + cwss->keys = NULL; + if (NULL != cwss->exchange) + { + TALER_EXCHANGE_get_keys_cancel (cwss->exchange); + cwss->exchange = NULL; + } GNUNET_free (cwss); } diff --git a/src/testing/testing_api_cmd_get_exchange.c b/src/testing/testing_api_cmd_get_exchange.c index 2822616c0..b6634286a 100644 --- a/src/testing/testing_api_cmd_get_exchange.c +++ b/src/testing/testing_api_cmd_get_exchange.c @@ -46,7 +46,12 @@ struct GetExchangeState /** * Exchange handle we produced. */ - struct TALER_EXCHANGE_Handle *exchange; + struct TALER_EXCHANGE_GetKeysHandle *exchange; + + /** + * Keys of the exchange. + */ + struct TALER_EXCHANGE_Keys *keys; /** * URL of the exchange. @@ -67,12 +72,15 @@ struct GetExchangeState static void cert_cb (void *cls, - const struct TALER_EXCHANGE_KeysResponse *kr) + 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; + ges->exchange = NULL; + ges->keys = keys; switch (hr->http_status) { case MHD_HTTP_OK: @@ -85,8 +93,9 @@ cert_cb (void *cls, return; default: GNUNET_break (0); - TALER_EXCHANGE_disconnect (ges->exchange); - ges->exchange = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "/keys responded with HTTP status %u\n", + hr->http_status); if (ges->wait_for_keys) { ges->wait_for_keys = false; @@ -133,11 +142,11 @@ get_exchange_run (void *cls, } ges->is = is; ges->exchange - = TALER_EXCHANGE_connect (TALER_TESTING_interpreter_get_context (is), - ges->exchange_url, - &cert_cb, - ges, - TALER_EXCHANGE_OPTION_END); + = TALER_EXCHANGE_get_keys (TALER_TESTING_interpreter_get_context (is), + ges->exchange_url, + NULL, + &cert_cb, + ges); if (NULL == ges->exchange) { GNUNET_break (0); @@ -163,9 +172,11 @@ get_exchange_cleanup (void *cls, if (NULL != ges->exchange) { - TALER_EXCHANGE_disconnect (ges->exchange); + TALER_EXCHANGE_get_keys_cancel (ges->exchange); ges->exchange = NULL; } + TALER_EXCHANGE_keys_decref (ges->keys); + ges->keys = NULL; GNUNET_free (ges->master_priv_file); GNUNET_free (ges->exchange_url); GNUNET_free (ges); @@ -189,16 +200,13 @@ get_exchange_traits (void *cls, { struct GetExchangeState *ges = cls; unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0; - struct TALER_EXCHANGE_Keys *keys - = TALER_EXCHANGE_get_keys (ges->exchange); - if (NULL != keys) + if (NULL != ges->keys) { struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_master_priv (&ges->master_priv), - TALER_TESTING_make_trait_master_pub (&keys->master_pub), - TALER_TESTING_make_trait_exchange (ges->exchange), - TALER_TESTING_make_trait_keys (keys), + TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub), + TALER_TESTING_make_trait_keys (ges->keys), TALER_TESTING_make_trait_exchange_url (ges->exchange_url), TALER_TESTING_trait_end () }; @@ -212,7 +220,6 @@ get_exchange_traits (void *cls, { struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_master_priv (&ges->master_priv), - TALER_TESTING_make_trait_exchange (ges->exchange), TALER_TESTING_make_trait_exchange_url (ges->exchange_url), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_cmd_purse_deposit.c b/src/testing/testing_api_cmd_purse_deposit.c index 8bddc53a6..eafe33423 100644 --- a/src/testing/testing_api_cmd_purse_deposit.c +++ b/src/testing/testing_api_cmd_purse_deposit.c @@ -133,11 +133,8 @@ deposit_cb (void *cls, const struct TALER_EXCHANGE_PurseDepositResponse *dr) { struct PurseDepositState *ds = cls; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (ds->is); ds->dh = NULL; - GNUNET_assert (NULL != exchange); if (ds->expected_response_code != dr->hr.http_status) { TALER_TESTING_unexpected_status (ds->is, @@ -197,10 +194,10 @@ deposit_cb (void *cls, /* Deposits complete, create trait! */ ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE; { - const struct TALER_EXCHANGE_Keys *keys; + struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_GlobalFee *gf; - keys = TALER_EXCHANGE_get_keys (exchange); + keys = TALER_TESTING_get_keys (ds->is); GNUNET_assert (NULL != keys); gf = TALER_EXCHANGE_get_global_fee (keys, *merge_timestamp); diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c index dfaf31fd4..6449c538c 100644 --- a/src/testing/testing_api_cmd_refresh.c +++ b/src/testing/testing_api_cmd_refresh.c @@ -371,12 +371,8 @@ reveal_cb (void *cls, struct RefreshRevealState *rrs = cls; const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr; const struct TALER_TESTING_Command *melt_cmd; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (rrs->is); rrs->rrh = NULL; - if (NULL == exchange) - return; if (rrs->expected_response_code != hr->http_status) { if (0 != rrs->do_retry) @@ -1006,12 +1002,8 @@ melt_run (void *cls, NULL }; const char **melt_fresh_amounts; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); rms->cmd = cmd; - if (NULL == exchange) - return; if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts)) melt_fresh_amounts = default_melt_fresh_amounts; rms->is = is; @@ -1115,7 +1107,7 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } - fresh_pk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (exchange), + fresh_pk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (rms->is), &fresh_amount, age_restricted); if (NULL == fresh_pk) diff --git a/src/testing/testing_api_cmd_reserve_history.c b/src/testing/testing_api_cmd_reserve_history.c index 6e68bbe26..a7df69e6e 100644 --- a/src/testing/testing_api_cmd_reserve_history.c +++ b/src/testing/testing_api_cmd_reserve_history.c @@ -230,19 +230,15 @@ reserve_history_cb (void *cls, struct HistoryState *ss = cls; struct TALER_TESTING_Interpreter *is = ss->is; struct TALER_Amount eb; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); ss->rsh = NULL; - if (NULL == exchange) - return; if (MHD_HTTP_OK == rs->hr.http_status) { - const struct TALER_EXCHANGE_Keys *keys; + struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_GlobalFee *gf; ss->reserve_history.type = TALER_EXCHANGE_RTT_HISTORY; - keys = TALER_EXCHANGE_get_keys (exchange); + keys = TALER_TESTING_get_keys (is); GNUNET_assert (NULL != keys); gf = TALER_EXCHANGE_get_global_fee (keys, rs->ts); @@ -343,11 +339,7 @@ history_run (void *cls, { struct HistoryState *ss = cls; const struct TALER_TESTING_Command *create_reserve; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); - if (NULL == exchange) - return; ss->is = is; create_reserve = TALER_TESTING_interpreter_lookup_command (is, diff --git a/src/testing/testing_api_cmd_reserve_open.c b/src/testing/testing_api_cmd_reserve_open.c index a78662c33..189d06b26 100644 --- a/src/testing/testing_api_cmd_reserve_open.c +++ b/src/testing/testing_api_cmd_reserve_open.c @@ -165,11 +165,7 @@ open_run (void *cls, struct OpenState *ss = cls; const struct TALER_TESTING_Command *create_reserve; struct TALER_EXCHANGE_PurseDeposit cp[GNUNET_NZL (ss->cpl)]; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); - if (NULL == exchange) - return; ss->is = is; create_reserve = TALER_TESTING_interpreter_lookup_command (is, diff --git a/src/testing/testing_api_cmd_reserve_purse.c b/src/testing/testing_api_cmd_reserve_purse.c index 7a356c231..511e2d498 100644 --- a/src/testing/testing_api_cmd_reserve_purse.c +++ b/src/testing/testing_api_cmd_reserve_purse.c @@ -184,12 +184,8 @@ purse_run (void *cls, struct ReservePurseState *ds = cls; const struct TALER_ReservePrivateKeyP *reserve_priv; const struct TALER_TESTING_Command *ref; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); (void) cmd; - if (NULL == exchange) - return; ds->is = is; ref = TALER_TESTING_interpreter_lookup_command (ds->is, ds->reserve_ref); diff --git a/src/testing/testing_api_cmd_reserve_status.c b/src/testing/testing_api_cmd_reserve_status.c index 2da1bf740..001582ed8 100644 --- a/src/testing/testing_api_cmd_reserve_status.c +++ b/src/testing/testing_api_cmd_reserve_status.c @@ -314,11 +314,7 @@ status_run (void *cls, { struct StatusState *ss = cls; const struct TALER_TESTING_Command *create_reserve; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); - if (NULL == exchange) - return; ss->is = is; create_reserve = TALER_TESTING_interpreter_lookup_command (is, diff --git a/src/testing/testing_api_cmd_serialize_keys.c b/src/testing/testing_api_cmd_serialize_keys.c index 9e5a25c4c..13464dffd 100644 --- a/src/testing/testing_api_cmd_serialize_keys.c +++ b/src/testing/testing_api_cmd_serialize_keys.c @@ -58,12 +58,12 @@ serialize_keys_run (void *cls, struct TALER_TESTING_Interpreter *is) { struct SerializeKeysState *sks = cls; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); + struct TALER_EXCHANGE_Keys *keys + = TALER_TESTING_get_keys (is); - if (NULL == exchange) + if (NULL == keys) return; - sks->keys = TALER_EXCHANGE_serialize_data (exchange); + sks->keys = TALER_EXCHANGE_keys_to_json (keys); if (NULL == sks->keys) { GNUNET_break (0); @@ -71,7 +71,7 @@ serialize_keys_run (void *cls, } sks->exchange_url = GNUNET_strdup ( - TALER_EXCHANGE_get_base_url (exchange)); + TALER_TESTING_get_exchange_url (is)); TALER_TESTING_interpreter_next (is); } diff --git a/src/testing/testing_api_cmd_transfer_get.c b/src/testing/testing_api_cmd_transfer_get.c index 37fe736ba..da3585d6c 100644 --- a/src/testing/testing_api_cmd_transfer_get.c +++ b/src/testing/testing_api_cmd_transfer_get.c @@ -309,12 +309,8 @@ track_transfer_run (void *cls, struct TrackTransferState *tts = cls; struct TALER_WireTransferIdentifierRawP wtid; const struct TALER_WireTransferIdentifierRawP *wtid_ptr; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); tts->cmd = cmd; - if (NULL == exchange) - return; /* If no reference is given, we'll use a all-zeros * WTID */ memset (&wtid, diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c index a6315f91e..3e735ad01 100644 --- a/src/testing/testing_api_cmd_withdraw.c +++ b/src/testing/testing_api_cmd_withdraw.c @@ -347,7 +347,6 @@ withdraw_run (void *cls, const struct TALER_ReservePrivateKeyP *rp; const struct TALER_TESTING_Command *create_reserve; const struct TALER_EXCHANGE_DenomPublicKey *dpk; - struct TALER_EXCHANGE_Handle *exchange; ws->cmd = cmd; ws->is = is; @@ -369,12 +368,9 @@ withdraw_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - exchange = TALER_TESTING_get_exchange (is); - if (NULL == exchange) - return; if (NULL == ws->exchange_url) ws->exchange_url - = GNUNET_strdup (TALER_EXCHANGE_get_base_url (exchange)); + = GNUNET_strdup (TALER_TESTING_get_exchange_url (is)); ws->reserve_priv = *rp; GNUNET_CRYPTO_eddsa_key_get_public (&ws->reserve_priv.eddsa_priv, &ws->reserve_pub.eddsa_pub); diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c index d00a8d8ca..799ae6718 100644 --- a/src/testing/testing_api_traits.c +++ b/src/testing/testing_api_traits.c @@ -75,33 +75,6 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, } -struct TALER_EXCHANGE_Handle * -TALER_TESTING_get_exchange (struct TALER_TESTING_Interpreter *is) -{ - struct TALER_EXCHANGE_Handle *exchange; - const struct TALER_TESTING_Command *exchange_cmd; - - exchange_cmd - = TALER_TESTING_interpreter_get_command (is, - "exchange"); - if (NULL == exchange_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return NULL; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_exchange (exchange_cmd, - &exchange)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return NULL; - } - return exchange; -} - - const char * TALER_TESTING_get_exchange_url (struct TALER_TESTING_Interpreter *is) {