commit 4ba6478acbbe14d5385459dd6012c718ba5fc444
parent 724743166b689cdd299f644fc6fcd8d2dd4bba68
Author: Florian Dold <florian@dold.me>
Date: Wed, 1 Jul 2026 17:10:28 +0200
wallet-core/util: fix dev experiment handling
Diffstat:
2 files changed, 102 insertions(+), 100 deletions(-)
diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts
@@ -30,6 +30,59 @@ import { HostPortPath, Paytos } from "./payto.js";
import { Result, ResultError, ResultOk } from "./result.js";
import { AmountString, HashCodeString } from "./types-taler-common.js";
import { URL, URLSearchParams } from "./url.js";
+
+export enum TalerUriAction {
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.1
+ */
+ Withdraw = "withdraw",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.2
+ */
+ Pay = "pay",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.3
+ */
+ Refund = "refund",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.4
+ */
+ PayPush = "pay-push",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.5
+ */
+ PayPull = "pay-pull",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.6
+ */
+ PayTemplate = "pay-template",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.7
+ */
+ Restore = "restore",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.8
+ */
+ DevExperiment = "dev-experiment",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.9
+ */
+ AddExchange = "add-exchange",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.10
+ */
+ WithdrawExchange = "withdraw-exchange",
+ /**
+ * https://lsd.gnunet.org/lsd0006/#section-5.11
+ */
+ WithdrawalTransferResult = "withdrawal-transfer-result",
+ /**
+ * FIXME: LSD
+ * Add a contact to the wallet
+ */
+ AddContact = "add-contact",
+}
+
/**
* A parsed taler URI.
*/
@@ -594,7 +647,7 @@ function parsePayPull(
scheme: "http" | "https",
uriType: TalerUriAction.PayPull,
cs: string[],
- params: Record<string, string>,
+ _params: Record<string, string>,
opts: TalerUris.PaytoParseOptions = {},
): TalerUris.ParseResult {
// check number of segments
@@ -636,7 +689,7 @@ function parseRefund(
scheme: "http" | "https",
uriType: TalerUriAction.Refund,
cs: string[],
- params: Record<string, string>,
+ _params: Record<string, string>,
opts: TalerUris.PaytoParseOptions = {},
): TalerUris.ParseResult {
// check number of segments
@@ -792,12 +845,11 @@ function parseDevExperiment(
}
const devExperimentId = cs[0];
- const query = new URLSearchParams(params);
return Result.of({
type: TalerUriAction.DevExperiment,
devExperimentId,
- query,
+ query: params,
});
}
@@ -1018,7 +1070,7 @@ export interface TalerPayPullUri {
export interface TalerDevExperimentUri {
type: TalerUriAction.DevExperiment;
devExperimentId: string;
- query?: URLSearchParams; // FIXME: Wrong type it should be Record<string,string>
+ query?: Record<string, string>;
}
export interface TalerRestoreUri {
@@ -1052,58 +1104,6 @@ export interface TalerAddContactUri {
sourceBaseUrl: string;
}
-export enum TalerUriAction {
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.1
- */
- Withdraw = "withdraw",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.2
- */
- Pay = "pay",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.3
- */
- Refund = "refund",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.4
- */
- PayPush = "pay-push",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.5
- */
- PayPull = "pay-pull",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.6
- */
- PayTemplate = "pay-template",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.7
- */
- Restore = "restore",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.8
- */
- DevExperiment = "dev-experiment",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.9
- */
- AddExchange = "add-exchange",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.10
- */
- WithdrawExchange = "withdraw-exchange",
- /**
- * https://lsd.gnunet.org/lsd0006/#section-5.11
- */
- WithdrawalTransferResult = "withdrawal-transfer-result",
- /**
- * FIXME: LSD
- * Add a contact to the wallet
- */
- AddContact = "add-contact",
-}
-
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#encoding_for_rfc3986
*/
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -104,7 +104,7 @@ export async function applyDevExperiment(
if (!wex.ws.config.testing.devModeActive) {
throw Error("can't handle devmode URI unless devmode is active");
}
-
+ logger.info(`parsed dev experiment URI: ${j2s(parsedUri)}`);
switch (parsedUri.devExperimentId) {
case "start-block-refresh": {
wex.ws.devExperimentState.blockRefreshes = true;
@@ -175,7 +175,7 @@ export async function applyDevExperiment(
}
case "start-tc": {
const maybeFloatParam = (name: string) => {
- const val = parsedUri.query?.get(name);
+ const val = parsedUri.query?.[name];
if (val == null) {
return undefined;
}
@@ -184,12 +184,15 @@ export async function applyDevExperiment(
}
throw Error("unsupported parameter");
};
+ logger.info(`dev experiment start-tc`);
+ logger.info(`query keys: ${j2s(parsedUri.query)}`);
wex.ws.devExperimentState.tc = {
delayResponseMs: maybeFloatParam("delay_resp"),
dropRequestProbability: maybeFloatParam("drop_req"),
dropResponseProbability: maybeFloatParam("drop_resp"),
fake500Probability: maybeFloatParam("fake_500"),
};
+ logger.info(`new state: ${j2s(wex.ws.devExperimentState)}`);
return;
}
case "stop-tc": {
@@ -197,11 +200,11 @@ export async function applyDevExperiment(
return;
}
case "start-fakeprotover": {
- const baseUrl = parsedUri.query?.get("base_url");
+ const baseUrl = parsedUri.query?.["base_url"];
if (!baseUrl) {
throw Error("base_url required");
}
- const fakeVer = parsedUri.query?.get("fake_ver");
+ const fakeVer = parsedUri.query?.["fake_ver"];
if (!fakeVer) {
throw Error("fake_ver required");
}
@@ -212,7 +215,7 @@ export async function applyDevExperiment(
fakeSt.set(baseUrl, {
fakeVer,
});
- const fup = parsedUri.query?.get("fup");
+ const fup = parsedUri.query?.["fup"];
if (fup) {
try {
await fetchFreshExchange(wex, baseUrl, {
@@ -229,11 +232,11 @@ export async function applyDevExperiment(
return;
}
case "start-fakemasterpub": {
- const baseUrl = parsedUri.query?.get("base_url");
+ const baseUrl = parsedUri.query?.["base_url"];
if (!baseUrl) {
throw Error("base_url required");
}
- const fakePub = parsedUri.query?.get("fake_pub");
+ const fakePub = parsedUri.query?.["fake_pub"];
if (!fakePub) {
throw Error("fake_pub required");
}
@@ -244,7 +247,7 @@ export async function applyDevExperiment(
fakeSt.set(baseUrl, {
fakeMasterPub: fakePub,
});
- const fup = parsedUri.query?.get("fup");
+ const fup = parsedUri.query?.["fup"];
if (fup) {
try {
await fetchFreshExchange(wex, baseUrl, {
@@ -290,7 +293,7 @@ export async function applyDevExperiment(
return;
}
case "stop-fakeprotover": {
- const baseUrl = parsedUri.query?.get("base_url");
+ const baseUrl = parsedUri.query?.["base_url"];
if (!baseUrl) {
throw Error("base_url required");
}
@@ -302,15 +305,15 @@ export async function applyDevExperiment(
return;
}
case "add-global-exchange": {
- const currency = parsedUri.query?.get("c");
+ const currency = parsedUri.query?.["c"];
if (!currency || currency.length === 0) {
throw Error("missing currency (c)");
}
- const exchangeBaseUrl = parsedUri.query?.get("e");
+ const exchangeBaseUrl = parsedUri.query?.["e"];
if (!exchangeBaseUrl || exchangeBaseUrl.length === 0) {
throw Error("missing exchange base URL (e)");
}
- const exchangeMasterPub = parsedUri.query?.get("p");
+ const exchangeMasterPub = parsedUri.query?.["p"];
if (!exchangeMasterPub || exchangeMasterPub.length === 0) {
throw Error("missing exchange master pub (p)");
}
@@ -322,15 +325,15 @@ export async function applyDevExperiment(
return;
}
case "remove-global-exchange": {
- const currency = parsedUri.query?.get("c");
+ const currency = parsedUri.query?.["c"];
if (!currency || currency.length === 0) {
throw Error("missing currency (c)");
}
- const exchangeBaseUrl = parsedUri.query?.get("e");
+ const exchangeBaseUrl = parsedUri.query?.["e"];
if (!exchangeBaseUrl || exchangeBaseUrl.length === 0) {
throw Error("missing exchange base URL (e)");
}
- const exchangeMasterPub = parsedUri.query?.get("p");
+ const exchangeMasterPub = parsedUri.query?.["p"];
if (!exchangeMasterPub || exchangeMasterPub.length === 0) {
throw Error("missing exchange master pub (p)");
}
@@ -342,7 +345,7 @@ export async function applyDevExperiment(
return;
}
case "pretend-no-fees": {
- const setVal = parsedUri.query?.get("val");
+ const setVal = parsedUri.query?.["val"];
let v: boolean;
if (setVal == null) {
v = true;
@@ -359,7 +362,7 @@ export async function applyDevExperiment(
case "pretend-post-wop-failed": {
// Pretend that POSTing to a withdrawal operation
// returns a permanent error response.
- const setVal = parsedUri.query?.get("val");
+ const setVal = parsedUri.query?.["val"];
let v: boolean;
if (setVal == null) {
v = true;
@@ -379,7 +382,7 @@ export async function applyDevExperiment(
}
case "flag-disable-direct-deposits": {
const flag = getValFlag(parsedUri);
- const exchange = parsedUri.query?.get("e");
+ const exchange = parsedUri.query?.["e"];
let mySet = wex.ws.devExperimentState.flagDisableDirectDeposits;
if (!(flag || exchange)) {
mySet?.clear();
@@ -401,7 +404,7 @@ export async function applyDevExperiment(
return;
}
case "fake-shopping-url": {
- const url = parsedUri.query?.get("url") ?? undefined;
+ const url = parsedUri.query?.["url"];
wex.ws.devExperimentState.fakeShoppingUrl = url;
return;
}
@@ -414,7 +417,7 @@ export async function applyDevExperiment(
return;
}
case "demo-shortcuts": {
- const v = parsedUri.query?.get("val");
+ const v = parsedUri.query?.["val"];
if (!v || v === "off") {
wex.ws.devExperimentState.fakeDemoShortcuts = undefined;
} else {
@@ -446,7 +449,7 @@ export async function applyDevExperiment(
}
function getValFlag(parsedUri: TalerDevExperimentUri): boolean {
- const setVal = parsedUri.query?.get("val");
+ const setVal = parsedUri.query?.["val"];
if (setVal == null) {
return true;
} else if (setVal === "0") {
@@ -462,7 +465,7 @@ async function addFakeTx(
wex: WalletExecutionContext,
parsedUri: TalerDevExperimentUri,
): Promise<void> {
- const txType = parsedUri.query?.get("txType") ?? "withdrawal";
+ const txType = parsedUri.query?.["txType"] ?? "withdrawal";
const withdrawalGroupId = encodeCrock(getRandomBytes(32));
const ctx = new WithdrawTransactionContext(wex, withdrawalGroupId);
switch (txType) {
@@ -470,10 +473,10 @@ async function addFakeTx(
const secretSeed = encodeCrock(getRandomBytes(32));
const reservePair = await wex.ws.cryptoApi.createEddsaKeypair({});
const exchangeBaseUrl =
- parsedUri.query?.get("exchangeBaseUrl") ??
+ parsedUri.query?.["exchangeBaseUrl"] ??
"https://exchange.demo.taler.net/";
- const trelStr = parsedUri.query?.get("tRel") ?? undefined;
- const amountEffectiveStr = parsedUri.query?.get("amountEffective");
+ const trelStr = parsedUri.query?.["tRel"] ?? undefined;
+ const amountEffectiveStr = parsedUri.query?.["amountEffective"];
if (!amountEffectiveStr) {
throw Error("missing amountEffective option");
}
@@ -528,21 +531,20 @@ async function addFakeTx(
case "payment": {
const proposalId = encodeCrock(getRandomBytes(32));
const ctx = new PayMerchantTransactionContext(wex, proposalId);
- const summary = parsedUri.query?.get("summary") ?? "Test";
- const amountEffectiveStr = parsedUri.query?.get("amountEffective");
+ const summary = parsedUri.query?.["summary"] ?? "Test";
+ const amountEffectiveStr = parsedUri.query?.["amountEffective"];
if (!amountEffectiveStr) {
throw Error("missing amountEffective option");
}
- const merchantName =
- parsedUri.query?.get("merchantName") ?? "Test Merchant";
+ const merchantName = parsedUri.query?.["merchantName"] ?? "Test Merchant";
const exchangeBaseUrl =
- parsedUri.query?.get("exchangeBaseUrl") ??
+ parsedUri.query?.["exchangeBaseUrl"] ??
"https://exchange.demo.taler.net/";
const merchantBaseUrl =
- parsedUri.query?.get("merchantBaseUrl") ??
+ parsedUri.query?.["merchantBaseUrl"] ??
"https://backend.demo.taler.net/";
const amountEffective = Amounts.parseOrThrow(amountEffectiveStr);
- const trelStr = parsedUri.query?.get("tRel") ?? undefined;
+ const trelStr = parsedUri.query?.["tRel"] ?? undefined;
let timestamp: AbsoluteTime;
if (trelStr) {
timestamp = AbsoluteTime.subtractDuraction(
@@ -633,17 +635,17 @@ async function addFakeTx(
const pursePair = await wex.cryptoApi.createEddsaKeypair({});
const pursePub = pursePair.pub;
const ctx = new PeerPushDebitTransactionContext(wex, pursePub);
- const summary = parsedUri.query?.get("summary") ?? "Test";
- const iconId = parsedUri.query?.get("iconId") ?? undefined;
- const amountEffectiveStr = parsedUri.query?.get("amountEffective");
+ const summary = parsedUri.query?.["summary"] ?? "Test";
+ const iconId = parsedUri.query?.["iconId"] ?? undefined;
+ const amountEffectiveStr = parsedUri.query?.["amountEffective"];
if (!amountEffectiveStr) {
throw Error("missing amountEffective option");
}
const exchangeBaseUrl =
- parsedUri.query?.get("exchangeBaseUrl") ??
+ parsedUri.query?.["exchangeBaseUrl"] ??
"https://exchange.demo.taler.net/";
const amountEffective = Amounts.parseOrThrow(amountEffectiveStr);
- const trelStr = parsedUri.query?.get("tRel") ?? undefined;
+ const trelStr = parsedUri.query?.["tRel"] ?? undefined;
let timestamp: AbsoluteTime;
if (trelStr) {
timestamp = AbsoluteTime.subtractDuraction(
@@ -696,17 +698,17 @@ async function addFakeTx(
const pursePub = pursePair.pub;
const peerPushCreditId = encodeCrock(getRandomBytes(32));
const ctx = new PeerPushCreditTransactionContext(wex, peerPushCreditId);
- const summary = parsedUri.query?.get("summary") ?? "Test";
- const iconId = parsedUri.query?.get("iconId") ?? undefined;
- const amountEffectiveStr = parsedUri.query?.get("amountEffective");
+ const summary = parsedUri.query?.["summary"] ?? "Test";
+ const iconId = parsedUri.query?.["iconId"] ?? undefined;
+ const amountEffectiveStr = parsedUri.query?.["amountEffective"];
if (!amountEffectiveStr) {
throw Error("missing amountEffective option");
}
const exchangeBaseUrl =
- parsedUri.query?.get("exchangeBaseUrl") ??
+ parsedUri.query?.["exchangeBaseUrl"] ??
"https://exchange.demo.taler.net/";
const amountEffective = Amounts.parseOrThrow(amountEffectiveStr);
- const trelStr = parsedUri.query?.get("tRel") ?? undefined;
+ const trelStr = parsedUri.query?.["tRel"] ?? undefined;
let timestamp: AbsoluteTime;
if (trelStr) {
timestamp = AbsoluteTime.subtractDuraction(
@@ -811,7 +813,7 @@ function waitMs(tMs: number): Promise<void> {
function evalFailProbability(p: number | undefined): boolean {
if (p == null) {
- return true;
+ return false;
}
return Math.random() >= p;
}