exchange

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

commit ff469f5a429f474e85584f31ac97867d08387f06
parent 33eb67b18af5a72eb40fbd118937e2cdafe753e5
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon, 25 Nov 2024 23:51:15 +0100

only pass requested inputs to AML programs, and also pass new inputs, specifically current_rules and default_rules

Diffstat:
Msrc/exchange/taler-exchange-httpd_common_kyc.c | 278+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/exchange/taler-exchange-httpd_common_kyc.h | 6++----
Msrc/exchange/taler-exchange-httpd_kyc-proof.c | 3+++
Msrc/exchange/taler-exchange-httpd_kyc-upload.c | 1+
Msrc/exchange/taler-exchange-httpd_kyc-webhook.c | 1+
Msrc/exchangedb/pg_get_kyc_rules.c | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/exchangedb/pg_get_kyc_rules.h | 16++++++++++++++++
Msrc/exchangedb/pg_insert_kyc_measure_result.c | 11+++++++++++
Msrc/exchangedb/plugin_exchangedb_postgres.c | 2++
Msrc/include/taler_exchangedb_plugin.h | 16++++++++++++++++
Msrc/include/taler_kyclogic_lib.h | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/include/taler_kyclogic_plugin.h | 2++
Msrc/kyclogic/kyclogic_api.c | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/kyclogic/plugin_kyclogic_kycaid.c | 1+
Msrc/kyclogic/plugin_kyclogic_oauth2.c | 1+
Msrc/kyclogic/plugin_kyclogic_persona.c | 2++
Msrc/kyclogic/taler-exchange-helper-measure-freeze | 11++++++++++-
Msrc/kyclogic/taler-exchange-helper-measure-test-form | 3++-
Msrc/kyclogic/taler-exchange-kyc-tester.c | 2++
19 files changed, 457 insertions(+), 213 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c @@ -64,7 +64,7 @@ struct TEH_KycMeasureRunContext uint64_t process_row; /** - * name of the provider with the logic that was run + * Name of the provider with the logic that was run */ char *provider_name; @@ -109,16 +109,6 @@ struct TEH_KycMeasureRunContext json_t *jmeasures; /** - * KYC history of the account. - */ - json_t *kyc_history; - - /** - * AML history of the account. - */ - json_t *aml_history; - - /** * KYC measure the client is (trying to) satisfy. */ uint32_t measure_index; @@ -129,6 +119,9 @@ struct TEH_KycMeasureRunContext */ struct TALER_KYCLOGIC_AmlProgramRunnerHandle *kyc_aml; + /** + * Task scheduled to return a result asynchronously. + */ struct GNUNET_SCHEDULER_Task *async_task; }; @@ -234,8 +227,6 @@ kyc_aml_finished ( &kat->account_id, kat->process_row, kat->attributes, - kat->aml_history, - kat->kyc_history, kat->fallback_name, &fallback_result_cb, kat); @@ -381,6 +372,44 @@ add_aml_history_entry ( /** + * Function called to obtain an AML + * history in JSON on-demand if needed. + * + * @param cls must be a `struct TALER_NormalizedPaytoHashP account_id *` + * @return AML history in JSON format, NULL on error + */ +static json_t * +aml_history_builder_cb (void *cls) +{ + const struct TALER_NormalizedPaytoHashP *acc = cls; + enum GNUNET_DB_QueryStatus qs; + json_t *aml_history; + + aml_history = json_array (); + GNUNET_assert (NULL != aml_history); + qs = TEH_plugin->lookup_aml_history ( + TEH_plugin->cls, + acc, + &add_aml_history_entry, + aml_history); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + json_decref (aml_history); + return NULL; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* empty history is fine! */ + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + return aml_history; +} + + +/** * Function called to expand KYC history for the account. * * @param cls a `json_t *` array to build @@ -462,6 +491,78 @@ add_kyc_history_entry ( } +/** + * Function called to obtain a KYC + * history in JSON on-demand if needed. + * + * @param cls must be a `struct TALER_NormalizedPaytoHashP account_id *` + * @return KYC history in JSON format, NULL on error + */ +static json_t * +kyc_history_builder_cb (void *cls) +{ + const struct TALER_NormalizedPaytoHashP *acc = cls; + enum GNUNET_DB_QueryStatus qs; + json_t *kyc_history; + + kyc_history = json_array (); + GNUNET_assert (NULL != kyc_history); + qs = TEH_plugin->lookup_kyc_history ( + TEH_plugin->cls, + acc, + &add_kyc_history_entry, + kyc_history); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + json_decref (kyc_history); + return NULL; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* empty history is fine! */ + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + return kyc_history; +} + + +/** + * Function called to obtain the current ``LegitimizationRuleSet`` + * in JSON for an account on-demand if needed. + * + * @param cls must be a `struct TALER_NormalizedPaytoHashP *` + * @return KYC history in JSON format, NULL on error + */ +static json_t * +current_rule_builder_cb (void *cls) +{ + const struct TALER_NormalizedPaytoHashP *acc = cls; + enum GNUNET_DB_QueryStatus qs; + json_t *jlrs; + + qs = TEH_plugin->get_kyc_rules2 ( + TEH_plugin->cls, + acc, + &jlrs); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return NULL; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + jlrs = json_incref ((json_t *) TALER_KYCLOGIC_get_default_legi_rules ()); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + return jlrs; +} + + void TEH_kyc_run_measure_cancel (struct TEH_KycMeasureRunContext *kat) { @@ -486,8 +587,6 @@ TEH_kyc_run_measure_cancel (struct TEH_KycMeasureRunContext *kat) GNUNET_free (kat->fallback_name); json_decref (kat->jmeasures); json_decref (kat->attributes); - json_decref (kat->aml_history); - json_decref (kat->kyc_history); GNUNET_free (kat); } @@ -497,6 +596,7 @@ TEH_kyc_run_measure_for_attributes ( const struct GNUNET_AsyncScopeId *scope, uint64_t process_row, const struct TALER_NormalizedPaytoHashP *account_id, + const char *provider_name, const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, @@ -514,6 +614,7 @@ TEH_kyc_run_measure_for_attributes ( kat = GNUNET_new (struct TEH_KycMeasureRunContext); kat->scope = *scope; + kat->provider_name = GNUNET_strdup (provider_name); kat->process_row = process_row; kat->account_id = *account_id; if (NULL != provider_user_id) @@ -525,8 +626,6 @@ TEH_kyc_run_measure_for_attributes ( kat->expiration = expiration; kat->cb = cb; kat->cb_cls = cb_cls; - kat->aml_history = json_array (); - kat->kyc_history = json_array (); kat->attributes = json_incref ((json_t*) new_attributes); qs = TEH_plugin->lookup_active_legitimization ( @@ -549,51 +648,17 @@ TEH_kyc_run_measure_for_attributes ( case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: break; } - - qs = TEH_plugin->lookup_aml_history ( - TEH_plugin->cls, - account_id, - &add_aml_history_entry, - kat->aml_history); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - TEH_kyc_run_measure_cancel (kat); - return NULL; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* empty history is fine! */ - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - qs = TEH_plugin->lookup_kyc_history ( - TEH_plugin->cls, - account_id, - &add_kyc_history_entry, - kat->kyc_history); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - TEH_kyc_run_measure_cancel (kat); - return NULL; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* empty history is fine! */ - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - kat->kyc_aml = TALER_KYCLOGIC_run_aml_program ( - kat->attributes, - kat->aml_history, - kat->kyc_history, kat->jmeasures, kat->measure_index, + kat->attributes, + &current_rule_builder_cb, + &kat->account_id, + &aml_history_builder_cb, + &kat->account_id, + &kyc_history_builder_cb, + &kat->account_id, &kyc_aml_finished, kat); @@ -643,7 +708,6 @@ TEH_kyc_run_measure_directly ( }; kat = GNUNET_new (struct TEH_KycMeasureRunContext); - kat->jmeasures = TALER_KYCLOGIC_measure_to_jmeasures (instant_ms); kat->provider_name = GNUNET_strdup ("SKIP"); kat->measure_index = 0; @@ -680,7 +744,9 @@ TEH_kyc_run_measure_directly ( break; } - if (0 != strcasecmp (instant_ms->check_name, "SKIP")) + if (0 != + strcasecmp (instant_ms->check_name, + "SKIP")) { /* Not an instant measure, it's enough to trigger it. The AMP will be run later. */ @@ -707,61 +773,18 @@ TEH_kyc_run_measure_directly ( return NULL; } - kat->aml_history = json_array (); - kat->kyc_history = json_array (); - qs = TEH_plugin->lookup_aml_history ( - TEH_plugin->cls, - account_id, - &add_aml_history_entry, - kat->aml_history); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - TEH_kyc_run_measure_cancel (kat); - return NULL; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* empty history is fine! */ - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - qs = TEH_plugin->lookup_kyc_history ( - TEH_plugin->cls, - account_id, - &add_kyc_history_entry, - kat->kyc_history); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - TEH_kyc_run_measure_cancel (kat); - return NULL; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* empty history is fine! */ - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - { - json_t *empty_attributes = json_object (); - - /* Attributes are in the aml_history. - No new attributes from instant measure. */ - - kat->kyc_aml - = TALER_KYCLOGIC_run_aml_program3 ( - instant_ms, - empty_attributes, - kat->aml_history, - kat->kyc_history, - &kyc_aml_finished, - kat); - - json_decref (empty_attributes); - } + kat->kyc_aml + = TALER_KYCLOGIC_run_aml_program3 ( + instant_ms, + NULL, /* no attributes */ + &current_rule_builder_cb, + &kat->account_id, + &aml_history_builder_cb, + &kat->account_id, + &kyc_history_builder_cb, + &kat->account_id, + &kyc_aml_finished, + kat); if (NULL == kat->kyc_aml) { GNUNET_break (0); @@ -877,7 +900,7 @@ handle_aml_fallback_result ( &fb->account_id, 0, GNUNET_TIME_timestamp_get (), - NULL, + "NONE", NULL, NULL, GNUNET_TIME_UNIT_FOREVER_ABS, @@ -888,7 +911,7 @@ handle_aml_fallback_result ( apr->details.success.events, 0 /* enc attr size */, NULL /* enc attr */); - if (qs <= 0) + if (qs < 0) { GNUNET_break (0); fb->cb (fb->cb_cls, @@ -936,8 +959,6 @@ TEH_kyc_fallback ( const struct TALER_NormalizedPaytoHashP *account_id, uint64_t orig_requirement_row, const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, const char *fallback_measure, TEH_KycAmlFallbackCallback cb, void *cb_cls) @@ -964,13 +985,18 @@ TEH_kyc_fallback ( { /* check was set to 'SKIP', run program immediately */ fb->aprh - = TALER_KYCLOGIC_run_aml_program2 (kcc.prog_name, - attributes, - aml_history, - kyc_history, - kcc.context, - &handle_aml_fallback_result, - fb); + = TALER_KYCLOGIC_run_aml_program2 ( + kcc.prog_name, + attributes, + kcc.context, + &current_rule_builder_cb, + &fb->account_id, + &aml_history_builder_cb, + &fb->account_id, + &kyc_history_builder_cb, + &fb->account_id, + &handle_aml_fallback_result, + fb); if (NULL == fb->aprh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, diff --git a/src/exchange/taler-exchange-httpd_common_kyc.h b/src/exchange/taler-exchange-httpd_common_kyc.h @@ -62,6 +62,7 @@ struct TEH_KycMeasureRunContext; * @param scope the HTTP request logging scope * @param process_row legitimization process the data provided is about * @param account_id account the the data provided is about + * @param provider_name name of the provider that provided the attributes * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown * @param expiration until when is the KYC check valid @@ -75,6 +76,7 @@ TEH_kyc_run_measure_for_attributes ( const struct GNUNET_AsyncScopeId *scope, uint64_t process_row, const struct TALER_NormalizedPaytoHashP *account_id, + const char *provider_name, const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, @@ -148,8 +150,6 @@ typedef void * @param orig_requirement_row original requirement * row that now triggered the fallback * @param attributes attributes to run with - * @param aml_history AML history of the account - * @param kyc_history KYC history of the account * @param fallback_measure fallback to activate * @param cb callback to call with result * @param cb_cls closure for @a cb @@ -162,8 +162,6 @@ TEH_kyc_fallback ( const struct TALER_NormalizedPaytoHashP *account_id, uint64_t orig_requirement_row, const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, const char *fallback_measure, TEH_KycAmlFallbackCallback cb, void *cb_cls); diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c @@ -296,6 +296,7 @@ respond_html_ec (struct TEH_RequestContext *rc, * * @param cls closure * @param status KYC status + * @param provider_name name of the provider * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown * @param expiration until when is the KYC check valid @@ -307,6 +308,7 @@ static void proof_cb ( void *cls, enum TALER_KYCLOGIC_KycStatus status, + const char *provider_name, const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, @@ -333,6 +335,7 @@ proof_cb ( &rc->async_scope_id, kpc->process_row, &kpc->h_payto, + provider_name, provider_user_id, provider_legitimization_id, expiration, diff --git a/src/exchange/taler-exchange-httpd_kyc-upload.c b/src/exchange/taler-exchange-httpd_kyc-upload.c @@ -597,6 +597,7 @@ TEH_handler_kyc_upload ( &rc->async_scope_id, legi_process_row, &h_payto, + "FORM", /* FIXME: get specific form name in DB interaction above! */ NULL /* provider account */, NULL /* provider legi ID */, GNUNET_TIME_UNIT_FOREVER_ABS, /* expiration time */ diff --git a/src/exchange/taler-exchange-httpd_kyc-webhook.c b/src/exchange/taler-exchange-httpd_kyc-webhook.c @@ -242,6 +242,7 @@ webhook_finished_cb ( &kwh->rc->async_scope_id, process_row, account_id, + provider_name, provider_user_id, provider_legitimization_id, expiration, diff --git a/src/exchangedb/pg_get_kyc_rules.c b/src/exchangedb/pg_get_kyc_rules.c @@ -91,3 +91,44 @@ TEH_PG_get_kyc_rules ( params, rs); } + + +enum GNUNET_DB_QueryStatus +TEH_PG_get_kyc_rules2 ( + void *cls, + const struct TALER_NormalizedPaytoHashP *h_payto, + json_t **jrules) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Timestamp now + = GNUNET_TIME_timestamp_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_allow_null ( + TALER_PQ_result_spec_json ("jnew_rules", + jrules), + NULL), + GNUNET_PQ_result_spec_end + }; + + *jrules = NULL; + PREPARE (pg, + "get_kyc_rules2", + "SELECT" + " jnew_rules" + " FROM legitimization_outcomes" + " WHERE h_payto=$1" + " AND expiration_time >= $2" + " AND is_active" + " ORDER BY expiration_time DESC" + " LIMIT 1;"); + return GNUNET_PQ_eval_prepared_singleton_select ( + pg->conn, + "get_kyc_rules2", + params, + rs); +} diff --git a/src/exchangedb/pg_get_kyc_rules.h b/src/exchangedb/pg_get_kyc_rules.h @@ -52,4 +52,20 @@ TEH_PG_get_kyc_rules ( struct TALER_ReservePublicKeyP *reserve_pub, json_t **jrules); + +/** + * Return only the KYC rules that apply to the given account. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param h_payto account identifier + * @param[out] jrules set to the active KYC rules for the + * given account, set to NULL if no custom rules are active + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TEH_PG_get_kyc_rules2 ( + void *cls, + const struct TALER_NormalizedPaytoHashP *h_payto, + json_t **jrules); + #endif diff --git a/src/exchangedb/pg_insert_kyc_measure_result.c b/src/exchangedb/pg_insert_kyc_measure_result.c @@ -115,8 +115,19 @@ TEH_PG_insert_kyc_measure_result ( GNUNET_free (kyc_completed_notify_s); GNUNET_PQ_event_do_poll (pg->conn); if (qs <= 0) + { + GNUNET_break (qs < 0); + GNUNET_break (0); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + GNUNET_break (0); + qs = GNUNET_DB_STATUS_HARD_ERROR; + } return qs; + } if (! ok) + { return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + } return qs; } diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c @@ -436,6 +436,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_select_aggregation_amounts_for_kyc_check; plugin->get_kyc_rules = &TEH_PG_get_kyc_rules; + plugin->get_kyc_rules2 + = &TEH_PG_get_kyc_rules2; plugin->kyc_provider_account_lookup = &TEH_PG_kyc_provider_account_lookup; plugin->lookup_kyc_process_by_account diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h @@ -7160,6 +7160,22 @@ struct TALER_EXCHANGEDB_Plugin /** + * Return just the KYC rules that apply to the given account. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param h_payto account identifier + * @param[out] jrules set to the active KYC rules for the + * given account, set to NULL if no custom rules are active + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*get_kyc_rules2)( + void *cls, + const struct TALER_NormalizedPaytoHashP *h_payto, + json_t **jrules); + + + /** * Call us on KYC legitimization processes satisfied and not expired for the * given account. * diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h @@ -823,6 +823,14 @@ TALER_KYCLOGIC_get_instant_measure ( /** + * Return default legitimization rule set in JSON. + * + * @return default legitimization rules + */ +const json_t * +TALER_KYCLOGIC_get_default_legi_rules (void); + +/** * Check if there is a measure in @a lrs that is named @a measure. * * @param lrs legitimization rule set @@ -951,17 +959,32 @@ typedef void /** + * Type of function called to obtain an AML or KYC + * history in JSON on-demand if needed. + * + * @param cls closure + * @return AML or KYC history in JSON format, NULL on error + */ +typedef json_t * +(*TALER_KYCLOGIC_HistoryBuilderCallback) (void *cls); + + +/** * Run AML program based on @a jmeasures using * the the given inputs. * - * @param attributes KYC attributes newly obtained - * @param aml_history AML history of the account - * @param kyc_history KYC history of the account * @param jmeasures current KYC/AML rules to apply; * they determine also the AML program and * provide the context * @param measure_index which KYC measure yielded the * @a attributes + * @param attributes KYC attributes newly obtained + * @param current_rules_cb callback to get current KYC rules that apply to the account + * @param current_rules_cb_cls closure for @a current_rules_cb + * @param aml_history_cb callback to get the AML history of the account + * @param aml_history_cb_cls closure for @a aml_history_cb + * @param kyc_history_cb callback to get the KYC history of the account + * @param kyc_history_cb_cls closure for @a aml_history_cb * @param aprc function to call with the result * @param aprc_cls closure for @a aprc * @return NULL if @a jmeasures is invalid for the @@ -969,11 +992,15 @@ typedef void */ struct TALER_KYCLOGIC_AmlProgramRunnerHandle * TALER_KYCLOGIC_run_aml_program ( - const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, const json_t *jmeasures, unsigned int measure_index, + const json_t *attributes, + TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, + void *current_rules_cls, + TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, + void *aml_history_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, + void *kyc_history_cb_cls, TALER_KYCLOGIC_AmlProgramResultCallback aprc, void *aprc_cls); @@ -983,9 +1010,13 @@ TALER_KYCLOGIC_run_aml_program ( * * @param prog_name name of AML program to run * @param attributes attributes to run with - * @param aml_history AML history of the account - * @param kyc_history KYC history of the account * @param context context to run with + * @param current_rules_cb callback to get current KYC rules that apply to the account + * @param current_rules_cb_cls closure for @a current_rules_cb + * @param aml_history_cb callback to get the AML history of the account + * @param aml_history_cb_cls closure for @a aml_history_cb + * @param kyc_history_cb callback to get the KYC history of the account + * @param kyc_history_cb_cls closure for @a aml_history_cb * @param aprc function to call with the result * @param aprc_cls closure for @a aprc * @return NULL if @a jmeasures is invalid for the @@ -995,9 +1026,13 @@ struct TALER_KYCLOGIC_AmlProgramRunnerHandle * TALER_KYCLOGIC_run_aml_program2 ( const char *prog_name, const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, const json_t *context, + TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, + void *current_rules_cls, + TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, + void *aml_history_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, + void *kyc_history_cb_cls, TALER_KYCLOGIC_AmlProgramResultCallback aprc, void *aprc_cls); @@ -1009,8 +1044,12 @@ TALER_KYCLOGIC_run_aml_program2 ( * @param measure measure with program name and context * to run * @param attributes attributes to run with - * @param aml_history AML history of the account - * @param kyc_history KYC history of the account + * @param current_rules_cb callback to get current KYC rules that apply to the account + * @param current_rules_cb_cls closure for @a current_rules_cb + * @param aml_history_cb callback to get the AML history of the account + * @param aml_history_cb_cls closure for @a aml_history_cb + * @param kyc_history_cb callback to get the KYC history of the account + * @param kyc_history_cb_cls closure for @a aml_history_cb * @param aprc function to call with the result * @param aprc_cls closure for @a aprc * @return NULL if @a jmeasures is invalid for the @@ -1020,8 +1059,12 @@ struct TALER_KYCLOGIC_AmlProgramRunnerHandle * TALER_KYCLOGIC_run_aml_program3 ( const struct TALER_KYCLOGIC_Measure *measure, const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, + TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, + void *current_rules_cls, + TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, + void *aml_history_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, + void *kyc_history_cb_cls, TALER_KYCLOGIC_AmlProgramResultCallback aprc, void *aprc_cls); diff --git a/src/include/taler_kyclogic_plugin.h b/src/include/taler_kyclogic_plugin.h @@ -160,6 +160,7 @@ typedef void * * @param cls closure * @param status KYC status + * @param provider_name name of the provider with the attributes * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown * @param attributes user attributes returned by the provider @@ -171,6 +172,7 @@ typedef void (*TALER_KYCLOGIC_ProofCallback)( void *cls, enum TALER_KYCLOGIC_KycStatus status, + const char *provider_name, const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c @@ -3965,11 +3965,15 @@ async_return_task (void *cls) struct TALER_KYCLOGIC_AmlProgramRunnerHandle * TALER_KYCLOGIC_run_aml_program ( - const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, const json_t *jmeasures, unsigned int measure_index, + const json_t *attributes, + TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, + void *current_rules_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, + void *aml_history_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, + void *kyc_history_cb_cls, TALER_KYCLOGIC_AmlProgramResultCallback aprc, void *aprc_cls) { @@ -3993,9 +3997,13 @@ TALER_KYCLOGIC_run_aml_program ( } return TALER_KYCLOGIC_run_aml_program2 (prog_name, attributes, - aml_history, - kyc_history, context, + current_rules_cb, + current_rules_cb_cls, + aml_history_cb, + aml_history_cb_cls, + kyc_history_cb, + kyc_history_cb_cls, aprc, aprc_cls); } @@ -4005,14 +4013,22 @@ struct TALER_KYCLOGIC_AmlProgramRunnerHandle * TALER_KYCLOGIC_run_aml_program2 ( const char *prog_name, const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, const json_t *context, + TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, + void *current_rules_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, + void *aml_history_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, + void *kyc_history_cb_cls, TALER_KYCLOGIC_AmlProgramResultCallback aprc, void *aprc_cls) { struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh; struct TALER_KYCLOGIC_AmlProgram *prog; + const json_t *jdefault_rules; + json_t *current_rules; + json_t *aml_history; + json_t *kyc_history; prog = find_program (prog_name); if (NULL == prog) @@ -4024,62 +4040,90 @@ TALER_KYCLOGIC_run_aml_program2 ( aprh->aprc = aprc; aprh->aprc_cls = aprc_cls; aprh->program = prog; - - for (unsigned int i = 0; i<prog->num_required_attributes; i++) + if (0 != (API_ATTRIBUTES & prog->input_mask)) { - const char *rattr = prog->required_attributes[i]; - - if (NULL == json_object_get (attributes, - rattr)) + for (unsigned int i = 0; i<prog->num_required_attributes; i++) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "KYC attributes lack required attribute `%s' for AML program %s\n", - rattr, - prog->program_name); - json_dumpf (attributes, - stderr, - JSON_INDENT (2)); - aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; - aprh->apr.details.failure.fallback_measure - = prog->fallback; - aprh->apr.details.failure.error_message - = rattr; - aprh->apr.details.failure.ec - = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_REPLY; - aprh->async_cb - = GNUNET_SCHEDULER_add_now (&async_return_task, - aprh); - return aprh; + const char *rattr = prog->required_attributes[i]; + + if (NULL == json_object_get (attributes, + rattr)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "KYC attributes lack required attribute `%s' for AML program %s\n", + rattr, + prog->program_name); + json_dumpf (attributes, + stderr, + JSON_INDENT (2)); + aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; + aprh->apr.details.failure.fallback_measure + = prog->fallback; + aprh->apr.details.failure.error_message + = rattr; + aprh->apr.details.failure.ec + = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_REPLY; + aprh->async_cb + = GNUNET_SCHEDULER_add_now (&async_return_task, + aprh); + return aprh; + } } } - for (unsigned int i = 0; i<prog->num_required_contexts; i++) + else { - const char *rctx = prog->required_contexts[i]; - - if (NULL == json_object_get (context, - rctx)) + attributes = NULL; + } + if (0 != (API_CONTEXT & prog->input_mask)) + { + for (unsigned int i = 0; i<prog->num_required_contexts; i++) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Context lacks required field `%s' for AML program %s\n", - rctx, - prog->program_name); - json_dumpf (context, - stderr, - JSON_INDENT (2)); - aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; - aprh->apr.details.failure.fallback_measure - = prog->fallback; - aprh->apr.details.failure.error_message - = rctx; - aprh->apr.details.failure.ec - = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_CONTEXT; - aprh->async_cb - = GNUNET_SCHEDULER_add_now (&async_return_task, - aprh); - return aprh; + const char *rctx = prog->required_contexts[i]; + + if (NULL == json_object_get (context, + rctx)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Context lacks required field `%s' for AML program %s\n", + rctx, + prog->program_name); + json_dumpf (context, + stderr, + JSON_INDENT (2)); + aprh->apr.status = TALER_KYCLOGIC_AMLR_FAILURE; + aprh->apr.details.failure.fallback_measure + = prog->fallback; + aprh->apr.details.failure.error_message + = rctx; + aprh->apr.details.failure.ec + = TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_INCOMPLETE_CONTEXT; + aprh->async_cb + = GNUNET_SCHEDULER_add_now (&async_return_task, + aprh); + return aprh; + } } } - + else + { + context = NULL; + } + if (0 == (API_AML_HISTORY & prog->input_mask)) + aml_history = NULL; + else + aml_history = aml_history_cb (aml_history_cb_cls); + if (0 == (API_KYC_HISTORY & prog->input_mask)) + kyc_history = NULL; + else + kyc_history = kyc_history_cb (kyc_history_cb_cls); + if (0 == (API_CURRENT_RULES & prog->input_mask)) + current_rules = NULL; + else + current_rules = current_rules_cb (current_rules_cb_cls); + if (0 != (API_DEFAULT_RULES & prog->input_mask)) + jdefault_rules = default_rules.jlrs; + else + jdefault_rules = NULL; { json_t *input; const char *extra_args[] = { @@ -4087,24 +4131,33 @@ TALER_KYCLOGIC_run_aml_program2 ( cfg_filename, NULL, }; - char **args; input = GNUNET_JSON_PACK ( GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_steal ("current_rules", + current_rules)), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("default_rules", + (json_t *) jdefault_rules)), + GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_incref ("context", (json_t *) context)), - GNUNET_JSON_pack_object_incref ("attributes", - (json_t *) attributes), - GNUNET_JSON_pack_array_incref ("aml_history", - (json_t *) aml_history), - GNUNET_JSON_pack_array_incref ("kyc_history", - (json_t *) kyc_history) + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("attributes", + (json_t *) attributes)), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_array_steal ("aml_history", + aml_history)), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_array_steal ("kyc_history", + kyc_history)) ); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running AML program %s\n", prog->command); - args = split_words (prog->command, extra_args); + args = split_words (prog->command, + extra_args); GNUNET_assert (NULL != args); GNUNET_assert (NULL != args[0]); json_dumpf (input, @@ -4127,17 +4180,25 @@ struct TALER_KYCLOGIC_AmlProgramRunnerHandle * TALER_KYCLOGIC_run_aml_program3 ( const struct TALER_KYCLOGIC_Measure *measure, const json_t *attributes, - const json_t *aml_history, - const json_t *kyc_history, + TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb, + void *current_rules_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb, + void *aml_history_cb_cls, + TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb, + void *kyc_history_cb_cls, TALER_KYCLOGIC_AmlProgramResultCallback aprc, void *aprc_cls) { return TALER_KYCLOGIC_run_aml_program2 ( measure->prog_name, attributes, - aml_history, - kyc_history, measure->context, + current_rules_cb, + current_rules_cb_cls, + aml_history_cb, + aml_history_cb_cls, + kyc_history_cb, + kyc_history_cb_cls, aprc, aprc_cls); } @@ -4230,4 +4291,11 @@ TALER_KYCLOGIC_get_zero_limits () } +const json_t * +TALER_KYCLOGIC_get_default_legi_rules () +{ + return default_rules.jlrs; +} + + /* end of kyclogic_api.c */ diff --git a/src/kyclogic/plugin_kyclogic_kycaid.c b/src/kyclogic/plugin_kyclogic_kycaid.c @@ -692,6 +692,7 @@ proof_reply (void *cls) GNUNET_break (GNUNET_SYSERR != ret); ph->cb (ph->cb_cls, TALER_KYCLOGIC_STATUS_PROVIDER_FAILED, + ph->pd->section, NULL, /* user id */ NULL, /* provider legi ID */ GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */ diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -899,6 +899,7 @@ return_proof_response (void *cls) ph->task = NULL; ph->cb (ph->cb_cls, ph->status, + ph->pd->section, ph->provider_user_id, ph->provider_legitimization_id, GNUNET_TIME_relative_to_absolute (ph->pd->validity), diff --git a/src/kyclogic/plugin_kyclogic_persona.c b/src/kyclogic/plugin_kyclogic_persona.c @@ -936,6 +936,7 @@ proof_generic_reply (struct TALER_KYCLOGIC_ProofHandle *ph, } ph->cb (ph->cb_cls, status, + ph->pd->section, account_id, inquiry_id, GNUNET_TIME_UNIT_ZERO_ABS, @@ -1088,6 +1089,7 @@ proof_post_conversion_cb (void *cls, TALER_MHD_add_global_headers (resp); ph->cb (ph->cb_cls, TALER_KYCLOGIC_STATUS_SUCCESS, + ph->pd->section, ph->account_id, ph->inquiry_id, expiration, diff --git a/src/kyclogic/taler-exchange-helper-measure-freeze b/src/kyclogic/taler-exchange-helper-measure-freeze @@ -154,7 +154,16 @@ jq -n \ "is_and_combinator" : true }, { - "operation_type": "AGE-WITHDRAW", + "operation_type": "TRANSACTION", + "threshold" : "EUR:0", + "timeframe" : { "d_us" : 3600000000 }, + "measures" : [ "verboten" ], + "display_priority" : 1, + "exposed" : false, + "is_and_combinator" : true + }, + { + "operation_type": "REFUND", "threshold" : "EUR:0", "timeframe" : { "d_us" : 3600000000 }, "measures" : [ "verboten" ], diff --git a/src/kyclogic/taler-exchange-helper-measure-test-form b/src/kyclogic/taler-exchange-helper-measure-test-form @@ -57,7 +57,8 @@ do exit 0 ;; i) - # No Inputs are required. + # Attributes are required. + echo "attributes" exit 0 ;; r) diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c @@ -730,6 +730,7 @@ static void proof_cb ( void *cls, enum TALER_KYCLOGIC_KycStatus status, + const char *provider_name, const char *provider_user_id, const char *provider_legitimization_id, struct GNUNET_TIME_Absolute expiration, @@ -740,6 +741,7 @@ proof_cb ( struct ProofRequestState *rs = cls; (void) expiration; + (void) provider_name; GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "KYC legitimization %s completed with status %d (%u) for %s\n", provider_legitimization_id,