summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2023-10-13 20:51:04 +0200
committerChristian Grothoff <grothoff@gnunet.org>2023-10-13 21:16:50 +0200
commit0f3490dc022620c7e42b86426e14198a04c2e17f (patch)
tree0b16661ae6aa9273bf81652fe6a8806060b31fb0
parenta5f50083e65a3e9a0945b150701349afa81a0e9e (diff)
downloadmerchant-0f3490dc022620c7e42b86426e14198a04c2e17f.tar.gz
merchant-0f3490dc022620c7e42b86426e14198a04c2e17f.tar.bz2
merchant-0f3490dc022620c7e42b86426e14198a04c2e17f.zip
more work on multicurrency support: use checks everywhere...
-rw-r--r--src/backend/taler-merchant-httpd_get-orders-ID.c135
-rw-r--r--src/backend/taler-merchant-httpd_helper.c8
-rw-r--r--src/backend/taler-merchant-httpd_post-orders-ID-pay.c159
-rw-r--r--src/backend/taler-merchant-httpd_post-using-templates.c23
-rw-r--r--src/backend/taler-merchant-httpd_private-get-orders-ID.c96
-rw-r--r--src/backend/taler-merchant-httpd_private-get-orders.c11
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c18
-rw-r--r--src/backend/taler-merchant-httpd_private-post-templates.c2
-rw-r--r--src/backenddb/pg_increase_refund.c9
9 files changed, 363 insertions, 98 deletions
diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c b/src/backend/taler-merchant-httpd_get-orders-ID.c
index 9c60f7a9..af5513d9 100644
--- a/src/backend/taler-merchant-httpd_get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_get-orders-ID.c
@@ -120,6 +120,22 @@ struct GetOrderData
json_t *contract_terms;
/**
+ * Merchant base URL from @e contract_terms.
+ */
+ const char *merchant_base_url;
+
+ /**
+ * Public reorder URL from @e contract_terms.
+ * Could be NULL if contract does not have one.
+ */
+ const char *public_reorder_url;
+
+ /**
+ * Total amount in contract.
+ */
+ struct TALER_Amount contract_total;
+
+ /**
* Total refunds granted for this payment. Only initialized
* if @e refunded is set to true.
*/
@@ -180,6 +196,16 @@ struct GetOrderData
*/
bool generate_html;
+ /**
+ * Did we parse the contract terms?
+ */
+ bool contract_parsed;
+
+ /**
+ * Set to true if the refunds found in the DB have
+ * a different currency then the main contract.
+ */
+ bool bad_refund_currency_in_db;
};
@@ -316,6 +342,9 @@ suspend_god (struct GetOrderData *god)
json_decref (god->contract_terms);
god->fulfillment_url = NULL;
god->contract_terms = NULL;
+ god->contract_parsed = false;
+ god->merchant_base_url = NULL;
+ god->public_reorder_url = NULL;
}
GNUNET_assert (! god->suspended);
god->suspended = GNUNET_YES;
@@ -712,6 +741,16 @@ process_refunds_cb (void *cls,
TALER_B2S (coin_pub),
reason);
god->refund_pending |= pending;
+ if ( (GNUNET_OK !=
+ TALER_amount_cmp_currency (&god->refund_taken,
+ refund_amount)) ||
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&god->refund_amount,
+ refund_amount)) )
+ {
+ god->bad_refund_currency_in_db = true;
+ return;
+ }
if (! pending)
{
GNUNET_assert (0 <=
@@ -767,7 +806,6 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
bool contract_match = false;
bool token_match = false;
bool contract_available = false;
- const char *merchant_base_url;
(void) rh;
if (NULL == god)
@@ -945,10 +983,9 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
if (NULL != god->contract_terms)
{
contract_available = true;
-
- if (GNUNET_YES == GNUNET_is_zero (&god->h_contract_terms))
+ if (GNUNET_YES ==
+ GNUNET_is_zero (&god->h_contract_terms))
{
-
if (GNUNET_OK !=
TALER_JSON_contract_hash (god->contract_terms,
&god->h_contract_terms))
@@ -959,11 +996,9 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
"contract terms");
}
-
}
else
{
-
struct TALER_PrivateContractHashP h;
if (GNUNET_OK !=
@@ -988,9 +1023,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
TALER_EC_MERCHANT_GENERIC_CONTRACT_HASH_DOES_NOT_MATCH_ORDER,
NULL);
}
-
}
-
}
if (contract_available)
@@ -1040,21 +1073,46 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
} /* end unclaimed order logic */
GNUNET_assert (NULL != god->contract_terms);
- merchant_base_url = json_string_value (json_object_get (god->contract_terms,
- "merchant_base_url"));
- if (NULL == merchant_base_url)
+ if (! god->contract_parsed)
{
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
- order_id);
+ struct GNUNET_JSON_Specification espec[] = {
+ TALER_JSON_spec_amount_any ("amount",
+ &god->contract_total),
+ GNUNET_JSON_spec_string ("merchant_base_url",
+ &god->merchant_base_url),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("fulfillment_url",
+ &god->fulfillment_url),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("public_reorder_url",
+ &god->public_reorder_url),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+ const char *ename;
+ unsigned int eline;
+
+ res = GNUNET_JSON_parse (god->contract_terms,
+ espec,
+ &ename,
+ &eline);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse contract %s in DB at field %s\n",
+ order_id,
+ ename);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
+ order_id);
+ }
+ god->contract_parsed = true;
}
- if (NULL == god->fulfillment_url)
- god->fulfillment_url = json_string_value (json_object_get (
- god->contract_terms,
- "fulfillment_url"));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Token match: %d, contract_available: %d, contract match: %d, claimed: %d\n",
token_match,
@@ -1085,15 +1143,11 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
if (! (token_match ||
contract_match) )
{
- const char *public_reorder_url;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Neither claim token nor contract matched\n");
- public_reorder_url = json_string_value (json_object_get (
- god->contract_terms,
- "public_reorder_url"));
/* Client has no rights to this order */
- if (NULL == public_reorder_url)
+ if (NULL == god->public_reorder_url)
{
/* We cannot give the client a new order, just fail */
if (! GNUNET_is_zero (&god->h_contract_terms))
@@ -1135,7 +1189,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
GNUNET_break (MHD_YES ==
MHD_add_response_header (reply,
MHD_HTTP_HEADER_LOCATION,
- public_reorder_url));
+ god->public_reorder_url));
ret = MHD_queue_response (connection,
MHD_HTTP_FOUND,
reply);
@@ -1147,7 +1201,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
connection,
MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_string ("public_reorder_url",
- public_reorder_url));
+ god->public_reorder_url));
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1247,13 +1301,25 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
}
}
+ if ( (god->sc.awaiting_refund) &&
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&god->contract_total,
+ &god->sc.refund_expected)) )
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ god->contract_total.currency);
+ }
+
/* At this point, we know the contract was paid. Let's check for
refunds. First, clear away refunds found from previous invocations. */
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
+ TALER_amount_set_zero (god->contract_total.currency,
&god->refund_amount));
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
+ TALER_amount_set_zero (god->contract_total.currency,
&god->refund_taken));
qs = TMH_db->lookup_refunds_detailed (TMH_db->cls,
hc->instance->settings.id,
@@ -1268,7 +1334,14 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"lookup_refunds_detailed");
}
-
+ if (god->bad_refund_currency_in_db)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "currency mix-up between contract price and refunds in database");
+ }
if ( ((god->sc.awaiting_refund) &&
( (! god->refunded) ||
(1 != TALER_amount_cmp (&god->refund_amount,
@@ -1308,7 +1381,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
char *uri;
GNUNET_assert (NULL != god->contract_terms);
- uri = make_taler_refund_uri (merchant_base_url,
+ uri = make_taler_refund_uri (god->merchant_base_url,
order_id);
if (NULL == uri)
{
diff --git a/src/backend/taler-merchant-httpd_helper.c b/src/backend/taler-merchant-httpd_helper.c
index 53b4fe89..3e525245 100644
--- a/src/backend/taler-merchant-httpd_helper.c
+++ b/src/backend/taler-merchant-httpd_helper.c
@@ -413,6 +413,7 @@ bool
TMH_template_contract_valid (const json_t *template_contract)
{
const char *summary;
+ const char *currency;
struct TALER_Amount amount = { .value = 0};
uint32_t minimum_age = 0;
struct GNUNET_TIME_Relative pay_duration = { 0 };
@@ -421,9 +422,10 @@ TMH_template_contract_valid (const json_t *template_contract)
GNUNET_JSON_spec_string ("summary",
&summary),
NULL),
- /* FIXME: #7951: may want to allow the template to only
- fix the currency but not the amount; current approach
- does not allow this! */
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("currency",
+ &currency),
+ NULL),
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount_any ("amount",
&amount),
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
index d17e98c8..9edc553c 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -399,6 +399,18 @@ struct PayContext
*/
enum GNUNET_GenericReturnValue suspended;
+ /**
+ * Set to true if the deposit currency of a coin
+ * does not match the contract currency.
+ */
+ bool deposit_currency_mismatch;
+
+ /**
+ * Set to true if the database contains a (bogus)
+ * refund for a different currency.
+ */
+ bool refund_currency_mismatch;
+
};
@@ -909,11 +921,13 @@ batch_deposit_transaction (const struct ExchangeGroup *eg,
{
const struct PayContext *pc = eg->pc;
enum GNUNET_DB_QueryStatus qs;
- struct TALER_Amount total_without_fees = { 0 };
+ struct TALER_Amount total_without_fees;
uint64_t b_dep_serial;
uint32_t off = 0;
- bool found = false;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pc->amount.currency,
+ &total_without_fees));
for (unsigned int i = 0; i<pc->coins_cnt; i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
@@ -925,25 +939,14 @@ batch_deposit_transaction (const struct ExchangeGroup *eg,
continue;
if (dc->found_in_db)
continue;
- /* FIXME: #7951 */
GNUNET_assert (0 <=
TALER_amount_subtract (&amount_without_fees,
&dc->cdd.amount,
&dc->deposit_fee));
- if (! found)
- {
- found = true;
- total_without_fees = amount_without_fees;
- }
- else
- {
- /* FIXME: #7951 */
- GNUNET_assert (
- 0 <=
- TALER_amount_add (&total_without_fees,
- &total_without_fees,
- &amount_without_fees));
- }
+ GNUNET_assert (0 <=
+ TALER_amount_add (&total_without_fees,
+ &total_without_fees,
+ &amount_without_fees));
}
qs = TMH_db->insert_deposit_confirmation (
TMH_db->cls,
@@ -960,13 +963,6 @@ batch_deposit_transaction (const struct ExchangeGroup *eg,
if (qs <= 0)
return qs; /* Entire batch already known or failure, we're done */
- if (! found)
- {
- /* All coins already done, but the batch was not? Invariant violation! */
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
for (unsigned int i = 0; i<pc->coins_cnt; i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
@@ -1596,14 +1592,26 @@ check_coin_paid (void *cls,
(0 !=
strcmp (exchange_url,
dc->exchange_url)) ||
- /* FIXME: #7951 */
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (amount_with_fee,
+ &dc->cdd.amount)) ||
(0 != TALER_amount_cmp (amount_with_fee,
&dc->cdd.amount)) )
continue; /* does not match, skip */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Deposit of coin `%s' already in our DB.\n",
TALER_B2S (coin_pub));
- /* FIXME: #7951 */
+ if ( (GNUNET_OK !=
+ TALER_amount_cmp_currency (&pc->total_paid,
+ amount_with_fee)) ||
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&pc->total_fees_paid,
+ deposit_fee)) )
+ {
+ GNUNET_break_op (0);
+ pc->deposit_currency_mismatch = true;
+ break;
+ }
GNUNET_assert (0 <=
TALER_amount_add (&pc->total_paid,
&pc->total_paid,
@@ -1654,7 +1662,14 @@ check_coin_refunded (void *cls,
if (0 != GNUNET_memcmp (coin_pub,
&dc->cdd.coin_pub))
continue;
- /* FIXME: #7951 */
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (&pc->total_refunded,
+ refund_amount))
+ {
+ GNUNET_break (0);
+ pc->refund_currency_mismatch = true;
+ break;
+ }
GNUNET_assert (0 <=
TALER_amount_add (&pc->total_refunded,
&pc->total_refunded,
@@ -1681,15 +1696,12 @@ check_payment_sufficient (struct PayContext *pc)
struct TALER_Amount total_needed;
if (0 == pc->coins_cnt)
+ return TALER_amount_is_zero (&pc->amount);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pc->amount.currency,
+ &total_wire_fee));
+ for (unsigned int i = 0; i < pc->num_exchanges; i++)
{
- return ((0 == pc->amount.value) &&
- (0 == pc->amount.fraction));
- }
-
- total_wire_fee = pc->egs[0]->wire_fee;
- for (unsigned int i = 1; i < pc->num_exchanges; i++)
- {
- /* FIXME: #7951 */
if (GNUNET_OK !=
TALER_amount_cmp_currency (&total_wire_fee,
&pc->egs[i]->wire_fee))
@@ -1700,7 +1712,6 @@ check_payment_sufficient (struct PayContext *pc)
total_wire_fee.currency);
return false;
}
- /* FIXME: #7951 */
if (0 >
TALER_amount_add (&total_wire_fee,
&total_wire_fee,
@@ -1714,19 +1725,34 @@ check_payment_sufficient (struct PayContext *pc)
}
}
- acc_fee = pc->dc[0].deposit_fee;
- acc_amount = pc->dc[0].cdd.amount;
-
/**
* This loops calculates what are the deposit fee / total
* amount with fee / and wire fee, for all the coins.
*/
- for (unsigned int i = 1; i<pc->coins_cnt; i++)
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pc->amount.currency,
+ &acc_fee));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pc->amount.currency,
+ &acc_amount));
+ for (unsigned int i = 0; i<pc->coins_cnt; i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
GNUNET_assert (dc->found_in_db);
- /* FIXME: #7951 */
+ if ( (GNUNET_OK !=
+ TALER_amount_cmp_currency (&acc_fee,
+ &dc->deposit_fee)) ||
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&acc_amount,
+ &dc->cdd.amount)) )
+ {
+ GNUNET_break_op (0);
+ resume_pay_with_error (pc,
+ TALER_EC_GENERIC_CURRENCY_MISMATCH,
+ dc->deposit_fee.currency);
+ return false;
+ }
if ( (0 >
TALER_amount_add (&acc_fee,
&dc->deposit_fee,
@@ -1743,7 +1769,6 @@ check_payment_sufficient (struct PayContext *pc)
"Overflow adding up amounts");
return false;
}
- /* FIXME: #7951 */
if (1 ==
TALER_amount_cmp (&dc->deposit_fee,
&dc->cdd.amount))
@@ -1786,9 +1811,7 @@ check_payment_sufficient (struct PayContext *pc)
return false;
}
-
/* add wire fee to the total fees */
- /* FIXME: #7951 */
if (0 >
TALER_amount_add (&acc_fee,
&acc_fee,
@@ -1800,7 +1823,6 @@ check_payment_sufficient (struct PayContext *pc)
"Overflow adding up amounts");
return false;
}
- /* FIXME: #7951 */
if (-1 == TALER_amount_cmp (&pc->max_fee,
&acc_fee))
{
@@ -2045,6 +2067,14 @@ execute_pay_transaction (struct PayContext *pc)
"lookup deposits");
return;
}
+ if (pc->deposit_currency_mismatch)
+ {
+ GNUNET_break_op (0);
+ resume_pay_with_error (pc,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ pc->amount.currency);
+ return;
+ }
}
@@ -2072,6 +2102,14 @@ execute_pay_transaction (struct PayContext *pc)
"lookup refunds");
return;
}
+ if (pc->refund_currency_mismatch)
+ {
+ TMH_db->rollback (TMH_db->cls);
+ resume_pay_with_error (pc,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "refund currency in database does not match order currency");
+ return;
+ }
}
/* Check if there are coins that still need to be processed */
@@ -2299,7 +2337,6 @@ parse_pay (struct PayContext *pc)
GNUNET_break_op (0);
return res;
}
-
for (unsigned int j = 0; j<coins_index; j++)
{
if (0 ==
@@ -2657,6 +2694,36 @@ check_contract (struct PayContext *pc)
}
}
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (&pc->max_fee,
+ &pc->amount))
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (pc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "'max_fee' in database does not match currency of contract price");
+ }
+
+ for (unsigned int i=0;i<pc->coins_cnt;i++)
+ {
+ struct DepositConfirmation *dc = &pc->dc[i];
+
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (&dc->cdd.amount,
+ &pc->amount))
+ {
+ GNUNET_break_op (0);
+ return (MHD_YES ==
+ TALER_MHD_reply_with_error (pc->connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ pc->amount.currency))
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ }
+ }
+
if (GNUNET_TIME_timestamp_cmp (pc->wire_transfer_deadline,
<,
pc->refund_deadline))
diff --git a/src/backend/taler-merchant-httpd_post-using-templates.c b/src/backend/taler-merchant-httpd_post-using-templates.c
index 9be6e46b..cdaf917e 100644
--- a/src/backend/taler-merchant-httpd_post-using-templates.c
+++ b/src/backend/taler-merchant-httpd_post-using-templates.c
@@ -160,7 +160,8 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
{
/* template */
- const char *tsummary;
+ const char *tsummary = NULL;
+ const char *tcurrency = NULL;
uint32_t min_age;
struct GNUNET_TIME_Relative pay_duration;
struct TALER_Amount tamount;
@@ -170,9 +171,10 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
GNUNET_JSON_spec_string ("summary",
&tsummary),
NULL),
- /* FIXME: #7951: may want to allow the template to only
- fix the currency but not the amount; current approach
- does not allow this! */
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("currency",
+ &tcurrency),
+ NULL),
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount_any ("amount",
&tamount),
@@ -219,6 +221,19 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
NULL);
}
+ if ( (! no_amount) &&
+ (NULL != tcurrency) &&
+ (0 != strcmp (tcurrency,
+ amount.currency)) )
+ {
+ GNUNET_JSON_parse_free (spec);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ tcurrency);
+ }
+
if (no_amount && no_tamount)
{
GNUNET_JSON_parse_free (spec);
diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
index 14e71762..98bf2ab8 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2017-2022 Taler Systems SA
+ (C) 2017-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
@@ -285,6 +285,19 @@ struct GetOrderRequestContext
*/
bool transfer_status_requested;
+ /**
+ * Set to true if our database (incorrectly) has refunds
+ * in a different currency than the currency of the
+ * original payment for the order.
+ */
+ bool refund_currency_mismatch;
+
+ /**
+ * Set to true if our database (incorrectly) has deposits
+ * in a different currency than the currency of the
+ * original payment for the order.
+ */
+ bool deposit_currency_mismatch;
};
@@ -484,6 +497,29 @@ deposit_get_cb (void *cls,
return;
}
/* Compute total amount *wired* */
+ if ( (GNUNET_OK !=
+ TALER_amount_cmp_currency (
+ &gorc->deposits_total,
+ &dr->details.ok.coin_contribution)) ||
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (
+ &gorc->deposit_fees_total,
+ &tq->deposit_fee)) )
+ {
+ /* something very wrong in our database ... */
+ GNUNET_break (0);
+ gorc_report (gorc,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ &tq->coin_pub,
+ NULL);
+ GNUNET_free (tq->exchange_url);
+ GNUNET_free (tq);
+ if (NULL == gorc->tq_head)
+ gorc_resume (gorc,
+ 0,
+ TALER_EC_NONE);
+ return;
+ }
if (0 >
TALER_amount_add (&gorc->deposits_total,
&gorc->deposits_total,
@@ -775,12 +811,29 @@ process_refunds_cb (void *cls,
GNUNET_memcmp (&tq->coin_pub,
coin_pub))
{
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (
+ &gorc->deposit_fees_total,
+ &tq->deposit_fee))
+ {
+ gorc->refund_currency_mismatch = true;
+ return;
+ }
+
GNUNET_assert (0 <=
TALER_amount_subtract (&gorc->deposit_fees_total,
&gorc->deposit_fees_total,
&tq->deposit_fee));
}
}
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (
+ &gorc->refund_amount,
+ refund_amount))
+ {
+ gorc->refund_currency_mismatch = true;
+ return;
+ }
GNUNET_assert (0 <=
TALER_amount_add (&gorc->refund_amount,
&gorc->refund_amount,
@@ -817,6 +870,18 @@ process_transfer_details (
json_t *wire_details = gorc->wire_details;
struct TALER_Amount wired;
+ if ( (GNUNET_OK !=
+ TALER_amount_cmp_currency (&gorc->deposits_total,
+ deposit_value)) ||
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&gorc->deposit_fees_total,
+ deposit_fee)) )
+ {
+ GNUNET_break (0);
+ gorc->deposit_currency_mismatch = true;
+ return;
+ }
+
/* Compute total amount *wired* */
GNUNET_assert (0 <
TALER_amount_add (&gorc->deposits_total,
@@ -1233,12 +1298,11 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
{
/* suspend connection, wait for exchange to check wire transfer status there */
gorc->transfer_status_requested = false; /* only try ONCE */
- /* FIXME: #7951 */
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
+ TALER_amount_set_zero (gorc->contract_amount.currency,
&gorc->deposits_total));
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
+ TALER_amount_set_zero (gorc->contract_amount.currency,
&gorc->deposit_fees_total));
TMH_db->lookup_deposits_by_order (TMH_db->cls,
gorc->order_serial,
@@ -1316,9 +1380,8 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
GNUNET_assert (paid);
/* Accumulate refunds, if any. */
{
- /* FIXME: #7951 */
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
+ TALER_amount_set_zero (gorc->contract_amount.currency,
&gorc->refund_amount));
qs = TMH_db->lookup_refunds_detailed (TMH_db->cls,
hc->instance->settings.id,
@@ -1334,18 +1397,25 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"detailed refunds");
}
+ if (gorc->refund_currency_mismatch)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "refunds in different currency than original order price");
+ }
/* Generate final reply, including wire details if we have them */
{
MHD_RESULT ret;
char *order_status_url;
- /* FIXME: #7951 */
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
+ TALER_amount_set_zero (gorc->contract_amount.currency,
&gorc->deposits_total));
GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TMH_currency,
+ TALER_amount_set_zero (gorc->contract_amount.currency,
&gorc->deposit_fees_total));
qs = TMH_db->lookup_transfer_details_by_order (TMH_db->cls,
gorc->order_serial,
@@ -1359,6 +1429,14 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"transfer details");
}
+ if (gorc->deposit_currency_mismatch)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "deposits in different currency than original order price");
+ }
if (! wired)
{
diff --git a/src/backend/taler-merchant-httpd_private-get-orders.c b/src/backend/taler-merchant-httpd_private-get-orders.c
index 3b8f8c34..0e0511cc 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders.c
@@ -251,6 +251,16 @@ process_refunds_cb (void *cls,
{
struct TALER_Amount *total_refund_amount = cls;
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (total_refund_amount,
+ refund_amount))
+ {
+ /* Database error, refunds in mixed currency in DB. Not OK! */
+ /* FIXME: we may want to return DB error to the client instead of just
+ ignoring the refund. */
+ GNUNET_break (0);
+ return;
+ }
GNUNET_assert (0 <=
TALER_amount_add (total_refund_amount,
total_refund_amount,
@@ -387,7 +397,6 @@ add_order (void *cls,
{
struct TALER_Amount refund_amount;
- /* FIXME: #7951 */
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (order_amount.currency,
&refund_amount));
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 09c709e9..7d9bc4f0 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -1238,6 +1238,7 @@ patch_order (struct OrderContext *oc)
* mostly because in GNUnet relative times can't
* be negative. */
struct GNUNET_TIME_Relative auto_refund;
+ bool no_fee;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("merchant_base_url",
@@ -1276,7 +1277,7 @@ patch_order (struct OrderContext *oc)
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount_any ("max_fee",
&oc->max_fee),
- NULL),
+ &no_fee),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_timestamp ("delivery_date",
&delivery_date),
@@ -1310,7 +1311,20 @@ patch_order (struct OrderContext *oc)
reply_with_error (oc,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_CURRENCY_MISMATCH,
- NULL);
+ "no trusted exchange for this currency");
+ return;
+ }
+ if ( (! no_fee) &&
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&oc->brutto,
+ &oc->max_fee)) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_CURRENCY_MISMATCH,
+ "different currencies used for 'max_fee' and 'amount' currency");
return;
}
diff --git a/src/backend/taler-merchant-httpd_private-post-templates.c b/src/backend/taler-merchant-httpd_private-post-templates.c
index 4a5d8133..a064769c 100644
--- a/src/backend/taler-merchant-httpd_private-post-templates.c
+++ b/src/backend/taler-merchant-httpd_private-post-templates.c
@@ -189,7 +189,7 @@ TMH_private_post_templates (const struct TMH_RequestHandler *rh,
/* idempotency check: is etp == tp? */
{
bool eq;
-
+
eq = templates_equal (&tp,
&etp);
TALER_MERCHANTDB_template_details_free (&etp);
diff --git a/src/backenddb/pg_increase_refund.c b/src/backenddb/pg_increase_refund.c
index 832a84eb..eef7adc6 100644
--- a/src/backenddb/pg_increase_refund.c
+++ b/src/backenddb/pg_increase_refund.c
@@ -91,7 +91,14 @@ process_refund_cb (void *cls,
ictx->err = true;
return;
}
- /* FIXME: #7951 */
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (&ictx->refunded_amount,
+ &acc))
+ {
+ GNUNET_break (0);
+ ictx->err = true;
+ return;
+ }
if (0 >
TALER_amount_add (&ictx->refunded_amount,
&ictx->refunded_amount,