-fix kycaid logic issues
This commit is contained in:
parent
ba006cd61b
commit
b2a67fcff9
@ -748,6 +748,9 @@ TALER_KYCLOGIC_kyc_done (void)
|
|||||||
{
|
{
|
||||||
struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i];
|
struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i];
|
||||||
|
|
||||||
|
GNUNET_array_grow (kc->providers,
|
||||||
|
kc->num_providers,
|
||||||
|
0);
|
||||||
GNUNET_free (kc->name);
|
GNUNET_free (kc->name);
|
||||||
GNUNET_free (kc);
|
GNUNET_free (kc);
|
||||||
}
|
}
|
||||||
|
@ -720,10 +720,54 @@ kycaid_webhook_cancel (struct TALER_KYCLOGIC_WebhookHandle *wh)
|
|||||||
}
|
}
|
||||||
GNUNET_free (wh->verification_id);
|
GNUNET_free (wh->verification_id);
|
||||||
GNUNET_free (wh->applicant_id);
|
GNUNET_free (wh->applicant_id);
|
||||||
|
GNUNET_free (wh->url);
|
||||||
GNUNET_free (wh);
|
GNUNET_free (wh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract KYC failure reasons and log those
|
||||||
|
*
|
||||||
|
* @param verifications JSON object with failure details
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
log_failure (json_t *verifications)
|
||||||
|
{
|
||||||
|
json_t *member;
|
||||||
|
const char *name;
|
||||||
|
json_object_foreach (verifications, name, member)
|
||||||
|
{
|
||||||
|
bool iverified;
|
||||||
|
const char *comment;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_bool ("verified",
|
||||||
|
&iverified),
|
||||||
|
GNUNET_JSON_spec_string ("comment",
|
||||||
|
&comment),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (member,
|
||||||
|
spec,
|
||||||
|
NULL, NULL))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
json_dumpf (member,
|
||||||
|
stderr,
|
||||||
|
JSON_INDENT (2));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (iverified)
|
||||||
|
continue;
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"KYC verification of attribute `%s' failed: %s\n",
|
||||||
|
name,
|
||||||
|
comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when we're done processing the
|
* Function called when we're done processing the
|
||||||
* HTTP "/verifications/{verification_id}" request.
|
* HTTP "/verifications/{verification_id}" request.
|
||||||
@ -749,7 +793,6 @@ handle_webhook_finished (void *cls,
|
|||||||
const char *applicant_id;
|
const char *applicant_id;
|
||||||
const char *verification_id;
|
const char *verification_id;
|
||||||
const char *status;
|
const char *status;
|
||||||
const char *type;
|
|
||||||
bool verified;
|
bool verified;
|
||||||
json_t *verifications;
|
json_t *verifications;
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
@ -757,10 +800,8 @@ handle_webhook_finished (void *cls,
|
|||||||
&applicant_id),
|
&applicant_id),
|
||||||
GNUNET_JSON_spec_string ("verification_id",
|
GNUNET_JSON_spec_string ("verification_id",
|
||||||
&verification_id),
|
&verification_id),
|
||||||
GNUNET_JSON_spec_string ("type",
|
|
||||||
&type),
|
|
||||||
GNUNET_JSON_spec_string ("status",
|
GNUNET_JSON_spec_string ("status",
|
||||||
&status),
|
&status), /* completed, pending, ... */
|
||||||
GNUNET_JSON_spec_bool ("verified",
|
GNUNET_JSON_spec_bool ("verified",
|
||||||
&verified),
|
&verified),
|
||||||
GNUNET_JSON_spec_json ("verifications",
|
GNUNET_JSON_spec_json ("verifications",
|
||||||
@ -794,12 +835,10 @@ handle_webhook_finished (void *cls,
|
|||||||
resp);
|
resp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* FIXME: comment out, unless debugging ... */
|
if (! verified)
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
{
|
||||||
"The provider returned the following verifications:\n");
|
log_failure (verifications);
|
||||||
json_dumpf (verifications,
|
}
|
||||||
stderr,
|
|
||||||
JSON_INDENT (2));
|
|
||||||
resp = MHD_create_response_from_buffer (0,
|
resp = MHD_create_response_from_buffer (0,
|
||||||
"",
|
"",
|
||||||
MHD_RESPMEM_PERSISTENT);
|
MHD_RESPMEM_PERSISTENT);
|
||||||
@ -980,11 +1019,15 @@ async_webhook_reply (void *cls)
|
|||||||
{
|
{
|
||||||
struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
|
struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
|
||||||
|
|
||||||
|
fprintf (stderr,
|
||||||
|
"async reply\n");
|
||||||
wh->cb (wh->cb_cls,
|
wh->cb (wh->cb_cls,
|
||||||
0LLU, /* legitimization row ID (unknown) */
|
wh->legi_row,
|
||||||
NULL, /* our account ID */
|
(0 == wh->legi_row)
|
||||||
NULL, /* provider user ID */
|
? NULL
|
||||||
NULL, /* provider legi ID */
|
: &wh->h_payto,
|
||||||
|
wh->applicant_id, /* provider user ID */
|
||||||
|
wh->verification_id, /* provider legi ID */
|
||||||
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
|
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
|
||||||
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
|
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
|
||||||
wh->response_code,
|
wh->response_code,
|
||||||
@ -994,7 +1037,11 @@ async_webhook_reply (void *cls)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check KYC status and return result for Webhook.
|
* Check KYC status and return result for Webhook. We do NOT implement the
|
||||||
|
* authentication check proposed by the KYCAID documentation, as it would
|
||||||
|
* allow an attacker who learns the access token to easily bypass the KYC
|
||||||
|
* checks. Instead, we insist on explicitly requesting the KYC status from the
|
||||||
|
* provider (at least on success).
|
||||||
*
|
*
|
||||||
* @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
|
||||||
@ -1085,6 +1132,7 @@ kycaid_webhook (void *cls,
|
|||||||
wh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
wh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
|
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
|
||||||
wh);
|
wh);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
return wh;
|
return wh;
|
||||||
}
|
}
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
||||||
@ -1098,10 +1146,25 @@ kycaid_webhook (void *cls,
|
|||||||
wh->response_code = MHD_HTTP_NOT_FOUND;
|
wh->response_code = MHD_HTTP_NOT_FOUND;
|
||||||
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
|
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
|
||||||
wh);
|
wh);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
return wh;
|
return wh;
|
||||||
}
|
}
|
||||||
wh->verification_id = GNUNET_strdup (verification_id);
|
wh->verification_id = GNUNET_strdup (verification_id);
|
||||||
wh->applicant_id = GNUNET_strdup (applicant_id);
|
wh->applicant_id = GNUNET_strdup (applicant_id);
|
||||||
|
if (! verified)
|
||||||
|
{
|
||||||
|
/* We don't need to re-confirm the failure by
|
||||||
|
asking the API again. */
|
||||||
|
log_failure (verifications);
|
||||||
|
wh->response_code = MHD_HTTP_NO_CONTENT;
|
||||||
|
wh->resp = MHD_create_response_from_buffer (0,
|
||||||
|
"",
|
||||||
|
MHD_RESPMEM_PERSISTENT);
|
||||||
|
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
|
||||||
|
wh);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return wh;
|
||||||
|
}
|
||||||
|
|
||||||
eh = curl_easy_init ();
|
eh = curl_easy_init ();
|
||||||
if (NULL == eh)
|
if (NULL == eh)
|
||||||
@ -1113,6 +1176,7 @@ kycaid_webhook (void *cls,
|
|||||||
wh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
wh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
|
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
|
||||||
wh);
|
wh);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
return wh;
|
return wh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1122,7 +1186,7 @@ kycaid_webhook (void *cls,
|
|||||||
GNUNET_break (CURLE_OK ==
|
GNUNET_break (CURLE_OK ==
|
||||||
curl_easy_setopt (eh,
|
curl_easy_setopt (eh,
|
||||||
CURLOPT_VERBOSE,
|
CURLOPT_VERBOSE,
|
||||||
1));
|
0));
|
||||||
GNUNET_assert (CURLE_OK ==
|
GNUNET_assert (CURLE_OK ==
|
||||||
curl_easy_setopt (eh,
|
curl_easy_setopt (eh,
|
||||||
CURLOPT_MAXREDIRS,
|
CURLOPT_MAXREDIRS,
|
||||||
@ -1131,18 +1195,18 @@ kycaid_webhook (void *cls,
|
|||||||
curl_easy_setopt (eh,
|
curl_easy_setopt (eh,
|
||||||
CURLOPT_URL,
|
CURLOPT_URL,
|
||||||
wh->url));
|
wh->url));
|
||||||
wh->job = GNUNET_CURL_job_add (ps->curl_ctx,
|
wh->job = GNUNET_CURL_job_add2 (ps->curl_ctx,
|
||||||
eh,
|
eh,
|
||||||
&handle_webhook_finished,
|
pd->slist,
|
||||||
wh);
|
&handle_webhook_finished,
|
||||||
GNUNET_CURL_extend_headers (wh->job,
|
wh);
|
||||||
pd->slist);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return wh;
|
return wh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize Kycaid.0 KYC logic plugin
|
* Initialize kycaid logic plugin
|
||||||
*
|
*
|
||||||
* @param cls a configuration instance
|
* @param cls a configuration instance
|
||||||
* @return NULL on error, otherwise a `struct TALER_KYCLOGIC_Plugin`
|
* @return NULL on error, otherwise a `struct TALER_KYCLOGIC_Plugin`
|
||||||
|
@ -81,6 +81,11 @@ struct TEKT_RequestContext
|
|||||||
*/
|
*/
|
||||||
void *rh_ctx;
|
void *rh_ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploaded JSON body, if any.
|
||||||
|
*/
|
||||||
|
json_t *root;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP status to return upon resume if @e response
|
* HTTP status to return upon resume if @e response
|
||||||
* is non-NULL.
|
* is non-NULL.
|
||||||
@ -555,6 +560,8 @@ handler_kyc_webhook_generic (
|
|||||||
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
|
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
|
||||||
"$LOGIC");
|
"$LOGIC");
|
||||||
}
|
}
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"Calling KYC provider specific webhook\n");
|
||||||
kwh->wh = kwh->plugin->webhook (kwh->plugin->cls,
|
kwh->wh = kwh->plugin->webhook (kwh->plugin->cls,
|
||||||
kwh->pd,
|
kwh->pd,
|
||||||
&kyc_provider_account_lookup,
|
&kyc_provider_account_lookup,
|
||||||
@ -583,6 +590,8 @@ handler_kyc_webhook_generic (
|
|||||||
|
|
||||||
if (NULL != kwh->response)
|
if (NULL != kwh->response)
|
||||||
{
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"Returning queued reply for KWH\n");
|
||||||
/* handle _failed_ resumed cases */
|
/* handle _failed_ resumed cases */
|
||||||
return MHD_queue_response (rc->connection,
|
return MHD_queue_response (rc->connection,
|
||||||
kwh->response_code,
|
kwh->response_code,
|
||||||
@ -845,7 +854,6 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
|
|||||||
const struct TEKT_RequestHandler *rh = rc->rh;
|
const struct TEKT_RequestHandler *rh = rc->rh;
|
||||||
const char *args[rh->nargs + 2];
|
const char *args[rh->nargs + 2];
|
||||||
size_t ulen = strlen (url) + 1;
|
size_t ulen = strlen (url) + 1;
|
||||||
json_t *root = NULL;
|
|
||||||
MHD_RESULT ret;
|
MHD_RESULT ret;
|
||||||
|
|
||||||
/* We do check for "ulen" here, because we'll later stack-allocate a buffer
|
/* We do check for "ulen" here, because we'll later stack-allocate a buffer
|
||||||
@ -866,8 +874,9 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
|
|||||||
|
|
||||||
/* All POST endpoints come with a body in JSON format. So we parse
|
/* All POST endpoints come with a body in JSON format. So we parse
|
||||||
the JSON here. */
|
the JSON here. */
|
||||||
if (0 == strcasecmp (rh->method,
|
if ( (NULL == rc->root) &&
|
||||||
MHD_HTTP_METHOD_POST))
|
(0 == strcasecmp (rh->method,
|
||||||
|
MHD_HTTP_METHOD_POST)) )
|
||||||
{
|
{
|
||||||
enum GNUNET_GenericReturnValue res;
|
enum GNUNET_GenericReturnValue res;
|
||||||
|
|
||||||
@ -875,16 +884,17 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
|
|||||||
&rc->opaque_post_parsing_context,
|
&rc->opaque_post_parsing_context,
|
||||||
upload_data,
|
upload_data,
|
||||||
upload_data_size,
|
upload_data_size,
|
||||||
&root);
|
&rc->root);
|
||||||
if (GNUNET_SYSERR == res)
|
if (GNUNET_SYSERR == res)
|
||||||
{
|
{
|
||||||
GNUNET_assert (NULL == root);
|
GNUNET_assert (NULL == rc->root);
|
||||||
|
GNUNET_break (0);
|
||||||
return MHD_NO; /* bad upload, could not even generate error */
|
return MHD_NO; /* bad upload, could not even generate error */
|
||||||
}
|
}
|
||||||
if ( (GNUNET_NO == res) ||
|
if ( (GNUNET_NO == res) ||
|
||||||
(NULL == root) )
|
(NULL == rc->root) )
|
||||||
{
|
{
|
||||||
GNUNET_assert (NULL == root);
|
GNUNET_assert (NULL == rc->root);
|
||||||
return MHD_YES; /* so far incomplete upload or parser error */
|
return MHD_YES; /* so far incomplete upload or parser error */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -921,7 +931,6 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
|
|||||||
rh->url,
|
rh->url,
|
||||||
url);
|
url);
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
json_decref (root);
|
|
||||||
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_GENERIC_WRONG_NUMBER_OF_SEGMENTS,
|
TALER_EC_EXCHANGE_GENERIC_WRONG_NUMBER_OF_SEGMENTS,
|
||||||
@ -931,16 +940,15 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
|
|||||||
|
|
||||||
/* Above logic ensures that 'root' is exactly non-NULL for POST operations,
|
/* Above logic ensures that 'root' is exactly non-NULL for POST operations,
|
||||||
so we test for 'root' to decide which handler to invoke. */
|
so we test for 'root' to decide which handler to invoke. */
|
||||||
if (NULL != root)
|
if (NULL != rc->root)
|
||||||
ret = rh->handler.post (rc,
|
ret = rh->handler.post (rc,
|
||||||
root,
|
rc->root,
|
||||||
args);
|
args);
|
||||||
else /* We also only have "POST" or "GET" in the API for at this point
|
else /* We also only have "POST" or "GET" in the API for at this point
|
||||||
(OPTIONS/HEAD are taken care of earlier) */
|
(OPTIONS/HEAD are taken care of earlier) */
|
||||||
ret = rh->handler.get (rc,
|
ret = rh->handler.get (rc,
|
||||||
args);
|
args);
|
||||||
}
|
}
|
||||||
json_decref (root);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,8 +957,15 @@ static void
|
|||||||
rh_cleaner_cb (struct TEKT_RequestContext *rc)
|
rh_cleaner_cb (struct TEKT_RequestContext *rc)
|
||||||
{
|
{
|
||||||
if (NULL != rc->response)
|
if (NULL != rc->response)
|
||||||
|
{
|
||||||
MHD_destroy_response (rc->response);
|
MHD_destroy_response (rc->response);
|
||||||
GNUNET_free (rc);
|
rc->response = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != rc->root)
|
||||||
|
{
|
||||||
|
json_decref (rc->root);
|
||||||
|
rc->root = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1082,7 +1097,8 @@ handle_mhd_request (void *cls,
|
|||||||
continue;
|
continue;
|
||||||
found = true;
|
found = true;
|
||||||
/* The URL is a match! What we now do depends on the method. */
|
/* The URL is a match! What we now do depends on the method. */
|
||||||
if (0 == strcasecmp (method, MHD_HTTP_METHOD_OPTIONS))
|
if (0 == strcasecmp (method,
|
||||||
|
MHD_HTTP_METHOD_OPTIONS))
|
||||||
{
|
{
|
||||||
return TALER_MHD_reply_cors_preflight (connection);
|
return TALER_MHD_reply_cors_preflight (connection);
|
||||||
}
|
}
|
||||||
@ -1276,7 +1292,7 @@ initiate_cb (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fprintf (stdout,
|
fprintf (stdout,
|
||||||
"Visit `%s' to begin KYC process (-u: '%s', -l: '%s')\n",
|
"Visit `%s' to begin KYC process (-u: '%s', -U: '%s')\n",
|
||||||
redirect_url,
|
redirect_url,
|
||||||
provider_user_id,
|
provider_user_id,
|
||||||
provider_legitimization_id);
|
provider_legitimization_id);
|
||||||
@ -1393,6 +1409,9 @@ run (void *cls,
|
|||||||
GNUNET_SCHEDULER_shutdown ();
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"Starting daemon on port %u\n",
|
||||||
|
(unsigned int) serve_port);
|
||||||
mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
|
mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
|
||||||
| MHD_USE_PIPE_FOR_SHUTDOWN
|
| MHD_USE_PIPE_FOR_SHUTDOWN
|
||||||
| MHD_USE_DEBUG | MHD_USE_DUAL_STACK
|
| MHD_USE_DEBUG | MHD_USE_DUAL_STACK
|
||||||
|
Loading…
Reference in New Issue
Block a user