From 7201ce3166127e45f924c3119c3037917d32e594 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 5 Jul 2022 12:56:55 +0200 Subject: [PATCH] -handle withdraw CS nonce reuse more nicely --- src/exchange/taler-exchange-httpd_withdraw.c | 15 +++++++++++---- src/exchangedb/exchange-0001-part.sql | 10 ++++++++-- src/exchangedb/plugin_exchangedb_postgres.c | 5 +++++ src/include/taler_exchangedb_plugin.h | 2 ++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c index 86d2c62b0..8d001488d 100644 --- a/src/exchange/taler-exchange-httpd_withdraw.c +++ b/src/exchange/taler-exchange-httpd_withdraw.c @@ -97,6 +97,7 @@ withdraw_transaction (void *cls, enum GNUNET_DB_QueryStatus qs; bool found = false; bool balance_ok = false; + bool nonce_ok = false; struct GNUNET_TIME_Timestamp now; uint64_t ruuid; const struct TALER_CsNonce *nonce; @@ -108,16 +109,13 @@ withdraw_transaction (void *cls, (TALER_DENOMINATION_CS == bp->cipher) ? &bp->details.cs_blinded_planchet.nonce : NULL; - // FIXME: what error is returned on nonce reuse? - // Should expand function to return this error - // specifically, and then we should return a - // TALER_EC_EXCHANGE_WITHDRAW_NONCE_REUSE, qs = TEH_plugin->do_withdraw (TEH_plugin->cls, nonce, &wc->collectable, now, &found, &balance_ok, + &nonce_ok, &wc->kyc, &ruuid); if (0 > qs) @@ -146,6 +144,15 @@ withdraw_transaction (void *cls, &wc->collectable.reserve_pub); return GNUNET_DB_STATUS_HARD_ERROR; } + if (! nonce_ok) + { + TEH_plugin->rollback (TEH_plugin->cls); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_EXCHANGE_WITHDRAW_NONCE_REUSE, + NULL); + return GNUNET_DB_STATUS_HARD_ERROR; + } if ( (TEH_KYC_NONE != TEH_kyc_config.mode) && (! wc->kyc.ok) && (TALER_EXCHANGEDB_KYC_W2W == wc->kyc.type) ) diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql index e24129957..d002fed8c 100644 --- a/src/exchangedb/exchange-0001-part.sql +++ b/src/exchangedb/exchange-0001-part.sql @@ -1422,6 +1422,7 @@ CREATE OR REPLACE FUNCTION exchange_do_withdraw( IN min_reserve_gc INT8, OUT reserve_found BOOLEAN, OUT balance_ok BOOLEAN, + OUT nonce_ok BOOLEAN, OUT kycok BOOLEAN, OUT account_uuid INT8, OUT ruuid INT8) @@ -1478,6 +1479,7 @@ THEN -- reserve unknown reserve_found=FALSE; balance_ok=FALSE; + nonce_ok=TRUE; kycok=FALSE; account_uuid=0; ruuid=2; @@ -1511,6 +1513,7 @@ THEN -- idempotent query, all constraints must be satisfied reserve_found=TRUE; balance_ok=TRUE; + nonce_ok=TRUE; kycok=TRUE; account_uuid=0; RETURN; @@ -1534,6 +1537,7 @@ ELSE reserve_frac=reserve_frac - amount_frac; ELSE reserve_found=TRUE; + nonce_ok=TRUE; -- we do not really know balance_ok=FALSE; kycok=FALSE; -- we do not really know or care account_uuid=0; @@ -1585,10 +1589,12 @@ THEN balance_ok=FALSE; kycok=FALSE; account_uuid=0; - ruuid=1; -- FIXME: return error message more nicely! - ASSERT false, 'nonce reuse attempted by client'; + nonce_ok=FALSE; + RETURN; END IF; END IF; +ELSE + nonce_ok=TRUE; -- no nonce, hence OK! END IF; diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 53be0364c..63f075210 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -827,6 +827,7 @@ prepare_statements (struct PostgresClosure *pg) "SELECT " " reserve_found" ",balance_ok" + ",nonce_ok" ",kycok AS kyc_ok" ",account_uuid AS payment_target_uuid" ",ruuid" @@ -5906,6 +5907,7 @@ postgres_get_withdraw_info ( * @param now current time (rounded) * @param[out] found set to true if the reserve was found * @param[out] balance_ok set to true if the balance was sufficient + * @param[out] nonce_ok set to false if the nonce was reused * @param[out] kyc set to true if the kyc status of the reserve is satisfied * @param[out] ruuid set to the reserve's UUID (reserves table row) * @return query execution status @@ -5918,6 +5920,7 @@ postgres_do_withdraw ( struct GNUNET_TIME_Timestamp now, bool *found, bool *balance_ok, + bool *nonce_ok, struct TALER_EXCHANGEDB_KycStatus *kyc, uint64_t *ruuid) { @@ -5944,6 +5947,8 @@ postgres_do_withdraw ( balance_ok), GNUNET_PQ_result_spec_bool ("kyc_ok", &kyc->ok), + GNUNET_PQ_result_spec_bool ("nonce_ok", + nonce_ok), GNUNET_PQ_result_spec_uint64 ("payment_target_uuid", &kyc->payment_target_uuid), GNUNET_PQ_result_spec_uint64 ("ruuid", diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index c3661d83b..4a871786f 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -3171,6 +3171,7 @@ struct TALER_EXCHANGEDB_Plugin * @param now current time (rounded) * @param[out] found set to true if the reserve was found * @param[out] balance_ok set to true if the balance was sufficient + * @param[out] nonce_ok set to false if the nonce was reused * @param[out] kyc set to the KYC status of the reserve * @param[out] ruuid set to the reserve's UUID (reserves table row) * @return query execution status @@ -3183,6 +3184,7 @@ struct TALER_EXCHANGEDB_Plugin struct GNUNET_TIME_Timestamp now, bool *found, bool *balance_ok, + bool *nonce_ok, struct TALER_EXCHANGEDB_KycStatus *kyc_ok, uint64_t *ruuid);