diff options
author | Florian Dold <florian@dold.me> | 2024-11-08 19:56:02 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-11-08 19:56:02 +0100 |
commit | 7f6a2ac5ab8fcd343a089d2029c0cc337018729e (patch) | |
tree | 1dc7eaf431f18492368810ceb0fcd9b79fda6690 | |
parent | a24a576338f2da8eae1d235c98e6d66d40e8bf6e (diff) |
handle successor measures in kyc-info
-rw-r--r-- | src/exchange/taler-exchange-httpd_common_kyc.c | 83 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_kyc-info.c | 136 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_kyc_measure_result.c | 1 | ||||
-rw-r--r-- | src/include/taler_kyclogic_lib.h | 4 | ||||
-rw-r--r-- | src/kyclogic/kyclogic_api.c | 14 |
5 files changed, 186 insertions, 52 deletions
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c index 24775845b..edc8bd9f4 100644 --- a/src/exchange/taler-exchange-httpd_common_kyc.c +++ b/src/exchange/taler-exchange-httpd_common_kyc.c @@ -186,8 +186,8 @@ kyc_aml_finished ( { struct TEH_KycMeasureRunContext *kat = cls; enum GNUNET_DB_QueryStatus qs; - size_t eas; - void *ea; + size_t eas = 0; + void *ea = NULL; unsigned int birthday = 0; struct GNUNET_AsyncScopeSave old_scope; @@ -280,10 +280,14 @@ kyc_aml_finished ( } } - TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key, - kat->attributes, - &ea, - &eas); + if (NULL != kat->attributes) + { + TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key, + kat->attributes, + &ea, + &eas); + } + qs = TEH_plugin->insert_kyc_measure_result ( TEH_plugin->cls, kat->process_row, @@ -631,7 +635,6 @@ TEH_kyc_run_measure_directly ( void *cb_cls) { struct TEH_KycMeasureRunContext *kat; - uint64_t process_row; uint64_t legi_measure_serial_id; bool bad_kyc_auth; enum GNUNET_DB_QueryStatus qs; @@ -645,7 +648,6 @@ TEH_kyc_run_measure_directly ( kat->provider_name = GNUNET_strdup ("SKIP"); kat->measure_index = 0; kat->scope = *scope; - kat->process_row = process_row; kat->account_id = *account_id; kat->expiration = GNUNET_TIME_UNIT_FOREVER_ABS; kat->cb = cb; @@ -668,17 +670,16 @@ TEH_kyc_run_measure_directly ( 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: GNUNET_break (0); + TEH_kyc_run_measure_cancel (kat); return NULL; case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: break; } - /* We're not checking kyc auth, so it can't be bad. */ - GNUNET_assert (! bad_kyc_auth); - if (0 != strcasecmp (instant_ms->check_name, "SKIP")) { /* Not an instant measure, it's enough to trigger it. @@ -698,16 +699,14 @@ TEH_kyc_run_measure_directly ( "SKIP", NULL, /* provider_account_id */ NULL, /* provider_legitimziation_id */ - &process_row); + &kat->process_row); if (qs < 0) { GNUNET_break (0); + TEH_kyc_run_measure_cancel (kat); return NULL; } - /* FIXME(fdold, 2024-11-07): - We need to look up the attributes before running the AMP. */ - kat->aml_history = json_array (); kat->kyc_history = json_array (); qs = TEH_plugin->lookup_aml_history ( @@ -746,14 +745,23 @@ TEH_kyc_run_measure_directly ( case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: break; } - kat->kyc_aml - = TALER_KYCLOGIC_run_aml_program3 ( - instant_ms, - kat->attributes, - kat->aml_history, - kat->kyc_history, - &kyc_aml_finished, - kat); + { + 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); + } if (NULL == kat->kyc_aml) { GNUNET_break (0); @@ -827,8 +835,6 @@ handle_aml_fallback_result ( const struct TALER_KYCLOGIC_AmlProgramResult *apr) { struct TEH_KycAmlFallback *fb = cls; - size_t eas; - void *ea; enum GNUNET_DB_QueryStatus qs; struct GNUNET_AsyncScopeSave old_scope; @@ -865,18 +871,6 @@ handle_aml_fallback_result ( return; } - { - json_t *attributes; - - /* empty attributes for fallback */ - attributes = json_object (); - GNUNET_assert (NULL != attributes); - TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key, - attributes, - &ea, - &eas); - json_decref (attributes); - } qs = TEH_plugin->insert_kyc_measure_result ( TEH_plugin->cls, fb->orig_requirement_row, @@ -892,9 +886,8 @@ handle_aml_fallback_result ( apr->details.success.to_investigate, apr->details.success.num_events, apr->details.success.events, - eas, - ea); - GNUNET_free (ea); + 0 /* enc attr size */, + NULL /* enc attr */); if (qs <= 0) { GNUNET_break (0); @@ -1575,6 +1568,7 @@ legitimization_check_run ( } } + /* Check if ruleset is expired and we need to run the successor measure */ if (NULL != lrs) { struct GNUNET_TIME_Timestamp ts; @@ -1582,18 +1576,17 @@ legitimization_check_run ( ts = TALER_KYCLOGIC_rules_get_expiration (lrs); if (GNUNET_TIME_absolute_is_past (ts.abs_time)) { - const char *successor; const struct TALER_KYCLOGIC_Measure *successor_measure; - successor - = TALER_KYCLOGIC_rules_get_successor (lrs); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Current KYC ruleset expired, running successor measure.\n"); - successor_measure = TALER_KYCLOGIC_get_measure (lrs, successor); + successor_measure = TALER_KYCLOGIC_rules_get_successor (lrs); if (NULL == successor_measure) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successor measure `%s' unknown, falling back to default rules!\n", - successor); + successor_measure->measure_name); TALER_KYCLOGIC_rules_free (lrs); lrs = NULL; } diff --git a/src/exchange/taler-exchange-httpd_kyc-info.c b/src/exchange/taler-exchange-httpd_kyc-info.c index f47ac0c6e..4b0689c07 100644 --- a/src/exchange/taler-exchange-httpd_kyc-info.c +++ b/src/exchange/taler-exchange-httpd_kyc-info.c @@ -32,10 +32,13 @@ #include "taler-exchange-httpd_keys.h" #include "taler-exchange-httpd_kyc-info.h" #include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd_common_kyc.h" /** - * Reserve GET request that is long-polling. + * Context for the GET /kyc-info request. + * + * Used for long-polling and other asynchronous waiting. */ struct KycPoller { @@ -93,6 +96,21 @@ struct KycPoller */ bool suspended; + /** + * Handle for async KYC processing. + */ + struct TEH_KycMeasureRunContext *kat; + + /** + * HTTP status code to use with @e response. + */ + unsigned int response_code; + + /** + * Response to return, NULL if none yet. + */ + struct MHD_Response *response; + }; @@ -146,6 +164,16 @@ kyp_cleanup (struct TEH_RequestContext *rc) kyp->eh); kyp->eh = NULL; } + if (NULL != kyp->response) + { + MHD_destroy_response (kyp->response); + kyp->response = NULL; + } + if (NULL != kyp->kat) + { + TEH_kyc_run_measure_cancel (kyp->kat); + kyp->kat = NULL; + } GNUNET_free (kyp); } @@ -405,6 +433,48 @@ contains_instant_measure (const json_t *jmeasures) } +/** + * Function called after a measure has been run. + * + * @param cls closure + * @param ec error code or 0 on success + * @param detail error message or NULL on success / no info + */ +static void +measure_run_cb ( + void *cls, + enum TALER_ErrorCode ec, + const char *detail) +{ + struct KycPoller *kyp = cls; + + GNUNET_assert (kyp->suspended); + GNUNET_assert (NULL == kyp->response); + GNUNET_assert (NULL != kyp->kat); + + kyp->kat = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Resuming after running successor measure, ec=%u\n", + (unsigned int) ec); + + if (TALER_EC_NONE != ec) + { + kyp->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + kyp->response = TALER_MHD_make_error ( + ec, + detail); + } + + GNUNET_CONTAINER_DLL_remove (kyp_head, + kyp_tail, + kyp); + kyp->suspended = false; + MHD_resume_connection (kyp->connection); + TALER_MHD_daemon_trigger (); +} + + MHD_RESULT TEH_handler_kyc_info ( struct TEH_RequestContext *rc, @@ -521,6 +591,14 @@ TEH_handler_kyc_info ( } } /* end of one-time initialization */ + if (NULL != kyp->response) + { + res = MHD_queue_response (rc->connection, + kyp->response_code, + kyp->response); + goto cleanup; + } + /* Get rules. */ { json_t *jnew_rules; @@ -552,6 +630,62 @@ TEH_handler_kyc_info ( } } + /* Check if ruleset is expired and we need to run the successor measure */ + if (NULL != lrs) + { + struct GNUNET_TIME_Timestamp ts; + + ts = TALER_KYCLOGIC_rules_get_expiration (lrs); + if (GNUNET_TIME_absolute_is_past (ts.abs_time)) + { + const struct TALER_KYCLOGIC_Measure *successor_measure; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Current KYC ruleset expired, running successor measure.\n"); + + successor_measure = TALER_KYCLOGIC_rules_get_successor (lrs); + if (NULL == successor_measure) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Successor measure `%s' unknown, falling back to default rules!\n", + successor_measure->measure_name); + TALER_KYCLOGIC_rules_free (lrs); + lrs = NULL; + } + else + { + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Running successor measure %s.\n", successor_measure-> + measure_name); + /* FIXME(fdold, 2024-01-08): Consider limiting how + often we try this, in case we run into expired rulesets + repeatedly. */ + kyp->kat = TEH_kyc_run_measure_directly ( + &rc->async_scope_id, + successor_measure, + &kyp->h_payto, + &measure_run_cb, + kyp); + if (NULL == kyp->kat) + { + GNUNET_break (0); + res = TALER_MHD_reply_with_ec ( + rc->connection, + TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE, + "successor measure"); + } + kyp->suspended = true; + GNUNET_CONTAINER_DLL_insert (kyp_head, + kyp_tail, + kyp); + MHD_suspend_connection (rc->connection); + res = MHD_YES; + goto cleanup; + } + } + } + jvoluntary = TALER_KYCLOGIC_voluntary_measures (lrs); diff --git a/src/exchangedb/pg_insert_kyc_measure_result.c b/src/exchangedb/pg_insert_kyc_measure_result.c index 1ddf1f6d4..24e78f014 100644 --- a/src/exchangedb/pg_insert_kyc_measure_result.c +++ b/src/exchangedb/pg_insert_kyc_measure_result.c @@ -99,7 +99,6 @@ TEH_PG_insert_kyc_measure_result ( kyc_completed_notify_s); GNUNET_break (NULL != new_rules); GNUNET_break (NULL != h_payto); - GNUNET_break (NULL != enc_attributes); PREPARE (pg, "insert_kyc_measure_result", "SELECT " diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h index a6025c738..009c436b7 100644 --- a/src/include/taler_kyclogic_lib.h +++ b/src/include/taler_kyclogic_lib.h @@ -733,11 +733,11 @@ TALER_KYCLOGIC_rules_get_expiration ( * Return successor measure for the given @a lrs * * @param lrs legitimization rules to inspect - * @return name of the successor measure; + * @return successor measure; * NULL to fall back to default rules; * pointer will be valid as long as @a lrs is valid */ -const char * +const struct TALER_KYCLOGIC_Measure * TALER_KYCLOGIC_rules_get_successor ( const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs); diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c index d8925e1e1..825282021 100644 --- a/src/kyclogic/kyclogic_api.c +++ b/src/kyclogic/kyclogic_api.c @@ -277,11 +277,19 @@ TALER_KYCLOGIC_rules_get_expiration ( } -const char * +const struct TALER_KYCLOGIC_Measure * TALER_KYCLOGIC_rules_get_successor ( const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs) { - return lrs->successor_measure; + const char *successor_measure_name = lrs->successor_measure; + + if (NULL == successor_measure_name) + { + return NULL; + } + return TALER_KYCLOGIC_get_measure ( + lrs, + successor_measure_name); } @@ -1337,7 +1345,7 @@ TALER_KYCLOGIC_measure_to_jmeasures ( GNUNET_JSON_pack_array_steal ("measures", jmeasures), GNUNET_JSON_pack_bool ("is_and_combinator", - true), + false), GNUNET_JSON_pack_bool ("verboten", false)); } |