commit 5bb1c3865627d53108ef602ee6339c4749664d73
parent 8156c65e18c08f98ac81c1e4bc86f643efd2e411
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 8 Jun 2026 21:53:17 +0200
properly signal tos_required
Diffstat:
3 files changed, 97 insertions(+), 2 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd_get-kyc-check-H_NORMALIZED_PAYTO.c b/src/exchange/taler-exchange-httpd_get-kyc-check-H_NORMALIZED_PAYTO.c
@@ -475,9 +475,21 @@ TEH_handler_kyc_check (
? "wallet"
: "account"));
tos_required = false;
- if (TEH_kyc_swap_tos_acceptance)
+ if ( (TEH_kyc_swap_tos_acceptance) &&
+ (NULL != TEH_tos_etag) )
{
- /* FIXME-#11183: derive tos_required from jrules! */
+ /* #11183: With the terms-of-service / KYC-auth swap enabled, and if
+ the rule set that applies to this account actually requires the
+ client to accept our terms of service, surface that requirement
+ up-front by returning the current ToS ETag below. This lets the
+ merchant backend submit a previously collected acceptance on the
+ user's behalf (via the accept-tos requirement it finds under
+ /kyc-info) instead of forcing the user to interact again. We
+ inspect the rules precisely (rather than just whether *some* KYC
+ is required), as the rule set may demand entirely different
+ measures here. */
+ tos_required =
+ TALER_KYCLOGIC_rules_require_tos_acceptance (jrules);
}
jlimits = TALER_KYCLOGIC_rules_to_limits (jrules,
is_wallet);
diff --git a/src/include/taler/taler_kyclogic_lib.h b/src/include/taler/taler_kyclogic_lib.h
@@ -516,6 +516,31 @@ TALER_KYCLOGIC_rules_to_limits (const json_t *jrules,
/**
+ * Name of the KYC form used to affirm acceptance of the exchange's
+ * terms of service. This is the ``form`` of the requirement returned
+ * by ``GET /kyc-info`` and the ``FORM_ID`` submitted to
+ * ``POST /kyc-upload/$ID`` for a terms-of-service acceptance.
+ */
+#define TALER_KYCLOGIC_TOS_ACCEPTANCE_FORM "accept-tos"
+
+
+/**
+ * Check if @a jrules contains a (still active) rule that requires the
+ * client to accept the exchange's terms of service, that is a rule one
+ * of whose measures resolves to a KYC check of type
+ * #TALER_KYCLOGIC_CT_FORM rendering the
+ * #TALER_KYCLOGIC_TOS_ACCEPTANCE_FORM form.
+ *
+ * @param jrules a ``LegitimizationRuleSet`` with KYC rules;
+ * NULL to use default rules
+ * @return true if terms-of-service acceptance is among the
+ * measures required by @a jrules
+ */
+bool
+TALER_KYCLOGIC_rules_require_tos_acceptance (const json_t *jrules);
+
+
+/**
* Parse the given @a jmeasures and return the measure
* at the @a measure_index.
*
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
@@ -1294,6 +1294,64 @@ TALER_KYCLOGIC_rules_to_limits (const json_t *jrules,
}
+bool
+TALER_KYCLOGIC_rules_require_tos_acceptance (const json_t *jrules)
+{
+ struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
+ const struct TALER_KYCLOGIC_LegitimizationRuleSet *rs;
+ bool found = false;
+
+ if (NULL == jrules)
+ {
+ /* default rules apply */
+ lrs = NULL;
+ rs = &default_rules;
+ }
+ else
+ {
+ lrs = TALER_KYCLOGIC_rules_parse (jrules);
+ if (NULL == lrs)
+ {
+ GNUNET_break_op (0);
+ return false;
+ }
+ rs = lrs;
+ }
+ for (unsigned int i = 0; (! found) && (i < rs->num_kyc_rules); i++)
+ {
+ const struct TALER_KYCLOGIC_KycRule *rule = &rs->kyc_rules[i];
+
+ for (unsigned int j = 0; j < rule->num_measures; j++)
+ {
+ const struct TALER_KYCLOGIC_Measure *m;
+ const struct TALER_KYCLOGIC_KycCheck *c;
+
+ /* Resolve the measure to its check exactly as GET /kyc-info does
+ (measure -> check -> form), so that our answer is consistent
+ with the requirements the merchant will observe there. */
+ m = find_measure (lrs,
+ rule->next_measures[j]);
+ if (NULL == m)
+ continue;
+ c = find_check (m->check_name);
+ if (NULL == c)
+ continue;
+ if ( (TALER_KYCLOGIC_CT_FORM == c->type) &&
+ (NULL != c->details.form.name) &&
+ (0 == strcasecmp (c->details.form.name,
+ TALER_KYCLOGIC_TOS_ACCEPTANCE_FORM)) )
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (NULL != lrs)
+ TALER_KYCLOGIC_rules_free (lrs);
+ return found;
+}
+
+
const struct TALER_KYCLOGIC_Measure *
TALER_KYCLOGIC_rule_get_instant_measure (
const struct TALER_KYCLOGIC_KycRule *r)