summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-09-19 17:07:08 +0200
committerChristian Grothoff <christian@grothoff.org>2023-09-19 17:07:36 +0200
commit73b8b9e975e0ce0be169a669a06f436223bb2c9d (patch)
treeda566f8551fc5101ea4c62ce35346078a31682c6 /src/lib
parent5846c63f935ed30914b34ccab46d1b6ea9e1bc74 (diff)
downloadmerchant-73b8b9e975e0ce0be169a669a06f436223bb2c9d.tar.gz
merchant-73b8b9e975e0ce0be169a669a06f436223bb2c9d.tar.bz2
merchant-73b8b9e975e0ce0be169a669a06f436223bb2c9d.zip
fix report when same exchange URL is configured in multiple configuration sections
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/merchant_api_post_order_pay.c284
1 files changed, 4 insertions, 280 deletions
diff --git a/src/lib/merchant_api_post_order_pay.c b/src/lib/merchant_api_post_order_pay.c
index fc2e9a29..5a5c1631 100644
--- a/src/lib/merchant_api_post_order_pay.c
+++ b/src/lib/merchant_api_post_order_pay.c
@@ -109,12 +109,6 @@ struct TALER_MERCHANT_OrderPayHandle
json_t *error_history;
/**
- * Handle to the exchange that issued a problematic
- * coin (if any).
- */
- struct TALER_EXCHANGE_GetKeysHandle *exchange;
-
- /**
* Number of @e coins we are paying with.
*/
unsigned int num_coins;
@@ -129,254 +123,6 @@ struct TALER_MERCHANT_OrderPayHandle
/**
- * We got a 409 response back from the exchange (or the merchant).
- * Now we need to check the provided cryptographic proof that the
- * coin was actually already spent!
- *
- * @param oph operation handle
- * @param keys key data from the exchange
- * @return #GNUNET_OK if conflict is valid
- */
-static enum GNUNET_GenericReturnValue
-check_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
- const struct TALER_EXCHANGE_Keys *keys)
-{
- struct TALER_Amount spent;
- struct TALER_Amount spent_plus_contrib;
- struct TALER_DenominationHashP h_denom_pub_pc;
- const struct TALER_EXCHANGE_DenomPublicKey *dpk;
-
- TALER_denom_pub_hash (&oph->error_pc->denom_pub,
- &h_denom_pub_pc);
- dpk = TALER_EXCHANGE_get_denomination_key_by_hash (
- keys,
- &h_denom_pub_pc);
- if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (dpk,
- &oph->error_pc->coin_pub,
- oph->error_history,
- &spent))
- {
- /* Exchange's history fails to verify */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (0 >
- TALER_amount_add (&spent_plus_contrib,
- &spent,
- &oph->error_pc->amount_with_fee))
- {
- /* We got an integer overflow? Bad application! */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (-1 != TALER_amount_cmp (&oph->error_pc->denom_value,
- &spent_plus_contrib))
- {
- /* according to our calculations, the transaction should
- have still worked, AND we did not get any proof of
- coin public key re-use; hence: exchange error! */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Accepting proof of double-spending (or coin public key re-use)\n");
- return GNUNET_OK;
-}
-
-
-/**
- * We got the fee structure from the exchange. Now
- * validate the conflict error.
- *
- * @param cls a `struct TALER_MERCHANT_OrderPayHandle`
- * @param kr reply from the exchange
- * @param keys keys of the exchange
- */
-static void
-cert_cb (void *cls,
- const struct TALER_EXCHANGE_KeysResponse *kr,
- struct TALER_EXCHANGE_Keys *keys)
-{
- struct TALER_MERCHANT_OrderPayHandle *oph = cls;
- const struct TALER_EXCHANGE_HttpResponse *ehr = &kr->hr;
-
- oph->exchange = NULL;
- if ( (MHD_HTTP_OK != ehr->http_status) ||
- (NULL == kr->details.ok.keys) ||
- (NULL == keys) )
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = MHD_HTTP_CONFLICT,
- .hr.exchange_http_status = ehr->http_status,
- .hr.ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- .hr.reply = oph->full_reply,
- .hr.exchange_reply = ehr->reply,
- .hr.hint = "failed to download /keys from the exchange"
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- return;
- }
- if (TALER_EXCHANGE_VC_INCOMPATIBLE & kr->details.ok.compat)
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = MHD_HTTP_CONFLICT,
- .hr.exchange_http_status = 0,
- .hr.ec = TALER_EC_WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE,
- .hr.reply = oph->full_reply,
- .hr.exchange_reply = ehr->reply,
- .hr.hint = "could not check error: incompatible exchange version"
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- TALER_EXCHANGE_keys_decref (keys);
- return;
- }
-
- if (GNUNET_OK !=
- check_conflict (oph,
- kr->details.ok.keys))
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = 0,
- .hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE,
- .hr.reply = oph->full_reply
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- TALER_EXCHANGE_keys_decref (keys);
- return;
- }
-
- {
- struct TALER_MERCHANT_PayResponse pr = {
- .hr.http_status = MHD_HTTP_CONFLICT,
- .hr.ec = TALER_JSON_get_error_code (oph->full_reply),
- .hr.reply = oph->full_reply
- };
-
- oph->pay_cb (oph->pay_cb_cls,
- &pr);
- TALER_MERCHANT_order_pay_cancel (oph);
- TALER_EXCHANGE_keys_decref (keys);
- }
-}
-
-
-/**
- * We got a 409 response back from the exchange (or the merchant).
- * Now we need to check the provided cryptograophic proof that the
- * coin was actually already spent!
- *
- * @param[in,out] oph handle of the original pay operation
- * @param[in,out] pr response to modify if #GNUNET_OK is returned
- * @param json cryptograophic proof returned by the
- * exchange/merchant
- * @return #GNUNET_OK if proof checks out,
- * #GNUNET_SYSERR if it is wrong,
- * #GNUNET_NO if checking continues asynchronously
- */
-static enum GNUNET_GenericReturnValue
-parse_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
- struct TALER_MERCHANT_PayResponse *pr,
- const json_t *json)
-{
- const json_t *ereply;
- const char *exchange_url;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_object_const ("exchange_reply",
- &ereply),
- GNUNET_JSON_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_JSON_Specification hspec[] = {
- GNUNET_JSON_spec_json ("history",
- &oph->error_history),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &coin_pub),
- GNUNET_JSON_spec_end ()
- };
- enum TALER_ErrorCode ec = TALER_JSON_get_error_code (json);
-
- switch (ec)
- {
- case TALER_EC_GENERIC_CURRENCY_MISMATCH:
- /* no proof to check, still very strange, as we
- should have checked that the currency matches */
- GNUNET_break_op (0);
- TALER_MERCHANT_parse_error_details_ (json,
- MHD_HTTP_CONFLICT,
- &pr->hr);
- return GNUNET_OK;
- case TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID:
- /* We can only be happy and accept the result;
- FIXME: parse the refunds... */
- TALER_MERCHANT_parse_error_details_ (json,
- MHD_HTTP_CONFLICT,
- &pr->hr);
- return GNUNET_OK;
- case TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_FUNDS:
- /* main case, handled below */
- break;
- default:
- GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected error code %d: %s\n",
- ec,
- TALER_ErrorCode_get_hint (ec));
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_JSON_parse (ereply,
- hspec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- for (unsigned int i = 0; i<oph->num_coins; i++)
- {
- if (0 ==
- GNUNET_memcmp (&oph->coins[i].coin_pub,
- &coin_pub))
- {
- oph->error_pc = &oph->coins[i];
- oph->full_reply = json_incref ((json_t *) json);
- oph->exchange = TALER_EXCHANGE_get_keys (oph->ctx,
- oph->error_pc->exchange_url,
- NULL,
- &cert_cb,
- oph);
- return GNUNET_NO;
- }
- }
- GNUNET_break_op (0); /* complaint is not about any of the coins
- that we actually paid with... */
- GNUNET_JSON_parse_free (hspec);
- return GNUNET_SYSERR;
-}
-
-
-/**
* Function called when we're done processing the
* HTTP /pay request.
*
@@ -486,27 +232,10 @@ handle_pay_finished (void *cls,
Pass on to application. */
break;
case MHD_HTTP_CONFLICT:
- {
- enum GNUNET_GenericReturnValue ret;
-
- ret = parse_conflict (oph,
- &pr,
- json);
- switch (ret)
- {
- case GNUNET_OK:
- /* continued below, 'pr' was modified */
- break;
- case GNUNET_NO:
- /* handled asynchronously! */
- return; /* ! */
- case GNUNET_SYSERR:
- GNUNET_break_op (0);
- pr.hr.http_status = 0;
- break;
- }
- break;
- }
+ TALER_MERCHANT_parse_error_details_ (json,
+ MHD_HTTP_CONFLICT,
+ &pr.hr);
+ break;
case MHD_HTTP_GONE:
TALER_MERCHANT_parse_error_details_ (json,
response_code,
@@ -830,11 +559,6 @@ TALER_MERCHANT_order_pay_cancel (struct TALER_MERCHANT_OrderPayHandle *oph)
GNUNET_CURL_job_cancel (oph->job);
oph->job = NULL;
}
- if (NULL != oph->exchange)
- {
- TALER_EXCHANGE_get_keys_cancel (oph->exchange);
- oph->exchange = NULL;
- }
TALER_curl_easy_post_finished (&oph->post_ctx);
json_decref (oph->error_history);
json_decref (oph->full_reply);