taler-typescript-core

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

commit f350a371605a98cdad36026dcc699ae844782584
parent 75a69a3646ad58a5df37abd784fe015b43adf0b0
Author: Florian Dold <dold@taler.net>
Date:   Tue, 21 Jul 2026 20:17:10 +0200

util: test that codecForURLString validates its value

Diffstat:
Mpackages/taler-util/src/types-taler-common.test.ts | 44++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+), 0 deletions(-)

diff --git a/packages/taler-util/src/types-taler-common.test.ts b/packages/taler-util/src/types-taler-common.test.ts @@ -17,6 +17,7 @@ import assert from "node:assert"; import { test } from "node:test"; import { Codec } from "./codec.js"; +import * as bankIntegration from "./types-taler-bank-integration.js"; import * as common from "./types-taler-common.js"; // Resolved dynamically so this file compiles before the codec exists. @@ -84,3 +85,46 @@ test("the corebank codec rejects a merchant token listing", (t) => { const codec = codecForBankTokenInfoList(); assert.throws(() => codec.decode(merchantTokenList)); }); + +test("codecForURLString validates that the value is an http(s) URL", (t) => { + const codec = common.codecForURLString(); + for (const ok of [ + "https://exchange.example/", + "http://localhost:8081/", + "https://merchant.example/orders/1?token=x", + ]) { + assert.strictEqual(codec.decode(ok), ok); + } + // These fields are opened by the browser or fetched over HTTP, so a URL + // that parses is not enough -- the scheme has to be one we would follow. + for (const bad of [ + "javascript:alert(document.cookie)//", + "data:text/html,<script>alert(1)</script>", + "file:///etc/passwd", + "not a url at all", + "/relative/path", + ]) { + assert.throws(() => codec.decode(bad), `accepted ${bad}`); + } + assert.throws(() => codec.decode(42 as any)); +}); + +test("a hostile confirm_transfer_url is rejected at the wire boundary", (t) => { + // The web extension assigns this field to document.location.href. + const status = { + status: "selected", + amount: "KUDOS:1", + currency: "KUDOS", + card_fees: "KUDOS:0", + sender_wire: "payto://iban/DE75512108001245126199", + suggested_exchange: "https://exchange.example/", + confirm_transfer_url: "javascript:alert(document.cookie)//", + wire_types: ["iban"], + aborted: false, + selection_done: true, + transfer_done: false, + }; + assert.throws(() => + bankIntegration.codecForBankWithdrawalOperationStatus().decode(status), + ); +});