gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] 02/02: -implement new kyc-webhook endpoint


From: gnunet
Subject: [taler-exchange] 02/02: -implement new kyc-webhook endpoint
Date: Sun, 07 Aug 2022 15:35:20 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

commit 3f99e4f3f8a89dfafcf37fcbf9046134adca436a
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sun Aug 7 15:35:06 2022 +0200

    -implement new kyc-webhook endpoint
---
 contrib/gana                                    |   2 +-
 src/exchange/Makefile.am                        |   1 +
 src/exchange/taler-exchange-httpd_kyc-webhook.c | 347 ++++++++++++++++++++++++
 src/exchange/taler-exchange-httpd_kyc-webhook.h |  64 +++++
 src/exchangedb/plugin_exchangedb_postgres.c     |   2 +-
 src/include/taler_exchangedb_plugin.h           |   2 +-
 src/include/taler_kyclogic_plugin.h             |  21 +-
 src/kyclogic/plugin_kyclogic_oauth2.c           |  12 +-
 8 files changed, 430 insertions(+), 21 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index 47522119..02da8656 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit 4752211918879f9ceec07bec5f64c8209d840b51
+Subproject commit 02da8656d6d915df023de0b90d18ade9e80603fa
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 23295c13..7141758b 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -136,6 +136,7 @@ taler_exchange_httpd_SOURCES = \
   taler-exchange-httpd_kyc-check.c taler-exchange-httpd_kyc-check.h \
   taler-exchange-httpd_kyc-proof.c taler-exchange-httpd_kyc-proof.h \
   taler-exchange-httpd_kyc-wallet.c taler-exchange-httpd_kyc-wallet.h \
+  taler-exchange-httpd_kyc-webhook.c taler-exchange-httpd_kyc-webhook.h \
   taler-exchange-httpd_link.c taler-exchange-httpd_link.h \
   taler-exchange-httpd_management.h \
   taler-exchange-httpd_management_auditors.c \
diff --git a/src/exchange/taler-exchange-httpd_kyc-webhook.c 
b/src/exchange/taler-exchange-httpd_kyc-webhook.c
new file mode 100644
index 00000000..a5c11cec
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-webhook.c
@@ -0,0 +1,347 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-webhook.c
+ * @brief Handle notification of KYC completion via webhook.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_kyc.h"
+#include "taler-exchange-httpd_kyc-webhook.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Context for the webhook.
+ */
+struct KycWebhookContext
+{
+
+  /**
+   * Kept in a DLL while suspended.
+   */
+  struct KycWebhookContext *next;
+
+  /**
+   * Kept in a DLL while suspended.
+   */
+  struct KycWebhookContext *prev;
+
+  /**
+   * Details about the connection we are processing.
+   */
+  struct TEH_RequestContext *rc;
+
+  /**
+   * Plugin responsible for the webhook.
+   */
+  struct TALER_KYCLOGIC_Plugin *plugin;
+
+  /**
+   * Configuration for the specific action.
+   */
+  struct TALER_KYCLOGIC_ProviderDetails *pd;
+
+  /**
+   * Webhook activity.
+   */
+  struct TALER_KYCLOGIC_WebhookHandle *wh;
+
+  /**
+   * HTTP response to return.
+   */
+  struct MHD_Response *response;
+
+  /**
+   * Logic the request is for. Name of the configuration
+   * section defining the KYC logic.
+   */
+  char *logic;
+
+  /**
+   * HTTP response code to return.
+   */
+  unsigned int response_code;
+
+  /**
+   * #GNUNET_YES if we are suspended,
+   * #GNUNET_NO if not.
+   * #GNUNET_SYSERR if we had some error.
+   */
+  enum GNUNET_GenericReturnValue suspended;
+
+};
+
+
+/**
+ * Contexts are kept in a DLL while suspended.
+ */
+static struct KycWebhookContext *kwh_head;
+
+/**
+ * Contexts are kept in a DLL while suspended.
+ */
+static struct KycWebhookContext *kwh_tail;
+
+
+/**
+ * Resume processing the @a kwh request.
+ *
+ * @param kwh request to resume
+ */
+static void
+kwh_resume (struct KycWebhookContext *kwh)
+{
+  GNUNET_assert (GNUNET_YES == kwh->suspended);
+  kwh->suspended = GNUNET_NO;
+  GNUNET_CONTAINER_DLL_remove (kwh_head,
+                               kwh_tail,
+                               kwh);
+  MHD_resume_connection (kwh->rc->connection);
+  TALER_MHD_daemon_trigger ();
+}
+
+
+void
+TEH_kyc_webhook_cleanup (void)
+{
+  struct KycWebhookContext *kwh;
+
+  while (NULL != (kwh = kwh_head))
+  {
+    if (NULL != kwh->wh)
+    {
+      kwh->plugin->webhook_cancel (kwh->wh);
+      kwh->wh = NULL;
+    }
+    kwh_resume (kwh);
+  }
+}
+
+
+/**
+ * Function called with the result of a webhook
+ * operation.
+ *
+ * Note that the "decref" for the @a response
+ * will be done by the plugin.
+ *
+ * @param cls closure
+ * @param legi_row legitimization request the webhook was about
+ * @param account_id account the webhook was about
+ * @param provider_user_id set to user ID at the provider, or NULL if not 
supported or unknown
+ * @param provider_legitimization_id set to legitimization process ID at the 
provider, or NULL if not supported or unknown
+ * @param status KYC status
+ * @param expiration until when is the KYC check valid
+ * @param http_status HTTP status code of @a response
+ * @param[in] response to return to the HTTP client
+ */
+static void
+webhook_finished_cb (
+  void *cls,
+  uint64_t legi_row,
+  const struct TALER_PaytoHashP *account_id,
+  const char *provider_user_id,
+  const char *provider_legitimization_id,
+  enum TALER_KYCLOGIC_KycStatus status,
+  struct GNUNET_TIME_Absolute expiration,
+  unsigned int http_status,
+  struct MHD_Response *response)
+{
+  struct KycWebhookContext *kwh = cls;
+
+  kwh->wh = NULL;
+  switch (status)
+  {
+  case TALER_KYCLOGIC_STATUS_SUCCESS:
+    /* _successfully_ resumed case */
+    {
+      enum GNUNET_DB_QueryStatus qs;
+
+      qs = TEH_plugin->update_kyc_requirement_by_row (TEH_plugin->cls,
+                                                      legi_row,
+                                                      kwh->logic,
+                                                      account_id,
+                                                      provider_user_id,
+                                                      
provider_legitimization_id,
+                                                      expiration);
+      if (qs < 0)
+      {
+        GNUNET_break (0);
+        kwh->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
+                                              "set_kyc_ok");
+        kwh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+        kwh_resume (kwh);
+        return;
+      }
+    }
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "KYC status of %s/%s (Row #%llu) is %d\n",
+                provider_user_id,
+                provider_legitimization_id,
+                (unsigned long long) legi_row,
+                status);
+    break;
+  }
+  kwh->response = response;
+  kwh->response_code = http_status;
+  kwh_resume (kwh);
+}
+
+
+/**
+ * Function called to clean up a context.
+ *
+ * @param rc request context
+ */
+static void
+clean_kwh (struct TEH_RequestContext *rc)
+{
+  struct KycWebhookContext *kwh = rc->rh_ctx;
+
+  if (NULL != kwh->wh)
+  {
+    kwh->plugin->webhook_cancel (kwh->wh);
+    kwh->wh = NULL;
+  }
+  if (NULL != kwh->response)
+  {
+    MHD_destroy_response (kwh->response);
+    kwh->response = NULL;
+  }
+  GNUNET_free (kwh->logic);
+  GNUNET_free (kwh);
+}
+
+
+/**
+ * Handle a (GET or POST) "/kyc-webhook" request.
+ *
+ * @param rc request to handle
+ * @param method HTTP request method used by the client
+ * @param root uploaded JSON body (can be NULL)
+ * @param args one argument with the payment_target_uuid
+ * @return MHD result code
+ */
+static MHD_RESULT
+handler_kyc_webhook_generic (
+  struct TEH_RequestContext *rc,
+  const char *method,
+  const json_t *root,
+  const char *const args[])
+{
+  struct KycWebhookContext *kwh = rc->rh_ctx;
+
+  if (NULL == kwh)
+  { /* first time */
+    kwh = GNUNET_new (struct KycWebhookContext);
+    kwh->logic = GNUNET_strdup (args[0]);
+    kwh->rc = rc;
+    rc->rh_ctx = kwh;
+    rc->rh_cleaner = &clean_kwh;
+
+    if (GNUNET_OK !=
+        TEH_kyc_get_logic (kwh->logic,
+                           &kwh->plugin,
+                           &kwh->pd))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "KYC logic `%s' unknown (check KYC provider 
configuration)\n",
+                  kwh->logic);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_NOT_FOUND,
+                                         
TALER_EC_EXCHANGE_KYC_WEBHOOK_LOGIC_UNKNOWN,
+                                         "$LOGIC");
+    }
+    kwh->wh = kwh->plugin->webhook (kwh->plugin->cls,
+                                    kwh->pd,
+                                    TEH_plugin->kyc_provider_account_lookup,
+                                    TEH_plugin->cls,
+                                    method,
+                                    &args[1],
+                                    rc->connection,
+                                    root,
+                                    &webhook_finished_cb,
+                                    kwh);
+    if (NULL == kwh->wh)
+    {
+      GNUNET_break_op (0);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+                                         "failed to run webhook logic");
+    }
+    kwh->suspended = GNUNET_YES;
+    GNUNET_CONTAINER_DLL_insert (kwh_head,
+                                 kwh_tail,
+                                 kwh);
+    MHD_suspend_connection (rc->connection);
+    return MHD_YES;
+  }
+
+  if (NULL != kwh->response)
+  {
+    /* handle _failed_ resumed cases */
+    return MHD_queue_response (rc->connection,
+                               kwh->response_code,
+                               kwh->response);
+  }
+
+  /* We resumed, but got no response? This should
+     not happen. */
+  GNUNET_break (0);
+  return TALER_MHD_reply_with_error (rc->connection,
+                                     MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                     
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+                                     "resumed without response");
+}
+
+
+MHD_RESULT
+TEH_handler_kyc_webhook_get (
+  struct TEH_RequestContext *rc,
+  const char *const args[])
+{
+  return handler_kyc_webhook_generic (rc,
+                                      MHD_HTTP_METHOD_GET,
+                                      NULL,
+                                      args);
+}
+
+
+MHD_RESULT
+TEH_handler_kyc_webhook_post (
+  struct TEH_RequestContext *rc,
+  const json_t *root,
+  const char *const args[])
+{
+  return handler_kyc_webhook_generic (rc,
+                                      MHD_HTTP_METHOD_POST,
+                                      root,
+                                      args);
+}
+
+
+/* end of taler-exchange-httpd_kyc-webhook.c */
diff --git a/src/exchange/taler-exchange-httpd_kyc-webhook.h 
b/src/exchange/taler-exchange-httpd_kyc-webhook.h
new file mode 100644
index 00000000..1f472a87
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-webhook.h
@@ -0,0 +1,64 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2021 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-webhook.h
+ * @brief Handle /kyc-webhook requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_KYC_WEBHOOK_H
+#define TALER_EXCHANGE_HTTPD_KYC_WEBHOOK_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Shutdown kyc-webhook subsystem.  Resumes all suspended long-polling clients
+ * and cleans up data structures.
+ */
+void
+TEH_kyc_webhook_cleanup (void);
+
+
+/**
+ * Handle a GET "/kyc-webhook" request.
+ *
+ * @param rc request to handle
+ * @param args one argument with the payment_target_uuid
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_kyc_webhook_get (
+  struct TEH_RequestContext *rc,
+  const char *const args[]);
+
+
+/**
+ * Handle a POST "/kyc-webhook" request.
+ *
+ * @param rc request to handle
+ * @param root uploaded JSON body
+ * @param args one argument with the payment_target_uuid
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_kyc_webhook_post (
+  struct TEH_RequestContext *rc,
+  const json_t *root,
+  const char *const args[]);
+
+
+#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index 7c066784..e501dc2d 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -16602,7 +16602,7 @@ postgres_update_kyc_requirement_by_row (
   void *cls,
   uint64_t legi_row,
   const char *provider_section,
-  struct TALER_PaytoHashP *h_payto,
+  const struct TALER_PaytoHashP *h_payto,
   const char *provider_account_id,
   const char *provider_legitimization_id,
   struct GNUNET_TIME_Absolute expiration)
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index 5411fbe1..42b8a742 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -5677,7 +5677,7 @@ struct TALER_EXCHANGEDB_Plugin
     void *cls,
     uint64_t legi_row,
     const char *provider_section,
-    struct TALER_PaytoHashP *h_payto,
+    const struct TALER_PaytoHashP *h_payto,
     const char *provider_account_id,
     const char *provider_legitimization_id,
     struct GNUNET_TIME_Absolute expiration);
diff --git a/src/include/taler_kyclogic_plugin.h 
b/src/include/taler_kyclogic_plugin.h
index f9484962..8e52e051 100644
--- a/src/include/taler_kyclogic_plugin.h
+++ b/src/include/taler_kyclogic_plugin.h
@@ -147,11 +147,10 @@ typedef void
 
 
 /**
- * Function called with the result of a proof check
- * operation.
+ * Function called with the result of a proof check operation.
  *
  * Note that the "decref" for the @a response
- * will be done by the plugin.
+ * will be done by the callee and MUST NOT be done by the plugin.
  *
  * @param cls closure
  * @param status KYC status
@@ -173,13 +172,13 @@ typedef void
 
 
 /**
- * Function called with the result of a webhook
- * operation.
+ * Function called with the result of a webhook operation.
  *
- * Note that the "decref" for the @a response
- * will be done by the plugin.
+ * Note that the "decref" for the @a response will be done by the callee and
+ * MUST NOT be done by the plugin!
  *
  * @param cls closure
+ * @param legi_row legitimization request the webhook was about
  * @param account_id account the webhook was about
  * @param provider_user_id set to user ID at the provider, or NULL if not 
supported or unknown
  * @param provider_legitimization_id set to legitimization process ID at the 
provider, or NULL if not supported or unknown
@@ -191,6 +190,7 @@ typedef void
 typedef void
 (*TALER_KYCLOGIC_WebhookCallback)(
   void *cls,
+  uint64_t legi_row,
   const struct TALER_PaytoHashP *account_id,
   const char *provider_user_id,
   const char *provider_legitimization_id,
@@ -330,7 +330,7 @@ struct TALER_KYCLOGIC_Plugin
    * @param plc callback to lookup accounts with
    * @param plc_cls closure for @a plc
    * @param http_method HTTP method used for the webhook
-   * @param url_path rest of the URL after `/kyc-webhook/`
+   * @param url_path rest of the URL after `/kyc-webhook/$LOGIC/`
    * @param connection MHD connection object (for HTTP headers)
    * @param body_size number of bytes in @a body
    * @param body HTTP request body
@@ -344,10 +344,9 @@ struct TALER_KYCLOGIC_Plugin
              TALER_KYCLOGIC_ProviderLookupCallback plc,
              void *plc_cls,
              const char *http_method,
-             const char *url_path,
+             const char *const url_path[],
              struct MHD_Connection *connection,
-             size_t body_size,
-             const void *body,
+             const json_t *upload,
              TALER_KYCLOGIC_WebhookCallback cb,
              void *cb_cls);
 
diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c 
b/src/kyclogic/plugin_kyclogic_oauth2.c
index 3bcd745c..ac13355e 100644
--- a/src/kyclogic/plugin_kyclogic_oauth2.c
+++ b/src/kyclogic/plugin_kyclogic_oauth2.c
@@ -556,7 +556,6 @@ return_proof_response (void *cls)
           GNUNET_TIME_relative_to_absolute (ph->pd->expiration),
           ph->http_status,
           ph->response);
-  MHD_destroy_response (ph->response);
   GNUNET_free (ph->provider_user_id);
   GNUNET_free (ph);
 }
@@ -943,6 +942,7 @@ wh_return_not_found (void *cls)
                                               "",
                                               MHD_RESPMEM_PERSISTENT);
   wh->cb (wh->cb_cls,
+          0LLU,
           NULL,
           NULL,
           NULL,
@@ -962,10 +962,9 @@ wh_return_not_found (void *cls)
  * @param plc callback to lookup accounts with
  * @param plc_cls closure for @a plc
  * @param http_method HTTP method used for the webhook
- * @param url_path rest of the URL after `/kyc-webhook/`
+ * @param url_path rest of the URL after `/kyc-webhook/$LOGIC/`, as 
NULL-terminated array
  * @param connection MHD connection object (for HTTP headers)
- * @param body_size number of bytes in @a body
- * @param body HTTP request body
+ * @param body HTTP request body, or NULL if not available
  * @param cb function to call with the result
  * @param cb_cls closure for @a cb
  * @return handle to cancel operation early
@@ -976,10 +975,9 @@ oauth2_webhook (void *cls,
                 TALER_KYCLOGIC_ProviderLookupCallback plc,
                 void *plc_cls,
                 const char *http_method,
-                const char *url_path,
+                const char *url_path[],
                 struct MHD_Connection *connection,
-                size_t body_size,
-                const void *body,
+                const json_t *body,
                 TALER_KYCLOGIC_WebhookCallback cb,
                 void *cb_cls)
 {

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