work on kycaid plugin response generation logic

This commit is contained in:
Christian Grothoff 2022-08-16 21:04:51 +02:00
parent af97071ad6
commit c62792638b
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
19 changed files with 499 additions and 183 deletions

View File

@ -3,7 +3,15 @@ SUBDIRS = .
tmplpkgdatadir = $(prefix)/share/taler/exchange/templates/ tmplpkgdatadir = $(prefix)/share/taler/exchange/templates/
dist_tmplpkgdata_DATA = \ dist_tmplpkgdata_DATA = \
test.en.must 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
# %%.must: merchant-backoffice/%.html # %%.must: merchant-backoffice/%.html
# WTF: cp $< $@ # WTF: cp $< $@

View File

@ -0,0 +1,12 @@
<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>

View File

@ -0,0 +1,20 @@
<html>
<head>
<title>KYC authentication failed</title>
</head>
<body>
You failed the KYC check. See below for details.
<!-- {{kyc_logic}} indicates the type of KYC provider
which generated the reply; for now, only
"kycaid" is possible. Switch on the
{{kyc_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>

View File

@ -0,0 +1,13 @@
<html>
<head>
<title>KYC server interaction failed</title>
</head>
<body>
The KYC backend returned a response indicating a problem with the exchange logic. Please inform the exchange operator about this failure.
<pre>
{{ kyc_http_status }}
{{ kyc_logic }}
{{ kyc_server_reply }}
</pre>
</body>
</html>

View File

@ -0,0 +1,13 @@
<html>
<head>
<title>KYC provider had an internal error</title>
</head>
<body>
The KYC backend had an internal error.
<pre>
{{ kyc_http_status }}
{{ kyc_logic }}
{{ kyc_server_reply }}
</pre>
</body>
</html>

View File

@ -0,0 +1,13 @@
<html>
<head>
<title>KYC provider rate limit reached</title>
</head>
<body>
The KYC backend interaction ran into a rate limit.
<pre>
{{ kyc_http_status }}
{{ kyc_logic }}
{{ kyc_server_reply }}
</pre>
</body>
</html>

View File

@ -0,0 +1,13 @@
<html>
<head>
<title>KYC provider timeout</title>
</head>
<body>
The KYC backend interaction ran into a timeout.
<pre>
{{ kyc_http_status }}
{{ kyc_logic }}
{{ kyc_server_reply }}
</pre>
</body>
</html>

View File

@ -0,0 +1,13 @@
<html>
<head>
<title>KYC server refused access</title>
</head>
<body>
The KYC backend refused the authorization code used by the exchange operator. Please inform the exchange operator about this failure.
<pre>
{{ kyc_http_status }}
{{ kyc_logic }}
{{ kyc_server_reply }}
</pre>
</body>
</html>

View File

@ -0,0 +1,13 @@
<html>
<head>
<title>KYC provider returned unexpected status code</title>
</head>
<body>
The KYC backend returned an unexpected status code.
<pre>
{{ kyc_http_status }}
{{ kyc_logic }}
{{ kyc_server_reply }}
</pre>
</body>
</html>

View File

@ -0,0 +1,13 @@
<html>
<head>
<title>KYC credit exhausted</title>
</head>
<body>
The KYC backend refused the process as the exchange operator's credit balance at the KYC provider is insufficient. Please inform the exchange operator about this failure.
<pre>
{{ kyc_http_status }}
{{ kyc_logic }}
{{ kyc_server_reply }}
</pre>
</body>
</html>

View File

@ -0,0 +1,20 @@
<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>

View File

View File

@ -24,6 +24,34 @@
#include <microhttpd.h> #include <microhttpd.h>
/**
* Load a @a template and substitute using @a root, returning the result in a
* @a reply encoded suitable for the @a connection with the given @a
* http_status code. On errors, the @a http_status code
* is updated to reflect the type of error encoded in the
* @a reply.
*
* @param connection the connection we act upon
* @param[in,out] http_status code to use on success,
* set to alternative code on failure
* @param template basename of the template to load
* @param instance_id instance ID, used to compute static files URL
* @param taler_uri value for "Taler:" header to set, or NULL
* @param root JSON object to pass as the root context
* @param[out] reply where to write the response object
* @return #GNUNET_OK on success (reply queued), #GNUNET_NO if an error was queued,
* #GNUNET_SYSERR on failure (to queue an error)
*/
enum GNUNET_GenericReturnValue
TALER_TEMPLATING_build (struct MHD_Connection *connection,
unsigned int *http_status,
const char *template,
const char *instance_id,
const char *taler_uri,
json_t *root,
struct MHD_Response **reply);
/** /**
* Load a @a template and substitute using @a root, returning * Load a @a template and substitute using @a root, returning
* the result to the @a connection with the given * the result to the @a connection with the given

View File

@ -39,6 +39,7 @@ taler_exchange_kyc_tester_LDADD = \
libtalerkyclogic.la \ libtalerkyclogic.la \
$(top_builddir)/src/mhd/libtalermhd.la \ $(top_builddir)/src/mhd/libtalermhd.la \
$(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/templating/libtalertemplating.la \
$(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/util/libtalerutil.la \
-lmicrohttpd \ -lmicrohttpd \
-lgnunetcurl \ -lgnunetcurl \
@ -83,6 +84,7 @@ libtaler_plugin_kyclogic_kycaid_la_LDFLAGS = \
$(TALER_PLUGIN_LDFLAGS) \ $(TALER_PLUGIN_LDFLAGS) \
$(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/curl/libtalercurl.la \ $(top_builddir)/src/curl/libtalercurl.la \
$(top_builddir)/src/templating/libtalertemplating.la \
$(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/util/libtalerutil.la \
-lgnunetutil \ -lgnunetutil \
-ljansson \ -ljansson \

View File

@ -20,9 +20,10 @@
*/ */
#include "platform.h" #include "platform.h"
#include "taler_kyclogic_plugin.h" #include "taler_kyclogic_plugin.h"
#include <taler/taler_mhd_lib.h> #include "taler_mhd_lib.h"
#include <taler/taler_curl_lib.h> #include "taler_curl_lib.h"
#include <taler/taler_json_lib.h> #include "taler_json_lib.h"
#include "taler_templating_lib.h"
#include <regex.h> #include <regex.h>
#include "taler_util.h" #include "taler_util.h"
@ -640,6 +641,43 @@ kycaid_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph)
} }
/**
* Call @a ph callback with HTTP response generated
* from @a template_name using the given @a template_data.
*
* @param http_status http response status to use
* @param template_name template to load and return
* @param[in] template_data data for the template, freed by this function!
*/
static void
proof_reply_with_template (struct TALER_KYCLOGIC_ProofHandle *ph,
unsigned int http_status,
const char *template_name,
json_t *template_data)
{
enum GNUNET_GenericReturnValue ret;
struct MHD_Response *resp;
ret = TALER_TEMPLATING_build (ph->connection,
&http_status,
template_name,
NULL, /* no instance */
NULL, /* no Taler URI */
template_data,
&resp);
json_decref (template_data);
if (GNUNET_SYSERR == ret)
http_status = 0;
ph->cb (ph->cb_cls,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
NULL, /* user id */
NULL, /* provider legi ID */
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
http_status,
resp);
}
/** /**
* 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.
@ -684,18 +722,19 @@ handle_proof_finished (void *cls,
spec, spec,
NULL, NULL)) NULL, NULL))
{ {
json_t *template_data;
GNUNET_break_op (0); GNUNET_break_op (0);
json_dumpf (j, json_dumpf (j,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
resp = NULL; // FIXME: generate response! template_data = GNUNET_JSON_PACK (
ph->cb (ph->cb_cls, GNUNET_JSON_pack_object_incref ("kyc_server_reply",
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED, (json_t *) j));
NULL, /* user id */ proof_reply_with_template (ph,
NULL, /* provider legi ID */
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
MHD_HTTP_BAD_GATEWAY, MHD_HTTP_BAD_GATEWAY,
resp); "bad_gateway",
template_data);
break; break;
} }
/* FIXME: comment out, unless debugging ... */ /* FIXME: comment out, unless debugging ... */
@ -706,26 +745,35 @@ handle_proof_finished (void *cls,
JSON_INDENT (2)); JSON_INDENT (2));
if (verified) if (verified)
{ {
resp = NULL; // FIXME: generate response! // FIXME: or should we return an empty body? Redirect?
resp = TALER_MHD_make_json_steal (json_object ());
// FIXME: setup redirect?
expiration = GNUNET_TIME_relative_to_absolute (ph->pd->validity); expiration = GNUNET_TIME_relative_to_absolute (ph->pd->validity);
ph->cb (ph->cb_cls, ph->cb (ph->cb_cls,
TALER_KYCLOGIC_STATUS_SUCCESS, TALER_KYCLOGIC_STATUS_SUCCESS,
applicant_id, applicant_id,
verification_id, verification_id,
expiration, expiration,
MHD_HTTP_OK, MHD_HTTP_OK, // OK, or redirect???
resp); resp);
} }
else else
{ {
resp = NULL; // FIXME: generate response! json_t *template_data;
ph->cb (ph->cb_cls,
TALER_KYCLOGIC_STATUS_USER_ABORTED, GNUNET_break_op (0);
applicant_id, json_dumpf (j,
verification_id, stderr,
GNUNET_TIME_UNIT_ZERO_ABS, JSON_INDENT (2));
template_data = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("kyc_logic",
"kycaid"),
GNUNET_JSON_pack_object_incref ("verifiations",
(json_t *) verifications));
proof_reply_with_template (ph,
MHD_HTTP_OK, MHD_HTTP_OK,
resp); "kyc_user_failed",
template_data);
} }
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
} }
@ -733,98 +781,132 @@ handle_proof_finished (void *cls,
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"KYCAID failed with response %u:\n",
(unsigned int) response_code);
json_dumpf (j,
stderr,
JSON_INDENT (2));
resp = NULL; // FIXME: generate response!
ph->cb (ph->cb_cls,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
NULL, /* user id */
NULL, /* provider legi ID */
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
MHD_HTTP_INTERNAL_SERVER_ERROR,
resp);
break;
case MHD_HTTP_UNAUTHORIZED:
case MHD_HTTP_PAYMENT_REQUIRED:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Refused access with HTTP status code %u\n",
(unsigned int) response_code);
resp = NULL; // FIXME: generate response!
ph->cb (ph->cb_cls,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
NULL, /* user id */
NULL, /* provider legi ID */
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
MHD_HTTP_NETWORK_AUTHENTICATION_REQUIRED,
resp);
break;
case MHD_HTTP_REQUEST_TIMEOUT:
resp = NULL; // FIXME: generate response!
ph->cb (ph->cb_cls,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
NULL, /* user id */
NULL, /* provider legi ID */
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
MHD_HTTP_GATEWAY_TIMEOUT,
resp);
break;
case MHD_HTTP_UNPROCESSABLE_ENTITY: /* validation */ case MHD_HTTP_UNPROCESSABLE_ENTITY: /* validation */
{
json_t *template_data;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"KYCAID failed with response %u:\n", "KYCAID failed with response %u:\n",
(unsigned int) response_code); (unsigned int) response_code);
json_dumpf (j, json_dumpf (j,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
resp = NULL; // FIXME: generate response! template_data = GNUNET_JSON_PACK (
ph->cb (ph->cb_cls, GNUNET_JSON_pack_uint64 ("kyc_http_status",
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED, response_code),
NULL, /* user id */ GNUNET_JSON_pack_string ("kyc_logic",
NULL, /* provider legi ID */ "kycaid"),
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */ GNUNET_JSON_pack_object_incref ("kyc_server_reply",
MHD_HTTP_BAD_GATEWAY, (json_t *) j));
resp); proof_reply_with_template (ph,
MHD_HTTP_INTERNAL_SERVER_ERROR,
"kyc_interaction_failed",
template_data);
break; break;
}
case MHD_HTTP_UNAUTHORIZED:
{
json_t *template_data;
template_data = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kyc_http_status",
response_code),
GNUNET_JSON_pack_string ("kyc_logic",
"kycaid"),
GNUNET_JSON_pack_object_incref ("kyc_server_reply",
(json_t *) j));
proof_reply_with_template (ph,
MHD_HTTP_INTERNAL_SERVER_ERROR,
"kyc_provider_unauthorized",
template_data);
break;
}
case MHD_HTTP_PAYMENT_REQUIRED:
{
json_t *template_data;
template_data = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kyc_http_status",
response_code),
GNUNET_JSON_pack_string ("kyc_logic",
"kycaid"),
GNUNET_JSON_pack_object_incref ("kyc_server_reply",
(json_t *) j));
proof_reply_with_template (ph,
MHD_HTTP_INTERNAL_SERVER_ERROR,
"kyc_provider_unpaid",
template_data);
break;
}
case MHD_HTTP_REQUEST_TIMEOUT:
{
json_t *template_data;
template_data = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kyc_http_status",
response_code),
GNUNET_JSON_pack_string ("kyc_logic",
"kycaid"),
GNUNET_JSON_pack_object_incref ("kyc_server_reply",
(json_t *) j));
proof_reply_with_template (ph,
MHD_HTTP_INTERNAL_SERVER_ERROR,
"kyc_provider_timeout",
template_data);
break;
}
case MHD_HTTP_TOO_MANY_REQUESTS: case MHD_HTTP_TOO_MANY_REQUESTS:
resp = NULL; // FIXME: generate response! {
ph->cb (ph->cb_cls, json_t *template_data;
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
NULL, /* user id */ template_data = GNUNET_JSON_PACK (
NULL, /* provider legi ID */ GNUNET_JSON_pack_uint64 ("kyc_http_status",
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */ response_code),
MHD_HTTP_SERVICE_UNAVAILABLE, GNUNET_JSON_pack_string ("kyc_logic",
resp); "kycaid"),
GNUNET_JSON_pack_object_incref ("kyc_server_reply",
(json_t *) j));
proof_reply_with_template (ph,
MHD_HTTP_INTERNAL_SERVER_ERROR,
"kyc_provider_ratelimit",
template_data);
break; break;
}
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
resp = NULL; // FIXME: generate response! {
ph->cb (ph->cb_cls, json_t *template_data;
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
NULL, /* user id */ template_data = GNUNET_JSON_PACK (
NULL, /* provider legi ID */ GNUNET_JSON_pack_uint64 ("kyc_http_status",
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */ response_code),
MHD_HTTP_BAD_GATEWAY, GNUNET_JSON_pack_string ("kyc_logic",
resp); "kycaid"),
GNUNET_JSON_pack_object_incref ("kyc_server_reply",
(json_t *) j));
proof_reply_with_template (ph,
MHD_HTTP_INTERNAL_SERVER_ERROR,
"kyc_provider_internal_error",
template_data);
break; break;
}
default: default:
resp = NULL; // FIXME: generate response! {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, json_t *template_data;
"Unexpected KYCAID response %u:\n",
(unsigned int) response_code); template_data = GNUNET_JSON_PACK (
json_dumpf (j, GNUNET_JSON_pack_uint64 ("kyc_http_status",
stderr, response_code),
JSON_INDENT (2)); GNUNET_JSON_pack_string ("kyc_logic",
ph->cb (ph->cb_cls, "kycaid"),
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED, GNUNET_JSON_pack_object_incref ("kyc_server_reply",
NULL, /* user id */ (json_t *) j));
NULL, /* provider legi ID */ proof_reply_with_template (ph,
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */ MHD_HTTP_INTERNAL_SERVER_ERROR,
MHD_HTTP_BAD_GATEWAY, "kyc_provider_unexpected_reply",
resp); template_data);
break; break;
} }
}
kycaid_proof_cancel (ph); kycaid_proof_cancel (ph);
} }
@ -970,7 +1052,11 @@ handle_webhook_finished (void *cls,
json_dumpf (j, json_dumpf (j,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code),
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -990,7 +1076,7 @@ handle_webhook_finished (void *cls,
JSON_INDENT (2)); JSON_INDENT (2));
if (verified) if (verified)
{ {
resp = NULL; // FIXME: generate response! resp = TALER_MHD_make_json_steal (json_object ());
expiration = GNUNET_TIME_relative_to_absolute (wh->pd->validity); expiration = GNUNET_TIME_relative_to_absolute (wh->pd->validity);
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
@ -1004,7 +1090,7 @@ handle_webhook_finished (void *cls,
} }
else else
{ {
resp = NULL; // FIXME: generate response! resp = TALER_MHD_make_json_steal (json_object ());
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -1027,7 +1113,9 @@ handle_webhook_finished (void *cls,
json_dumpf (j, json_dumpf (j,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code));
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -1043,7 +1131,11 @@ handle_webhook_finished (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Refused access with HTTP status code %u\n", "Refused access with HTTP status code %u\n",
(unsigned int) response_code); (unsigned int) response_code);
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code),
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -1055,7 +1147,11 @@ handle_webhook_finished (void *cls,
resp); resp);
break; break;
case MHD_HTTP_REQUEST_TIMEOUT: case MHD_HTTP_REQUEST_TIMEOUT:
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code),
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -1073,7 +1169,11 @@ handle_webhook_finished (void *cls,
json_dumpf (j, json_dumpf (j,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code),
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -1085,7 +1185,11 @@ handle_webhook_finished (void *cls,
resp); resp);
break; break;
case MHD_HTTP_TOO_MANY_REQUESTS: case MHD_HTTP_TOO_MANY_REQUESTS:
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code),
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -1097,7 +1201,11 @@ handle_webhook_finished (void *cls,
resp); resp);
break; break;
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code),
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
wh->legi_row, wh->legi_row,
&wh->h_payto, &wh->h_payto,
@ -1109,7 +1217,11 @@ handle_webhook_finished (void *cls,
resp); resp);
break; break;
default: default:
resp = NULL; // FIXME: generate response! resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code),
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected KYCAID response %u:\n", "Unexpected KYCAID response %u:\n",
(unsigned int) response_code); (unsigned int) response_code);
@ -1226,7 +1338,9 @@ kycaid_webhook (void *cls,
json_dumpf (body, json_dumpf (body,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
wh->resp = NULL; // FIXME: generate response! wh->resp = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_object_incref ("webhook_body",
(json_t *) body));
wh->response_code = MHD_HTTP_BAD_REQUEST; wh->response_code = MHD_HTTP_BAD_REQUEST;
wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply, wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
wh); wh);
@ -1239,7 +1353,8 @@ kycaid_webhook (void *cls,
&wh->legi_row); &wh->legi_row);
if (qs < 0) if (qs < 0)
{ {
wh->resp = NULL; // FIXME: generate response! wh->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
"provider-legitimization-lookup");
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);
@ -1250,7 +1365,9 @@ kycaid_webhook (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Received webhook for unknown verification ID `%s'\n", "Received webhook for unknown verification ID `%s'\n",
verification_id); verification_id);
wh->resp = NULL; // FIXME: generate response! wh->resp = TALER_MHD_make_error (
TALER_EC_EXCHANGE_KYC_PROOF_REQUEST_UNKNOWN,
verification_id);
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);
@ -1263,8 +1380,10 @@ kycaid_webhook (void *cls,
if (NULL == eh) if (NULL == eh)
{ {
GNUNET_break (0); GNUNET_break (0);
wh->resp = NULL; // FIXME: generate response! wh->resp = TALER_MHD_make_error (
wh->response_code = MHD_HTTP_BAD_REQUEST; TALER_EC_GENERIC_ALLOCATION_FAILURE,
verification_id);
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);
return wh; return wh;

View File

@ -20,8 +20,8 @@
*/ */
#include "platform.h" #include "platform.h"
#include "taler_kyclogic_plugin.h" #include "taler_kyclogic_plugin.h"
#include <taler/taler_mhd_lib.h> #include "taler_mhd_lib.h"
#include <taler/taler_json_lib.h> #include "taler_json_lib.h"
#include <regex.h> #include <regex.h>
#include "taler_util.h" #include "taler_util.h"

View File

@ -20,8 +20,8 @@
*/ */
#include "platform.h" #include "platform.h"
#include "taler_kyclogic_plugin.h" #include "taler_kyclogic_plugin.h"
#include <taler/taler_mhd_lib.h> #include "taler_mhd_lib.h"
#include <taler/taler_json_lib.h> #include "taler_json_lib.h"
#include <regex.h> #include <regex.h>
#include "taler_util.h" #include "taler_util.h"

View File

@ -27,6 +27,7 @@
#include <limits.h> #include <limits.h>
#include "taler_mhd_lib.h" #include "taler_mhd_lib.h"
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_templating_lib.h"
#include "taler_crypto_lib.h" #include "taler_crypto_lib.h"
#include "taler_kyclogic_lib.h" #include "taler_kyclogic_lib.h"
#include "taler_kyclogic_plugin.h" #include "taler_kyclogic_plugin.h"
@ -1239,6 +1240,7 @@ do_shutdown (void *cls)
GNUNET_CURL_gnunet_rc_destroy (exchange_curl_rc); GNUNET_CURL_gnunet_rc_destroy (exchange_curl_rc);
exchange_curl_rc = NULL; exchange_curl_rc = NULL;
} }
TALER_TEMPLATING_done ();
} }
@ -1309,6 +1311,12 @@ run (void *cls,
(void) cls; (void) cls;
(void) args; (void) args;
(void ) cfgfile; (void ) cfgfile;
if (GNUNET_OK !=
TALER_TEMPLATING_init ("exchange"))
{
GNUNET_break (0);
return;
}
if (print_h_payto) if (print_h_payto)
{ {
char *s; char *s;
@ -1322,6 +1330,8 @@ run (void *cls,
} }
TALER_MHD_setup (TALER_MHD_GO_NONE); TALER_MHD_setup (TALER_MHD_GO_NONE);
TEKT_cfg = config; TEKT_cfg = config;
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_init (config)) TALER_KYCLOGIC_kyc_init (config))
{ {
@ -1329,8 +1339,6 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
return; return;
} }
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
if (GNUNET_OK != if (GNUNET_OK !=
exchange_serve_process_config ()) exchange_serve_process_config ())
{ {

View File

@ -171,29 +171,15 @@ make_static_url (struct MHD_Connection *con,
} }
/**
* Load a @a template and substitute using @a root, returning
* the result to the @a connection with the given
* @a http_status code.
*
* @param connection the connection we act upon
* @param http_status code to use on success
* @param template basename of the template to load
* @param instance_id instance ID, used to compute static files URL
* @param taler_uri value for "Taler:" header to set, or NULL
* @param root JSON object to pass as the root context
* @return #GNUNET_OK on success (reply queued), #GNUNET_NO if an error was queued,
* #GNUNET_SYSERR on failure (to queue an error)
*/
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_TEMPLATING_reply (struct MHD_Connection *connection, TALER_TEMPLATING_build (struct MHD_Connection *connection,
unsigned int http_status, unsigned int *http_status,
const char *template, const char *template,
const char *instance_id, const char *instance_id,
const char *taler_uri, const char *taler_uri,
json_t *root) json_t *root,
struct MHD_Response **reply)
{ {
struct MHD_Response *reply;
char *body; char *body;
size_t body_size; size_t body_size;
@ -205,24 +191,27 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection,
template); template);
if (NULL == tmpl) if (NULL == tmpl)
{ {
/* FIXME: should this not be an
internal failure? The language
missmatch is not critical here! */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to load template `%s'\n", "Failed to load template `%s'\n",
template); template);
if (MHD_YES != *http_status = MHD_HTTP_NOT_ACCEPTABLE;
TALER_MHD_reply_with_error (connection, *reply = TALER_MHD_make_error (TALER_EC_GENERIC_FAILED_TO_LOAD_TEMPLATE,
MHD_HTTP_NOT_ACCEPTABLE, template);
TALER_EC_GENERIC_FAILED_TO_LOAD_TEMPLATE,
template))
return GNUNET_SYSERR;
return GNUNET_NO; return GNUNET_NO;
} }
/* Add default values to the context */ /* Add default values to the context */
if (NULL != instance_id)
{ {
char *static_url = make_static_url (connection, char *static_url = make_static_url (connection,
instance_id); instance_id);
json_object_set (root,
GNUNET_break (0 ==
json_object_set_new (root,
"static_url", "static_url",
json_string (static_url)); json_string (static_url)));
GNUNET_free (static_url); GNUNET_free (static_url);
} }
if (0 != if (0 !=
@ -235,12 +224,9 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection,
"mustach failed on template `%s' with error %d\n", "mustach failed on template `%s' with error %d\n",
template, template,
eno); eno);
if (MHD_YES != *http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
TALER_MHD_reply_with_error (connection, *reply = TALER_MHD_make_error (TALER_EC_GENERIC_FAILED_TO_EXPAND_TEMPLATE,
MHD_HTTP_INTERNAL_SERVER_ERROR, template);
TALER_EC_GENERIC_FAILED_TO_EXPAND_TEMPLATE,
template))
return GNUNET_SYSERR;
return GNUNET_NO; return GNUNET_NO;
} }
} }
@ -255,10 +241,10 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection,
compressed = TALER_MHD_body_compress ((void **) &body, compressed = TALER_MHD_body_compress ((void **) &body,
&body_size); &body_size);
} }
reply = MHD_create_response_from_buffer (body_size, *reply = MHD_create_response_from_buffer (body_size,
body, body,
MHD_RESPMEM_MUST_FREE); MHD_RESPMEM_MUST_FREE);
if (NULL == reply) if (NULL == *reply)
{ {
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -266,12 +252,13 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection,
if (compressed) if (compressed)
{ {
if (MHD_NO == if (MHD_NO ==
MHD_add_response_header (reply, MHD_add_response_header (*reply,
MHD_HTTP_HEADER_CONTENT_ENCODING, MHD_HTTP_HEADER_CONTENT_ENCODING,
"deflate")) "deflate"))
{ {
GNUNET_break (0); GNUNET_break (0);
MHD_destroy_response (reply); MHD_destroy_response (*reply);
*reply = NULL;
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
} }
@ -280,26 +267,47 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection,
/* Add standard headers */ /* Add standard headers */
if (NULL != taler_uri) if (NULL != taler_uri)
GNUNET_break (MHD_NO != GNUNET_break (MHD_NO !=
MHD_add_response_header (reply, MHD_add_response_header (*reply,
"Taler", "Taler",
taler_uri)); taler_uri));
GNUNET_break (MHD_NO != GNUNET_break (MHD_NO !=
MHD_add_response_header (reply, MHD_add_response_header (*reply,
MHD_HTTP_HEADER_CONTENT_TYPE, MHD_HTTP_HEADER_CONTENT_TYPE,
"text/html")); "text/html"));
return GNUNET_OK;
}
/* Actually return reply */
enum GNUNET_GenericReturnValue
TALER_TEMPLATING_reply (struct MHD_Connection *connection,
unsigned int http_status,
const char *template,
const char *instance_id,
const char *taler_uri,
json_t *root)
{ {
enum GNUNET_GenericReturnValue res;
struct MHD_Response *reply;
MHD_RESULT ret; MHD_RESULT ret;
res = TALER_TEMPLATING_build (connection,
&http_status,
template,
instance_id,
taler_uri,
root,
&reply);
if (GNUNET_SYSERR == res)
return res;
ret = MHD_queue_response (connection, ret = MHD_queue_response (connection,
http_status, http_status,
reply); reply);
MHD_destroy_response (reply); MHD_destroy_response (reply);
if (MHD_NO == ret) if (MHD_NO == ret)
return GNUNET_SYSERR; return GNUNET_SYSERR;
} return (res == GNUNET_OK)
return GNUNET_OK; ? GNUNET_OK
: GNUNET_NO;
} }