gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: implement #7052


From: gnunet
Subject: [taler-merchant] branch master updated: implement #7052
Date: Sat, 20 Nov 2021 21:22:04 +0100

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 8edd5641 implement #7052
8edd5641 is described below

commit 8edd5641430d7e352cf9d14edd3e57b6f75642a3
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Nov 20 21:22:01 2021 +0100

    implement #7052
---
 src/backend/taler-merchant-httpd.c                 |  13 +-
 src/backend/taler-merchant-httpd.h                 |   9 +
 .../taler-merchant-httpd_post-orders-ID-pay.c      | 316 ++++++++++++++++++++-
 3 files changed, 328 insertions(+), 10 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 9f460df1..73d3327f 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -199,13 +199,8 @@ TMH_compute_auth (const char *token,
 }
 
 
-/**
- * Decrement reference counter of @a mi, and free if it hits zero.
- *
- * @param[in,out] mi merchant instance to update and possibly free
- */
-static void
-instance_decref (struct TMH_MerchantInstance *mi)
+void
+TMH_instance_decref (struct TMH_MerchantInstance *mi)
 {
   struct TMH_WireMethod *wm;
 
@@ -252,7 +247,7 @@ TMH_instance_free_cb (void *cls,
                  GNUNET_CONTAINER_multihashmap_remove (TMH_by_id_map,
                                                        &mi->h_instance,
                                                        mi));
-  instance_decref (mi);
+  TMH_instance_decref (mi);
   return GNUNET_YES;
 }
 
@@ -360,7 +355,7 @@ handle_mhd_completion_callback (void *cls,
   if (NULL != hc->request_body)
     json_decref (hc->request_body);
   if (NULL != hc->instance)
-    instance_decref (hc->instance);
+    TMH_instance_decref (hc->instance);
   GNUNET_free (hc);
   *con_cls = NULL;
 }
diff --git a/src/backend/taler-merchant-httpd.h 
b/src/backend/taler-merchant-httpd.h
index 7fbc8bb5..f81b15aa 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -639,6 +639,15 @@ enum GNUNET_GenericReturnValue
 TMH_add_instance (struct TMH_MerchantInstance *mi);
 
 
+/**
+ * Decrement reference counter of @a mi, and free if it hits zero.
+ *
+ * @param[in,out] mi merchant instance to update and possibly free
+ */
+void
+TMH_instance_decref (struct TMH_MerchantInstance *mi);
+
+
 /**
  * Lookup a merchant instance by its instance ID.
  *
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 fcdb9821..3baf7293 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -46,6 +46,13 @@
  */
 #define MAX_COIN_ALLOWED_COINS 1024
 
+/**
+ * How often do we ask the exchange again about our
+ * KYC status? Very rarely, as if the user actively
+ * changes it, we should usually notice anyway.
+ */
+#define KYC_RETRY_FREQUENCY GNUNET_TIME_UNIT_WEEKS
+
 /**
  * Information we keep for an individual call to the pay handler.
  */
@@ -359,6 +366,69 @@ struct PayContext
 };
 
 
+/**
+ * Active KYC operation with an exchange.
+ */
+struct KycContext
+{
+  /**
+   * Kept in a DLL.
+   */
+  struct KycContext *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct KycContext *prev;
+
+  /**
+   * Looking for the exchange.
+   */
+  struct TMH_EXCHANGES_FindOperation *fo;
+
+  /**
+   * Exchange this is about.
+   */
+  char *exchange_url;
+
+  /**
+   * Merchant instance this is for.
+   */
+  struct TMH_MerchantInstance *mi;
+
+  /**
+   * Wire method we are checking the status of.
+   */
+  struct TMH_WireMethod *wm;
+
+  /**
+   * Handle for the GET /deposits operation.
+   */
+  struct TALER_EXCHANGE_DepositGetHandle *dg;
+
+  /**
+   * Contract we are looking up.
+   */
+  struct TALER_PrivateContractHash h_contract_terms;
+
+  /**
+   * Coin we are looking up.
+   */
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+
+  /**
+   * Initial DB timestamp.
+   */
+  struct GNUNET_TIME_Absolute kyc_timestamp;
+
+  /**
+   * Initial KYC status.
+   */
+  bool kyc_ok;
+
+};
+
+
 /**
  * Head of active pay context DLL.
  */
@@ -369,6 +439,44 @@ static struct PayContext *pc_head;
  */
 static struct PayContext *pc_tail;
 
+/**
+ * Head of active KYC context DLL.
+ */
+static struct KycContext *kc_head;
+
+/**
+ * Tail of active KYC context DLL.
+ */
+static struct KycContext *kc_tail;
+
+
+/**
+ * Free resources used by @a kc.
+ *
+ * @param[in] kc object to free
+ */
+static void
+destroy_kc (struct KycContext *kc)
+{
+  if (NULL != kc->fo)
+  {
+    TMH_EXCHANGES_find_exchange_cancel (kc->fo);
+    kc->fo = NULL;
+  }
+  if (NULL != kc->dg)
+  {
+    TALER_EXCHANGE_deposits_get_cancel (kc->dg);
+    kc->dg = NULL;
+  }
+  TMH_instance_decref (kc->mi);
+  kc->mi = NULL;
+  GNUNET_free (kc->exchange_url);
+  GNUNET_CONTAINER_DLL_remove (kc_head,
+                               kc_tail,
+                               kc);
+  GNUNET_free (kc);
+}
+
 
 /**
  * Compute the timeout for a /pay request based on the number of coins
@@ -419,6 +527,15 @@ abort_active_deposits (struct PayContext *pc)
 void
 TMH_force_pc_resume ()
 {
+  struct KycContext *kc;
+
+  while (NULL != (kc = kc_head))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Aborting KYC check at %s\n",
+                kc->exchange_url);
+    destroy_kc (kc);
+  }
   for (struct PayContext *pc = pc_head;
        NULL != pc;
        pc = pc->next)
@@ -555,6 +672,200 @@ static void
 execute_pay_transaction (struct PayContext *pc);
 
 
+/**
+ * Function called with detailed wire transfer data.
+ *
+ * @param cls a `struct KycContext *`
+ * @param hr HTTP response data
+ * @param dd details about the deposit (NULL on errors)
+ */
+static void
+deposit_get_callback (
+  void *cls,
+  const struct TALER_EXCHANGE_GetDepositResponse *dr)
+{
+  struct KycContext *kc = cls;
+  enum GNUNET_DB_QueryStatus qs;
+
+  kc->dg = NULL;
+  switch (dr->hr.http_status)
+  {
+  case MHD_HTTP_OK:
+    qs = TMH_db->account_kyc_set_status (
+      TMH_db->cls,
+      kc->mi->settings.id,
+      &kc->wm->h_wire,
+      kc->exchange_url,
+      dr->details.success.payment_target_uuid,
+      NULL, /* no signature */
+      NULL, /* no signature */
+      GNUNET_TIME_absolute_get (),
+      true);
+    GNUNET_break (qs > 0);
+    break;
+  case MHD_HTTP_ACCEPTED:
+    qs = TMH_db->account_kyc_set_status (
+      TMH_db->cls,
+      kc->mi->settings.id,
+      &kc->wm->h_wire,
+      kc->exchange_url,
+      dr->details.accepted.payment_target_uuid,
+      NULL, /* no signature */
+      NULL, /* no signature */
+      GNUNET_TIME_absolute_get (),
+      dr->details.accepted.kyc_ok);
+    GNUNET_break (qs > 0);
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "KYC check failed at %s with unexpected status %u\n",
+                kc->exchange_url,
+                dr->hr.http_status);
+  }
+  destroy_kc (kc);
+}
+
+
+/**
+ * Function called with the result of our exchange lookup.
+ *
+ * @param cls the `struct KycContext`
+ * @param hr HTTP response details
+ * @param exchange_handle NULL if exchange was not found to be acceptable
+ * @param payto_uri payto://-URI of the exchange
+ * @param wire_fee current applicable fee for dealing with @a exchange_handle,
+ *        NULL if not available
+ * @param exchange_trusted true if this exchange is
+ *        trusted by config
+ */
+static void
+process_kyc_with_exchange (void *cls,
+                           const struct TALER_EXCHANGE_HttpResponse *hr,
+                           struct TALER_EXCHANGE_Handle *exchange_handle,
+                           const char *payto_uri,
+                           const struct TALER_Amount *wire_fee,
+                           bool exchange_trusted)
+{
+  struct KycContext *kc = cls;
+
+  kc->fo = NULL;
+  if (NULL == exchange_handle)
+  {
+    destroy_kc (kc);
+    return;
+  }
+  kc->dg = TALER_EXCHANGE_deposits_get (exchange_handle,
+                                        &kc->mi->merchant_priv,
+                                        &kc->wm->h_wire,
+                                        &kc->h_contract_terms,
+                                        &kc->coin_pub,
+                                        &deposit_get_callback,
+                                        kc);
+  if (NULL == kc->dg)
+  {
+    GNUNET_break (0);
+    destroy_kc (kc);
+  }
+}
+
+
+/**
+ * Function called from ``account_kyc_get_status``
+ * with KYC status information for this merchant.
+ *
+ * @param cls a `struct KycContext *`
+ * @param h_wire hash of the wire account
+ * @param exchange_kyc_serial serial number for the KYC process at the 
exchange, 0 if unknown
+ * @param payto_uri payto:// URI of the merchant's bank account
+ * @param exchange_url base URL of the exchange for which this is a status
+ * @param last_check when did we last get an update on our KYC status from the 
exchange
+ * @param kyc_ok true if we satisfied the KYC requirements
+ */
+static void
+kyc_cb (
+  void *cls,
+  const struct TALER_MerchantWireHash *h_wire,
+  uint64_t exchange_kyc_serial,
+  const char *payto_uri,
+  const char *exchange_url,
+  struct GNUNET_TIME_Absolute last_check,
+  bool kyc_ok)
+{
+  struct KycContext *kc = cls;
+
+  kc->kyc_timestamp = last_check;
+  kc->kyc_ok = kyc_ok;
+}
+
+
+/**
+ * Check for our KYC status at @a exchange_url for the
+ * payment of @a pc. First checks if we already have a
+ * positive result from the exchange, and if not checks
+ * with the exchange.
+ *
+ * @param pc payment context to use as starting point
+ * @param dc deposit confirmation we are triggering on
+ */
+static void
+check_kyc (struct PayContext *pc,
+           const struct DepositConfirmation *dc)
+{
+  enum GNUNET_DB_QueryStatus qs;
+  struct KycContext *kc;
+
+  kc = GNUNET_new (struct KycContext);
+  qs = TMH_db->account_kyc_get_status (TMH_db->cls,
+                                       pc->hc->instance->settings.id,
+                                       &pc->wm->h_wire,
+                                       dc->exchange_url,
+                                       &kyc_cb,
+                                       kc);
+  if (qs < 0)
+  {
+    GNUNET_break (0);
+    GNUNET_free (kc);
+    return;
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+  {
+    if (kc->kyc_ok)
+    {
+      GNUNET_free (kc);
+      return; /* we are done */
+    }
+    if (GNUNET_TIME_absolute_get_duration (kc->kyc_timestamp).rel_value_us <
+        KYC_RETRY_FREQUENCY.rel_value_us)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "Not re-checking KYC status at `%s', as we already recently 
asked\n",
+                  dc->exchange_url);
+      GNUNET_free (kc);
+      return;
+    }
+  }
+  kc->mi = pc->hc->instance;
+  kc->mi->rc++;
+  kc->wm = pc->wm;
+  kc->exchange_url = GNUNET_strdup (dc->exchange_url);
+  kc->h_contract_terms = pc->h_contract_terms;
+  kc->coin_pub = dc->coin_pub;
+  GNUNET_CONTAINER_DLL_insert (kc_head,
+                               kc_tail,
+                               kc);
+  kc->fo = TMH_EXCHANGES_find_exchange (dc->exchange_url,
+                                        NULL,
+                                        GNUNET_NO,
+                                        &process_kyc_with_exchange,
+                                        kc);
+  if (NULL == kc->fo)
+  {
+    GNUNET_break (0);
+    destroy_kc (kc);
+  }
+}
+
+
 /**
  * Callback to handle a deposit permission's response.
  *
@@ -629,6 +940,8 @@ deposit_cb (void *cls,
 
       if (0 != pc->pending_at_ce)
         return; /* still more to do with current exchange */
+      check_kyc (pc,
+                 dc);
       find_next_exchange (pc);
       return;
     }
@@ -1337,8 +1650,9 @@ trigger_payment_notification (struct PayContext *pc)
 
 
 /**
+ * Actually perform the payment transaction.
  *
- *
+ * @param pc payment transaction to run
  */
 static void
 execute_pay_transaction (struct PayContext *pc)

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