aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-08-08 19:22:13 +0200
committerChristian Grothoff <christian@grothoff.org>2024-08-08 19:22:20 +0200
commit6ef309790ffa8d1dda5e6604cfe9bc6763831668 (patch)
treeebd6f80242ef055f337f5686750e1424a2494763 /src
parente008de3ea47db34ffd6ed029bcf12fa7bfe668e1 (diff)
return current threshold and expiration date with kyc-wallet endpoint
Diffstat (limited to 'src')
-rw-r--r--src/exchange/taler-exchange-aggregator.c17
-rw-r--r--src/exchange/taler-exchange-httpd_common_kyc.c15
-rw-r--r--src/exchange/taler-exchange-httpd_common_kyc.h12
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-wallet.c35
-rw-r--r--src/include/taler_amount_lib.h14
-rw-r--r--src/include/taler_exchange_service.h18
-rw-r--r--src/include/taler_kyclogic_lib.h7
-rw-r--r--src/kyclogic/kyclogic_api.c28
-rw-r--r--src/kyclogic/taler-exchange-kyc-tester.c17
-rw-r--r--src/lib/exchange_api_kyc_wallet.c26
-rw-r--r--src/testing/test_kyc_api.c4
-rw-r--r--src/util/amount.c23
12 files changed, 193 insertions, 23 deletions
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index b4ff32cd2..5a7be23b5 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -528,12 +528,17 @@ legitimization_satisfied (struct AggregationUnit *au_active)
json_decref (jrules);
}
}
- qs = TALER_KYCLOGIC_kyc_test_required (
- TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT,
- lrs,
- &return_relevant_amounts,
- (void *) au_active,
- &requirement);
+ {
+ struct TALER_Amount next_threshold;
+
+ qs = TALER_KYCLOGIC_kyc_test_required (
+ TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT,
+ lrs,
+ &return_relevant_amounts,
+ (void *) au_active,
+ &requirement,
+ &next_threshold);
+ }
if (qs < 0)
{
TALER_KYCLOGIC_rules_free (lrs);
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c
index 8bcda3977..0ac1fbc25 100644
--- a/src/exchange/taler-exchange-httpd_common_kyc.c
+++ b/src/exchange/taler-exchange-httpd_common_kyc.c
@@ -1440,6 +1440,11 @@ legitimization_check_run (
/* AML/KYC disabled, just immediately return success! */
lch->lcr.kyc.requirement_row = 0;
lch->lcr.kyc.ok = true;
+ lch->lcr.expiration_date
+ = GNUNET_TIME_UNIT_FOREVER_TS;
+ memset (&lch->lcr.next_threshold,
+ 0,
+ sizeof (struct TALER_Amount));
lch->lcr.http_status = 0;
lch->lcr.response = NULL;
lch->async_task
@@ -1509,7 +1514,8 @@ legitimization_check_run (
lrs,
lch->ai,
lch->ai_cls,
- &requirement);
+ &requirement,
+ &lch->lcr.next_threshold);
if (qs < 0)
{
TALER_KYCLOGIC_rules_free (lrs);
@@ -1521,8 +1527,13 @@ legitimization_check_run (
if (NULL == requirement)
{
- TALER_KYCLOGIC_rules_free (lrs);
lch->lcr.kyc.ok = true;
+ lch->lcr.expiration_date
+ = TALER_KYCLOGIC_rules_get_expiration (lrs);
+ TALER_KYCLOGIC_rules_free (lrs);
+ memset (&lch->lcr.next_threshold,
+ 0,
+ sizeof (struct TALER_Amount));
/* return success! */
lch->async_task
= GNUNET_SCHEDULER_add_now (
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.h b/src/exchange/taler-exchange-httpd_common_kyc.h
index 68fc31768..cd753746b 100644
--- a/src/exchange/taler-exchange-httpd_common_kyc.h
+++ b/src/exchange/taler-exchange-httpd_common_kyc.h
@@ -195,6 +195,18 @@ struct TEH_LegitimizationCheckResult
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
+ * Smallest amount (over any timeframe) that may
+ * require additional KYC checks (if @a kyc.ok).
+ */
+ struct TALER_Amount next_threshold;
+
+ /**
+ * When do the current KYC rules possibly expire.
+ * Only valid if @a kyc.ok.
+ */
+ struct GNUNET_TIME_Timestamp expiration_date;
+
+ /**
* HTTP status code for @a response, or 0
*/
unsigned int http_status;
diff --git a/src/exchange/taler-exchange-httpd_kyc-wallet.c b/src/exchange/taler-exchange-httpd_kyc-wallet.c
index a74f6eca6..0e992f5f3 100644
--- a/src/exchange/taler-exchange-httpd_kyc-wallet.c
+++ b/src/exchange/taler-exchange-httpd_kyc-wallet.c
@@ -93,6 +93,18 @@ struct KycRequestContext
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
+ * Smallest amount (over any timeframe) that may
+ * require additional KYC checks (if @a kyc.ok).
+ */
+ struct TALER_Amount next_threshold;
+
+ /**
+ * When do the current KYC rules possibly expire.
+ * Only valid if @a kyc.ok.
+ */
+ struct GNUNET_TIME_Timestamp expiration_date;
+
+ /**
* HTTP status code for @a response, or 0
*/
unsigned int http_status;
@@ -173,10 +185,15 @@ legi_result_cb (
{
struct KycRequestContext *krc = cls;
+ GNUNET_assert (0 ==
+ lcr->expiration_date.abs_time.abs_value_us
+ % GNUNET_TIME_UNIT_SECONDS.rel_value_us);
krc->lch = NULL;
krc->http_status = lcr->http_status;
krc->response = lcr->response;
krc->kyc = lcr->kyc;
+ krc->next_threshold = lcr->next_threshold;
+ krc->expiration_date = lcr->expiration_date;
GNUNET_CONTAINER_DLL_remove (krc_head,
krc_tail,
krc);
@@ -289,13 +306,21 @@ TEH_handler_kyc_wallet (
krc->response);
if (krc->kyc.ok)
{
+ bool have_ts
+ = TALER_amount_is_valid (&krc->next_threshold);
+
+
/* KYC not required or already satisfied */
- return TALER_MHD_reply_static (
+ return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
- MHD_HTTP_NO_CONTENT,
- NULL,
- NULL,
- 0);
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_timestamp ("expiration_time",
+ krc->expiration_date),
+ GNUNET_JSON_pack_allow_null (
+ TALER_JSON_pack_amount ("next_threshold",
+ have_ts
+ ? &krc->next_threshold
+ : NULL)));
}
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&krc->h_payto,
diff --git a/src/include/taler_amount_lib.h b/src/include/taler_amount_lib.h
index 937238d15..71af13932 100644
--- a/src/include/taler_amount_lib.h
+++ b/src/include/taler_amount_lib.h
@@ -251,6 +251,20 @@ TALER_amount_cmp (const struct TALER_Amount *a1,
/**
+ * Compute maximum of two amounts.
+ *
+ * @param[out] ma set to maximum of @a a1 and @a a2
+ * @param a1 first amount
+ * @param a2 second amount
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+TALER_amount_max (struct TALER_Amount *ma,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2);
+
+
+/**
* Compare the value/fraction of two amounts. Does not compare the currency.
* Comparing amounts of different currencies will cause the program to abort().
* If unsure, check with #TALER_amount_cmp_currency() first to be sure that
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index ab8b799ac..f937d9293 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -4745,6 +4745,24 @@ struct TALER_EXCHANGE_WalletKycResponse
union
{
+ struct
+ {
+
+ /**
+ * Above which amount does the wallet need to check
+ * for KYC again?
+ */
+ struct TALER_Amount next_threshold;
+
+ /**
+ * When will the current set of AML/KYC rules
+ * expire (and the wallet should again check
+ * for new KYC requirements)?
+ */
+ struct GNUNET_TIME_Timestamp expiration_time;
+
+ } ok;
+
/**
* Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
*/
diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h
index b852ba14c..d146b0c57 100644
--- a/src/include/taler_kyclogic_lib.h
+++ b/src/include/taler_kyclogic_lib.h
@@ -331,6 +331,10 @@ TALER_KYCLOGIC_rules_free (struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs);
* is triggered, otherwise the rule with measures
* that must be satisfied (will be the highest
* applicable rule by display priority)
+ * @param[out] next_threshold set to the next amount
+ * that may trigger a KYC check (note: only really
+ * useful for the wallet balance right now, as we
+ * cannot easily state the applicable timeframe)
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
@@ -339,7 +343,8 @@ TALER_KYCLOGIC_kyc_test_required (
const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
TALER_KYCLOGIC_KycAmountIterator ai,
void *ai_cls,
- const struct TALER_KYCLOGIC_KycRule **triggered_rule);
+ const struct TALER_KYCLOGIC_KycRule **triggered_rule,
+ struct TALER_Amount *next_threshold);
/**
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
index 066fd1202..1deac34ff 100644
--- a/src/kyclogic/kyclogic_api.c
+++ b/src/kyclogic/kyclogic_api.c
@@ -300,6 +300,11 @@ struct GNUNET_TIME_Timestamp
TALER_KYCLOGIC_rules_get_expiration (
const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs)
{
+ if (NULL == lrs)
+ return GNUNET_TIME_UNIT_FOREVER_TS;
+ GNUNET_assert (0 ==
+ lrs->expiration_time.abs_time.abs_value_us
+ % GNUNET_TIME_UNIT_SECONDS.rel_value_us);
return lrs->expiration_time;
}
@@ -530,6 +535,9 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
JSON_INDENT (2));
return NULL;
}
+ GNUNET_assert (0 ==
+ expiration_time.abs_time.abs_value_us
+ % GNUNET_TIME_UNIT_SECONDS.rel_value_us);
lrs = GNUNET_new (struct TALER_KYCLOGIC_LegitimizationRuleSet);
lrs->expiration_time = expiration_time;
lrs->successor_measure
@@ -2644,6 +2652,7 @@ struct KycTestContext
* Set to the triggered rule.
*/
const struct TALER_KYCLOGIC_KycRule *triggered_rule;
+
};
@@ -2736,12 +2745,17 @@ TALER_KYCLOGIC_kyc_test_required (
const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
TALER_KYCLOGIC_KycAmountIterator ai,
void *ai_cls,
- const struct TALER_KYCLOGIC_KycRule **triggered_rule)
+ const struct TALER_KYCLOGIC_KycRule **triggered_rule,
+ struct TALER_Amount *next_threshold)
{
struct GNUNET_TIME_Relative range
= GNUNET_TIME_UNIT_ZERO;
enum GNUNET_DB_QueryStatus qs;
+ bool have_threshold = false;
+ memset (next_threshold,
+ 0,
+ sizeof (struct TALER_Amount));
if (NULL == lrs)
lrs = &default_rules;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -2755,6 +2769,18 @@ TALER_KYCLOGIC_kyc_test_required (
if (event != rule->trigger)
continue;
+ if (have_threshold)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_max (next_threshold,
+ next_threshold,
+ &rule->threshold));
+ }
+ else
+ {
+ *next_threshold = rule->threshold;
+ have_threshold = true;
+ }
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Matched rule %u with timeframe %s\n",
i,
diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c
index 841fe939a..021b10fb8 100644
--- a/src/kyclogic/taler-exchange-kyc-tester.c
+++ b/src/kyclogic/taler-exchange-kyc-tester.c
@@ -1586,12 +1586,17 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- qs = TALER_KYCLOGIC_kyc_test_required (
- event,
- lrs,
- &amount_iterator,
- &trigger_amount,
- &rule);
+ {
+ struct TALER_Amount next_threshold;
+
+ qs = TALER_KYCLOGIC_kyc_test_required (
+ event,
+ lrs,
+ &amount_iterator,
+ &trigger_amount,
+ &rule,
+ &next_threshold);
+ }
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
diff --git a/src/lib/exchange_api_kyc_wallet.c b/src/lib/exchange_api_kyc_wallet.c
index b12657a64..695a6cfde 100644
--- a/src/lib/exchange_api_kyc_wallet.c
+++ b/src/lib/exchange_api_kyc_wallet.c
@@ -91,6 +91,32 @@ handle_kyc_wallet_finished (void *cls,
case 0:
ks.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
+ case MHD_HTTP_OK:
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount_any (
+ "next_threshold",
+ &ks.details.ok.next_threshold),
+ NULL),
+ GNUNET_JSON_spec_timestamp (
+ "expiration_time",
+ &ks.details.ok.expiration_time),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (j,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ ks.hr.http_status = 0;
+ ks.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ break;
+ }
case MHD_HTTP_NO_CONTENT:
break;
case MHD_HTTP_BAD_REQUEST:
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index 423198433..01fda98c5 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -642,7 +642,7 @@ run (void *cls,
"wallet-trigger-kyc-for-aml-allowed",
"wallet-trigger-kyc-for-aml",
"EUR:1000",
- MHD_HTTP_NO_CONTENT),
+ MHD_HTTP_OK),
TALER_TESTING_cmd_wallet_kyc_get (
"wallet-trigger-kyc-for-aml-denied-high",
"wallet-trigger-kyc-for-aml",
@@ -739,7 +739,7 @@ run (void *cls,
"wallet-trigger-kyc-for-form-aml-allowed",
"wallet-trigger-kyc-for-form-aml",
"EUR:500",
- MHD_HTTP_NO_CONTENT),
+ MHD_HTTP_OK),
TALER_TESTING_cmd_end ()
};
diff --git a/src/util/amount.c b/src/util/amount.c
index cce84d73a..d102b4d94 100644
--- a/src/util/amount.c
+++ b/src/util/amount.c
@@ -270,6 +270,29 @@ TALER_amount_is_valid (const struct TALER_Amount *amount)
}
+enum GNUNET_GenericReturnValue
+TALER_amount_max (struct TALER_Amount *ma,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
+{
+ if (GNUNET_OK !=
+ TALER_amount_cmp_currency (a1,
+ a2))
+ {
+ memset (ma,
+ 0,
+ sizeof (*ma));
+ return GNUNET_SYSERR;
+ }
+ if (1 == TALER_amount_cmp (a1,
+ a2))
+ *ma = *a1;
+ else
+ *ma = *a2;
+ return GNUNET_OK;
+}
+
+
bool
TALER_amount_is_zero (const struct TALER_Amount *amount)
{