diff options
author | Florian Dold <florian@dold.me> | 2024-11-08 21:49:22 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-11-10 02:33:55 +0100 |
commit | 63bb33a5bd01a459d2a8996119346dad34209df4 (patch) | |
tree | fc6eeb980743fa4e932eda9c485820f854f41685 | |
parent | 2d01575f5810be410e49564288268671945eb625 (diff) |
towards handling non-instant successor measures
-rw-r--r-- | src/exchange/taler-exchange-httpd_common_kyc.c | 52 | ||||
-rw-r--r-- | src/exchangedb/Makefile.am | 1 | ||||
-rw-r--r-- | src/exchangedb/exchange_do_insert_successor_measure.sql | 156 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_aml_decision.c | 20 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_successor_measure.c | 88 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_successor_measure.h | 39 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 3 | ||||
-rw-r--r-- | src/exchangedb/procedures.sql.in | 1 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 14 |
9 files changed, 363 insertions, 11 deletions
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c index edc8bd9f4..d5766e5ba 100644 --- a/src/exchange/taler-exchange-httpd_common_kyc.c +++ b/src/exchange/taler-exchange-httpd_common_kyc.c @@ -1568,6 +1568,9 @@ legitimization_check_run ( } } + /* FIXME(fdold, 2024-11-08): We are doing the same logic + here and in kyc-info, abstract it out? */ + /* Check if ruleset is expired and we need to run the successor measure */ if (NULL != lrs) { @@ -1590,7 +1593,7 @@ legitimization_check_run ( TALER_KYCLOGIC_rules_free (lrs); lrs = NULL; } - else + else if (0 == strcmp (successor_measure->prog_name, "SKIP")) { lch->measure_run_ctx = TEH_kyc_run_measure_directly ( &lch->scope, @@ -1606,6 +1609,53 @@ legitimization_check_run ( } goto cleanup; } + else + { + bool unknown_account; + struct GNUNET_TIME_Timestamp decision_time + = GNUNET_TIME_timestamp_get (); + struct GNUNET_TIME_Timestamp last_date; + json_t *succ_jmeasures = TALER_KYCLOGIC_get_jmeasures ( + lrs, + successor_measure->measure_name); + + GNUNET_assert (NULL != succ_jmeasures); + qs = TEH_plugin->insert_successor_measure ( + TEH_plugin->cls, + &lch->h_payto, + decision_time, + successor_measure->measure_name, + succ_jmeasures, + &unknown_account, + &last_date); + json_decref (succ_jmeasures); + if (qs <= 0) + { + legi_fail (lch, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert_successor_measure"); + goto cleanup; + } + if (unknown_account) + { + legi_fail (lch, + TALER_EC_EXCHANGE_GENERIC_BANK_ACCOUNT_UNKNOWN, + NULL); + goto cleanup; + } + if (GNUNET_TIME_timestamp_cmp (last_date, + >=, + decision_time)) + { + legi_fail (lch, + TALER_EC_EXCHANGE_AML_DECISION_MORE_RECENT_PRESENT, + "later decision exists"); + goto cleanup; + } + /* Back to default rules. */ + TALER_KYCLOGIC_rules_free (lrs); + lrs = NULL; + } } } diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index f34573724..138c0882d 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -195,6 +195,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_lookup_completed_legitimization.h pg_lookup_completed_legitimization.c \ pg_lookup_active_legitimization.h pg_lookup_active_legitimization.c \ pg_insert_aml_decision.h pg_insert_aml_decision.c \ + pg_insert_successor_measure.h pg_insert_successor_measure.c \ pg_select_aggregation_transient.h pg_select_aggregation_transient.c \ pg_find_aggregation_transient.h pg_find_aggregation_transient.c \ pg_update_aggregation_transient.h pg_update_aggregation_transient.c \ diff --git a/src/exchangedb/exchange_do_insert_successor_measure.sql b/src/exchangedb/exchange_do_insert_successor_measure.sql new file mode 100644 index 000000000..a98a6c4a8 --- /dev/null +++ b/src/exchangedb/exchange_do_insert_successor_measure.sql @@ -0,0 +1,156 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2023, 2024 Taler Systems SA +-- +-- TALER is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +-- + +DROP FUNCTION IF EXISTS exchange_do_insert_successor_measure; +CREATE FUNCTION exchange_do_insert_successor_measure( + IN in_h_normalized_payto BYTEA, + IN in_decision_time INT8, + IN in_expiration_time INT8, + IN in_new_measure_name TEXT, -- can be NULL + IN in_jmeasures TEXT, -- can be NULL + OUT out_last_date INT8, + OUT out_account_unknown BOOLEAN, +) +LANGUAGE plpgsql +AS $$ +DECLARE + my_outcome_serial_id INT8; + my_access_token BYTEA; +BEGIN + +out_account_unknown=FALSE; +out_legitimization_measure_serial_id=0; + +-- Check no more recent decision exists. +SELECT decision_time + INTO out_last_date + FROM legitimization_outcomes + WHERE h_payto=in_h_normalized_payto + AND is_active + ORDER BY decision_time DESC; + +IF FOUND +THEN + IF out_last_date >= in_decision_time + THEN + -- Refuse to insert older decision. + RETURN; + END IF; + UPDATE legitimization_outcomes + SET is_active=FALSE + WHERE h_payto=in_h_normalized_payto + AND is_active; +ELSE + out_last_date = 0; +END IF; + +SELECT access_token + INTO my_access_token + FROM wire_targets + WHERE h_normalized_payto=in_h_normalized_payto; + +IF NOT FOUND +THEN + IF in_payto_uri IS NULL + THEN + -- AML decision on an unknown account without payto_uri => fail. + out_account_unknown=TRUE; + RETURN; + END IF; + + INSERT INTO wire_targets + (wire_target_h_payto + ,h_normalized_payto + ,payto_uri) + VALUES + (in_h_full_payto + ,in_h_normalized_payto + ,in_payto_uri) + RETURNING access_token + INTO my_access_token; +END IF; + + +-- First check if a perfectly equivalent legi measure +-- already exists, to avoid creating tons of duplicates. +SELECT legitimization_measure_serial_id + INTO out_legitimization_measure_serial_id + FROM legitimization_measures + WHERE access_token=my_access_token + AND jmeasures=in_jmeasures + AND NOT is_finished; + +IF NOT FOUND +THEN + -- Enable new legitimization measure + INSERT INTO legitimization_measures + (access_token + ,start_time + ,jmeasures + ,display_priority) + VALUES + (my_access_token + ,in_decision_time + ,in_jmeasures + ,1) + RETURNING + legitimization_measure_serial_id + INTO + out_legitimization_measure_serial_id; +END IF; + +-- AML decision: mark all other active measures finished! +UPDATE legitimization_measures + SET is_finished=TRUE + WHERE access_token=my_access_token + AND NOT is_finished + AND legitimization_measure_serial_id != out_legitimization_measure_serial_id; + +UPDATE legitimization_outcomes + SET is_active=FALSE + WHERE h_payto=in_h_normalized_payto + -- this clause is a minor optimization to avoid + -- updating outcomes that have long expired. + AND expiration_time >= in_decision_time; + +INSERT INTO legitimization_outcomes + (h_payto + ,decision_time + ,expiration_time + ,jproperties + ,new_measure_name + ,to_investigate + ,jnew_rules + ) + VALUES + (in_h_normalized_payto + ,in_decision_time + ,in_expiration_time + ,'{}' + ,in_new_measure_name + ,FALSE + ,in_new_rules + ) + RETURNING + outcome_serial_id + INTO + my_outcome_serial_id; + +END $$; + + +COMMENT ON FUNCTION exchange_do_insert_successor_measure(BYTEA, INT8, INT8, TEXT, TEXT, INT8) + IS 'Checks whether the AML officer is eligible to make AML decisions and if so inserts the decision into the table'; diff --git a/src/exchangedb/pg_insert_aml_decision.c b/src/exchangedb/pg_insert_aml_decision.c index 26fa329e8..7109eaa75 100644 --- a/src/exchangedb/pg_insert_aml_decision.c +++ b/src/exchangedb/pg_insert_aml_decision.c @@ -58,25 +58,25 @@ TEH_PG_insert_aml_decision ( = GNUNET_PQ_get_event_notify_channel (&rep.header); struct GNUNET_PQ_QueryParam params[] = { NULL == payto_uri.full_payto - ? GNUNET_PQ_query_param_null () - : GNUNET_PQ_query_param_string (payto_uri.full_payto), + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_string (payto_uri.full_payto), GNUNET_PQ_query_param_auto_from_type (h_payto), NULL == payto_uri.full_payto - ? GNUNET_PQ_query_param_null () - : GNUNET_PQ_query_param_auto_from_type (&h_full_payto), + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_auto_from_type (&h_full_payto), GNUNET_PQ_query_param_timestamp (&decision_time), GNUNET_PQ_query_param_timestamp (&expiration_time), NULL != properties - ? TALER_PQ_query_param_json (properties) - : GNUNET_PQ_query_param_null (), + ? TALER_PQ_query_param_json (properties) + : GNUNET_PQ_query_param_null (), TALER_PQ_query_param_json (new_rules), GNUNET_PQ_query_param_bool (to_investigate), NULL != new_measure_name - ? GNUNET_PQ_query_param_string (new_measure_name) - : GNUNET_PQ_query_param_null (), + ? GNUNET_PQ_query_param_string (new_measure_name) + : GNUNET_PQ_query_param_null (), NULL != jmeasures - ? TALER_PQ_query_param_json (jmeasures) - : GNUNET_PQ_query_param_null (), + ? TALER_PQ_query_param_json (jmeasures) + : GNUNET_PQ_query_param_null (), GNUNET_PQ_query_param_string (justification), GNUNET_PQ_query_param_auto_from_type (decider_pub), GNUNET_PQ_query_param_auto_from_type (decider_sig), diff --git a/src/exchangedb/pg_insert_successor_measure.c b/src/exchangedb/pg_insert_successor_measure.c new file mode 100644 index 000000000..0be070bdd --- /dev/null +++ b/src/exchangedb/pg_insert_successor_measure.c @@ -0,0 +1,88 @@ +/* + This file is part of TALER + Copyright (C) 2022, 2023, 2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/pg_insert_succesor_measure.c + * @brief Implementation of the insert_succesor_measure function for Postgres + * @author Florian Dold + */ +#include "platform.h" +#include "taler_error_codes.h" +#include "taler_dbevents.h" +#include "taler_pq_lib.h" +#include "pg_insert_successor_measure.h" +#include "pg_helper.h" +#include <gnunet/gnunet_pq_lib.h> + + +enum GNUNET_DB_QueryStatus +TEH_PG_insert_successor_measure ( + void *cls, + const struct TALER_NormalizedPaytoHashP *h_payto, + struct GNUNET_TIME_Timestamp decision_time, + const char *new_measure_name, + const json_t *jmeasures, + bool *unknown_account, + struct GNUNET_TIME_Timestamp *last_date) +{ + struct PostgresClosure *pg = cls; + struct TALER_KycCompletedEventP rep = { + .header.size = htons (sizeof (rep)), + .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED), + .h_payto = *h_payto + }; + /* We're reverting back to default rules => never expires.*/ + struct GNUNET_TIME_Timestamp expiration_time = { + .abs_time = GNUNET_TIME_UNIT_FOREVER_ABS, + }; + struct TALER_FullPaytoHashP h_full_payto; + char *notify_s + = GNUNET_PQ_get_event_notify_channel (&rep.header); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_timestamp (&decision_time), + GNUNET_PQ_query_param_timestamp (&expiration_time), + NULL != new_measure_name + ? GNUNET_PQ_query_param_string (new_measure_name) + : GNUNET_PQ_query_param_null (), + NULL != jmeasures + ? TALER_PQ_query_param_json (jmeasures) + : GNUNET_PQ_query_param_null (), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("out_account_unknown", + unknown_account), + GNUNET_PQ_result_spec_timestamp ("out_last_date", + last_date), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_DB_QueryStatus qs; + + PREPARE (pg, + "do_insert_successor_measure", + "SELECT" + ",out_account_unknown" + ",out_last_date" + " FROM exchange_do_insert_successor_measure" + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);"); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "do_insert_successor_measure", + params, + rs); + GNUNET_free (notify_s); + GNUNET_PQ_event_do_poll (pg->conn); + return qs; +} diff --git a/src/exchangedb/pg_insert_successor_measure.h b/src/exchangedb/pg_insert_successor_measure.h new file mode 100644 index 000000000..e817822aa --- /dev/null +++ b/src/exchangedb/pg_insert_successor_measure.h @@ -0,0 +1,39 @@ +/* + This file is part of TALER + Copyright (C) 2022, 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/pg_insert_successor_measure.h + * @brief implementation of the insert_successor_measure function for Postgres + * @author Florian Dold + */ +#ifndef PG_INSERT_SUCCESSOR_MEASURE_H +#define PG_INSERT_SUCCESSOR_MEASURE_H + +#include "taler_util.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" + +enum GNUNET_DB_QueryStatus +TEH_PG_insert_successor_measure ( + void *cls, + const struct TALER_NormalizedPaytoHashP *h_payto, + struct GNUNET_TIME_Timestamp decision_time, + const char *new_measure_name, + const json_t *jmeasures, + bool *unknown_account, + struct GNUNET_TIME_Timestamp *last_date); + + +#endif diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 4648520f5..7626759e2 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -228,6 +228,7 @@ #include "pg_lookup_aml_officer.h" #include "pg_lookup_kyc_requirement_by_row.h" #include "pg_insert_aml_decision.h" +#include "pg_insert_successor_measure.h" #include "pg_batch_ensure_coin_known.h" #include "plugin_exchangedb_postgres.h" @@ -826,6 +827,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_batch_ensure_coin_known; plugin->inject_auditor_triggers = &TEH_PG_inject_auditor_triggers; + plugin->insert_successor_measure + = &TEH_PG_insert_successor_measure; return plugin; } diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in index 9adb1ef3b..bd6dd27fa 100644 --- a/src/exchangedb/procedures.sql.in +++ b/src/exchangedb/procedures.sql.in @@ -44,6 +44,7 @@ SET search_path TO exchange; #include "exchange_do_reserve_open.sql" #include "exchange_do_insert_or_update_policy_details.sql" #include "exchange_do_insert_aml_decision.sql" +#include "exchange_do_insert_successor_measure.sql" #include "exchange_do_insert_aml_officer.sql" #include "exchange_do_insert_kyc_measure_result.sql" #include "exchange_do_reserves_in_insert.sql" diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 66e0c4587..88d05ce24 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -7296,6 +7296,20 @@ struct TALER_EXCHANGEDB_Plugin /** + * Revert account back to default rules and insert successor measure. + */ + enum GNUNET_DB_QueryStatus + (*insert_successor_measure)( + void *cls, + const struct TALER_NormalizedPaytoHashP *h_payto, + struct GNUNET_TIME_Timestamp decision_time, + const char *new_measure_name, + const json_t *jmeasures, + bool *unknown_account, + struct GNUNET_TIME_Timestamp *last_date); + + + /** * Lookup KYC attribute data for a specific account. * * @param cls closure |