commit 3d4d25ed08ba4d50ff3de1f3bf6c8ae727fbdd6c
parent a2b1a5cdd17dc58b136494162b3f0179008b1893
Author: Florian Dold <florian@dold.me>
Date: Wed, 11 Dec 2024 16:49:32 +0100
test
Diffstat:
4 files changed, 174 insertions(+), 3 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-deposit-aggregate-implicit-auth.ts b/packages/taler-harness/src/integrationtests/test-kyc-deposit-aggregate-implicit-auth.ts
@@ -0,0 +1,147 @@
+/*
+ This file is part of GNU Taler
+ (C) 2020 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,
+ TransactionMajorState,
+ TransactionMinorState,
+} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import {
+ createKycTestkudosEnvironment,
+ postAmlDecisionNoRules,
+ withdrawViaBankV3,
+} from "../harness/environments.js";
+import { GlobalTestState } from "../harness/harness.js";
+
+function adjustExchangeConfig(config: Configuration): void {
+ config.setString("exchange", "enable_kyc", "yes");
+
+ config.setString("KYC-RULE-R1", "operation_type", "aggregate");
+ config.setString("KYC-RULE-R1", "enabled", "yes");
+ config.setString("KYC-RULE-R1", "exposed", "yes");
+ config.setString("KYC-RULE-R1", "is_and_combinator", "yes");
+ 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-MEASURE-M1", "check_name", "C1");
+ config.setString("KYC-MEASURE-M1", "context", "{}");
+ config.setString("KYC-MEASURE-M1", "program", "P1");
+
+ config.setString("AML-PROGRAM-P1", "command", "/bin/true");
+ config.setString("AML-PROGRAM-P1", "enabled", "true");
+ config.setString("AML-PROGRAM-P1", "description", "this does nothing");
+ config.setString("AML-PROGRAM-P1", "fallback", "M1");
+
+ config.setString("KYC-CHECK-C1", "type", "INFO");
+ config.setString("KYC-CHECK-C1", "description", "my check!");
+ config.setString("KYC-CHECK-C1", "fallback", "M1");
+}
+
+export async function runKycDepositAggregateImplicitAuthTest(t: GlobalTestState) {
+ // Set up test environment
+
+ const {
+ walletClient,
+ bankClient,
+ exchange,
+ amlKeypair,
+ } = await createKycTestkudosEnvironment(t, {
+ adjustExchangeConfig,
+ });
+
+ // Withdraw digital cash into the wallet.
+
+ const wres = await withdrawViaBankV3(t, {
+ bankClient,
+ amount: "TESTKUDOS:50",
+ exchange: exchange,
+ walletClient: walletClient,
+ });
+
+ await wres.withdrawalFinishedCond;
+
+ const depositResp = await walletClient.call(
+ WalletApiOperation.CreateDepositGroup,
+ {
+ amount: "TESTKUDOS:10",
+ depositPaytoUri: wres.accountPaytoUri,
+ },
+ );
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Pending,
+ minor: TransactionMinorState.Track,
+ },
+ });
+
+ await exchange.runAggregatorOnceWithTimetravel({
+ timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
+ });
+
+ console.log("waiting for kyc-required");
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Pending,
+ minor: TransactionMinorState.KycRequired,
+ },
+ });
+
+ console.log("waiting done");
+
+ const txDetails = await walletClient.call(
+ WalletApiOperation.GetTransactionById,
+ {
+ transactionId: depositResp.transactionId,
+ },
+ );
+
+ const kycPaytoHash = txDetails.kycPaytoHash;
+
+ t.assertTrue(!!kycPaytoHash);
+
+ await postAmlDecisionNoRules(t, {
+ amlPriv: amlKeypair.priv,
+ amlPub: amlKeypair.pub,
+ exchangeBaseUrl: exchange.baseUrl,
+ paytoHash: kycPaytoHash,
+ });
+
+ await exchange.runAggregatorOnceWithTimetravel({
+ timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
+ });
+
+ await exchange.runTransferOnceWithTimetravel({
+ timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
+ });
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Done,
+ },
+ });
+}
+
+runKycDepositAggregateImplicitAuthTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -51,6 +51,7 @@ import { runForcedSelectionTest } from "./test-forced-selection.js";
import { runKnownAccountsTest } from "./test-known-accounts.js";
import { runKycBalanceWithdrawalTest } from "./test-kyc-balance-withdrawal.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";
import { runKycDepositDepositKyctransferTest } from "./test-kyc-deposit-deposit-kyctransfer.js";
import { runKycDepositDepositTest } from "./test-kyc-deposit-deposit.js";
@@ -64,6 +65,7 @@ import { runKycPeerPullTest } from "./test-kyc-peer-pull.js";
import { runKycPeerPushTest } from "./test-kyc-peer-push.js";
import { runKycSkipExpirationTest } from "./test-kyc-skip-expiration.js";
import { runKycThresholdWithdrawalTest } from "./test-kyc-threshold-withdrawal.js";
+import { runKycTwoFormsTest } from "./test-kyc-two-forms.js";
import { runKycWithdrawalVerbotenTest } from "./test-kyc-withdrawal-verboten.js";
import { runKycTest } from "./test-kyc.js";
import { runLibeufinBankTest } from "./test-libeufin-bank.js";
@@ -148,7 +150,6 @@ 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.
@@ -288,6 +289,7 @@ const allTests: TestMainFunction[] = [
runKycMerchantActivateBankAccountTest,
runKycDecisionsTest,
runKnownAccountsTest,
+ runKycDepositAggregateImplicitAuthTest,
];
export interface TestRunSpec {
diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts
@@ -1379,6 +1379,17 @@ export interface TrackTransactionAccepted {
// Time by which the exchange currently thinks the deposit will be executed.
// Actual execution may be later if the KYC check is not satisfied by then.
execution_time: TalerProtocolTimestamp;
+
+ // Public key associated with the account. The client must sign
+ // the initial request for the KYC status using the corresponding
+ // private key. Will be the merchant (instance) public key.
+ //
+ // Absent if no public key is currently associated
+ // with the account and the client MUST thus first
+ // credit the exchange via an inbound wire transfer
+ // to associate a public key with the debited account.
+ // @since protocol **v20**.
+ account_pub: EddsaPublicKeyString | undefined;
}
export const codecForTackTransactionAccepted =
@@ -1387,6 +1398,7 @@ export const codecForTackTransactionAccepted =
.property("requirement_row", codecOptional(codecForNumber()))
.property("kyc_ok", codecForBoolean())
.property("execution_time", codecForTimestamp)
+ .property("account_pub", codecOptional(codecForString()))
.build("TackTransactionAccepted");
export const codecForPeerContractTerms = (): Codec<PeerContractTerms> =>
@@ -2460,7 +2472,10 @@ export const codecForAmlProgramRequirement = (): Codec<AmlProgramRequirement> =>
export const codecForKycCheckInformation = (): Codec<KycCheckInformation> =>
buildCodecForObject<KycCheckInformation>()
.property("description", codecForString())
- .property("description_i18n", codecOptional(codecForInternationalizedString()))
+ .property(
+ "description_i18n",
+ codecOptional(codecForInternationalizedString()),
+ )
.property("fallback", codecForString())
.property("outputs", codecForList(codecForString()))
.property("requires", codecForList(codecForString()))
@@ -2607,7 +2622,10 @@ export const codecForKycCheckPublicInformation =
(): Codec<KycCheckPublicInformation> =>
buildCodecForObject<KycCheckPublicInformation>()
.property("description", codecForString())
- .property("description_i18n", codecOptional(codecForInternationalizedString()))
+ .property(
+ "description_i18n",
+ codecOptional(codecForInternationalizedString()),
+ )
.build("TalerExchangeApi.KycCheckPublicInformation");
export const codecForKycRequirementInformationId =
diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts
@@ -1322,6 +1322,10 @@ async function processDepositGroupPendingTrack(
logger.trace(`track response: ${j2s(track)}`);
if (track.type === "accepted") {
if (!track.kyc_ok && track.requirement_row !== undefined) {
+ if (!track.account_pub) {
+ // FIXME: Handle this properly.
+ throw Error("Deposit accepted but KYC auth missing");
+ }
// FIXME: Take this from the response. If not present, require KYC transfer.
// But: Why did exchange accept deposit in the first place if missing?
const paytoHash = encodeCrock(