diff --git a/packages/taler-wallet-embedded/README.md b/packages/taler-wallet-embedded/README.md index b0444b208..b59e79e9a 100644 --- a/packages/taler-wallet-embedded/README.md +++ b/packages/taler-wallet-embedded/README.md @@ -1,4 +1,4 @@ # taler-wallet-embedded Minimal wrapper and build system code to make `taler-wallet-core` run -on embedded interpreters (currently NodeJS via akono, and `quickjs-tart`). +on embedded interpreters (currently `quickjs-tart`). diff --git a/packages/taler-wallet-embedded/package.json b/packages/taler-wallet-embedded/package.json index 6dcb45e01..4f57ebd45 100644 --- a/packages/taler-wallet-embedded/package.json +++ b/packages/taler-wallet-embedded/package.json @@ -3,20 +3,18 @@ "version": "0.9.3-dev.1", "description": "", "engines": { - "node": ">=0.12.0" + "node": ">=0.18.0" }, "repository": { "type": "git", "url": "git://git.taler.net/wallet-core.git" }, - "main": "dist/taler-wallet-embedded.cjs", "author": "Florian Dold", "license": "GPL-3.0", "type": "module", "scripts": { "compile": "./build.mjs", "pretty": "prettier --write src", - "coverage": "tsc && nyc ava", "clean": "rimraf lib dist tsconfig.tsbuildinfo", "deps": "pnpm install --frozen-lockfile --filter @gnu-taler/taler-wallet-embedded..." }, @@ -29,18 +27,10 @@ "src/" ], "devDependencies": { - "@rollup/plugin-commonjs": "^22.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.3.0", - "@rollup/plugin-replace": "^4.0.0", "@types/node": "^18.11.17", "esbuild": "^0.17.7", "prettier": "^2.5.1", - "rimraf": "^3.0.2", - "rollup": "^2.79.0", - "rollup-plugin-sourcemaps": "^0.6.3", - "rollup-plugin-terser": "^7.0.2", - "typescript": "^4.9.4" + "rimraf": "^3.0.2" }, "dependencies": { "@gnu-taler/idb-bridge": "workspace:*", diff --git a/packages/taler-wallet-embedded/rollup.config.js b/packages/taler-wallet-embedded/rollup.config.js deleted file mode 100644 index 1ebefae9a..000000000 --- a/packages/taler-wallet-embedded/rollup.config.js +++ /dev/null @@ -1,63 +0,0 @@ -// rollup.config.js -import commonjs from "@rollup/plugin-commonjs"; -import nodeResolve from "@rollup/plugin-node-resolve"; -import json from "@rollup/plugin-json"; -import builtins from "builtin-modules"; -import pkg from "./package.json"; -import walletCorePkg from "../taler-wallet-core/package.json"; -import replace from "@rollup/plugin-replace"; -import fs from "fs"; -import path from "path"; - -function git_hash() { - const rev = fs - .readFileSync(path.join(GIT_ROOT, ".git", "HEAD")) - .toString() - .trim() - .split(/.*[: ]/) - .slice(-1)[0]; - if (rev.indexOf("/") === -1) { - return rev; - } else { - return fs.readFileSync(path.join(GIT_ROOT, ".git", rev)).toString().trim(); - } -} - -const BASE = process.cwd(); -let GIT_ROOT = BASE; -while (!fs.existsSync(path.join(GIT_ROOT, ".git")) && GIT_ROOT !== "/") { - GIT_ROOT = path.join(GIT_ROOT, "../"); -} -const GIT_HASH = GIT_ROOT === "/" ? undefined : git_hash(); - -export default { - input: "lib/index.js", - output: { - file: pkg.main, - format: "cjs", - }, - external: builtins, - plugins: [ - nodeResolve({ - preferBuiltins: true, - exportConditions: ["node"], - }), - - replace({ - values: { - __VERSION__: `"${walletCorePkg.version}"`, - __GIT_HASH__: `"${GIT_HASH}"`, - }, - preventAssignment: false, - }), - - commonjs({ - include: [/node_modules/, /dist/], - extensions: [".js", ".ts"], - ignoreGlobal: false, - sourceMap: false, - }), - - json(), - ], -}; diff --git a/packages/taler-wallet-embedded/src/index.ts b/packages/taler-wallet-embedded/src/index.ts deleted file mode 100644 index 8079ba739..000000000 --- a/packages/taler-wallet-embedded/src/index.ts +++ /dev/null @@ -1,293 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2019 GNUnet e.V. - - 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 - */ - -/** - * Imports. - */ -import { - CoreApiMessageEnvelope, - CoreApiResponse, - CoreApiResponseSuccess, - getErrorDetailFromException, - Logger, - WalletNotification, -} from "@gnu-taler/taler-util"; -import { - createPlatformHttpLib, - Headers, - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, -} from "@gnu-taler/taler-util/http"; -import { - createNativeWalletHost, - DefaultNodeWalletArgs, - handleWorkerError, - handleWorkerMessage, - OpenedPromise, - openPromise, - Wallet, -} from "@gnu-taler/taler-wallet-core"; -import fs from "fs"; - -export { handleWorkerError, handleWorkerMessage }; - -const logger = new Logger("taler-wallet-embedded/index.ts"); - -export class NativeHttpLib implements HttpRequestLibrary { - useNfcTunnel = false; - - private httpLib: HttpRequestLibrary = createPlatformHttpLib(); - - private requestId = 1; - - private requestMap: { - [id: number]: OpenedPromise; - } = {}; - - constructor(private sendMessage: (m: string) => void) {} - - fetch(url: string, opt?: HttpRequestOptions): Promise { - return this.httpLib.fetch(url, opt); - } - - get(url: string, opt?: HttpRequestOptions): Promise { - if (this.useNfcTunnel) { - const myId = this.requestId++; - const p = openPromise(); - this.requestMap[myId] = p; - const request = { - method: "get", - url, - }; - this.sendMessage( - JSON.stringify({ - type: "tunnelHttp", - request, - id: myId, - }), - ); - return p.promise; - } else { - return this.httpLib.get(url, opt); - } - } - - postJson( - url: string, - body: any, - opt?: HttpRequestOptions, - ): Promise { - if (this.useNfcTunnel) { - const myId = this.requestId++; - const p = openPromise(); - this.requestMap[myId] = p; - const request = { - method: "postJson", - url, - body, - }; - this.sendMessage( - JSON.stringify({ type: "tunnelHttp", request, id: myId }), - ); - return p.promise; - } else { - return this.httpLib.postJson(url, body, opt); - } - } - - handleTunnelResponse(msg: any): void { - const myId = msg.id; - const p = this.requestMap[myId]; - if (!p) { - logger.error( - `no matching request for tunneled HTTP response, id=${myId}`, - ); - } - const headers = new Headers(); - if (msg.status != 0) { - const resp: HttpResponse = { - // FIXME: pass through this URL - requestUrl: "", - headers, - status: msg.status, - requestMethod: "FIXME", - json: async () => JSON.parse(msg.responseText), - text: async () => msg.responseText, - bytes: async () => { - throw Error("bytes() not supported for tunnel response"); - }, - }; - p.resolve(resp); - } else { - p.reject(new Error(`unexpected HTTP status code ${msg.status}`)); - } - delete this.requestMap[myId]; - } -} - -function sendNativeMessage(ev: CoreApiMessageEnvelope): void { - // @ts-ignore - const sendMessage = globalThis.__native_sendMessage; - if (typeof sendMessage !== "function") { - const errMsg = - "FATAL: cannot install native wallet listener: native functions missing"; - logger.error(errMsg); - throw new Error(errMsg); - } - const m = JSON.stringify(ev); - // @ts-ignore - sendMessage(m); -} - -class NativeWalletMessageHandler { - walletArgs: DefaultNodeWalletArgs | undefined; - maybeWallet: Wallet | undefined; - wp = openPromise(); - httpLib = createPlatformHttpLib(); - - /** - * Handle a request from the native wallet. - */ - async handleMessage( - operation: string, - id: string, - args: any, - ): Promise { - const wrapResponse = (result: unknown): CoreApiResponseSuccess => { - return { - type: "response", - id, - operation, - result, - }; - }; - - let initResponse: any = {}; - - const reinit = async () => { - logger.info("in reinit"); - const w = await createNativeWalletHost(this.walletArgs); - this.maybeWallet = w; - const resp = await w.handleCoreApiRequest( - "initWallet", - "native-init", - {}, - ); - initResponse = resp.type == "response" ? resp.result : resp.error; - w.runTaskLoop().catch((e) => { - logger.error( - `Error during wallet retry loop: ${e.stack ?? e.toString()}`, - ); - }); - this.wp.resolve(w); - }; - - switch (operation) { - case "init": { - this.walletArgs = { - notifyHandler: async (notification: WalletNotification) => { - sendNativeMessage({ type: "notification", payload: notification }); - }, - persistentStoragePath: args.persistentStoragePath, - httpLib: this.httpLib, - cryptoWorkerType: args.cryptoWorkerType, - }; - await reinit(); - return wrapResponse({ - ...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": { - const oldArgs = this.walletArgs; - this.walletArgs = { ...oldArgs }; - if (oldArgs && oldArgs.persistentStoragePath) { - try { - fs.unlinkSync(oldArgs.persistentStoragePath); - } catch (e) { - logger.error("Error while deleting the wallet db:", e); - } - // Prevent further storage! - this.walletArgs.persistentStoragePath = undefined; - } - const wallet = await this.wp.promise; - wallet.stop(); - this.wp = openPromise(); - this.maybeWallet = undefined; - await reinit(); - return wrapResponse({}); - } - default: { - const wallet = await this.wp.promise; - return await wallet.handleCoreApiRequest(operation, id, args); - } - } - } -} - -export function installNativeWalletListener(): void { - 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") { - logger.error( - "message to native wallet helper must contain operation of type string", - ); - return; - } - const id = msg.id; - logger.info(`native listener: got request for ${operation} (${id})`); - - try { - const respMsg = await handler.handleMessage(operation, id, msg.args); - logger.info( - `native listener: sending success response for ${operation} (${id})`, - ); - sendNativeMessage(respMsg); - } catch (e) { - const respMsg: CoreApiResponse = { - type: "error", - id, - operation, - error: getErrorDetailFromException(e), - }; - sendNativeMessage(respMsg); - return; - } - }; - - // @ts-ignore - globalThis.__native_onMessage = onMessage; - - logger.info("native wallet listener installed"); -} diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts index 9c379063e..9cf735b12 100644 --- a/packages/taler-wallet-embedded/src/wallet-qjs.ts +++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -14,6 +14,10 @@ GNU Taler; see the file COPYING. If not, see */ +/** + * Entry-point for the wallet under qtart, the QuckJS-based GNU Taler runtime. + */ + /** * Imports. */ diff --git a/packages/taler-wallet-embedded/test-embedded.cjs b/packages/taler-wallet-embedded/test-embedded.cjs deleted file mode 100644 index bc5bf9086..000000000 --- a/packages/taler-wallet-embedded/test-embedded.cjs +++ /dev/null @@ -1,68 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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 - */ - -// This file demonstrates how to use the single-file embedded wallet. - -// Load the embedded wallet -const embedded = require("./dist/taler-wallet-embedded.cjs"); - -// Some bookkeeping to correlate requests to responses. -const requestMap = {}; -let requestCounter = 1; - -// Install __native_onMessage in the global namespace. -// The __native_onMessage handles messages from the host, -// i.e. it handles wallet-core requests from the host application (UI etc.). -embedded.installNativeWalletListener(); - -// The host application must the __native_sendMessage callback -// to allow wallet-core to respond. -globalThis.__native_sendMessage = (msgStr) => { - const message = JSON.parse(msgStr); - if (message.type === "notification") { - console.log("got notification:", JSON.stringify(message.payload)); - return; - } - if (message.type === "response") { - console.log("got response", JSON.parse(msgStr)); - const msgId = message.id; - requestMap[msgId](message); - delete requestMap[msgId]; - return; - } - throw Error("not reached"); -}; - -async function makeRequest(operation, payload = {}) { - return new Promise((resolve, reject) => { - const reqId = `req-${requestCounter++}`; - requestMap[reqId] = (x) => resolve(x); - __native_onMessage( - JSON.stringify({ - operation, - args: payload, - id: reqId, - }), - ); - }); -} - -async function testMain() { - const resp = await makeRequest("init"); - console.log("response from init", JSON.stringify(resp)); -} - -testMain(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80d0a0e94..442388b22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -518,37 +518,21 @@ importers: '@gnu-taler/idb-bridge': workspace:* '@gnu-taler/taler-util': workspace:* '@gnu-taler/taler-wallet-core': workspace:* - '@rollup/plugin-commonjs': ^22.0.2 - '@rollup/plugin-json': ^4.1.0 - '@rollup/plugin-node-resolve': ^13.3.0 - '@rollup/plugin-replace': ^4.0.0 '@types/node': ^18.11.17 esbuild: ^0.17.7 prettier: ^2.5.1 rimraf: ^3.0.2 - rollup: ^2.79.0 - rollup-plugin-sourcemaps: ^0.6.3 - rollup-plugin-terser: ^7.0.2 tslib: ^2.4.0 - typescript: ^4.9.4 dependencies: '@gnu-taler/idb-bridge': link:../idb-bridge '@gnu-taler/taler-util': link:../taler-util '@gnu-taler/taler-wallet-core': link:../taler-wallet-core tslib: 2.4.0 devDependencies: - '@rollup/plugin-commonjs': 22.0.2_rollup@2.79.1 - '@rollup/plugin-json': 4.1.0_rollup@2.79.1 - '@rollup/plugin-node-resolve': 13.3.0_rollup@2.79.1 - '@rollup/plugin-replace': 4.0.0_rollup@2.79.1 '@types/node': 18.11.17 esbuild: 0.17.7 prettier: 2.7.1 rimraf: 3.0.2 - rollup: 2.79.1 - rollup-plugin-sourcemaps: 0.6.3_bipou45jdaxtftg6fcql4vnhdm - rollup-plugin-terser: 7.0.2_rollup@2.79.1 - typescript: 4.9.4 packages/taler-wallet-webextension: specifiers: @@ -2573,7 +2557,7 @@ packages: dependencies: '@babel/core': 7.18.9 '@babel/helper-module-imports': 7.18.6 - '@babel/helper-plugin-utils': 7.19.0 + '@babel/helper-plugin-utils': 7.20.2 babel-plugin-polyfill-corejs2: 0.3.3_@babel+core@7.18.9 babel-plugin-polyfill-corejs3: 0.6.0_@babel+core@7.18.9 babel-plugin-polyfill-regenerator: 0.4.1_@babel+core@7.18.9