[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-exchange] 22/151: basic refactoring of httpd for new AML, incompl
From: |
gnunet |
Subject: |
[taler-exchange] 22/151: basic refactoring of httpd for new AML, incomplete |
Date: |
Tue, 30 Jul 2024 23:36:32 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository exchange.
commit e362663b75830c89f620be750d36e343b0d8ca3d
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Tue May 7 14:56:08 2024 +0200
basic refactoring of httpd for new AML, incomplete
---
src/exchange/Makefile.am | 22 +-
src/exchange/taler-exchange-aggregator.c | 17 +-
src/exchange/taler-exchange-httpd_age-withdraw.c | 274 +++-----
src/exchange/taler-exchange-httpd_batch-withdraw.c | 265 +------
src/exchange/taler-exchange-httpd_deposits_get.c | 8 +-
src/exchange/taler-exchange-httpd_responses.c | 25 -
src/exchange/taler-exchange-httpd_responses.h | 13 -
src/exchange/taler-exchange-httpd_withdraw.c | 211 ++++++
src/exchange/taler-exchange-httpd_withdraw.h | 51 ++
src/exchangedb/pg_get_kyc_rules.c | 9 +-
src/exchangedb/pg_get_kyc_rules.h | 2 -
src/include/taler_exchangedb_plugin.h | 2 -
src/include/taler_kyclogic_lib.h | 41 +-
src/kyclogic/kyclogic_api.c | 758 +++++++++++----------
src/kyclogic/taler-exchange-kyc-tester.c | 24 +-
15 files changed, 835 insertions(+), 887 deletions(-)
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 1c0c2c684..2cf514f0c 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -127,9 +127,6 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
taler-exchange-httpd_age-withdraw_reveal.c
taler-exchange-httpd_age-withdraw_reveal.h \
taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \
- taler-exchange-httpd_aml-decision.c taler-exchange-httpd_aml-decision.h \
- taler-exchange-httpd_aml-decision-get.c \
- taler-exchange-httpd_aml-decisions-get.c \
taler-exchange-httpd_batch-deposit.c taler-exchange-httpd_batch-deposit.h \
taler-exchange-httpd_batch-withdraw.c taler-exchange-httpd_batch-withdraw.h \
taler-exchange-httpd_coins_get.c taler-exchange-httpd_coins_get.h \
@@ -139,12 +136,9 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \
taler-exchange-httpd_csr.c taler-exchange-httpd_csr.h \
taler-exchange-httpd_db.c taler-exchange-httpd_db.h \
- taler-exchange-httpd_deposits_get.c taler-exchange-httpd_deposits_get.h \
taler-exchange-httpd_extensions.c taler-exchange-httpd_extensions.h \
taler-exchange-httpd_keys.c taler-exchange-httpd_keys.h \
- taler-exchange-httpd_kyc-check.c taler-exchange-httpd_kyc-check.h \
taler-exchange-httpd_kyc-proof.c taler-exchange-httpd_kyc-proof.h \
- taler-exchange-httpd_kyc-wallet.c taler-exchange-httpd_kyc-wallet.h \
taler-exchange-httpd_kyc-webhook.c taler-exchange-httpd_kyc-webhook.h \
taler-exchange-httpd_link.c taler-exchange-httpd_link.h \
taler-exchange-httpd_management.h \
@@ -168,22 +162,30 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_purses_deposit.c taler-exchange-httpd_purses_deposit.h \
taler-exchange-httpd_purses_delete.c taler-exchange-httpd_purses_delete.h \
taler-exchange-httpd_purses_get.c taler-exchange-httpd_purses_get.h \
- taler-exchange-httpd_purses_merge.c taler-exchange-httpd_purses_merge.h \
taler-exchange-httpd_recoup.c taler-exchange-httpd_recoup.h \
taler-exchange-httpd_recoup-refresh.c taler-exchange-httpd_recoup-refresh.h \
taler-exchange-httpd_refreshes_reveal.c
taler-exchange-httpd_refreshes_reveal.h \
taler-exchange-httpd_refund.c taler-exchange-httpd_refund.h \
taler-exchange-httpd_reserves_attest.c
taler-exchange-httpd_reserves_attest.h \
- taler-exchange-httpd_reserves_close.c taler-exchange-httpd_reserves_close.h \
taler-exchange-httpd_reserves_get.c taler-exchange-httpd_reserves_get.h \
taler-exchange-httpd_reserves_get_attest.c
taler-exchange-httpd_reserves_get_attest.h \
taler-exchange-httpd_reserves_history.c
taler-exchange-httpd_reserves_history.h \
taler-exchange-httpd_reserves_open.c taler-exchange-httpd_reserves_open.h \
- taler-exchange-httpd_reserves_purse.c taler-exchange-httpd_reserves_purse.h \
taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
taler-exchange-httpd_spa.c taler-exchange-httpd_spa.h \
taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \
- taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h
+ taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h \
+ taler-exchange-httpd_withdraw.c taler-exchange-httpd_withdraw.h
+
+# taler-exchange-httpd_purses_merge.c taler-exchange-httpd_purses_merge.h \
+# taler-exchange-httpd_reserves_close.c taler-exchange-httpd_reserves_close.h
\
+# taler-exchange-httpd_reserves_purse.c taler-exchange-httpd_reserves_purse.h
\
+# taler-exchange-httpd_kyc-check.c taler-exchange-httpd_kyc-check.h \
+# taler-exchange-httpd_kyc-wallet.c taler-exchange-httpd_kyc-wallet.h \
+# taler-exchange-httpd_deposits_get.c taler-exchange-httpd_deposits_get.h \
+# taler-exchange-httpd_aml-decision.c taler-exchange-httpd_aml-decision.h \
+# taler-exchange-httpd_aml-decision-get.c \
+# taler-exchange-httpd_aml-decisions-get.c
taler_exchange_httpd_LDADD = \
$(LIBGCRYPT_LIBS) \
diff --git a/src/exchange/taler-exchange-aggregator.c
b/src/exchange/taler-exchange-aggregator.c
index 9a4b36a71..0e485ae9c 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -500,7 +500,6 @@ legitimization_satisfied (struct AggregationUnit *au_active)
{
struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL;
struct TALER_KYCLOGIC_KycRule *requirement;
- struct GNUNET_TIME_Timestamp expiration_time;
enum GNUNET_DB_QueryStatus qs;
json_t *jrule;
@@ -512,29 +511,17 @@ legitimization_satisfied (struct AggregationUnit
*au_active)
qs = db_plugin->get_kyc_rules (db_plugin->cls,
&au_active->h_payto,
- &expiration_time,
&jrules);
if (qs < 0)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return false;
}
- if ( (qs > 0) &&
- (GNUNET_TIME_absolute_is_past (expiration_time.abs_time)) )
- {
- json_decref (jrules);
- jrules = NULL;
- qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- }
if (qs > 0)
{
lrs = TALER_KYCLOGIC_rules_parse (jrules);
- if (NULL == lrs)
- {
- GNUNET_break (0);
- json_decref (jrules);
- return false;
- }
+ GNUNET_break (NULL != lrs);
+ /* Fall back to default rules on parse error! */
json_decref (jrules);
}
}
diff --git a/src/exchange/taler-exchange-httpd_age-withdraw.c
b/src/exchange/taler-exchange-httpd_age-withdraw.c
index 9276fb191..4bb1db5b9 100644
--- a/src/exchange/taler-exchange-httpd_age-withdraw.c
+++ b/src/exchange/taler-exchange-httpd_age-withdraw.c
@@ -33,6 +33,7 @@
#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_age-withdraw.h"
+#include "taler-exchange-httpd_withdraw.h"
#include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keys.h"
#include "taler_util.h"
@@ -53,11 +54,6 @@ struct AgeWithdrawContext
*/
struct GNUNET_TIME_Timestamp now;
- /**
- * Hash of the wire source URL, needed when kyc is needed.
- */
- struct TALER_PaytoHashP h_payto;
-
/**
* The data from the age-withdraw request, as we persist it
*/
@@ -549,19 +545,18 @@ reply_age_withdraw_success (
{
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
- enum TALER_ErrorCode ec =
- TALER_exchange_online_age_withdraw_confirmation_sign (
- &TEH_keys_exchange_sign_,
- ach,
- noreveal_index,
- &pub,
- &sig);
-
+ enum TALER_ErrorCode ec;
+
+ ec = TALER_exchange_online_age_withdraw_confirmation_sign (
+ &TEH_keys_exchange_sign_,
+ ach,
+ noreveal_index,
+ &pub,
+ &sig);
if (TALER_EC_NONE != ec)
return TALER_MHD_reply_with_ec (connection,
ec,
NULL);
-
return TALER_MHD_REPLY_JSON_PACK (connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_uint64 ("noreveal_index",
@@ -618,49 +613,6 @@ request_is_idempotent (struct MHD_Connection *con,
}
-/**
- * Function called to iterate over KYC-relevant transaction amounts for a
- * particular time range. Called within a database transaction, so must
- * not start a new one.
- *
- * @param cls closure, identifies the event type and account to iterate
- * over events for
- * @param limit maximum time-range for which events should be fetched
- * (timestamp in the past)
- * @param cb function to call on each event found, events must be returned
- * in reverse chronological order
- * @param cb_cls closure for @a cb, of type struct AgeWithdrawContext
- */
-static void
-age_withdraw_amount_cb (void *cls,
- struct GNUNET_TIME_Absolute limit,
- TALER_EXCHANGEDB_KycAmountCallback cb,
- void *cb_cls)
-{
- struct AgeWithdrawContext *awc = cls;
- enum GNUNET_DB_QueryStatus qs;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Signaling amount %s for KYC check during age-withdrawal\n",
- TALER_amount2s (&awc->commitment.amount_with_fee));
- if (GNUNET_OK !=
- cb (cb_cls,
- &awc->commitment.amount_with_fee,
- awc->now.abs_time))
- return;
- qs = TEH_plugin->select_withdraw_amounts_for_kyc_check (TEH_plugin->cls,
- &awc->h_payto,
- limit,
- cb,
- cb_cls);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Got %d additional transactions for this age-withdrawal and
limit %llu\n",
- qs,
- (unsigned long long) limit.abs_value_us);
- GNUNET_break (qs >= 0);
-}
-
-
/**
* Function implementing age withdraw transaction. Runs the
* transaction logic; IF it returns a non-error code, the transaction
@@ -682,135 +634,89 @@ age_withdraw_transaction (void *cls,
{
struct AgeWithdrawContext *awc = cls;
enum GNUNET_DB_QueryStatus qs;
-
- qs = TEH_plugin->reserves_get_origin (TEH_plugin->cls,
- &awc->commitment.reserve_pub,
- &awc->h_payto);
- if (qs < 0)
+ bool found = false;
+ bool balance_ok = false;
+ bool age_ok = false;
+ bool conflict = false;
+ uint16_t allowed_maximum_age = 0;
+ uint32_t reserve_birthday = 0;
+ struct TALER_Amount reserve_balance;
+
+ qs = TEH_withdraw_kyc_check (&awc->kyc,
+ connection,
+ mhd_ret,
+ &awc->commitment.reserve_pub,
+ &awc->commitment.amount_with_fee,
+ awc->now);
+ if ( (qs < 0) ||
+ (! awc->kyc.ok) )
return qs;
-
- /* If _no_ results, reserve was created by merge,
- in which case no KYC check is required as the
- merge already did that. */
-
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ qs = TEH_plugin->do_age_withdraw (TEH_plugin->cls,
+ &awc->commitment,
+ awc->now,
+ &found,
+ &balance_ok,
+ &reserve_balance,
+ &age_ok,
+ &allowed_maximum_age,
+ &reserve_birthday,
+ &conflict);
+ if (0 > qs)
{
- char *kyc_required;
-
- qs = TALER_KYCLOGIC_kyc_test_required (
- TALER_KYCLOGIC_KYC_TRIGGER_AGE_WITHDRAW,
- &awc->h_payto,
- TEH_plugin->select_satisfied_kyc_processes,
- TEH_plugin->cls,
- &age_withdraw_amount_cb,
- awc,
- &kyc_required);
-
- if (qs < 0)
- {
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- GNUNET_break (0);
- *mhd_ret = TALER_MHD_reply_with_ec (connection,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "kyc_test_required");
- }
- return qs;
- }
-
- if (NULL != kyc_required)
- {
- /* Mark result and return by inserting KYC requirement into DB! */
- awc->kyc.ok = false;
- return TEH_plugin->insert_kyc_requirement_for_account (
- TEH_plugin->cls,
- kyc_required,
- &awc->h_payto,
- &awc->commitment.reserve_pub,
- &awc->kyc.requirement_row);
- }
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ *mhd_ret = TALER_MHD_reply_with_ec (connection,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "do_age_withdraw");
+ return qs;
}
-
- awc->kyc.ok = true;
-
- /* KYC requirement fulfilled, do the age-withdraw transaction */
+ if (! found)
{
- bool found = false;
- bool balance_ok = false;
- bool age_ok = false;
- bool conflict = false;
- uint16_t allowed_maximum_age = 0;
- uint32_t reserve_birthday = 0;
- struct TALER_Amount reserve_balance;
-
- qs = TEH_plugin->do_age_withdraw (TEH_plugin->cls,
- &awc->commitment,
- awc->now,
- &found,
- &balance_ok,
- &reserve_balance,
- &age_ok,
- &allowed_maximum_age,
- &reserve_birthday,
- &conflict);
- if (0 > qs)
- {
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- *mhd_ret = TALER_MHD_reply_with_ec (connection,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "do_age_withdraw");
- return qs;
- }
- if (! found)
- {
- *mhd_ret = TALER_MHD_reply_with_ec (connection,
-
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
- NULL);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- if (! age_ok)
- {
- enum TALER_ErrorCode ec =
- TALER_EC_EXCHANGE_AGE_WITHDRAW_MAXIMUM_AGE_TOO_LARGE;
-
- *mhd_ret =
- TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_MHD_PACK_EC (ec),
- GNUNET_JSON_pack_uint64 ("allowed_maximum_age",
- allowed_maximum_age),
- GNUNET_JSON_pack_uint64 ("reserve_birthday",
- reserve_birthday));
-
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- if (! balance_ok)
- {
- TEH_plugin->rollback (TEH_plugin->cls);
+ *mhd_ret = TALER_MHD_reply_with_ec (connection,
+
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
+ NULL);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ if (! age_ok)
+ {
+ enum TALER_ErrorCode ec =
+ TALER_EC_EXCHANGE_AGE_WITHDRAW_MAXIMUM_AGE_TOO_LARGE;
- *mhd_ret = TEH_RESPONSE_reply_reserve_insufficient_balance (
+ *mhd_ret =
+ TALER_MHD_REPLY_JSON_PACK (
connection,
- TALER_EC_EXCHANGE_AGE_WITHDRAW_INSUFFICIENT_FUNDS,
- &reserve_balance,
- &awc->commitment.amount_with_fee,
- &awc->commitment.reserve_pub);
-
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- if (conflict)
- {
- /* do_age_withdraw signaled a conflict, so there MUST be an entry
- * in the DB. Put that into the response */
- bool ok = request_is_idempotent (connection,
- awc,
- mhd_ret);
- GNUNET_assert (ok);
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- }
- *mhd_ret = -1;
+ MHD_HTTP_CONFLICT,
+ TALER_MHD_PACK_EC (ec),
+ GNUNET_JSON_pack_uint64 ("allowed_maximum_age",
+ allowed_maximum_age),
+ GNUNET_JSON_pack_uint64 ("reserve_birthday",
+ reserve_birthday));
+
+ return GNUNET_DB_STATUS_HARD_ERROR;
}
+ if (! balance_ok)
+ {
+ TEH_plugin->rollback (TEH_plugin->cls);
+
+ *mhd_ret = TEH_RESPONSE_reply_reserve_insufficient_balance (
+ connection,
+ TALER_EC_EXCHANGE_AGE_WITHDRAW_INSUFFICIENT_FUNDS,
+ &reserve_balance,
+ &awc->commitment.amount_with_fee,
+ &awc->commitment.reserve_pub);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ if (conflict)
+ {
+ /* do_age_withdraw signaled a conflict, so there MUST be an entry
+ * in the DB. Put that into the response */
+ bool ok = request_is_idempotent (connection,
+ awc,
+ mhd_ret);
+ GNUNET_assert (ok);
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+ }
+ *mhd_ret = -1;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
TEH_METRICS_num_success[TEH_MT_SUCCESS_AGE_WITHDRAW]++;
return qs;
@@ -846,8 +752,6 @@ sign_and_do_age_withdraw (
struct TALER_BlindedDenominationSignature denom_sigs[awc->num_coins];
uint8_t noreveal_index;
- awc->now = GNUNET_TIME_timestamp_get ();
-
/* Pick the challenge */
noreveal_index =
GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
@@ -918,7 +822,10 @@ TEH_handler_age_withdraw (struct TEH_RequestContext *rc,
MHD_RESULT mhd_ret;
const json_t *j_denom_hs;
const json_t *j_blinded_coin_evs;
- struct AgeWithdrawContext awc = {0};
+ struct AgeWithdrawContext awc = {
+ .commitment.reserve_pub = *reserve_pub,
+ .now = GNUNET_TIME_timestamp_get ()
+ };
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_array_const ("denom_hs",
&j_denom_hs),
@@ -931,9 +838,6 @@ TEH_handler_age_withdraw (struct TEH_RequestContext *rc,
GNUNET_JSON_spec_end ()
};
- awc.commitment.reserve_pub = *reserve_pub;
-
-
/* Parse the JSON body */
{
enum GNUNET_GenericReturnValue res;
@@ -1000,7 +904,7 @@ TEH_handler_age_withdraw (struct TEH_RequestContext *rc,
* the DB-transaction */
if (! awc.kyc.ok)
mhd_ret = TEH_RESPONSE_reply_kyc_required (rc->connection,
- &awc.h_payto,
+ NULL, /* FIXME! */
&awc.kyc);
else
mhd_ret = reply_age_withdraw_success (rc->connection,
diff --git a/src/exchange/taler-exchange-httpd_batch-withdraw.c
b/src/exchange/taler-exchange-httpd_batch-withdraw.c
index 2212897a0..d9f5489d8 100644
--- a/src/exchange/taler-exchange-httpd_batch-withdraw.c
+++ b/src/exchange/taler-exchange-httpd_batch-withdraw.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2023 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -31,6 +31,7 @@
#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_batch-withdraw.h"
+#include "taler-exchange-httpd_withdraw.h"
#include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keys.h"
#include "taler_util.h"
@@ -89,12 +90,6 @@ struct BatchWithdrawContext
*/
struct PlanchetContext *planchets;
- /**
- * Hash of the payto-URI representing the reserve
- * from which we are withdrawing.
- */
- struct TALER_PaytoHashP h_payto;
-
/**
* Current time for the DB transaction.
*/
@@ -110,81 +105,9 @@ struct BatchWithdrawContext
*/
unsigned int planchets_length;
- /**
- * AML decision, #TALER_AML_NORMAL if we may proceed.
- */
- enum TALER_AmlDecisionState aml_decision;
-
};
-/**
- * Function called to iterate over KYC-relevant
- * transaction amounts for a particular time range.
- * Called within a database transaction, so must
- * not start a new one.
- *
- * @param cls closure, identifies the event type and
- * account to iterate over events for
- * @param limit maximum time-range for which events
- * should be fetched (timestamp in the past)
- * @param cb function to call on each event found,
- * events must be returned in reverse chronological
- * order
- * @param cb_cls closure for @a cb
- */
-static void
-batch_withdraw_amount_cb (void *cls,
- struct GNUNET_TIME_Absolute limit,
- TALER_EXCHANGEDB_KycAmountCallback cb,
- void *cb_cls)
-{
- struct BatchWithdrawContext *wc = cls;
- enum GNUNET_DB_QueryStatus qs;
-
- if (GNUNET_OK !=
- cb (cb_cls,
- &wc->batch_total,
- wc->now.abs_time))
- return;
- qs = TEH_plugin->select_withdraw_amounts_for_kyc_check (
- TEH_plugin->cls,
- &wc->h_payto,
- limit,
- cb,
- cb_cls);
- GNUNET_break (qs >= 0);
-}
-
-
-/**
- * Function called on each @a amount that was found to
- * be relevant for the AML check as it was merged into
- * the reserve.
- *
- * @param cls `struct TALER_Amount *` to total up the amounts
- * @param amount encountered transaction amount
- * @param date when was the amount encountered
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to abort iteration
- * #GNUNET_SYSERR on internal error (also abort itaration)
- */
-static enum GNUNET_GenericReturnValue
-aml_amount_cb (
- void *cls,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute date)
-{
- struct TALER_Amount *total = cls;
-
- GNUNET_assert (0 <=
- TALER_amount_add (total,
- total,
- amount));
- return GNUNET_OK;
-}
-
-
/**
* Generates our final (successful) response.
*
@@ -198,17 +121,6 @@ generate_reply_success (const struct TEH_RequestContext
*rc,
{
json_t *sigs;
- if (! wc->kyc.ok)
- {
- /* KYC required */
- return TEH_RESPONSE_reply_kyc_required (rc->connection,
- &wc->h_payto,
- &wc->kyc);
- }
- if (TALER_AML_NORMAL != wc->aml_decision)
- return TEH_RESPONSE_reply_aml_blocked (rc->connection,
- wc->aml_decision);
-
sigs = json_array ();
GNUNET_assert (NULL != sigs);
for (unsigned int i = 0; i<wc->planchets_length; i++)
@@ -309,163 +221,16 @@ batch_withdraw_transaction (void *cls,
bool age_ok = false;
uint16_t allowed_maximum_age = 0;
struct TALER_Amount reserve_balance;
- char *kyc_required;
- struct TALER_PaytoHashP reserve_h_payto;
-
- wc->now = GNUNET_TIME_timestamp_get ();
- /* Do AML check: compute total merged amount and check
- against applicable AML threshold */
- {
- char *reserve_payto;
-
- reserve_payto = TALER_reserve_make_payto (TEH_base_url,
- wc->reserve_pub);
- TALER_payto_hash (reserve_payto,
- &reserve_h_payto);
- GNUNET_free (reserve_payto);
- }
- {
- struct TALER_Amount merge_amount;
- struct TALER_Amount threshold;
- struct GNUNET_TIME_Absolute now_minus_one_month;
-
- now_minus_one_month
- = GNUNET_TIME_absolute_subtract (wc->now.abs_time,
- GNUNET_TIME_UNIT_MONTHS);
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (TEH_currency,
- &merge_amount));
- qs = TEH_plugin->select_merge_amounts_for_kyc_check (TEH_plugin->cls,
- &reserve_h_payto,
- now_minus_one_month,
- &aml_amount_cb,
- &merge_amount);
- if (qs < 0)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_GENERIC_DB_FETCH_FAILED,
-
"select_merge_amounts_for_kyc_check");
- return qs;
- }
- qs = TEH_plugin->select_aml_threshold (TEH_plugin->cls,
- &reserve_h_payto,
- &wc->aml_decision,
- &wc->kyc,
- &threshold);
- if (qs < 0)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_GENERIC_DB_FETCH_FAILED,
- "select_aml_threshold");
- return qs;
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- threshold = TEH_aml_threshold; /* use default */
- wc->aml_decision = TALER_AML_NORMAL;
- }
-
- switch (wc->aml_decision)
- {
- case TALER_AML_NORMAL:
- if (0 >= TALER_amount_cmp (&merge_amount,
- &threshold))
- {
- /* merge_amount <= threshold, continue withdraw below */
- break;
- }
- wc->aml_decision = TALER_AML_PENDING;
- qs = TEH_plugin->trigger_aml_process (TEH_plugin->cls,
- &reserve_h_payto,
- &merge_amount);
- if (qs <= 0)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- *mhd_ret = TALER_MHD_reply_with_error (connection,
-
MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_GENERIC_DB_STORE_FAILED,
- "trigger_aml_process");
- return qs;
- }
- return qs;
- case TALER_AML_PENDING:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "AML already pending, doing nothing\n");
- return qs;
- case TALER_AML_FROZEN:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Account frozen, doing nothing\n");
- return qs;
- }
- }
- /* Check if the money came from a wire transfer */
- qs = TEH_plugin->reserves_get_origin (TEH_plugin->cls,
- wc->reserve_pub,
- &wc->h_payto);
- if (qs < 0)
- {
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "reserves_get_origin");
+ qs = TEH_withdraw_kyc_check (&wc->kyc,
+ connection,
+ mhd_ret,
+ wc->reserve_pub,
+ &wc->batch_total,
+ wc->now);
+ if ( (qs < 0) ||
+ (! wc->kyc.ok) )
return qs;
- }
- /* If no results, reserve was created by merge, in which case no KYC check
- is required as the merge already did that. */
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- qs = TALER_KYCLOGIC_kyc_test_required (
- TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW,
- &wc->h_payto,
- TEH_plugin->select_satisfied_kyc_processes,
- TEH_plugin->cls,
- &batch_withdraw_amount_cb,
- wc,
- &kyc_required);
- if (qs < 0)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_GENERIC_DB_FETCH_FAILED,
- "kyc_test_required");
- return qs;
- }
- if (NULL != kyc_required)
- {
- /* insert KYC requirement into DB! */
- wc->kyc.ok = false;
- qs = TEH_plugin->insert_kyc_requirement_for_account (
- TEH_plugin->cls,
- kyc_required,
- &wc->h_payto,
- wc->reserve_pub,
- &wc->kyc.requirement_row);
- GNUNET_free (kyc_required);
- if (qs < 0)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- *mhd_ret = TALER_MHD_reply_with_error (connection,
-
MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_GENERIC_DB_STORE_FAILED,
-
"insert_kyc_requirement_for_account");
- }
- return qs;
- }
- }
- wc->kyc.ok = true;
-
qs = TEH_plugin->do_batch_withdraw (TEH_plugin->cls,
wc->now,
wc->reserve_pub,
@@ -669,6 +434,13 @@ prepare_transaction (const struct TEH_RequestContext *rc,
}
}
/* return final positive response */
+ if (! wc->kyc.ok)
+ {
+ /* KYC required */
+ return TEH_RESPONSE_reply_kyc_required (rc->connection,
+ NULL, /* FIXME! */
+ &wc->kyc);
+ }
return generate_reply_success (rc,
wc);
}
@@ -877,7 +649,8 @@ TEH_handler_batch_withdraw (struct TEH_RequestContext *rc,
{
struct BatchWithdrawContext wc = {
.reserve_pub = reserve_pub,
- .rc = rc
+ .rc = rc,
+ .now = GNUNET_TIME_timestamp_get ()
};
const json_t *planchets;
struct GNUNET_JSON_Specification spec[] = {
diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c
b/src/exchange/taler-exchange-httpd_deposits_get.c
index 0850d19eb..934c638b7 100644
--- a/src/exchange/taler-exchange-httpd_deposits_get.c
+++ b/src/exchange/taler-exchange-httpd_deposits_get.c
@@ -122,11 +122,6 @@ struct DepositWtidContext
*/
struct TALER_EXCHANGEDB_KycStatus kyc;
- /**
- * AML status information for the receiving account.
- */
- enum TALER_AmlDecisionState aml_decision;
-
/**
* Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
* (and the above were not set).
@@ -377,7 +372,8 @@ handle_track_transaction_request (
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
- "wire fees exceed aggregate in
database");
+ "wire fees exceed aggregate in
database")
+ ;
if (GNUNET_YES == ctx->pending)
{
if ( (GNUNET_TIME_absolute_is_future (ctx->timeout)) &&
diff --git a/src/exchange/taler-exchange-httpd_responses.c
b/src/exchange/taler-exchange-httpd_responses.c
index 8993ea50f..b3825c9c2 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -353,31 +353,6 @@ TEH_RESPONSE_reply_kyc_required (struct MHD_Connection
*connection,
}
-MHD_RESULT
-TEH_RESPONSE_reply_aml_blocked (struct MHD_Connection *connection,
- enum TALER_AmlDecisionState status)
-{
- enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
-
- switch (status)
- {
- case TALER_AML_NORMAL:
- GNUNET_break (0);
- return MHD_NO;
- case TALER_AML_PENDING:
- ec = TALER_EC_EXCHANGE_GENERIC_AML_PENDING;
- break;
- case TALER_AML_FROZEN:
- ec = TALER_EC_EXCHANGE_GENERIC_AML_FROZEN;
- break;
- }
- return TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
- TALER_JSON_pack_ec (ec));
-}
-
-
MHD_RESULT
TEH_RESPONSE_reply_not_modified (
struct MHD_Connection *connection,
diff --git a/src/exchange/taler-exchange-httpd_responses.h
b/src/exchange/taler-exchange-httpd_responses.h
index 24b24621f..77ca9d557 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -97,19 +97,6 @@ TEH_RESPONSE_reply_kyc_required (struct MHD_Connection
*connection,
const struct TALER_EXCHANGEDB_KycStatus *kyc);
-/**
- * Send information that an AML process is blocking
- * the operation right now.
- *
- * @param connection connection to the client
- * @param status current AML status
- * @return MHD result code
- */
-MHD_RESULT
-TEH_RESPONSE_reply_aml_blocked (struct MHD_Connection *connection,
- enum TALER_AmlDecisionState status);
-
-
/**
* Send assertion that the given denomination key hash
* is not usable (typically expired) at this time.
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c
b/src/exchange/taler-exchange-httpd_withdraw.c
new file mode 100644
index 000000000..f54235bde
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -0,0 +1,211 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General
+ Public License along with TALER; see the file COPYING. If not,
+ see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_batch-withdraw.c
+ * @brief Handle /reserves/$RESERVE_PUB/batch-withdraw requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include "taler-exchange-httpd.h"
+#include "taler_json_lib.h"
+#include "taler_kyclogic_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_withdraw.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler_util.h"
+
+
+/**
+ * Closure for #withdraw_amount_cb().
+ */
+struct WithdrawContext
+{
+ /**
+ * Total amount being withdrawn now.
+ */
+ const struct TALER_Amount *withdraw_total;
+
+ /**
+ * Current time.
+ */
+ struct GNUNET_TIME_Timestamp now;
+
+ /**
+ * Account we are checking against.
+ */
+ struct TALER_PaytoHashP h_payto;
+};
+
+
+/**
+ * Function called to iterate over KYC-relevant transaction amounts for a
+ * particular time range. Called within a database transaction, so must
+ * not start a new one.
+ *
+ * @param cls closure, identifies the event type and account to iterate
+ * over events for
+ * @param limit maximum time-range for which events should be fetched
+ * (timestamp in the past)
+ * @param cb function to call on each event found, events must be returned
+ * in reverse chronological order
+ * @param cb_cls closure for @a cb, of type struct AgeWithdrawContext
+ */
+static void
+withdraw_amount_cb (
+ void *cls,
+ struct GNUNET_TIME_Absolute limit,
+ TALER_EXCHANGEDB_KycAmountCallback cb,
+ void *cb_cls)
+{
+ struct WithdrawContext *wc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Signaling amount %s for KYC check during age-withdrawal\n",
+ TALER_amount2s (wc->withdraw_total));
+ if (GNUNET_OK !=
+ cb (cb_cls,
+ wc->withdraw_total,
+ wc->now.abs_time))
+ return;
+ qs = TEH_plugin->select_withdraw_amounts_for_kyc_check (TEH_plugin->cls,
+ &wc->h_payto,
+ limit,
+ cb,
+ cb_cls);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Got %d additional transactions for this age-withdrawal and
limit %llu\n",
+ qs,
+ (unsigned long long) limit.abs_value_us);
+ GNUNET_break (qs >= 0);
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_withdraw_kyc_check (
+ struct TALER_EXCHANGEDB_KycStatus *kyc,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *withdraw_total,
+ struct GNUNET_TIME_Timestamp now
+ )
+{
+ enum GNUNET_DB_QueryStatus qs;
+ struct WithdrawContext wc = {
+ .withdraw_total = withdraw_total,
+ .now = now
+ };
+
+ /* Check if the money came from a wire transfer */
+ qs = TEH_plugin->reserves_get_origin (
+ TEH_plugin->cls,
+ reserve_pub,
+ &wc.h_payto);
+ if (qs < 0)
+ {
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "reserves_get_origin");
+ return qs;
+ }
+
+ /* If _no_ results, reserve was created by merge,
+ in which case no KYC check is required as the
+ merge already did that. */
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ json_t *jrules;
+ struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL;
+ struct TALER_KYCLOGIC_KycRule *requirement;
+
+ qs = TEH_plugin->get_kyc_rules (TEH_plugin->cls,
+ &wc.h_payto,
+ &jrules);
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ return qs;
+ }
+ if (qs > 0)
+ {
+ lrs = TALER_KYCLOGIC_rules_parse (jrules);
+ GNUNET_break (NULL != lrs);
+ /* Fall back to default rules on parse error! */
+ json_decref (jrules);
+ }
+ qs = TALER_KYCLOGIC_kyc_test_required (
+ TALER_KYCLOGIC_KYC_TRIGGER_AGE_WITHDRAW,
+ &wc.h_payto,
+ lrs,
+ &withdraw_amount_cb,
+ &wc,
+ &requirement);
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ TALER_KYCLOGIC_rules_free (lrs);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ *mhd_ret = TALER_MHD_reply_with_ec (connection,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "kyc_test_required");
+ return qs;
+ }
+
+ if (NULL != requirement)
+ {
+ json_t *jrule;
+ union TALER_AccountPublicKeyP account_pub;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC requirement is %s\n",
+ TALER_KYCLOGIC_rule2s (requirement));
+ jrule = TALER_KYCLOGIC_rule2j (requirement);
+ account_pub.reserve_pub
+ = *reserve_pub;
+ kyc->ok = false;
+ qs = TEH_plugin->trigger_kyc_rule_for_account (
+ TEH_plugin->cls,
+ &wc.h_payto,
+ &account_pub,
+ jrule,
+ TALER_KYCLOGIC_rule2priority (requirement),
+ &kyc->requirement_row);
+ TALER_KYCLOGIC_rules_free (lrs);
+ json_decref (jrule);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_ec (connection,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "trigger_kyc_rule_for_account");
+ }
+ return qs;
+ }
+ TALER_KYCLOGIC_rules_free (lrs);
+ }
+ kyc->ok = true;
+ return qs;
+}
diff --git a/src/exchange/taler-exchange-httpd_withdraw.h
b/src/exchange/taler-exchange-httpd_withdraw.h
new file mode 100644
index 000000000..1391735c5
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_withdraw.h
@@ -0,0 +1,51 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero 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 Affero General Public License for more
details.
+
+ You should have received a copy of the GNU Affero General Public License
along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_withdraw.h
+ * @brief common code for withdraw requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_WITHDRAW_H
+#define TALER_EXCHANGE_HTTPD_WITHDRAW_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Do legitimization check for withdrawing @a withdraw_total
+ * from @a reserve_pub at time @a now.
+ *
+ * @param[out] kyc set to kyc status
+ * @param[in,out] connection used to return hard errors
+ * @param[out] mhd_ret set if errors were returned
+ * (only on hard error)
+ * @param reserve_pub reserve from which we withdraw
+ * @param withdraw_total how much are being withdrawn
+ * @param now current time
+ * @return transaction status, error will have been
+ * queued if transaction status is set to hard error
+ */
+enum GNUNET_DB_QueryStatus
+TEH_withdraw_kyc_check (
+ struct TALER_EXCHANGEDB_KycStatus *kyc,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *withdraw_total,
+ struct GNUNET_TIME_Timestamp now);
+
+#endif
diff --git a/src/exchangedb/pg_get_kyc_rules.c
b/src/exchangedb/pg_get_kyc_rules.c
index 0364470b7..52d69b6b3 100644
--- a/src/exchangedb/pg_get_kyc_rules.c
+++ b/src/exchangedb/pg_get_kyc_rules.c
@@ -30,19 +30,20 @@ enum GNUNET_DB_QueryStatus
TEH_PG_get_kyc_rules (
void *cls,
const struct TALER_PaytoHashP *h_payto,
- struct GNUNET_TIME_Timestamp *expiration_time,
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",
+ &now),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_json ("jnew_rules",
jrules),
- GNUNET_PQ_result_spec_timestamp ("expiration_time",
- expiration_time),
GNUNET_PQ_result_spec_end
};
@@ -50,9 +51,9 @@ TEH_PG_get_kyc_rules (
"get_kyc_rules",
"SELECT"
" jnew_rules"
- " ,expiration_time"
" FROM legitimization_outcomes"
" WHERE h_payto=$1"
+ " AND expiration_time >= $2"
" AND is_active;");
return GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
diff --git a/src/exchangedb/pg_get_kyc_rules.h
b/src/exchangedb/pg_get_kyc_rules.h
index 8d43b9546..9b0e2d68d 100644
--- a/src/exchangedb/pg_get_kyc_rules.h
+++ b/src/exchangedb/pg_get_kyc_rules.h
@@ -31,7 +31,6 @@
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param h_payto account identifier
- * @param[out] expiration_time when do the @a jrules expire
* @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
@@ -40,7 +39,6 @@ enum GNUNET_DB_QueryStatus
TEH_PG_get_kyc_rules (
void *cls,
const struct TALER_PaytoHashP *h_payto,
- struct GNUNET_TIME_Timestamp *expiration_time,
json_t **jrules);
#endif
diff --git a/src/include/taler_exchangedb_plugin.h
b/src/include/taler_exchangedb_plugin.h
index 3e82e3bb5..cc1c39d5f 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -6866,7 +6866,6 @@ struct TALER_EXCHANGEDB_Plugin
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param h_payto account identifier
- * @param[out] expiration_time when do the @a jrules expire
* @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
@@ -6875,7 +6874,6 @@ struct TALER_EXCHANGEDB_Plugin
(*get_kyc_rules)(
void *cls,
const struct TALER_PaytoHashP *h_payto,
- struct GNUNET_TIME_Timestamp *expiration_time,
json_t **jrules);
diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h
index 08ba424cf..168415b64 100644
--- a/src/include/taler_kyclogic_lib.h
+++ b/src/include/taler_kyclogic_lib.h
@@ -222,6 +222,7 @@ TALER_KYCLOGIC_rule2j (struct TALER_KYCLOGIC_KycRule *r);
uint32_t
TALER_KYCLOGIC_rule2priority (struct TALER_KYCLOGIC_KycRule *r);
+
/**
* Iterate over all thresholds that are applicable to a particular type of @a
* event under exposed global rules.
@@ -258,8 +259,9 @@ TALER_KYCLOGIC_is_satisfiable (
* FIXME: we probably want to instead set up the logic
* with the context instead of just returning it here!
*
- * @param requirements space-separated list of required checks
- * @param ut type of the entity performing the check
+ * @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
@@ -311,4 +313,39 @@ TALER_KYCLOGIC_lookup_checks (
char ***provided_checks);
+/**
+ * Function called with the provider details and
+ * associated plugin closures for matching logics.
+ *
+ * @param cls closure
+ * @param pd provider details of a matching logic
+ * @param plugin_cls closure of the plugin
+ * @return #GNUNET_OK to continue to iterate
+ */
+typedef enum GNUNET_GenericReturnValue
+(*TALER_KYCLOGIC_DetailsCallback)(
+ void *cls,
+ const struct TALER_KYCLOGIC_ProviderDetails *pd,
+ void *plugin_cls);
+
+
+/**
+ * Call @a cb for all logics with name @a logic_name,
+ * providing the plugin closure and the @a pd configurations.
+ * 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.
+ *
+ * @param logic_name name of the logic to match
+ * @param cb function to call on matching results
+ * @param cb_cls closure for @a cb
+ */
+void
+TALER_KYCLOGIC_kyc_get_details (
+ const char *logic_name,
+ TALER_KYCLOGIC_DetailsCallback cb,
+ void *cb_cls);
+
+
#endif
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
index 9fb024a57..7c1984f28 100644
--- a/src/kyclogic/kyclogic_api.c
+++ b/src/kyclogic/kyclogic_api.c
@@ -215,6 +215,11 @@ struct TALER_KYCLOGIC_KycRule
*/
unsigned int num_measures;
+ /**
+ * Display priority for this rule.
+ */
+ uint32_t display_priority;
+
/**
* What operation type is this rule for?
*/
@@ -279,27 +284,24 @@ struct TALER_KYCLOGIC_LegitimizationRuleSet
*/
unsigned int num_custom_measures;
- /**
- * Display priority for this rule.
- */
- uint32_t display_priority;
};
-enum GNUNET_GenericReturnValue
-TALER_KYCLOGIC_rules_parse (
- const json_t *jrules,
- struct TALER_KYCLOGIC_KycRuleSet *rules)
+struct TALER_KYCLOGIC_LegitimizationRuleSet *
+TALER_KYCLOGIC_rules_parse (const json_t *jrules)
{
// FIXME!
- return GNUNET_SYSERR;
+ GNUNET_break (0);
+ return NULL;
}
void
-TALER_KYCLOGIC_rules_free (struct TALER_KYCLOGIC_KycRuleSet *krs)
+TALER_KYCLOGIC_rules_free (struct TALER_KYCLOGIC_LegitimizationRuleSet *krs)
{
- // fIXME
+ // FIXME
+ GNUNET_break (0);
+ GNUNET_free (krs);
}
@@ -310,6 +312,15 @@ TALER_KYCLOGIC_rule2s (struct TALER_KYCLOGIC_KycRule *r)
}
+json_t *
+TALER_KYCLOGIC_rule2j (struct TALER_KYCLOGIC_KycRule *r)
+{
+ // FIXME!
+ GNUNET_break (0);
+ return NULL;
+}
+
+
uint32_t
TALER_KYCLOGIC_rule2priority (struct TALER_KYCLOGIC_KycRule *r)
{
@@ -401,7 +412,7 @@ static unsigned int num_kyc_checks;
/**
* Rules that apply if we do not have an AMLA record.
*/
-static struct TALER_KYCLOGIC_KycRuleSet default_rules;
+static struct TALER_KYCLOGIC_LegitimizationRuleSet default_rules;
/**
* Array of available AML programs.
@@ -1148,8 +1159,8 @@ add_rule (const struct GNUNET_CONFIGURATION_Handle *cfg,
&kt->next_measures,
&kt->num_measures);
GNUNET_free (measures);
- GNUNET_array_append (kyc_rules,
- num_kyc_rules,
+ GNUNET_array_append (default_rules.kyc_rules,
+ default_rules.num_kyc_rules,
kt);
}
return GNUNET_OK;
@@ -1370,9 +1381,9 @@ TALER_KYCLOGIC_kyc_init (const struct
GNUNET_CONFIGURATION_Handle *cfg)
return GNUNET_SYSERR;
}
- if (0 != num_kyc_rules)
- qsort (kyc_rules,
- num_kyc_rules,
+ if (0 != default_rules.num_kyc_rules)
+ qsort (default_rules.kyc_rules,
+ default_rules.num_kyc_rules,
sizeof (struct TALER_KYCLOGIC_KycRule *),
&sort_by_timeframe);
// FIXME: add configuration sanity checking!
@@ -1383,9 +1394,10 @@ TALER_KYCLOGIC_kyc_init (const struct
GNUNET_CONFIGURATION_Handle *cfg)
void
TALER_KYCLOGIC_kyc_done (void)
{
- for (unsigned int i = 0; i<num_kyc_rules; i++)
+ for (unsigned int i = 0; i<default_rules.num_kyc_rules; i++)
{
- struct TALER_KYCLOGIC_KycRule *kt = kyc_rules[i];
+ struct TALER_KYCLOGIC_KycRule *kt
+ = default_rules.kyc_rules[i];
for (unsigned int j = 0; j<kt->num_measures; j++)
GNUNET_free (kt->next_measures[j]);
@@ -1395,8 +1407,8 @@ TALER_KYCLOGIC_kyc_done (void)
GNUNET_free (kt->rule_name);
GNUNET_free (kt);
}
- GNUNET_array_grow (kyc_rules,
- num_kyc_rules,
+ GNUNET_array_grow (default_rules.kyc_rules,
+ default_rules.num_kyc_rules,
0);
for (unsigned int i = 0; i<num_kyc_providers; i++)
{
@@ -1482,240 +1494,161 @@ TALER_KYCLOGIC_kyc_done (void)
}
-/* end of kyclogic_api.c */
-
-#if 0
-// FIXME from here...
-
-
-/**
- * Closure for the #eval_trigger().
- */
-struct ThresholdTestContext
+enum GNUNET_GenericReturnValue
+TALER_KYCLOGIC_requirements_to_logic (
+ 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)
{
- /**
- * Total amount so far.
- */
- struct TALER_Amount total;
-
- /**
- * Trigger event to evaluate triggers of.
- */
- enum TALER_KYCLOGIC_KycTriggerEvent event;
-
- /**
- * Offset in the triggers array where we need to start
- * checking for triggers. All trigges below this
- * offset were already hit.
- */
- unsigned int start;
-
- /**
- * Array of checks needed so far.
- */
- struct TALER_KYCLOGIC_KycCheck **needed;
-
- /**
- * Pointer to number of entries used in @a needed.
- */
- unsigned int *needed_cnt;
-
- /**
- * Has @e total been initialized yet?
- */
- bool have_total;
-};
+#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);
-/**
- * Function called on each @a amount that was found to
- * be relevant for a KYC check.
- *
- * @param cls closure to allow the KYC module to
- * total up amounts and evaluate rules
- * @param amount encountered transaction amount
- * @param date when was the amount encountered
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to abort iteration
- * #GNUNET_SYSERR on internal error (also abort itaration)
- */
-static enum GNUNET_GenericReturnValue
-eval_trigger (void *cls,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute date)
-{
- struct ThresholdTestContext *ttc = cls;
- struct GNUNET_TIME_Relative duration;
- bool bump = true;
+ for (const char *tok = strtok (req, " ");
+ NULL != tok;
+ tok = strtok (NULL, " "))
+ needed[needed_cnt++] = add_check (tok);
+ GNUNET_free (req);
+ }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "KYC check with new amount %s\n",
- TALER_amount2s (amount));
- duration = GNUNET_TIME_absolute_get_duration (date);
- if (ttc->have_total)
+ /* Count maximum number of remaining checks covered by any
+ provider */
+ for (unsigned int i = 0; i<num_kyc_providers; i++)
{
- if (0 >
- TALER_amount_add (&ttc->total,
- &ttc->total,
- amount))
+ 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++)
{
- GNUNET_break (0);
- return GNUNET_SYSERR;
+ 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);
}
- else
- {
- ttc->total = *amount;
- ttc->have_total = true;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "KYC check: new total is %s\n",
- TALER_amount2s (&ttc->total));
- for (unsigned int i = ttc->start; i<num_kyc_triggers; i++)
+ 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_KycTrigger *kt = kyc_triggers[i];
+ const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
+ unsigned int matched = 0;
- if (ttc->event != kt->trigger)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "KYC check #%u: trigger type does not match\n",
- i);
+ if (kp->user_type != ut)
continue;
- }
- duration = GNUNET_TIME_relative_max (duration,
- kt->timeframe);
- if (GNUNET_TIME_relative_cmp (kt->timeframe,
- >,
- duration))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "KYC check #%u: amount is beyond time limit\n",
- i);
- if (bump)
- ttc->start = i;
- return GNUNET_OK;
- }
- if (-1 ==
- TALER_amount_cmp (&ttc->total,
- &kt->threshold))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "KYC check #%u: amount is below threshold\n",
- i);
- if (bump)
- ttc->start = i;
- bump = false;
- continue; /* amount too low to trigger */
- }
- /* add check to list of required checks, unless
- already present... */
- for (unsigned int j = 0; j<kt->num_checks; j++)
+ for (unsigned int j = 0; j<kp->num_checks; j++)
{
- struct TALER_KYCLOGIC_KycCheck *rc = kt->required_checks[j];
- bool found = false;
+ const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
- for (unsigned int k = 0; k<*ttc->needed_cnt; k++)
- if (ttc->needed[k] == rc)
+ for (unsigned int k = 0; k<needed_cnt; k++)
+ if (kc == needed[k])
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "KYC rule #%u already listed\n",
- j);
- found = true;
+ matched++;
break;
}
- if (! found)
- {
- ttc->needed[*ttc->needed_cnt] = rc;
- (*ttc->needed_cnt)++;
- }
}
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "KYC check #%u (%s) is applicable, %u checks needed so far\n",
- i,
- ttc->needed[(*ttc->needed_cnt) - 1]->name,
- *ttc->needed_cnt);
+ if ( (max_checks == matched) &&
+ (kp->cost < min_cost) )
+ {
+ min_cost = kp->cost;
+ kp_best = kp;
+ }
}
- if (bump)
- return GNUNET_NO; /* we hit all possible triggers! */
+ 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);
+ return GNUNET_SYSERR;
+#endif
}
-/**
- * Closure for the #remove_satisfied().
- */
-struct RemoveContext
+enum GNUNET_GenericReturnValue
+TALER_KYCLOGIC_lookup_logic (
+ const char *name,
+ struct TALER_KYCLOGIC_Plugin **plugin,
+ struct TALER_KYCLOGIC_ProviderDetails **pd,
+ const char **provider_section)
{
+#if FIXME
+ for (unsigned int i = 0; i<num_kyc_providers; i++)
+ {
+ struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
- /**
- * Array of checks needed so far.
- */
- struct TALER_KYCLOGIC_KycCheck **needed;
+ if (0 !=
+ strcasecmp (name,
+ kp->provider_section_name))
+ continue;
+ *plugin = kp->logic;
+ *pd = kp->pd;
+ *provider_section = kp->provider_section_name;
+ return GNUNET_OK;
+ }
+ for (unsigned int i = 0; i<num_kyc_logics; i++)
+ {
+ struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i];
- /**
- * Pointer to number of entries used in @a needed.
- */
- unsigned int *needed_cnt;
-
- /**
- * Object with information about collected KYC data.
- */
- json_t *kyc_details;
-};
+ if (0 !=
+ strcasecmp (logic->name,
+ name))
+ continue;
+ *plugin = logic;
+ *pd = NULL;
+ *provider_section = NULL;
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Provider `%s' unknown\n",
+ name);
+#else
+ GNUNET_break (0);
+#endif
+ return GNUNET_SYSERR;
+}
-/**
- * Remove all checks satisfied by @a provider_name from
- * our list of checks.
- *
- * @param cls a `struct RemoveContext`
- * @param provider_name section name of provider that was already run
previously
- */
-static void
-remove_satisfied (void *cls,
- const char *provider_name)
+void
+TALER_KYCLOGIC_kyc_get_details (
+ const char *logic_name,
+ TALER_KYCLOGIC_DetailsCallback cb,
+ void *cb_cls)
{
- struct RemoveContext *rc = cls;
-
for (unsigned int i = 0; i<num_kyc_providers; i++)
{
- const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
+ struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
- if (0 != strcasecmp (provider_name,
- kp->provider_section_name))
+ if (0 !=
+ strcmp (kp->logic->name,
+ logic_name))
continue;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Provider `%s' satisfied\n",
- provider_name);
- for (unsigned int j = 0; j<kp->num_checks; j++)
- {
- const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Provider satisfies check `%s'\n",
- kc->name);
- if (NULL != rc->kyc_details)
- {
- GNUNET_assert (0 ==
- json_object_set_new (
- rc->kyc_details,
- kc->name,
- json_object ()));
- }
- for (unsigned int k = 0; k<*rc->needed_cnt; k++)
- if (kc == rc->needed[k])
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Removing check `%s' from list\n",
- kc->name);
- rc->needed[k] = rc->needed[*rc->needed_cnt - 1];
- (*rc->needed_cnt)--;
- if (0 == *rc->needed_cnt)
- return; /* for sure finished */
- break;
- }
- }
- break;
+ if (GNUNET_OK !=
+ cb (cb_cls,
+ kp->pd,
+ kp->logic->cls))
+ return;
}
}
@@ -1724,12 +1657,12 @@ enum GNUNET_DB_QueryStatus
TALER_KYCLOGIC_kyc_test_required (
enum TALER_KYCLOGIC_KycTriggerEvent event,
const struct TALER_PaytoHashP *h_payto,
- TALER_KYCLOGIC_KycSatisfiedIterator ki,
- void *ki_cls,
+ const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
TALER_KYCLOGIC_KycAmountIterator ai,
void *ai_cls,
- char **required)
+ struct TALER_KYCLOGIC_KycRule **triggered_rule)
{
+#if FIXME
struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
unsigned int needed_cnt = 0;
char *ret;
@@ -1865,28 +1798,247 @@ TALER_KYCLOGIC_kyc_test_required (
}
*required = ret;
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+#else
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+#endif
}
-void
-TALER_KYCLOGIC_kyc_get_details (
- const char *logic_name,
- TALER_KYCLOGIC_DetailsCallback cb,
- void *cb_cls)
+/* end of kyclogic_api.c */
+
+#if 0
+// FIXME from here...
+
+
+/**
+ * Closure for the #eval_trigger().
+ */
+struct ThresholdTestContext
+{
+ /**
+ * Total amount so far.
+ */
+ struct TALER_Amount total;
+
+ /**
+ * Trigger event to evaluate triggers of.
+ */
+ enum TALER_KYCLOGIC_KycTriggerEvent event;
+
+ /**
+ * Offset in the triggers array where we need to start
+ * checking for triggers. All trigges below this
+ * offset were already hit.
+ */
+ unsigned int start;
+
+ /**
+ * Array of checks needed so far.
+ */
+ struct TALER_KYCLOGIC_KycCheck **needed;
+
+ /**
+ * Pointer to number of entries used in @a needed.
+ */
+ unsigned int *needed_cnt;
+
+ /**
+ * Has @e total been initialized yet?
+ */
+ bool have_total;
+};
+
+
+/**
+ * Function called on each @a amount that was found to
+ * be relevant for a KYC check.
+ *
+ * @param cls closure to allow the KYC module to
+ * total up amounts and evaluate rules
+ * @param amount encountered transaction amount
+ * @param date when was the amount encountered
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to abort iteration
+ * #GNUNET_SYSERR on internal error (also abort itaration)
+ */
+static enum GNUNET_GenericReturnValue
+eval_trigger (void *cls,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute date)
{
+ struct ThresholdTestContext *ttc = cls;
+ struct GNUNET_TIME_Relative duration;
+ bool bump = true;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC check with new amount %s\n",
+ TALER_amount2s (amount));
+ duration = GNUNET_TIME_absolute_get_duration (date);
+ if (ttc->have_total)
+ {
+ if (0 >
+ TALER_amount_add (&ttc->total,
+ &ttc->total,
+ amount))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ {
+ ttc->total = *amount;
+ ttc->have_total = true;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC check: new total is %s\n",
+ TALER_amount2s (&ttc->total));
+ for (unsigned int i = ttc->start; i<num_kyc_triggers; i++)
+ {
+ const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
+
+ if (ttc->event != kt->trigger)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC check #%u: trigger type does not match\n",
+ i);
+ continue;
+ }
+ duration = GNUNET_TIME_relative_max (duration,
+ kt->timeframe);
+ if (GNUNET_TIME_relative_cmp (kt->timeframe,
+ >,
+ duration))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC check #%u: amount is beyond time limit\n",
+ i);
+ if (bump)
+ ttc->start = i;
+ return GNUNET_OK;
+ }
+ if (-1 ==
+ TALER_amount_cmp (&ttc->total,
+ &kt->threshold))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC check #%u: amount is below threshold\n",
+ i);
+ if (bump)
+ ttc->start = i;
+ bump = false;
+ continue; /* amount too low to trigger */
+ }
+ /* add check to list of required checks, unless
+ already present... */
+ for (unsigned int j = 0; j<kt->num_checks; j++)
+ {
+ struct TALER_KYCLOGIC_KycCheck *rc = kt->required_checks[j];
+ bool found = false;
+
+ for (unsigned int k = 0; k<*ttc->needed_cnt; k++)
+ if (ttc->needed[k] == rc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC rule #%u already listed\n",
+ j);
+ found = true;
+ break;
+ }
+ if (! found)
+ {
+ ttc->needed[*ttc->needed_cnt] = rc;
+ (*ttc->needed_cnt)++;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC check #%u (%s) is applicable, %u checks needed so far\n",
+ i,
+ ttc->needed[(*ttc->needed_cnt) - 1]->name,
+ *ttc->needed_cnt);
+ }
+ if (bump)
+ return GNUNET_NO; /* we hit all possible triggers! */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Closure for the #remove_satisfied().
+ */
+struct RemoveContext
+{
+
+ /**
+ * Array of checks needed so far.
+ */
+ struct TALER_KYCLOGIC_KycCheck **needed;
+
+ /**
+ * Pointer to number of entries used in @a needed.
+ */
+ unsigned int *needed_cnt;
+
+ /**
+ * Object with information about collected KYC data.
+ */
+ json_t *kyc_details;
+};
+
+
+/**
+ * Remove all checks satisfied by @a provider_name from
+ * our list of checks.
+ *
+ * @param cls a `struct RemoveContext`
+ * @param provider_name section name of provider that was already run
previously
+ */
+static void
+remove_satisfied (void *cls,
+ const char *provider_name)
+{
+ struct RemoveContext *rc = cls;
+
for (unsigned int i = 0; i<num_kyc_providers; i++)
{
- struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
+ const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
- if (0 !=
- strcmp (kp->logic->name,
- logic_name))
+ if (0 != strcasecmp (provider_name,
+ kp->provider_section_name))
continue;
- if (GNUNET_OK !=
- cb (cb_cls,
- kp->pd,
- kp->logic->cls))
- return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Provider `%s' satisfied\n",
+ provider_name);
+ for (unsigned int j = 0; j<kp->num_checks; j++)
+ {
+ const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Provider satisfies check `%s'\n",
+ kc->name);
+ if (NULL != rc->kyc_details)
+ {
+ GNUNET_assert (0 ==
+ json_object_set_new (
+ rc->kyc_details,
+ kc->name,
+ json_object ()));
+ }
+ for (unsigned int k = 0; k<*rc->needed_cnt; k++)
+ if (kc == rc->needed[k])
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Removing check `%s' from list\n",
+ kc->name);
+ rc->needed[k] = rc->needed[*rc->needed_cnt - 1];
+ (*rc->needed_cnt)--;
+ if (0 == *rc->needed_cnt)
+ return; /* for sure finished */
+ break;
+ }
+ }
+ break;
}
}
@@ -1982,132 +2134,6 @@ TALER_KYCLOGIC_check_satisfied (
}
-enum GNUNET_GenericReturnValue
-TALER_KYCLOGIC_requirements_to_logic (
- const char *requirements,
- enum TALER_KYCLOGIC_KycUserType ut,
- struct TALER_KYCLOGIC_Plugin **plugin,
- struct TALER_KYCLOGIC_ProviderDetails **pd,
- const char **configuration_section)
-{
- 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) )
- {
- min_cost = kp->cost;
- kp_best = kp;
- }
- }
- GNUNET_assert (NULL != kp_best);
- *plugin = kp_best->logic;
- *pd = kp_best->pd;
- *configuration_section = kp_best->provider_section_name;
- return GNUNET_OK;
-}
-
-
-enum GNUNET_GenericReturnValue
-TALER_KYCLOGIC_lookup_logic (
- const char *name,
- struct TALER_KYCLOGIC_Plugin **plugin,
- struct TALER_KYCLOGIC_ProviderDetails **pd,
- const char **provider_section)
-{
- for (unsigned int i = 0; i<num_kyc_providers; i++)
- {
- struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
-
- if (0 !=
- strcasecmp (name,
- kp->provider_section_name))
- continue;
- *plugin = kp->logic;
- *pd = kp->pd;
- *provider_section = kp->provider_section_name;
- return GNUNET_OK;
- }
- for (unsigned int i = 0; i<num_kyc_logics; i++)
- {
- struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i];
-
- if (0 !=
- strcasecmp (logic->name,
- name))
- continue;
- *plugin = logic;
- *pd = NULL;
- *provider_section = NULL;
- return GNUNET_OK;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Provider `%s' unknown\n",
- name);
- return GNUNET_SYSERR;
-}
-
-
void
TALER_KYCLOGIC_kyc_iterate_thresholds (
enum TALER_KYCLOGIC_KycTriggerEvent event,
diff --git a/src/kyclogic/taler-exchange-kyc-tester.c
b/src/kyclogic/taler-exchange-kyc-tester.c
index e942ff7a8..629de5995 100644
--- a/src/kyclogic/taler-exchange-kyc-tester.c
+++ b/src/kyclogic/taler-exchange-kyc-tester.c
@@ -278,9 +278,9 @@ static int run_webservice;
static int global_ret;
/**
- * -r command-line flag.
+ * -m command-line flag.
*/
-static char *requirements;
+static char *measure;
/**
* Handle for ongoing initiation operation.
@@ -1466,19 +1466,21 @@ run (void *cls,
return;
}
global_ret = EXIT_SUCCESS;
- if (NULL != requirements)
+ if (NULL != measure)
{
struct TALER_KYCLOGIC_ProviderDetails *pd;
if (GNUNET_OK !=
- TALER_KYCLOGIC_requirements_to_logic (requirements,
+ TALER_KYCLOGIC_requirements_to_logic (NULL, /* FIXME! */
+ NULL, /* FIXME! */
+ measure,
&ih_logic,
&pd,
&provider_section_name))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not initiate KYC for requirements `%s' (configuration
error?)\n",
- requirements);
+ "Could not initiate KYC for measure `%s' (configuration
error?)\n",
+ measure);
global_ret = EXIT_NOTCONFIGURED;
GNUNET_SCHEDULER_shutdown ();
return;
@@ -1575,11 +1577,11 @@ main (int argc,
"run the integrated HTTP service",
&run_webservice),
GNUNET_GETOPT_option_string (
- 'R',
- "requirements",
- "CHECKS",
- "initiate KYC check for the given list of (space-separated) checks",
- &requirements),
+ 'm',
+ "measure",
+ "MEASURE_NAME",
+ "initiate KYC check for the selected measure",
+ &measure),
GNUNET_GETOPT_option_string (
'u',
"user",
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-exchange] 84/151: add account_sig for authorization, (continued)
- [taler-exchange] 84/151: add account_sig for authorization, gnunet, 2024/07/30
- [taler-exchange] 19/151: -fix comment, gnunet, 2024/07/30
- [taler-exchange] 60/151: implement TALER_EXCHANGE_lookup_kyc_attributes, gnunet, 2024/07/30
- [taler-exchange] 36/151: store provider_name, instead of provider_section, gnunet, 2024/07/30
- [taler-exchange] 48/151: add spa logic, gnunet, 2024/07/30
- [taler-exchange] 87/151: skeleton, gnunet, 2024/07/30
- [taler-exchange] 78/151: WIP: kyc-start, gnunet, 2024/07/30
- [taler-exchange] 47/151: -towards having 3 SPAs, gnunet, 2024/07/30
- [taler-exchange] 112/151: more bugfixes, gnunet, 2024/07/30
- [taler-exchange] 24/151: fix purses_merge, gnunet, 2024/07/30
- [taler-exchange] 22/151: basic refactoring of httpd for new AML, incomplete,
gnunet <=
- [taler-exchange] 27/151: -fix more build issues, gnunet, 2024/07/30
- [taler-exchange] 98/151: add logic to parse measures from configuration, gnunet, 2024/07/30
- [taler-exchange] 35/151: fix FTBFS, gnunet, 2024/07/30
- [taler-exchange] 79/151: -bump gana, gnunet, 2024/07/30
- [taler-exchange] 89/151: -improve logging, gnunet, 2024/07/30
- [taler-exchange] 80/151: -fix FTBFS of new kyc-start logic, gnunet, 2024/07/30
- [taler-exchange] 90/151: pass h_payto, gnunet, 2024/07/30
- [taler-exchange] 106/151: -fixing minor bugs, gnunet, 2024/07/30
- [taler-exchange] 59/151: -implement GET "/aml/$PUB/attributes/$H_PAYTO", gnunet, 2024/07/30
- [taler-exchange] 95/151: -fix auditor insanity, gnunet, 2024/07/30