commit 8823084f2ae0f3d5b40795c91a6714d0259cd5e3
parent fd3a61012d093663d77ebf0bb4cac3a011c981b6
Author: Christian Grothoff <christian@grothoff.org>
Date: Tue, 14 May 2024 20:15:08 +0200
work on kyc API
Diffstat:
3 files changed, 293 insertions(+), 300 deletions(-)
diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h
@@ -71,6 +71,142 @@ enum TALER_KYCLOGIC_KycTriggerEvent
/**
+ * Types of KYC checks.
+ */
+enum CheckType
+{
+ /**
+ * Wait for staff or contact staff out-of-band.
+ */
+ CT_INFO,
+
+ /**
+ * SPA should show an inline form.
+ */
+ CT_FORM,
+
+ /**
+ * SPA may start external KYC process.
+ */
+ CT_LINK
+};
+
+
+/**
+ * Information about a KYC provider.
+ */
+struct TALER_KYCLOGIC_KycProvider;
+
+
+/**
+ * Abstract representation of a KYC check.
+ */
+struct TALER_KYCLOGIC_KycCheck
+{
+ /**
+ * Human-readable name given to the KYC check.
+ */
+ char *check_name;
+
+ /**
+ * Human-readable description of the check in English.
+ */
+ char *description;
+
+ /**
+ * Optional translations of @e description, can be
+ * NULL.
+ */
+ json_t *description_i18n;
+
+ /**
+ * Array of fields that the context must provide as
+ * inputs for this check.
+ */
+ char **requires;
+
+ /**
+ * Name of an original measure to take as a fallback
+ * in case the check fails.
+ */
+ char *fallback;
+
+ /**
+ * Array of outputs provided by the check. Names of the attributes provided
+ * by the check for the AML program. Either from the configuration or
+ * obtained via the converter.
+ */
+ char **outputs;
+
+ /**
+ * Length of the @e requires array.
+ */
+ unsigned int num_requires;
+
+ /**
+ * Length of the @e outputs array.
+ */
+ unsigned int num_outputs;
+
+ /**
+ * True if clients can voluntarily trigger this check.
+ */
+ bool voluntary;
+
+ /**
+ * Type of the KYC check.
+ */
+ enum CheckType type;
+
+ /**
+ * Details depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Fields present only if @e type is #CT_FORM.
+ */
+ struct
+ {
+
+ /**
+ * Name of the form to render.
+ */
+ char *name;
+
+ } form;
+
+ /**
+ * Fields present only if @e type is CT_LINK.
+ */
+ struct
+ {
+
+ /**
+ * Provider used.
+ */
+ const struct TALER_KYCLOGIC_KycProvider *provider;
+
+ } link;
+
+ } details;
+
+};
+
+
+/**
+ * Rule that triggers some measure(s).
+ */
+struct TALER_KYCLOGIC_KycRule;
+
+/**
+ * Set of rules that applies to an account.
+ */
+struct TALER_KYCLOGIC_LegitimizationRuleSet;
+
+
+/**
* Parse KYC trigger string value from a string
* into enumeration value.
*
@@ -162,17 +298,6 @@ typedef void
/**
- * Rule that triggers some measure(s).
- */
-struct TALER_KYCLOGIC_KycRule;
-
-/**
- * Set of rules that applies to an account.
- */
-struct TALER_KYCLOGIC_LegitimizationRuleSet;
-
-
-/**
* Parse set of legitimization rules that applies to an account.
*
* @param jlrs JSON representation to parse
@@ -261,29 +386,65 @@ TALER_KYCLOGIC_is_satisfiable (
/**
+ * Extract logic data from a KYC @a provider.
+ *
+ * @param provider provider to get logic data from
+ * @param[out] plugin set to the KYC logic API
+ * @param[out] pd set to the specific operation context
+ * @param[out] provider_name set to the name
+ * of the KYC provider
+ */
+void
+TALER_KYCLOGIC_provider_to_logic (
+ const struct TALER_KYCLOGIC_KycProvider *provider,
+ struct TALER_KYCLOGIC_Plugin **plugin,
+ struct TALER_KYCLOGIC_ProviderDetails **pd,
+ const char **provider_name);
+
+
+/**
+ * Tuple with information about a KYC check to perform. Note that it will
+ * have references into the legitimization rule set provided to
+ * #TALER_KYCLOGIC_requirements_to_check() and thus has a lifetime that
+ * matches the legitimization rule set.
+ */
+struct TALER_KYCLOGIC_KycCheckContext
+{
+ /**
+ * KYC check to perform.
+ */
+ const struct TALER_KYCLOGIC_KycCheck *check;
+
+ /**
+ * Context for the check. Can be NULL.
+ */
+ const json_t *context;
+
+ /**
+ * Name of the AML program.
+ */
+ char *prog_name;
+};
+
+
+/**
* Obtain the provider logic for a given set of @a lrs
* and a specific @a kyc_rule from @a lrs that was
* triggered and the choosen @a measure_name from the
* list of measures of that @a kyc_rule.
*
- * FIXME: we probably want to instead set up the logic
- * with the context instead of just returning it here!
- *
* @param lrs rule set
* @param kyc_rule rule that was triggered
* @param measure_name selected measure
- * @param[out] plugin set to the KYC logic API
- * @param[out] pd set to the specific operation context
- * @param[out] configuration_section set to the name of the KYC logic configuration section * @return #GNUNET_OK on success
+ * @param[out] kcc set to check to run
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
enum GNUNET_GenericReturnValue
-TALER_KYCLOGIC_requirements_to_logic (
+TALER_KYCLOGIC_requirements_to_check (
const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
const struct TALER_KYCLOGIC_KycRule *kyc_rule,
const char *measure_name,
- struct TALER_KYCLOGIC_Plugin **plugin,
- struct TALER_KYCLOGIC_ProviderDetails **pd,
- const char **configuration_section);
+ struct TALER_KYCLOGIC_KycCheckContext *kcc);
/**
@@ -303,26 +464,6 @@ TALER_KYCLOGIC_lookup_logic (
const char **configuration_section);
-// FIXME: we probably want to instead have some
-// functionality that returns information that
-// is more directly applicable for /keys or /config
-// and not this:
-/**
- * Obtain array of KYC checks provided by the provider
- * configured in @a section_name.
- *
- * @param section_name configuration section name
- * @param[out] num_checks set to the length of the array
- * @param[out] provided_checks set to an array with the
- * names of the checks provided by this KYC provider
- */
-void
-TALER_KYCLOGIC_lookup_checks (
- const char *section_name,
- unsigned int *num_checks,
- char ***provided_checks);
-
-
/**
* Function called with the provider details and
* associated plugin closures for matching logics.
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
@@ -64,124 +64,6 @@ struct TALER_KYCLOGIC_KycProvider
/**
- * Types of KYC checks.
- */
-enum CheckType
-{
- /**
- * Wait for staff or contact staff out-of-band.
- */
- CT_INFO,
-
- /**
- * SPA should show an inline form.
- */
- CT_FORM,
-
- /**
- * SPA may start external KYC process.
- */
- CT_LINK
-};
-
-/**
- * Abstract representation of a KYC check.
- */
-struct TALER_KYCLOGIC_KycCheck
-{
- /**
- * Human-readable name given to the KYC check.
- */
- char *check_name;
-
- /**
- * Human-readable description of the check in English.
- */
- char *description;
-
- /**
- * Optional translations of @e description, can be
- * NULL.
- */
- json_t *description_i18n;
-
- /**
- * Array of fields that the context must provide as
- * inputs for this check.
- */
- char **requires;
-
- /**
- * Length of the @e requires array.
- */
- unsigned int num_requires;
-
- /**
- * Name of an original measure to take as a fallback
- * in case the check fails.
- */
- char *fallback;
-
- /**
- * Array of outputs provided by the check. Names of the attributes provided
- * by the check for the AML program. Either from the configuration or
- * obtained via the converter.
- */
- char **outputs;
-
- /**
- * Length of the @e outputs array.
- */
- unsigned int num_outputs;
-
- /**
- * True if clients can voluntarily trigger this check.
- */
- bool voluntary;
-
- /**
- * Type of the KYC check.
- */
- enum CheckType type;
-
- /**
- * Details depending on @e type.
- */
- union
- {
-
- /**
- * Fields present only if @e type is #CT_FORM.
- */
- struct
- {
-
- /**
- * Name of the form to render.
- */
- char *name;
-
- } form;
-
- /**
- * Fields present only if @e type is CT_LINK.
- */
- struct
- {
-
- /**
- * Provider used.
- */
- const struct TALER_KYCLOGIC_KycProvider *provider;
-
- } link;
-
- } details;
-
-};
-
-
-/**
* Rule that triggers some measure(s).
*/
struct TALER_KYCLOGIC_KycRule
@@ -1755,19 +1637,30 @@ TALER_KYCLOGIC_kyc_done (void)
}
+void
+TALER_KYCLOGIC_provider_to_logic (
+ const struct TALER_KYCLOGIC_KycProvider *provider,
+ struct TALER_KYCLOGIC_Plugin **plugin,
+ struct TALER_KYCLOGIC_ProviderDetails **pd,
+ const char **provider_name)
+{
+ *plugin = provider->logic;
+ *pd = provider->pd;
+ *provider_name = provider->provider_name;
+}
+
+
enum GNUNET_GenericReturnValue
-TALER_KYCLOGIC_requirements_to_logic (
+TALER_KYCLOGIC_requirements_to_check (
const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
const struct TALER_KYCLOGIC_KycRule *kyc_rule,
const char *measure_name,
- struct TALER_KYCLOGIC_Plugin **plugin,
- struct TALER_KYCLOGIC_ProviderDetails **pd,
- const char **configuration_section)
+ struct TALER_KYCLOGIC_KycCheckContext *kcc)
{
bool found = false;
const struct TALER_KYCLOGIC_Measure *measure = NULL;
- for (unsigned int i=0; i<kyc_rule->num_measures; i++)
+ for (unsigned int i = 0; i<kyc_rule->num_measures; i++)
{
if (0 != strcmp (measure_name,
kyc_rule->next_measures[i]))
@@ -1791,7 +1684,7 @@ TALER_KYCLOGIC_requirements_to_logic (
}
if (NULL != lrs)
{
- for (unsigned int i=0; i<lrs->num_custom_measures; i++)
+ for (unsigned int i = 0; i<lrs->num_custom_measures; i++)
{
const struct TALER_KYCLOGIC_Measure *cm
= &lrs->custom_measures[i];
@@ -1806,7 +1699,7 @@ TALER_KYCLOGIC_requirements_to_logic (
if (NULL == measure)
{
/* Try measures from default rules */
- for (unsigned int i=0; i<default_rules.num_custom_measures; i++)
+ for (unsigned int i = 0; i<default_rules.num_custom_measures; i++)
{
const struct TALER_KYCLOGIC_Measure *cm
= &default_rules.custom_measures[i];
@@ -1827,86 +1720,20 @@ TALER_KYCLOGIC_requirements_to_logic (
return GNUNET_SYSERR;
}
-#if FIXME
- struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
- unsigned int needed_cnt = 0;
- unsigned long long min_cost = ULLONG_MAX;
- unsigned int max_checks = 0;
- const struct TALER_KYCLOGIC_KycProvider *kp_best = NULL;
-
- if (NULL == requirements)
- return GNUNET_NO;
- {
- char *req = GNUNET_strdup (requirements);
-
- for (const char *tok = strtok (req, " ");
- NULL != tok;
- tok = strtok (NULL, " "))
- needed[needed_cnt++] = add_check (tok);
- GNUNET_free (req);
- }
-
- /* Count maximum number of remaining checks covered by any
- provider */
- for (unsigned int i = 0; i<num_kyc_providers; i++)
- {
- const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
- unsigned int matched = 0;
-
- if (kp->user_type != ut)
- continue;
- for (unsigned int j = 0; j<kp->num_checks; j++)
- {
- const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
-
- for (unsigned int k = 0; k<needed_cnt; k++)
- if (kc == needed[k])
- {
- matched++;
- break;
- }
- }
- max_checks = GNUNET_MAX (max_checks,
- matched);
- }
- if (0 == max_checks)
- return GNUNET_SYSERR;
-
- /* Find min-cost provider covering max_checks. */
- for (unsigned int i = 0; i<num_kyc_providers; i++)
- {
- const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
- unsigned int matched = 0;
-
- if (kp->user_type != ut)
- continue;
- for (unsigned int j = 0; j<kp->num_checks; j++)
- {
- const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
-
- for (unsigned int k = 0; k<needed_cnt; k++)
- if (kc == needed[k])
- {
- matched++;
- break;
- }
- }
- if ( (max_checks == matched) &&
- (kp->cost < min_cost) )
+ for (unsigned int i = 0; i<num_kyc_checks; i++)
+ if (0 == strcmp (measure->check_name,
+ kyc_checks[i]->check_name))
{
- min_cost = kp->cost;
- kp_best = kp;
+ kcc->check = kyc_checks[i];
+ kcc->prog_name = measure->prog_name;
+ kcc->context = measure->context;
+ return GNUNET_OK;
}
- }
- GNUNET_assert (NULL != kp_best);
- *plugin = kp_best->logic;
- *pd = kp_best->pd;
- *configuration_section = kp_best->provider_section_name;
- return GNUNET_OK;
-#else
- GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Check `%s' unknown (but required by measure %s)\n",
+ measure->check_name,
+ measure_name);
return GNUNET_SYSERR;
-#endif
}
diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c
@@ -252,12 +252,6 @@ static char *cmd_provider_user_id;
static char *cmd_provider_legitimization_id;
/**
- * Name of the configuration section with the
- * configuration data of the selected provider.
- */
-static const char *provider_section_name;
-
-/**
* Custom legitimization rule in JSON given as
* a string.
*/
@@ -961,10 +955,11 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
/deposits/). The value should be adjusted if we ever define protocol
endpoints with plausibly longer inputs. */
GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_URI_TOO_LONG,
- TALER_EC_GENERIC_URI_TOO_LONG,
- url);
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_URI_TOO_LONG,
+ TALER_EC_GENERIC_URI_TOO_LONG,
+ url);
}
/* All POST endpoints come with a body in JSON format. So we parse
@@ -975,11 +970,12 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
{
enum GNUNET_GenericReturnValue res;
- res = TALER_MHD_parse_post_json (rc->connection,
- &rc->opaque_post_parsing_context,
- upload_data,
- upload_data_size,
- &rc->root);
+ res = TALER_MHD_parse_post_json (
+ rc->connection,
+ &rc->opaque_post_parsing_context,
+ upload_data,
+ upload_data_size,
+ &rc->root);
if (GNUNET_SYSERR == res)
{
GNUNET_assert (NULL == rc->root);
@@ -1026,10 +1022,11 @@ proceed_with_handler (struct TEKT_RequestContext *rc,
rh->url,
url);
GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_EXCHANGE_GENERIC_WRONG_NUMBER_OF_SEGMENTS,
- emsg);
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_EXCHANGE_GENERIC_WRONG_NUMBER_OF_SEGMENTS,
+ emsg);
}
GNUNET_assert (NULL == args[i - 1]);
@@ -1257,12 +1254,14 @@ handle_mhd_request (void *cls,
allowed = tmp;
}
}
- reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID,
- method);
- GNUNET_break (MHD_YES ==
- MHD_add_response_header (reply,
- MHD_HTTP_HEADER_ALLOW,
- allowed));
+ reply = TALER_MHD_make_error (
+ TALER_EC_GENERIC_METHOD_INVALID,
+ method);
+ GNUNET_break (
+ MHD_YES ==
+ MHD_add_response_header (reply,
+ MHD_HTTP_HEADER_ALLOW,
+ allowed));
GNUNET_free (allowed);
ret = MHD_queue_response (connection,
MHD_HTTP_METHOD_NOT_ALLOWED,
@@ -1613,11 +1612,11 @@ run (void *cls,
if (NULL != rule)
{
- struct TALER_KYCLOGIC_ProviderDetails *pd;
+ struct TALER_KYCLOGIC_KycCheckContext kcc;
if (NULL == measure)
{
- // FIXME: print rule!
+ // FIXME: print rule with possible measures!
global_ret = EXIT_SUCCESS;
GNUNET_SCHEDULER_shutdown ();
@@ -1625,12 +1624,10 @@ run (void *cls,
}
if (GNUNET_OK !=
- TALER_KYCLOGIC_requirements_to_logic (lrs,
+ TALER_KYCLOGIC_requirements_to_check (lrs,
rule,
measure,
- &ih_logic,
- &pd,
- &provider_section_name))
+ &kcc))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not initiate KYC for measure `%s' (configuration error?)\n",
@@ -1639,16 +1636,43 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Initiating KYC at provider `%s'\n",
- provider_section_name);
- ih = ih_logic->initiate (ih_logic->cls,
- pd,
- &cmd_line_h_payto,
- kyc_row_id,
- &initiate_cb,
- NULL);
- GNUNET_break (NULL != ih);
+ switch (kcc.check->type)
+ {
+ case CT_INFO:
+ GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+ "KYC information is `%s'\n",
+ kcc.check->description);
+ break;
+ case CT_FORM:
+ GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+ "Would initiate KYC check `%s' with form `%s'\n",
+ kcc.check->check_name,
+ kcc.check->details.form.name);
+ break;
+ case CT_LINK:
+ {
+ struct TALER_KYCLOGIC_ProviderDetails *pd;
+ const char *provider_name;
+
+ TALER_KYCLOGIC_provider_to_logic (
+ kcc.check->details.link.provider,
+ &ih_logic,
+ &pd,
+ &provider_name);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Initiating KYC check `%s' at provider `%s'\n",
+ kcc.check->check_name,
+ provider_name);
+ ih = ih_logic->initiate (ih_logic->cls,
+ pd,
+ &cmd_line_h_payto,
+ kyc_row_id,
+ &initiate_cb,
+ NULL);
+ GNUNET_break (NULL != ih);
+ break;
+ }
+ }
}
if (run_webservice)
{
@@ -1675,22 +1699,23 @@ run (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting daemon on port %u\n",
(unsigned int) serve_port);
- mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
- | MHD_USE_PIPE_FOR_SHUTDOWN
- | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
- | MHD_USE_TCP_FASTOPEN,
- (-1 == fh) ? serve_port : 0,
- NULL, NULL,
- &handle_mhd_request, NULL,
- MHD_OPTION_LISTEN_SOCKET,
- fh,
- MHD_OPTION_EXTERNAL_LOGGER,
- &TALER_MHD_handle_logs,
- NULL,
- MHD_OPTION_NOTIFY_COMPLETED,
- &handle_mhd_completion_callback,
- NULL,
- MHD_OPTION_END);
+ mhd = MHD_start_daemon (
+ MHD_USE_SUSPEND_RESUME
+ | MHD_USE_PIPE_FOR_SHUTDOWN
+ | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
+ | MHD_USE_TCP_FASTOPEN,
+ (-1 == fh) ? serve_port : 0,
+ NULL, NULL,
+ &handle_mhd_request, NULL,
+ MHD_OPTION_LISTEN_SOCKET,
+ fh,
+ MHD_OPTION_EXTERNAL_LOGGER,
+ &TALER_MHD_handle_logs,
+ NULL,
+ MHD_OPTION_NOTIFY_COMPLETED,
+ &handle_mhd_completion_callback,
+ NULL,
+ MHD_OPTION_END);
if (NULL == mhd)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,