diff options
Diffstat (limited to 'packages/taler-harness')
-rw-r--r-- | packages/taler-harness/src/harness/harness.ts | 6 | ||||
-rw-r--r-- | packages/taler-harness/src/harness/helpers.ts | 19 | ||||
-rw-r--r-- | packages/taler-harness/src/integrationtests/test-kyc.ts | 199 |
3 files changed, 196 insertions, 28 deletions
diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts index 3659ea538..275592091 100644 --- a/packages/taler-harness/src/harness/harness.ts +++ b/packages/taler-harness/src/harness/harness.ts @@ -2028,9 +2028,9 @@ export class WalletClient { return getClientFromRemoteWallet(this.remoteWallet); } - waitForNotificationCond( - cond: (n: WalletNotification) => boolean, - ): Promise<void> { + waitForNotificationCond<T>( + cond: (n: WalletNotification) => T | undefined | false, + ): Promise<T> { return this.waiter.waitForNotificationCond(cond); } } diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts index 59a37e4b8..4c2ca80a7 100644 --- a/packages/taler-harness/src/harness/helpers.ts +++ b/packages/taler-harness/src/harness/helpers.ts @@ -53,9 +53,14 @@ import { MerchantServiceInterface, setupDb, WalletCli, + WalletClient, + WalletService, WithAuthorization, } from "./harness.js"; +/** + * @deprecated + */ export interface SimpleTestEnvironment { commonDb: DbInfo; bank: BankService; @@ -65,6 +70,20 @@ export interface SimpleTestEnvironment { wallet: WalletCli; } +/** + * Improved version of the simple test environment, + * with the daemonized wallet. + */ +export interface SimpleTestEnvironmentNg { + commonDb: DbInfo; + bank: BankService; + exchange: ExchangeService; + exchangeBankAccount: HarnessExchangeBankAccount; + merchant: MerchantService; + walletClient: WalletClient; + walletService: WalletService; +} + export interface EnvOptions { /** * If provided, enable age restrictions with the specified age mask string. diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts index c652c86fa..b08db66f7 100644 --- a/packages/taler-harness/src/integrationtests/test-kyc.ts +++ b/packages/taler-harness/src/integrationtests/test-kyc.ts @@ -17,7 +17,13 @@ /** * Imports. */ -import { Duration } from "@gnu-taler/taler-util"; +import { Duration, j2s, NotificationType } from "@gnu-taler/taler-util"; +import { + BankAccessApi, + BankApi, + NodeHttpLib, + WalletApiOperation, +} from "@gnu-taler/taler-wallet-core"; import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js"; import { BankService, @@ -26,20 +32,17 @@ import { GlobalTestState, MerchantService, setupDb, - WalletCli, + WalletClient, + WalletService, } from "../harness/harness.js"; -import { - withdrawViaBank, - makeTestPayment, - EnvOptions, - SimpleTestEnvironment, -} from "../harness/helpers.js"; +import { EnvOptions, SimpleTestEnvironmentNg } from "../harness/helpers.js"; +import * as http from "node:http"; export async function createKycTestkudosEnvironment( t: GlobalTestState, coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("TESTKUDOS")), opts: EnvOptions = {}, -): Promise<SimpleTestEnvironment> { +): Promise<SimpleTestEnvironmentNg> { const db = await setupDb(t); const bank = await BankService.create(t, { @@ -117,11 +120,11 @@ export async function createKycTestkudosEnvironment( config.setString( myprov, "kyc_oauth2_info_url", - "http://localhost:6666/oauth/v2/login", + "http://localhost:6666/oauth/v2/info", ); config.setString(myprov, "kyc_oauth2_client_id", "taler-exchange"); config.setString(myprov, "kyc_oauth2_client_secret", "exchange-secret"); - config.setString(myprov, "kyc_oauth2_post_url", "https://taler.com"); + config.setString(myprov, "kyc_oauth2_post_url", "https://taler.net"); config.setString( "kyc-legitimization-withdraw1", @@ -167,40 +170,186 @@ export async function createKycTestkudosEnvironment( ), }); - console.log("setup done!"); + const walletService = new WalletService(t, { + name: "wallet", + useInMemoryDb: true, + }); + await walletService.start(); + await walletService.pingUntilAvailable(); - const wallet = new WalletCli(t); + const walletClient = new WalletClient({ + unixPath: walletService.socketPath, + onNotification(n) { + console.log("got notification", n); + }, + }); + await walletClient.connect(); + await walletClient.client.call(WalletApiOperation.InitWallet, { + skipDefaults: true, + }); + + console.log("setup done!"); return { commonDb: db, exchange, merchant, - wallet, + walletClient, + walletService, bank, exchangeBankAccount, }; } +interface TestfakeKycService { + stop: () => void; +} + +function splitInTwoAt(s: string, separator: string): [string, string] { + const idx = s.indexOf(separator); + if (idx === -1) { + return [s, ""]; + } + return [s.slice(0, idx), s.slice(idx + 1)]; +} + +/** + * Testfake for the kyc service that the exchange talks to. + */ +async function runTestfakeKycService(): Promise<TestfakeKycService> { + const server = http.createServer((req, res) => { + const requestUrl = req.url!; + console.log(`kyc: got ${req.method} request`, requestUrl); + + const [path, query] = splitInTwoAt(requestUrl, "?"); + + const qp = new URLSearchParams(query); + + if (path === "/oauth/v2/login") { + // Usually this would render some HTML page for the user to log in, + // but we return JSON here. + const redirUri = new URL(qp.get("redirect_uri")!); + redirUri.searchParams.set("code", "code_is_ok"); + res.writeHead(200, { "Content-Type": "application/json" }); + res.end( + JSON.stringify({ + redirect_uri: redirUri.href, + }), + ); + } else if (path === "/oauth/v2/token") { + let reqBody = ""; + req.on("data", (x) => { + reqBody += x; + }); + + req.on("end", () => { + console.log("login request body:", reqBody); + + res.writeHead(200, { "Content-Type": "application/json" }); + // Normally, the access_token would also include which user we're trying + // to get info about, but we (for now) skip it in this test. + res.end( + JSON.stringify({ + access_token: "exchange_access_token", + token_type: "Bearer", + }), + ); + }); + } else if (path === "/oauth/v2/info") { + console.log("authorization header:", req.headers.authorization); + res.writeHead(200, { "Content-Type": "application/json" }); + res.end( + JSON.stringify({ + status: "success", + data: { + id: "foobar", + }, + }), + ); + } else { + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ code: 1, message: "bad request" })); + } + }); + await new Promise<void>((resolve, reject) => { + server.listen(6666, () => resolve()); + }); + return { + stop() { + server.close(); + }, + }; +} + export async function runKycTest(t: GlobalTestState) { // Set up test environment - const { wallet, bank, exchange, merchant } = + const { walletClient, bank, exchange, merchant } = await createKycTestkudosEnvironment(t); + const kycServer = await runTestfakeKycService(); + // Withdraw digital cash into the wallet. - await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" }); + const amount = "TESTKUDOS:20"; + const user = await BankApi.createRandomBankUser(bank); + const wop = await BankAccessApi.createWithdrawalOperation(bank, user, amount); - const order = { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "taler://fulfillment-success/thx", - }; + // Hand it to the wallet + + await walletClient.client.call( + WalletApiOperation.GetWithdrawalDetailsForUri, + { + talerWithdrawUri: wop.taler_withdraw_uri, + }, + ); + + // Withdraw + + const kycNotificationCond = walletClient.waitForNotificationCond((x) => { + if (x.type === NotificationType.WithdrawalKycRequested) { + return x; + } + return false; + }); + + const withdrawalDoneCond = walletClient.waitForNotificationCond( + (x) => x.type === NotificationType.WithdrawGroupFinished, + ); + + await walletClient.client.call( + WalletApiOperation.AcceptBankIntegratedWithdrawal, + { + exchangeBaseUrl: exchange.baseUrl, + talerWithdrawUri: wop.taler_withdraw_uri, + }, + ); + + // Confirm it + + await BankApi.confirmWithdrawalOperation(bank, user, wop); + + const kycNotif = await kycNotificationCond; + + console.log("got kyc notification:", j2s(kycNotif)); + + // We now simulate the user interacting with the KYC service, + // which would usually done in the browser. + + const httpClient = new NodeHttpLib(); + const kycServerResp = await httpClient.get(kycNotif.kycUrl); + const kycLoginResp = await kycServerResp.json(); + console.log("kyc server resp:", j2s(kycLoginResp)); + const kycProofUrl = kycLoginResp.redirect_uri; + const proofHttpResp = await httpClient.get(kycProofUrl); + console.log("proof resp status", proofHttpResp.status); + console.log("resp headers", proofHttpResp.headers.toJSON()); + + // Now that KYC is done, withdrawal should finally succeed. + + await withdrawalDoneCond; - await makeTestPayment(t, { wallet, merchant, order }); - await wallet.runUntilDone(); + kycServer.stop(); } runKycTest.suites = ["wallet"]; -// See bugs.taler.net/n/7599 -runKycTest.experimental = true; |