commit c673e775b442f2dff0f8398bcb7ef8d74100311f
parent 2cbb2d4405890418a612d30619b1eb4a4369a475
Author: Florian Dold <florian@dold.me>
Date: Wed, 26 Mar 2025 23:32:37 +0100
harness: new kyc-decision-events test
Diffstat:
4 files changed, 152 insertions(+), 0 deletions(-)
diff --git a/packages/taler-harness/src/harness/environments.ts b/packages/taler-harness/src/harness/environments.ts
@@ -1036,6 +1036,7 @@ export async function postAmlDecision(
properties?: AccountProperties;
attributes?: Object;
attributes_expiration?: TalerProtocolTimestamp;
+ events?: string[];
},
) {
const { exchangeBaseUrl, paytoHash, amlPriv, amlPub } = req;
@@ -1058,6 +1059,7 @@ export async function postAmlDecision(
...sigData,
officer_sig: encodeCrock(sig),
payto_uri: req.paytoUri,
+ events: req.events,
};
const reqUrl = new URL(`aml/${amlPub}/decision`, exchangeBaseUrl);
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-decision-events.ts b/packages/taler-harness/src/integrationtests/test-kyc-decision-events.ts
@@ -0,0 +1,142 @@
+/*
+ This file is part of GNU Taler
+ (C) 2024 Taler Systems S.A.
+
+ GNU 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.
+
+ GNU 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
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Imports.
+ */
+import {
+ codecForAny,
+ Configuration,
+ decodeCrock,
+ Duration,
+ encodeCrock,
+ hashNormalizedPaytoUri,
+ j2s,
+ LimitOperationType,
+ signAmlQuery,
+ TalerProtocolTimestamp,
+} from "@gnu-taler/taler-util";
+import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
+import { createSyncCryptoApi } from "@gnu-taler/taler-wallet-core";
+import {
+ configureCommonKyc,
+ createKycTestkudosEnvironment,
+ postAmlDecision,
+} from "../harness/environments.js";
+import {
+ getTestHarnessPaytoForLabel,
+ GlobalTestState,
+ harnessHttpLib,
+} from "../harness/harness.js";
+
+function adjustExchangeConfig(config: Configuration) {
+ configureCommonKyc(config);
+
+ config.setString("KYC-RULE-R1", "operation_type", "withdraw");
+ config.setString("KYC-RULE-R1", "enabled", "yes");
+ config.setString("KYC-RULE-R1", "exposed", "yes");
+ config.setString("KYC-RULE-R1", "is_and_combinator", "no");
+ config.setString("KYC-RULE-R1", "threshold", "TESTKUDOS:100");
+ config.setString("KYC-RULE-R1", "timeframe", "1d");
+ config.setString("KYC-RULE-R1", "next_measures", "verboten");
+}
+
+/**
+ * Tests for making AML decisions.
+ * - Test making decisions on unknown accounts.
+ * - Test making decisions with default rules.
+ */
+export async function runKycDecisionEventsTest(t: GlobalTestState) {
+ // Set up test environment
+
+ // FIXME: Reduced test environment without merchant suffices
+ const {
+ walletClient,
+ bankClient,
+ exchange,
+ amlKeypair,
+ exchangeBankAccount,
+ } = await createKycTestkudosEnvironment(t, { adjustExchangeConfig });
+
+ const merchantPayto = getTestHarnessPaytoForLabel("merchant-default");
+
+ const cryptoApi = createSyncCryptoApi();
+
+ const kycPaytoHash = encodeCrock(hashNormalizedPaytoUri(merchantPayto));
+
+ await postAmlDecision(t, {
+ amlPriv: amlKeypair.priv,
+ amlPub: amlKeypair.pub,
+ exchangeBaseUrl: exchange.baseUrl,
+ paytoHash: kycPaytoHash,
+ paytoUri: merchantPayto,
+ attributes: { foo: 42 },
+ attributes_expiration: TalerProtocolTimestamp.never(),
+ events: ["bla", "spam", "eggs"],
+ newRules: {
+ expiration_time: TalerProtocolTimestamp.now(),
+ custom_measures: {},
+ rules: [
+ {
+ operation_type: LimitOperationType.deposit,
+ display_priority: 1,
+ exposed: true,
+ measures: ["verboten"],
+ threshold: "TESTKUDOS:10",
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({
+ days: 1,
+ }),
+ ),
+ },
+ {
+ operation_type: LimitOperationType.withdraw,
+ display_priority: 1,
+ exposed: true,
+ measures: ["verboten"],
+ threshold: "TESTKUDOS:0",
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({
+ days: 1,
+ }),
+ ),
+ },
+ ],
+ },
+ });
+
+ const sig = signAmlQuery(decodeCrock(amlKeypair.priv));
+
+ const attributesResp = await harnessHttpLib.fetch(
+ new URL(`aml/${amlKeypair.pub}/kyc-statistics/bla`, exchange.baseUrl).href,
+ {
+ headers: {
+ "Taler-AML-Officer-Signature": encodeCrock(sig),
+ },
+ },
+ );
+
+ const evtResp = await readSuccessResponseJsonOrThrow(
+ attributesResp,
+ codecForAny(),
+ );
+
+ console.log(j2s(evtResp));
+
+ t.assertDeepEqual(evtResp.counter, 1);
+}
+
+runKycDecisionEventsTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -55,6 +55,7 @@ import { runKycAmpFailureTest } from "./test-kyc-amp-failure.js";
import { runKycAmpTimeoutTest } from "./test-kyc-amp-timeout.js";
import { runKycBalanceWithdrawalTest } from "./test-kyc-balance-withdrawal.js";
import { runKycDecisionAttrTest } from "./test-kyc-decision-attr.js";
+import { runKycDecisionEventsTest } from "./test-kyc-decision-events.js";
import { runKycDecisionsTest } from "./test-kyc-decisions.js";
import { runKycDepositAggregateImplicitAuthTest } from "./test-kyc-deposit-aggregate-implicit-auth.js";
import { runKycDepositAggregateTest } from "./test-kyc-deposit-aggregate.js";
@@ -308,6 +309,7 @@ const allTests: TestMainFunction[] = [
runAgeRestrictionsMixedMerchantTest,
runAgeRestrictionsPeerTest,
runAgeRestrictionsDepositTest,
+ runKycDecisionEventsTest,
];
export interface TestRunSpec {
diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts
@@ -2011,6 +2011,12 @@ export interface AmlDecisionRequest {
// Expiration timestamp of the attributes.
// Mandatory if attributes are present.
attributes_expiration?: Timestamp;
+
+ // Array of AML/KYC events to trigger for statistics.
+ // Note that this information is not covered by the signature
+ // (which is OK as events are just for statistics).
+ // New since protocol **v24**.
+ events?: string[];
}
export interface KycRule {