taler-typescript-core

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

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:
Mpackages/taler-util/src/taleruri.ts | 114++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mpackages/taler-wallet-core/src/dev-experiments.ts | 88++++++++++++++++++++++++++++++++++++++++---------------------------------------
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; }