From 299b4b78e0e4b8f194d0f0db18e22b540b174b88 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 4 Apr 2020 13:27:46 +0200 Subject: return more error details for /wire and /keys to clients --- src/include/taler_error_codes.h | 6 ++ src/include/taler_exchange_service.h | 12 ++- src/include/taler_testing_lib.h | 8 +- src/lib/exchange_api_handle.c | 126 +++++++++++++++------------ src/lib/exchange_api_wire.c | 6 +- src/testing/testing_api_cmd_serialize_keys.c | 2 +- src/testing/testing_api_cmd_wire.c | 5 +- src/testing/testing_api_loop.c | 29 +++--- 8 files changed, 121 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index ce75cf6ac..7bdbd573a 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -111,6 +111,12 @@ enum TALER_ErrorCode */ TALER_EC_WRONG_NUMBER_OF_SEGMENTS = 12, + /** + * The start and end-times in the wire fee structure leave a hole. + * This is not allowed. Generated as an error on the client-side. + */ + TALER_EC_HOLE_IN_WIRE_FEE_STRUCTURE = 13, + /** * The exchange failed to even just initialize its connection to the * database. This response is provided with HTTP status code diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index e935c9196..5f7cf6033 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -359,12 +359,18 @@ enum TALER_EXCHANGE_VersionCompatibility * @param keys information about the various keys used * by the exchange, NULL if /keys failed * @param compat protocol compatibility information + * @param ec error code, #TALER_EC_NONE on success + * @param http_status status returned by /keys, #MHD_HTTP_OK on success + * @param full_reply JSON body of /keys request, NULL if reply was not in JSON */ typedef void (*TALER_EXCHANGE_CertificationCallback) ( void *cls, const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat); + enum TALER_EXCHANGE_VersionCompatibility compat, + enum TALER_ErrorCode ec, + unsigned int http_status, + const json_t *full_reply); /** @@ -649,6 +655,7 @@ struct TALER_EXCHANGE_WireAccount * @param ec taler-specific error code, #TALER_EC_NONE on success * @param accounts_len length of the @a accounts array * @param accounts list of wire accounts of the exchange, NULL on error + * @param full_reply the complete reply from the exchange (if it was in JSON) */ typedef void (*TALER_EXCHANGE_WireCallback) ( @@ -656,7 +663,8 @@ typedef void unsigned int http_status, enum TALER_ErrorCode ec, unsigned int accounts_len, - const struct TALER_EXCHANGE_WireAccount *accounts); + const struct TALER_EXCHANGE_WireAccount *accounts, + const json_t *full_reply); /** diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index c8949ee38..be20e0cd7 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -137,11 +137,17 @@ TALER_TESTING_prepare_exchange (const char *config_filename, * all the commands to be run, and a closure for it. * @param keys the exchange's keys. * @param compat protocol compatibility information. + * @param ec error code, #TALER_EC_NONE on success + * @param http_status status returned by /keys, #MHD_HTTP_OK on success + * @param full_reply JSON body of /keys request, NULL if reply was not in JSON */ void TALER_TESTING_cert_cb (void *cls, const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat); + enum TALER_EXCHANGE_VersionCompatibility compat, + enum TALER_ErrorCode ec, + unsigned int http_status, + const json_t *full_reply); /** diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index cb02f68e0..8ae5b06d2 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -373,7 +373,6 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, json_t *sign_key_obj, const struct TALER_MasterPublicKeyP *master_key) { - struct TALER_ExchangeSigningKeyValidityPS sign_key_issue; struct TALER_MasterSignatureP sign_key_issue_sig; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("master_sig", @@ -400,23 +399,26 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, if (! check_sigs) return GNUNET_OK; - sign_key_issue.signkey_pub = sign_key->key; - sign_key_issue.purpose.purpose = htonl ( - TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY); - sign_key_issue.purpose.size = htonl (sizeof (struct - TALER_ExchangeSigningKeyValidityPS)); - sign_key_issue.master_public_key = *master_key; - sign_key_issue.start = GNUNET_TIME_absolute_hton (sign_key->valid_from); - sign_key_issue.expire = GNUNET_TIME_absolute_hton (sign_key->valid_until); - sign_key_issue.end = GNUNET_TIME_absolute_hton (sign_key->valid_legal); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY, - &sign_key_issue.purpose, - &sign_key_issue_sig.eddsa_signature, - &master_key->eddsa_pub)) { - GNUNET_break_op (0); - return GNUNET_SYSERR; + struct TALER_ExchangeSigningKeyValidityPS sign_key_issue = { + .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY), + .purpose.size = htonl (sizeof (sign_key_issue)), + .signkey_pub = sign_key->key, + .master_public_key = *master_key, + .start = GNUNET_TIME_absolute_hton (sign_key->valid_from), + .expire = GNUNET_TIME_absolute_hton (sign_key->valid_until), + .end = GNUNET_TIME_absolute_hton (sign_key->valid_legal) + }; + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY, + &sign_key_issue.purpose, + &sign_key_issue_sig.eddsa_signature, + &master_key->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } } sign_key->master_sig = sign_key_issue_sig; return GNUNET_OK; @@ -441,7 +443,6 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, struct TALER_MasterPublicKeyP *master_key, struct GNUNET_HashContext *hash_context) { - struct TALER_DenominationKeyValidityPS denom_key_issue; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("master_sig", &denom_key->master_sig), @@ -479,46 +480,50 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, GNUNET_CRYPTO_rsa_public_key_hash (denom_key->key.rsa_public_key, &denom_key->h_key); + if (NULL != hash_context) + GNUNET_CRYPTO_hash_context_read (hash_context, + &denom_key->h_key, + sizeof (struct GNUNET_HashCode)); if (! check_sigs) return GNUNET_OK; - memset (&denom_key_issue, - 0, - sizeof (denom_key_issue)); - denom_key_issue.purpose.purpose - = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY); - denom_key_issue.purpose.size - = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); - denom_key_issue.master = *master_key; - denom_key_issue.denom_hash = denom_key->h_key; - denom_key_issue.start = GNUNET_TIME_absolute_hton (denom_key->valid_from); - denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton ( - denom_key->withdraw_valid_until); - denom_key_issue.expire_deposit = GNUNET_TIME_absolute_hton ( - denom_key->expire_deposit); - denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton ( - denom_key->expire_legal); - TALER_amount_hton (&denom_key_issue.value, - &denom_key->value); - TALER_amount_hton (&denom_key_issue.fee_withdraw, - &denom_key->fee_withdraw); - TALER_amount_hton (&denom_key_issue.fee_deposit, - &denom_key->fee_deposit); - TALER_amount_hton (&denom_key_issue.fee_refresh, - &denom_key->fee_refresh); - TALER_amount_hton (&denom_key_issue.fee_refund, - &denom_key->fee_refund); - EXITIF (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_verify ( - TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY, - &denom_key_issue.purpose, - &denom_key->master_sig.eddsa_signature, - &master_key->eddsa_pub)); - GNUNET_CRYPTO_hash_context_read (hash_context, - &denom_key_issue.denom_hash, - sizeof (struct GNUNET_HashCode)); + { + struct TALER_DenominationKeyValidityPS denom_key_issue = { + .purpose.purpose + = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY), + .purpose.size = htonl (sizeof (denom_key_issue)), + .master = *master_key, + .denom_hash = denom_key->h_key, + .start = GNUNET_TIME_absolute_hton (denom_key->valid_from), + .expire_withdraw + = GNUNET_TIME_absolute_hton (denom_key->withdraw_valid_until), + .expire_deposit = GNUNET_TIME_absolute_hton (denom_key->expire_deposit), + .expire_legal = GNUNET_TIME_absolute_hton (denom_key->expire_legal) + }; + + TALER_amount_hton (&denom_key_issue.value, + &denom_key->value); + TALER_amount_hton (&denom_key_issue.fee_withdraw, + &denom_key->fee_withdraw); + TALER_amount_hton (&denom_key_issue.fee_deposit, + &denom_key->fee_deposit); + TALER_amount_hton (&denom_key_issue.fee_refresh, + &denom_key->fee_refresh); + TALER_amount_hton (&denom_key_issue.fee_refund, + &denom_key->fee_refund); + EXITIF (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY, + &denom_key_issue.purpose, + &denom_key->master_sig.eddsa_signature, + &master_key->eddsa_pub)); + } return GNUNET_OK; EXITIF_exit: + /* invalidate denom_key, just to be sure */ + memset (denom_key, + 0, + sizeof (*denom_key)); GNUNET_JSON_parse_free (spec); return GNUNET_SYSERR; } @@ -1376,7 +1381,10 @@ keys_completed_cb (void *cls, /* notify application that we failed */ exchange->cert_cb (exchange->cert_cb_cls, NULL, - vc); + vc, + TALER_JSON_get_error_code (j), + response_code, + j); return; } @@ -1390,7 +1398,10 @@ keys_completed_cb (void *cls, /* notify application about the key information */ exchange->cert_cb (exchange->cert_cb_cls, &exchange->key_data, - vc); + vc, + TALER_EC_NONE, + MHD_HTTP_OK, + j); free_key_data (&kd_old); } @@ -1612,7 +1623,10 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange, /* notify application about the key information */ exchange->cert_cb (exchange->cert_cb_cls, &exchange->key_data, - vc); + vc, + TALER_EC_NONE, + MHD_HTTP_OK, + data); GNUNET_JSON_parse_free (spec); } diff --git a/src/lib/exchange_api_wire.c b/src/lib/exchange_api_wire.c index ccab4562d..3f3998f5b 100644 --- a/src/lib/exchange_api_wire.c +++ b/src/lib/exchange_api_wire.c @@ -328,7 +328,8 @@ handle_wire_finished (void *cls, response_code, ec, num_accounts, - was); + was, + j); wh->cb = NULL; } } /* end of 'parse accounts */ @@ -367,7 +368,8 @@ handle_wire_finished (void *cls, response_code, ec, 0, - NULL); + NULL, + j); TALER_EXCHANGE_wire_cancel (wh); } diff --git a/src/testing/testing_api_cmd_serialize_keys.c b/src/testing/testing_api_cmd_serialize_keys.c index 296a2ddc7..8a723c5ba 100644 --- a/src/testing/testing_api_cmd_serialize_keys.c +++ b/src/testing/testing_api_cmd_serialize_keys.c @@ -209,7 +209,7 @@ connect_with_state_run (void *cls, &exchange_url)); is->exchange = TALER_EXCHANGE_connect (is->ctx, exchange_url, - TALER_TESTING_cert_cb, + &TALER_TESTING_cert_cb, cwss, TALER_EXCHANGE_OPTION_DATA, serialized_keys, diff --git a/src/testing/testing_api_cmd_wire.c b/src/testing/testing_api_cmd_wire.c index 2d79a546f..c8946bb93 100644 --- a/src/testing/testing_api_cmd_wire.c +++ b/src/testing/testing_api_cmd_wire.c @@ -77,19 +77,22 @@ struct WireState * @param accounts_len length of the @a accounts array. * @param accounts list of wire accounts of the exchange, * NULL on error. + * @param full_reply the complete response from the exchange */ static void wire_cb (void *cls, unsigned int http_status, enum TALER_ErrorCode ec, unsigned int accounts_len, - const struct TALER_EXCHANGE_WireAccount *accounts) + const struct TALER_EXCHANGE_WireAccount *accounts, + const json_t *full_reply) { struct WireState *ws = cls; struct TALER_TESTING_Command *cmd = &ws->is->commands[ws->is->ip]; struct TALER_Amount expected_fee; (void) ec; + (void) full_reply; TALER_LOG_DEBUG ("Checking parsed /wire response\n"); ws->wh = NULL; if (ws->expected_response_code != http_status) diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index 361fe6305..51cd74a23 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c @@ -570,7 +570,7 @@ struct MainContext * respective handler by writing to the trigger pipe. */ static void -sighandler_child_death () +sighandler_child_death (void) { static char c; int old_errno = errno; /* back-up errno */ @@ -591,24 +591,31 @@ sighandler_child_death () * all the commands to be run, and a closure for it. * @param keys the exchange's keys. * @param compat protocol compatibility information. + * @param ec error code, #TALER_EC_NONE on success + * @param http_status status returned by /keys, #MHD_HTTP_OK on success + * @param full_reply JSON body of /keys request, NULL if reply was not in JSON */ void TALER_TESTING_cert_cb (void *cls, const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat) + enum TALER_EXCHANGE_VersionCompatibility compat, + enum TALER_ErrorCode ec, + unsigned int http_status, + const json_t *full_reply) { struct MainContext *main_ctx = cls; struct TALER_TESTING_Interpreter *is = main_ctx->is; (void) compat; + (void) full_reply; if (NULL == keys) { if (GNUNET_NO == is->working) { - GNUNET_log - (GNUNET_ERROR_TYPE_WARNING, - "Got NULL response for /keys" - " during startup, retrying!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Got NULL response for /keys during startup (%u/%d), retrying!\n", + http_status, + (int) ec); TALER_EXCHANGE_disconnect (is->exchange); GNUNET_assert (NULL != (is->exchange = TALER_EXCHANGE_connect @@ -620,10 +627,12 @@ TALER_TESTING_cert_cb (void *cls, return; } else - GNUNET_log - (GNUNET_ERROR_TYPE_ERROR, - "Got NULL response for /keys" - " during execution!\n"); + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Got NULL response for /keys during execution (%u/%d)!\n", + http_status, + (int) ec); + } } else { -- cgit v1.2.3