exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 75e3b7d5eca3b32073f3c90b14a53a6100fb0be4
parent 214994750ba655d3cc4234b1bd757e06e903ba8e
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 27 Nov 2025 16:03:21 +0100

new EC

Diffstat:
Mcontrib/typst/vqf_902_1_customer.typ | 11++++++++---
Msrc/exchange/taler-exchange-httpd.c | 31+++++++++++++++++++++++++++++++
Msrc/exchange/taler-exchange-httpd.h | 5+++++
Msrc/exchange/taler-exchange-httpd_aml-attributes-get.c | 59++++++++++++++++++++++++++++++++++++++++++++++++++---------
4 files changed, 94 insertions(+), 12 deletions(-)

diff --git a/contrib/typst/vqf_902_1_customer.typ b/contrib/typst/vqf_902_1_customer.typ @@ -28,6 +28,11 @@ data.at(key, default: default) } + // Helper function to get value or false + let getb(key, default: false) = { + data.at(key, default: default) + } + // Helper function for checkbox let checkbox(checked) = { box( @@ -413,9 +418,9 @@ inset: 5pt, checkbox("" != get("CUSTOMER_ID_AMLA_FILE_REFERENCE_NO")), [Customer identification documents (or: reference#footnote[If the identification document is lists kept in another AMLA-File (in the case of Art. 15 para. 3 SRO Regulations) a reference to the according AMLA-File is sufficient.] to AMLA File No.: #underline([#get("CUSTOMER_ID_AMLA_FILE_REFERENCE_NO")]))], checkbox("" != get("ESTABLISHER_ID_AMLA_FILE_REFERENCE_NO")), [Identification document of persons establishing the business relationship (or: reference to AMLA File No.: #underline([#get("ESTABLISHER_ID_AMLA_FILE_REFERENCE_NO")]))], -// checkbox(get("HAVE_VQF_902_9") or get("HAVE_vqf_902_11") or get("HAVE_vqf_902_12") or get("HAVE_vqf_902_13") or get("HAVE_vqf_902_15")), [Establishing of the beneficial owner of the assets/controlling person (VQF Doc No. 902.15, 902.9, 902.11, 902.12 or 902.13)], -// checkbox(get("HAVE_vqf_902_5")), [Customer profile (VQF doc. No. 902.5; only in the case of permanent business relationship and regular customers)], -// checkbox(get("HAVE_vqf_902_4")), [Risk profile (VQF doc. No. 902.4)], + checkbox(getb("HAVE_vqf_902_9") or getb("HAVE_vqf_902_11") or getb("HAVE_vqf_902_12") or getb("HAVE_vqf_902_13") or getb("HAVE_vqf_902_15")), [Establishing of the beneficial owner of the assets/controlling person (VQF Doc No. 902.15, 902.9, 902.11, 902.12 or 902.13)], + checkbox(getb("HAVE_vqf_902_5")), [Customer profile (VQF doc. No. 902.5; only in the case of permanent business relationship and regular customers)], + checkbox(getb("HAVE_vqf_902_4")), [Risk profile (VQF doc. No. 902.4)], ) v(1em) diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c @@ -212,6 +212,11 @@ char *TEH_obg_url; static char *toplevel_redirect_url; /** + * Form data to inject into any Typst form generation. + */ +json_t *TEH_global_pdf_form_data; + +/** * Our currency. */ char *TEH_currency; @@ -2442,6 +2447,32 @@ exchange_serve_process_config (const char *cfg_fn) GNUNET_free (attr_enc_key_str); } + { + char *pdf_data; + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (TEH_cfg, + "exchange", + "GLOBAL_PDF_FORM_DATA", + &pdf_data)) + { + json_error_t err; + + TEH_global_pdf_form_data = json_loads (pdf_data, + JSON_REJECT_DUPLICATES, + &err); + GNUNET_free (pdf_data); + if (NULL == TEH_global_pdf_form_data) + { + GNUNET_log_config_malformed (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "GLOBAL_PDF_FORM_DATA", + err.text); + return GNUNET_SYSERR; + } + } + } + for (unsigned int i = 0; i<MAX_DB_RETRIES; i++) { TEH_plugin = TALER_EXCHANGEDB_plugin_load (TEH_cfg, diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h @@ -170,6 +170,11 @@ extern float TEH_stefan_lin; extern const struct TALER_CurrencySpecification *TEH_cspec; /** + * Form data to inject into any Typst form generation. + */ +json_t *TEH_global_pdf_form_data; + +/** * Our currency. */ extern char *TEH_currency; diff --git a/src/exchange/taler-exchange-httpd_aml-attributes-get.c b/src/exchange/taler-exchange-httpd_aml-attributes-get.c @@ -111,6 +111,12 @@ struct ResponseContext * Next write offset into @e docs and @e jdata. */ size_t off; + + /** + * Global attributes we need to inject in to each @e jdata. + */ + json_t *global_attrs; + } pdf; } details; @@ -171,6 +177,7 @@ free_rc (struct TEH_RequestContext *rc) case RCF_PDF: for (size_t i = 0; i<rctx->details.pdf.off; i++) json_decref (rctx->details.pdf.jdata[i]); + json_decref (rctx->details.pdf.global_attrs); break; } GNUNET_free (rctx); @@ -243,10 +250,18 @@ detail_cb ( json_object_set_new (attrs, "DATADIR", json_string (datadir))); - // FIXME: add FILE_NUMBER to attrs (=> need it in rc first!) - // FIXME: add VQF_MEMBER_NUMBER and possibly other meta data to attrs! - // (need new config option for VQF_MEMBER_NUMBER-style globals!) - + { + char *have; + + GNUNET_asprintf (&have, + "HAVE_%s", + form_id); + GNUNET_assert (0 == + json_object_set_new (rc->pdf.global_attrs, + have, + json_true ())); + GNUNET_free (have); + } // FIXME: probably should move this into a helper function, // we'll need it in various places: rc->details.pdf.jdata[rc->details.pdf.off] @@ -296,6 +311,25 @@ pdf_cb (void *cls, } +/** + * Adds cross-reference data to each @a doc that are only available + * in @a rctx after we have processed all inputs. + * + * @param rctx global context + * @param doc document to modify + */ +static void +post_process_pdf (struct ResponseContext *rctx, + struct TALER_MHD_TypstDocument *doc) +{ + json_t *attrs = doc->attrs; + + GNUNET_assert (0 == + json_object_update_missing (attrs, + rctx->pdf.global_attrs)); +} + + MHD_RESULT TEH_handler_aml_attributes_get ( struct TEH_RequestContext *rc, @@ -379,6 +413,12 @@ TEH_handler_aml_attributes_get ( "application/pdf")) { rctx->format = RCF_PDF; + rctx->details.pdf.global_attrs = json_array (); + GNUNET_assert (NULL != rctx->details.pdf.global_attrs); + if (NULL != TEH_global_pdf_form_data) + GNUNET_assert (0 == + json_object_update (attrs, + TEH_global_pdf_form_data)); // FIXME: need to obtain globals about the // account here first, like the FILE_NUMBER. // Might just as well select current rules/etc @@ -451,6 +491,9 @@ TEH_handler_aml_attributes_get ( NULL, 0); } + for (unsigned int i = 0; i<rctx->details.pdf.off; i++) + post_process_pdf (rctx, + &rctx->details.pdf.docs[i]); GNUNET_CONTAINER_DLL_insert (rctx_head, rctx_tail, rctx); @@ -466,13 +509,11 @@ TEH_handler_aml_attributes_get ( { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Client requested PDF, but Typst is unavailable\n"); - // FIXME: return JSON... - return TALER_MHD_reply_static ( + return TALER_MHD_reply_with_error ( rc->connection, MHD_HTTP_NOT_IMPLEMENTED, - NULL, - NULL, - 0); + TALER_EC_EXCHANGE_GENERIC_NO_TYPST_OR_PDFTK, + NULL); } return MHD_YES; }