From 54933e533d2d650f3ffe4f443c6ff1a662e053c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20=C3=81valos?= Date: Tue, 4 Jun 2024 14:10:25 -0600 Subject: embedded: simplify wallet-qjs.ts (#8698) --- .../taler-wallet-embedded/src/wallet-qjs-tests.ts | 118 ++++++++++++ packages/taler-wallet-embedded/src/wallet-qjs.ts | 209 +++++---------------- 2 files changed, 169 insertions(+), 158 deletions(-) create mode 100644 packages/taler-wallet-embedded/src/wallet-qjs-tests.ts (limited to 'packages') diff --git a/packages/taler-wallet-embedded/src/wallet-qjs-tests.ts b/packages/taler-wallet-embedded/src/wallet-qjs-tests.ts new file mode 100644 index 000000000..ca4eb28c0 --- /dev/null +++ b/packages/taler-wallet-embedded/src/wallet-qjs-tests.ts @@ -0,0 +1,118 @@ +/* + This file is part of GNU Taler + (C) 2019 GNUnet e.V. + (C) 2024 Taler Systems SA + + 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 + */ + +import { userIdentifierDerive } from "@gnu-taler/anastasis-core/lib/crypto.js"; +import { AmountString, j2s } from "@gnu-taler/taler-util"; +import { + WalletApiOperation, + createNativeWalletHost2, +} from "@gnu-taler/taler-wallet-core"; + +export async function testWithGv() { + const w = await createNativeWalletHost2({}); + await w.wallet.client.call(WalletApiOperation.InitWallet, { + config: { + features: { + allowHttp: true, + }, + }, + }); + await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { + amountToSpend: "KUDOS:1" as AmountString, + amountToWithdraw: "KUDOS:3" as AmountString, + corebankApiBaseUrl: "https://bank.demo.taler.net/", + exchangeBaseUrl: "https://exchange.demo.taler.net/", + merchantBaseUrl: "https://backend.demo.taler.net/", + merchantAuthToken: "secret-token:sandbox", + }); + await w.wallet.client.call(WalletApiOperation.TestingWaitTasksDone, {}); + await w.wallet.client.call(WalletApiOperation.Shutdown, {}); +} + +export async function testWithFdold() { + const w = await createNativeWalletHost2({}); + await w.wallet.client.call(WalletApiOperation.InitWallet, { + config: { + features: { + allowHttp: true, + }, + }, + }); + await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { + amountToSpend: "TESTKUDOS:1" as AmountString, + amountToWithdraw: "TESTKUDOS:3" as AmountString, + corebankApiBaseUrl: "https://bank.taler.fdold.eu/", + exchangeBaseUrl: "https://exchange.taler.fdold.eu/", + merchantBaseUrl: "https://merchant.taler.fdold.eu/", + }); + await w.wallet.client.call(WalletApiOperation.TestingWaitTasksDone, {}); + await w.wallet.client.call(WalletApiOperation.Shutdown, {}); +} + +export async function testWithLocal(path: string) { + console.log("running local test"); + const w = await createNativeWalletHost2({ + persistentStoragePath: path ?? "walletdb.json", + }); + console.log("created wallet"); + await w.wallet.client.call(WalletApiOperation.InitWallet, { + config: { + features: { + allowHttp: true, + }, + testing: { + skipDefaults: true, + }, + }, + }); + console.log("initialized wallet"); + await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { + amountToSpend: "TESTKUDOS:1" as AmountString, + amountToWithdraw: "TESTKUDOS:3" as AmountString, + corebankApiBaseUrl: "http://localhost:8082/taler-bank-access/", + exchangeBaseUrl: "http://localhost:8081/", + merchantBaseUrl: "http://localhost:8083/", + }); + console.log("started integration test"); + await w.wallet.client.call(WalletApiOperation.TestingWaitTasksDone, {}); + console.log("done with task loop"); + await w.wallet.client.call(WalletApiOperation.Shutdown, {}); + console.log("DB stats:", j2s(w.getDbStats())); +} + +export async function testArgon2id() { + const userIdVector = { + input_id_data: { + name: "Fleabag", + ssn: "AB123", + }, + input_server_salt: "FZ48EFS7WS3R2ZR4V53A3GFFY4", + output_id: + "YS45R6CGJV84K1NN7T14ZBCPVTZ6H15XJSM1FV0R748MHPV82SM0126EBZKBAAGCR34Q9AFKPEW1HRT2Q9GQ5JRA3642AB571DKZS18", + }; + + if ( + (await userIdentifierDerive( + userIdVector.input_id_data, + userIdVector.input_server_salt, + )) != userIdVector.output_id + ) { + throw Error("argon2id is not working!"); + } + + console.log("argon2id is working!"); +} diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts index cbda401e9..2780a3cab 100644 --- a/packages/taler-wallet-embedded/src/wallet-qjs.ts +++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -1,6 +1,7 @@ /* This file is part of GNU Taler (C) 2019 GNUnet e.V. + (C) 2024 Taler Systems SA 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 @@ -28,30 +29,27 @@ import { mergeDiscoveryAggregate, reduceAction, } from "@gnu-taler/anastasis-core"; -import { userIdentifierDerive } from "@gnu-taler/anastasis-core/lib/crypto.js"; import { - AmountString, CoreApiMessageEnvelope, CoreApiResponse, CoreApiResponseSuccess, Logger, - PartialWalletRunConfig, WalletNotification, enableNativeLogging, getErrorDetailFromException, - j2s, openPromise, performanceNow, setGlobalLogLevelFromString, } from "@gnu-taler/taler-util"; import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { qjsOs } from "@gnu-taler/taler-util/qtart"; +import { Wallet, createNativeWalletHost2 } from "@gnu-taler/taler-wallet-core"; import { - DefaultNodeWalletArgs, - Wallet, - WalletApiOperation, - createNativeWalletHost2, -} from "@gnu-taler/taler-wallet-core"; + testArgon2id, + testWithFdold, + testWithGv, + testWithLocal, +} from './wallet-qjs-tests.js'; setGlobalLogLevelFromString("trace"); @@ -68,9 +66,6 @@ function sendNativeMessage(ev: CoreApiMessageEnvelope): void { } class NativeWalletMessageHandler { - walletArgs: DefaultNodeWalletArgs | undefined; - walletConfig: PartialWalletRunConfig | undefined; - maybeWallet: Wallet | undefined; wp = openPromise(); httpLib = createPlatformHttpLib(); @@ -91,23 +86,9 @@ class NativeWalletMessageHandler { }; }; - let initResponse: any = {}; - - const reinit = async () => { - logger.info("in reinit"); - const wR = await createNativeWalletHost2(this.walletArgs); - const w = wR.wallet; - this.maybeWallet = w; - const resp = await w.handleCoreApiRequest("initWallet", "native-init", { - config: this.walletConfig, - }); - initResponse = resp.type == "response" ? resp.result : resp.error; - this.wp.resolve(w); - }; - switch (operation) { case "init": { - this.walletArgs = { + const wR = await createNativeWalletHost2({ notifyHandler: async (notification: WalletNotification) => { sendNativeMessage({ type: "notification", payload: notification }); }, @@ -115,38 +96,29 @@ class NativeWalletMessageHandler { httpLib: this.httpLib, cryptoWorkerType: args.cryptoWorkerType, ...args, - }; - this.walletConfig = args.config ?? {}; - const logLevel = args.logLevel; - if (logLevel) { - setGlobalLogLevelFromString(logLevel); + }); + + if (args.logLevel) { + setGlobalLogLevelFromString(args.logLevel); } - const nativeLogging = args.useNativeLogging ?? false; - if (nativeLogging) { + + if (args.useNativeLogging === true) { enableNativeLogging(); } - await reinit(); + + const resp = await wR.wallet.handleCoreApiRequest("initWallet", "native-init", { + config: args.config ?? {}, + }); + + let initResponse: any = resp.type == "response" ? resp.result : resp.error; + + this.wp.resolve(wR.wallet); + return wrapSuccessResponse({ ...initResponse, }); } - case "startTunnel": { - // this.httpLib.useNfcTunnel = true; - throw Error("not implemented"); - } - case "stopTunnel": { - // this.httpLib.useNfcTunnel = false; - throw Error("not implemented"); - } - case "tunnelResponse": { - // httpLib.handleTunnelResponse(msg.args); - throw Error("not implemented"); - } - case "reset": { - throw Error( - "reset not supported anymore, please use the clearDb wallet-core request", - ); - } + default: { const wallet = await this.wp.promise; return await wallet.handleCoreApiRequest(operation, id, args); @@ -175,17 +147,22 @@ async function handleAnastasisRequest( let req = args ?? {}; switch (operation) { - case "anastasisReduce": - // TODO: do some input validation here + case "anastasisReduce": { let reduceRes = await reduceAction(req.state, req.action, req.args ?? {}); // For now, this will return "success" even if the wrapped Anastasis // response is a ReducerStateError. return wrapSuccessResponse(reduceRes); - case "anastasisStartBackup": + } + + case "anastasisStartBackup": { return wrapSuccessResponse(await getBackupStartState()); - case "anastasisStartRecovery": + } + + case "anastasisStartRecovery": { return wrapSuccessResponse(await getRecoveryStartState()); - case "anastasisDiscoverPolicies": + } + + case "anastasisDiscoverPolicies": { let discoverRes = await discoverPolicies(req.state, req.cursor); let aggregatedPolicies = mergeDiscoveryAggregate( discoverRes.policies ?? [], @@ -199,19 +176,25 @@ async function handleAnastasisRequest( cursor: discoverRes.cursor, }, }); - default: + } + + default: { throw Error("unsupported anastasis operation"); + } } } export function installNativeWalletListener(): void { setGlobalLogLevelFromString("trace"); + const handler = new NativeWalletMessageHandler(); + const onMessage = async (msgStr: any): Promise => { if (typeof msgStr !== "string") { logger.error("expected string as message"); return; } + const msg = JSON.parse(msgStr); const operation = msg.operation; if (typeof operation !== "string") { @@ -220,20 +203,23 @@ export function installNativeWalletListener(): void { ); return; } + const id = msg.id; logger.info(`native listener: got request for ${operation} (${id})`); - const startTimeNs = performanceNow(); - + const startTimeMs = performanceNow(); let respMsg: CoreApiResponse; + try { if (msg.operation.startsWith("anastasis")) { + // Entry point for Anastasis respMsg = await handleAnastasisRequest(operation, id, msg.args ?? {}); } else if (msg.operation === "testing-dangerously-eval") { // Eval code, used only for testing. No client may rely on this. logger.info(`evaluating ${msg.args.jscode}`); const f = new Function(msg.args.jscode); f(); + respMsg = { type: "response", result: {}, @@ -241,6 +227,7 @@ export function installNativeWalletListener(): void { id: msg.id, }; } else { + // Entry point for wallet-core respMsg = await handler.handleMessage(operation, id, msg.args ?? {}); } } catch (e) { @@ -251,10 +238,12 @@ export function installNativeWalletListener(): void { error: getErrorDetailFromException(e), }; } - const endTimeNs = performanceNow(); + + const endTimeMs = performanceNow(); const requestDurationMs = Math.round( - Number((endTimeNs - startTimeNs) / 1000n / 1000n), + Number((endTimeMs - startTimeMs) / 1000n / 1000n), ); + logger.info( `native listener: sending back ${respMsg.type} message for operation ${operation} (${id}) after ${requestDurationMs} ms`, ); @@ -268,102 +257,6 @@ export function installNativeWalletListener(): void { // @ts-ignore globalThis.installNativeWalletListener = installNativeWalletListener; - -export async function testWithGv() { - const w = await createNativeWalletHost2({}); - await w.wallet.client.call(WalletApiOperation.InitWallet, { - config: { - features: { - allowHttp: true, - }, - }, - }); - await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { - amountToSpend: "KUDOS:1" as AmountString, - amountToWithdraw: "KUDOS:3" as AmountString, - corebankApiBaseUrl: "https://bank.demo.taler.net/", - exchangeBaseUrl: "https://exchange.demo.taler.net/", - merchantBaseUrl: "https://backend.demo.taler.net/", - merchantAuthToken: "secret-token:sandbox", - }); - await w.wallet.client.call(WalletApiOperation.TestingWaitTasksDone, {}); - await w.wallet.client.call(WalletApiOperation.Shutdown, {}); -} - -export async function testWithFdold() { - const w = await createNativeWalletHost2({}); - await w.wallet.client.call(WalletApiOperation.InitWallet, { - config: { - features: { - allowHttp: true, - }, - }, - }); - await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { - amountToSpend: "TESTKUDOS:1" as AmountString, - amountToWithdraw: "TESTKUDOS:3" as AmountString, - corebankApiBaseUrl: "https://bank.taler.fdold.eu/", - exchangeBaseUrl: "https://exchange.taler.fdold.eu/", - merchantBaseUrl: "https://merchant.taler.fdold.eu/", - }); - await w.wallet.client.call(WalletApiOperation.TestingWaitTasksDone, {}); - await w.wallet.client.call(WalletApiOperation.Shutdown, {}); -} - -export async function testWithLocal(path: string) { - console.log("running local test"); - const w = await createNativeWalletHost2({ - persistentStoragePath: path ?? "walletdb.json", - }); - console.log("created wallet"); - await w.wallet.client.call(WalletApiOperation.InitWallet, { - config: { - features: { - allowHttp: true, - }, - testing: { - skipDefaults: true, - }, - }, - }); - console.log("initialized wallet"); - await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { - amountToSpend: "TESTKUDOS:1" as AmountString, - amountToWithdraw: "TESTKUDOS:3" as AmountString, - corebankApiBaseUrl: "http://localhost:8082/taler-bank-access/", - exchangeBaseUrl: "http://localhost:8081/", - merchantBaseUrl: "http://localhost:8083/", - }); - console.log("started integration test"); - await w.wallet.client.call(WalletApiOperation.TestingWaitTasksDone, {}); - console.log("done with task loop"); - await w.wallet.client.call(WalletApiOperation.Shutdown, {}); - console.log("DB stats:", j2s(w.getDbStats())); -} - -export async function testArgon2id() { - const userIdVector = { - input_id_data: { - name: "Fleabag", - ssn: "AB123", - }, - input_server_salt: "FZ48EFS7WS3R2ZR4V53A3GFFY4", - output_id: - "YS45R6CGJV84K1NN7T14ZBCPVTZ6H15XJSM1FV0R748MHPV82SM0126EBZKBAAGCR34Q9AFKPEW1HRT2Q9GQ5JRA3642AB571DKZS18", - }; - - if ( - (await userIdentifierDerive( - userIdVector.input_id_data, - userIdVector.input_server_salt, - )) != userIdVector.output_id - ) { - throw Error("argon2id is not working!"); - } - - console.log("argon2id is working!"); -} - // @ts-ignore globalThis.testWithGv = testWithGv; // @ts-ignore -- cgit v1.2.3