implement kyc-proof hook in kyc-tester

This commit is contained in:
Christian Grothoff 2022-08-09 13:00:58 +02:00
parent f50a2e11b0
commit d58334cf89
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
6 changed files with 243 additions and 22 deletions

@ -1 +1 @@
Subproject commit 02da8656d6d915df023de0b90d18ade9e80603fa Subproject commit 2075d42719b00f2763fe71d327ef4b9fd23be476

View File

@ -272,7 +272,7 @@ handler_kyc_webhook_generic (
kwh->logic); kwh->logic);
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_WEBHOOK_LOGIC_UNKNOWN, TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
"$LOGIC"); "$LOGIC");
} }
kwh->wh = kwh->plugin->webhook (kwh->plugin->cls, kwh->wh = kwh->plugin->webhook (kwh->plugin->cls,

View File

@ -292,7 +292,7 @@ struct TALER_KYCLOGIC_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param pd provider configuration details * @param pd provider configuration details
* @param url_path rest of the URL after `/kyc-webhook/` * @param url_path rest of the URL after `/kyc-webhook/$H_PAYTO/$LOGIC`
* @param connection MHD connection object (for HTTP headers) * @param connection MHD connection object (for HTTP headers)
* @param account_id which account to trigger process for * @param account_id which account to trigger process for
* @param provider_user_id user ID (or NULL) the proof is for * @param provider_user_id user ID (or NULL) the proof is for
@ -304,7 +304,7 @@ struct TALER_KYCLOGIC_Plugin
struct TALER_KYCLOGIC_ProofHandle * struct TALER_KYCLOGIC_ProofHandle *
(*proof)(void *cls, (*proof)(void *cls,
const struct TALER_KYCLOGIC_ProviderDetails *pd, const struct TALER_KYCLOGIC_ProviderDetails *pd,
const char *url_path, const char *const url_path[],
struct MHD_Connection *connection, struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id, const struct TALER_PaytoHashP *account_id,
const char *provider_user_id, const char *provider_user_id,

View File

@ -767,7 +767,7 @@ handle_curl_proof_finished (void *cls,
static struct TALER_KYCLOGIC_ProofHandle * static struct TALER_KYCLOGIC_ProofHandle *
oauth2_proof (void *cls, oauth2_proof (void *cls,
const struct TALER_KYCLOGIC_ProviderDetails *pd, const struct TALER_KYCLOGIC_ProviderDetails *pd,
const char *url_path, const char *const url_path[],
struct MHD_Connection *connection, struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id, const struct TALER_PaytoHashP *account_id,
const char *provider_user_id, const char *provider_user_id,

View File

@ -262,7 +262,7 @@ template_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih)
static struct TALER_KYCLOGIC_ProofHandle * static struct TALER_KYCLOGIC_ProofHandle *
template_proof (void *cls, template_proof (void *cls,
const struct TALER_KYCLOGIC_ProviderDetails *pd, const struct TALER_KYCLOGIC_ProviderDetails *pd,
const char *url_path, const char *const url_path[],
struct MHD_Connection *connection, struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id, const struct TALER_PaytoHashP *account_id,
const char *provider_user_id, const char *provider_user_id,

View File

@ -161,6 +161,48 @@ struct TEKT_RequestHandler
}; };
/**
* Information we track per ongoing kyc-proof request.
*/
struct ProofRequestState
{
/**
* Kept in a DLL.
*/
struct ProofRequestState *next;
/**
* Kept in a DLL.
*/
struct ProofRequestState *prev;
/**
* Handle for operation with the plugin.
*/
struct TALER_KYCLOGIC_ProofHandle *ph;
/**
* Logic plugin we are using.
*/
struct TALER_KYCLOGIC_Plugin *logic;
/**
* HTTP request details.
*/
struct TEKT_RequestContext *rc;
};
/**
* Head of DLL.
*/
static struct ProofRequestState *rs_head;
/**
* Tail of DLL.
*/
static struct ProofRequestState *rs_tail;
/** /**
* The exchange's configuration (global) * The exchange's configuration (global)
*/ */
@ -181,6 +223,16 @@ static char *TEKT_base_url;
*/ */
static struct TALER_PaytoHashP cmd_line_h_payto; static struct TALER_PaytoHashP cmd_line_h_payto;
/**
* Provider user ID to use.
*/
static char *cmd_provider_user_id;
/**
* Provider legitimization ID to use.
*/
static char *cmd_provider_legitimization_id;
/** /**
* Row ID to use, override with '-r' * Row ID to use, override with '-r'
*/ */
@ -214,7 +266,7 @@ static struct TALER_KYCLOGIC_InitiateHandle *ih;
/** /**
* KYC logic running for @e ih. * KYC logic running for @e ih.
*/ */
static struct TALER_KYCLOGIC_Plugin *logic; static struct TALER_KYCLOGIC_Plugin *ih_logic;
/** /**
* Port to run the daemon on. * Port to run the daemon on.
@ -484,7 +536,7 @@ handler_kyc_webhook_generic (
kwh->logic); kwh->logic);
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_WEBHOOK_LOGIC_UNKNOWN, TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
"$LOGIC"); "$LOGIC");
} }
kwh->wh = kwh->plugin->webhook (kwh->plugin->cls, kwh->wh = kwh->plugin->webhook (kwh->plugin->cls,
@ -531,6 +583,13 @@ handler_kyc_webhook_generic (
} }
/**
* Handle a GET "/kyc-webhook" request.
*
* @param rc request to handle
* @param args one argument with the payment_target_uuid
* @return MHD result code
*/
static MHD_RESULT static MHD_RESULT
handler_kyc_webhook_get ( handler_kyc_webhook_get (
struct TEKT_RequestContext *rc, struct TEKT_RequestContext *rc,
@ -543,6 +602,14 @@ handler_kyc_webhook_get (
} }
/**
* Handle a POST "/kyc-webhook" request.
*
* @param rc request to handle
* @param root uploaded JSON body (can be NULL)
* @param args one argument with the payment_target_uuid
* @return MHD result code
*/
static MHD_RESULT static MHD_RESULT
handler_kyc_webhook_post ( handler_kyc_webhook_post (
struct TEKT_RequestContext *rc, struct TEKT_RequestContext *rc,
@ -556,6 +623,127 @@ handler_kyc_webhook_post (
} }
/**
* Function called with the result of a proof check operation.
*
* 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 with the `struct ProofRequestState`
* @param status KYC status
* @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 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
proof_cb (
void *cls,
enum TALER_KYCLOGIC_KycStatus status,
const char *provider_user_id,
const char *provider_legitimization_id,
struct GNUNET_TIME_Absolute expiration,
unsigned int http_status,
struct MHD_Response *response)
{
struct ProofRequestState *rs = cls;
MHD_resume_connection (rs->rc->connection);
// FIXME: kick MHD event loop!
// FIXME: actually queue response...
GNUNET_CONTAINER_DLL_remove (rs_head,
rs_tail,
rs);
GNUNET_free (rs);
}
/**
* Function called when we receive a 'GET' to the
* '/kyc-proof' endpoint.
*
* @param rc request context
* @param args remaining URL arguments;
* args[0] is the 'h_payto',
* args[1] should be the logic plugin name
*/
static MHD_RESULT
handler_kyc_proof_get (
struct TEKT_RequestContext *rc,
const char *const args[])
{
struct TALER_PaytoHashP h_payto;
struct TALER_KYCLOGIC_ProviderDetails *pd;
struct TALER_KYCLOGIC_Plugin *logic;
struct ProofRequestState *rs;
if ( (NULL == args[0]) ||
(NULL == args[1]) )
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
"'/$H_PAYTO/$LOGIC' required after '/kyc-proof'");
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
&h_payto,
sizeof (h_payto)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"h_payto");
}
if (0 !=
GNUNET_memcmp (&h_payto,
&cmd_line_h_payto))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_PROOF_REQUEST_UNKNOWN,
"h_payto");
}
if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_get_logic (args[1],
&logic,
&pd))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not initiate KYC with provider `%s' (configuration error?)\n",
initiate_section);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
args[1]);
}
rs = GNUNET_new (struct ProofRequestState);
rs->rc = rc;
rs->logic = logic;
MHD_suspend_connection (rc->connection);
GNUNET_CONTAINER_DLL_insert (rs_head,
rs_tail,
rs);
rs->ph = logic->proof (logic->cls,
pd,
&args[2],
rc->connection,
&h_payto,
cmd_provider_user_id,
cmd_provider_legitimization_id,
&proof_cb,
rs);
GNUNET_assert (NULL != rs->ph);
return MHD_YES;
}
/** /**
* Function called whenever MHD is done with a request. If the * Function called whenever MHD is done with a request. If the
* request was a POST, we may have stored a `struct Buffer *` in the * request was a POST, we may have stored a `struct Buffer *` in the
@ -757,15 +945,14 @@ handle_mhd_request (void *cls,
void **con_cls) void **con_cls)
{ {
static struct TEKT_RequestHandler handlers[] = { static struct TEKT_RequestHandler handlers[] = {
#if FIXME
/* simulated KYC endpoints */ /* simulated KYC endpoints */
{ {
.url = "kyc-proof", .url = "kyc-proof",
.method = MHD_HTTP_METHOD_GET, .method = MHD_HTTP_METHOD_GET,
.handler.get = &TEKT_handler_kyc_proof, .handler.get = &handler_kyc_proof_get,
.nargs = 1 .nargs = 128,
.nargs_is_upper_bound = true
}, },
#endif
{ {
.url = "kyc-webhook", .url = "kyc-webhook",
.method = MHD_HTTP_METHOD_POST, .method = MHD_HTTP_METHOD_POST,
@ -993,11 +1180,21 @@ static void
do_shutdown (void *cls) do_shutdown (void *cls)
{ {
struct MHD_Daemon *mhd; struct MHD_Daemon *mhd;
(void) cls; struct ProofRequestState *rs;
(void) cls;
while (NULL != (rs = rs_head))
{
GNUNET_CONTAINER_DLL_remove (rs_head,
rs_tail,
rs);
rs->logic->proof_cancel (rs->ph);
MHD_resume_connection (rs->rc->connection);
GNUNET_free (rs);
}
if (NULL != ih) if (NULL != ih)
{ {
logic->initiate_cancel (ih); ih_logic->initiate_cancel (ih);
ih = NULL; ih = NULL;
} }
kyc_webhook_cleanup (); kyc_webhook_cleanup ();
@ -1050,10 +1247,16 @@ initiate_cb (
return; return;
} }
fprintf (stdout, fprintf (stdout,
"Visit `%s' to begin KYC process (%s/%s)\n", "Visit `%s' to begin KYC process (-u: '%s', -l: '%s')\n",
redirect_url, redirect_url,
provider_user_id, provider_user_id,
provider_legitimization_id); provider_legitimization_id);
GNUNET_free (cmd_provider_user_id);
GNUNET_free (cmd_provider_legitimization_id);
if (NULL != provider_user_id)
cmd_provider_user_id = GNUNET_strdup (provider_user_id);
if (NULL != provider_legitimization_id)
cmd_provider_legitimization_id = GNUNET_strdup (provider_legitimization_id);
} }
@ -1113,7 +1316,7 @@ run (void *cls,
if (GNUNET_OK != if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_get_logic (initiate_section, TALER_KYCLOGIC_kyc_get_logic (initiate_section,
&logic, &ih_logic,
&pd)) &pd))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -1123,7 +1326,7 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
return; return;
} }
ih = logic->initiate (logic->cls, ih = ih_logic->initiate (ih_logic->cls,
pd, pd,
&cmd_line_h_payto, &cmd_line_h_payto,
kyc_row_id, kyc_row_id,
@ -1217,6 +1420,24 @@ main (int argc,
"SECTION_NAME", "SECTION_NAME",
"initiate KYC check using provider configured in SECTION_NAME of the configuration", "initiate KYC check using provider configured in SECTION_NAME of the configuration",
&initiate_section), &initiate_section),
GNUNET_GETOPT_option_string (
'i',
"initiate",
"SECTION_NAME",
"initiate KYC check using provider configured in SECTION_NAME of the configuration",
&initiate_section),
GNUNET_GETOPT_option_string (
'u',
"user",
"ID",
"use the given provider user ID (overridden if -i is also used)",
&cmd_provider_user_id),
GNUNET_GETOPT_option_string (
'l',
"legitimization",
"ID",
"use the given provider legitimization ID (overridden if -i is also used)",
&cmd_provider_legitimization_id),
GNUNET_GETOPT_option_base32_fixed_size ( GNUNET_GETOPT_option_base32_fixed_size (
'p', 'p',
"payto-hash", "payto-hash",