aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-04-19 12:42:47 -0300
committerSebastian <sebasjm@gmail.com>2023-04-19 12:42:47 -0300
commitd483a3f5574355ed9c43eb6ddea59e5734323cf0 (patch)
tree2f4e3830512b50808b396991791c3c8877e5676e /packages/taler-wallet-core
parent7330f0daf907133876baf8831c44ec34cec326e5 (diff)
downloadwallet-core-d483a3f5574355ed9c43eb6ddea59e5734323cf0.tar.xz
fix #7704
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/dbless.ts8
-rw-r--r--packages/taler-wallet-core/src/dev-experiments.ts62
-rw-r--r--packages/taler-wallet-core/src/host-common.ts6
-rw-r--r--packages/taler-wallet-core/src/host-impl.node.ts8
-rw-r--r--packages/taler-wallet-core/src/host-impl.qtart.ts8
-rw-r--r--packages/taler-wallet-core/src/index.ts1
-rw-r--r--packages/taler-wallet-core/src/internal-wallet-state.ts7
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts7
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts11
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts30
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer.ts1
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts13
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts16
-rw-r--r--packages/taler-wallet-core/src/util/coinSelection.ts12
-rw-r--r--packages/taler-wallet-core/src/util/debugFlags.ts32
-rw-r--r--packages/taler-wallet-core/src/util/denominations.ts9
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts90
-rw-r--r--packages/taler-wallet-core/src/wallet.ts217
18 files changed, 294 insertions, 244 deletions
diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts
index 5dc13433a..04bfa1359 100644
--- a/packages/taler-wallet-core/src/dbless.ts
+++ b/packages/taler-wallet-core/src/dbless.ts
@@ -65,7 +65,7 @@ import {
} from "./operations/withdraw.js";
import { ExchangeInfo } from "./operations/exchanges.js";
import { assembleRefreshRevealRequest } from "./operations/refresh.js";
-import { isWithdrawableDenom } from "./index.js";
+import { isWithdrawableDenom, WalletConfig } from "./index.js";
const logger = new Logger("dbless.ts");
@@ -206,6 +206,7 @@ export async function withdrawCoin(args: {
}
export function findDenomOrThrow(
+ denomselAllowLate: boolean,
exchangeInfo: ExchangeInfo,
amount: AmountString,
): DenominationRecord {
@@ -215,7 +216,10 @@ export function findDenomOrThrow(
fraction: d.amountFrac,
value: d.amountVal,
};
- if (Amounts.cmp(value, amount) === 0 && isWithdrawableDenom(d)) {
+ if (
+ Amounts.cmp(value, amount) === 0 &&
+ isWithdrawableDenom(d, denomselAllowLate)
+ ) {
return d;
}
}
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts
index 3e6194ccd..113e9bede 100644
--- a/packages/taler-wallet-core/src/dev-experiments.ts
+++ b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -36,35 +36,6 @@ import {
const logger = new Logger("dev-experiments.ts");
-export async function setDevMode(
- ws: InternalWalletState,
- enabled: boolean,
-): Promise<void> {
- if (enabled) {
- logger.info("enabling devmode");
- await ws.db
- .mktx((x) => [x.config])
- .runReadWrite(async (tx) => {
- tx.config.put({
- key: ConfigRecordKey.DevMode,
- value: true,
- });
- });
- await maybeInitDevMode(ws);
- } else {
- logger.info("disabling devmode");
- await ws.db
- .mktx((x) => [x.config])
- .runReadWrite(async (tx) => {
- tx.config.put({
- key: ConfigRecordKey.DevMode,
- value: false,
- });
- });
- await leaveDevMode(ws);
- }
-}
-
/**
* Apply a dev experiment to the wallet database / state.
*/
@@ -78,7 +49,7 @@ export async function applyDevExperiment(
logger.info("unable to parse dev experiment URI");
return;
}
- if (!ws.devModeActive) {
+ if (!ws.config.testing.devModeActive) {
throw Error(
"can't handle devmode URI (other than enable-devmode) unless devmode is active",
);
@@ -86,37 +57,6 @@ export async function applyDevExperiment(
throw Error(`dev-experiment id not understood ${parsedUri.devExperimentId}`);
}
-/**
- * Enter dev mode, if the wallet's config entry in the DB demands it.
- */
-export async function maybeInitDevMode(ws: InternalWalletState): Promise<void> {
- const devMode = await ws.db
- .mktx((x) => [x.config])
- .runReadOnly(async (tx) => {
- const rec = await tx.config.get(ConfigRecordKey.DevMode);
- if (!rec || rec.key !== ConfigRecordKey.DevMode) {
- return false;
- }
- return rec.value;
- });
- if (!devMode) {
- ws.devModeActive = false;
- return;
- }
- ws.devModeActive = true;
- if (ws.http instanceof DevExperimentHttpLib) {
- return;
- }
- ws.http = new DevExperimentHttpLib(ws.http);
-}
-
-export async function leaveDevMode(ws: InternalWalletState): Promise<void> {
- if (ws.http instanceof DevExperimentHttpLib) {
- ws.http = ws.http.underlyingLib;
- }
- ws.devModeActive = false;
-}
-
export class DevExperimentHttpLib implements HttpRequestLibrary {
_isDevExperimentLib = true;
underlyingLib: HttpRequestLibrary;
diff --git a/packages/taler-wallet-core/src/host-common.ts b/packages/taler-wallet-core/src/host-common.ts
index 7651e5a12..21e7f1157 100644
--- a/packages/taler-wallet-core/src/host-common.ts
+++ b/packages/taler-wallet-core/src/host-common.ts
@@ -16,6 +16,7 @@
import { WalletNotification } from "@gnu-taler/taler-util";
import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
+import { WalletConfig, WalletConfigParameter } from "./index.js";
/**
* Helpers to initiate a wallet in a host environment.
@@ -44,6 +45,11 @@ 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 097b5856a..bf5c14f99 100644
--- a/packages/taler-wallet-core/src/host-impl.node.ts
+++ b/packages/taler-wallet-core/src/host-impl.node.ts
@@ -144,7 +144,13 @@ export async function createNativeWalletHost2(
const timer = new SetTimeoutTimerAPI();
- const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory);
+ const w = await Wallet.create(
+ myDb,
+ myHttpLib,
+ timer,
+ workerFactory,
+ args.config,
+ );
if (args.notifyHandler) {
w.addNotificationListener(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 337914292..db7a1fa5c 100644
--- a/packages/taler-wallet-core/src/host-impl.qtart.ts
+++ b/packages/taler-wallet-core/src/host-impl.qtart.ts
@@ -108,7 +108,13 @@ export async function createNativeWalletHost2(
const timer = new SetTimeoutTimerAPI();
- const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory);
+ const w = await Wallet.create(
+ myDb,
+ myHttpLib,
+ timer,
+ workerFactory,
+ args.config,
+ );
if (args.notifyHandler) {
w.addNotificationListener(args.notifyHandler);
diff --git a/packages/taler-wallet-core/src/index.ts b/packages/taler-wallet-core/src/index.ts
index 7b21d8f91..8dd06fe2b 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -36,7 +36,6 @@ export {
export * from "./pending-types.js";
-export * from "./util/debugFlags.js";
export { InternalWalletState } from "./internal-wallet-state.js";
export * from "./wallet-api-types.js";
export * from "./wallet.js";
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts b/packages/taler-wallet-core/src/internal-wallet-state.ts
index 8434c3b8f..e59781471 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -52,6 +52,7 @@ import {
GetReadWriteAccess,
} from "./util/query.js";
import { TimerGroup } from "./util/timer.js";
+import { WalletConfig } from "./wallet-api-types.js";
export const EXCHANGE_COINS_LOCK = "exchange-coins-lock";
export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock";
@@ -168,9 +169,7 @@ export interface InternalWalletState {
timerGroup: TimerGroup;
stopped: boolean;
- insecureTrustExchange: boolean;
-
- batchWithdrawal: boolean;
+ config: Readonly<WalletConfig>;
/**
* Asynchronous condition to interrupt the sleep of the
@@ -191,8 +190,6 @@ export interface InternalWalletState {
merchantOps: MerchantOperations;
refreshOps: RefreshOperations;
- devModeActive: boolean;
-
getDenomInfo(
ws: InternalWalletState,
tx: GetReadOnlyAccess<{
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts
index d1dbf5f53..700b875d3 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -840,7 +840,12 @@ export async function getTotalFeesForDepositAmount(
denom.value,
pcs.coinContributions[i],
).amount;
- const refreshCost = getTotalRefreshCost(allDenoms, denom, amountLeft);
+ const refreshCost = getTotalRefreshCost(
+ allDenoms,
+ denom,
+ amountLeft,
+ ws.config.testing.denomselAllowLate,
+ );
refreshFee.push(refreshCost);
}
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index d9051b32f..b5e02e64d 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -245,7 +245,7 @@ async function validateWireInfo(
for (const a of wireInfo.accounts) {
logger.trace("validating exchange acct");
let isValid = false;
- if (ws.insecureTrustExchange) {
+ if (ws.config.testing.insecureTrustExchange) {
isValid = true;
} else {
const { valid: v } = await ws.cryptoApi.isValidWireAccount({
@@ -275,7 +275,7 @@ async function validateWireInfo(
wireFee: Amounts.stringify(x.wire_fee),
};
let isValid = false;
- if (ws.insecureTrustExchange) {
+ if (ws.config.testing.insecureTrustExchange) {
isValid = true;
} else {
const { valid: v } = await ws.cryptoApi.isValidWireFee({
@@ -308,7 +308,7 @@ async function validateGlobalFees(
for (const gf of fees) {
logger.trace("validating exchange global fees");
let isValid = false;
- if (ws.insecureTrustExchange) {
+ if (ws.config.testing.insecureTrustExchange) {
isValid = true;
} else {
const { valid: v } = await ws.cryptoApi.isValidGlobalFees({
@@ -665,7 +665,10 @@ export async function updateExchangeFromUrlHandler(
let ageMask = 0;
for (const x of keysInfo.currentDenominations) {
- if (isWithdrawableDenom(x) && x.denomPub.age_mask != 0) {
+ if (
+ isWithdrawableDenom(x, ws.config.testing.denomselAllowLate) &&
+ x.denomPub.age_mask != 0
+ ) {
ageMask = x.denomPub.age_mask;
break;
}
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 496641fe7..2419d32a2 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -168,6 +168,7 @@ export async function getTotalPaymentCost(
allDenoms,
DenominationRecord.toDenomInfo(denom),
amountLeft,
+ ws.config.testing.denomselAllowLate,
);
costs.push(Amounts.parseOrThrow(pcs.coinContributions[i]));
costs.push(refreshCost);
@@ -1659,6 +1660,7 @@ async function applySuccessfulRefund(
p: PurchaseRecord,
refreshCoinsMap: Record<string, CoinRefreshRequest>,
r: MerchantCoinRefundSuccessStatus,
+ denomselAllowLate: boolean,
): Promise<void> {
// FIXME: check signature before storing it as valid!
@@ -1688,6 +1690,7 @@ async function applySuccessfulRefund(
allDenoms,
DenominationRecord.toDenomInfo(denom),
amountLeft,
+ denomselAllowLate,
);
refreshCoinsMap[coin.coinPub] = {
@@ -1714,6 +1717,7 @@ async function storePendingRefund(
}>,
p: PurchaseRecord,
r: MerchantCoinRefundFailureStatus,
+ denomselAllowLate: boolean,
): Promise<void> {
const refundKey = getRefundKey(r);
@@ -1745,6 +1749,7 @@ async function storePendingRefund(
allDenoms,
DenominationRecord.toDenomInfo(denom),
amountLeft,
+ denomselAllowLate,
);
p.refunds[refundKey] = {
@@ -1767,6 +1772,7 @@ async function storeFailedRefund(
p: PurchaseRecord,
refreshCoinsMap: Record<string, CoinRefreshRequest>,
r: MerchantCoinRefundFailureStatus,
+ denomselAllowLate: boolean,
): Promise<void> {
const refundKey = getRefundKey(r);
@@ -1797,6 +1803,7 @@ async function storeFailedRefund(
allDenoms,
DenominationRecord.toDenomInfo(denom),
amountLeft,
+ denomselAllowLate,
);
p.refunds[refundKey] = {
@@ -1905,11 +1912,28 @@ async function acceptRefunds(
// Invariant: (!existingRefundInfo) || (existingRefundInfo === Pending)
if (refundStatus.type === "success") {
- await applySuccessfulRefund(tx, p, refreshCoinsMap, refundStatus);
+ await applySuccessfulRefund(
+ tx,
+ p,
+ refreshCoinsMap,
+ refundStatus,
+ ws.config.testing.denomselAllowLate,
+ );
} else if (isPermanentFailure) {
- await storeFailedRefund(tx, p, refreshCoinsMap, refundStatus);
+ await storeFailedRefund(
+ tx,
+ p,
+ refreshCoinsMap,
+ refundStatus,
+ ws.config.testing.denomselAllowLate,
+ );
} else {
- await storePendingRefund(tx, p, refundStatus);
+ await storePendingRefund(
+ tx,
+ p,
+ refundStatus,
+ ws.config.testing.denomselAllowLate,
+ );
}
}
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts
index ebf521079..33659afe0 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -417,6 +417,7 @@ export async function getTotalPeerPaymentCost(
allDenoms,
DenominationRecord.toDenomInfo(denom),
amountLeft,
+ ws.config.testing.denomselAllowLate,
);
costs.push(Amounts.parseOrThrow(pcs[i].contribution));
costs.push(refreshCost);
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 70f0579c0..3122c9685 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -86,7 +86,7 @@ import {
import { makeCoinAvailable } from "./common.js";
import { updateExchangeFromUrl } from "./exchanges.js";
import { selectWithdrawalDenominations } from "../util/coinSelection.js";
-import { isWithdrawableDenom } from "../index.js";
+import { isWithdrawableDenom, WalletConfig } from "../index.js";
const logger = new Logger("refresh.ts");
@@ -105,13 +105,18 @@ export function getTotalRefreshCost(
denoms: DenominationRecord[],
refreshedDenom: DenominationInfo,
amountLeft: AmountJson,
+ denomselAllowLate: boolean,
): AmountJson {
const withdrawAmount = Amounts.sub(
amountLeft,
refreshedDenom.feeRefresh,
).amount;
const denomMap = Object.fromEntries(denoms.map((x) => [x.denomPubHash, x]));
- const withdrawDenoms = selectWithdrawalDenominations(withdrawAmount, denoms);
+ const withdrawDenoms = selectWithdrawalDenominations(
+ withdrawAmount,
+ denoms,
+ denomselAllowLate,
+ );
const resultingAmount = Amounts.add(
Amounts.zeroOfCurrency(withdrawAmount.currency),
...withdrawDenoms.selectedDenoms.map(
@@ -232,6 +237,7 @@ async function refreshCreateSession(
const newCoinDenoms = selectWithdrawalDenominations(
availableAmount,
availableDenoms,
+ ws.config.testing.denomselAllowLate,
);
if (newCoinDenoms.selectedDenoms.length === 0) {
@@ -897,7 +903,7 @@ export async function createRefreshGroup(
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
.iter(exchangeBaseUrl)
.filter((x) => {
- return isWithdrawableDenom(x);
+ return isWithdrawableDenom(x, ws.config.testing.denomselAllowLate);
});
denomsPerExchange[exchangeBaseUrl] = allDenoms;
return allDenoms;
@@ -955,6 +961,7 @@ export async function createRefreshGroup(
denoms,
denom,
Amounts.parseOrThrow(refreshAmount),
+ ws.config.testing.denomselAllowLate,
);
const output = Amounts.sub(refreshAmount, cost).amount;
estimatedOutputPerCoin.push(output);
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index 643737e93..23c3e6713 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -210,7 +210,9 @@ export async function getCandidateWithdrawalDenoms(
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl.getAll(
exchangeBaseUrl,
);
- return allDenoms.filter(isWithdrawableDenom);
+ return allDenoms.filter((d) =>
+ isWithdrawableDenom(d, ws.config.testing.denomselAllowLate),
+ );
});
}
@@ -719,7 +721,7 @@ export async function updateWithdrawalDenoms(
}) signature of ${denom.denomPubHash}`,
);
let valid = false;
- if (ws.insecureTrustExchange) {
+ if (ws.config.testing.insecureTrustExchange) {
valid = true;
} else {
const res = await ws.cryptoApi.isValidDenom({
@@ -1003,7 +1005,7 @@ export async function processWithdrawalGroup(
const resp = await processPlanchetExchangeBatchRequest(ws, wgContext, {
batchSize: maxBatchSize,
coinStartIndex: i,
- useBatchRequest: ws.batchWithdrawal,
+ useBatchRequest: ws.config.features.batchWithdrawal,
});
let work: Promise<void>[] = [];
work = [];
@@ -1180,6 +1182,7 @@ export async function getExchangeWithdrawalInfo(
const selectedDenoms = selectWithdrawalDenominations(
instructedAmount,
denoms,
+ ws.config.testing.denomselAllowLate,
);
if (selectedDenoms.selectedDenoms.length === 0) {
@@ -1710,9 +1713,14 @@ export async function internalCreateWithdrawalGroup(
amount,
denoms,
args.forcedDenomSel,
+ ws.config.testing.denomselAllowLate,
);
} else {
- initialDenomSel = selectWithdrawalDenominations(amount, denoms);
+ initialDenomSel = selectWithdrawalDenominations(
+ amount,
+ denoms,
+ ws.config.testing.denomselAllowLate,
+ );
}
const withdrawalGroup: WithdrawalGroupRecord = {
diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts
index 176d636fc..3b986d72b 100644
--- a/packages/taler-wallet-core/src/util/coinSelection.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection.ts
@@ -48,7 +48,11 @@ import {
AllowedExchangeInfo,
DenominationRecord,
} from "../db.js";
-import { getExchangeDetails, isWithdrawableDenom } from "../index.js";
+import {
+ getExchangeDetails,
+ isWithdrawableDenom,
+ WalletConfig,
+} from "../index.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { getMerchantPaymentBalanceDetails } from "../operations/balance.js";
import { checkDbInvariant, checkLogicInvariant } from "./invariants.js";
@@ -664,6 +668,7 @@ export async function selectCandidates(
export function selectWithdrawalDenominations(
amountAvailable: AmountJson,
denoms: DenominationRecord[],
+ denomselAllowLate: boolean = false,
): DenomSelectionState {
let remaining = Amounts.copy(amountAvailable);
@@ -675,7 +680,7 @@ export function selectWithdrawalDenominations(
let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
- denoms = denoms.filter(isWithdrawableDenom);
+ denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
denoms.sort((d1, d2) =>
Amounts.cmp(
DenominationRecord.getValue(d2),
@@ -737,6 +742,7 @@ export function selectForcedWithdrawalDenominations(
amountAvailable: AmountJson,
denoms: DenominationRecord[],
forcedDenomSel: ForcedDenomSel,
+ denomselAllowLate: boolean,
): DenomSelectionState {
const selectedDenoms: {
count: number;
@@ -746,7 +752,7 @@ export function selectForcedWithdrawalDenominations(
let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
- denoms = denoms.filter(isWithdrawableDenom);
+ denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
denoms.sort((d1, d2) =>
Amounts.cmp(
DenominationRecord.getValue(d2),
diff --git a/packages/taler-wallet-core/src/util/debugFlags.ts b/packages/taler-wallet-core/src/util/debugFlags.ts
deleted file mode 100644
index cea249d27..000000000
--- a/packages/taler-wallet-core/src/util/debugFlags.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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 <http://www.gnu.org/licenses/>
- */
-
-/**
- * Debug flags for wallet-core.
- *
- * @author Florian Dold
- */
-
-export interface WalletCoreDebugFlags {
- /**
- * Allow withdrawal of denominations even though they are about to expire.
- */
- denomselAllowLate: boolean;
-}
-
-export const walletCoreDebugFlags: WalletCoreDebugFlags = {
- denomselAllowLate: false,
-};
diff --git a/packages/taler-wallet-core/src/util/denominations.ts b/packages/taler-wallet-core/src/util/denominations.ts
index fb766e96a..5cc57bdab 100644
--- a/packages/taler-wallet-core/src/util/denominations.ts
+++ b/packages/taler-wallet-core/src/util/denominations.ts
@@ -29,7 +29,7 @@ import {
WireFee,
} from "@gnu-taler/taler-util";
import { DenominationRecord } from "../db.js";
-import { walletCoreDebugFlags } from "./debugFlags.js";
+import { WalletConfig } from "../index.js";
/**
* Given a list of denominations with the same value and same period of time:
@@ -452,13 +452,16 @@ export function createTimeline<Type extends object>(
* Check if a denom is withdrawable based on the expiration time,
* revocation and offered state.
*/
-export function isWithdrawableDenom(d: DenominationRecord): boolean {
+export function isWithdrawableDenom(
+ d: DenominationRecord,
+ denomselAllowLate?: boolean,
+): boolean {
const now = AbsoluteTime.now();
const start = AbsoluteTime.fromTimestamp(d.stampStart);
const withdrawExpire = AbsoluteTime.fromTimestamp(d.stampExpireWithdraw);
const started = AbsoluteTime.cmp(now, start) >= 0;
let lastPossibleWithdraw: AbsoluteTime;
- if (walletCoreDebugFlags.denomselAllowLate) {
+ if (denomselAllowLate) {
lastPossibleWithdraw = start;
} else {
lastPossibleWithdraw = AbsoluteTime.subtractDuraction(
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index 2ac649f59..94348f095 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -29,8 +29,6 @@ import {
AcceptExchangeTosRequest,
AcceptManualWithdrawalRequest,
AcceptManualWithdrawalResult,
- ConfirmPeerPullDebitRequest,
- ConfirmPeerPushCreditRequest,
AcceptTipRequest,
AcceptTipResponse,
AcceptWithdrawalResponse,
@@ -42,17 +40,18 @@ import {
ApplyRefundResponse,
BackupRecovery,
BalancesResponse,
- PreparePeerPullDebitRequest,
- PreparePeerPullDebitResponse,
- PreparePeerPushCredit,
- PreparePeerPushCreditResponse,
+ CheckPeerPullCreditRequest,
+ CheckPeerPullCreditResponse,
+ CheckPeerPushDebitRequest,
+ CheckPeerPushDebitResponse,
CoinDumpJson,
ConfirmPayRequest,
ConfirmPayResult,
+ ConfirmPeerPullDebitRequest,
+ ConfirmPeerPushCreditRequest,
CreateDepositGroupRequest,
CreateDepositGroupResponse,
DeleteTransactionRequest,
- DepositGroupFees,
ExchangeDetailedResponse,
ExchangesListResponse,
ForceRefreshRequest,
@@ -63,12 +62,12 @@ import {
GetExchangeTosResult,
GetWithdrawalDetailsForAmountRequest,
GetWithdrawalDetailsForUriRequest,
+ InitRequest,
+ InitResponse,
InitiatePeerPullCreditRequest,
InitiatePeerPullCreditResponse,
InitiatePeerPushPaymentRequest,
InitiatePeerPushPaymentResponse,
- InitRequest,
- InitResponse,
IntegrationTestArgs,
KnownBankAccounts,
ListKnownBankAccountsRequest,
@@ -78,10 +77,10 @@ import {
PreparePayRequest,
PreparePayResult,
PreparePayTemplateRequest,
- CheckPeerPullCreditRequest,
- CheckPeerPullCreditResponse,
- CheckPeerPushDebitRequest,
- CheckPeerPushDebitResponse,
+ PreparePeerPullDebitRequest,
+ PreparePeerPullDebitResponse,
+ PreparePeerPushCredit,
+ PreparePeerPushCreditResponse,
PrepareRefundRequest,
PrepareRefundResult,
PrepareTipRequest,
@@ -89,7 +88,6 @@ import {
RecoveryLoadRequest,
RetryTransactionRequest,
SetCoinSuspendedRequest,
- SetDevModeRequest,
SetWalletDeviceIdRequest,
TestPayArgs,
TestPayResult,
@@ -97,21 +95,21 @@ import {
TransactionByIdRequest,
TransactionsRequest,
TransactionsResponse,
+ TxIdResponse,
UserAttentionByIdRequest,
UserAttentionsCountResponse,
UserAttentionsRequest,
UserAttentionsResponse,
+ ValidateIbanRequest,
+ ValidateIbanResponse,
WalletBackupContentV1,
WalletCoreVersion,
WalletCurrencyInfo,
WithdrawFakebankRequest,
WithdrawTestBalanceRequest,
WithdrawUriInfoResponse,
- ValidateIbanRequest,
- ValidateIbanResponse,
- TxIdResponse,
} from "@gnu-taler/taler-util";
-import { WalletContractData } from "./db.js";
+import { AuditorTrustRecord, WalletContractData } from "./db.js";
import {
AddBackupProviderRequest,
AddBackupProviderResponse,
@@ -195,13 +193,11 @@ export enum WalletApiOperation {
ConfirmPeerPullDebit = "confirmPeerPullDebit",
ClearDb = "clearDb",
Recycle = "recycle",
- SetDevMode = "setDevMode",
ApplyDevExperiment = "applyDevExperiment",
ValidateIban = "validateIban",
}
// group: Initialization
-
type EmptyObject = Record<string, never>;
/**
* Initialize wallet-core.
@@ -739,12 +735,6 @@ export type ApplyDevExperimentOp = {
response: EmptyObject;
};
-export type SetDevModeOp = {
- op: WalletApiOperation.SetDevMode;
- request: SetDevModeRequest;
- response: EmptyObject;
-};
-
/**
* Run a simple integration test on a test deployment
* of the exchange and merchant.
@@ -953,7 +943,6 @@ export type WalletOperations = {
[WalletApiOperation.ClearDb]: ClearDbOp;
[WalletApiOperation.Recycle]: RecycleOp;
[WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp;
- [WalletApiOperation.SetDevMode]: SetDevModeOp;
[WalletApiOperation.ValidateIban]: ValidateIbanOp;
};
@@ -973,3 +962,50 @@ export interface WalletCoreApiClient {
payload: WalletCoreRequestType<Op>,
): Promise<WalletCoreResponseType<Op>>;
}
+
+type Primitives = string | number | boolean;
+
+export 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;
+
+export type WalletConfigParameter = RecursivePartial<WalletConfig>;
+
+export interface WalletConfig {
+ /**
+ * Initialization values useful for a complete startup.
+ *
+ * These are values may be overridden by different wallets
+ */
+ builtin: {
+ exchanges: string[];
+ auditors: AuditorTrustRecord[];
+ };
+
+ /**
+ * 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;
+ };
+
+ /**
+ * Configurations values that may be safe to show to the user
+ */
+ features: {
+ batchWithdrawal: boolean;
+ allowHttp: boolean;
+ };
+}
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index d6d64b5c9..45b33ce45 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -25,12 +25,38 @@
import {
AbsoluteTime,
Amounts,
+ CoinDumpJson,
+ CoinRefreshRequest,
+ CoinStatus,
+ CoreApiResponse,
+ DenomOperationMap,
+ DenominationInfo,
+ Duration,
+ ExchangeDetailedResponse,
+ ExchangeListItem,
+ ExchangeTosStatusDetails,
+ ExchangesListResponse,
+ FeeDescription,
+ GetExchangeTosResult,
+ InitResponse,
+ KnownBankAccounts,
+ KnownBankAccountsInfo,
+ Logger,
+ ManualWithdrawalDetails,
+ MerchantUsingTemplateDetails,
+ NotificationType,
+ RefreshReason,
+ TalerError,
+ TalerErrorCode,
+ URL,
+ ValidateIbanResponse,
+ WalletCoreVersion,
+ WalletNotification,
codecForAbortTransaction,
codecForAcceptBankIntegratedWithdrawalRequest,
codecForAcceptExchangeTosRequest,
codecForAcceptManualWithdrawalRequet,
codecForAcceptPeerPullPaymentRequest,
- codecForConfirmPeerPushPaymentRequest,
codecForAcceptTipRequest,
codecForAddExchangeRequest,
codecForAddKnownBankAccounts,
@@ -39,8 +65,9 @@ import {
codecForApplyRefundFromPurchaseIdRequest,
codecForApplyRefundRequest,
codecForCheckPeerPullPaymentRequest,
- codecForPreparePeerPushCreditRequest,
+ codecForCheckPeerPushDebitRequest,
codecForConfirmPayRequest,
+ codecForConfirmPeerPushPaymentRequest,
codecForCreateDepositGroupRequest,
codecForDeleteTransactionRequest,
codecForForceRefreshRequest,
@@ -54,86 +81,58 @@ import {
codecForInitiatePeerPullPaymentRequest,
codecForInitiatePeerPushPaymentRequest,
codecForIntegrationTestArgs,
+ codecForIntegrationTestV2Args,
codecForListKnownBankAccounts,
codecForMerchantPostOrderResponse,
codecForPrepareDepositRequest,
codecForPreparePayRequest,
codecForPreparePayTemplateRequest,
codecForPreparePeerPullPaymentRequest,
- codecForCheckPeerPushDebitRequest,
+ codecForPreparePeerPushCreditRequest,
codecForPrepareRefundRequest,
codecForPrepareTipRequest,
+ codecForResumeTransaction,
codecForRetryTransactionRequest,
codecForSetCoinSuspendedRequest,
- codecForSetDevModeRequest,
codecForSetWalletDeviceIdRequest,
+ codecForSuspendTransaction,
codecForTestPayArgs,
codecForTransactionByIdRequest,
codecForTransactionsRequest,
codecForUserAttentionByIdRequest,
codecForUserAttentionsRequest,
+ codecForValidateIbanRequest,
codecForWithdrawFakebankRequest,
codecForWithdrawTestBalance,
- CoinDumpJson,
- CoinRefreshRequest,
- CoinStatus,
constructPayUri,
- CoreApiResponse,
- DenominationInfo,
- DenomOperationMap,
- Duration,
durationFromSpec,
durationMin,
- ExchangeDetailedResponse,
- ExchangeListItem,
- ExchangesListResponse,
- ExchangeTosStatusDetails,
- FeeDescription,
- GetExchangeTosResult,
- InitResponse,
+ getErrorDetailFromException,
j2s,
- KnownBankAccounts,
- KnownBankAccountsInfo,
- Logger,
- ManualWithdrawalDetails,
- MerchantUsingTemplateDetails,
- NotificationType,
parsePayTemplateUri,
parsePaytoUri,
- RefreshReason,
- TalerErrorCode,
- URL,
- WalletCoreVersion,
- WalletNotification,
- codecForSuspendTransaction,
- codecForResumeTransaction,
validateIban,
- codecForValidateIbanRequest,
- ValidateIbanResponse,
- codecForIntegrationTestV2Args,
} from "@gnu-taler/taler-util";
+import {
+ HttpRequestLibrary,
+ readSuccessResponseJsonOrThrow,
+} from "@gnu-taler/taler-util/http";
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
import {
CryptoDispatcher,
CryptoWorkerFactory,
} from "./crypto/workers/crypto-dispatcher.js";
import {
- AuditorTrustRecord,
- clearDatabase,
CoinSourceType,
ConfigRecordKey,
DenominationRecord,
ExchangeDetailsRecord,
+ WalletStoresV1,
+ clearDatabase,
exportDb,
importDb,
- WalletStoresV1,
} from "./db.js";
-import {
- applyDevExperiment,
- maybeInitDevMode,
- setDevMode,
-} from "./dev-experiments.js";
-import { getErrorDetailFromException, TalerError } from "@gnu-taler/taler-util";
+import { DevExperimentHttpLib, applyDevExperiment } from "./dev-experiments.js";
import {
ActiveLongpollInfo,
ExchangeOperations,
@@ -198,18 +197,18 @@ import {
processPurchase,
} from "./operations/pay-merchant.js";
import {
+ checkPeerPullPaymentInitiation,
+ checkPeerPushDebit,
confirmPeerPullDebit,
confirmPeerPushCredit,
- preparePeerPullDebit,
- preparePeerPushCredit,
initiatePeerPullPayment,
initiatePeerPushPayment,
- checkPeerPullPaymentInitiation,
- checkPeerPushDebit,
+ preparePeerPullDebit,
+ preparePeerPushCredit,
processPeerPullCredit,
- processPeerPushInitiation,
processPeerPullDebit,
processPeerPushCredit,
+ processPeerPushInitiation,
} from "./operations/pay-peer.js";
import { getPendingOperations } from "./operations/pending.js";
import {
@@ -252,10 +251,6 @@ import {
selectBestForOverlappingDenominations,
selectMinimumFee,
} from "./util/denominations.js";
-import {
- HttpRequestLibrary,
- readSuccessResponseJsonOrThrow,
-} from "@gnu-taler/taler-util/http";
import { checkDbInvariant } from "./util/invariants.js";
import {
AsyncCondition,
@@ -275,22 +270,14 @@ import {
WALLET_MERCHANT_PROTOCOL_VERSION,
} from "./versions.js";
import {
+ RecursivePartial,
WalletApiOperation,
+ WalletConfig,
+ WalletConfigParameter,
WalletCoreApiClient,
WalletCoreResponseType,
} from "./wallet-api-types.js";
-const builtinAuditors: AuditorTrustRecord[] = [
- {
- currency: "KUDOS",
- auditorPub: "BW9DC48PHQY4NH011SHHX36DZZ3Q22Y6X7FZ1VD1CMZ2PTFZ6PN0",
- auditorBaseUrl: "https://auditor.demo.taler.net/",
- uids: ["5P25XF8TVQP9AW6VYGY2KV47WT5Y3ZXFSJAA570GJPX5SVJXKBVG"],
- },
-];
-
-const builtinExchanges: string[] = ["https://exchange.demo.taler.net/"];
-
const logger = new Logger("wallet.ts");
/**
@@ -495,10 +482,10 @@ async function fillDefaults(ws: InternalWalletState): Promise<void> {
return;
}
logger.info("importing default exchanges and auditors");
- for (const c of builtinAuditors) {
+ for (const c of ws.config.builtin.auditors) {
await tx.auditorTrust.put(c);
}
- for (const baseUrl of builtinExchanges) {
+ for (const baseUrl of ws.config.builtin.exchanges) {
const now = AbsoluteTime.now();
provideExchangeRecordInTx(ws, tx, baseUrl, now);
}
@@ -1018,7 +1005,6 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
logger.trace("filling defaults");
await fillDefaults(ws);
}
- await maybeInitDevMode(ws);
const resp: InitResponse = {
versionInfo: getVersion(ws),
};
@@ -1482,15 +1468,10 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
await applyDevExperiment(ws, req.devExperimentUri);
return {};
}
- case WalletApiOperation.SetDevMode: {
- const req = codecForSetDevModeRequest().decode(payload);
- await setDevMode(ws, req.devModeEnabled);
- return {};
- }
case WalletApiOperation.GetVersion: {
return getVersion(ws);
}
- //default:
+ // default:
// assertUnreachable(operation);
}
throw TalerError.fromDetail(
@@ -1509,7 +1490,7 @@ export function getVersion(ws: InternalWalletState): WalletCoreVersion {
exchange: WALLET_EXCHANGE_PROTOCOL_VERSION,
merchant: WALLET_MERCHANT_PROTOCOL_VERSION,
bank: WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
- devMode: ws.devModeActive,
+ devMode: false,
};
return version;
}
@@ -1575,8 +1556,15 @@ export class Wallet {
http: HttpRequestLibrary,
timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
+ config?: WalletConfigParameter,
) {
- this.ws = new InternalWalletStateImpl(db, http, timer, cryptoWorkerFactory);
+ this.ws = new InternalWalletStateImpl(
+ db,
+ http,
+ timer,
+ cryptoWorkerFactory,
+ config ?? {},
+ );
}
get client(): WalletCoreApiClient {
@@ -1586,29 +1574,22 @@ export class Wallet {
return this._client;
}
- /**
- * Trust the exchange, do not validate signatures.
- * Only used to benchmark the exchange.
- */
- setInsecureTrustExchange(): void {
- this.ws.insecureTrustExchange = true;
- }
-
- setBatchWithdrawal(enable: boolean): void {
- this.ws.batchWithdrawal = enable;
- }
-
static async create(
db: DbAccess<typeof WalletStoresV1>,
http: HttpRequestLibrary,
timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
+ config?: WalletConfigParameter,
): Promise<Wallet> {
- const w = new Wallet(db, http, timer, cryptoWorkerFactory);
+ const w = new Wallet(db, http, timer, cryptoWorkerFactory, config);
w._client = await getClientFromWalletState(w.ws);
return w;
}
+ static getDefaultConfig(): Readonly<WalletConfig> {
+ return InternalWalletStateImpl.defaultConfig;
+ }
+
addNotificationListener(f: (n: WalletNotification) => void): void {
return this.ws.addNotificationListener(f);
}
@@ -1650,10 +1631,6 @@ class InternalWalletStateImpl implements InternalWalletState {
merchantInfoCache: Record<string, MerchantInfo> = {};
- insecureTrustExchange = false;
-
- batchWithdrawal = false;
-
readonly timerGroup: TimerGroup;
latch = new AsyncCondition();
stopped = false;
@@ -1662,8 +1639,6 @@ class InternalWalletStateImpl implements InternalWalletState {
initCalled = false;
- devModeActive = false;
-
exchangeOps: ExchangeOperations = {
getExchangeDetails,
getExchangeTrust,
@@ -1696,6 +1671,31 @@ class InternalWalletStateImpl implements InternalWalletState {
*/
private resourceLocks: Set<string> = new Set();
+ config: Readonly<WalletConfig>;
+
+ public static defaultConfig: Readonly<WalletConfig> = {
+ builtin: {
+ exchanges: ["https://exchange.demo.taler.net/"],
+ auditors: [
+ {
+ currency: "KUDOS",
+ auditorPub: "BW9DC48PHQY4NH011SHHX36DZZ3Q22Y6X7FZ1VD1CMZ2PTFZ6PN0",
+ auditorBaseUrl: "https://auditor.demo.taler.net/",
+ uids: ["5P25XF8TVQP9AW6VYGY2KV47WT5Y3ZXFSJAA570GJPX5SVJXKBVG"],
+ },
+ ],
+ },
+ features: {
+ batchWithdrawal: false,
+ allowHttp: false,
+ },
+ testing: {
+ devModeActive: false,
+ insecureTrustExchange: false,
+ denomselAllowLate: false,
+ },
+ };
+
constructor(
// FIXME: Make this a getter and make
// the actual value nullable.
@@ -1705,10 +1705,15 @@ class InternalWalletStateImpl implements InternalWalletState {
public http: HttpRequestLibrary,
public timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
+ config: WalletConfigParameter,
) {
this.cryptoDispatcher = new CryptoDispatcher(cryptoWorkerFactory);
this.cryptoApi = this.cryptoDispatcher.cryptoApi;
this.timerGroup = new TimerGroup(timer);
+ this.config = deepMerge(InternalWalletStateImpl.defaultConfig, config);
+ if (this.config.testing.devModeActive) {
+ this.http = new DevExperimentHttpLib(this.http);
+ }
}
async getDenomInfo(
@@ -1808,3 +1813,29 @@ class InternalWalletStateImpl implements InternalWalletState {
}
}
}
+
+/**
+ * Take the full object as template, create a new result with all the values.
+ * Use the override object to change the values in the result
+ * return result
+ * @param full
+ * @param override
+ * @returns
+ */
+function deepMerge<T extends object>(
+ full: T,
+ override: RecursivePartial<T>,
+): T {
+ const keys = Object.keys(full);
+ const result = { ...full };
+ for (const k of keys) {
+ // @ts-ignore
+ const newVal = override[k];
+ if (newVal === undefined) continue;
+ // @ts-ignore
+ result[k] =
+ // @ts-ignore
+ typeof newVal === "object" ? deepMerge(full[k], newVal) : newVal;
+ }
+ return result;
+}