taler-typescript-core

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

commit ab5f1771a65b39a61a8e8c4e8ed08f574507f059
parent 562d239a6eab98e4dd5bc18e34a97ef5655f60a3
Author: Florian Dold <florian@dold.me>
Date:   Tue,  6 May 2025 19:36:45 +0200

harness: refactor test

Diffstat:
Mpackages/taler-harness/src/harness/tops.ts | 209++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mpackages/taler-harness/src/integrationtests/test-tops-aml-custom-addr-postal.ts | 51+++++++++++++--------------------------------------
Mpackages/taler-harness/src/integrationtests/test-tops-aml-kyx-natural.ts | 194++++++++++---------------------------------------------------------------------
3 files changed, 243 insertions(+), 211 deletions(-)

diff --git a/packages/taler-harness/src/harness/tops.ts b/packages/taler-harness/src/harness/tops.ts @@ -15,6 +15,16 @@ */ import { + AccessToken, + decodeCrock, + encodeCrock, + hashNormalizedPaytoUri, + j2s, + KycStatusLongPollingReason, + OfficerAccount, + OfficerId, + parsePaytoUriOrThrow, + succeedOrThrow, TalerCorebankApiClient, TalerCoreBankHttpClient, TalerExchangeHttpClient, @@ -24,12 +34,15 @@ import { } from "@gnu-taler/taler-util"; import { createSyncCryptoApi, + EddsaKeyPairStrings, WalletApiOperation, } from "@gnu-taler/taler-wallet-core"; +import { logger } from "../integrationtests/test-tops-aml-kyx-natural.js"; import { CoinConfig, defaultCoinConfig } from "./denomStructures.js"; -import { KycTestEnv } from "./environments.js"; +import { TestfakeChallengerService } from "./fake-challenger.js"; import { BankService, + DbInfo, ExchangeService, getTestHarnessPaytoForLabel, GlobalTestState, @@ -562,9 +575,25 @@ KYC_KYCAID_FORM_ID = form_individual KYC_KYCAID_POST_URL = http://localhost:6005/done `; +export interface TopsTestEnv { + commonDb: DbInfo; + bankClient: TalerCorebankApiClient; + exchange: ExchangeService; + exchangeBankAccount: HarnessExchangeBankAccount; + walletClient: WalletClient; + walletService: WalletService; + amlKeypair: EddsaKeyPairStrings; + merchant: MerchantService; + bankApi: TalerCoreBankHttpClient; + exchangeApi: TalerExchangeHttpClient; + wireGatewayApi: TalerWireGatewayHttpClient; + merchantApi: TalerMerchantInstanceHttpClient; + officerAcc: OfficerAccount; +} + export async function createTopsEnvironment( t: GlobalTestState, -): Promise<KycTestEnv> { +): Promise<TopsTestEnv> { const db = await setupDb(t); let coinConfig: CoinConfig[]; @@ -722,10 +751,16 @@ export async function createTopsEnvironment( httpClient: harnessHttpLib, }); + const officerAcc: OfficerAccount = { + id: amlKeypair.pub as OfficerId, + signingKey: decodeCrock(amlKeypair.priv), + }; + return { commonDb: db, exchange, amlKeypair, + officerAcc, walletClient, walletService, bankClient, @@ -737,3 +772,173 @@ export async function createTopsEnvironment( exchangeApi, }; } + +export async function doFakeChallenger( + t: GlobalTestState, + args: { + exchangeClient: TalerExchangeHttpClient; + requirementId: string; + challenger: TestfakeChallengerService; + address: any; + }, +): Promise<{ setupRequest: any }> { + const { exchangeClient, challenger, requirementId } = args; + const startResp = succeedOrThrow( + await exchangeClient.startExternalKycProcess(requirementId, {}), + ); + console.log(`start resp`, j2s(startResp)); + + let challengerRedirectUrl = startResp.redirect_url; + + const resp = await harnessHttpLib.fetch(challengerRedirectUrl); + const respJson = await resp.json(); + console.log(`challenger resp: ${j2s(respJson)}`); + + const nonce = respJson.nonce; + t.assertTrue(typeof nonce === "string"); + const proofRedirectUrl = respJson.redirect_url; + + challenger.fakeVerification(nonce, args.address); + + console.log("nonce", nonce); + console.log("proof redirect URL", proofRedirectUrl); + + const proofResp = await harnessHttpLib.fetch(proofRedirectUrl, { + redirect: "manual", + }); + console.log("proof status:", proofResp.status); + t.assertDeepEqual(proofResp.status, 303); + + const setupRequest = challenger.getSetupRequest(nonce); + console.log(`setup request: ${j2s(setupRequest)}`); + return { + setupRequest, + }; +} + +export async function doTopsKycAuth( + t: GlobalTestState, + args: { + merchantClient: TalerMerchantInstanceHttpClient; + exchangeBankAccount: HarnessExchangeBankAccount; + wireGatewayApi: TalerWireGatewayHttpClient; + }, +): Promise<{ accessToken: AccessToken; merchantPaytoHash: string }> { + const { merchantClient, wireGatewayApi, exchangeBankAccount } = args; + { + const kycStatus = await merchantClient.getCurrentInstanceKycStatus( + undefined, + {}, + ); + + console.log(`kyc status: ${j2s(kycStatus)}`); + + t.assertDeepEqual(kycStatus.case, "ok"); + + t.assertTrue(kycStatus.body != null); + + t.assertDeepEqual(kycStatus.body.kyc_data[0].status, "kyc-wire-required"); + + const depositPaytoUri = kycStatus.body.kyc_data[0].payto_uri; + t.assertTrue(kycStatus.body.kyc_data[0].payto_kycauths != null); + const authTxPayto = parsePaytoUriOrThrow( + kycStatus.body.kyc_data[0]?.payto_kycauths[0], + ); + const authTxMessage = authTxPayto?.params["message"]; + t.assertTrue(typeof authTxMessage === "string"); + t.assertTrue(authTxMessage.startsWith("KYC:")); + const accountPub = authTxMessage.substring(4); + logger.info(`merchant account pub: ${accountPub}`); + await wireGatewayApi.addKycAuth({ + auth: exchangeBankAccount.wireGatewayAuth, + body: { + amount: "CHF:0.1", + debit_account: depositPaytoUri, + account_pub: accountPub, + }, + }); + } + + let accessToken: AccessToken; + let merchantPaytoHash: string; + + // Wait for auth transfer to be registered by the exchange + { + const kycStatus = await merchantClient.getCurrentInstanceKycStatus( + undefined, + { + reason: KycStatusLongPollingReason.AUTH_TRANSFER, + timeout: 30000, + }, + ); + logger.info(`kyc status after transfer: ${j2s(kycStatus)}`); + t.assertDeepEqual(kycStatus.case, "ok"); + t.assertTrue(kycStatus.body != null); + t.assertDeepEqual(kycStatus.body.kyc_data[0].status, "kyc-required"); + t.assertTrue(typeof kycStatus.body.kyc_data[0].access_token === "string"); + accessToken = kycStatus.body.kyc_data[0].access_token as AccessToken; + merchantPaytoHash = encodeCrock( + hashNormalizedPaytoUri(kycStatus.body.kyc_data[0].payto_uri), + ); + return { accessToken, merchantPaytoHash }; + } +} + +export async function doTopsAcceptTos( + t: GlobalTestState, + args: { + accessToken: AccessToken; + exchangeClient: TalerExchangeHttpClient; + merchantClient: TalerMerchantInstanceHttpClient; + merchant: MerchantService; + }, +): Promise<void> { + const { exchangeClient, merchant, merchantClient, accessToken } = args; + { + const kycInfo = await exchangeClient.checkKycInfo( + accessToken, + undefined, + undefined, + ); + console.log(j2s(kycInfo)); + + t.assertDeepEqual(kycInfo.case, "ok"); + t.assertDeepEqual(kycInfo.body.requirements.length, 1); + t.assertDeepEqual(kycInfo.body.requirements[0].form, "accept-tos"); + const requirementId = kycInfo.body.requirements[0].id; + t.assertTrue(typeof requirementId === "string"); + + const uploadRes = await exchangeClient.uploadKycForm(requirementId, { + FORM_ID: "accept-tos", + FORM_VERSION: 1, + ACCEPTED_TERMS_OF_SERVICE: "v1", + }); + console.log("upload res", uploadRes); + t.assertDeepEqual(uploadRes.case, "ok"); + } + + { + const kycInfo = await exchangeClient.checkKycInfo( + accessToken, + undefined, + undefined, + ); + console.log(j2s(kycInfo)); + + // FIXME: Do we expect volunary measures here? + // => not yet, see https://bugs.gnunet.org/view.php?id=9879 + } + + await merchant.runKyccheckOnce(); + + { + const kycStatus = await merchantClient.getCurrentInstanceKycStatus( + undefined, + { + reason: KycStatusLongPollingReason.AUTH_TRANSFER, + timeout: 30000, + }, + ); + logger.info(`kyc status after accept-tos: ${j2s(kycStatus)}`); + } +} diff --git a/packages/taler-harness/src/integrationtests/test-tops-aml-custom-addr-postal.ts b/packages/taler-harness/src/integrationtests/test-tops-aml-custom-addr-postal.ts @@ -35,7 +35,7 @@ import { } from "@gnu-taler/taler-util"; import { startFakeChallenger } from "../harness/fake-challenger.js"; import { GlobalTestState, harnessHttpLib } from "../harness/harness.js"; -import { createTopsEnvironment } from "../harness/tops.js"; +import { createTopsEnvironment, doFakeChallenger } from "../harness/tops.js"; const logger = new Logger("test-tops-aml.ts"); @@ -48,6 +48,7 @@ export async function runTopsAmlCustomAddrPostalTest(t: GlobalTestState) { const { exchange, amlKeypair, + officerAcc, merchant, exchangeBankAccount, wireGatewayApi, @@ -172,11 +173,6 @@ export async function runTopsAmlCustomAddrPostalTest(t: GlobalTestState) { logger.info(`kyc status after accept-tos: ${j2s(kycStatus)}`); } - const officerAcc: OfficerAccount = { - id: amlKeypair.pub as OfficerId, - signingKey: decodeCrock(amlKeypair.priv), - }; - // Trigger postal registration check // via AML officer. { @@ -232,41 +228,20 @@ export async function runTopsAmlCustomAddrPostalTest(t: GlobalTestState) { t.assertDeepEqual(kycInfoResp.case, "ok"); const kycInfo = kycInfoResp.body; t.assertDeepEqual(kycInfo.requirements[0].form, "LINK"); - t.assertTrue(typeof kycInfo.requirements[0].id === "string"); - - const startResp = succeedOrThrow( - await exchangeClient.startExternalKycProcess( - kycInfo.requirements[0].id, - {}, - ), - ); - console.log(`start resp`, j2s(startResp)); - - let challengerRedirectUrl = startResp.redirect_url; - - const resp = await harnessHttpLib.fetch(challengerRedirectUrl); - const respJson = await resp.json(); - console.log(`challenger resp: ${j2s(respJson)}`); - - const nonce = respJson.nonce; - t.assertTrue(typeof nonce === "string"); - const proofRedirectUrl = respJson.redirect_url; - - challenger.fakeVerification(nonce, { - CONTACT_NAME: "Richard Stallman", - ADDRESS_LINES: "Bundesgasse 1\n1234 Bern", - }); - - console.log("nonce", nonce); - console.log("proof redirect URL", proofRedirectUrl); + const requirementId = kycInfo.requirements[0].id; + t.assertTrue(typeof requirementId === "string"); - const proofResp = await harnessHttpLib.fetch(proofRedirectUrl, { - redirect: "manual", + const chRes = await doFakeChallenger(t, { + exchangeClient, + requirementId, + challenger, + address: { + CONTACT_NAME: "Richard Stallman", + ADDRESS_LINES: "Bundesgasse 1\n1234 Bern", + }, }); - console.log("proof status:", proofResp.status); - t.assertDeepEqual(proofResp.status, 303); - const setupReq = challenger.getSetupRequest(nonce); + const setupReq = chRes.setupRequest; console.log(`setup request: ${j2s(setupReq)}`); t.assertDeepEqual(setupReq.CONTACT_NAME, "Richard Stallman"); diff --git a/packages/taler-harness/src/integrationtests/test-tops-aml-kyx-natural.ts b/packages/taler-harness/src/integrationtests/test-tops-aml-kyx-natural.ts @@ -18,38 +18,29 @@ * Imports. */ import { - AccessToken, - decodeCrock, - encodeCrock, - hashNormalizedPaytoUri, j2s, - KycStatusLongPollingReason, Logger, - OfficerAccount, - OfficerId, - parsePaytoUriOrThrow, succeedOrThrow, TalerExchangeHttpClient, TalerMerchantInstanceHttpClient, TalerProtocolTimestamp, } from "@gnu-taler/taler-util"; -import { - startFakeChallenger, - TestfakeChallengerService, -} from "../harness/fake-challenger.js"; +import { startFakeChallenger } from "../harness/fake-challenger.js"; import { GlobalTestState, harnessHttpLib } from "../harness/harness.js"; -import { createTopsEnvironment } from "../harness/tops.js"; +import { + createTopsEnvironment, + doFakeChallenger, + doTopsAcceptTos, + doTopsKycAuth, +} from "../harness/tops.js"; -const logger = new Logger("test-tops-aml.ts"); +export const logger = new Logger("test-tops-aml.ts"); export async function runTopsAmlKyxNaturalTest(t: GlobalTestState) { // Set up test environment - const { - walletClient, - bankClient, exchange, - amlKeypair, + officerAcc, merchant, exchangeBankAccount, wireGatewayApi, @@ -63,124 +54,27 @@ export async function runTopsAmlKyxNaturalTest(t: GlobalTestState) { const merchantClient = new TalerMerchantInstanceHttpClient( merchant.makeInstanceBaseUrl(), ); - // Do KYC auth transfer - { - const kycStatus = await merchantClient.getCurrentInstanceKycStatus( - undefined, - {}, - ); - - console.log(`kyc status: ${j2s(kycStatus)}`); - - t.assertDeepEqual(kycStatus.case, "ok"); - - t.assertTrue(kycStatus.body != null); - - t.assertDeepEqual(kycStatus.body.kyc_data[0].status, "kyc-wire-required"); - - const depositPaytoUri = kycStatus.body.kyc_data[0].payto_uri; - t.assertTrue(kycStatus.body.kyc_data[0].payto_kycauths != null); - const authTxPayto = parsePaytoUriOrThrow( - kycStatus.body.kyc_data[0]?.payto_kycauths[0], - ); - const authTxMessage = authTxPayto?.params["message"]; - t.assertTrue(typeof authTxMessage === "string"); - t.assertTrue(authTxMessage.startsWith("KYC:")); - const accountPub = authTxMessage.substring(4); - logger.info(`merchant account pub: ${accountPub}`); - await wireGatewayApi.addKycAuth({ - auth: exchangeBankAccount.wireGatewayAuth, - body: { - amount: "CHF:0.1", - debit_account: depositPaytoUri, - account_pub: accountPub, - }, - }); - } - - let accessToken: AccessToken; - let merchantPaytoHash: string; - // Wait for auth transfer to be registered by the exchange - { - const kycStatus = await merchantClient.getCurrentInstanceKycStatus( - undefined, - { - reason: KycStatusLongPollingReason.AUTH_TRANSFER, - timeout: 30000, - }, - ); - logger.info(`kyc status after transfer: ${j2s(kycStatus)}`); - t.assertDeepEqual(kycStatus.case, "ok"); - t.assertTrue(kycStatus.body != null); - t.assertDeepEqual(kycStatus.body.kyc_data[0].status, "kyc-required"); - t.assertTrue(typeof kycStatus.body.kyc_data[0].access_token === "string"); - accessToken = kycStatus.body.kyc_data[0].access_token as AccessToken; - merchantPaytoHash = encodeCrock( - hashNormalizedPaytoUri(kycStatus.body.kyc_data[0].payto_uri), - ); - } + // Do KYC auth transfer + const { accessToken, merchantPaytoHash } = await doTopsKycAuth(t, { + merchantClient, + exchangeBankAccount, + wireGatewayApi, + }); const exchangeClient = new TalerExchangeHttpClient(exchange.baseUrl, { httpClient: harnessHttpLib, }); // Accept ToS - { - const kycInfo = await exchangeClient.checkKycInfo( - accessToken, - undefined, - undefined, - ); - console.log(j2s(kycInfo)); - - t.assertDeepEqual(kycInfo.case, "ok"); - t.assertDeepEqual(kycInfo.body.requirements.length, 1); - t.assertDeepEqual(kycInfo.body.requirements[0].form, "accept-tos"); - const requirementId = kycInfo.body.requirements[0].id; - t.assertTrue(typeof requirementId === "string"); - - const uploadRes = await exchangeClient.uploadKycForm(requirementId, { - FORM_ID: "accept-tos", - FORM_VERSION: 1, - ACCEPTED_TERMS_OF_SERVICE: "v1", - }); - console.log("upload res", uploadRes); - t.assertDeepEqual(uploadRes.case, "ok"); - } - - { - const kycInfo = await exchangeClient.checkKycInfo( - accessToken, - undefined, - undefined, - ); - console.log(j2s(kycInfo)); - - // FIXME: Do we expect volunary measures here? - // => not yet, see https://bugs.gnunet.org/view.php?id=9879 - } - - await merchant.runKyccheckOnce(); - - { - const kycStatus = await merchantClient.getCurrentInstanceKycStatus( - undefined, - { - reason: KycStatusLongPollingReason.AUTH_TRANSFER, - timeout: 30000, - }, - ); - logger.info(`kyc status after accept-tos: ${j2s(kycStatus)}`); - } - - const officerAcc: OfficerAccount = { - id: amlKeypair.pub as OfficerId, - signingKey: decodeCrock(amlKeypair.priv), - }; + await doTopsAcceptTos(t, { + accessToken, + exchangeClient, + merchantClient, + merchant, + }); - // Trigger postal registration check - // via AML officer. + // Trigger kyx measure. { const decisionsResp = succeedOrThrow( await exchangeClient.getAmlDecisions(officerAcc, { @@ -211,9 +105,7 @@ export async function runTopsAmlKyxNaturalTest(t: GlobalTestState) { ); } - // Trigger postal registration check - // via AML officer. - + // Upload form. { const kycInfoResp = await exchangeClient.checkKycInfo( accessToken, @@ -278,44 +170,4 @@ export async function runTopsAmlKyxNaturalTest(t: GlobalTestState) { // and make a decision. } -async function doFakeChallenger( - t: GlobalTestState, - args: { - exchangeClient: TalerExchangeHttpClient; - requirementId: string; - challenger: TestfakeChallengerService; - address: any; - }, -): Promise<void> { - const { exchangeClient, challenger, requirementId } = args; - const startResp = succeedOrThrow( - await exchangeClient.startExternalKycProcess(requirementId, {}), - ); - console.log(`start resp`, j2s(startResp)); - - let challengerRedirectUrl = startResp.redirect_url; - - const resp = await harnessHttpLib.fetch(challengerRedirectUrl); - const respJson = await resp.json(); - console.log(`challenger resp: ${j2s(respJson)}`); - - const nonce = respJson.nonce; - t.assertTrue(typeof nonce === "string"); - const proofRedirectUrl = respJson.redirect_url; - - challenger.fakeVerification(nonce, args.address); - - console.log("nonce", nonce); - console.log("proof redirect URL", proofRedirectUrl); - - const proofResp = await harnessHttpLib.fetch(proofRedirectUrl, { - redirect: "manual", - }); - console.log("proof status:", proofResp.status); - t.assertDeepEqual(proofResp.status, 303); - - const setupReq = challenger.getSetupRequest(nonce); - console.log(`setup request: ${j2s(setupReq)}`); -} - runTopsAmlKyxNaturalTest.suites = ["wallet"];