aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-11-08 19:56:02 +0100
committerFlorian Dold <florian@dold.me>2024-11-08 19:56:02 +0100
commit7f6a2ac5ab8fcd343a089d2029c0cc337018729e (patch)
tree1dc7eaf431f18492368810ceb0fcd9b79fda6690
parenta24a576338f2da8eae1d235c98e6d66d40e8bf6e (diff)
handle successor measures in kyc-info
-rw-r--r--src/exchange/taler-exchange-httpd_common_kyc.c83
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-info.c136
-rw-r--r--src/exchangedb/pg_insert_kyc_measure_result.c1
-rw-r--r--src/include/taler_kyclogic_lib.h4
-rw-r--r--src/kyclogic/kyclogic_api.c14
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));
}