gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] branch master updated: implement per-transaction limits


From: gnunet
Subject: [taler-merchant] branch master updated: implement per-transaction limits
Date: Sun, 01 Sep 2024 12:21:02 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new 20a950c1 implement per-transaction limits
20a950c1 is described below

commit 20a950c1c385c08f6bd6ee63460a750892a42b12
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sun Sep 1 12:20:53 2024 +0200

    implement per-transaction limits
---
 src/backend/taler-merchant-httpd_exchanges.c       | 29 ++++++++
 src/backend/taler-merchant-httpd_exchanges.h       | 17 +++++
 .../taler-merchant-httpd_post-orders-ID-pay.c      | 64 +++++++++++++----
 ...aler-merchant-httpd_private-patch-products-ID.c |  8 +--
 ...-merchant-httpd_private-post-orders-ID-refund.c | 80 +++++++++++++---------
 src/backend/taler-merchant-webhook.c               | 22 +++---
 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
@@ -152,6 +152,23 @@ TMH_EXCHANGES_get_currency (
   const struct TMH_Exchange *exchange);
 
 
+/**
+ * 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.
  *
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
@@ -331,6 +331,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,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]