taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 3090d60068a6a4a3441fd0e6481190a03c407847
parent 89a6f069a93a109525de114e3dea6ec1823b5fb8
Author: Florian Dold <florian@dold.me>
Date:   Thu, 21 Nov 2024 19:35:26 +0100

harness: extend test-kyc-decision to provoke exchange crash

Diffstat:
Mpackages/taler-harness/src/integrationtests/test-kyc-decisions.ts | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mpackages/taler-util/src/types-taler-wallet.ts | 6++++++
Mpackages/taler-wallet-core/src/deposits.ts | 10+++++++++-
3 files changed, 141 insertions(+), 4 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-kyc-decisions.ts b/packages/taler-harness/src/integrationtests/test-kyc-decisions.ts @@ -18,20 +18,34 @@ * Imports. */ import { + AccountKycStatus, + codecForAccountKycStatus, + codecForKycProcessClientInformation, Configuration, Duration, encodeCrock, - hashFullPaytoUri, hashNormalizedPaytoUri, + j2s, TalerProtocolTimestamp, + TransactionMajorState, + TransactionMinorState, + WireGatewayApiClient, } from "@gnu-taler/taler-util"; +import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; +import { + createSyncCryptoApi, + WalletApiOperation, +} from "@gnu-taler/taler-wallet-core"; import { createKycTestkudosEnvironment, postAmlDecision, + withdrawViaBankV3, } from "../harness/environments.js"; import { getTestHarnessPaytoForLabel, GlobalTestState, + harnessHttpLib, + waitMs, } from "../harness/harness.js"; function adjustExchangeConfig(config: Configuration) { @@ -54,13 +68,47 @@ function adjustExchangeConfig(config: Configuration) { export async function runKycDecisionsTest(t: GlobalTestState) { // Set up test environment - const { walletClient, bankClient, exchange, amlKeypair, merchant } = - await createKycTestkudosEnvironment(t, { adjustExchangeConfig }); + // 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 wireGatewayApiClient = new WireGatewayApiClient( + exchangeBankAccount.wireGatewayApiBaseUrl, + { + auth: { + username: exchangeBankAccount.accountName, + password: exchangeBankAccount.accountPassword, + }, + }, + ); + + const merchantPair = await cryptoApi.createEddsaKeypair({}); + + const sigResp = await cryptoApi.signWalletKycAuth({ + accountPriv: merchantPair.priv, + accountPub: merchantPair.pub, + }); + const kycPaytoHash = encodeCrock(hashNormalizedPaytoUri(merchantPayto)); + const wres = await withdrawViaBankV3(t, { + walletClient, + exchange, + bankClient, + amount: "TESTKUDOS:20", + }); + + await wres.withdrawalFinishedCond; + // Make a decision where the exchange doesn't know the account yet. await postAmlDecision(t, { amlPriv: amlKeypair.priv, @@ -76,6 +124,7 @@ export async function runKycDecisionsTest(t: GlobalTestState) { { operation_type: "DEPOSIT", display_priority: 1, + exposed: true, measures: ["verboten"], threshold: "TESTKUDOS:10", timeframe: Duration.toTalerProtocolDuration( @@ -84,9 +133,83 @@ export async function runKycDecisionsTest(t: GlobalTestState) { }), ), }, + { + operation_type: "WITHDRAW", + display_priority: 1, + exposed: true, + measures: ["verboten"], + threshold: "TESTKUDOS:0", + timeframe: Duration.toTalerProtocolDuration( + Duration.fromSpec({ + days: 1, + }), + ), + }, ], }, }); + + const dgRes = await walletClient.call(WalletApiOperation.CreateDepositGroup, { + amount: "TESTKUDOS:15", + depositPaytoUri: merchantPayto, + testingFixedPriv: merchantPair.priv, + }); + + await walletClient.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: dgRes.transactionId, + txState: { + major: TransactionMajorState.Pending, + minor: TransactionMinorState.KycAuthRequired, + }, + }); + + await wireGatewayApiClient.adminAddKycauth({ + amount: "TESTKUDOS:0.1", + debitAccountPayto: merchantPayto, + accountPub: merchantPair.pub, + }); + + let checkResp: AccountKycStatus | undefined; + + while (1) { + let checkHttpResp = await harnessHttpLib.fetch( + new URL(`kyc-check/${kycPaytoHash}`, exchange.baseUrl).href, + { + headers: { + ["Account-Owner-Signature"]: sigResp.sig, + }, + }, + ); + + console.log(`status: ${checkHttpResp.status}`); + + if (checkHttpResp.status == 409) { + await waitMs(200); + continue; + } + + checkResp = await readSuccessResponseJsonOrThrow( + checkHttpResp, + codecForAccountKycStatus(), + ); + + break; + } + + t.assertTrue(!!checkResp); + + console.log(j2s(checkResp)); + + let infoHttpResp = await harnessHttpLib.fetch( + new URL(`kyc-info/${checkResp.access_token}`, exchange.baseUrl).href, + ); + t.assertDeepEqual(infoHttpResp.status, 200); + const infoResp = await readSuccessResponseJsonOrThrow( + infoHttpResp, + codecForKycProcessClientInformation(), + ); + + console.log(j2s(infoResp)); } runKycDecisionsTest.suites = ["wallet"]; diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts @@ -2323,6 +2323,11 @@ export interface CreateDepositGroupRequest { transactionId?: TransactionIdStr; depositPaytoUri: string; amount: AmountString; + + /** + * Use a fixed merchant private key. + */ + testingFixedPriv?: string; } export interface CheckDepositRequest { @@ -2380,6 +2385,7 @@ export const codecForCreateDepositGroupRequest = .property("amount", codecForAmountString()) .property("depositPaytoUri", codecForString()) .property("transactionId", codecOptional(codecForTransactionIdStr())) + .property("testingFixedPriv", codecOptional(codecForString())) .build("CreateDepositGroupRequest"); export interface CreateDepositGroupResponse { diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts @@ -2061,7 +2061,15 @@ export async function createDepositGroup( // a KYC transfer to establish a kyc account key pair. // FIXME: Extend the heuristic to use the last used merchant key pair? let merchantPair: EddsaKeyPairStrings | undefined = undefined; - if (coins.length > 0) { + if (req.testingFixedPriv) { + const merchantPub = await wex.cryptoApi.eddsaGetPublic({ + priv: req.testingFixedPriv, + }); + merchantPair = { + priv: req.testingFixedPriv, + pub: merchantPub.pub, + }; + } else if (coins.length > 0) { const res = await getLastWithdrawalKeyPair(wex, coins[0].exchangeBaseUrl); if (res) { logger.info(