gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: -implement more of the KYC handl


From: gnunet
Subject: [taler-exchange] branch master updated: -implement more of the KYC handlers
Date: Tue, 19 Oct 2021 21:02:13 +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 778a402d -implement more of the KYC handlers
778a402d is described below

commit 778a402d07706462818e9c9d01520fd3d8d238d8
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Tue Oct 19 21:02:04 2021 +0200

    -implement more of the KYC handlers
---
 contrib/gana                                  |   2 +-
 src/curl/curl.c                               |   2 +-
 src/exchange/Makefile.am                      |   1 +
 src/exchange/exchange.conf                    |   4 +
 src/exchange/taler-exchange-httpd.c           |  77 ++++-
 src/exchange/taler-exchange-httpd.h           |  15 +
 src/exchange/taler-exchange-httpd_deposit.c   |   2 +-
 src/exchange/taler-exchange-httpd_keys.c      |   2 +-
 src/exchange/taler-exchange-httpd_kyc-check.c |  23 +-
 src/exchange/taler-exchange-httpd_kyc-proof.c | 481 ++++++++++++++++++++++++--
 src/exchange/taler-exchange-httpd_kyc-proof.h |   8 +
 src/exchangedb/plugin_exchangedb_postgres.c   |  32 ++
 src/include/taler_curl_lib.h                  |   2 +-
 src/include/taler_exchangedb_plugin.h         |  14 +
 src/lib/exchange_api_link.c                   |   4 +-
 15 files changed, 621 insertions(+), 48 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index ca56acca..8c7d9be4 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit ca56accac72b6ce050a38d36172390b14100a538
+Subproject commit 8c7d9be40ba627348da3e01b91b4f1d3cc78631f
diff --git a/src/curl/curl.c b/src/curl/curl.c
index 1410294e..73fcf86a 100644
--- a/src/curl/curl.c
+++ b/src/curl/curl.c
@@ -37,7 +37,7 @@
  * @param body JSON body to add to @e ctx
  * @return #GNUNET_OK on success #GNUNET_SYSERR on failure
  */
-int
+enum GNUNET_GenericReturnValue
 TALER_curl_easy_post (struct TALER_CURL_PostContext *ctx,
                       CURL *eh,
                       const json_t *body)
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index d199e4bc..7779c38b 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -123,6 +123,7 @@ taler_exchange_httpd_LDADD = \
   -lgnunetutil \
   -lgnunetjson \
   -ljansson \
+  -lcurl \
   -lz \
   $(XLIB)
 
diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf
index 590b9c39..3bcea08f 100644
--- a/src/exchange/exchange.conf
+++ b/src/exchange/exchange.conf
@@ -102,3 +102,7 @@ KYC_MODE = NONE
 
 # KYC Client secret used to obtain access tokens.
 # KYC_OAUTH2_CLIENT_SECRET =
+
+# Where to redirect clients after successful
+# authorization?
+# KYC_OAUTH_POST_URL = https://bank.com/
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index 5491c3ef..1feede1a 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -102,6 +102,11 @@ struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
  */
 char *TEH_currency;
 
+/**
+ * Our base URL.
+ */
+char *TEH_base_url;
+
 /**
  * Default timeout in seconds for HTTP requests.
  */
@@ -134,6 +139,17 @@ static unsigned long long req_count;
  */
 static unsigned long long req_max;
 
+/**
+ * Context for all CURL operations (useful to the event loop)
+ */
+struct GNUNET_CURL_Context *TEH_curl_ctx;
+
+/**
+ * Context for integrating #exchange_curl_ctx with the
+ * GNUnet event loop.
+ */
+static struct GNUNET_CURL_RescheduleContext *exchange_curl_rc;
+
 
 /**
  * Signature of functions that handle operations on coins.
@@ -1203,6 +1219,19 @@ parse_kyc_oauth_cfg (void)
     return GNUNET_SYSERR;
   }
   TEH_kyc_config.details.oauth2.client_secret = s;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+                                             "exchange-kyc-oauth2",
+                                             "KYC_OAUTH2_POST_URL",
+                                             &s))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "exchange-kyc-oauth2",
+                               "KYC_OAUTH2_POST_URL");
+    return GNUNET_SYSERR;
+  }
+  TEH_kyc_config.details.oauth2.post_kyc_redirect_url = s;
   return GNUNET_OK;
 }
 
@@ -1301,6 +1330,26 @@ exchange_serve_process_config (void)
                                "CURRENCY");
     return GNUNET_SYSERR;
   }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+                                             "exchange",
+                                             "BASE_URL",
+                                             &TEH_base_url))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "exchange",
+                               "BASE_URL");
+    return GNUNET_SYSERR;
+  }
+  if (! TALER_url_valid_charset (TEH_base_url))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               "exchange",
+                               "BASE_URL",
+                               "invalid URL");
+    return GNUNET_SYSERR;
+  }
+
   if (TEH_KYC_NONE != TEH_kyc_config.mode)
   {
     if (GNUNET_YES ==
@@ -1593,11 +1642,26 @@ do_shutdown (void *cls)
   mhd = TALER_MHD_daemon_stop ();
   TEH_resume_keys_requests (true);
   TEH_reserves_get_cleanup ();
+  TEH_kyc_proof_cleanup ();
   if (NULL != mhd)
     MHD_stop_daemon (mhd);
   TEH_WIRE_done ();
   TEH_keys_finished ();
-  TALER_EXCHANGEDB_plugin_unload (TEH_plugin);
+  if (NULL != TEH_plugin)
+  {
+    TALER_EXCHANGEDB_plugin_unload (TEH_plugin);
+    TEH_plugin = NULL;
+  }
+  if (NULL != TEH_curl_ctx)
+  {
+    GNUNET_CURL_fini (TEH_curl_ctx);
+    TEH_curl_ctx = NULL;
+  }
+  if (NULL != exchange_curl_rc)
+  {
+    GNUNET_CURL_gnunet_rc_destroy (exchange_curl_rc);
+    exchange_curl_rc = NULL;
+  }
 }
 
 
@@ -1655,6 +1719,17 @@ run (void *cls,
   }
 
   TEH_load_terms (TEH_cfg);
+  TEH_curl_ctx
+    = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+                        &exchange_curl_rc);
+  if (NULL == TEH_curl_ctx)
+  {
+    GNUNET_break (0);
+    global_ret = EXIT_FAILURE;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  exchange_curl_rc = GNUNET_CURL_gnunet_rc_create (TEH_curl_ctx);
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
                                  NULL);
   fh = TALER_MHD_bind (TEH_cfg,
diff --git a/src/exchange/taler-exchange-httpd.h 
b/src/exchange/taler-exchange-httpd.h
index 3f934dbd..f66626b3 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -105,6 +105,12 @@ struct TEH_KycOptions
        */
       char *client_secret;
 
+      /**
+       * Where to redirect clients after the
+       * Web-based KYC process is done?
+       */
+      char *post_kyc_redirect_url;
+
     } oauth2;
 
   } details;
@@ -162,11 +168,20 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
  */
 extern char *TEH_currency;
 
+/**
+ * Our (externally visible) base URL.
+ */
+extern char *TEH_base_url;
+
 /**
  * Are we shutting down?
  */
 extern volatile bool MHD_terminating;
 
+/**
+ * Context for all CURL operations (useful to the event loop)
+ */
+extern struct GNUNET_CURL_Context *TEH_curl_ctx;
 
 /**
  * @brief Struct describing an URL and the handler for it.
diff --git a/src/exchange/taler-exchange-httpd_deposit.c 
b/src/exchange/taler-exchange-httpd_deposit.c
index 7148b93f..42162f8a 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -381,7 +381,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
           sizeof (deposit));
   deposit.coin.coin_pub = *coin_pub;
   {
-    int res;
+    enum GNUNET_GenericReturnValue res;
 
     res = TALER_MHD_parse_json_data (connection,
                                      root,
diff --git a/src/exchange/taler-exchange-httpd_keys.c 
b/src/exchange/taler-exchange-httpd_keys.c
index 99c72745..70590020 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -1345,7 +1345,7 @@ get_date_string (struct GNUNET_TIME_Absolute at,
  * @param[in,out] response the response to modify
  * @return #GNUNET_OK on success
  */
-static int
+static enum GNUNET_GenericReturnValue
 setup_general_response_headers (const struct TEH_KeyStateHandle *ksh,
                                 struct MHD_Response *response)
 {
diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c 
b/src/exchange/taler-exchange-httpd_kyc-check.c
index 13f5810b..ae1ab34f 100644
--- a/src/exchange/taler-exchange-httpd_kyc-check.c
+++ b/src/exchange/taler-exchange-httpd_kyc-check.c
@@ -143,12 +143,31 @@ TEH_handler_kyc_check (
       return res;
     if (! kcc.kyc.ok)
     {
+      char *url;
+      char *redirect_uri;
+      char *redirect_uri_encoded;
+
       GNUNET_assert (TEH_KYC_OAUTH2 == TEH_kyc_config.mode);
-      return TALER_MHD_REPLY_JSON_PACK (
+      GNUNET_asprintf (&redirect_uri,
+                       "%s/kyc-proof/%llu",
+                       TEH_base_url,
+                       payment_target_uuid);
+      redirect_uri_encoded = TALER_urlencode (redirect_uri);
+      GNUNET_free (redirect_uri);
+      GNUNET_asprintf (&url,
+                       "%s/login?client_id=%s&redirect_uri=%s",
+                       TEH_kyc_config.details.oauth2.url,
+                       TEH_kyc_config.details.oauth2.client_id,
+                       redirect_uri_encoded);
+      GNUNET_free (redirect_uri_encoded);
+
+      res = TALER_MHD_REPLY_JSON_PACK (
         rc->connection,
         MHD_HTTP_ACCEPTED,
         GNUNET_JSON_pack_string ("kyc_url",
-                                 TEH_kyc_config.details.oauth2.url));
+                                 url));
+      GNUNET_free (url);
+      return res;
     }
     {
       struct TALER_ExchangePublicKeyP pub;
diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c 
b/src/exchange/taler-exchange-httpd_kyc-proof.c
index be7fc50f..842e5dfd 100644
--- a/src/exchange/taler-exchange-httpd_kyc-proof.c
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.c
@@ -36,9 +36,99 @@
 struct KycProofContext
 {
 
+  /**
+   * Kept in a DLL while suspended.
+   */
+  struct KycProofContext *next;
+
+  /**
+   * Kept in a DLL while suspended.
+   */
+  struct KycProofContext *prev;
+
+  /**
+   * Details about the connection we are processing.
+   */
+  struct TEH_RequestContext *rc;
+
+  /**
+   * Handle for the OAuth 2.0 CURL request.
+   */
+  struct GNUNET_CURL_Job *job;
+
+  /**
+   * OAuth 2.0 authorization code.
+   */
+  const char *authorization_code;
+
+  /**
+   * OAuth 2.0 token URL we are using for the
+   * request.
+   */
+  char *token_url;
+
+  /**
+   * Body of the POST request.
+   */
+  char *post_body;
+
+  /**
+   * Payment target this is about.
+   */
+  unsigned long long payment_target_uuid;
+
+  /**
+   * HTTP response to return.
+   */
+  struct MHD_Response *response;
+
+  /**
+   * 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 KycProofContext *kpc_head;
+
+/**
+ * Contexts are kept in a DLL while suspended.
+ */
+static struct KycProofContext *kpc_tail;
+
+
+void
+TEH_kyc_proof_cleanup (void)
+{
+  struct KycProofContext *kpc;
+
+  while (NULL != (kpc = kpc_head))
+  {
+    if (NULL != kpc->job)
+    {
+      GNUNET_CURL_job_cancel (kpc->job);
+      kpc->job = NULL;
+    }
+    GNUNET_CONTAINER_DLL_remove (kpc_head,
+                                 kpc_tail,
+                                 kpc);
+    kpc->suspended = GNUNET_NO;
+    MHD_resume_connection (kpc->rc->connection);
+  }
+}
+
+
 /**
  * Function implementing database transaction to check proof's KYC status.
  * Runs the transaction logic; IF it returns a non-error code, the transaction
@@ -54,14 +144,185 @@ struct KycProofContext
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-proof_kyc_check (void *cls,
-                 struct MHD_Connection *connection,
-                 MHD_RESULT *mhd_ret)
+persist_kyc_ok (void *cls,
+                struct MHD_Connection *connection,
+                MHD_RESULT *mhd_ret)
 {
   struct KycProofContext *kpc = cls;
 
-  (void) kpc; // FIXME: do work here!
-  return -2;
+  return TEH_plugin->set_kyc_ok (TEH_plugin->cls,
+                                 kpc->payment_target_uuid);
+}
+
+
+/**
+ * After we are done with the CURL interaction we
+ * need to update our database state.
+ *
+ * @param cls our `struct KycProofContext`
+ * @param response_code HTTP response code from server, 0 on hard error
+ * @param response in JSON, NULL if response was not in JSON format
+ */
+static void
+handle_curl_login_finished (void *cls,
+                            long response_code,
+                            const void *response)
+{
+  struct KycProofContext *kpc = cls;
+  const json_t *j = response;
+
+  kpc->job = NULL;
+  switch (response_code)
+  {
+  case MHD_HTTP_OK:
+    {
+      const char *access_token;
+      const char *token_type;
+      uint64_t expires_in_s;
+      const char *refresh_token;
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_string ("access_token",
+                                 &access_token),
+        GNUNET_JSON_spec_string ("token_type",
+                                 &token_type),
+        GNUNET_JSON_spec_uint64 ("expires_in",
+                                 &expires_in_s),
+        GNUNET_JSON_spec_string ("refresh_token",
+                                 &refresh_token),
+        GNUNET_JSON_spec_end ()
+      };
+
+      {
+        enum GNUNET_GenericReturnValue res;
+        const char *emsg;
+        unsigned int line;
+
+        res = GNUNET_JSON_parse (j,
+                                 spec,
+                                 &emsg,
+                                 &line);
+        if (GNUNET_OK != res)
+        {
+          GNUNET_break_op (0);
+          kpc->response
+            = TALER_MHD_make_error (
+                TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+                "Unexpected response from KYC gateway");
+          kpc->response_code
+            = MHD_HTTP_BAD_GATEWAY;
+          MHD_resume_connection (kpc->rc->connection);
+          TALER_MHD_daemon_trigger ();
+          return;
+        }
+      }
+      if (0 != strcasecmp (token_type,
+                           "bearer"))
+      {
+        GNUNET_break_op (0);
+        kpc->response
+          = TALER_MHD_make_error (
+              TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+              "Unexpected token type in response from KYC gateway");
+        kpc->response_code
+          = MHD_HTTP_BAD_GATEWAY;
+        MHD_resume_connection (kpc->rc->connection);
+        TALER_MHD_daemon_trigger ();
+        return;
+      }
+
+      /* TODO: Here we might want to keep something to persist in the DB, and
+         possibly use the access_token to download information we should
+         persist; then continue! */
+
+      MHD_resume_connection (kpc->rc->connection);
+      TALER_MHD_daemon_trigger ();
+      return;
+    }
+  default:
+    {
+      const char *msg;
+      const char *desc;
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_string ("error",
+                                 &msg),
+        GNUNET_JSON_spec_string ("error_description",
+                                 &desc),
+        GNUNET_JSON_spec_end ()
+      };
+
+      {
+        enum GNUNET_GenericReturnValue res;
+        const char *emsg;
+        unsigned int line;
+
+        res = GNUNET_JSON_parse (j,
+                                 spec,
+                                 &emsg,
+                                 &line);
+        if (GNUNET_OK != res)
+        {
+          GNUNET_break_op (0);
+          kpc->response
+            = TALER_MHD_make_error (
+                TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+                "Unexpected response from KYC gateway");
+          kpc->response_code
+            = MHD_HTTP_BAD_GATEWAY;
+          MHD_resume_connection (kpc->rc->connection);
+          TALER_MHD_daemon_trigger ();
+          return;
+        }
+      }
+      /* case TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_AUTHORZATION_FAILED,
+         we MAY want to in the future look at the requested content type
+         and possibly respond in JSON if indicated. */
+      {
+        char *reply;
+
+        GNUNET_asprintf (&reply,
+                         
"<html><head><title>%s</title></head><body><h1>%s</h1><p>%s</p></body></html>",
+                         msg,
+                         msg,
+                         desc);
+        kpc->response
+          = MHD_create_response_from_buffer (strlen (reply),
+                                             reply,
+                                             MHD_RESPMEM_MUST_COPY);
+        GNUNET_assert (NULL != kpc->response);
+        GNUNET_free (reply);
+      }
+      kpc->response_code = MHD_HTTP_FORBIDDEN;
+      MHD_resume_connection (kpc->rc->connection);
+      TALER_MHD_daemon_trigger ();
+    }
+    break;
+  }
+}
+
+
+/**
+ * Function called to clean up a context.
+ *
+ * @param rc request context
+ */
+static void
+clean_kpc (struct TEH_RequestContext *rc)
+{
+  struct KycProofContext *kpc = rc->rh_ctx;
+
+  if (NULL != kpc->job)
+  {
+    GNUNET_CURL_job_cancel (kpc->job);
+    kpc->job = NULL;
+  }
+  if (NULL != kpc->response)
+  {
+    MHD_destroy_response (kpc->response);
+    kpc->response = NULL;
+  }
+  GNUNET_free (kpc->post_body);
+  GNUNET_free (kpc->token_url);
+  GNUNET_free (kpc);
 }
 
 
@@ -70,44 +331,188 @@ TEH_handler_kyc_proof (
   struct TEH_RequestContext *rc,
   const char *const args[])
 {
-  struct KycProofContext kpc;
-  MHD_RESULT res;
-  enum GNUNET_GenericReturnValue ret;
-  unsigned long long payment_target_uuid;
-  char dummy;
+  struct KycProofContext *kpc = rc->rh_ctx;
+
+  if (NULL == kpc)
+  { /* first time */
+    char dummy;
+
+    kpc = GNUNET_new (struct KycProofContext);
+    kpc->rc = rc;
+    rc->rh_ctx = kpc;
+    rc->rh_cleaner = &clean_kpc;
+
+    if (1 !=
+        sscanf (args[0],
+                "%llu%c",
+                &kpc->payment_target_uuid,
+                &dummy))
+    {
+      GNUNET_break_op (0);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
+                                         "payment_target_uuid");
+    }
+    kpc->authorization_code
+      = MHD_lookup_connection_value (rc->connection,
+                                     MHD_GET_ARGUMENT_KIND,
+                                     "code");
+    if (NULL == kpc->authorization_code)
+    {
+      GNUNET_break_op (0);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
+                                         "code");
+    }
+    if (TEH_KYC_NONE == TEH_kyc_config.mode)
+      return TALER_MHD_reply_static (
+        rc->connection,
+        MHD_HTTP_NO_CONTENT,
+        NULL,
+        NULL,
+        0);
+
+    {
+      CURL *eh;
+
+      eh = curl_easy_init ();
+      if (NULL == eh)
+      {
+        GNUNET_break (0);
+        return TALER_MHD_reply_with_error (rc->connection,
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           TALER_EC_GENERIC_ALLOCATION_FAILURE,
+                                           "curl_easy_init");
+      }
+      GNUNET_asprintf (&kpc->token_url,
+                       "%s/token",
+                       TEH_kyc_config.details.oauth2.url);
+      GNUNET_assert (CURLE_OK ==
+                     curl_easy_setopt (eh,
+                                       CURLOPT_URL,
+                                       kpc->token_url));
+      GNUNET_assert (CURLE_OK ==
+                     curl_easy_setopt (eh,
+                                       CURLOPT_POST,
+                                       1));
+      {
+        char *client_id;
+        char *redirect_uri;
+        char *client_secret;
+        char *authorization_code;
+
+        client_id = curl_easy_escape (eh,
+                                      TEH_kyc_config.details.oauth2.client_id,
+                                      0);
+        GNUNET_assert (NULL != client_id);
+        {
+          char *request_uri;
+
+          GNUNET_asprintf (&request_uri,
+                           "%s/login?client_id=%s",
+                           TEH_kyc_config.details.oauth2.url,
+                           TEH_kyc_config.details.oauth2.client_id);
+          redirect_uri = curl_easy_escape (eh,
+                                           request_uri,
+                                           0);
+          GNUNET_free (request_uri);
+        }
+        GNUNET_assert (NULL != redirect_uri);
+        client_secret = curl_easy_escape (eh,
+                                          TEH_kyc_config.details.oauth2.
+                                          client_secret,
+                                          0);
+        GNUNET_assert (NULL != client_secret);
+        authorization_code = curl_easy_escape (eh,
+                                               kpc->authorization_code,
+                                               0);
+        GNUNET_assert (NULL != authorization_code);
+        GNUNET_asprintf (&kpc->post_body,
+                         
"client_id=%s&redirect_uri=%s&client_secret=%s&code=%s&grant_type=authorization_code",
+                         client_id,
+                         redirect_uri,
+                         client_secret,
+                         authorization_code);
+        curl_free (authorization_code);
+        curl_free (client_secret);
+        curl_free (redirect_uri);
+        curl_free (client_id);
+      }
+      GNUNET_assert (CURLE_OK ==
+                     curl_easy_setopt (eh,
+                                       CURLOPT_POSTFIELDS,
+                                       kpc->post_body));
+      GNUNET_assert (CURLE_OK ==
+                     curl_easy_setopt (eh,
+                                       CURLOPT_FOLLOWLOCATION,
+                                       1L));
+      /* limit MAXREDIRS to 5 as a simple security measure against
+         a potential infinite loop caused by a malicious target */
+      GNUNET_assert (CURLE_OK ==
+                     curl_easy_setopt (eh,
+                                       CURLOPT_MAXREDIRS,
+                                       5L));
 
-  if (1 !=
-      sscanf (args[0],
-              "%llu%c",
-              &payment_target_uuid,
-              &dummy))
+      kpc->job = GNUNET_CURL_job_add (TEH_curl_ctx,
+                                      eh,
+                                      &handle_curl_login_finished,
+                                      kpc);
+      kpc->suspended = GNUNET_YES;
+      GNUNET_CONTAINER_DLL_insert (kpc_head,
+                                   kpc_tail,
+                                   kpc);
+      MHD_suspend_connection (rc->connection);
+      return MHD_YES;
+    }
+  }
+
+  if (NULL != kpc->response)
   {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
-                                       "payment_target_uuid");
+    /* handle _failed_ resumed cases */
+    return MHD_queue_response (rc->connection,
+                               kpc->response_code,
+                               kpc->response);
   }
 
-  if (1 || (TEH_KYC_NONE == TEH_kyc_config.mode))
-    return TALER_MHD_reply_static (
-      rc->connection,
-      MHD_HTTP_NO_CONTENT,
-      NULL,
-      NULL,
-      0);
-  ret = TEH_DB_run_transaction (rc->connection,
-                                "check proof kyc",
-                                &res,
-                                &proof_kyc_check,
-                                &kpc);
-  if (GNUNET_SYSERR == ret)
+  /* _successfully_ resumed case */
+  {
+    MHD_RESULT res;
+    enum GNUNET_GenericReturnValue ret;
+
+    ret = TEH_DB_run_transaction (kpc->rc->connection,
+                                  "check proof kyc",
+                                  &res,
+                                  &persist_kyc_ok,
+                                  kpc);
+    if (GNUNET_SYSERR == ret)
+      return res;
+  }
+
+  {
+    struct MHD_Response *response;
+    MHD_RESULT res;
+
+    response = MHD_create_response_from_buffer (0,
+                                                "",
+                                                MHD_RESPMEM_PERSISTENT);
+    if (NULL == response)
+    {
+      GNUNET_break (0);
+      return MHD_NO;
+    }
+    GNUNET_break (MHD_YES ==
+                  MHD_add_response_header (
+                    response,
+                    MHD_HTTP_HEADER_LOCATION,
+                    TEH_kyc_config.details.oauth2.post_kyc_redirect_url));
+    res = MHD_queue_response (rc->connection,
+                              MHD_HTTP_SEE_OTHER,
+                              response);
+    MHD_destroy_response (response);
     return res;
-  return TALER_MHD_REPLY_JSON_PACK (
-    rc->connection,
-    MHD_HTTP_OK,
-    GNUNET_JSON_pack_uint64 ("42",
-                             42));
+  }
 }
 
 
diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.h 
b/src/exchange/taler-exchange-httpd_kyc-proof.h
index 9cf1963c..c075b242 100644
--- a/src/exchange/taler-exchange-httpd_kyc-proof.h
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.h
@@ -25,6 +25,14 @@
 #include "taler-exchange-httpd.h"
 
 
+/**
+ * Shutdown kyc-proof subsystem.  Resumes all suspended long-polling clients
+ * and cleans up data structures.
+ */
+void
+TEH_kyc_proof_cleanup (void);
+
+
 /**
  * Handle a "/kyc-proof" request.
  *
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index 0026829d..4b3ae19d 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -360,6 +360,12 @@ prepare_statements (struct PostgresClosure *pg)
                             " LIMIT 1;",
                             1),
 #if FIXME_DD23
+    /* Used in #postgres_set_kyc_ok() */
+    GNUNET_PQ_make_prepare ("set_kyc_ok",
+                            "UPDATE wire_targets"
+                            " SET kyc_ok=TRUE"
+                            " WHERE wire_target_serial_id=$1",
+                            1),
     /* Used in #postgres_get_kyc_status() */
     GNUNET_PQ_make_prepare ("get_kyc_status",
                             "SELECT"
@@ -3555,6 +3561,31 @@ postgres_reserves_get (void *cls,
 }
 
 
+/**
+ * Set the KYC status to "OK" for a bank account.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param payment_target_uuid which account has been checked
+ * @param ... possibly additional data to persist (TODO)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_set_kyc_ok (void *cls,
+                     uint64_t payment_target_uuid,
+                     ...)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&payment_target_uuid),
+    GNUNET_PQ_query_param_end
+  };
+
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "set_kyc_ok",
+                                             params);
+}
+
+
 /**
  * Get the KYC status for a bank account.
  *
@@ -11261,6 +11292,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
   plugin->iterate_auditor_denominations =
     &postgres_iterate_auditor_denominations;
   plugin->reserves_get = &postgres_reserves_get;
+  plugin->set_kyc_ok = &postgres_set_kyc_ok;
   plugin->get_kyc_status = &postgres_get_kyc_status;
   plugin->select_kyc_status = &postgres_select_kyc_status;
   plugin->inselect_wallet_kyc_status = &postgres_inselect_wallet_kyc_status;
diff --git a/src/include/taler_curl_lib.h b/src/include/taler_curl_lib.h
index 42d7f9d1..5151f4cf 100644
--- a/src/include/taler_curl_lib.h
+++ b/src/include/taler_curl_lib.h
@@ -59,7 +59,7 @@ struct TALER_CURL_PostContext
  * @param body JSON body to add to @e ctx
  * @return #GNUNET_OK on success #GNUNET_SYSERR on failure
  */
-int
+enum GNUNET_GenericReturnValue
 TALER_curl_easy_post (struct TALER_CURL_PostContext *ctx,
                       CURL *eh,
                       const json_t *body);
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index b8c50406..5a3313ca 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -2360,6 +2360,20 @@ struct TALER_EXCHANGEDB_Plugin
                   struct TALER_EXCHANGEDB_KycStatus *kyc);
 
 
+  /**
+   * Set the KYC status to "OK" for a bank account.
+   *
+   * @param cls the @e cls of this struct with the plugin-specific state
+   * @param payment_target_uuid which account has been checked
+   * @param ... possibly additional data to persist (TODO)
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*set_kyc_ok)(void *cls,
+                uint64_t payment_target_uuid,
+                ...);
+
+
   /**
    * Get the KYC status for a bank account.
    *
diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c
index 7f29b3b8..ceb31884 100644
--- a/src/lib/exchange_api_link.c
+++ b/src/lib/exchange_api_link.c
@@ -82,7 +82,7 @@ struct TALER_EXCHANGE_LinkHandle
  * @param[out] pub where to return the public key for the coin
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
-static int
+static enum GNUNET_GenericReturnValue
 parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
                  const json_t *json,
                  uint32_t coin_num,
@@ -175,7 +175,7 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
  * @param json json reply with the data for one coin
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
-static int
+static enum GNUNET_GenericReturnValue
 parse_link_ok (struct TALER_EXCHANGE_LinkHandle *lh,
                const json_t *json)
 {

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