[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-typescript-core] branch master updated: harness: add test for exc
From: |
Admin |
Subject: |
[taler-typescript-core] branch master updated: harness: add test for exchange kyc auth |
Date: |
Tue, 03 Jun 2025 20:30:11 +0200 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository taler-typescript-core.
The following commit(s) were added to refs/heads/master by this push:
new cca3196ed harness: add test for exchange kyc auth
cca3196ed is described below
commit cca3196ed9c61d3e3d92dcd18bea7a97d4526948
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Jun 3 20:29:55 2025 +0200
harness: add test for exchange kyc auth
Issue: https://bugs.taler.net/n/10044
---
packages/taler-harness/src/harness/environments.ts | 6 +-
.../src/integrationtests/test-exchange-kyc-auth.ts | 302 +++++++++++++++++++++
.../src/integrationtests/testrunner.ts | 2 +
.../taler-util/src/http-client/exchange-client.ts | 54 ++++
4 files changed, 361 insertions(+), 3 deletions(-)
diff --git a/packages/taler-harness/src/harness/environments.ts
b/packages/taler-harness/src/harness/environments.ts
index b4c598d63..ac56d857e 100644
--- a/packages/taler-harness/src/harness/environments.ts
+++ b/packages/taler-harness/src/harness/environments.ts
@@ -46,7 +46,7 @@ import {
succeedOrThrow,
TalerCorebankApiClient,
TalerCoreBankHttpClient,
- TalerExchangeHttpClient,
+ TalerExchangeHttpClient2,
TalerMerchantApi,
TalerMerchantInstanceHttpClient,
TalerProtocolTimestamp,
@@ -1098,7 +1098,7 @@ export interface KycTestEnv {
amlKeypair: EddsaKeyPairStrings;
merchant: MerchantService;
bankApi: TalerCoreBankHttpClient;
- exchangeApi: TalerExchangeHttpClient;
+ exchangeApi: TalerExchangeHttpClient2;
wireGatewayApi: TalerWireGatewayHttpClient;
merchantApi: TalerMerchantInstanceHttpClient;
}
@@ -1272,7 +1272,7 @@ export async function createKycTestkudosEnvironment(
harnessHttpLib,
);
- const exchangeApi = new TalerExchangeHttpClient(exchange.baseUrl, {
+ const exchangeApi = new TalerExchangeHttpClient2(exchange.baseUrl, {
httpClient: harnessHttpLib,
});
diff --git
a/packages/taler-harness/src/integrationtests/test-exchange-kyc-auth.ts
b/packages/taler-harness/src/integrationtests/test-exchange-kyc-auth.ts
new file mode 100644
index 000000000..0bd71c27e
--- /dev/null
+++ b/packages/taler-harness/src/integrationtests/test-exchange-kyc-auth.ts
@@ -0,0 +1,302 @@
+/*
+ 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 {
+ Configuration,
+ createEddsaKeyPair,
+ encodeCrock,
+ hashNormalizedPaytoUri,
+ HttpStatusCode,
+ j2s,
+ TalerWireGatewayHttpClient,
+ TransactionMajorState,
+ TransactionMinorState,
+} from "@gnu-taler/taler-util";
+import {
+ createSyncCryptoApi,
+ WalletApiOperation,
+} from "@gnu-taler/taler-wallet-core";
+import {
+ configureCommonKyc,
+ createKycTestkudosEnvironment,
+ withdrawViaBankV3,
+} from "../harness/environments.js";
+import {
+ getTestHarnessPaytoForLabel,
+ GlobalTestState,
+} from "../harness/harness.js";
+
+const myAmlConfig = `
+# Fallback measure on errors.
+[kyc-measure-freeze-investigate]
+CHECK_NAME = skip
+PROGRAM = freeze-investigate
+VOLUNTARY = NO
+CONTEXT = {}
+
+[aml-program-freeze-investigate]
+DESCRIPTION = "Fallback measure on errors that freezes the account and asks
AML staff to investigate the system failure."
+COMMAND = taler-exchange-helper-measure-freeze
+ENABLED = YES
+FALLBACK = freeze-investigate
+
+[aml-program-inform-investigate]
+DESCRIPTION = "Measure that asks AML staff to investigate an account and
informs the account owner about it."
+COMMAND = taler-exchange-helper-measure-inform-investigate
+ENABLED = YES
+FALLBACK = freeze-investigate
+
+[kyc-check-form-gls-merchant-onboarding]
+TYPE = FORM
+FORM_NAME = gls-merchant-onboarding
+DESCRIPTION = "GLS Merchant Onboarding"
+DESCRIPTION_I18N = {}
+OUTPUTS =
+FALLBACK = freeze-investigate
+
+[kyc-measure-merchant-onboarding]
+CHECK_NAME = form-gls-merchant-onboarding
+PROGRAM = inform-investigate
+CONTEXT = {}
+VOLUNTARY = NO
+
+[kyc-rule-deposit-limit-zero]
+OPERATION_TYPE = DEPOSIT
+NEXT_MEASURES = merchant-onboarding
+EXPOSED = YES
+ENABLED = YES
+THRESHOLD = TESTKUDOS:1
+TIMEFRAME = "1 days"
+`;
+
+function adjustExchangeConfig(config: Configuration) {
+ configureCommonKyc(config);
+ config.loadFromString(myAmlConfig);
+}
+
+/**
+ * Test for KYC auth, based on withdrawals and/or
+ * KYC auth transfers.
+ */
+export async function runExchangeKycAuthTest(t: GlobalTestState) {
+ // Set up test environment
+
+ // FIXME: Reduced test environment without merchant suffices
+ const {
+ walletClient,
+ bankClient,
+ exchange,
+ amlKeypair,
+ exchangeBankAccount,
+ exchangeApi,
+ } = await createKycTestkudosEnvironment(t, { adjustExchangeConfig });
+
+ const merchantPayto = getTestHarnessPaytoForLabel("merchant-default");
+
+ const cryptoApi = createSyncCryptoApi();
+
+ const wireGatewayApiClient = new TalerWireGatewayHttpClient(
+ exchangeBankAccount.wireGatewayApiBaseUrl,
+ );
+
+ const merchantPair = await cryptoApi.createEddsaKeypair({});
+
+ const wres = await withdrawViaBankV3(t, {
+ walletClient,
+ exchange,
+ bankClient,
+ amount: "TESTKUDOS:20",
+ });
+
+ const kycPaytoHash = encodeCrock(hashNormalizedPaytoUri(merchantPayto));
+
+ await wres.withdrawalFinishedCond;
+
+ // Use the wallet to trigger KYC
+
+ const depositResp = await walletClient.call(
+ WalletApiOperation.CreateDepositGroup,
+ {
+ amount: "TESTKUDOS:5",
+ depositPaytoUri: merchantPayto,
+ testingFixedPriv: merchantPair.priv,
+ },
+ );
+
+ // Wait until KYC got triggered.
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Pending,
+ minor: TransactionMinorState.KycAuthRequired,
+ },
+ });
+
+ await wireGatewayApiClient.addKycAuth({
+ body: {
+ account_pub: merchantPair.pub,
+ amount: "TESTKUDOS:0.1",
+ debit_account: merchantPayto,
+ },
+ auth: exchangeBankAccount.wireGatewayAuth,
+ });
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Pending,
+ minor: TransactionMinorState.KycRequired,
+ },
+ });
+
+ {
+ const sigResp = await cryptoApi.signWalletKycAuth({
+ accountPriv: merchantPair.priv,
+ accountPub: merchantPair.pub,
+ });
+ const checkResp1 = await exchangeApi.checkKycStatus({
+ accountPub: merchantPair.pub,
+ accountSig: sigResp.sig,
+ paytoHash: kycPaytoHash,
+ });
+
+ console.log(j2s(checkResp1));
+
+ t.assertDeepEqual(checkResp1.case, HttpStatusCode.Accepted);
+ }
+
+ const reservePair2 = createEddsaKeyPair();
+ const reservePair3 = createEddsaKeyPair();
+ const reservePair4 = createEddsaKeyPair();
+
+ {
+ const sigResp = await cryptoApi.signWalletKycAuth({
+ accountPriv: encodeCrock(reservePair2.eddsaPriv),
+ accountPub: encodeCrock(reservePair2.eddsaPub),
+ });
+ const checkResp = await exchangeApi.checkKycStatus({
+ accountPub: merchantPair.pub,
+ accountSig: sigResp.sig,
+ paytoHash: kycPaytoHash,
+ });
+
+ console.log(j2s(checkResp));
+
+ t.assertDeepEqual(checkResp.case, HttpStatusCode.Forbidden);
+ }
+
+ await wireGatewayApiClient.addIncoming({
+ body: {
+ reserve_pub: encodeCrock(reservePair2.eddsaPub),
+ amount: "TESTKUDOS:5",
+ debit_account: merchantPayto,
+ },
+ auth: exchangeBankAccount.wireGatewayAuth,
+ });
+
+ await wireGatewayApiClient.addIncoming({
+ body: {
+ reserve_pub: encodeCrock(reservePair3.eddsaPub),
+ amount: "TESTKUDOS:5",
+ debit_account: merchantPayto,
+ },
+ auth: exchangeBankAccount.wireGatewayAuth,
+ });
+
+ await wireGatewayApiClient.addIncoming({
+ body: {
+ reserve_pub: encodeCrock(reservePair4.eddsaPub),
+ amount: "TESTKUDOS:5",
+ debit_account: getTestHarnessPaytoForLabel("bob"),
+ },
+ auth: exchangeBankAccount.wireGatewayAuth,
+ });
+
+ await exchange.runWirewatchOnce();
+
+ // Even when no account pub is specified, the last reserve pub for
+ // the account must work.
+
+ {
+ const sigResp = await cryptoApi.signWalletKycAuth({
+ accountPriv: encodeCrock(reservePair3.eddsaPriv),
+ accountPub: encodeCrock(reservePair3.eddsaPub),
+ });
+ const checkResp = await exchangeApi.testingCheckKycStatusNoPub({
+ accountSig: sigResp.sig,
+ paytoHash: kycPaytoHash,
+ });
+
+ console.log(j2s(checkResp));
+
+ t.assertDeepEqual(checkResp.case, HttpStatusCode.Accepted);
+ }
+
+ // Now, kyc auth must work with explicit account key and both reserve pubs!
+
+ {
+ const sigResp = await cryptoApi.signWalletKycAuth({
+ accountPriv: merchantPair.priv,
+ accountPub: merchantPair.pub,
+ });
+ const checkResp = await exchangeApi.checkKycStatus({
+ accountPub: merchantPair.pub,
+ accountSig: sigResp.sig,
+ paytoHash: kycPaytoHash,
+ });
+
+ console.log(j2s(checkResp));
+
+ t.assertDeepEqual(checkResp.case, HttpStatusCode.Accepted);
+ }
+
+ {
+ const sigResp = await cryptoApi.signWalletKycAuth({
+ accountPriv: encodeCrock(reservePair3.eddsaPriv),
+ accountPub: encodeCrock(reservePair3.eddsaPub),
+ });
+ const checkResp = await exchangeApi.checkKycStatus({
+ accountPub: encodeCrock(reservePair3.eddsaPub),
+ accountSig: sigResp.sig,
+ paytoHash: kycPaytoHash,
+ });
+
+ console.log(j2s(checkResp));
+
+ t.assertDeepEqual(checkResp.case, HttpStatusCode.Accepted);
+ }
+
+ {
+ const sigResp = await cryptoApi.signWalletKycAuth({
+ accountPriv: encodeCrock(reservePair2.eddsaPriv),
+ accountPub: encodeCrock(reservePair2.eddsaPub),
+ });
+ const checkResp = await exchangeApi.checkKycStatus({
+ accountPub: encodeCrock(reservePair2.eddsaPub),
+ accountSig: sigResp.sig,
+ paytoHash: kycPaytoHash,
+ });
+
+ console.log(j2s(checkResp));
+
+ t.assertDeepEqual(checkResp.case, HttpStatusCode.Accepted);
+ }
+}
+
+runExchangeKycAuthTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts
b/packages/taler-harness/src/integrationtests/testrunner.ts
index 453d80014..dad48dcdd 100644
--- a/packages/taler-harness/src/integrationtests/testrunner.ts
+++ b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -49,6 +49,7 @@ import { runDepositFaultTest } from "./test-deposit-fault.js";
import { runDepositMergeTest } from "./test-deposit-merge.js";
import { runDepositTest } from "./test-deposit.js";
import { runExchangeDepositTest } from "./test-exchange-deposit.js";
+import { runExchangeKycAuthTest } from "./test-exchange-kyc-auth.js";
import { runExchangeManagementFaultTest } from
"./test-exchange-management-fault.js";
import { runExchangeManagementTest } from "./test-exchange-management.js";
import { runExchangeMasterPubChangeTest } from
"./test-exchange-master-pub-change.js";
@@ -347,6 +348,7 @@ const allTests: TestMainFunction[] = [
runUtilMerchantClientTest,
runKycWalletDepositAbortTest,
runKycMerchantDepositFormTest,
+ runExchangeKycAuthTest,
];
export interface TestRunSpec {
diff --git a/packages/taler-util/src/http-client/exchange-client.ts
b/packages/taler-util/src/http-client/exchange-client.ts
index 5a8919ae3..4ad168193 100644
--- a/packages/taler-util/src/http-client/exchange-client.ts
+++ b/packages/taler-util/src/http-client/exchange-client.ts
@@ -664,6 +664,60 @@ export class TalerExchangeHttpClient2 {
}
}
+ /**
+ * Do a /kyc-check request, but don't specify
+ * the account pub explicitly.
+ *
+ * Deprecated, but used in tests.
+ */
+ async testingCheckKycStatusNoPub(args: {
+ paytoHash: string;
+ accountSig: EddsaSignatureString;
+ longpoll?: boolean;
+ awaitAuth?: boolean;
+ }): Promise<
+ | OperationOk<void>
+ | OperationAlternative<HttpStatusCode.Ok, AccountKycStatus>
+ | OperationAlternative<HttpStatusCode.Accepted, AccountKycStatus>
+ | OperationFail<HttpStatusCode.Forbidden>
+ | OperationFail<HttpStatusCode.NotFound>
+ | OperationFail<HttpStatusCode.Conflict>
+ > {
+ const { paytoHash, accountSig, longpoll, awaitAuth } = args;
+ const url = new URL(`kyc-check/${paytoHash}`, this.baseUrl);
+ if (awaitAuth !== undefined) {
+ url.searchParams.set("await_auth", awaitAuth ? "YES" : "NO");
+ }
+
+ const resp = await this.fetch(
+ url,
+ {
+ headers: {
+ "Account-Owner-Signature": accountSig,
+ },
+ },
+ longpoll,
+ );
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeHttpFailure(
+ resp,
+ resp.status,
+ codecForAccountKycStatus(),
+ );
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess();
+ case HttpStatusCode.Forbidden:
+ case HttpStatusCode.NotFound:
+ case HttpStatusCode.Conflict:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownHttpFailure(resp);
+ }
+ }
+
/**
* https://docs.taler.net/core/api-exchange.html#get--kyc-info-$ACCESS_TOKEN
*
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-typescript-core] branch master updated: harness: add test for exchange kyc auth,
Admin <=