aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.c29
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.h17
-rw-r--r--src/backend/taler-merchant-httpd_post-orders-ID-pay.c64
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-products-ID.c8
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c80
-rw-r--r--src/backend/taler-merchant-webhook.c22
6 files changed, 157 insertions, 63 deletions
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c
index 918bc48f..6bcbd5c8 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -1651,6 +1651,35 @@ update_exchange_keys (void *cls,
}
+bool
+TMH_EXCHANGES_is_below_limit (
+ const struct TALER_EXCHANGE_Keys *keys,
+ enum TALER_KYCLOGIC_KycTriggerEvent operation_type,
+ const struct TALER_Amount *amount)
+{
+ if (NULL == keys)
+ {
+ /* should only be called after we have keys! */
+ GNUNET_break (0);
+ return false;
+ }
+ for (unsigned int i = 0; i<keys->hard_limits_length; i++)
+ {
+ const struct TALER_EXCHANGE_AccountLimit *al
+ = &keys->hard_limits[i];
+
+ if (operation_type != al->operation_type)
+ continue;
+ if (-1 ==
+ TALER_amount_cmp (&al->threshold,
+ amount))
+ /* -1: threshold < amount */
+ return false;
+ }
+ return true;
+}
+
+
enum GNUNET_GenericReturnValue
TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
diff --git a/src/backend/taler-merchant-httpd_exchanges.h b/src/backend/taler-merchant-httpd_exchanges.h
index 892843f6..f4de947a 100644
--- a/src/backend/taler-merchant-httpd_exchanges.h
+++ b/src/backend/taler-merchant-httpd_exchanges.h
@@ -153,6 +153,23 @@ TMH_EXCHANGES_get_currency (
/**
+ * Check if the given operation and amount would
+ * violate any hard limits of the exchange.
+ * Only useful for transaction and refund limits.
+ *
+ * @param keys the keys of the exchange to check limit for
+ * @param operation_type the kind of operation we perform
+ * @param amount the amount we want to transact
+ * @return true if this is allowed
+ */
+bool
+TMH_EXCHANGES_is_below_limit (
+ const struct TALER_EXCHANGE_Keys *keys,
+ enum TALER_KYCLOGIC_KycTriggerEvent operation_type,
+ const struct TALER_Amount *amount);
+
+
+/**
* Lookup current wire fee by @a exchange_url and @a wire_method.
*
* @param exchange the exchange to check
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 c9fbd34e..049db1f0 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -332,6 +332,11 @@ struct ExchangeGroup
const char *exchange_url;
/**
+ * Total deposit amount in this exchange group.
+ */
+ struct TALER_Amount total;
+
+ /**
* Wire fee that applies to this exchange for the
* given payment context's wire method.
*/
@@ -1115,6 +1120,18 @@ process_pay_with_keys (
NULL);
return;
}
+ if (! TMH_EXCHANGES_is_below_limit (keys,
+ TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION,
+ &eg->total))
+ {
+ GNUNET_break_op (0);
+ resume_pay_with_error (
+ pc,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION,
+ eg->exchange_url);
+ return;
+ }
+
if (GNUNET_OK !=
TMH_exchange_check_debit (exchange,
@@ -3146,7 +3163,6 @@ phase_parse_wallet_data (struct PayContext *pc)
NULL),
GNUNET_JSON_spec_end ()
};
- enum GNUNET_GenericReturnValue res;
pc->choice_index = -1;
if (NULL == pc->wallet_data)
@@ -3154,17 +3170,21 @@ phase_parse_wallet_data (struct PayContext *pc)
pc->phase = PP_CHECK_CONTRACT;
return;
}
- res = TALER_MHD_parse_json_data (pc->connection,
- pc->wallet_data,
- spec);
- if (GNUNET_YES != res)
{
- GNUNET_break_op (0);
- pay_end (pc,
- (GNUNET_NO == res)
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (pc->connection,
+ pc->wallet_data,
+ spec);
+ if (GNUNET_YES != res)
+ {
+ GNUNET_break_op (0);
+ pay_end (pc,
+ (GNUNET_NO == res)
? MHD_YES
: MHD_NO);
- return;
+ return;
+ }
}
pc->token_envelopes_cnt = json_array_size (tokens_evs);
@@ -3362,7 +3382,7 @@ phase_parse_pay (struct PayContext *pc)
GNUNET_JSON_spec_end ()
};
enum GNUNET_GenericReturnValue res;
- bool have_eg = false;
+ struct ExchangeGroup *eg = NULL;
res = TALER_MHD_parse_json_data (pc->connection,
coin,
@@ -3418,21 +3438,37 @@ phase_parse_pay (struct PayContext *pc)
strcmp (pc->egs[i]->exchange_url,
exchange_url))
{
- have_eg = true;
+ eg = pc->egs[i];
break;
}
}
- if (! have_eg)
+ if (NULL == eg)
{
- struct ExchangeGroup *eg;
-
eg = GNUNET_new (struct ExchangeGroup);
eg->pc = pc;
eg->exchange_url = dc->exchange_url;
+ eg->total = dc->cdd.amount;
GNUNET_array_append (pc->egs,
pc->num_exchanges,
eg);
}
+ else
+ {
+ if (0 >
+ TALER_amount_add (&eg->total,
+ &eg->total,
+ &dc->cdd.amount))
+ {
+ GNUNET_break_op (0);
+ pay_end (pc,
+ TALER_MHD_reply_with_error (
+ pc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
+ "Overflow adding up amounts"));
+ return;
+ }
+ }
}
}
diff --git a/src/backend/taler-merchant-httpd_private-patch-products-ID.c b/src/backend/taler-merchant-httpd_private-patch-products-ID.c
index 6e50cced..81633051 100644
--- a/src/backend/taler-merchant-httpd_private-patch-products-ID.c
+++ b/src/backend/taler-merchant-httpd_private-patch-products-ID.c
@@ -261,16 +261,16 @@ TMH_private_patch_products_ID (
}
if (-1 != no_cat)
{
- char cats[24];
+ char cat_str[24];
- GNUNET_snprintf (cats,
- sizeof (cats),
+ GNUNET_snprintf (cat_str,
+ sizeof (cat_str),
"%llu",
(unsigned long long) no_cat);
ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_MERCHANT_GENERIC_CATEGORY_UNKNOWN,
- cats);
+ cat_str);
goto cleanup;
}
if (no_product)
diff --git a/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c b/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c
index 67e1410b..1a7ffe37 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c
@@ -35,6 +35,9 @@
*/
#define MAX_RETRIES 5
+/* FIXME-9061: check exchange refund limits and return 403/
+ MERCHANT_POST_ORDERS_ID_REFUND_EXCHANGE_TRANSACTION_LIMIT_VIOLATION
+ if they are violated! */
/**
* Use database to notify other clients about the
@@ -44,8 +47,9 @@
* @param amount the (total) refunded amount
*/
static void
-trigger_refund_notification (struct TMH_HandlerContext *hc,
- const struct TALER_Amount *amount)
+trigger_refund_notification (
+ struct TMH_HandlerContext *hc,
+ const struct TALER_Amount *amount)
{
const char *as;
struct TMH_OrderRefundEventP refund_eh = {
@@ -114,9 +118,10 @@ make_taler_refund_uri (struct MHD_Connection *connection,
* @return MHD result code
*/
MHD_RESULT
-TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc)
+TMH_private_post_orders_ID_refund (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
{
struct TALER_Amount refund;
const char *reason;
@@ -162,15 +167,17 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
if (qs < 0)
{
GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "lookup_contract_terms");
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "lookup_contract_terms");
}
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
- hc->infix);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
+ hc->infix);
}
if (GNUNET_OK !=
TALER_JSON_contract_hash (contract_terms,
@@ -178,10 +185,11 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
{
GNUNET_break (0);
json_decref (contract_terms);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
- "Could not hash contract terms");
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
+ "Could not hash contract terms");
}
{
struct GNUNET_JSON_Specification cspec[] = {
@@ -311,24 +319,28 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Refund amount %s is not in the currency of the original payment\n",
TALER_amount2s (&refund));
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- "Order was paid in a different currency");
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ "Order was paid in a different currency")
+ ;
case TALER_MERCHANTDB_RS_TOO_HIGH:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Refusing refund amount %s that is larger than original payment\n",
TALER_amount2s (&refund));
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_EXCHANGE_REFUND_INCONSISTENT_AMOUNT,
- "Amount above payment");
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_EXCHANGE_REFUND_INCONSISTENT_AMOUNT,
+ "Amount above payment");
case TALER_MERCHANTDB_RS_SOFT_ERROR:
case TALER_MERCHANTDB_RS_HARD_ERROR:
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_COMMIT_FAILED,
- NULL);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_COMMIT_FAILED,
+ NULL);
case TALER_MERCHANTDB_RS_NO_SUCH_ORDER:
/* We know the order exists from the
"lookup_contract_terms" at the beginning;
@@ -345,7 +357,6 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
} /* end switch */
{
- struct GNUNET_TIME_Timestamp timestamp;
uint64_t order_serial;
enum GNUNET_DB_QueryStatus qs;
@@ -357,10 +368,11 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
if (0 >= qs)
{
GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
- NULL);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
+ NULL);
}
TMH_notify_order_change (hc->instance,
TMH_OSF_CLAIMED
diff --git a/src/backend/taler-merchant-webhook.c b/src/backend/taler-merchant-webhook.c
index 1d17843e..f081aab5 100644
--- a/src/backend/taler-merchant-webhook.c
+++ b/src/backend/taler-merchant-webhook.c
@@ -42,7 +42,7 @@ static struct WorkResponse *w_head;
static struct WorkResponse *w_tail;
-static struct GNUNET_DB_EventHandler *eh;
+static struct GNUNET_DB_EventHandler *event_handler;
/**
* The merchant's configuration.
@@ -93,10 +93,10 @@ shutdown_task (void *cls)
(void) cls;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Running shutdown\n");
- if (NULL != eh)
+ if (NULL != event_handler)
{
- db_plugin->event_listen_cancel (eh);
- eh = NULL;
+ db_plugin->event_listen_cancel (event_handler);
+ event_handler = NULL;
}
if (NULL != task)
{
@@ -279,11 +279,11 @@ pending_webhooks_cb (void *cls,
{
struct WorkResponse *w = GNUNET_new (struct WorkResponse);
CURL *eh;
+ struct curl_slist *job_headers = NULL;
+
(void) retries;
(void) next_attempt;
(void) cls;
- struct curl_slist *job_headers = NULL;
-
GNUNET_CONTAINER_DLL_insert (w_head,
w_tail,
w);
@@ -533,11 +533,11 @@ run (void *cls,
.type = htons (TALER_DBEVENT_MERCHANT_WEBHOOK_PENDING)
};
- eh = db_plugin->event_listen (db_plugin->cls,
- &es,
- GNUNET_TIME_UNIT_FOREVER_REL,
- &db_notify,
- NULL);
+ event_handler = db_plugin->event_listen (db_plugin->cls,
+ &es,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &db_notify,
+ NULL);
}
GNUNET_assert (NULL == task);
task = GNUNET_SCHEDULER_add_now (&select_work,