taler-typescript-core

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

commit c73a73e3471c37e59d63f4fd429e9f4589685003
parent 5fc116155854d334d131db06e2e8db6f6add855b
Author: Florian Dold <dold@taler.net>
Date:   Sun,  9 Aug 2026 14:49:47 +0200

wallet-cli: add offline mode

Diffstat:
Mpackages/taler-wallet-cli/README.md | 9+++++++++
Mpackages/taler-wallet-cli/src/index.ts | 46+++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/packages/taler-wallet-cli/README.md b/packages/taler-wallet-cli/README.md @@ -7,3 +7,12 @@ GNU Taler wallet. To be able to use the sqlite3 backend, make sure that better-sqlite3 is installed as an optional dependency in the ../idb-bridge package. + +## Offline mode + +Set `TALER_WALLET_OFFLINE=1` to make every network request from the local +wallet-core fail before it is sent. This is useful when inspecting or +debugging a wallet database without changing server-side state. Offline mode +does not support `--wallet-connection` (or `TALER_WALLET_CONNECTION`), because +that connects to a separately running wallet-core process that the CLI cannot +constrain. diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts @@ -43,6 +43,7 @@ import { setDangerousTimetravel, setGlobalLogLevelFromString, summarizeTalerErrorDetail, + TalerError, TalerErrorCode, TalerUriAction, TalerUris, @@ -81,7 +82,11 @@ import { readlinePrompt, setUnhandledRejectionHandler, } from "@gnu-taler/taler-util/compat"; -import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; +import { + createPlatformHttpLib, + type HttpRequestOptions, + type HttpRequestLibrary, +} from "@gnu-taler/taler-util/http"; import { JsonMessage, runRpcServer } from "@gnu-taler/taler-util/twrpc"; import { createNativeWalletHost2, @@ -493,6 +498,35 @@ function checkEnvFlag(name: string): boolean { return false; } +/** + * HTTP implementation used when TALER_WALLET_OFFLINE=1. + * + * Rejecting at this boundary means the request cannot reach the platform HTTP + * implementation, and thus cannot result in a connection to a server. + */ +class OfflineHttpLib implements HttpRequestLibrary { + async fetch(requestUrl: string, opt?: HttpRequestOptions): Promise<never> { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_NETWORK_ERROR, + { + requestUrl, + requestMethod: opt?.method ?? "GET", + }, + "network requests are disabled by TALER_WALLET_OFFLINE=1", + ); + } +} + +function createWalletHttpLib(args?: { + enableThrottling?: boolean; + requireTls?: boolean; +}): HttpRequestLibrary { + if (checkEnvFlag("TALER_WALLET_OFFLINE")) { + return new OfflineHttpLib(); + } + return createPlatformHttpLib(args); +} + export interface WalletContext { /** * High-level client for making API requests to wallet-core. @@ -535,7 +569,7 @@ async function createLocalWallet( notificationHandler?: (n: WalletNotification) => void, ): Promise<CreateWalletResult> { const dbPath = walletCliArgs.wallet.walletDbFile ?? defaultWalletDbPath; - const myHttpLib = createPlatformHttpLib({ + const myHttpLib = createWalletHttpLib({ enableThrottling: walletCliArgs.wallet.noThrottle ? false : true, requireTls: walletCliArgs.wallet.noHttp, }); @@ -649,6 +683,12 @@ async function withWallet<T>( } if (walletSocketPath) { + if (checkEnvFlag("TALER_WALLET_OFFLINE")) { + throw new CliUsageError( + "TALER_WALLET_OFFLINE=1 cannot be used with a remote wallet connection", + "offline mode only supports the wallet-core process started by taler-wallet-cli", + ); + } logger.info("creating remote wallet"); const w = await createRemoteWallet({ name: "wallet", @@ -3181,7 +3221,7 @@ advancedCli mark: "experimental", }) .action(async (args) => { - const myHttpLib = createPlatformHttpLib(); + const myHttpLib = createWalletHttpLib(); const res = await createNativeWalletHost2({ // No persistent DB storage. persistentStoragePath: undefined,