summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-02-29 18:37:13 +0100
committerFlorian Dold <florian@dold.me>2024-02-29 23:24:06 +0100
commit277a5c641df336d8b5b2d9bd6559e45f0b02aa79 (patch)
tree49cbdadaf04b5630cdae3e2a89e6d3a74d30632b /packages/taler-wallet-core/src
parent206780bb0ee763bcf50a3f4f9f78579a8adcdb3a (diff)
downloadwallet-core-277a5c641df336d8b5b2d9bd6559e45f0b02aa79.tar.gz
wallet-core-277a5c641df336d8b5b2d9bd6559e45f0b02aa79.tar.bz2
wallet-core-277a5c641df336d8b5b2d9bd6559e45f0b02aa79.zip
wallet-core: improve config handling, test builtin exchange config
Diffstat (limited to 'packages/taler-wallet-core/src')
-rw-r--r--packages/taler-wallet-core/src/host-common.ts6
-rw-r--r--packages/taler-wallet-core/src/host-impl.node.ts30
-rw-r--r--packages/taler-wallet-core/src/host-impl.qtart.ts30
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts61
-rw-r--r--packages/taler-wallet-core/src/wallet.ts133
5 files changed, 123 insertions, 137 deletions
diff --git a/packages/taler-wallet-core/src/host-common.ts b/packages/taler-wallet-core/src/host-common.ts
index c56d7ed1c..7651e5a12 100644
--- a/packages/taler-wallet-core/src/host-common.ts
+++ b/packages/taler-wallet-core/src/host-common.ts
@@ -16,7 +16,6 @@
import { WalletNotification } from "@gnu-taler/taler-util";
import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
-import { WalletConfigParameter } from "./index.js";
/**
* Helpers to initiate a wallet in a host environment.
@@ -45,11 +44,6 @@ export interface DefaultNodeWalletArgs {
httpLib?: HttpRequestLibrary;
cryptoWorkerType?: "sync" | "node-worker-thread";
-
- /**
- * Config parameters
- */
- config?: WalletConfigParameter;
}
/**
diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts
index a0c739f45..6a32a086a 100644
--- a/packages/taler-wallet-core/src/host-impl.node.ts
+++ b/packages/taler-wallet-core/src/host-impl.node.ts
@@ -32,7 +32,11 @@ import {
shimIndexedDB,
} from "@gnu-taler/idb-bridge";
import { createNodeSqlite3Impl } from "@gnu-taler/idb-bridge/node-sqlite3-bindings";
-import { Logger, SetTimeoutTimerAPI } from "@gnu-taler/taler-util";
+import {
+ Logger,
+ SetTimeoutTimerAPI,
+ WalletRunConfig,
+} from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import * as fs from "fs";
import { NodeThreadCryptoWorkerFactory } from "./crypto/workers/nodeThreadWorker.js";
@@ -133,15 +137,18 @@ export async function createNativeWalletHost2(
wallet: Wallet;
getDbStats: () => AccessStats;
}> {
- let myHttpLib;
- if (args.httpLib) {
- myHttpLib = args.httpLib;
- } else {
- myHttpLib = createPlatformHttpLib({
- enableThrottling: true,
- requireTls: !args.config?.features?.allowHttp,
- });
- }
+ const myHttpFactory = (config: WalletRunConfig) => {
+ let myHttpLib;
+ if (args.httpLib) {
+ myHttpLib = args.httpLib;
+ } else {
+ myHttpLib = createPlatformHttpLib({
+ enableThrottling: true,
+ requireTls: !config.features.allowHttp,
+ });
+ }
+ return myHttpLib;
+ };
let dbResp: MakeDbResult;
@@ -188,10 +195,9 @@ export async function createNativeWalletHost2(
const w = await Wallet.create(
myIdbFactory,
- myHttpLib,
+ myHttpFactory,
timer,
workerFactory,
- args.config,
);
if (args.notifyHandler) {
diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts
index 329e491bf..9c985d0c1 100644
--- a/packages/taler-wallet-core/src/host-impl.qtart.ts
+++ b/packages/taler-wallet-core/src/host-impl.qtart.ts
@@ -36,7 +36,11 @@ import {
createSqliteBackend,
shimIndexedDB,
} from "@gnu-taler/idb-bridge";
-import { Logger, SetTimeoutTimerAPI } from "@gnu-taler/taler-util";
+import {
+ Logger,
+ SetTimeoutTimerAPI,
+ WalletRunConfig,
+} from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import { qjsOs, qjsStd } from "@gnu-taler/taler-util/qtart";
import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js";
@@ -180,15 +184,18 @@ export async function createNativeWalletHost2(
shimIndexedDB(dbResp.idbFactory);
- let myHttpLib;
- if (args.httpLib) {
- myHttpLib = args.httpLib;
- } else {
- myHttpLib = createPlatformHttpLib({
- enableThrottling: true,
- requireTls: !args.config?.features?.allowHttp,
- });
- }
+ const myHttpFactory = (config: WalletRunConfig) => {
+ let myHttpLib;
+ if (args.httpLib) {
+ myHttpLib = args.httpLib;
+ } else {
+ myHttpLib = createPlatformHttpLib({
+ enableThrottling: true,
+ requireTls: !config.features.allowHttp,
+ });
+ }
+ return myHttpLib;
+ };
let workerFactory;
workerFactory = new SynchronousCryptoWorkerFactoryPlain();
@@ -197,10 +204,9 @@ export async function createNativeWalletHost2(
const w = await Wallet.create(
myIdbFactory,
- myHttpLib,
+ myHttpFactory,
timer,
workerFactory,
- args.config,
);
if (args.notifyHandler) {
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index 553155ece..240012bca 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -277,53 +277,6 @@ export type GetVersionOp = {
response: WalletCoreVersion;
};
-/**
- * Configurations options for the Wallet
- *
- * All missing values of the config will be replaced with default values
- * Default values are defined by Wallet.getDefaultConfig()
- */
-export type WalletConfigParameter = RecursivePartial<WalletConfig>;
-
-export interface BuiltinExchange {
- exchangeBaseUrl: string;
- currencyHint?: string;
-}
-
-export interface WalletConfig {
- /**
- * Initialization values useful for a complete startup.
- *
- * These are values may be overridden by different wallets
- */
- builtin: {
- exchanges: BuiltinExchange[];
- };
-
- /**
- * Unsafe options which it should only be used to create
- * testing environment.
- */
- testing: {
- /**
- * Allow withdrawal of denominations even though they are about to expire.
- */
- denomselAllowLate: boolean;
- devModeActive: boolean;
- insecureTrustExchange: boolean;
- preventThrottling: boolean;
- skipDefaults: boolean;
- emitObservabilityEvents: boolean;
- };
-
- /**
- * Configurations values that may be safe to show to the user
- */
- features: {
- allowHttp: boolean;
- };
-}
-
// group: Basic Wallet Information
/**
@@ -1100,14 +1053,12 @@ export type GetPendingTasksOp = {
response: any;
};
-
export type GetActiveTasksOp = {
op: WalletApiOperation.GetActiveTasks;
request: EmptyObject;
response: GetActiveTasks;
};
-
/**
* Dump all coins of the wallet in a simple JSON format.
*/
@@ -1305,15 +1256,3 @@ export interface WalletCoreApiClient {
payload: WalletCoreRequestType<Op>,
): Promise<WalletCoreResponseType<Op>>;
}
-
-type Primitives = string | number | boolean;
-
-type RecursivePartial<T extends object> = {
- [P in keyof T]?: T[P] extends Array<infer U extends object>
- ? Array<RecursivePartial<U>>
- : T[P] extends Array<infer J extends Primitives>
- ? Array<J>
- : T[P] extends object
- ? RecursivePartial<T[P]>
- : T[P];
-} & object;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 0dc066730..b397c43d5 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -47,6 +47,7 @@ import {
ObservabilityContext,
ObservabilityEventType,
OpenedPromise,
+ PartialWalletRunConfig,
PrepareWithdrawExchangeRequest,
PrepareWithdrawExchangeResponse,
RecoverStoredBackupRequest,
@@ -64,6 +65,7 @@ import {
ValidateIbanResponse,
WalletCoreVersion,
WalletNotification,
+ WalletRunConfig,
WithdrawalDetailsForAmount,
checkDbInvariant,
codecForAbortTransaction,
@@ -99,6 +101,7 @@ import {
codecForGetWithdrawalDetailsForAmountRequest,
codecForGetWithdrawalDetailsForUri,
codecForImportDbRequest,
+ codecForInitRequest,
codecForInitiatePeerPullPaymentRequest,
codecForInitiatePeerPushDebitRequest,
codecForIntegrationTestArgs,
@@ -277,8 +280,6 @@ import {
} from "./versions.js";
import {
WalletApiOperation,
- WalletConfig,
- WalletConfigParameter,
WalletCoreApiClient,
WalletCoreResponseType,
} from "./wallet-api-types.js";
@@ -685,6 +686,17 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
return {};
}
case WalletApiOperation.InitWallet: {
+ const req = codecForInitRequest().decode(payload);
+
+ logger.info(`init request: ${req}`);
+
+ if (wex.ws.initCalled) {
+ logger.warn(
+ "initWallet called twice, new run configuration is ignored",
+ );
+ return;
+ }
+
logger.trace("initializing wallet");
// Write to the DB to make sure that we're failing early in
// case the DB is not writeable.
@@ -701,6 +713,9 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
innerError: getErrorDetailFromException(e),
});
}
+
+ wex.ws.initWithConfig(applyRunConfigDefaults(req.config));
+
wex.ws.initCalled = true;
if (wex.ws.config.testing.skipDefaults) {
logger.trace("skipping defaults");
@@ -1437,7 +1452,12 @@ export function getNormalWalletExecutionContext(
cancellationToken,
cryptoApi: ws.cryptoApi,
db: ws.db,
- http: ws.http,
+ get http() {
+ if (ws.initCalled) {
+ return ws.http;
+ }
+ throw Error("wallet not initialized");
+ },
taskScheduler: ws.taskScheduler,
oc,
};
@@ -1456,7 +1476,7 @@ async function handleCoreApiRequest(
let wex: WalletExecutionContext;
let oc: ObservabilityContext;
- if (ws.config.testing.emitObservabilityEvents) {
+ if (ws.initCalled && ws.config.testing.emitObservabilityEvents) {
oc = {
observe(evt) {
ws.notify({
@@ -1512,6 +1532,34 @@ async function handleCoreApiRequest(
}
}
+export function applyRunConfigDefaults(
+ wcp?: PartialWalletRunConfig,
+): WalletRunConfig {
+ return {
+ builtin: {
+ exchanges: wcp?.builtin?.exchanges ?? [
+ {
+ exchangeBaseUrl: "https://exchange.demo.taler.net/",
+ currencyHint: "KUDOS",
+ },
+ ],
+ },
+ features: {
+ allowHttp: wcp?.features?.allowHttp ?? false,
+ },
+ testing: {
+ denomselAllowLate: wcp?.testing?.denomselAllowLate ?? false,
+ devModeActive: wcp?.testing?.devModeActive ?? false,
+ insecureTrustExchange: wcp?.testing?.insecureTrustExchange ?? false,
+ preventThrottling: wcp?.testing?.preventThrottling ?? false,
+ skipDefaults: wcp?.testing?.skipDefaults ?? false,
+ emitObservabilityEvents: wcp?.testing?.emitObservabilityEvents ?? false,
+ },
+ };
+}
+
+export type HttpFactory = (config: WalletRunConfig) => HttpRequestLibrary;
+
/**
* Public handle to a running wallet.
*/
@@ -1521,17 +1569,15 @@ export class Wallet {
private constructor(
idb: IDBFactory,
- http: HttpRequestLibrary,
+ httpFactory: HttpFactory,
timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
- config?: WalletConfigParameter,
) {
this.ws = new InternalWalletState(
idb,
- http,
+ httpFactory,
timer,
cryptoWorkerFactory,
- Wallet.getEffectiveConfig(config),
);
}
@@ -1544,44 +1590,15 @@ export class Wallet {
static async create(
idb: IDBFactory,
- http: HttpRequestLibrary,
+ httpFactory: HttpFactory,
timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
- config?: WalletConfigParameter,
): Promise<Wallet> {
- const w = new Wallet(idb, http, timer, cryptoWorkerFactory, config);
+ const w = new Wallet(idb, httpFactory, timer, cryptoWorkerFactory);
w._client = await getClientFromWalletState(w.ws);
return w;
}
- public static defaultConfig: Readonly<WalletConfig> = {
- builtin: {
- exchanges: [
- {
- exchangeBaseUrl: "https://exchange.demo.taler.net/",
- currencyHint: "KUDOS",
- },
- ],
- },
- features: {
- allowHttp: false,
- },
- testing: {
- preventThrottling: false,
- devModeActive: false,
- insecureTrustExchange: false,
- denomselAllowLate: false,
- skipDefaults: false,
- emitObservabilityEvents: false,
- },
- };
-
- static getEffectiveConfig(
- param?: WalletConfigParameter,
- ): Readonly<WalletConfig> {
- return deepMerge(Wallet.defaultConfig, param ?? {});
- }
-
addNotificationListener(f: (n: WalletNotification) => void): CancelFn {
return this.ws.addNotificationListener(f);
}
@@ -1637,10 +1654,12 @@ export class InternalWalletState {
taskScheduler: TaskScheduler = new TaskSchedulerImpl(this);
- config: Readonly<WalletConfig>;
+ private _config: Readonly<WalletRunConfig> | undefined;
private _db: DbAccess<typeof WalletStoresV1> | undefined = undefined;
+ private _http: HttpRequestLibrary | undefined = undefined;
+
get db(): DbAccess<typeof WalletStoresV1> {
if (!this._db) {
throw Error("db not initialized");
@@ -1648,20 +1667,42 @@ export class InternalWalletState {
return this._db;
}
+ initWithConfig(newConfig: WalletRunConfig): void {
+ if (this._config) {
+ throw Error("config already set");
+ }
+ this._config = newConfig;
+
+ this._http = this.httpFactory(newConfig);
+
+ if (this.config.testing.devModeActive) {
+ this._http = new DevExperimentHttpLib(this.http);
+ }
+ }
+
+ get config(): WalletRunConfig {
+ if (!this._config) {
+ throw Error("config not initialized");
+ }
+ return this._config;
+ }
+
+ get http(): HttpRequestLibrary {
+ if (!this._http) {
+ throw Error("wallet not initialized");
+ }
+ return this._http;
+ }
+
constructor(
public idb: IDBFactory,
- public http: HttpRequestLibrary,
+ private httpFactory: HttpFactory,
public timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
- configParam: WalletConfig,
) {
this.cryptoDispatcher = new CryptoDispatcher(cryptoWorkerFactory);
this.cryptoApi = this.cryptoDispatcher.cryptoApi;
this.timerGroup = new TimerGroup(timer);
- this.config = configParam;
- if (this.config.testing.devModeActive) {
- this.http = new DevExperimentHttpLib(this.http);
- }
}
async ensureWalletDbOpen(): Promise<void> {