From 825d2c4352022e7397854b2bd9ba7d3589873c07 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 15 Feb 2023 23:32:42 +0100 Subject: [PATCH] make wallet-cli runnable under qtart --- packages/anastasis-core/src/cli.ts | 2 +- .../src/utils/regex.test.ts | 2 +- packages/taler-harness/src/bench1.ts | 17 +- packages/taler-harness/src/bench2.ts | 11 +- packages/taler-harness/src/bench3.ts | 15 +- packages/taler-harness/src/harness/harness.ts | 9 +- packages/taler-harness/src/index.ts | 13 +- .../test-exchange-timetravel.ts | 10 +- .../src/integrationtests/test-kyc.ts | 14 +- .../test-merchant-spec-public-orders.ts | 5 +- .../integrationtests/test-payment-on-demo.ts | 4 +- .../test-wallet-cryptoworker.ts | 13 - .../integrationtests/test-wallet-dbless.ts | 11 +- packages/taler-harness/src/lint.ts | 10 +- packages/taler-util/package.json | 30 ++- packages/taler-util/src/clk.ts | 53 ++-- .../src/compat.d.ts} | 28 +-- packages/taler-util/src/compat.node.ts | 59 +++++ packages/taler-util/src/compat.qtart.ts | 53 ++++ .../src/errors.ts | 0 packages/taler-util/src/http-common.ts | 39 +++ packages/taler-util/src/http-impl.node.d.ts | 17 ++ packages/taler-util/src/http-impl.node.ts | 175 +++++++++++++ packages/taler-util/src/http-impl.qtart.ts | 127 ++++++++++ .../src/util => taler-util/src}/http.ts | 8 +- packages/taler-util/src/index.browser.ts | 4 + packages/taler-util/src/index.node.ts | 1 - packages/taler-util/src/index.ts | 1 + packages/taler-util/src/qtart.ts | 36 +++ packages/taler-util/src/twrpc-impl.missing.ts | 9 + packages/taler-wallet-cli/build.mjs | 6 +- packages/taler-wallet-cli/src/index.ts | 129 +++++----- packages/taler-wallet-core/package.json | 8 +- .../taler-wallet-core/src/bank-api-client.ts | 7 +- .../crypto/workers/crypto-dispatcher.test.ts | 2 - .../src/crypto/workers/crypto-dispatcher.ts | 2 +- .../src/crypto/workers/rpcClient.ts | 92 ------- .../crypto/workers/synchronousWorkerNode.ts | 174 ------------- .../src/crypto/workers/worker-common.ts | 2 +- packages/taler-wallet-core/src/db.ts | 3 + packages/taler-wallet-core/src/dbless.ts | 2 +- .../taler-wallet-core/src/dev-experiments.ts | 2 +- .../src/headless/NodeHttpLib.ts | 183 -------------- packages/taler-wallet-core/src/host-common.ts | 60 +++++ .../helpers.ts => host-impl.node.ts} | 78 ++---- .../taler-wallet-core/src/host-impl.qtart.ts | 120 +++++++++ packages/taler-wallet-core/src/host.ts | 47 ++++ packages/taler-wallet-core/src/index.node.ts | 11 +- packages/taler-wallet-core/src/index.ts | 6 +- .../src/internal-wallet-state.ts | 13 +- .../src/operations/backup/index.ts | 4 +- .../src/operations/common.ts | 2 +- .../src/operations/deposits.ts | 6 +- .../src/operations/exchanges.ts | 9 +- .../src/operations/merchants.ts | 2 +- .../src/operations/pay-merchant.ts | 7 +- .../src/operations/pay-peer.ts | 5 +- .../src/operations/recoup.ts | 2 +- .../src/operations/refresh.ts | 4 +- .../src/operations/testing.ts | 2 +- .../taler-wallet-core/src/operations/tip.ts | 4 +- .../src/operations/withdraw.ts | 4 +- packages/taler-wallet-core/src/remote.ts | 2 +- .../taler-wallet-core/src/util/retries.ts | 2 +- packages/taler-wallet-core/src/wallet.ts | 4 +- packages/taler-wallet-embedded/build.mjs | 1 + packages/taler-wallet-embedded/src/index.ts | 28 +-- .../taler-wallet-embedded/src/wallet-qjs.ts | 237 ++---------------- .../src/browserHttpLib.ts | 10 +- .../src/browserWorkerEntry.ts | 7 +- .../src/cta/InvoiceCreate/state.ts | 2 +- .../src/cta/InvoicePay/state.ts | 6 +- .../src/cta/TransferCreate/state.ts | 6 +- .../src/cta/TransferPickup/state.ts | 7 +- .../src/cta/Withdraw/state.ts | 3 +- .../src/hooks/useAsyncAsHook.ts | 3 +- .../src/platform/chrome.ts | 3 +- .../src/serviceWorkerCryptoWorkerFactory.ts | 4 +- .../src/serviceWorkerHttpLib.ts | 4 +- .../taler-wallet-webextension/src/wxApi.ts | 8 +- .../src/wxBackend.ts | 4 +- 81 files changed, 1069 insertions(+), 1046 deletions(-) rename packages/{taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts => taler-util/src/compat.d.ts} (51%) create mode 100644 packages/taler-util/src/compat.node.ts create mode 100644 packages/taler-util/src/compat.qtart.ts rename packages/{taler-wallet-core => taler-util}/src/errors.ts (100%) create mode 100644 packages/taler-util/src/http-common.ts create mode 100644 packages/taler-util/src/http-impl.node.d.ts create mode 100644 packages/taler-util/src/http-impl.node.ts create mode 100644 packages/taler-util/src/http-impl.qtart.ts rename packages/{taler-wallet-core/src/util => taler-util/src}/http.ts (97%) create mode 100644 packages/taler-util/src/qtart.ts delete mode 100644 packages/taler-wallet-core/src/crypto/workers/rpcClient.ts delete mode 100644 packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts delete mode 100644 packages/taler-wallet-core/src/headless/NodeHttpLib.ts create mode 100644 packages/taler-wallet-core/src/host-common.ts rename packages/taler-wallet-core/src/{headless/helpers.ts => host-impl.node.ts} (67%) create mode 100644 packages/taler-wallet-core/src/host-impl.qtart.ts create mode 100644 packages/taler-wallet-core/src/host.ts diff --git a/packages/anastasis-core/src/cli.ts b/packages/anastasis-core/src/cli.ts index 517f2876d..df53d6bd0 100644 --- a/packages/anastasis-core/src/cli.ts +++ b/packages/anastasis-core/src/cli.ts @@ -1,4 +1,4 @@ -import { clk } from "@gnu-taler/taler-util"; +import { clk } from "@gnu-taler/taler-util/clk"; import { getBackupStartState, getRecoveryStartState, diff --git a/packages/merchant-backoffice-ui/src/utils/regex.test.ts b/packages/merchant-backoffice-ui/src/utils/regex.test.ts index 341a19fb1..d473bd08c 100644 --- a/packages/merchant-backoffice-ui/src/utils/regex.test.ts +++ b/packages/merchant-backoffice-ui/src/utils/regex.test.ts @@ -20,7 +20,7 @@ */ import { expect } from "chai"; -import { AMOUNT_REGEX, PAYTO_REGEX } from "../../src/utils/constants.js"; +import { AMOUNT_REGEX, PAYTO_REGEX } from "./constants.js"; describe("payto uri format", () => { const valids = [ diff --git a/packages/taler-harness/src/bench1.ts b/packages/taler-harness/src/bench1.ts index 84786d25a..0a4118ec1 100644 --- a/packages/taler-harness/src/bench1.ts +++ b/packages/taler-harness/src/bench1.ts @@ -19,19 +19,19 @@ */ import { buildCodecForObject, + codecForBoolean, codecForNumber, codecForString, - codecForBoolean, codecOptional, j2s, Logger, } from "@gnu-taler/taler-util"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { - getDefaultNodeWallet2, - NodeHttpLib, - WalletApiOperation, - Wallet, AccessStats, + createNativeWalletHost2, + Wallet, + WalletApiOperation, } from "@gnu-taler/taler-wallet-core"; /** @@ -46,8 +46,9 @@ export async function runBench1(configJson: any): Promise { // Validate the configuration file for this benchmark. const b1conf = codecForBench1Config().decode(configJson); - const myHttpLib = new NodeHttpLib(); - myHttpLib.setThrottling(false); + const myHttpLib = createPlatformHttpLib({ + enableThrottling: false, + }); const numIter = b1conf.iterations ?? 1; const numDeposits = b1conf.deposits ?? 5; @@ -81,7 +82,7 @@ export async function runBench1(configJson: any): Promise { console.log("wallet DB stats", j2s(getDbStats!())); } - const res = await getDefaultNodeWallet2({ + const res = await createNativeWalletHost2({ // No persistent DB storage. persistentStoragePath: undefined, httpLib: myHttpLib, diff --git a/packages/taler-harness/src/bench2.ts b/packages/taler-harness/src/bench2.ts index 9fa5d7caf..ff87da52a 100644 --- a/packages/taler-harness/src/bench2.ts +++ b/packages/taler-harness/src/bench2.ts @@ -24,6 +24,7 @@ import { codecOptional, Logger, } from "@gnu-taler/taler-util"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { checkReserve, createFakebankReserve, @@ -31,9 +32,8 @@ import { depositCoin, downloadExchangeInfo, findDenomOrThrow, - NodeHttpLib, refreshCoin, - SynchronousCryptoWorkerFactoryNode, + SynchronousCryptoWorkerFactoryPlain, withdrawCoin, } from "@gnu-taler/taler-wallet-core"; @@ -50,12 +50,13 @@ export async function runBench2(configJson: any): Promise { const benchConf = codecForBench2Config().decode(configJson); const curr = benchConf.currency; const cryptoDisp = new CryptoDispatcher( - new SynchronousCryptoWorkerFactoryNode(), + new SynchronousCryptoWorkerFactoryPlain(), ); const cryptoApi = cryptoDisp.cryptoApi; - const http = new NodeHttpLib(); - http.setThrottling(false); + const http = createPlatformHttpLib({ + enableThrottling: false, + }); const numIter = benchConf.iterations ?? 1; const numDeposits = benchConf.deposits ?? 5; diff --git a/packages/taler-harness/src/bench3.ts b/packages/taler-harness/src/bench3.ts index 9679f05a6..5e8fac0e9 100644 --- a/packages/taler-harness/src/bench3.ts +++ b/packages/taler-harness/src/bench3.ts @@ -25,12 +25,12 @@ import { j2s, Logger, } from "@gnu-taler/taler-util"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { - getDefaultNodeWallet2, - NodeHttpLib, - WalletApiOperation, - Wallet, AccessStats, + createNativeWalletHost2, + Wallet, + WalletApiOperation, } from "@gnu-taler/taler-wallet-core"; import benchMerchantIDGenerator from "./benchMerchantIDGenerator.js"; @@ -50,8 +50,9 @@ export async function runBench3(configJson: any): Promise { throw new Error("Payto template url must contain '${id}' placeholder"); } - const myHttpLib = new NodeHttpLib(); - myHttpLib.setThrottling(false); + const myHttpLib = createPlatformHttpLib({ + enableThrottling: false, + }); const numIter = b3conf.iterations ?? 1; const numDeposits = b3conf.deposits ?? 5; @@ -89,7 +90,7 @@ export async function runBench3(configJson: any): Promise { console.log("wallet DB stats", j2s(getDbStats!())); } - const res = await getDefaultNodeWallet2({ + const res = await createNativeWalletHost2({ // No persistent DB storage. persistentStoragePath: undefined, httpLib: myHttpLib, diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts index 0b7ba14cf..518b98d82 100644 --- a/packages/taler-harness/src/harness/harness.ts +++ b/packages/taler-harness/src/harness/harness.ts @@ -41,17 +41,15 @@ import { MerchantTemplateAddDetails, parsePaytoUri, stringToBytes, + TalerError, TalerProtocolDuration, WalletNotification, } from "@gnu-taler/taler-util"; import { - BankAccessApi, BankApi, BankServiceHandle, HarnessExchangeBankAccount, - NodeHttpLib, openPromise, - TalerError, WalletCoreApiClient, } from "@gnu-taler/taler-wallet-core"; import { deepStrictEqual } from "assert"; @@ -83,6 +81,7 @@ import { RemoteWallet, WalletNotificationWaiter, } from "@gnu-taler/taler-wallet-core/remote"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; const logger = new Logger("harness.ts"); @@ -507,7 +506,7 @@ class LibEuFinBankService extends BankServiceBase implements BankServiceHandle { sandboxProc: ProcessWrapper | undefined; nexusProc: ProcessWrapper | undefined; - http = new NodeHttpLib(); + http = createPlatformHttpLib(); static async create( gc: GlobalTestState, @@ -794,7 +793,7 @@ export class FakebankService { proc: ProcessWrapper | undefined; - http = new NodeHttpLib(); + http = createPlatformHttpLib(); // We store "created" accounts during setup and // register them after startup. diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts index e4ee25dae..14b8a4302 100644 --- a/packages/taler-harness/src/index.ts +++ b/packages/taler-harness/src/index.ts @@ -23,7 +23,6 @@ import os from "os"; import path from "path"; import { Amounts, - clk, Configuration, decodeCrock, Logger, @@ -38,6 +37,7 @@ import { GlobalTestState, runTestWithState } from "./harness/harness.js"; import { getTestInfo, runTests } from "./integrationtests/testrunner.js"; import { lintExchangeDeployment } from "./lint.js"; import { runEnvFull } from "./env-full.js"; +import { clk } from "@gnu-taler/taler-util/clk"; const logger = new Logger("taler-harness:index.ts"); @@ -74,6 +74,15 @@ const advancedCli = testingCli.subcommand("advancedArgs", "advanced", { help: "Subcommands for advanced operations (only use if you know what you're doing!).", }); +advancedCli + .subcommand("decode", "decode", { + help: "Decode base32-crockford.", + }) + .action((args) => { + const enc = fs.readFileSync(0, "utf8"); + console.log(decodeCrock(enc.trim())); + }); + advancedCli .subcommand("bench1", "bench1", { help: "Run the 'bench1' benchmark", @@ -272,7 +281,7 @@ testingCli help: "Produce less output.", }) .flag("noTimeout", ["--no-timeout"], { - help: "Do not time out tests." + help: "Do not time out tests.", }) .action(async (args) => { await runTests({ diff --git a/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts b/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts index 074126e9f..20285cb6a 100644 --- a/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts +++ b/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts @@ -24,22 +24,18 @@ import { Duration, durationFromSpec, } from "@gnu-taler/taler-util"; -import { - NodeHttpLib, - readSuccessResponseJsonOrThrow, -} from "@gnu-taler/taler-wallet-core"; +import { createPlatformHttpLib, readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; import { makeNoFeeCoinConfig } from "../harness/denomStructures.js"; import { BankService, ExchangeService, GlobalTestState, - MerchantPrivateApi, MerchantService, setupDb, WalletCli, getPayto, } from "../harness/harness.js"; -import { startWithdrawViaBank, withdrawViaBank } from "../harness/helpers.js"; +import { withdrawViaBank } from "../harness/helpers.js"; async function applyTimeTravel( timetravelDuration: Duration, @@ -69,7 +65,7 @@ async function applyTimeTravel( } } -const http = new NodeHttpLib(); +const http = createPlatformHttpLib(); /** * Basic time travel test. diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts index 490673cee..915c3d470 100644 --- a/packages/taler-harness/src/integrationtests/test-kyc.ts +++ b/packages/taler-harness/src/integrationtests/test-kyc.ts @@ -17,11 +17,14 @@ /** * Imports. */ -import { Duration, j2s, NotificationType } 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"; @@ -37,6 +40,7 @@ import { } from "../harness/harness.js"; import { EnvOptions, SimpleTestEnvironmentNg } from "../harness/helpers.js"; import * as http from "node:http"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; export async function createKycTestkudosEnvironment( t: GlobalTestState, @@ -336,12 +340,12 @@ export async function runKycTest(t: GlobalTestState) { // 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 httpLib = createPlatformHttpLib(); + const kycServerResp = await httpLib.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); + const proofHttpResp = await httpLib.get(kycProofUrl); console.log("proof resp status", proofHttpResp.status); console.log("resp headers", proofHttpResp.headers.toJSON()); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts b/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts index 70edaaf0c..2fafe7584 100644 --- a/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts +++ b/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts @@ -24,7 +24,8 @@ import { encodeCrock, getRandomBytes, } from "@gnu-taler/taler-util"; -import { NodeHttpLib, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { BankService, ExchangeService, @@ -38,7 +39,7 @@ import { withdrawViaBank, } from "../harness/helpers.js"; -const httpLib = new NodeHttpLib(); +const httpLib = createPlatformHttpLib(); interface Context { merchant: MerchantService; diff --git a/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts b/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts index 737620ce7..22e88c8a0 100644 --- a/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts +++ b/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts @@ -24,8 +24,8 @@ import { BankApi, BankAccessApi, BankServiceHandle, - NodeHttpLib, } from "@gnu-taler/taler-wallet-core"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; /** * Run test for basic, bank-integrated withdrawal and payment. @@ -35,7 +35,7 @@ export async function runPaymentDemoTest(t: GlobalTestState) { let bankInterface: BankServiceHandle = { baseUrl: "https://bank.demo.taler.net/", bankAccessApiBaseUrl: "https://bank.demo.taler.net/", - http: new NodeHttpLib(), + http: createPlatformHttpLib(), }; let user = await BankApi.createRandomBankUser(bankInterface); let wop = await BankAccessApi.createWithdrawalOperation( diff --git a/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts b/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts index a9f1c4d80..6c2006636 100644 --- a/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts +++ b/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts @@ -17,23 +17,10 @@ /** * Imports. */ -import { j2s } from "@gnu-taler/taler-util"; import { - checkReserve, - CryptoDispatcher, - depositCoin, - downloadExchangeInfo, - findDenomOrThrow, - NodeHttpLib, - refreshCoin, - SynchronousCryptoWorkerFactoryNode, - TalerError, - topupReserveWithDemobank, WalletApiOperation, - withdrawCoin, } from "@gnu-taler/taler-wallet-core"; import { GlobalTestState, WalletCli } from "../harness/harness.js"; -import { createSimpleTestkudosEnvironment } from "../harness/helpers.js"; /** * Run test for the different crypto workers. diff --git a/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts b/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts index 7692f12b2..08c10fd91 100644 --- a/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts +++ b/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts @@ -17,17 +17,16 @@ /** * Imports. */ -import { j2s } from "@gnu-taler/taler-util"; +import { j2s, TalerError } from "@gnu-taler/taler-util"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { checkReserve, CryptoDispatcher, depositCoin, downloadExchangeInfo, findDenomOrThrow, - NodeHttpLib, refreshCoin, - SynchronousCryptoWorkerFactoryNode, - TalerError, + SynchronousCryptoWorkerFactoryPlain, topupReserveWithDemobank, withdrawCoin, } from "@gnu-taler/taler-wallet-core"; @@ -42,9 +41,9 @@ export async function runWalletDblessTest(t: GlobalTestState) { const { bank, exchange } = await createSimpleTestkudosEnvironment(t); - const http = new NodeHttpLib(); + const http = createPlatformHttpLib(); const cryptiDisp = new CryptoDispatcher( - new SynchronousCryptoWorkerFactoryNode(), + new SynchronousCryptoWorkerFactoryPlain(), ); const cryptoApi = cryptiDisp.cryptoApi; diff --git a/packages/taler-harness/src/lint.ts b/packages/taler-harness/src/lint.ts index 49fb9dc86..3d3805e79 100644 --- a/packages/taler-harness/src/lint.ts +++ b/packages/taler-harness/src/lint.ts @@ -37,13 +37,13 @@ import { Configuration, decodeCrock, } from "@gnu-taler/taler-util"; -import { - NodeHttpLib, - readSuccessResponseJsonOrThrow, -} from "@gnu-taler/taler-wallet-core"; import { URL } from "url"; import { spawn } from "child_process"; import { delayMs } from "./harness/harness.js"; +import { + createPlatformHttpLib, + readSuccessResponseJsonOrThrow, +} from "@gnu-taler/taler-util/http"; interface BasicConf { mainCurrency: string; @@ -53,7 +53,7 @@ interface PubkeyConf { masterPublicKey: string; } -const httpLib = new NodeHttpLib(); +const httpLib = createPlatformHttpLib(); interface ShellResult { stdout: string; diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json index 23ff5dcfa..9cf47d256 100644 --- a/packages/taler-util/package.json +++ b/packages/taler-util/package.json @@ -15,12 +15,38 @@ }, "./twrpc": { "default": "./lib/twrpc.js" + }, + "./compat": { + "types": "./lib/compat.node.js", + "node": "./lib/compat.node.js", + "qtart": "./lib/compat.qtart.js", + "default": "./lib/not-implemented.js" + }, + "./clk": { + "default": "./lib/clk.js" + }, + "./http": { + "default": "./lib/http.js" + }, + "./qtart": { + "types": "./lib/qtart.js", + "qtart": "./lib/qtart.js", + "default": "./lib/not-implemented.js" } }, "imports": { "#twrpc-impl": { - "node": "./lib/twrpc-impl.node.js", - "default": "./lib/twrpc-impl.missing.js" + "node": "./lib/twrpc-impl.node.js" + }, + "#compat-impl": { + "node": "./lib/compat.node.js", + "qtart": "./lib/compat.qtart.js", + "type": "./lib/compat.d.ts" + }, + "#http-impl": { + "type": "./lib/http-impl.node.js", + "node": "./lib/http-impl.node.js", + "qtart": "./lib/http-impl.qtart.js" } }, "scripts": { diff --git a/packages/taler-util/src/clk.ts b/packages/taler-util/src/clk.ts index e99ebf733..7bcd19b04 100644 --- a/packages/taler-util/src/clk.ts +++ b/packages/taler-util/src/clk.ts @@ -17,10 +17,12 @@ /** * Imports. */ -import process from "process"; -import path from "path"; -import readline from "readline"; -import { devNull } from "os"; +import { + processExit, + processArgv, + readlinePrompt, + pathBasename, +} from "#compat-impl"; export namespace clk { class Converter {} @@ -359,13 +361,13 @@ export namespace clk { console.error( `error: unknown option '--${r.key}' for ${currentName}`, ); - process.exit(-1); + processExit(-1); throw Error("not reached"); } if (d.isFlag) { if (r.value !== undefined) { console.error(`error: flag '--${r.key}' does not take a value`); - process.exit(-1); + processExit(-1); throw Error("not reached"); } storeFlag(d, true); @@ -373,7 +375,7 @@ export namespace clk { if (r.value === undefined) { if (i === unparsedArgs.length - 1) { console.error(`error: option '--${r.key}' needs an argument`); - process.exit(-1); + processExit(-1); throw Error("not reached"); } storeOption(d, unparsedArgs[i + 1]); @@ -391,7 +393,7 @@ export namespace clk { const opt = this.shortOptions[chr]; if (!opt) { console.error(`error: option '-${chr}' not known`); - process.exit(-1); + processExit(-1); } if (opt.isFlag) { storeFlag(opt, true); @@ -399,7 +401,7 @@ export namespace clk { if (si == optShort.length - 1) { if (i === unparsedArgs.length - 1) { console.error(`error: option '-${chr}' needs an argument`); - process.exit(-1); + processExit(-1); throw Error("not reached"); } else { storeOption(opt, unparsedArgs[i + 1]); @@ -418,7 +420,7 @@ export namespace clk { const subcmd = this.subcommandMap[argVal]; if (!subcmd) { console.error(`error: unknown command '${argVal}'`); - process.exit(-1); + processExit(-1); throw Error("not reached"); } foundSubcommand = subcmd.commandGroup; @@ -427,7 +429,7 @@ export namespace clk { const d = this.arguments[posArgIndex]; if (!d) { console.error(`error: too many arguments for ${currentName}`); - process.exit(-1); + processExit(-1); throw Error("not reached"); } myArgs[d.name] = unparsedArgs[i]; @@ -437,7 +439,7 @@ export namespace clk { if (parsedArgs[this.argKey].help) { this.printHelp(progname, parents); - process.exit(0); + processExit(0); throw Error("not reached"); } @@ -450,7 +452,7 @@ export namespace clk { console.error( `error: missing positional argument '${d.name}' for ${currentName}`, ); - process.exit(-1); + processExit(-1); throw Error("not reached"); } } @@ -464,7 +466,7 @@ export namespace clk { } else { const name = option.flagspec.join(","); console.error(`error: missing option '${name}'`); - process.exit(-1); + processExit(-1); throw Error("not reached"); } } @@ -492,16 +494,16 @@ export namespace clk { } catch (e) { console.error(`An error occurred while running ${currentName}`); console.error(e); - process.exit(1); + processExit(1); } Promise.resolve(r).catch((e) => { console.error(`An error occurred while running ${currentName}`); console.error(e); - process.exit(1); + processExit(1); }); } else { this.printHelp(progname, parents); - process.exit(-1); + processExit(-1); throw Error("not reached"); } } @@ -524,15 +526,15 @@ export namespace clk { if (cmdlineArgs) { args = cmdlineArgs; } else { - args = process.argv.slice(1); + args = processArgv().slice(1); } if (args.length < 1) { console.error( "Error while parsing command line arguments: not enough arguments", ); - process.exit(-1); + processExit(-1); } - const progname = path.basename(args[0]); + const progname = pathBasename(args[0]); const rest = args.slice(1); this.mainCommand.run(progname, [], rest, {}); @@ -622,15 +624,6 @@ export namespace clk { } export function prompt(question: string): Promise { - const stdinReadline = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - return new Promise((resolve, reject) => { - stdinReadline.question(question, (res) => { - resolve(res); - stdinReadline.close(); - }); - }); + return readlinePrompt(question); } } diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts b/packages/taler-util/src/compat.d.ts similarity index 51% rename from packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts rename to packages/taler-util/src/compat.d.ts index 90f9a43fa..12ba31124 100644 --- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts +++ b/packages/taler-util/src/compat.d.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2019 GNUnet e.V. + (C) 2023 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 @@ -14,23 +14,9 @@ GNU Taler; see the file COPYING. If not, see */ -/** - * Imports. - */ -import { CryptoWorkerFactory } from "./crypto-dispatcher.js"; -import { CryptoWorker } from "./cryptoWorkerInterface.js"; -import { SynchronousCryptoWorkerNode } from "./synchronousWorkerNode.js"; - -/** - * The synchronous crypto worker produced by this factory doesn't run in the - * background, but actually blocks the caller until the operation is done. - */ -export class SynchronousCryptoWorkerFactoryNode implements CryptoWorkerFactory { - startWorker(): CryptoWorker { - return new SynchronousCryptoWorkerNode(); - } - - getConcurrency(): number { - return 1; - } -} +export function processExit(status: number): never; +export function processArgv(): string[]; +export function readlinePrompt(prompt: string): Promise; +export function pathBasename(s: string): string; +export function setUnhandledRejectionHandler(h: (e: any) => void): void; +export function getenv(name: string): string | undefined; \ No newline at end of file diff --git a/packages/taler-util/src/compat.node.ts b/packages/taler-util/src/compat.node.ts new file mode 100644 index 000000000..ed27a7acd --- /dev/null +++ b/packages/taler-util/src/compat.node.ts @@ -0,0 +1,59 @@ +/* + This file is part of GNU Taler + (C) 2023 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 + */ + +import process from "node:process"; +import readline from "node:readline"; +import path from "node:path"; +import os from "node:os"; + +export function processExit(status: number): never { + process.exit(1); +} + +export function processArgv(): string[] { + return [...process.argv]; +} + +export function readlinePrompt(prompt: string): Promise { + const stdinReadline = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + return new Promise((resolve, reject) => { + stdinReadline.question(prompt, (res) => { + resolve(res); + stdinReadline.close(); + }); + }); +} + +export function pathBasename(p: string): string { + return path.basename(p); +} + +export function pathHomedir(): string { + return os.homedir(); +} + +export function setUnhandledRejectionHandler(h: (e: any) => void): void { + process.on("unhandledRejection", (e) => { + h(e); + }); +} + +export function getenv(name: string): string | undefined { + return process.env[name]; +} diff --git a/packages/taler-util/src/compat.qtart.ts b/packages/taler-util/src/compat.qtart.ts new file mode 100644 index 000000000..f8b336b11 --- /dev/null +++ b/packages/taler-util/src/compat.qtart.ts @@ -0,0 +1,53 @@ +/* + This file is part of GNU Taler + (C) 2023 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 + */ + +// qtart "std" library +// @ts-ignore +import * as std from "std"; + +export function processExit(status: number): never { + std.exit(status); + throw Error("not reached"); +} + +export function processArgv(): string[] { + // @ts-ignore + return ["qtart", ...globalThis.scriptArgs]; +} + +export function readlinePrompt(prompt: string): Promise { + throw new Error("not supported"); +} + +export function pathBasename(p: string): string { + const slashIndex = p.lastIndexOf("/"); + if (slashIndex < 0) { + return p; + } + return p.substring(0, slashIndex); +} + +export function pathHomedir(): string { + return std.getenv("HOME"); +} + +export function setUnhandledRejectionHandler(h: (e: any) => void): void { + // not supported +} + +export function getenv(name: string): string | undefined { + return std.getenv(name); +} diff --git a/packages/taler-wallet-core/src/errors.ts b/packages/taler-util/src/errors.ts similarity index 100% rename from packages/taler-wallet-core/src/errors.ts rename to packages/taler-util/src/errors.ts diff --git a/packages/taler-util/src/http-common.ts b/packages/taler-util/src/http-common.ts new file mode 100644 index 000000000..eeb335ba7 --- /dev/null +++ b/packages/taler-util/src/http-common.ts @@ -0,0 +1,39 @@ +/* + This file is part of GNU Taler + (C) 2023 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 + + SPDX-License-Identifier: AGPL3.0-or-later +*/ + +const textEncoder = new TextEncoder(); + +export interface HttpLibArgs { + enableThrottling?: boolean, +} + +export function encodeBody(body: any): ArrayBuffer { + if (body == null) { + return new ArrayBuffer(0); + } + if (typeof body === "string") { + return textEncoder.encode(body).buffer; + } else if (ArrayBuffer.isView(body)) { + return body.buffer; + } else if (body instanceof ArrayBuffer) { + return body; + } else if (typeof body === "object") { + return textEncoder.encode(JSON.stringify(body)).buffer; + } + throw new TypeError("unsupported request body type"); +} diff --git a/packages/taler-util/src/http-impl.node.d.ts b/packages/taler-util/src/http-impl.node.d.ts new file mode 100644 index 000000000..b0fba9b30 --- /dev/null +++ b/packages/taler-util/src/http-impl.node.d.ts @@ -0,0 +1,17 @@ +import { HttpLibArgs } from "./http-common.js"; +import { HttpRequestLibrary, HttpRequestOptions, HttpResponse } from "./http.js"; +/** + * Implementation of the HTTP request library interface for node. + */ +export declare class HttpLibImpl implements HttpRequestLibrary { + private throttle; + private throttlingEnabled; + constructor(args?: HttpLibArgs); + /** + * Set whether requests should be throttled. + */ + setThrottling(enabled: boolean): void; + fetch(url: string, opt?: HttpRequestOptions): Promise; + get(url: string, opt?: HttpRequestOptions): Promise; + postJson(url: string, body: any, opt?: HttpRequestOptions): Promise; +} diff --git a/packages/taler-util/src/http-impl.node.ts b/packages/taler-util/src/http-impl.node.ts new file mode 100644 index 000000000..5f2b3ac8a --- /dev/null +++ b/packages/taler-util/src/http-impl.node.ts @@ -0,0 +1,175 @@ +/* + This file is part of GNU Taler + (C) 2019 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 + + SPDX-License-Identifier: AGPL3.0-or-later +*/ + +/** + * Imports. + */ +import * as http from "node:http"; +import { RequestOptions } from "node:http"; +import { TalerError } from "./errors.js"; +import { encodeBody, HttpLibArgs } from "./http-common.js"; +import { + DEFAULT_REQUEST_TIMEOUT_MS, + Headers, + HttpRequestLibrary, + HttpRequestOptions, + HttpResponse, +} from "./http.js"; +import { + Logger, + RequestThrottler, + TalerErrorCode, + typedArrayConcat, + URL, +} from "./index.js"; + +const logger = new Logger("http-impl.node.ts"); + +const textDecoder = new TextDecoder(); + +/** + * Implementation of the HTTP request library interface for node. + */ +export class HttpLibImpl implements HttpRequestLibrary { + private throttle = new RequestThrottler(); + private throttlingEnabled = true; + + constructor(args?: HttpLibArgs) { + this.throttlingEnabled = args?.enableThrottling ?? false; + } + + /** + * Set whether requests should be throttled. + */ + setThrottling(enabled: boolean): void { + this.throttlingEnabled = enabled; + } + + async fetch(url: string, opt?: HttpRequestOptions): Promise { + const method = opt?.method?.toUpperCase() ?? "GET"; + let body = opt?.body; + + logger.trace(`Requesting ${method} ${url}`); + + const parsedUrl = new URL(url); + if (this.throttlingEnabled && this.throttle.applyThrottle(url)) { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED, + { + requestMethod: method, + requestUrl: url, + throttleStats: this.throttle.getThrottleStats(url), + }, + `request to origin ${parsedUrl.origin} was throttled`, + ); + } + let timeoutMs: number | undefined; + if (typeof opt?.timeout?.d_ms === "number") { + timeoutMs = opt.timeout.d_ms; + } else { + timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS; + } + + const headers = { ...opt?.headers }; + headers["Content-Type"] = "application/json"; + + let reqBody: ArrayBuffer | undefined; + + if (opt?.method == "POST") { + reqBody = encodeBody(opt.body); + } + + const options: RequestOptions = { + protocol: parsedUrl.protocol, + port: parsedUrl.port, + host: parsedUrl.host, + method: method, + path: parsedUrl.pathname, + headers: opt?.headers, + }; + + const chunks: Uint8Array[] = []; + + return new Promise((resolve, reject) => { + const req = http.request(options, (res) => { + res.on("data", (d) => { + chunks.push(d); + }); + res.on("end", () => { + const headers: Headers = new Headers(); + for (const [k, v] of Object.entries(res.headers)) { + if (!v) { + continue; + } + if (typeof v === "string") { + headers.set(k, v); + } else { + headers.set(k, v.join(", ")); + } + } + const data = typedArrayConcat(chunks); + const resp: HttpResponse = { + requestMethod: method, + requestUrl: parsedUrl.href, + status: res.statusCode || 0, + headers, + async bytes() { + return data; + }, + json() { + const text = textDecoder.decode(data); + return JSON.parse(text); + }, + async text() { + const text = textDecoder.decode(data); + return text; + }, + }; + resolve(resp); + }); + res.on("error", (e) => { + reject(e); + }); + }); + + if (reqBody) { + req.write(reqBody); + } + req.end(); + }); + } + + async get(url: string, opt?: HttpRequestOptions): Promise { + return this.fetch(url, { + method: "GET", + ...opt, + }); + } + + async postJson( + url: string, + body: any, + opt?: HttpRequestOptions, + ): Promise { + return this.fetch(url, { + method: "POST", + body, + ...opt, + }); + } +} diff --git a/packages/taler-util/src/http-impl.qtart.ts b/packages/taler-util/src/http-impl.qtart.ts new file mode 100644 index 000000000..954b41802 --- /dev/null +++ b/packages/taler-util/src/http-impl.qtart.ts @@ -0,0 +1,127 @@ +/* + This file is part of GNU Taler + (C) 2019 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 + + SPDX-License-Identifier: AGPL3.0-or-later +*/ + +/** + * Imports. + */ +import { Logger } from "@gnu-taler/taler-util"; +import { TalerError } from "./errors.js"; +import { encodeBody, HttpLibArgs } from "./http-common.js"; +import { + Headers, + HttpRequestLibrary, + HttpRequestOptions, + HttpResponse, +} from "./http.js"; +import { RequestThrottler, TalerErrorCode, URL } from "./index.js"; +import { qjsOs } from "./qtart.js"; + +const logger = new Logger("http-impl.qtart.ts"); + +const textDecoder = new TextDecoder(); + +/** + * Implementation of the HTTP request library interface for node. + */ +export class HttpLibImpl implements HttpRequestLibrary { + private throttle = new RequestThrottler(); + private throttlingEnabled = true; + + constructor(args?: HttpLibArgs) { + this.throttlingEnabled = args?.enableThrottling ?? false; + } + + /** + * Set whether requests should be throttled. + */ + setThrottling(enabled: boolean): void { + this.throttlingEnabled = enabled; + } + + async fetch(url: string, opt?: HttpRequestOptions): Promise { + const method = opt?.method ?? "GET"; + + logger.trace(`Requesting ${method} ${url}`); + + const parsedUrl = new URL(url); + if (this.throttlingEnabled && this.throttle.applyThrottle(url)) { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED, + { + requestMethod: method, + requestUrl: url, + throttleStats: this.throttle.getThrottleStats(url), + }, + `request to origin ${parsedUrl.origin} was throttled`, + ); + } + + let data: ArrayBuffer | undefined = undefined; + let headers: string[] = []; + if (opt?.headers) { + for (let headerName of Object.keys(opt.headers)) { + headers.push(`${headerName}: ${opt.headers[headerName]}`); + } + } + if (method.toUpperCase() === "POST") { + data = encodeBody(opt?.body); + } + const res = await qjsOs.fetchHttp(url, { + method, + data, + headers, + }); + return { + requestMethod: method, + // FIXME: We don't return headers! + headers: new Headers(), + async bytes() { + return res.data; + }, + json() { + const text = textDecoder.decode(res.data); + return JSON.parse(text); + }, + async text() { + const text = textDecoder.decode(res.data); + return text; + }, + requestUrl: url, + status: res.status, + }; + } + + async get(url: string, opt?: HttpRequestOptions): Promise { + return this.fetch(url, { + method: "GET", + ...opt, + }); + } + + async postJson( + url: string, + body: any, + opt?: HttpRequestOptions, + ): Promise { + return this.fetch(url, { + method: "POST", + body, + ...opt, + }); + } +} diff --git a/packages/taler-wallet-core/src/util/http.ts b/packages/taler-util/src/http.ts similarity index 97% rename from packages/taler-wallet-core/src/util/http.ts rename to packages/taler-util/src/http.ts index 1da31a315..fd594b655 100644 --- a/packages/taler-wallet-core/src/util/http.ts +++ b/packages/taler-util/src/http.ts @@ -34,7 +34,9 @@ import { CancellationToken, } from "@gnu-taler/taler-util"; import { TalerErrorCode } from "@gnu-taler/taler-util"; -import { makeErrorDetail, TalerError } from "../errors.js"; +import { makeErrorDetail, TalerError } from "./errors.js"; +import * as impl from "#http-impl"; +import { HttpLibArgs } from "./http-common.js"; const logger = new Logger("http.ts"); @@ -352,3 +354,7 @@ export function getExpiry( } return t; } + +export function createPlatformHttpLib(args?: HttpLibArgs): HttpRequestLibrary { + return new impl.HttpLibImpl(args); +} diff --git a/packages/taler-util/src/index.browser.ts b/packages/taler-util/src/index.browser.ts index 3b8e194b3..2a600644d 100644 --- a/packages/taler-util/src/index.browser.ts +++ b/packages/taler-util/src/index.browser.ts @@ -19,3 +19,7 @@ import { loadBrowserPrng } from "./prng-browser.js"; loadBrowserPrng(); export * from "./index.js"; + +// The web stuff doesn't support package.json export declarations yet, +// so we export more stuff here than we should. +export * from "./http.js"; diff --git a/packages/taler-util/src/index.node.ts b/packages/taler-util/src/index.node.ts index bd59f320a..018b4767f 100644 --- a/packages/taler-util/src/index.node.ts +++ b/packages/taler-util/src/index.node.ts @@ -21,4 +21,3 @@ initNodePrng(); export * from "./index.js"; export * from "./talerconfig.js"; export * from "./globbing/minimatch.js"; -export { clk } from "./clk.js"; diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts index 661b0332f..cf4f545a4 100644 --- a/packages/taler-util/src/index.ts +++ b/packages/taler-util/src/index.ts @@ -36,3 +36,4 @@ export * from "./CancellationToken.js"; export * from "./contract-terms.js"; export * from "./base64.js"; export * from "./merchant-api-types.js"; +export * from "./errors.js"; diff --git a/packages/taler-util/src/qtart.ts b/packages/taler-util/src/qtart.ts new file mode 100644 index 000000000..f8edf234e --- /dev/null +++ b/packages/taler-util/src/qtart.ts @@ -0,0 +1,36 @@ + +// @ts-ignore +import * as _qjsOsImp from "os"; +// @ts-ignore +import * as _qjsStdImp from "std"; + + +export interface QjsHttpResp { + status: number; + data: ArrayBuffer; +} + +export interface QjsHttpOptions { + method: string; + debug?: boolean; + data?: ArrayBuffer; + headers?: string[]; +} + + +export interface QjsOsLib { + fetchHttp(url: string, options?: QjsHttpOptions): Promise; + postMessageToHost(s: string): void; + setMessageFromHostHandler(h: (s: string) => void): void; + rename(oldPath: string, newPath: string): number; +} + +export interface QjsStdLib { + writeFile(filename: string, contents: string): void; + loadFile(filename: string): string; +} + +// This is not the nodejs "os" module, but the qjs "os" module. +export const qjsOs: QjsOsLib = _qjsOsImp as any; + +export const qjsStd: QjsStdLib = _qjsStdImp as any; \ No newline at end of file diff --git a/packages/taler-util/src/twrpc-impl.missing.ts b/packages/taler-util/src/twrpc-impl.missing.ts index d9ed37815..7d7fa84ae 100644 --- a/packages/taler-util/src/twrpc-impl.missing.ts +++ b/packages/taler-util/src/twrpc-impl.missing.ts @@ -14,4 +14,13 @@ GNU Taler; see the file COPYING. If not, see */ +import type { RpcConnectArgs, RpcServerArgs } from "./twrpc.js"; + // Not implemented. +export async function connectRpc(args: RpcConnectArgs): Promise { + throw Error("not implemented"); +} + +export async function runRpcServer(args: RpcServerArgs): Promise { + throw Error("not implemented"); +} diff --git a/packages/taler-wallet-cli/build.mjs b/packages/taler-wallet-cli/build.mjs index 14b626815..b2ed2c937 100755 --- a/packages/taler-wallet-cli/build.mjs +++ b/packages/taler-wallet-cli/build.mjs @@ -53,7 +53,7 @@ function git_hash() { export const buildConfig = { entryPoints: ["src/index.ts"], - outfile: "dist/taler-wallet-cli.mjs", + outfile: "dist/taler-wallet-cli.qtart.mjs", bundle: true, minify: false, target: [ @@ -61,7 +61,11 @@ export const buildConfig = { ], format: 'esm', platform: 'neutral', + mainFields: ["module", "main"], + conditions: ["qtart"], sourcemap: true, + // quickjs standard library + external: ["std", "os"], define: { '__VERSION__': `"${_package.version}"`, '__GIT_HASH__': `"${GIT_HASH}"`, diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 228395991..aed9a24c0 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -21,12 +21,11 @@ import { addPaytoQueryParams, AgeRestriction, classifyTalerUri, - clk, codecForList, codecForString, CoreApiResponse, - decodeCrock, encodeCrock, + getErrorDetailFromException, getRandomBytes, j2s, Logger, @@ -35,20 +34,26 @@ import { RecoveryMergeStrategy, setDangerousTimetravel, setGlobalLogLevelFromString, + summarizeTalerErrorDetail, TalerUriType, WalletNotification, } from "@gnu-taler/taler-util"; +import { clk } from "@gnu-taler/taler-util/clk"; +import { + getenv, + pathHomedir, + processExit, + setUnhandledRejectionHandler, +} from "@gnu-taler/taler-util/compat"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { JsonMessage, runRpcServer } from "@gnu-taler/taler-util/twrpc"; import { + createNativeWalletHost, + createNativeWalletHost2, CryptoDispatcher, - getDefaultNodeWallet, - getDefaultNodeWallet2, - getErrorDetailFromException, nativeCrypto, - NodeHttpLib, - NodeThreadCryptoWorkerFactory, - summarizeTalerErrorDetail, - SynchronousCryptoWorkerFactoryNode, + //NodeThreadCryptoWorkerFactory, + //SynchronousCryptoWorkerFactoryPlain, TalerCryptoInterface, Wallet, WalletApiOperation, @@ -60,8 +65,6 @@ import { getClientFromRemoteWallet, makeNotificationWaiter, } from "@gnu-taler/taler-wallet-core/remote"; -import fs from "fs"; -import os from "os"; // This module also serves as the entry point for the crypto // thread worker, and thus must expose these two handlers. @@ -76,13 +79,13 @@ const EXIT_EXCEPTION = 4; const EXIT_API_ERROR = 5; const EXIT_RETRIES_EXCEEDED = 6; -process.on("unhandledRejection", (error: any) => { +setUnhandledRejectionHandler((error: any) => { logger.error("unhandledRejection", error.message); logger.error("stack", error.stack); - process.exit(2); + processExit(1); }); -const defaultWalletDbPath = os.homedir + "/" + ".talerwalletdb.json"; +const defaultWalletDbPath = pathHomedir() + "/" + ".talerwalletdb.json"; function assertUnreachable(x: never): never { throw new Error("Didn't expect to get here"); @@ -99,7 +102,7 @@ async function doPay( if (result.status === PreparePayResultType.InsufficientBalance) { console.log("contract", result.contractTerms); console.error("insufficient balance"); - process.exit(1); + processExit(1); return; } if (result.status === PreparePayResultType.AlreadyConfirmed) { @@ -108,8 +111,7 @@ async function doPay( } else { console.log("payment already in progress"); } - - process.exit(0); + processExit(0); return; } if (result.status === "payment-possible") { @@ -154,7 +156,7 @@ function applyVerbose(verbose: boolean): void { declare const __VERSION__: string; function printVersion(): void { console.log(__VERSION__); - process.exit(0); + processExit(0); } export const walletCli = clk @@ -203,7 +205,7 @@ export const walletCli = clk type WalletCliArgsType = clk.GetArgType; function checkEnvFlag(name: string): boolean { - const val = process.env[name]; + const val = getenv(name); if (val == "1") { return true; } @@ -238,11 +240,10 @@ async function createLocalWallet( notificationHandler?: (n: WalletNotification) => void, ): Promise { const dbPath = walletCliArgs.wallet.walletDbFile ?? defaultWalletDbPath; - const myHttpLib = new NodeHttpLib(); - if (walletCliArgs.wallet.noThrottle) { - myHttpLib.setThrottling(false); - } - const wallet = await getDefaultNodeWallet({ + const myHttpLib = createPlatformHttpLib({ + enableThrottling: walletCliArgs.wallet.noThrottle ? false : true, + }); + const wallet = await createNativeWalletHost({ persistentStoragePath: dbPath !== ":memory:" ? dbPath : undefined, httpLib: myHttpLib, notifyHandler: (n) => { @@ -268,7 +269,7 @@ async function createLocalWallet( const ed = getErrorDetailFromException(e); console.error("Operation failed: " + summarizeTalerErrorDetail(ed)); console.error("Error details:", JSON.stringify(ed, undefined, 2)); - process.exit(1); + processExit(1); } finally { logger.trace("operation with wallet finished, stopping"); logger.trace("stopped wallet"); @@ -357,7 +358,7 @@ walletCli requestJson = JSON.parse(args.api.request); } catch (e) { console.error("Invalid JSON"); - process.exit(1); + processExit(1); } try { const resp = await wallet.makeCoreApiRequest( @@ -367,12 +368,12 @@ walletCli console.log(JSON.stringify(resp, undefined, 2)); if (resp.type === "error") { if (args.api.expectSuccess) { - process.exit(EXIT_API_ERROR); + processExit(EXIT_API_ERROR); } } } catch (e) { logger.error(`Got exception while handling API request ${e}`); - process.exit(EXIT_EXCEPTION); + processExit(EXIT_EXCEPTION); } }); logger.info("finished handling API request"); @@ -475,7 +476,7 @@ walletCli }); wallet.ws.stop(); if (resp.retriesExceeded && args.finishPendingOpt.failOnMaxRetries) { - process.exit(EXIT_RETRIES_EXCEEDED); + processExit(EXIT_RETRIES_EXCEEDED); } }); }); @@ -594,7 +595,7 @@ walletCli const selectedExchange = withdrawInfo.defaultExchangeBaseUrl; if (!selectedExchange) { console.error("no suggested exchange!"); - process.exit(1); + processExit(1); return; } const res = await wallet.client.call( @@ -1014,9 +1015,10 @@ advancedCli help: "Run the 'bench-internal' benchmark", }) .action(async (args) => { - const myHttpLib = new NodeHttpLib(); - myHttpLib.setThrottling(false); - const res = await getDefaultNodeWallet2({ + const myHttpLib = createPlatformHttpLib({ + enableThrottling: false, + }); + const res = await createNativeWalletHost2({ // No persistent DB storage. persistentStoragePath: undefined, httpLib: myHttpLib, @@ -1060,15 +1062,6 @@ advancedCli }); }); -advancedCli - .subcommand("decode", "decode", { - help: "Decode base32-crockford.", - }) - .action((args) => { - const enc = fs.readFileSync(0, "utf8"); - console.log(decodeCrock(enc.trim())); - }); - advancedCli .subcommand("genSegwit", "gen-segwit") .requiredArgument("paytoUri", clk.STRING) @@ -1229,7 +1222,7 @@ advancedCli ); } catch (e: any) { console.log("could not parse coin list:", e.message); - process.exit(1); + processExit(1); } for (const c of coinPubList) { await wallet.client.call(WalletApiOperation.SetCoinSuspended, { @@ -1254,7 +1247,7 @@ advancedCli ); } catch (e: any) { console.log("could not parse coin list:", e.message); - process.exit(1); + processExit(1); } for (const c of coinPubList) { await wallet.client.call(WalletApiOperation.SetCoinSuspended, { @@ -1420,33 +1413,33 @@ async function read(stream: NodeJS.ReadStream) { return Buffer.concat(chunks).toString("utf8"); } -testCli - .subcommand("cryptoworker", "cryptoworker") - .maybeOption("impl", ["--impl"], clk.STRING) - .action(async (args) => { - let cryptoApi: TalerCryptoInterface; - if (!args.cryptoworker.impl || args.cryptoworker.impl === "node") { - const workerFactory = new NodeThreadCryptoWorkerFactory(); - const cryptoDisp = new CryptoDispatcher(workerFactory); - cryptoApi = cryptoDisp.cryptoApi; - } else if (args.cryptoworker.impl === "sync") { - const workerFactory = new SynchronousCryptoWorkerFactoryNode(); - const cryptoDisp = new CryptoDispatcher(workerFactory); - cryptoApi = cryptoDisp.cryptoApi; - } else if (args.cryptoworker.impl === "none") { - cryptoApi = nativeCrypto; - } else { - throw Error(`invalid crypto worker type ${args.cryptoworker.impl}`); - } +// testCli +// .subcommand("cryptoworker", "cryptoworker") +// .maybeOption("impl", ["--impl"], clk.STRING) +// .action(async (args) => { +// let cryptoApi: TalerCryptoInterface; +// if (!args.cryptoworker.impl || args.cryptoworker.impl === "node") { +// const workerFactory = new NodeThreadCryptoWorkerFactory(); +// const cryptoDisp = new CryptoDispatcher(workerFactory); +// cryptoApi = cryptoDisp.cryptoApi; +// } else if (args.cryptoworker.impl === "sync") { +// const workerFactory = new SynchronousCryptoWorkerFactoryPlain(); +// const cryptoDisp = new CryptoDispatcher(workerFactory); +// cryptoApi = cryptoDisp.cryptoApi; +// } else if (args.cryptoworker.impl === "none") { +// cryptoApi = nativeCrypto; +// } else { +// throw Error(`invalid crypto worker type ${args.cryptoworker.impl}`); +// } - const input = "foo"; - console.log(`testing crypto worker by hashing string '${input}'`); - const res = await cryptoApi.hashString({ str: input }); - console.log(res); - }); +// const input = "foo"; +// console.log(`testing crypto worker by hashing string '${input}'`); +// const res = await cryptoApi.hashString({ str: input }); +// console.log(res); +// }); export function main() { - if (process.env["TALER_WALLET_DEBUG_DENOMSEL_ALLOW_LATE"]) { + if (getenv("TALER_WALLET_DEBUG_DENOMSEL_ALLOW_LATE")) { logger.warn("Allowing withdrawal of late denominations for debugging"); walletCoreDebugFlags.denomselAllowLate = true; } diff --git a/packages/taler-wallet-core/package.json b/packages/taler-wallet-core/package.json index 4f1692872..72b4eb410 100644 --- a/packages/taler-wallet-core/package.json +++ b/packages/taler-wallet-core/package.json @@ -38,7 +38,13 @@ "default": "./lib/index.js" }, "./remote": { - "node": "./lib/remote.js" + "default": "./lib/remote.js" + } + }, + "imports": { + "#host-impl": { + "node": "./lib/host-impl.node.js", + "qtart": "./lib/host-impl.qtart.js" } }, "devDependencies": { diff --git a/packages/taler-wallet-core/src/bank-api-client.ts b/packages/taler-wallet-core/src/bank-api-client.ts index dc7845150..addec709f 100644 --- a/packages/taler-wallet-core/src/bank-api-client.ts +++ b/packages/taler-wallet-core/src/bank-api-client.ts @@ -33,13 +33,10 @@ import { j2s, Logger, stringToBytes, + TalerError, TalerErrorCode, } from "@gnu-taler/taler-util"; -import { TalerError } from "./errors.js"; -import { - HttpRequestLibrary, - readSuccessResponseJsonOrThrow, -} from "./util/http.js"; +import { HttpRequestLibrary, readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; const logger = new Logger("bank-api-client.ts"); diff --git a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts index d8d53a839..1e9d82f66 100644 --- a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts +++ b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts @@ -21,8 +21,6 @@ import { CryptoWorker, CryptoWorkerResponseMessage, } from "./cryptoWorkerInterface.js"; -import { SynchronousCryptoWorkerFactoryNode } from "./synchronousWorkerFactoryNode.js"; -import { processRequestWithImpl } from "./worker-common.js"; export class MyCryptoWorker implements CryptoWorker { /** diff --git a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts index f086691e5..192e9cda1 100644 --- a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts +++ b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts @@ -24,7 +24,7 @@ * Imports. */ import { j2s, Logger, TalerErrorCode } from "@gnu-taler/taler-util"; -import { TalerError } from "../../errors.js"; +import { TalerError } from "@gnu-taler/taler-util"; import { openPromise } from "../../util/promiseUtils.js"; import { timer, performanceNow, TimerHandle } from "../../util/timer.js"; import { nullCrypto, TalerCryptoInterface } from "../cryptoImplementation.js"; diff --git a/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts b/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts deleted file mode 100644 index 21d88fffa..000000000 --- a/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts +++ /dev/null @@ -1,92 +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 - */ - -/** - * Imports. - */ -import { Logger } from "@gnu-taler/taler-util"; -import child_process from "child_process"; -import type internal from "stream"; -import { OpenedPromise, openPromise } from "../../util/promiseUtils.js"; - -const logger = new Logger("synchronousWorkerFactory.ts"); - -/** - * Client for the crypto helper process (taler-crypto-worker from exchange.git). - */ -export class CryptoRpcClient { - proc: child_process.ChildProcessByStdio< - internal.Writable, - internal.Readable, - null - >; - requests: Array<{ - p: OpenedPromise; - req: any; - }> = []; - - constructor() { - const stdoutChunks: Buffer[] = []; - this.proc = child_process.spawn("taler-crypto-worker", { - //stdio: ["pipe", "pipe", "inherit"], - stdio: ["pipe", "pipe", "inherit"], - detached: true, - }); - this.proc.on("close", (): void => { - logger.error("child process exited"); - }); - (this.proc.stdout as any).unref(); - (this.proc.stdin as any).unref(); - this.proc.unref(); - - this.proc.stdout.on("data", (x) => { - if (x instanceof Buffer) { - const nlIndex = x.indexOf("\n"); - if (nlIndex >= 0) { - const before = x.slice(0, nlIndex); - const after = x.slice(nlIndex + 1); - stdoutChunks.push(after); - const str = Buffer.concat([...stdoutChunks, before]).toString( - "utf-8", - ); - const req = this.requests.shift(); - if (!req) { - throw Error("request was undefined"); - } - if (this.requests.length === 0) { - this.proc.unref(); - } - //logger.info(`got response: ${str}`); - req.p.resolve(JSON.parse(str)); - } else { - stdoutChunks.push(x); - } - } else { - throw Error(`unexpected data chunk type (${typeof x})`); - } - }); - } - - async queueRequest(req: any): Promise { - const p = openPromise(); - if (this.requests.length === 0) { - this.proc.ref(); - } - this.requests.push({ req, p }); - this.proc.stdin.write(`${JSON.stringify(req)}\n`); - return p.promise; - } -} diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts deleted file mode 100644 index b2653158c..000000000 --- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts +++ /dev/null @@ -1,174 +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 - */ - -import { j2s, Logger } from "@gnu-taler/taler-util"; -import { - nativeCryptoR, - TalerCryptoInterfaceR, -} from "../cryptoImplementation.js"; -import { CryptoWorker } from "./cryptoWorkerInterface.js"; -import { CryptoRpcClient } from "./rpcClient.js"; -import { processRequestWithImpl } from "./worker-common.js"; - -const logger = new Logger("synchronousWorker.ts"); - -/** - * Worker implementation that uses node subprocesses. - * - * The node crypto worker can also use IPC to offload cryptographic - * operations to a helper process (usually written in C / part of taler-exchange). - */ -export class SynchronousCryptoWorkerNode implements CryptoWorker { - /** - * Function to be called when we receive a message from the worker thread. - */ - onmessage: undefined | ((m: any) => void); - - /** - * Function to be called when we receive an error from the worker thread. - */ - onerror: undefined | ((m: any) => void); - - cryptoImplR: TalerCryptoInterfaceR; - - rpcClient: CryptoRpcClient | undefined; - - constructor() { - this.onerror = undefined; - this.onmessage = undefined; - - this.cryptoImplR = { ...nativeCryptoR }; - - if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) { - logger.info("using RPC for some crypto operations"); - const rpc = (this.rpcClient = new CryptoRpcClient()); - this.cryptoImplR.eddsaSign = async (_, req) => { - return await rpc.queueRequest({ - op: "eddsa_sign", - args: { - msg: req.msg, - priv: req.priv, - }, - }); - }; - this.cryptoImplR.setupRefreshPlanchet = async (_, req) => { - const res = await rpc.queueRequest({ - op: "setup_refresh_planchet", - args: { - coin_index: req.coinNumber, - transfer_secret: req.transferSecret, - }, - }); - return { - bks: res.blinding_key, - coinPriv: res.coin_priv, - coinPub: res.coin_pub, - }; - }; - this.cryptoImplR.rsaBlind = async (_, req) => { - const res = await rpc.queueRequest({ - op: "rsa_blind", - args: { - bks: req.bks, - hm: req.hm, - pub: req.pub, - }, - }); - return { - blinded: res.blinded, - }; - }; - this.cryptoImplR.keyExchangeEcdheEddsa = async (_, req) => { - const res = await rpc.queueRequest({ - op: "kx_ecdhe_eddsa", - args: { - ecdhe_priv: req.ecdhePriv, - eddsa_pub: req.eddsaPub, - }, - }); - return { - h: res.h, - }; - }; - this.cryptoImplR.eddsaGetPublic = async (_, req) => { - const res = await rpc.queueRequest({ - op: "eddsa_get_public", - args: { - eddsa_priv: req.priv, - }, - }); - return { - pub: res.eddsa_pub, - }; - }; - this.cryptoImplR.ecdheGetPublic = async (_, req) => { - const res = await rpc.queueRequest({ - op: "ecdhe_get_public", - args: { - ecdhe_priv: req.priv, - }, - }); - return { - pub: res.ecdhe_pub, - }; - }; - } - } - - /** - * Add an event listener for either an "error" or "message" event. - */ - addEventListener(event: "message" | "error", fn: (x: any) => void): void { - switch (event) { - case "message": - this.onmessage = fn; - break; - case "error": - this.onerror = fn; - break; - } - } - - private dispatchMessage(msg: any): void { - if (this.onmessage) { - this.onmessage(msg); - } - } - - /** - * Send a message to the worker thread. - */ - postMessage(msg: any): void { - const handleRequest = async () => { - const responseMsg = await processRequestWithImpl(msg, this.cryptoImplR); - try { - setTimeout(() => this.dispatchMessage(responseMsg), 0); - } catch (e) { - logger.error("got error during dispatch", e); - } - }; - handleRequest().catch((e) => { - logger.error("Error while handling crypto request:", e); - }); - } - - /** - * Forcibly terminate the worker thread. - */ - terminate(): void { - // This is a no-op. - } -} diff --git a/packages/taler-wallet-core/src/crypto/workers/worker-common.ts b/packages/taler-wallet-core/src/crypto/workers/worker-common.ts index 8a74a5231..9f23cf685 100644 --- a/packages/taler-wallet-core/src/crypto/workers/worker-common.ts +++ b/packages/taler-wallet-core/src/crypto/workers/worker-common.ts @@ -23,7 +23,7 @@ import { stringifyError as safeStringifyError, TalerErrorCode, } from "@gnu-taler/taler-util"; -import { getErrorDetailFromException, makeErrorDetail } from "../../errors.js"; +import { getErrorDetailFromException, makeErrorDetail } from "@gnu-taler/taler-util"; import { TalerCryptoInterfaceR } from "../cryptoImplementation.js"; import { CryptoWorkerRequestMessage, diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 8bb8d519f..75e6408f7 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -2659,6 +2659,9 @@ function onMetaDbUpgradeNeeded( /** * Return a promise that resolves * to the taler wallet db. + * + * @param onVersionChange Called when another client concurrenctly connects to the database + * with a higher version. */ export async function openTalerDatabase( idbFactory: IDBFactory, diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index 544e2d458..99596edd8 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -58,7 +58,7 @@ import { import { HttpRequestLibrary, readSuccessResponseJsonOrThrow, -} from "./util/http.js"; +} from "@gnu-taler/taler-util/http"; import { getBankStatusUrl, getBankWithdrawalInfo, diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts index 6c36d6f6c..3e6194ccd 100644 --- a/packages/taler-wallet-core/src/dev-experiments.ts +++ b/packages/taler-wallet-core/src/dev-experiments.ts @@ -32,7 +32,7 @@ import { HttpRequestLibrary, HttpRequestOptions, HttpResponse, -} from "./util/http.js"; +} from "@gnu-taler/taler-util/http"; const logger = new Logger("dev-experiments.ts"); diff --git a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts b/packages/taler-wallet-core/src/headless/NodeHttpLib.ts deleted file mode 100644 index c1d42796d..000000000 --- a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts +++ /dev/null @@ -1,183 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2019 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 - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * Imports. - */ -import { - DEFAULT_REQUEST_TIMEOUT_MS, - Headers, - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, -} from "../util/http.js"; -import { RequestThrottler } from "@gnu-taler/taler-util"; -import axios, { AxiosResponse } from "axios"; -import { TalerError } from "../errors.js"; -import { Logger, bytesToString } from "@gnu-taler/taler-util"; -import { TalerErrorCode, URL } from "@gnu-taler/taler-util"; - -const logger = new Logger("NodeHttpLib.ts"); - -/** - * Implementation of the HTTP request library interface for node. - */ -export class NodeHttpLib implements HttpRequestLibrary { - private throttle = new RequestThrottler(); - private throttlingEnabled = true; - - /** - * Set whether requests should be throttled. - */ - setThrottling(enabled: boolean): void { - this.throttlingEnabled = enabled; - } - - async fetch(url: string, opt?: HttpRequestOptions): Promise { - const method = opt?.method ?? "GET"; - let body = opt?.body; - - logger.trace(`Requesting ${method} ${url}`); - - const parsedUrl = new URL(url); - if (this.throttlingEnabled && this.throttle.applyThrottle(url)) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED, - { - requestMethod: method, - requestUrl: url, - throttleStats: this.throttle.getThrottleStats(url), - }, - `request to origin ${parsedUrl.origin} was throttled`, - ); - } - let timeoutMs: number | undefined; - if (typeof opt?.timeout?.d_ms === "number") { - timeoutMs = opt.timeout.d_ms; - } else { - timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS; - } - // FIXME: Use AbortController / etc. to handle cancellation - let resp: AxiosResponse; - try { - let respPromise = axios.default({ - method, - url: url, - responseType: "arraybuffer", - headers: opt?.headers, - validateStatus: () => true, - transformResponse: (x) => x, - data: body, - timeout: timeoutMs, - maxRedirects: 0, - }); - if (opt?.cancellationToken) { - respPromise = opt.cancellationToken.racePromise(respPromise); - } - resp = await respPromise; - } catch (e: any) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_NETWORK_ERROR, - { - requestUrl: url, - requestMethod: method, - }, - `${e.message}`, - ); - } - - const makeText = async (): Promise => { - opt?.cancellationToken?.throwIfCancelled(); - const respText = new Uint8Array(resp.data); - return bytesToString(respText); - }; - - const makeJson = async (): Promise => { - opt?.cancellationToken?.throwIfCancelled(); - let responseJson; - const respText = await makeText(); - try { - responseJson = JSON.parse(respText); - } catch (e) { - logger.trace(`invalid json: '${resp.data}'`); - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - httpStatusCode: resp.status, - requestUrl: url, - requestMethod: method, - }, - "Could not parse response body as JSON", - ); - } - if (responseJson === null || typeof responseJson !== "object") { - logger.trace(`invalid json (not an object): '${respText}'`); - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - httpStatusCode: resp.status, - requestUrl: url, - requestMethod: method, - }, - `invalid JSON`, - ); - } - return responseJson; - }; - const makeBytes = async () => { - opt?.cancellationToken?.throwIfCancelled(); - if (typeof resp.data.byteLength !== "number") { - throw Error("expected array buffer"); - } - const buf = resp.data; - return buf; - }; - const headers = new Headers(); - for (const hn of Object.keys(resp.headers)) { - headers.set(hn, resp.headers[hn]); - } - return { - requestUrl: url, - requestMethod: method, - headers, - status: resp.status, - text: makeText, - json: makeJson, - bytes: makeBytes, - }; - } - - async get(url: string, opt?: HttpRequestOptions): Promise { - return this.fetch(url, { - method: "GET", - ...opt, - }); - } - - async postJson( - url: string, - body: any, - opt?: HttpRequestOptions, - ): Promise { - return this.fetch(url, { - method: "POST", - body, - ...opt, - }); - } -} diff --git a/packages/taler-wallet-core/src/host-common.ts b/packages/taler-wallet-core/src/host-common.ts new file mode 100644 index 000000000..7651e5a12 --- /dev/null +++ b/packages/taler-wallet-core/src/host-common.ts @@ -0,0 +1,60 @@ +/* + This file is part of GNU Taler + (C) 2019 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 + */ + +import { WalletNotification } from "@gnu-taler/taler-util"; +import { HttpRequestLibrary } from "@gnu-taler/taler-util/http"; + +/** + * Helpers to initiate a wallet in a host environment. + */ + +/** + */ +export interface DefaultNodeWalletArgs { + /** + * Location of the wallet database. + * + * If not specified, the wallet starts out with an empty database and + * the wallet database is stored only in memory. + */ + persistentStoragePath?: string; + + /** + * Handler for asynchronous notifications from the wallet. + */ + notifyHandler?: (n: WalletNotification) => void; + + /** + * If specified, use this as HTTP request library instead + * of the default one. + */ + httpLib?: HttpRequestLibrary; + + cryptoWorkerType?: "sync" | "node-worker-thread"; +} + +/** + * Generate a random alphanumeric ID. Does *not* use cryptographically + * secure randomness. + */ +export function makeTempfileId(length: number): string { + let result = ""; + const characters = "abcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)); + } + return result; +} diff --git a/packages/taler-wallet-core/src/headless/helpers.ts b/packages/taler-wallet-core/src/host-impl.node.ts similarity index 67% rename from packages/taler-wallet-core/src/headless/helpers.ts rename to packages/taler-wallet-core/src/host-impl.node.ts index fbeb84c67..ec57e0ebe 100644 --- a/packages/taler-wallet-core/src/headless/helpers.ts +++ b/packages/taler-wallet-core/src/host-impl.node.ts @@ -30,70 +30,27 @@ import { shimIndexedDB, } from "@gnu-taler/idb-bridge"; import { AccessStats } from "@gnu-taler/idb-bridge"; -import { Logger, WalletNotification } from "@gnu-taler/taler-util"; +import { Logger } from "@gnu-taler/taler-util"; import * as fs from "fs"; -import { NodeThreadCryptoWorkerFactory } from "../crypto/workers/nodeThreadWorker.js"; -import { SynchronousCryptoWorkerFactoryNode } from "../crypto/workers/synchronousWorkerFactoryNode.js"; -import { openTalerDatabase } from "../index.js"; -import { HttpRequestLibrary } from "../util/http.js"; -import { SetTimeoutTimerAPI } from "../util/timer.js"; -import { Wallet } from "../wallet.js"; -import { NodeHttpLib } from "./NodeHttpLib.js"; +import { NodeThreadCryptoWorkerFactory } from "./crypto/workers/nodeThreadWorker.js"; +import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js"; +import { openTalerDatabase } from "./index.js"; +import { + createPlatformHttpLib, +} from "@gnu-taler/taler-util/http"; +import { SetTimeoutTimerAPI } from "./util/timer.js"; +import { Wallet } from "./wallet.js"; +import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js"; -const logger = new Logger("headless/helpers.ts"); +const logger = new Logger("host-impl.node.ts"); -export interface DefaultNodeWalletArgs { - /** - * Location of the wallet database. - * - * If not specified, the wallet starts out with an empty database and - * the wallet database is stored only in memory. - */ - persistentStoragePath?: string; - - /** - * Handler for asynchronous notifications from the wallet. - */ - notifyHandler?: (n: WalletNotification) => void; - - /** - * If specified, use this as HTTP request library instead - * of the default one. - */ - httpLib?: HttpRequestLibrary; - - cryptoWorkerType?: "sync" | "node-worker-thread"; -} - -/** - * Generate a random alphanumeric ID. Does *not* use cryptographically - * secure randomness. - */ -function makeId(length: number): string { - let result = ""; - const characters = "abcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * characters.length)); - } - return result; -} - -/** - * Get a wallet instance with default settings for node. - */ -export async function getDefaultNodeWallet( - args: DefaultNodeWalletArgs = {}, -): Promise { - const res = await getDefaultNodeWallet2(args); - return res.wallet; -} /** * Get a wallet instance with default settings for node. * * Extended version that allows getting DB stats. */ -export async function getDefaultNodeWallet2( +export async function createNativeWalletHost2( args: DefaultNodeWalletArgs = {}, ): Promise<{ wallet: Wallet; @@ -127,7 +84,8 @@ export async function getDefaultNodeWallet2( if (args.persistentStoragePath === undefined) { return; } - const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`; + const tmpPath = `${args.persistentStoragePath}-${makeTempfileId(5)}.tmp`; + logger.trace("exported DB dump"); const dbContent = myBackend.exportDump(); fs.writeFileSync(tmpPath, JSON.stringify(dbContent, undefined, 2), { encoding: "utf-8", @@ -147,7 +105,9 @@ export async function getDefaultNodeWallet2( if (args.httpLib) { myHttpLib = args.httpLib; } else { - myHttpLib = new NodeHttpLib(); + myHttpLib = createPlatformHttpLib({ + enableThrottling: true, + }); } const myVersionChange = (): Promise => { @@ -165,7 +125,7 @@ export async function getDefaultNodeWallet2( const cryptoWorkerType = args.cryptoWorkerType ?? "node-worker-thread"; if (cryptoWorkerType === "sync") { logger.info("using synchronous crypto worker"); - workerFactory = new SynchronousCryptoWorkerFactoryNode(); + workerFactory = new SynchronousCryptoWorkerFactoryPlain(); } else if (cryptoWorkerType === "node-worker-thread") { try { // Try if we have worker threads available, fails in older node versions. @@ -179,7 +139,7 @@ export async function getDefaultNodeWallet2( logger.warn( "worker threads not available, falling back to synchronous workers", ); - workerFactory = new SynchronousCryptoWorkerFactoryNode(); + workerFactory = new SynchronousCryptoWorkerFactoryPlain(); } } else { throw Error(`unsupported crypto worker type '${cryptoWorkerType}'`); diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts new file mode 100644 index 000000000..337914292 --- /dev/null +++ b/packages/taler-wallet-core/src/host-impl.qtart.ts @@ -0,0 +1,120 @@ +/* + This file is part of GNU Taler + (C) 2019 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 + */ + +/** + * Helpers to create headless wallets. + * @author Florian Dold + */ + +/** + * Imports. + */ +import type { IDBFactory } from "@gnu-taler/idb-bridge"; +// eslint-disable-next-line no-duplicate-imports +import { + BridgeIDBFactory, + MemoryBackend, + shimIndexedDB, +} from "@gnu-taler/idb-bridge"; +import { AccessStats } from "@gnu-taler/idb-bridge"; +import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js"; +import { openTalerDatabase } from "./index.js"; +import { Logger } from "@gnu-taler/taler-util"; +import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; +import { SetTimeoutTimerAPI } from "./util/timer.js"; +import { Wallet } from "./wallet.js"; +import { qjsOs, qjsStd } from "@gnu-taler/taler-util/qtart"; +import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js"; + +const logger = new Logger("host-impl.qtart.ts"); + +export async function createNativeWalletHost2( + args: DefaultNodeWalletArgs = {}, +): Promise<{ + wallet: Wallet; + getDbStats: () => AccessStats; +}> { + BridgeIDBFactory.enableTracing = false; + const myBackend = new MemoryBackend(); + myBackend.enableTracing = false; + + const storagePath = args.persistentStoragePath; + if (storagePath) { + const dbContentStr = qjsStd.loadFile(storagePath); + if (dbContentStr != null) { + const dbContent = JSON.parse(dbContentStr); + myBackend.importDump(dbContent); + } + + myBackend.afterCommitCallback = async () => { + logger.trace("committing database"); + // Allow caller to stop persisting the wallet. + if (args.persistentStoragePath === undefined) { + return; + } + const tmpPath = `${args.persistentStoragePath}-${makeTempfileId(5)}.tmp`; + const dbContent = myBackend.exportDump(); + logger.trace("exported DB dump"); + qjsStd.writeFile(tmpPath, JSON.stringify(dbContent, undefined, 2)); + // Atomically move the temporary file onto the DB path. + const res = qjsOs.rename(tmpPath, args.persistentStoragePath); + if (res != 0) { + throw Error("db commit failed at rename"); + } + logger.trace("committing database done"); + }; + } + + logger.info("done processing storage path"); + + BridgeIDBFactory.enableTracing = false; + + const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); + const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory; + + let myHttpLib; + if (args.httpLib) { + myHttpLib = args.httpLib; + } else { + myHttpLib = createPlatformHttpLib(); + } + + const myVersionChange = (): Promise => { + logger.error("version change requested, should not happen"); + throw Error( + "BUG: wallet DB version change event can't happen with memory IDB", + ); + }; + + shimIndexedDB(myBridgeIdbFactory); + + const myDb = await openTalerDatabase(myIdbFactory, myVersionChange); + + let workerFactory; + workerFactory = new SynchronousCryptoWorkerFactoryPlain(); + + const timer = new SetTimeoutTimerAPI(); + + const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory); + + if (args.notifyHandler) { + w.addNotificationListener(args.notifyHandler); + } + return { + wallet: w, + getDbStats: () => myBackend.accessStats, + }; +} diff --git a/packages/taler-wallet-core/src/host.ts b/packages/taler-wallet-core/src/host.ts new file mode 100644 index 000000000..4b319f081 --- /dev/null +++ b/packages/taler-wallet-core/src/host.ts @@ -0,0 +1,47 @@ +/* + This file is part of GNU Taler + (C) 2019 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 + */ + +import { DefaultNodeWalletArgs } from "./host-common.js"; +import { Wallet } from "./index.js"; + +import * as hostImpl from "#host-impl"; +import { AccessStats } from "@gnu-taler/idb-bridge"; + +/** + * Helpers to initiate a wallet in a host environment. + */ + +/** + * Get a wallet instance. + */ +export async function createNativeWalletHost2( + args: DefaultNodeWalletArgs = {}, +): Promise<{ + wallet: Wallet; + getDbStats: () => AccessStats; +}> { + return hostImpl.createNativeWalletHost2(args); +} + +/** + * Get a wallet instance. + */ +export async function createNativeWalletHost( + args: DefaultNodeWalletArgs = {}, +): Promise { + const res = await hostImpl.createNativeWalletHost2(args); + return res.wallet; +} diff --git a/packages/taler-wallet-core/src/index.node.ts b/packages/taler-wallet-core/src/index.node.ts index 8567d13ac..13392d39c 100644 --- a/packages/taler-wallet-core/src/index.node.ts +++ b/packages/taler-wallet-core/src/index.node.ts @@ -16,15 +16,8 @@ export * from "./index.js"; -// Utils for using the wallet under node -export { NodeHttpLib } from "./headless/NodeHttpLib.js"; -export { - getDefaultNodeWallet, - getDefaultNodeWallet2, - DefaultNodeWalletArgs, -} from "./headless/helpers.js"; export * from "./crypto/workers/nodeThreadWorker.js"; -export { SynchronousCryptoWorkerNode as SynchronousCryptoWorker } from "./crypto/workers/synchronousWorkerNode.js"; +export { SynchronousCryptoWorkerPlain } from "./crypto/workers/synchronousWorkerPlain.js"; export type { AccessStats } from "@gnu-taler/idb-bridge"; -export * from "./crypto/workers/synchronousWorkerFactoryNode.js"; +export * from "./crypto/workers/synchronousWorkerFactoryPlain.js"; diff --git a/packages/taler-wallet-core/src/index.ts b/packages/taler-wallet-core/src/index.ts index 031656a6c..7b21d8f91 100644 --- a/packages/taler-wallet-core/src/index.ts +++ b/packages/taler-wallet-core/src/index.ts @@ -18,13 +18,9 @@ * Module entry point for the wallet when used as a node module. */ -// Errors -export * from "./errors.js"; - // Util functionality export * from "./util/promiseUtils.js"; export * from "./util/query.js"; -export * from "./util/http.js"; export * from "./versions.js"; @@ -67,3 +63,5 @@ export * from "./util/timer.js"; export * from "./util/denominations.js"; export { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js"; +export * from "./host-common.js"; +export * from "./host.js"; diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts b/packages/taler-wallet-core/src/internal-wallet-state.ts index d180861f8..8434c3b8f 100644 --- a/packages/taler-wallet-core/src/internal-wallet-state.ts +++ b/packages/taler-wallet-core/src/internal-wallet-state.ts @@ -30,18 +30,14 @@ * Imports. */ import { - WalletNotification, - BalancesResponse, - AmountJson, - DenominationPubKey, - TalerProtocolTimestamp, CancellationToken, + CoinRefreshRequest, DenominationInfo, RefreshGroupId, - CoinRefreshRequest, RefreshReason, + WalletNotification, } from "@gnu-taler/taler-util"; -import { CryptoDispatcher } from "./crypto/workers/crypto-dispatcher.js"; +import { HttpRequestLibrary } from "@gnu-taler/taler-util/http"; import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js"; import { ExchangeDetailsRecord, @@ -49,9 +45,6 @@ import { RefreshReasonDetails, WalletStoresV1, } from "./db.js"; -import { PendingOperationsResponse } from "./pending-types.js"; -import { AsyncOpMemoMap, AsyncOpMemoSingle } from "./util/asyncMemo.js"; -import { HttpRequestLibrary } from "./util/http.js"; import { AsyncCondition } from "./util/promiseUtils.js"; import { DbAccess, diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts b/packages/taler-wallet-core/src/operations/backup/index.ts index 7d3953ebb..3dae26087 100644 --- a/packages/taler-wallet-core/src/operations/backup/index.ts +++ b/packages/taler-wallet-core/src/operations/backup/index.ts @@ -85,13 +85,13 @@ import { ConfigRecordKey, WalletBackupConfState, } from "../../db.js"; -import { TalerError } from "../../errors.js"; +import { TalerError } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../../internal-wallet-state.js"; import { assertUnreachable } from "../../util/assertUnreachable.js"; import { readSuccessResponseJsonOrThrow, readTalerErrorResponse, -} from "../../util/http.js"; +} from "@gnu-taler/taler-util/http"; import { checkDbInvariant, checkLogicInvariant, diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts index 3ea02012b..e61a6fe95 100644 --- a/packages/taler-wallet-core/src/operations/common.ts +++ b/packages/taler-wallet-core/src/operations/common.ts @@ -42,7 +42,7 @@ import { ExchangeDetailsRecord, ExchangeRecord, } from "../db.js"; -import { makeErrorDetail, TalerError } from "../errors.js"; +import { makeErrorDetail, TalerError } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { GetReadWriteAccess } from "../util/query.js"; diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index 4ff6a65cd..9d71f020f 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -62,10 +62,10 @@ import { OperationStatus, TransactionStatus, } from "../db.js"; -import { TalerError } from "../errors.js"; -import { checkWithdrawalKycStatus, KycPendingInfo, KycUserType } from "../index.js"; +import { TalerError } from "@gnu-taler/taler-util"; +import { KycPendingInfo, KycUserType } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; -import { readSuccessResponseJsonOrThrow } from "../util/http.js"; +import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; import { OperationAttemptResult } from "../util/retries.js"; import { makeTransactionId, spendCoins } from "./common.js"; import { getExchangeDetails } from "./exchanges.js"; diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 67f77de77..2b6a881dd 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -41,6 +41,7 @@ import { NotificationType, parsePaytoUri, Recoup, + TalerError, TalerErrorCode, TalerProtocolDuration, TalerProtocolTimestamp, @@ -49,6 +50,7 @@ import { WireFeeMap, WireInfo, } from "@gnu-taler/taler-util"; +import { HttpRequestLibrary, readSuccessResponseTextOrThrow, readSuccessResponseJsonOrThrow, getExpiry } from "@gnu-taler/taler-util/http"; import { DenominationRecord, DenominationVerificationStatus, @@ -56,14 +58,7 @@ import { ExchangeRecord, WalletStoresV1, } from "../db.js"; -import { TalerError } from "../errors.js"; import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js"; -import { - getExpiry, - HttpRequestLibrary, - readSuccessResponseJsonOrThrow, - readSuccessResponseTextOrThrow, -} from "../util/http.js"; import { checkDbInvariant } from "../util/invariants.js"; import { DbAccess, diff --git a/packages/taler-wallet-core/src/operations/merchants.ts b/packages/taler-wallet-core/src/operations/merchants.ts index eeefc0f79..c47ec4a0a 100644 --- a/packages/taler-wallet-core/src/operations/merchants.ts +++ b/packages/taler-wallet-core/src/operations/merchants.ts @@ -25,7 +25,7 @@ import { LibtoolVersion, } from "@gnu-taler/taler-util"; import { InternalWalletState, MerchantInfo } from "../internal-wallet-state.js"; -import { readSuccessResponseJsonOrThrow } from "../util/http.js"; +import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; const logger = new Logger("taler-wallet-core:merchants.ts"); diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts index 2a89c59ed..f84ac2567 100644 --- a/packages/taler-wallet-core/src/operations/pay-merchant.ts +++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -94,13 +94,12 @@ import { makePendingOperationFailedError, TalerError, TalerProtocolViolationError, -} from "../errors.js"; -import { GetReadWriteAccess } from "../index.browser.js"; +} from "@gnu-taler/taler-util"; +import { GetReadWriteAccess } from "../index.js"; import { EXCHANGE_COINS_LOCK, InternalWalletState, } from "../internal-wallet-state.js"; -import { PendingTaskType } from "../pending-types.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; import { CoinSelectionTally, @@ -114,7 +113,7 @@ import { readTalerErrorResponse, readUnexpectedResponseDetails, throwUnexpectedRequestError, -} from "../util/http.js"; +} from "@gnu-taler/taler-util/http"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { OperationAttemptResult, diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts index 7dc7b67fe..022a824de 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer.ts @@ -81,16 +81,15 @@ import { WithdrawalGroupStatus, WithdrawalRecordType, } from "../db.js"; -import { TalerError } from "../errors.js"; +import { TalerError } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; import { makeTransactionId, runOperationWithErrorReporting, spendCoins, } from "../operations/common.js"; -import { readSuccessResponseJsonOrThrow } from "../util/http.js"; +import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; import { checkDbInvariant } from "../util/invariants.js"; -import { GetReadOnlyAccess } from "../util/query.js"; import { OperationAttemptResult, OperationAttemptResultType, diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts index 00dd0e1c6..3b423474b 100644 --- a/packages/taler-wallet-core/src/operations/recoup.ts +++ b/packages/taler-wallet-core/src/operations/recoup.ts @@ -49,7 +49,7 @@ import { WithdrawCoinSource, } from "../db.js"; import { InternalWalletState } from "../internal-wallet-state.js"; -import { readSuccessResponseJsonOrThrow } from "../util/http.js"; +import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; import { checkDbInvariant } from "../util/invariants.js"; import { GetReadWriteAccess } from "../util/query.js"; import { diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index 5b7bf8d83..773689635 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -63,7 +63,7 @@ import { RefreshReasonDetails, WalletStoresV1, } from "../db.js"; -import { TalerError } from "../errors.js"; +import { TalerError } from "@gnu-taler/taler-util"; import { EXCHANGE_COINS_LOCK, InternalWalletState, @@ -72,7 +72,7 @@ import { assertUnreachable } from "../util/assertUnreachable.js"; import { readSuccessResponseJsonOrThrow, readUnexpectedResponseDetails, -} from "../util/http.js"; +} from "@gnu-taler/taler-util/http"; import { checkDbInvariant } from "../util/invariants.js"; import { GetReadWriteAccess } from "../util/query.js"; import { diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index 50454a920..873fac021 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -29,7 +29,7 @@ import { HttpRequestLibrary, readSuccessResponseJsonOrThrow, checkSuccessResponseOrThrow, -} from "../util/http.js"; +} from "@gnu-taler/taler-util/http"; import { AmountString, codecForAny, diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts index 2bf216102..ec7546992 100644 --- a/packages/taler-wallet-core/src/operations/tip.ts +++ b/packages/taler-wallet-core/src/operations/tip.ts @@ -45,12 +45,12 @@ import { DenominationRecord, TipRecord, } from "../db.js"; -import { makeErrorDetail } from "../errors.js"; +import { makeErrorDetail } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; import { getHttpResponseErrorDetails, readSuccessResponseJsonOrThrow, -} from "../util/http.js"; +} from "@gnu-taler/taler-util/http"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { OperationAttemptResult, diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index bcc8600c7..f6d79b229 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -85,7 +85,7 @@ import { getErrorDetailFromException, makeErrorDetail, TalerError, -} from "../errors.js"; +} from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; import { makeCoinAvailable, @@ -99,7 +99,7 @@ import { readSuccessResponseJsonOrErrorCode, readSuccessResponseJsonOrThrow, throwUnexpectedRequestError, -} from "../util/http.js"; +} from "@gnu-taler/taler-util/http"; import { checkDbInvariant, checkLogicInvariant, diff --git a/packages/taler-wallet-core/src/remote.ts b/packages/taler-wallet-core/src/remote.ts index bc0be9d30..89348698e 100644 --- a/packages/taler-wallet-core/src/remote.ts +++ b/packages/taler-wallet-core/src/remote.ts @@ -19,10 +19,10 @@ import { CoreApiResponse, j2s, Logger, + TalerError, WalletNotification, } from "@gnu-taler/taler-util"; import { connectRpc, JsonMessage } from "@gnu-taler/taler-util/twrpc"; -import { TalerError } from "./errors.js"; import { OpenedPromise, openPromise } from "./index.js"; import { WalletCoreApiClient } from "./wallet-api-types.js"; diff --git a/packages/taler-wallet-core/src/util/retries.ts b/packages/taler-wallet-core/src/util/retries.ts index fcb63ecd1..742381f7b 100644 --- a/packages/taler-wallet-core/src/util/retries.ts +++ b/packages/taler-wallet-core/src/util/retries.ts @@ -40,7 +40,7 @@ import { WalletStoresV1, WithdrawalGroupRecord, } from "../db.js"; -import { TalerError } from "../errors.js"; +import { TalerError } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; import { PendingTaskType } from "../pending-types.js"; import { GetReadWriteAccess } from "./query.js"; diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index a57c71bcf..0d02b667b 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -129,7 +129,7 @@ import { maybeInitDevMode, setDevMode, } from "./dev-experiments.js"; -import { getErrorDetailFromException, TalerError } from "./errors.js"; +import { getErrorDetailFromException, TalerError } from "@gnu-taler/taler-util"; import { ActiveLongpollInfo, ExchangeOperations, @@ -247,7 +247,7 @@ import { import { HttpRequestLibrary, readSuccessResponseJsonOrThrow, -} from "./util/http.js"; +} from "@gnu-taler/taler-util/http"; import { checkDbInvariant } from "./util/invariants.js"; import { AsyncCondition, diff --git a/packages/taler-wallet-embedded/build.mjs b/packages/taler-wallet-embedded/build.mjs index 537a4fbc0..28351e6e5 100755 --- a/packages/taler-wallet-embedded/build.mjs +++ b/packages/taler-wallet-embedded/build.mjs @@ -55,6 +55,7 @@ export const buildConfig = { format: 'esm', platform: 'neutral', mainFields: ["module", "main"], + conditions: ["qtart"], sourcemap: true, define: { '__VERSION__': `"${_package.version}"`, diff --git a/packages/taler-wallet-embedded/src/index.ts b/packages/taler-wallet-embedded/src/index.ts index b505a2d9d..e0a13390d 100644 --- a/packages/taler-wallet-embedded/src/index.ts +++ b/packages/taler-wallet-embedded/src/index.ts @@ -18,27 +18,25 @@ * Imports. */ import { + createNativeWalletHost, DefaultNodeWalletArgs, - getDefaultNodeWallet, - getErrorDetailFromException, handleWorkerError, handleWorkerMessage, - Headers, - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, - NodeHttpLib, OpenedPromise, openPromise, Wallet, - WALLET_EXCHANGE_PROTOCOL_VERSION, - WALLET_MERCHANT_PROTOCOL_VERSION, } from "@gnu-taler/taler-wallet-core"; import { CoreApiMessageEnvelope, CoreApiResponse, CoreApiResponseSuccess, + createPlatformHttpLib, + getErrorDetailFromException, + Headers, + HttpRequestLibrary, + HttpRequestOptions, + HttpResponse, Logger, WalletNotification, } from "@gnu-taler/taler-util"; @@ -51,7 +49,7 @@ const logger = new Logger("taler-wallet-embedded/index.ts"); export class NativeHttpLib implements HttpRequestLibrary { useNfcTunnel = false; - private nodeHttpLib: HttpRequestLibrary = new NodeHttpLib(); + private httpLib: HttpRequestLibrary = createPlatformHttpLib(); private requestId = 1; @@ -62,7 +60,7 @@ export class NativeHttpLib implements HttpRequestLibrary { constructor(private sendMessage: (m: string) => void) {} fetch(url: string, opt?: HttpRequestOptions): Promise { - return this.nodeHttpLib.fetch(url, opt); + return this.httpLib.fetch(url, opt); } get(url: string, opt?: HttpRequestOptions): Promise { @@ -83,7 +81,7 @@ export class NativeHttpLib implements HttpRequestLibrary { ); return p.promise; } else { - return this.nodeHttpLib.get(url, opt); + return this.httpLib.get(url, opt); } } @@ -106,7 +104,7 @@ export class NativeHttpLib implements HttpRequestLibrary { ); return p.promise; } else { - return this.nodeHttpLib.postJson(url, body, opt); + return this.httpLib.postJson(url, body, opt); } } @@ -158,7 +156,7 @@ class NativeWalletMessageHandler { walletArgs: DefaultNodeWalletArgs | undefined; maybeWallet: Wallet | undefined; wp = openPromise(); - httpLib = new NodeHttpLib(); + httpLib = createPlatformHttpLib(); /** * Handle a request from the native wallet. @@ -181,7 +179,7 @@ class NativeWalletMessageHandler { const reinit = async () => { logger.info("in reinit"); - const w = await getDefaultNodeWallet(this.walletArgs); + const w = await createNativeWalletHost(this.walletArgs); this.maybeWallet = w; const resp = await w.handleCoreApiRequest( "initWallet", diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts index f7b73711c..77d166095 100644 --- a/packages/taler-wallet-embedded/src/wallet-qjs.ts +++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -17,44 +17,26 @@ /** * Imports. */ -import { - AccessStats, - DefaultNodeWalletArgs, - getErrorDetailFromException, - Headers, - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, - openPromise, - openTalerDatabase, - SetTimeoutTimerAPI, - SynchronousCryptoWorkerFactoryPlain, - Wallet, - WalletApiOperation, -} from "@gnu-taler/taler-wallet-core"; - import { CoreApiMessageEnvelope, CoreApiResponse, CoreApiResponseSuccess, + createPlatformHttpLib, + getErrorDetailFromException, InitRequest, - j2s, Logger, setGlobalLogLevelFromString, setPRNG, WalletNotification, } from "@gnu-taler/taler-util"; -import { BridgeIDBFactory } from "@gnu-taler/idb-bridge"; -import { MemoryBackend } from "@gnu-taler/idb-bridge"; -import { shimIndexedDB } from "@gnu-taler/idb-bridge"; -import { IDBFactory } from "@gnu-taler/idb-bridge"; - -import * as _qjsOsImp from "os"; -// @ts-ignore -import * as _qjsStdImp from "std"; - -const textDecoder = new TextDecoder(); -const textEncoder = new TextEncoder(); +import { qjsOs } from "@gnu-taler/taler-util/qtart"; +import { + createNativeWalletHost2, + DefaultNodeWalletArgs, + openPromise, + Wallet, + WalletApiOperation, +} from "@gnu-taler/taler-wallet-core"; setGlobalLogLevelFromString("trace"); @@ -66,210 +48,19 @@ setPRNG(function (x: Uint8Array, n: number) { for (let i = 0; i < v.length; i++) v[i] = 0; }); -export interface QjsHttpResp { - status: number; - data: ArrayBuffer; -} - -export interface QjsHttpOptions { - method: string; - debug?: boolean; - data?: ArrayBuffer; - headers?: string[]; -} - -export interface QjsOsLib { - fetchHttp(url: string, options?: QjsHttpOptions): Promise; - postMessageToHost(s: string): void; - setMessageFromHostHandler(h: (s: string) => void): void; - rename(oldPath: string, newPath: string): number; -} - -export interface QjsStdLib { - writeFile(filename: string, contents: string): void; - loadFile(filename: string): string; -} - -// This is not the nodejs "os" module, but the qjs "os" module. -const qjsOs: QjsOsLib = _qjsOsImp as any; - -const qjsStd: QjsStdLib = _qjsStdImp as any; - const logger = new Logger("taler-wallet-embedded/index.ts"); -export class NativeHttpLib implements HttpRequestLibrary { - get( - url: string, - opt?: HttpRequestOptions | undefined, - ): Promise { - return this.fetch(url, { - method: "GET", - ...opt, - }); - } - postJson( - url: string, - body: any, - opt?: HttpRequestOptions | undefined, - ): Promise { - return this.fetch(url, { - method: "POST", - body, - ...opt, - }); - } - async fetch( - url: string, - opt?: HttpRequestOptions | undefined, - ): Promise { - const method = opt?.method ?? "GET"; - let data: ArrayBuffer | undefined = undefined; - let headers: string[] = []; - if (opt?.headers) { - for (let headerName of Object.keys(opt.headers)) { - headers.push(`${headerName}: ${opt.headers[headerName]}`); - } - } - if (method.toUpperCase() === "POST") { - if (opt?.body) { - if (typeof opt.body === "string") { - data = textEncoder.encode(opt.body).buffer; - } else if (ArrayBuffer.isView(opt.body)) { - data = opt.body.buffer; - } else if (opt.body instanceof ArrayBuffer) { - data = opt.body; - } else if (typeof opt.body === "object") { - data = textEncoder.encode(JSON.stringify(opt.body)).buffer; - } - } else { - data = new ArrayBuffer(0); - } - } - const res = await qjsOs.fetchHttp(url, { - method, - data, - headers, - }); - return { - requestMethod: method, - headers: new Headers(), - async bytes() { - return res.data; - }, - json() { - const text = textDecoder.decode(res.data); - return JSON.parse(text); - }, - async text() { - const text = textDecoder.decode(res.data); - return text; - }, - requestUrl: url, - status: res.status, - }; - } -} - function sendNativeMessage(ev: CoreApiMessageEnvelope): void { const m = JSON.stringify(ev); qjsOs.postMessageToHost(m); } -/** - * Generate a random alphanumeric ID. Does *not* use cryptographically - * secure randomness. - */ -function makeId(length: number): string { - let result = ""; - const characters = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * characters.length)); - } - return result; -} - -export async function getWallet(args: DefaultNodeWalletArgs = {}): Promise<{ - wallet: Wallet; - getDbStats: () => AccessStats; -}> { - BridgeIDBFactory.enableTracing = false; - const myBackend = new MemoryBackend(); - myBackend.enableTracing = false; - - const storagePath = args.persistentStoragePath; - if (storagePath) { - const dbContentStr = qjsStd.loadFile(storagePath); - if (dbContentStr != null) { - const dbContent = JSON.parse(dbContentStr); - myBackend.importDump(dbContent); - } - - myBackend.afterCommitCallback = async () => { - logger.trace("committing database"); - // Allow caller to stop persisting the wallet. - if (args.persistentStoragePath === undefined) { - return; - } - const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`; - const dbContent = myBackend.exportDump(); - qjsStd.writeFile(tmpPath, JSON.stringify(dbContent, undefined, 2)); - // Atomically move the temporary file onto the DB path. - const res = qjsOs.rename(tmpPath, args.persistentStoragePath); - if (res != 0) { - throw Error("db commit failed at rename"); - } - logger.trace("committing database done"); - }; - } - - console.log("done processing storage path"); - - BridgeIDBFactory.enableTracing = false; - - const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); - const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory; - - let myHttpLib; - if (args.httpLib) { - myHttpLib = args.httpLib; - } else { - myHttpLib = new NativeHttpLib(); - } - - const myVersionChange = (): Promise => { - logger.error("version change requested, should not happen"); - throw Error( - "BUG: wallet DB version change event can't happen with memory IDB", - ); - }; - - shimIndexedDB(myBridgeIdbFactory); - - const myDb = await openTalerDatabase(myIdbFactory, myVersionChange); - - let workerFactory; - workerFactory = new SynchronousCryptoWorkerFactoryPlain(); - - const timer = new SetTimeoutTimerAPI(); - - const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory); - - if (args.notifyHandler) { - w.addNotificationListener(args.notifyHandler); - } - return { - wallet: w, - getDbStats: () => myBackend.accessStats, - }; -} - class NativeWalletMessageHandler { walletArgs: DefaultNodeWalletArgs | undefined; initRequest: InitRequest = {}; maybeWallet: Wallet | undefined; wp = openPromise(); - httpLib = new NativeHttpLib(); + httpLib = createPlatformHttpLib(); /** * Handle a request from the native wallet. @@ -292,7 +83,7 @@ class NativeWalletMessageHandler { const reinit = async () => { logger.info("in reinit"); - const wR = await getWallet(this.walletArgs); + const wR = await createNativeWalletHost2(this.walletArgs); const w = wR.wallet; this.maybeWallet = w; const resp = await w.handleCoreApiRequest("initWallet", "native-init", { @@ -422,7 +213,7 @@ globalThis.installNativeWalletListener = installNativeWalletListener; globalThis.makeWallet = getWallet; export async function testWithGv() { - const w = await getWallet(); + const w = await createNativeWalletHost2(); await w.wallet.client.call(WalletApiOperation.InitWallet, {}); await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { amountToSpend: "KUDOS:1", @@ -438,7 +229,7 @@ export async function testWithGv() { export async function testWithLocal() { console.log("running local test"); - const w = await getWallet({ + const w = await createNativeWalletHost2({ persistentStoragePath: "walletdb.json", }); console.log("created wallet"); diff --git a/packages/taler-wallet-webextension/src/browserHttpLib.ts b/packages/taler-wallet-webextension/src/browserHttpLib.ts index 165a0037c..3b8bb1881 100644 --- a/packages/taler-wallet-webextension/src/browserHttpLib.ts +++ b/packages/taler-wallet-webextension/src/browserHttpLib.ts @@ -18,19 +18,17 @@ * Imports. */ import { + Logger, + RequestThrottler, + TalerErrorCode, HttpRequestLibrary, HttpRequestOptions, HttpResponse, Headers, TalerError, -} from "@gnu-taler/taler-wallet-core"; -import { - Logger, - RequestThrottler, - stringToBytes, - TalerErrorCode, } from "@gnu-taler/taler-util"; + const logger = new Logger("browserHttpLib"); /** diff --git a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts index 2f1a26e36..bb1794e56 100644 --- a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts +++ b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts @@ -22,11 +22,12 @@ * Imports. */ -import { j2s, Logger } from "@gnu-taler/taler-util"; import { + j2s, + Logger, getErrorDetailFromException, - nativeCrypto, -} from "@gnu-taler/taler-wallet-core"; +} from "@gnu-taler/taler-util"; +import { nativeCrypto } from "@gnu-taler/taler-wallet-core"; const logger = new Logger("browserWorkerEntry.ts"); diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts index ee5375859..670a67599 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts @@ -16,7 +16,7 @@ /* eslint-disable react-hooks/rules-of-hooks */ import { Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util"; -import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { isFuture, parse } from "date-fns"; import { useState } from "preact/hooks"; import { alertFromError, useAlertContext } from "../../context/alert.js"; diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts index 66c018ddf..8459d5ca2 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts @@ -20,16 +20,14 @@ import { NotificationType, PreparePayResult, PreparePayResultType, - TalerErrorDetail, TalerProtocolTimestamp, } from "@gnu-taler/taler-util"; -import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { useEffect, useState } from "preact/hooks"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { useEffect } from "preact/hooks"; import { alertFromError, useAlertContext } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; import { useTranslationContext } from "../../context/translation.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { withSafe } from "../../mui/handlers.js"; import { Props, State } from "./index.js"; export function useComponentState({ diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts index 6574d6ba1..b306ca122 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts @@ -15,11 +15,9 @@ */ import { - Amounts, - TalerErrorDetail, - TalerProtocolTimestamp, + Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util"; -import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { isFuture, parse } from "date-fns"; import { useState } from "preact/hooks"; import { alertFromError, useAlertContext } from "../../context/alert.js"; diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts index 12643b893..6b50faf10 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts @@ -16,12 +16,9 @@ import { AbsoluteTime, - Amounts, - TalerErrorDetail, - TalerProtocolTimestamp, + Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util"; -import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { useState } from "preact/hooks"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { alertFromError, useAlertContext } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; import { useTranslationContext } from "../../context/translation.js"; diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts index 5f149064c..9522c2bfb 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts @@ -20,8 +20,9 @@ import { Amounts, ExchangeListItem, ExchangeTosStatus, + TalerError, } from "@gnu-taler/taler-util"; -import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; import { alertFromError, useAlertContext } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts index cf9409bad..a5e357f7d 100644 --- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts +++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts @@ -13,8 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ -import { TalerErrorDetail } from "@gnu-taler/taler-util"; -import { TalerError } from "@gnu-taler/taler-wallet-core"; +import { TalerErrorDetail, TalerError } from "@gnu-taler/taler-util"; import { useEffect, useMemo, useState } from "preact/hooks"; import { BackgroundError } from "../wxApi.js"; diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index 07829641e..beb65b2d0 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -19,8 +19,9 @@ import { Logger, TalerErrorCode, TalerUriType, + TalerError, } from "@gnu-taler/taler-util"; -import { TalerError, WalletOperations } from "@gnu-taler/taler-wallet-core"; +import { WalletOperations } from "@gnu-taler/taler-wallet-core"; import { BackgroundOperations } from "../wxApi.js"; import { BackgroundPlatformAPI, diff --git a/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts index 0742d5ccd..4ee572435 100644 --- a/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts +++ b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts @@ -22,12 +22,12 @@ import { CryptoWorker, CryptoWorkerFactory, - SynchronousCryptoWorker, + SynchronousCryptoWorkerPlain, } from "@gnu-taler/taler-wallet-core"; export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory { startWorker(): CryptoWorker { - return new SynchronousCryptoWorker(); + return new SynchronousCryptoWorkerPlain(); } getConcurrency(): number { diff --git a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts index 4b47e89d5..00c0085ef 100644 --- a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts +++ b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts @@ -21,14 +21,12 @@ import { Logger, RequestThrottler, TalerErrorCode, -} from "@gnu-taler/taler-util"; -import { Headers, HttpRequestLibrary, HttpRequestOptions, HttpResponse, TalerError, -} from "@gnu-taler/taler-wallet-core"; +} from "@gnu-taler/taler-util"; /** * An implementation of the [[HttpRequestLibrary]] using the diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts index c064d7111..5f3d09619 100644 --- a/packages/taler-wallet-webextension/src/wxApi.ts +++ b/packages/taler-wallet-webextension/src/wxApi.ts @@ -29,20 +29,18 @@ import { NotificationType, TalerErrorCode, TalerErrorDetail, - WalletDiagnostics, + WalletDiagnostics } from "@gnu-taler/taler-util"; import { - TalerError, WalletCoreApiClient, WalletCoreOpKeys, WalletCoreRequestType, - WalletCoreResponseType, - WalletOperations, + WalletCoreResponseType } from "@gnu-taler/taler-wallet-core"; import { MessageFromBackend, MessageFromFrontendBackground, - MessageFromFrontendWallet, + MessageFromFrontendWallet } from "./platform/api.js"; import { platform } from "./platform/foreground.js"; diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index 99602445d..cca07941a 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -32,14 +32,14 @@ import { TalerErrorCode, TalerUriType, WalletDiagnostics, + makeErrorDetail, + getErrorDetailFromException, } from "@gnu-taler/taler-util"; import { DbAccess, deleteTalerDatabase, exportDb, - getErrorDetailFromException, importDb, - makeErrorDetail, OpenedPromise, openPromise, openTalerDatabase,