From c62792638bd933b9e6fe57358c1233b7a48d6d3f Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 16 Aug 2022 21:04:51 +0200 Subject: [PATCH] work on kycaid plugin response generation logic --- contrib/Makefile.am | 10 +- contrib/bad_gateway.en.must | 12 + contrib/kyc_failed.en.must | 20 + contrib/kyc_interaction_failed.en.must | 13 + contrib/kyc_provider_internal_error.en.must | 13 + contrib/kyc_provider_ratelimit.en.must | 13 + contrib/kyc_provider_timeout.en.must | 13 + contrib/kyc_provider_unauthorized.en.must | 13 + contrib/kyc_provider_unexpected_reply.en.must | 13 + contrib/kyc_provider_unpaid.en.must | 13 + contrib/kyc_user_failed.en.must | 20 + contrib/test.en.must | 0 src/include/taler_templating_lib.h | 28 ++ src/kyclogic/Makefile.am | 2 + src/kyclogic/plugin_kyclogic_kycaid.c | 365 ++++++++++++------ src/kyclogic/plugin_kyclogic_oauth2.c | 4 +- src/kyclogic/plugin_kyclogic_template.c | 4 +- src/kyclogic/taler-exchange-kyc-tester.c | 12 +- src/templating/templating_api.c | 114 +++--- 19 files changed, 499 insertions(+), 183 deletions(-) create mode 100644 contrib/bad_gateway.en.must create mode 100644 contrib/kyc_failed.en.must create mode 100644 contrib/kyc_interaction_failed.en.must create mode 100644 contrib/kyc_provider_internal_error.en.must create mode 100644 contrib/kyc_provider_ratelimit.en.must create mode 100644 contrib/kyc_provider_timeout.en.must create mode 100644 contrib/kyc_provider_unauthorized.en.must create mode 100644 contrib/kyc_provider_unexpected_reply.en.must create mode 100644 contrib/kyc_provider_unpaid.en.must create mode 100644 contrib/kyc_user_failed.en.must delete mode 100644 contrib/test.en.must diff --git a/contrib/Makefile.am b/contrib/Makefile.am index 671e7908b..c69be57e4 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am @@ -3,7 +3,15 @@ SUBDIRS = . tmplpkgdatadir = $(prefix)/share/taler/exchange/templates/ 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 # WTF: cp $< $@ diff --git a/contrib/bad_gateway.en.must b/contrib/bad_gateway.en.must new file mode 100644 index 000000000..f177db900 --- /dev/null +++ b/contrib/bad_gateway.en.must @@ -0,0 +1,12 @@ + + +KYC server failure + + +The KYC backend returned a malformed response, reproduced +below. Please inform the exchange operator about this failure. +
+{{ kyc_server_reply }}
+
+ + \ No newline at end of file diff --git a/contrib/kyc_failed.en.must b/contrib/kyc_failed.en.must new file mode 100644 index 000000000..c1e27a821 --- /dev/null +++ b/contrib/kyc_failed.en.must @@ -0,0 +1,20 @@ + + +KYC authentication failed + + +You failed the KYC check. See below for details. + + +
+{{ verifications }}
+
+ + \ No newline at end of file diff --git a/contrib/kyc_interaction_failed.en.must b/contrib/kyc_interaction_failed.en.must new file mode 100644 index 000000000..504cd09c9 --- /dev/null +++ b/contrib/kyc_interaction_failed.en.must @@ -0,0 +1,13 @@ + + +KYC server interaction failed + + +The KYC backend returned a response indicating a problem with the exchange logic. Please inform the exchange operator about this failure. +
+{{ kyc_http_status }}
+{{ kyc_logic }}
+{{ kyc_server_reply }}
+
+ + diff --git a/contrib/kyc_provider_internal_error.en.must b/contrib/kyc_provider_internal_error.en.must new file mode 100644 index 000000000..37d1e0f3a --- /dev/null +++ b/contrib/kyc_provider_internal_error.en.must @@ -0,0 +1,13 @@ + + +KYC provider had an internal error + + +The KYC backend had an internal error. +
+{{ kyc_http_status }}
+{{ kyc_logic }}
+{{ kyc_server_reply }}
+
+ + diff --git a/contrib/kyc_provider_ratelimit.en.must b/contrib/kyc_provider_ratelimit.en.must new file mode 100644 index 000000000..77917c0b3 --- /dev/null +++ b/contrib/kyc_provider_ratelimit.en.must @@ -0,0 +1,13 @@ + + +KYC provider rate limit reached + + +The KYC backend interaction ran into a rate limit. +
+{{ kyc_http_status }}
+{{ kyc_logic }}
+{{ kyc_server_reply }}
+
+ + diff --git a/contrib/kyc_provider_timeout.en.must b/contrib/kyc_provider_timeout.en.must new file mode 100644 index 000000000..c1ad79b34 --- /dev/null +++ b/contrib/kyc_provider_timeout.en.must @@ -0,0 +1,13 @@ + + +KYC provider timeout + + +The KYC backend interaction ran into a timeout. +
+{{ kyc_http_status }}
+{{ kyc_logic }}
+{{ kyc_server_reply }}
+
+ + diff --git a/contrib/kyc_provider_unauthorized.en.must b/contrib/kyc_provider_unauthorized.en.must new file mode 100644 index 000000000..9b4858178 --- /dev/null +++ b/contrib/kyc_provider_unauthorized.en.must @@ -0,0 +1,13 @@ + + +KYC server refused access + + +The KYC backend refused the authorization code used by the exchange operator. Please inform the exchange operator about this failure. +
+{{ kyc_http_status }}
+{{ kyc_logic }}
+{{ kyc_server_reply }}
+
+ + diff --git a/contrib/kyc_provider_unexpected_reply.en.must b/contrib/kyc_provider_unexpected_reply.en.must new file mode 100644 index 000000000..b3df670a4 --- /dev/null +++ b/contrib/kyc_provider_unexpected_reply.en.must @@ -0,0 +1,13 @@ + + +KYC provider returned unexpected status code + + +The KYC backend returned an unexpected status code. +
+{{ kyc_http_status }}
+{{ kyc_logic }}
+{{ kyc_server_reply }}
+
+ + diff --git a/contrib/kyc_provider_unpaid.en.must b/contrib/kyc_provider_unpaid.en.must new file mode 100644 index 000000000..65fa4f9b7 --- /dev/null +++ b/contrib/kyc_provider_unpaid.en.must @@ -0,0 +1,13 @@ + + +KYC credit exhausted + + +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. +
+{{ kyc_http_status }}
+{{ kyc_logic }}
+{{ kyc_server_reply }}
+
+ + diff --git a/contrib/kyc_user_failed.en.must b/contrib/kyc_user_failed.en.must new file mode 100644 index 000000000..54a4637c4 --- /dev/null +++ b/contrib/kyc_user_failed.en.must @@ -0,0 +1,20 @@ + + +KYC authentication failed + + +You failed the KYC check. See below for details. + + +
+{{ verifications }}
+
+ + \ No newline at end of file diff --git a/contrib/test.en.must b/contrib/test.en.must deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/include/taler_templating_lib.h b/src/include/taler_templating_lib.h index bad200f50..9cce84f5a 100644 --- a/src/include/taler_templating_lib.h +++ b/src/include/taler_templating_lib.h @@ -24,6 +24,34 @@ #include +/** + * 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 * the result to the @a connection with the given diff --git a/src/kyclogic/Makefile.am b/src/kyclogic/Makefile.am index 53c0660a0..9f034731c 100644 --- a/src/kyclogic/Makefile.am +++ b/src/kyclogic/Makefile.am @@ -39,6 +39,7 @@ taler_exchange_kyc_tester_LDADD = \ libtalerkyclogic.la \ $(top_builddir)/src/mhd/libtalermhd.la \ $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/templating/libtalertemplating.la \ $(top_builddir)/src/util/libtalerutil.la \ -lmicrohttpd \ -lgnunetcurl \ @@ -83,6 +84,7 @@ libtaler_plugin_kyclogic_kycaid_la_LDFLAGS = \ $(TALER_PLUGIN_LDFLAGS) \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/curl/libtalercurl.la \ + $(top_builddir)/src/templating/libtalertemplating.la \ $(top_builddir)/src/util/libtalerutil.la \ -lgnunetutil \ -ljansson \ diff --git a/src/kyclogic/plugin_kyclogic_kycaid.c b/src/kyclogic/plugin_kyclogic_kycaid.c index acfcb0e03..5c56bcf48 100644 --- a/src/kyclogic/plugin_kyclogic_kycaid.c +++ b/src/kyclogic/plugin_kyclogic_kycaid.c @@ -20,9 +20,10 @@ */ #include "platform.h" #include "taler_kyclogic_plugin.h" -#include -#include -#include +#include "taler_mhd_lib.h" +#include "taler_curl_lib.h" +#include "taler_json_lib.h" +#include "taler_templating_lib.h" #include #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 * HTTP "/verifications/{verification_id}" request. @@ -684,18 +722,19 @@ handle_proof_finished (void *cls, spec, NULL, NULL)) { + json_t *template_data; + GNUNET_break_op (0); 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_BAD_GATEWAY, - resp); + template_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_object_incref ("kyc_server_reply", + (json_t *) j)); + proof_reply_with_template (ph, + MHD_HTTP_BAD_GATEWAY, + "bad_gateway", + template_data); break; } /* FIXME: comment out, unless debugging ... */ @@ -706,26 +745,35 @@ handle_proof_finished (void *cls, JSON_INDENT (2)); 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); ph->cb (ph->cb_cls, TALER_KYCLOGIC_STATUS_SUCCESS, applicant_id, verification_id, expiration, - MHD_HTTP_OK, + MHD_HTTP_OK, // OK, or redirect??? resp); } else { - resp = NULL; // FIXME: generate response! - ph->cb (ph->cb_cls, - TALER_KYCLOGIC_STATUS_USER_ABORTED, - applicant_id, - verification_id, - GNUNET_TIME_UNIT_ZERO_ABS, - MHD_HTTP_OK, - resp); + json_t *template_data; + + GNUNET_break_op (0); + json_dumpf (j, + stderr, + 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, + "kyc_user_failed", + template_data); } GNUNET_JSON_parse_free (spec); } @@ -733,97 +781,131 @@ handle_proof_finished (void *cls, case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_NOT_FOUND: 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 */ - 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_BAD_GATEWAY, - resp); - break; + { + json_t *template_data; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "KYCAID failed with response %u:\n", + (unsigned int) response_code); + json_dumpf (j, + stderr, + JSON_INDENT (2)); + 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_interaction_failed", + template_data); + 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: - 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_SERVICE_UNAVAILABLE, - resp); - break; + { + 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_ratelimit", + template_data); + break; + } case MHD_HTTP_INTERNAL_SERVER_ERROR: - 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_BAD_GATEWAY, - resp); - break; + { + 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_internal_error", + template_data); + break; + } default: - resp = NULL; // FIXME: generate response! - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected KYCAID response %u:\n", - (unsigned int) response_code); - json_dumpf (j, - stderr, - JSON_INDENT (2)); - 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_BAD_GATEWAY, - resp); - break; + { + 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_unexpected_reply", + template_data); + break; + } } kycaid_proof_cancel (ph); } @@ -970,7 +1052,11 @@ handle_webhook_finished (void *cls, json_dumpf (j, stderr, 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->legi_row, &wh->h_payto, @@ -990,7 +1076,7 @@ handle_webhook_finished (void *cls, JSON_INDENT (2)); if (verified) { - resp = NULL; // FIXME: generate response! + resp = TALER_MHD_make_json_steal (json_object ()); expiration = GNUNET_TIME_relative_to_absolute (wh->pd->validity); wh->cb (wh->cb_cls, wh->legi_row, @@ -1004,7 +1090,7 @@ handle_webhook_finished (void *cls, } else { - resp = NULL; // FIXME: generate response! + resp = TALER_MHD_make_json_steal (json_object ()); wh->cb (wh->cb_cls, wh->legi_row, &wh->h_payto, @@ -1027,7 +1113,9 @@ handle_webhook_finished (void *cls, json_dumpf (j, stderr, 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->legi_row, &wh->h_payto, @@ -1043,7 +1131,11 @@ handle_webhook_finished (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Refused access with HTTP status code %u\n", (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->legi_row, &wh->h_payto, @@ -1055,7 +1147,11 @@ handle_webhook_finished (void *cls, resp); break; 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->legi_row, &wh->h_payto, @@ -1073,7 +1169,11 @@ handle_webhook_finished (void *cls, json_dumpf (j, stderr, 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->legi_row, &wh->h_payto, @@ -1085,7 +1185,11 @@ handle_webhook_finished (void *cls, resp); break; 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->legi_row, &wh->h_payto, @@ -1097,7 +1201,11 @@ handle_webhook_finished (void *cls, resp); break; 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->legi_row, &wh->h_payto, @@ -1109,7 +1217,11 @@ handle_webhook_finished (void *cls, resp); break; 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, "Unexpected KYCAID response %u:\n", (unsigned int) response_code); @@ -1226,7 +1338,9 @@ kycaid_webhook (void *cls, json_dumpf (body, stderr, 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->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply, wh); @@ -1239,7 +1353,8 @@ kycaid_webhook (void *cls, &wh->legi_row); 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->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply, wh); @@ -1250,7 +1365,9 @@ kycaid_webhook (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received webhook for unknown verification ID `%s'\n", 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->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply, wh); @@ -1263,8 +1380,10 @@ kycaid_webhook (void *cls, if (NULL == eh) { GNUNET_break (0); - wh->resp = NULL; // FIXME: generate response! - wh->response_code = MHD_HTTP_BAD_REQUEST; + wh->resp = TALER_MHD_make_error ( + 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); return wh; diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c index b9384e8ff..da7ddfc31 100644 --- a/src/kyclogic/plugin_kyclogic_oauth2.c +++ b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -20,8 +20,8 @@ */ #include "platform.h" #include "taler_kyclogic_plugin.h" -#include -#include +#include "taler_mhd_lib.h" +#include "taler_json_lib.h" #include #include "taler_util.h" diff --git a/src/kyclogic/plugin_kyclogic_template.c b/src/kyclogic/plugin_kyclogic_template.c index aefa4a62f..4a21882b8 100644 --- a/src/kyclogic/plugin_kyclogic_template.c +++ b/src/kyclogic/plugin_kyclogic_template.c @@ -20,8 +20,8 @@ */ #include "platform.h" #include "taler_kyclogic_plugin.h" -#include -#include +#include "taler_mhd_lib.h" +#include "taler_json_lib.h" #include #include "taler_util.h" diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c index 9d75b3ec8..740fcda7a 100644 --- a/src/kyclogic/taler-exchange-kyc-tester.c +++ b/src/kyclogic/taler-exchange-kyc-tester.c @@ -27,6 +27,7 @@ #include #include "taler_mhd_lib.h" #include "taler_json_lib.h" +#include "taler_templating_lib.h" #include "taler_crypto_lib.h" #include "taler_kyclogic_lib.h" #include "taler_kyclogic_plugin.h" @@ -1239,6 +1240,7 @@ do_shutdown (void *cls) GNUNET_CURL_gnunet_rc_destroy (exchange_curl_rc); exchange_curl_rc = NULL; } + TALER_TEMPLATING_done (); } @@ -1309,6 +1311,12 @@ run (void *cls, (void) cls; (void) args; (void ) cfgfile; + if (GNUNET_OK != + TALER_TEMPLATING_init ("exchange")) + { + GNUNET_break (0); + return; + } if (print_h_payto) { char *s; @@ -1322,6 +1330,8 @@ run (void *cls, } TALER_MHD_setup (TALER_MHD_GO_NONE); TEKT_cfg = config; + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); if (GNUNET_OK != TALER_KYCLOGIC_kyc_init (config)) { @@ -1329,8 +1339,6 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } - GNUNET_SCHEDULER_add_shutdown (&do_shutdown, - NULL); if (GNUNET_OK != exchange_serve_process_config ()) { diff --git a/src/templating/templating_api.c b/src/templating/templating_api.c index 50356e45a..38a2d3e31 100644 --- a/src/templating/templating_api.c +++ b/src/templating/templating_api.c @@ -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 -TALER_TEMPLATING_reply (struct MHD_Connection *connection, - unsigned int http_status, +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) + json_t *root, + struct MHD_Response **reply) { - struct MHD_Response *reply; char *body; size_t body_size; @@ -205,24 +191,27 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection, template); if (NULL == tmpl) { + /* FIXME: should this not be an + internal failure? The language + missmatch is not critical here! */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to load template `%s'\n", template); - if (MHD_YES != - TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_ACCEPTABLE, - TALER_EC_GENERIC_FAILED_TO_LOAD_TEMPLATE, - template)) - return GNUNET_SYSERR; + *http_status = MHD_HTTP_NOT_ACCEPTABLE; + *reply = TALER_MHD_make_error (TALER_EC_GENERIC_FAILED_TO_LOAD_TEMPLATE, + template); return GNUNET_NO; } /* Add default values to the context */ + if (NULL != instance_id) { char *static_url = make_static_url (connection, instance_id); - json_object_set (root, - "static_url", - json_string (static_url)); + + GNUNET_break (0 == + json_object_set_new (root, + "static_url", + json_string (static_url))); GNUNET_free (static_url); } if (0 != @@ -235,12 +224,9 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection, "mustach failed on template `%s' with error %d\n", template, eno); - if (MHD_YES != - TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_FAILED_TO_EXPAND_TEMPLATE, - template)) - return GNUNET_SYSERR; + *http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; + *reply = TALER_MHD_make_error (TALER_EC_GENERIC_FAILED_TO_EXPAND_TEMPLATE, + template); return GNUNET_NO; } } @@ -255,10 +241,10 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection, compressed = TALER_MHD_body_compress ((void **) &body, &body_size); } - reply = MHD_create_response_from_buffer (body_size, - body, - MHD_RESPMEM_MUST_FREE); - if (NULL == reply) + *reply = MHD_create_response_from_buffer (body_size, + body, + MHD_RESPMEM_MUST_FREE); + if (NULL == *reply) { GNUNET_break (0); return GNUNET_SYSERR; @@ -266,12 +252,13 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection, if (compressed) { if (MHD_NO == - MHD_add_response_header (reply, + MHD_add_response_header (*reply, MHD_HTTP_HEADER_CONTENT_ENCODING, "deflate")) { GNUNET_break (0); - MHD_destroy_response (reply); + MHD_destroy_response (*reply); + *reply = NULL; return GNUNET_SYSERR; } } @@ -280,29 +267,50 @@ TALER_TEMPLATING_reply (struct MHD_Connection *connection, /* Add standard headers */ if (NULL != taler_uri) GNUNET_break (MHD_NO != - MHD_add_response_header (reply, + MHD_add_response_header (*reply, "Taler", taler_uri)); GNUNET_break (MHD_NO != - MHD_add_response_header (reply, + MHD_add_response_header (*reply, MHD_HTTP_HEADER_CONTENT_TYPE, "text/html")); - - /* Actually return reply */ - { - MHD_RESULT ret; - - ret = MHD_queue_response (connection, - http_status, - reply); - MHD_destroy_response (reply); - if (MHD_NO == ret) - return GNUNET_SYSERR; - } return GNUNET_OK; } +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; + + 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, + http_status, + reply); + MHD_destroy_response (reply); + if (MHD_NO == ret) + return GNUNET_SYSERR; + return (res == GNUNET_OK) + ? GNUNET_OK + : GNUNET_NO; +} + + /** * Function called with a template's filename. *