[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-core] 02/02: test using multiple form in kyc measures
From: |
gnunet |
Subject: |
[taler-wallet-core] 02/02: test using multiple form in kyc measures |
Date: |
Tue, 03 Dec 2024 15:13:12 +0100 |
This is an automated email from the git hooks/post-receive script.
sebasjm pushed a commit to branch master
in repository wallet-core.
commit 5e8bd098b1e1aac592ae893e2798d69aaac6d78c
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue Dec 3 11:13:02 2024 -0300
test using multiple form in kyc measures
---
packages/taler-harness/src/harness/environments.ts | 13 +-
packages/taler-harness/src/index.ts | 8 +
.../src/integrationtests/test-kyc-two-forms.ts | 399 +++++++++++++++++++++
.../src/integrationtests/testrunner.ts | 2 +
4 files changed, 418 insertions(+), 4 deletions(-)
diff --git a/packages/taler-harness/src/harness/environments.ts
b/packages/taler-harness/src/harness/environments.ts
index d5a4b1376..fa5d4a395 100644
--- a/packages/taler-harness/src/harness/environments.ts
+++ b/packages/taler-harness/src/harness/environments.ts
@@ -1101,9 +1101,14 @@ export async function postAmlDecision(
t.assertDeepEqual(resp.status, HttpStatusCode.NoContent);
}
+function defaultOnNotification(n: WalletNotification):void {
+ console.log("wallet-core notification", n);
+}
+
+
export interface KycEnvOptions {
coinConfig?: CoinConfig[];
-
+ onWalletNotification?: (n: WalletNotification) => void;
adjustExchangeConfig?(config: Configuration): void;
}
@@ -1118,6 +1123,7 @@ export interface KycTestEnv {
merchant: MerchantService;
}
+
export async function createKycTestkudosEnvironment(
t: GlobalTestState,
opts: KycEnvOptions = {},
@@ -1206,12 +1212,11 @@ export async function createKycTestkudosEnvironment(
await walletService.start();
await walletService.pingUntilAvailable();
+
const walletClient = new WalletClient({
name: "wallet",
unixPath: walletService.socketPath,
- onNotification(n) {
- console.log("wallet-core notification", n);
- },
+ onNotification: opts.onWalletNotification ?? defaultOnNotification,
});
await walletClient.connect();
await walletClient.client.call(WalletApiOperation.InitWallet, {
diff --git a/packages/taler-harness/src/index.ts
b/packages/taler-harness/src/index.ts
index 4de5b1527..de2b27a39 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -83,6 +83,7 @@ import {
import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
import { lintExchangeDeployment } from "./lint.js";
import { AML_PROGRAM_FROM_ATTRIBUTES_TO_CONTEXT } from
"integrationtests/test-kyc-skip-expiration.js";
+import { AML_PROGRAM_NEXT_MEASURE_FORM } from
"integrationtests/test-kyc-two-forms.js";
const logger = new Logger("taler-harness:index.ts");
@@ -1451,12 +1452,14 @@ const allAmlPrograms:
TalerKycAml.AmlProgramDefinition[] = [
requiredContext: [],
},
AML_PROGRAM_FROM_ATTRIBUTES_TO_CONTEXT,
+ AML_PROGRAM_NEXT_MEASURE_FORM,
];
amlProgramCli
.subcommand("run", "run-program")
.requiredOption("name", ["-n", "--name"], clk.STRING)
.flag("requires", ["-r"])
+ .flag("inputs", ["-i"])
.flag("attributes", ["-a"])
.maybeOption("config", ["-c", "--config"], clk.STRING)
.action(async (args) => {
@@ -1473,6 +1476,11 @@ amlProgramCli
console.log(found.requiredContext.join("\n"));
return;
}
+ if (args.run.inputs) {
+ logger.info("Reporting requirements");
+ console.log(found.requiredInputs.join("\n"));
+ return;
+ }
if (args.run.attributes) {
logger.info("reporting attributes");
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-two-forms.ts
b/packages/taler-harness/src/integrationtests/test-kyc-two-forms.ts
new file mode 100644
index 000000000..b3fb2fcf8
--- /dev/null
+++ b/packages/taler-harness/src/integrationtests/test-kyc-two-forms.ts
@@ -0,0 +1,399 @@
+/*
+ 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 {
+ AbsoluteTime,
+ AmountString,
+ amountToBuffer,
+ buildSigPS,
+ codecForAccountKycStatus,
+ codecForAny,
+ codecForKycProcessClientInformation,
+ codecForLegitimizationNeededResponse,
+ codecOptional,
+ Configuration,
+ createNewWalletKycAccount,
+ decodeCrock,
+ eddsaSign,
+ encodeCrock,
+ j2s,
+ Logger,
+ signAmlQuery,
+ TalerKycAml,
+ TalerProtocolTimestamp,
+ TalerSignaturePurpose,
+ TransactionIdStr,
+ TransactionMajorState,
+ TransactionMinorState,
+ WalletKycRequest,
+} from "@gnu-taler/taler-util";
+import { readResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import {
+ createKycTestkudosEnvironment,
+ postAmlDecision,
+ withdrawViaBankV3,
+} from "../harness/environments.js";
+import { GlobalTestState, harnessHttpLib, waitMs } from
"../harness/harness.js";
+
+const logger = new Logger("test-kyc-two-forms.ts");
+
+export const AML_PROGRAM_NEXT_MEASURE_FORM: TalerKycAml.AmlProgramDefinition =
{
+ name: "TWO_FORMS",
+ logic: (input, config) => {
+ const outcome: TalerKycAml.AmlOutcome = {
+ to_investigate: false,
+ properties: {},
+ events: [],
+ new_rules: {
+ expiration_time: { t_s: 1 },
+ rules: [],
+ successor_measure: "M2",
+ custom_measures: {},
+ },
+ };
+ logger.info("aml program TWO FORMS outcome", j2s(outcome));
+
+ return outcome;
+ },
+ requiredAttributes: [],
+ requiredInputs: [],
+ requiredContext: [],
+};
+
+function adjustExchangeConfig(config: Configuration) {
+ config.setString("exchange", "enable_kyc", "yes");
+
+ // 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:5");
+ // config.setString("KYC-RULE-R1", "timeframe", "1d");
+ // config.setString("KYC-RULE-R1", "next_measures", "M1");
+
+ config.setString("KYC-RULE-R1", "operation_type", "balance");
+ 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:5");
+ config.setString("KYC-RULE-R1", "timeframe", "forever");
+ config.setString("KYC-RULE-R1", "next_measures", "M1");
+
+ config.setString("KYC-MEASURE-M1", "check_name", "C1");
+ config.setString("KYC-MEASURE-M1", "context", "{}");
+ config.setString("KYC-MEASURE-M1", "program", "P1");
+
+ config.setString("KYC-MEASURE-M2", "check_name", "C2");
+ config.setString("KYC-MEASURE-M2", "context", "{}");
+ config.setString("KYC-MEASURE-M2", "program", "P2");
+
+ config.setString("KYC-MEASURE-M3", "check_name", "C3");
+ config.setString("KYC-MEASURE-M3", "context", "{}");
+ config.setString("KYC-MEASURE-M3", "program", "NOP");
+
+ config.setString("KYC-MEASURE-M4", "check_name", "C4");
+ config.setString("KYC-MEASURE-M4", "context", "{}");
+ config.setString("KYC-MEASURE-M4", "program", "NOP");
+
+ config.setString("KYC-MEASURE-MF", "check_name", "SKIP");
+ config.setString("KYC-MEASURE-MF", "context", "{}");
+ config.setString("KYC-MEASURE-MF", "program", "NOP");
+
+ config.setString(
+ "AML-PROGRAM-P1",
+ "command",
+ "taler-harness aml-program run-program --name TWO_FORMS",
+ );
+ config.setString("AML-PROGRAM-P1", "enabled", "true");
+ config.setString("AML-PROGRAM-P1", "description", "remove all rules");
+ config.setString("AML-PROGRAM-P1", "description_i18n", "{}");
+ config.setString("AML-PROGRAM-P1", "fallback", "M1");
+
+ config.setString("AML-PROGRAM-P2", "command", "/bin/true");
+ config.setString("AML-PROGRAM-P2", "enabled", "true");
+ config.setString("AML-PROGRAM-P2", "description", "does nothing");
+ config.setString("AML-PROGRAM-P2", "description_i18n", "{}");
+ config.setString("AML-PROGRAM-P2", "fallback", "M1");
+
+ config.setString("AML-PROGRAM-NOP", "command", "/bin/true");
+ config.setString("AML-PROGRAM-NOP", "enabled", "true");
+ config.setString(
+ "AML-PROGRAM-NOP",
+ "description",
+ "does nothing (never used)",
+ );
+ config.setString("AML-PROGRAM-NOP", "description_i18n", "{}");
+ config.setString("AML-PROGRAM-NOP", "fallback", "MF");
+
+ config.setString("KYC-CHECK-C1", "type", "FORM");
+ config.setString("KYC-CHECK-C1", "form_name", "firstForm");
+ config.setString("KYC-CHECK-C1", "description", "starting check!");
+ config.setString("KYC-CHECK-C1", "description_i18n", "{}");
+ config.setString("KYC-CHECK-C1", "outputs", "NAME");
+ config.setString("KYC-CHECK-C1", "fallback", "MF");
+
+ config.setString("KYC-CHECK-C2", "type", "FORM");
+ config.setString("KYC-CHECK-C2", "form_name", "secondForm");
+ config.setString("KYC-CHECK-C2", "description", "final check!");
+ config.setString("KYC-CHECK-C2", "description_i18n", "{}");
+ config.setString("KYC-CHECK-C2", "outputs", "FINAL");
+ config.setString("KYC-CHECK-C2", "fallback", "MF");
+
+ config.setString("KYC-CHECK-C3", "type", "FORM");
+ config.setString("KYC-CHECK-C3", "form_name", "thirdForm");
+ config.setString(
+ "KYC-CHECK-C3",
+ "description",
+ "this is check c3 (never used)",
+ );
+ config.setString("KYC-CHECK-C3", "description_i18n", "{}");
+ config.setString("KYC-CHECK-C3", "fallback", "MF");
+
+ config.setString("KYC-CHECK-C4", "type", "FORM");
+ config.setString("KYC-CHECK-C4", "form_name", "fourthForm");
+ config.setString(
+ "KYC-CHECK-C4",
+ "description",
+ "this is check c4 (never used)",
+ );
+ config.setString("KYC-CHECK-C4", "description_i18n", "{}");
+ config.setString("KYC-CHECK-C4", "fallback", "MF");
+}
+
+/**
+ * Test setting a `new_measure` as the AML officer.
+ */
+export async function runKycTwoFormsTest(t: GlobalTestState) {
+ // Set up test environment
+
+ const { exchange, amlKeypair } = await createKycTestkudosEnvironment(t, {
+ adjustExchangeConfig,
+ onWalletNotification: () => {},
+ });
+
+ // Withdraw digital cash into the wallet.
+ let kycPaytoHash: string;
+ let accessToken: string;
+ let latestFormId: string;
+
+ // {
+ // logger.info("step 1) Withdraw to trigger AML and 2) get access token")
+ // const wres = await withdrawViaBankV3(t, {
+ // amount: "TESTKUDOS:20",
+ // bankClient,
+ // exchange,
+ // walletClient,
+ // });
+
+ // await walletClient.call(WalletApiOperation.TestingWaitTransactionState,
{
+ // transactionId: wres.transactionId as TransactionIdStr,
+ // txState: {
+ // major: TransactionMajorState.Pending,
+ // minor: TransactionMinorState.KycRequired,
+ // },
+ // });
+
+ // const txDetails = await walletClient.call(
+ // WalletApiOperation.GetTransactionById,
+ // {
+ // transactionId: wres.transactionId,
+ // },
+ // );
+
+ // accessToken = txDetails.kycAccessToken;
+ // kycPaytoHash = txDetails.kycPaytoHash;
+ // firstTransaction = wres.transactionId;
+ // }
+ const account = await createNewWalletKycAccount(new Uint8Array());
+ {
+ logger.info("step 1) Check balance to trigger AML");
+
+ const balance: AmountString = "TESTKUDOS:20";
+ const sigBlob = buildSigPS(TalerSignaturePurpose.WALLET_ACCOUNT_SETUP)
+ .put(amountToBuffer(balance))
+ .build();
+ const body: WalletKycRequest = {
+ balance,
+ reserve_pub: account.id,
+ reserve_sig: encodeCrock(eddsaSign(sigBlob, account.signingKey)),
+ };
+ const infoResp = await harnessHttpLib.fetch(
+ new URL(`kyc-wallet`, exchange.baseUrl).href,
+ {
+ method: "POST",
+ body,
+ },
+ );
+
+ t.assertDeepEqual(infoResp.status, 451);
+ const clientInfo = await readResponseJsonOrThrow(
+ infoResp,
+ codecOptional(codecForLegitimizationNeededResponse()),
+ );
+
+ t.assertTrue(clientInfo?.h_payto !== undefined);
+ kycPaytoHash = clientInfo?.h_payto;
+ }
+
+ {
+ logger.info("step 2) Get account access token");
+ const sigBlob = buildSigPS(TalerSignaturePurpose.KYC_AUTH).build();
+
+ const infoResp = await harnessHttpLib.fetch(
+ new URL(`kyc-check/${kycPaytoHash}`, exchange.baseUrl).href,
+ {
+ headers: {
+ "Account-Owner-Signature": encodeCrock(
+ eddsaSign(sigBlob, account.signingKey),
+ ),
+ },
+ },
+ );
+
+ t.assertDeepEqual(infoResp.status, 202);
+ const clientInfo = await readResponseJsonOrThrow(
+ infoResp,
+ codecOptional(codecForAccountKycStatus()),
+ );
+ t.assertTrue(clientInfo?.access_token !== undefined);
+ accessToken = clientInfo?.access_token;
+ }
+
+ // {
+ // // step 2) Check KYC info
+ // const infoResp = await harnessHttpLib.fetch(
+ // new URL(`kyc-info/${accessToken}`, exchange.baseUrl).href,
+ // );
+
+ // const clientInfo = await readResponseJsonOrThrow(
+ // infoResp,
+ // codecOptional(codecForKycProcessClientInformation()),
+ // );
+
+ // console.log(j2s(clientInfo));
+ // t.assertDeepEqual(infoResp.status, 200);
+ // t.assertDeepEqual(clientInfo?.requirements.length, 1);
+ // t.assertDeepEqual(clientInfo?.requirements[0].form, "firstForm");
+ // }
+
+ {
+ logger.info("step 3) Check KYC info, should be waiting for the first
form");
+ const infoResp = await harnessHttpLib.fetch(
+ new URL(`kyc-info/${accessToken}?timeout_ms=1000`,
exchange.baseUrl).href,
+ );
+ const clientInfo = await readResponseJsonOrThrow(
+ infoResp,
+ codecOptional(codecForKycProcessClientInformation()),
+ );
+
+ console.log(j2s(clientInfo));
+ t.assertDeepEqual(infoResp.status, 200);
+ t.assertDeepEqual(clientInfo?.requirements.length, 1);
+ t.assertDeepEqual(clientInfo?.requirements[0].form, "firstForm");
+ t.assertTrue(!!clientInfo?.requirements[0].id);
+ latestFormId = clientInfo?.requirements[0].id;
+ }
+
+ {
+ logger.info("step 4) Complete form");
+ const infoResp = await harnessHttpLib.fetch(
+ new URL(`kyc-upload/${latestFormId}`, exchange.baseUrl).href,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ body: "NAME=who",
+ },
+ );
+
+ t.assertDeepEqual(infoResp.status, 204);
+ }
+
+ {
+ logger.info(
+ "step 5) Check KYC info again, should see the second form but this time
is too fast",
+ );
+
+ ///////////////////////////////////////////
+ // if the request is too early id result in garbage
+ // can't be ignored because browser see this
+ ///////////////////////////////////////////
+ {
+ const infoResp = await harnessHttpLib.fetch(
+ new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl)
+ .href,
+ );
+ {
+ const clientInfo = await readResponseJsonOrThrow(
+ infoResp,
+ codecOptional(codecForKycProcessClientInformation()),
+ );
+
+ console.log(j2s(clientInfo));
+ // t.assertDeepEqual(infoResp.status, 200);
+ // t.assertDeepEqual(clientInfo?.requirements.length, 1);
+ // t.assertDeepEqual(clientInfo?.requirements[0].form, "secondForm");
+
+ }
+ }
+ }
+
+ await waitMs(2000);
+ {
+ logger.info("step 6) Check KYC info again after some time, should see the
second form");
+ //doing a second request shouldnt fail
+ const infoResp = await harnessHttpLib.fetch(
+ new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl)
+ .href,
+ );
+
+ const clientInfo = await readResponseJsonOrThrow(
+ infoResp,
+ codecOptional(codecForKycProcessClientInformation()),
+ );
+
+ console.log(j2s(clientInfo));
+ t.assertDeepEqual(infoResp.status, 200);
+ t.assertDeepEqual(clientInfo?.requirements.length, 1);
+ t.assertDeepEqual(clientInfo?.requirements[0].form, "secondForm");
+ }
+
+ await waitMs(2000);
+
+ {
+ logger.info("step 6) Check KYC info again after some time, here the
exchange fails");
+ const infoResp = await harnessHttpLib.fetch(
+ new URL(`kyc-info/${accessToken}?timeout_ms=1000`,
exchange.baseUrl).href,
+ );
+
+ const clientInfo = await readResponseJsonOrThrow(
+ infoResp,
+ codecOptional(codecForKycProcessClientInformation()),
+ );
+
+ console.log(j2s(clientInfo));
+ t.assertDeepEqual(infoResp.status, 200);
+ t.assertDeepEqual(clientInfo?.requirements.length, 1);
+ t.assertDeepEqual(clientInfo?.requirements[0].form, "secondForm");
+ }
+}
+
+runKycTwoFormsTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts
b/packages/taler-harness/src/integrationtests/testrunner.ts
index 0816d2584..fefb35393 100644
--- a/packages/taler-harness/src/integrationtests/testrunner.ts
+++ b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -148,6 +148,7 @@ import { runWithdrawalHugeTest } from
"./test-withdrawal-huge.js";
import { runWithdrawalIdempotentTest } from "./test-withdrawal-idempotent.js";
import { runWithdrawalManualTest } from "./test-withdrawal-manual.js";
import { runWithdrawalPrepareTest } from "./test-withdrawal-prepare.js";
+import { runKycTwoFormsTest } from "./test-kyc-two-forms.js";
/**
* Test runner.
@@ -274,6 +275,7 @@ const allTests: TestMainFunction[] = [
runKycBalanceWithdrawalTest,
runKycNewMeasureTest,
runKycSkipExpirationTest,
+ runKycTwoFormsTest,
runKycDepositDepositTest,
runKycMerchantDepositTest,
runKycMerchantAggregateTest,
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.