summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------contrib/gana0
-rw-r--r--src/curl/curl.c2
-rw-r--r--src/exchange/Makefile.am1
-rw-r--r--src/exchange/exchange.conf4
-rw-r--r--src/exchange/taler-exchange-httpd.c77
-rw-r--r--src/exchange/taler-exchange-httpd.h15
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c2
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c2
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-check.c23
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-proof.c481
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-proof.h8
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c32
-rw-r--r--src/include/taler_curl_lib.h2
-rw-r--r--src/include/taler_exchangedb_plugin.h14
-rw-r--r--src/lib/exchange_api_link.c4
15 files changed, 620 insertions, 47 deletions
diff --git a/contrib/gana b/contrib/gana
-Subproject ca56accac72b6ce050a38d36172390b14100a53
+Subproject 8c7d9be40ba627348da3e01b91b4f1d3cc78631
diff --git a/src/curl/curl.c b/src/curl/curl.c
index 1410294e4..73fcf86a4 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 d199e4bc2..7779c38b1 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 590b9c39f..3bcea08fb 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 5491c3ef3..1feede1a8 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -103,6 +103,11 @@ struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
char *TEH_currency;
/**
+ * Our base URL.
+ */
+char *TEH_base_url;
+
+/**
* Default timeout in seconds for HTTP requests.
*/
static unsigned int connection_timeout = 30;
@@ -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 3f934dbd5..f66626b3d 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;
@@ -163,10 +169,19 @@ 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 7148b93fc..42162f8a4 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 99c727450..705900206 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 13f5810b8..ae1ab34f2 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 be7fc50fe..842e5dfd2 100644
--- a/src/exchange/taler-exchange-httpd_kyc-proof.c
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.c
@@ -36,10 +36,100 @@
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
* logic MUST NOT queue a MHD response. IF it returns an hard error, the
@@ -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 9cf1963c7..c075b2424 100644
--- a/src/exchange/taler-exchange-httpd_kyc-proof.h
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.h
@@ -26,6 +26,14 @@
/**
+ * 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.
*
* @param rc request to handle
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 0026829da..4b3ae19d7 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"
@@ -3556,6 +3562,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.
*
* @param cls the @e cls of this struct with the plugin-specific state
@@ -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 42d7f9d1f..5151f4cf6 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 b8c504063..5a3313ca7 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -2361,6 +2361,20 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * 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.
*
* @param cls the @e cls of this struct with the plugin-specific state
diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c
index 7f29b3b8c..ceb318841 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)
{