gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: -basic logic for withdraw KYC ch


From: gnunet
Subject: [taler-exchange] branch master updated: -basic logic for withdraw KYC checks
Date: Thu, 14 Oct 2021 21:06:50 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new ca12adce -basic logic for withdraw KYC checks
ca12adce is described below

commit ca12adced4ab5a54d7ee25b40b49cd034b920cc8
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Oct 14 21:06:47 2021 +0200

    -basic logic for withdraw KYC checks
---
 src/auditor/taler-helper-auditor-reserves.c  |   5 +-
 src/exchange/taler-exchange-httpd_withdraw.c | 113 +++++++++++++++++++++++--
 src/exchangedb/plugin_exchangedb_postgres.c  | 122 +++++++++++++++++++++++++++
 src/include/taler_exchangedb_plugin.h        |  33 ++++++++
 4 files changed, 265 insertions(+), 8 deletions(-)

diff --git a/src/auditor/taler-helper-auditor-reserves.c 
b/src/auditor/taler-helper-auditor-reserves.c
index aa9c241b..c27574d1 100644
--- a/src/auditor/taler-helper-auditor-reserves.c
+++ b/src/auditor/taler-helper-auditor-reserves.c
@@ -1083,10 +1083,13 @@ verify_reserve_balance (void *cls,
        internal audit, as otherwise the balance of the 'reserves' table
        is not replicated at the auditor. */
     struct TALER_EXCHANGEDB_Reserve reserve;
+    struct TALER_EXCHANGEDB_KycStatus kyc;
 
     reserve.pub = rs->reserve_pub;
     qs = TALER_ARL_edb->reserves_get (TALER_ARL_edb->cls,
-                                      &reserve);
+                                      &reserve,
+                                      &kyc);
+    // FIXME: figure out what to do with KYC status!
     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     {
       /* If the exchange doesn't have this reserve in the summary, it
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c 
b/src/exchange/taler-exchange-httpd_withdraw.c
index ca5618af..4839ec97 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -129,9 +129,44 @@ struct WithdrawContext
    */
   struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
 
+  /**
+   * KYC status for the operation.
+   */
+  struct TALER_EXCHANGEDB_KycStatus kyc;
+
+  /**
+   * Set to true if the operation was denied due to
+   * failing @e kyc checks.
+   */
+  bool kyc_denied;
+
 };
 
 
+/**
+ * Function called with another amount that was
+ * already withdrawn. Accumulates all amounts in
+ * @a cls.
+ *
+ * @param[in,out] cls a `struct TALER_Amount`
+ * @param val value to add to @a cls
+ */
+static void
+accumulate_withdraws (void *cls,
+                      const struct TALER_Amount *val)
+{
+  struct TALER_Amount *acc = cls;
+
+  if (GNUNET_OK !=
+      TALER_amount_is_valid (acc))
+    return; /* ignore */
+  GNUNET_break (0 <=
+                TALER_amount_add (acc,
+                                  acc,
+                                  val));
+}
+
+
 /**
  * Function implementing withdraw transaction.  Runs the
  * transaction logic; IF it returns a non-error code, the transaction
@@ -165,7 +200,6 @@ withdraw_transaction (void *cls,
   struct TALER_EXCHANGEDB_Reserve r;
   enum GNUNET_DB_QueryStatus qs;
   struct TALER_DenominationSignature denom_sig;
-  struct TALER_EXCHANGEDB_KycStatus kyc;
 
 #if OPTIMISTIC_SIGN
   /* store away optimistic signature to protect
@@ -211,7 +245,7 @@ withdraw_transaction (void *cls,
               TALER_B2S (&r.pub));
   qs = TEH_plugin->reserves_get (TEH_plugin->cls,
                                  &r,
-                                 &kyc);
+                                 &wc->kyc);
   if (0 > qs)
   {
     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -270,11 +304,60 @@ withdraw_transaction (void *cls,
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
 
-  if ( (! kyc.ok) &&
-       (TEH_KYC_NONE != TEH_kyc_config.mode) )
+  if ( (! wc->kyc.ok) &&
+       (TEH_KYC_NONE != TEH_kyc_config.mode) &&
+       (TALER_EXCHANGEDB_KYC_W2W == wc->kyc.type) )
+  {
+    /* Wallet-to-wallet payments _always_ require KYC */
+    wc->kyc_denied = true;
+    return qs;
+  }
+  if ( (! wc->kyc.ok) &&
+       (TEH_KYC_NONE != TEH_kyc_config.mode) &&
+       (TALER_EXCHANGEDB_KYC_WITHDRAW == wc->kyc.type) &&
+       (! GNUNET_TIME_relative_is_zero (TEH_kyc_config.withdraw_period)) )
   {
-    // FIXME: check if we are above the limit
-    // for KYC, and if so, deny the transaction!
+    /* Withdraws require KYC if above threshold */
+    struct TALER_Amount acc;
+    enum GNUNET_DB_QueryStatus qs2;
+
+    TALER_amount_set_zero (TEH_currency,
+                           &acc);
+    accumulate_withdraws (&acc,
+                          &wc->amount_required);
+    qs2 = TEH_plugin->select_withdraw_amounts_by_account (
+      TEH_plugin->cls,
+      &wc->wsrd.reserve_pub,
+      TEH_kyc_config.withdraw_period,
+      &accumulate_withdraws,
+      &acc);
+    if (0 > qs2)
+    {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs2);
+      if (GNUNET_DB_STATUS_HARD_ERROR == qs2)
+        *mhd_ret = TALER_MHD_reply_with_error (connection,
+                                               MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                               
TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                               "withdraw details");
+      return qs2;
+    }
+
+    if (GNUNET_OK !=
+        TALER_amount_is_valid (&acc))
+    {
+      GNUNET_break (0);
+      *mhd_ret = TALER_MHD_reply_with_ec (connection,
+                                          
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+                                          NULL);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+    if (1 == /* 1: acc > withdraw_limit */
+        TALER_amount_cmp (&acc,
+                          &TEH_kyc_config.withdraw_limit))
+    {
+      wc->kyc_denied = true;
+      return qs;
+    }
   }
 
   /* Balance is good, sign the coin! */
@@ -338,6 +421,9 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
   enum TALER_ErrorCode ec;
   struct TEH_DenominationKey *dk;
 
+  memset (&wc,
+          0,
+          sizeof (wc));
   if (GNUNET_OK !=
       GNUNET_STRINGS_string_to_data (args[0],
                                      strlen (args[0]),
@@ -480,6 +566,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
 #endif
 
   /* run transaction and sign (if not optimistically signed before) */
+  wc.kyc_denied = false;
   {
     MHD_RESULT mhd_ret;
 
@@ -499,9 +586,21 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
     }
   }
 
-  /* Clean up and send back final (positive) response */
+  /* Clean up and send back final response */
   GNUNET_JSON_parse_free (spec);
 
+  if (wc.kyc_denied)
+  {
+    if (NULL != wc.collectable.sig.rsa_signature)
+      GNUNET_CRYPTO_rsa_signature_free (wc.collectable.sig.rsa_signature);
+
+    return TALER_MHD_REPLY_JSON_PACK (
+      rc->connection,
+      MHD_HTTP_ACCEPTED,
+      GNUNET_JSON_pack_uint64 ("payment_target_uuid",
+                               wc.kyc.payment_target_uuid));
+  }
+
   {
     MHD_RESULT ret;
 
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index 34b785e7..eda6468b 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -4388,6 +4388,126 @@ postgres_get_reserve_history (void *cls,
 }
 
 
+/**
+ * Closure for withdraw_amount_by_account_cb()
+ */
+struct WithdrawAmountByAccountContext
+{
+  /**
+   * Function to call on each amount.
+   */
+  TALER_EXCHANGEDB_WithdrawHistoryCallback cb;
+
+  /**
+   * Closure for @e cb
+   */
+  void *cb_cls;
+
+  /**
+   * Our plugin's context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Set to true on failures.
+   */
+  bool failed;
+};
+
+
+/**
+ * Helper function for #postgres_select_withdraw_amounts_by_account().
+ * To be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct WithdrawAmountByAccountContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+withdraw_amount_by_account_cb (void *cls,
+                               PGresult *result,
+                               unsigned int num_results)
+{
+  struct WithdrawAmountByAccountContext *wac = cls;
+  struct PostgresClosure *pg = wac->pg;
+
+  for (unsigned int i = 0; num_results; i++)
+  {
+    struct TALER_Amount val;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("val",
+                                   &val),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      wac->failed = true;
+      return;
+    }
+    wac->cb (wac->cb_cls,
+             &val);
+  }
+}
+
+
+/**
+ * Find out all of the amounts that have been withdrawn
+ * so far from the same bank account that created the
+ * given reserve.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param reserve_pub reserve to select withdrawals by
+ * @param duration how far back should we select withdrawals
+ * @param cb function to call on each amount withdrawn
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_select_withdraw_amounts_by_account (
+  void *cls,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  struct GNUNET_TIME_Relative duration,
+  TALER_EXCHANGEDB_WithdrawHistoryCallback cb,
+  void *cb_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct WithdrawAmountByAccountContext wac = {
+    .pg = pg,
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
+  struct GNUNET_TIME_Absolute start
+    = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (),
+                                     duration);
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+    GNUNET_PQ_query_param_absolute_time (&start),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "select_XXX",
+    params,
+    &withdraw_amount_by_account_cb,
+    &wac);
+
+  if (wac.failed)
+  {
+    GNUNET_break (0);
+    qs = GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  return qs;
+}
+
+
 /**
  * Check if we have the specified deposit already in the database.
  *
@@ -10957,6 +11077,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
   plugin->get_withdraw_info = &postgres_get_withdraw_info;
   plugin->insert_withdraw_info = &postgres_insert_withdraw_info;
   plugin->get_reserve_history = &postgres_get_reserve_history;
+  plugin->select_withdraw_amounts_by_account
+    = &postgres_select_withdraw_amounts_by_account;
   plugin->free_reserve_history = &common_free_reserve_history;
   plugin->count_known_coins = &postgres_count_known_coins;
   plugin->ensure_coin_known = &postgres_ensure_coin_known;
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index d94a985d..34196aad 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -2011,6 +2011,18 @@ typedef enum GNUNET_GenericReturnValue
   const struct TALER_WireTransferIdentifierRawP *wtid);
 
 
+/**
+ * Function called with the amounts historically
+ * withdrawn from the same origin account.
+ *
+ * @param cls closure
+ * @param val one of the withdrawn amounts
+ */
+typedef void
+(*TALER_EXCHANGEDB_WithdrawHistoryCallback)(
+  void *cls,
+  const struct TALER_Amount *val);
+
 /**
  * Function called with details about expired reserves.
  *
@@ -2450,6 +2462,27 @@ struct TALER_EXCHANGEDB_Plugin
                          struct TALER_EXCHANGEDB_ReserveHistory **rhp);
 
 
+  /**
+   * Find out all of the amounts that have been withdrawn
+   * so far from the same bank account that created the
+   * given reserve.
+   *
+   * @param cls closure
+   * @param reserve_pub reserve to select withdrawals by
+   * @param duration how far back should we select withdrawals
+   * @param cb function to call on each amount withdrawn
+   * @param cb_cls closure for @a cb
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*select_withdraw_amounts_by_account)(
+    void *cls,
+    const struct TALER_ReservePublicKeyP *reserve_pub,
+    struct GNUNET_TIME_Relative duration,
+    TALER_EXCHANGEDB_WithdrawHistoryCallback cb,
+    void *cb_cls);
+
+
   /**
    * Free memory associated with the given reserve history.
    *

-- 
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]