diff options
author | Christian Grothoff <christian@grothoff.org> | 2022-08-18 14:02:54 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2022-08-18 14:02:54 +0200 |
commit | 246d49b37923689c4e347f403f6bb3c9c24b45be (patch) | |
tree | 5df8c3e01395ca1fac2511d17bd1e0035dbdeb2d | |
parent | 14a240f7cc7213959ae11a020b37a6c10837bc4a (diff) | |
download | exchange-246d49b37923689c4e347f403f6bb3c9c24b45be.tar.xz |
-work on kyc-proof persona plugin
-rw-r--r-- | contrib/Makefile.am | 17 | ||||
-rw-r--r-- | contrib/bad_gateway.en.must | 12 | ||||
-rw-r--r-- | contrib/kyc_user_failed.en.must | 20 | ||||
-rw-r--r-- | contrib/persona-exchange-unauthorized.en.must (renamed from contrib/kyc_provider_unauthorized.en.must) | 0 | ||||
-rw-r--r-- | contrib/persona-exchange-unpaid.en.must (renamed from contrib/kyc_provider_unpaid.en.must) | 0 | ||||
-rw-r--r-- | contrib/persona-invalid-response.en.must (renamed from contrib/kyc_provider_unexpected_reply.en.must) | 4 | ||||
-rw-r--r-- | contrib/persona-kyc-failed.en.must (renamed from contrib/kyc_failed.en.must) | 0 | ||||
-rw-r--r-- | contrib/persona-load-failure.en.must (renamed from contrib/kyc_provider_ratelimit.en.must) | 0 | ||||
-rw-r--r-- | contrib/persona-logic-failure.en.must (renamed from contrib/kyc_interaction_failed.en.must) | 0 | ||||
-rw-r--r-- | contrib/persona-network-timeout.en.must (renamed from contrib/kyc_provider_timeout.en.must) | 0 | ||||
-rw-r--r-- | contrib/persona-provider-failure.en.must (renamed from contrib/kyc_provider_internal_error.en.must) | 0 | ||||
-rw-r--r-- | src/bank-lib/bank_api_admin.c | 7 | ||||
-rw-r--r-- | src/curl/curl.c | 28 | ||||
-rw-r--r-- | src/include/taler_curl_lib.h | 5 | ||||
-rw-r--r-- | src/kyclogic/plugin_kyclogic_persona.c | 605 | ||||
-rw-r--r-- | src/kyclogic/taler-exchange-kyc-tester.c | 3 |
16 files changed, 548 insertions, 153 deletions
diff --git a/contrib/Makefile.am b/contrib/Makefile.am index c69be57e4..aae1473b8 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am @@ -3,15 +3,14 @@ SUBDIRS = . tmplpkgdatadir = $(prefix)/share/taler/exchange/templates/ dist_tmplpkgdata_DATA = \ - bad_gateway.en.must \ - kyc_provider_unauthorized.en.must \ - kyc_provider_unexpected_reply.en.must \ - kyc_interaction_failed.en.must \ - kyc_provider_unpaid.en.must \ - kyc_provider_internal_error.en.must \ - kyc_user_failed.en.must \ - kyc_provider_ratelimit.en.must \ - kyc_provider_timeout.en.must + persona-exchange-unauthorized.en.must \ + persona-load-failure.en.must \ + persona-exchange-unpaid.en.must \ + persona-logic-failure.en.must \ + persona-invalid-response.en.must \ + persona-network-timeout.en.must \ + persona-kyc-failed.en.must \ + persona-provider-failure.en.must # %%.must: merchant-backoffice/%.html # WTF: cp $< $@ diff --git a/contrib/bad_gateway.en.must b/contrib/bad_gateway.en.must deleted file mode 100644 index f177db900..000000000 --- a/contrib/bad_gateway.en.must +++ /dev/null @@ -1,12 +0,0 @@ -<html> -<head> -<title>KYC server failure</title> -</head> -<body> -The KYC backend returned a malformed response, reproduced -below. Please inform the exchange operator about this failure. -<pre> -{{ kyc_server_reply }} -</pre> -</body> -</html>
\ No newline at end of file diff --git a/contrib/kyc_user_failed.en.must b/contrib/kyc_user_failed.en.must deleted file mode 100644 index 54a4637c4..000000000 --- a/contrib/kyc_user_failed.en.must +++ /dev/null @@ -1,20 +0,0 @@ -<html> -<head> -<title>KYC authentication failed</title> -</head> -<body> -You failed the KYC check. See below for details. -<!-- {{logic}} indicates the type of KYC provider - which generated the reply; for now, only - "kycaid" is possible. Switch on the - {{logic}} to render results in a provider-specific - way. (or introduce new templates per provider?) --> -<!-- TODO: figure out exactly what the - format of 'verifications' is here - based on KYCAID documentation and parse - that here. --> -<pre> -{{ verifications }} -</pre> -</body> -</html>
\ No newline at end of file diff --git a/contrib/kyc_provider_unauthorized.en.must b/contrib/persona-exchange-unauthorized.en.must index 9b4858178..9b4858178 100644 --- a/contrib/kyc_provider_unauthorized.en.must +++ b/contrib/persona-exchange-unauthorized.en.must diff --git a/contrib/kyc_provider_unpaid.en.must b/contrib/persona-exchange-unpaid.en.must index 65fa4f9b7..65fa4f9b7 100644 --- a/contrib/kyc_provider_unpaid.en.must +++ b/contrib/persona-exchange-unpaid.en.must diff --git a/contrib/kyc_provider_unexpected_reply.en.must b/contrib/persona-invalid-response.en.must index b3df670a4..a288ae074 100644 --- a/contrib/kyc_provider_unexpected_reply.en.must +++ b/contrib/persona-invalid-response.en.must @@ -1,9 +1,9 @@ <html> <head> -<title>KYC provider returned unexpected status code</title> +<title>KYC provider returned unexpected response</title> </head> <body> -The KYC backend returned an unexpected status code. +The KYC backend returned an unexpected response. <pre> {{ kyc_http_status }} {{ kyc_logic }} diff --git a/contrib/kyc_failed.en.must b/contrib/persona-kyc-failed.en.must index c1e27a821..c1e27a821 100644 --- a/contrib/kyc_failed.en.must +++ b/contrib/persona-kyc-failed.en.must diff --git a/contrib/kyc_provider_ratelimit.en.must b/contrib/persona-load-failure.en.must index 77917c0b3..77917c0b3 100644 --- a/contrib/kyc_provider_ratelimit.en.must +++ b/contrib/persona-load-failure.en.must diff --git a/contrib/kyc_interaction_failed.en.must b/contrib/persona-logic-failure.en.must index 504cd09c9..504cd09c9 100644 --- a/contrib/kyc_interaction_failed.en.must +++ b/contrib/persona-logic-failure.en.must diff --git a/contrib/kyc_provider_timeout.en.must b/contrib/persona-network-timeout.en.must index c1ad79b34..c1ad79b34 100644 --- a/contrib/kyc_provider_timeout.en.must +++ b/contrib/persona-network-timeout.en.must diff --git a/contrib/kyc_provider_internal_error.en.must b/contrib/persona-provider-failure.en.must index 37d1e0f3a..37d1e0f3a 100644 --- a/contrib/kyc_provider_internal_error.en.must +++ b/contrib/persona-provider-failure.en.must diff --git a/src/bank-lib/bank_api_admin.c b/src/bank-lib/bank_api_admin.c index 77b1a38e4..f0d97bda1 100644 --- a/src/bank-lib/bank_api_admin.c +++ b/src/bank-lib/bank_api_admin.c @@ -215,9 +215,10 @@ TALER_BANK_admin_add_incoming ( "Requesting administrative transaction at `%s' for reserve %s\n", aai->request_url, TALER_B2S (reserve_pub)); - aai->post_ctx.headers = curl_slist_append - (aai->post_ctx.headers, - "Content-Type: application/json"); + aai->post_ctx.headers + = curl_slist_append ( + aai->post_ctx.headers, + "Content-Type: application/json"); eh = curl_easy_init (); if ( (NULL == eh) || diff --git a/src/curl/curl.c b/src/curl/curl.c index 5009fa3cf..caa0052f7 100644 --- a/src/curl/curl.c +++ b/src/curl/curl.c @@ -46,7 +46,8 @@ TALER_curl_easy_post (struct TALER_CURL_PostContext *ctx, return GNUNET_SYSERR; } slen = strlen (str); -#if TALER_CURL_COMPRESS_BODIES + if (TALER_CURL_COMPRESS_BODIES && + (! ctx->disable_compression) ) { Bytef *cbuf; uLongf cbuf_size; @@ -68,18 +69,21 @@ TALER_curl_easy_post (struct TALER_CURL_PostContext *ctx, free (str); slen = (size_t) cbuf_size; ctx->json_enc = (char *) cbuf; + GNUNET_assert ( + NULL != + (ctx->headers = curl_slist_append ( + ctx->headers, + "Content-Encoding: deflate"))); } - GNUNET_assert (NULL != (ctx->headers = curl_slist_append ( - ctx->headers, - "Content-Encoding: deflate"))); -#else - ctx->json_enc = str; -#endif - - GNUNET_assert - (NULL != (ctx->headers = curl_slist_append ( - ctx->headers, - "Content-Type: application/json"))); + else + { + ctx->json_enc = str; + } + GNUNET_assert ( + NULL != + (ctx->headers = curl_slist_append ( + ctx->headers, + "Content-Type: application/json"))); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, diff --git a/src/include/taler_curl_lib.h b/src/include/taler_curl_lib.h index 5151f4cf6..04dc20b9e 100644 --- a/src/include/taler_curl_lib.h +++ b/src/include/taler_curl_lib.h @@ -47,6 +47,11 @@ struct TALER_CURL_PostContext * Custom headers. */ struct curl_slist *headers; + + /** + * Set to true to disable compression of the body. + */ + bool disable_compression; }; diff --git a/src/kyclogic/plugin_kyclogic_persona.c b/src/kyclogic/plugin_kyclogic_persona.c index 220aaeb12..c8040f828 100644 --- a/src/kyclogic/plugin_kyclogic_persona.c +++ b/src/kyclogic/plugin_kyclogic_persona.c @@ -23,9 +23,11 @@ #include "taler_mhd_lib.h" #include "taler_curl_lib.h" #include "taler_json_lib.h" +#include "taler_templating_lib.h" #include <regex.h> #include "taler_util.h" + /** * Which version of the persona API are we implementing? */ @@ -159,6 +161,11 @@ struct TALER_KYCLOGIC_InitiateHandle */ char *url; + /** + * Request-specific headers to use. + */ + struct curl_slist *slist; + }; @@ -315,6 +322,7 @@ persona_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd) curl_slist_free_all (pd->slist); GNUNET_free (pd->auth_token); GNUNET_free (pd->template_id); + GNUNET_free (pd->subdomain); GNUNET_free (pd->section); GNUNET_free (pd->post_kyc_redirect_url); GNUNET_free (pd); @@ -435,6 +443,8 @@ persona_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih) ih->job = NULL; } GNUNET_free (ih->url); + TALER_curl_easy_post_finished (&ih->ctx); + curl_slist_free_all (ih->slist); GNUNET_free (ih); } @@ -520,6 +530,57 @@ handle_initiate_finished (void *cls, persona_initiate_cancel (ih); return; } + case MHD_HTTP_BAD_REQUEST: + case MHD_HTTP_UNPROCESSABLE_CONTENT: + { + const char *msg; + + GNUNET_break (0); + json_dumpf (j, + stderr, + JSON_INDENT (2)); + msg = json_string_value ( + json_object_get ( + json_array_get ( + json_object_get (j, + "errors"), + 0), + "title")); + + ih->cb (ih->cb_cls, + TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG, + NULL, + NULL, + NULL, + msg); + persona_initiate_cancel (ih); + return; + } + case MHD_HTTP_TOO_MANY_REQUESTS: + { + const char *msg; + + /* FIXME: figure out how to nicely extract + the rate limit data from the reply */ + json_dumpf (j, + stderr, + JSON_INDENT (2)); + msg = json_string_value ( + json_object_get ( + json_array_get ( + json_object_get (j, + "errors"), + 0), + "title")); + ih->cb (ih->cb_cls, + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_RATE_LIMIT_EXCEEDED, + NULL, + NULL, + NULL, + msg); + persona_initiate_cancel (ih); + return; + } default: { char *err; @@ -532,7 +593,7 @@ handle_initiate_finished (void *cls, "Unexpected HTTP status %u from Persona\n", (unsigned int) response_code); ih->cb (ih->cb_cls, - TALER_EC_NONE, + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY, NULL, NULL, NULL, @@ -652,28 +713,35 @@ persona_initiate (void *cls, (unsigned long long) ih->legitimization_uuid); payto_s = GNUNET_STRINGS_data_to_string_alloc (&ih->h_payto, sizeof (ih->h_payto)); + /* NOTE: check here that exchange_base_url ends + with a '/'? */ GNUNET_asprintf (&proof_url, - "%s/kyc-proof/%s/%s", + "%skyc-proof/%s/%s", pd->ps->exchange_base_url, payto_s, pd->section); body = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("inquiry_template_id", - pd->template_id), - GNUNET_JSON_pack_string ("account_id", - payto_s), - GNUNET_JSON_pack_string ("reference_id", - ref_s), - GNUNET_JSON_pack_string ("redirect_uri", - proof_url) - ); + GNUNET_JSON_pack_object_steal ( + "data", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_object_steal ( + "attributes", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("inquiry_template_id", + pd->template_id), + GNUNET_JSON_pack_string ("reference_id", + ref_s), + GNUNET_JSON_pack_string ("redirect_uri", + proof_url) + ))))); + GNUNET_assert (NULL != body); GNUNET_free (payto_s); GNUNET_free (proof_url); } GNUNET_break (CURLE_OK == curl_easy_setopt (eh, CURLOPT_VERBOSE, - 1)); + 0)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_MAXREDIRS, @@ -682,6 +750,7 @@ persona_initiate (void *cls, curl_easy_setopt (eh, CURLOPT_URL, ih->url)); + ih->ctx.disable_compression = true; if (GNUNET_OK != TALER_curl_easy_post (&ih->ctx, eh, @@ -694,6 +763,7 @@ persona_initiate (void *cls, json_decref (body); return NULL; } + json_decref (body); ih->job = GNUNET_CURL_job_add2 (ps->curl_ctx, eh, ih->ctx.headers, @@ -701,6 +771,23 @@ persona_initiate (void *cls, ih); GNUNET_CURL_extend_headers (ih->job, pd->slist); + /* FIXME: this should be used, but IF we use it, + the testing should be moved to random/noncy legi rows; + or better: add some additional noncy thing here from + the config that we randomize if not given! */ + if (0) + { + char *ikh; + + GNUNET_asprintf (&ikh, + "Idempotency-Key: %llu", + (unsigned long long) ih->legitimization_uuid); + ih->slist = curl_slist_append (NULL, + ikh); + GNUNET_free (ikh); + } + GNUNET_CURL_extend_headers (ih->job, + ih->slist); return ih; } @@ -726,6 +813,79 @@ persona_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) /** + * Call @a ph callback with the operation result. + * + * @param ph proof handle to generate reply for + * @param status status to return + * @param account_id account to return + * @param inquiry_id inquiry ID to supply + * @param http_status HTTP status to use + * @param template template to instantiate + * @param[in] body body for the template to use (reference + * is consumed) + */ +static void +proof_generic_reply (struct TALER_KYCLOGIC_ProofHandle *ph, + enum TALER_KYCLOGIC_KycStatus status, + const char *account_id, + const char *inquiry_id, + unsigned int http_status, + const char *template, + json_t *body) +{ + struct MHD_Response *resp; + enum GNUNET_GenericReturnValue ret; + + ret = TALER_TEMPLATING_build (ph->connection, + &http_status, + template, + NULL, + NULL, + body, + &resp); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + resp = NULL; /* good luck */ + } + ph->cb (ph->cb_cls, + status, + account_id, + inquiry_id, + GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */ + http_status, + resp); +} + + +/** + * Call @a ph callback with HTTP error response. + * + * @param ph proof handle to generate reply for + * @param inquiry_id inquiry ID to supply + * @param http_status HTTP status to use + * @param template template to instantiate + * @param[in] body body for the template to use (reference + * is consumed) + */ +static void +proof_reply_error (struct TALER_KYCLOGIC_ProofHandle *ph, + const char *inquiry_id, + unsigned int http_status, + const char *template, + json_t *body) +{ + proof_generic_reply (ph, + TALER_KYCLOGIC_STATUS_PROVIDER_FAILED, + NULL, /* user id */ + inquiry_id, + http_status, + template, + body); +} + + +/** * Function called when we're done processing the * HTTP "/api/v1/verifications/{verification-id}" request. * @@ -740,142 +900,396 @@ handle_proof_finished (void *cls, { struct TALER_KYCLOGIC_ProofHandle *ph = cls; const json_t *j = response; + const json_t *data = json_object_get (j, + "data"); ph->job = NULL; - json_dumpf (j, - stderr, - JSON_INDENT (2)); -#if 0 switch (response_code) { case MHD_HTTP_OK: { - const char *verification_id; - const char *form_url; + const char *inquiry_id; + const char *account_id; + const char *type = NULL; + json_t *attributes; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("verification_id", - &verification_id), - GNUNET_JSON_spec_string ("form_url", - &form_url), + GNUNET_JSON_spec_string ("type", + &type), + GNUNET_JSON_spec_string ("id", + &inquiry_id), + GNUNET_JSON_spec_json ("attributes", + &attributes), GNUNET_JSON_spec_end () }; - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, NULL)) + if ( (NULL == data) || + (GNUNET_OK != + GNUNET_JSON_parse (data, + spec, + NULL, NULL)) || + (0 != strcmp (type, + "inquiry")) ) { GNUNET_break_op (0); json_dumpf (j, stderr, JSON_INDENT (2)); - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); + proof_reply_error (ph, + inquiry_id, + MHD_HTTP_BAD_GATEWAY, + "persona-logic-failure", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + GNUNET_JSON_pack_string ("persona_inquiry_id", + inquiry_id), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY), + GNUNET_JSON_pack_string ("detail", + "data"), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) data)))); break; } - ph->cb (ph->cb_cls, - TALER_EC_NONE, - form_url, - NULL, /* no provider_user_id */ - verification_id, - NULL /* no error */); + + { + const char *status; /* "completed", what else? */ + const char *reference_id; /* or legitimization number */ + const char *expired_at = NULL; /* often 'null' format: "2022-08-18T10:14:26.000Z" */ + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_string ("reference_id", + &reference_id), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("expired_at", + &expired_at), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (attributes, + ispec, + NULL, NULL)) + { + GNUNET_break_op (0); + json_dumpf (j, + stderr, + JSON_INDENT (2)); + proof_reply_error (ph, + inquiry_id, + MHD_HTTP_BAD_GATEWAY, + "persona-invalid-response", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + GNUNET_JSON_pack_string ("persona_inquiry_id", + inquiry_id), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY), + GNUNET_JSON_pack_string ("detail", + "data-attributes"), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) data)))); + GNUNET_JSON_parse_free (ispec); + GNUNET_JSON_parse_free (spec); + break; + } + { + unsigned long long idr; + char dummy; + + if ( (1 != sscanf (reference_id, + "%llu%c", + &idr, + &dummy)) || + (idr != ph->legitimization_uuid) ) + { + GNUNET_break_op (0); + proof_reply_error (ph, + inquiry_id, + MHD_HTTP_BAD_GATEWAY, + "persona-invalid-response", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + GNUNET_JSON_pack_string ("persona_inquiry_id", + inquiry_id), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY), + GNUNET_JSON_pack_string ("detail", + "data-attributes-reference_id"), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); + GNUNET_JSON_parse_free (ispec); + GNUNET_JSON_parse_free (spec); + break; + } + } + + if (0 != strcmp (inquiry_id, + ph->provider_legitimization_id)) + { + GNUNET_break_op (0); + proof_reply_error (ph, + inquiry_id, + MHD_HTTP_BAD_GATEWAY, + "persona-invalid-response", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + GNUNET_JSON_pack_string ("persona_inquiry_id", + inquiry_id), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY), + GNUNET_JSON_pack_string ("detail", + "data-id"), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); + GNUNET_JSON_parse_free (ispec); + GNUNET_JSON_parse_free (spec); + break; + } + + account_id = json_string_value ( + json_object_get ( + json_object_get ( + json_object_get ( + json_object_get ( + data, + "relationships"), + "account"), + "data"), + "id")); + + if (0 != strcmp (status, + "completed")) + { + proof_generic_reply (ph, + TALER_KYCLOGIC_STATUS_FAILED, + account_id, + inquiry_id, + MHD_HTTP_OK, + "persona-kyc-failed", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + GNUNET_JSON_pack_string ("persona_inquiry_id", + inquiry_id), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); + GNUNET_JSON_parse_free (ispec); + GNUNET_JSON_parse_free (spec); + break; + } + + if (NULL == account_id) + { + GNUNET_break_op (0); + json_dumpf (data, + stderr, + JSON_INDENT (2)); + proof_reply_error (ph, + inquiry_id, + MHD_HTTP_BAD_GATEWAY, + "persona-invalid-response", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + GNUNET_JSON_pack_string ("persona_inquiry_id", + inquiry_id), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY), + GNUNET_JSON_pack_string ("detail", + "data-relationships-account-data-id"), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); + break; + } + + proof_generic_reply (ph, + TALER_KYCLOGIC_STATUS_SUCCESS, + account_id, + inquiry_id, + MHD_HTTP_OK, + "kyc-completed", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("attributes", + (json_t *) + data)))); + GNUNET_JSON_parse_free (ispec); + } GNUNET_JSON_parse_free (spec); + break; } - break; case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_NOT_FOUND: case MHD_HTTP_CONFLICT: + case MHD_HTTP_UNPROCESSABLE_ENTITY: + /* These are errors with this code */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "PERSONA failed with response %u:\n", (unsigned int) response_code); json_dumpf (j, stderr, JSON_INDENT (2)); - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); + proof_reply_error (ph, + ph->provider_legitimization_id, + MHD_HTTP_BAD_GATEWAY, + "persona-logic-failure", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY), + + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); break; case MHD_HTTP_UNAUTHORIZED: + /* These are failures of the exchange operator */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Refused access with HTTP status code %u\n", + (unsigned int) response_code); + proof_reply_error (ph, + ph->provider_legitimization_id, + MHD_HTTP_INTERNAL_SERVER_ERROR, + "persona-exchange-unauthorized", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_ACCESS_REFUSED), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); + break; case MHD_HTTP_PAYMENT_REQUIRED: + /* These are failures of the exchange operator */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Refused access with HTTP status code %u\n", (unsigned int) response_code); - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_ACCESS_REFUSED, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); + + proof_reply_error (ph, + ph->provider_legitimization_id, + MHD_HTTP_INTERNAL_SERVER_ERROR, + "persona-exchange-unpaid", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_ACCESS_REFUSED), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); break; case MHD_HTTP_REQUEST_TIMEOUT: - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_TIMEOUT, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); - break; - case MHD_HTTP_UNPROCESSABLE_ENTITY: /* validation */ + /* These are networking issues */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "PERSONA failed with response %u:\n", (unsigned int) response_code); json_dumpf (j, stderr, JSON_INDENT (2)); - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); + proof_reply_error (ph, + ph->provider_legitimization_id, + MHD_HTTP_GATEWAY_TIMEOUT, + "persona-network-timeout", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_TIMEOUT), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); break; case MHD_HTTP_TOO_MANY_REQUESTS: - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_RATE_LIMIT_EXCEEDED, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); + /* This is a load issue */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "PERSONA failed with response %u:\n", + (unsigned int) response_code); + json_dumpf (j, + stderr, + JSON_INDENT (2)); + proof_reply_error (ph, + ph->provider_legitimization_id, + MHD_HTTP_SERVICE_UNAVAILABLE, + "persona-load-failure", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_RATE_LIMIT_EXCEEDED), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); break; case MHD_HTTP_INTERNAL_SERVER_ERROR: - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); + /* This is an issue with Persona */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "PERSONA failed with response %u:\n", + (unsigned int) response_code); + json_dumpf (j, + stderr, + JSON_INDENT (2)); + proof_reply_error (ph, + ph->provider_legitimization_id, + MHD_HTTP_BAD_GATEWAY, + "persona-provider-failure", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_ERROR), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); break; default: + /* This is an issue with Persona */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected PERSONA response %u:\n", + "PERSONA failed with response %u:\n", (unsigned int) response_code); json_dumpf (j, stderr, JSON_INDENT (2)); - ph->cb (ph->cb_cls, - TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY, - NULL, - NULL, - NULL, - json_string_value (json_object_get (j, - "type"))); + proof_reply_error (ph, + ph->provider_legitimization_id, + MHD_HTTP_BAD_GATEWAY, + "persona-invalid-response", + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("persona_http_status", + response_code), + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY), + GNUNET_JSON_pack_string ("detail", + "data-relationships-account-data-id"), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("data", + (json_t *) + data)))); break; } -#endif persona_proof_cancel (ph); } @@ -925,8 +1339,10 @@ persona_proof (void *cls, ph->connection = connection; ph->legitimization_uuid = legi_row; ph->h_payto = *account_id; + /* NOTE: we do not expect this to be non-NULL */ if (NULL != provider_user_id) ph->provider_user_id = GNUNET_strdup (provider_user_id); + /* This should be the inquiry ID; FIXME: rename variable? */ if (NULL != provider_legitimization_id) ph->provider_legitimization_id = GNUNET_strdup (provider_legitimization_id); GNUNET_asprintf (&ph->url, @@ -935,7 +1351,7 @@ persona_proof (void *cls, GNUNET_break (CURLE_OK == curl_easy_setopt (eh, CURLOPT_VERBOSE, - 1)); + 0)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_MAXREDIRS, @@ -1286,6 +1702,7 @@ persona_webhook (void *cls, enum GNUNET_DB_QueryStatus qs; const char *persona_inquiry_id; + // FIXME: check webhook 'Authorization' header first! wh = GNUNET_new (struct TALER_KYCLOGIC_WebhookHandle); wh->cb = cb; wh->cb_cls = cb_cls; diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c index 40aadba1a..b13be4bee 100644 --- a/src/kyclogic/taler-exchange-kyc-tester.c +++ b/src/kyclogic/taler-exchange-kyc-tester.c @@ -1330,7 +1330,8 @@ run (void *cls, if (GNUNET_OK != TALER_TEMPLATING_init ("exchange")) { - GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not load templates. Installation broken.\n"); return; } if (print_h_payto) |