taler-typescript-core

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

commit cb1beccfe021351323ce032257941972638820e3
parent f3aa21b26baf2d0e4aa463f0886012eb1031cec7
Author: Sebastian <sebasjm@gmail.com>
Date:   Wed, 22 Oct 2025 13:49:19 -0300

add missing payto helper unit test

Diffstat:
Mpackages/taler-util/src/payto.test.ts | 1+
Mpackages/taler-util/src/payto.ts | 47+++++++++++++++++++++++++++++++++--------------
Apackages/taler-util/src/paytos.test.ts | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 125 insertions(+), 14 deletions(-)

diff --git a/packages/taler-util/src/payto.test.ts b/packages/taler-util/src/payto.test.ts @@ -18,6 +18,7 @@ import test from "ava"; import { PaytoString, + Paytos, addPaytoQueryParams, parsePaytoUri, stringifyPaytoUri, diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts @@ -150,7 +150,12 @@ export namespace Paytos { export interface PaytoTalerBank extends PaytoGeneric { targetType: PaytoType.TalerBank; - host: HostPortPath; + /** + * this is kept to keep compatiblity with old parser + * @deprecated use URL + */ + host: string; + url: HostPortPath; account: string; } @@ -250,7 +255,7 @@ export namespace Paytos { try { // https://url.spec.whatwg.org/#concept-basic-url-parser if (path === undefined) { - path = "" + path = ""; } if (!path.endsWith("/")) { path = path + "/"; @@ -262,15 +267,24 @@ export namespace Paytos { url.hash = ""; return url.href as HostPortPath; } catch (e) { - console.log(e) + console.log(e); return undefined; } } + function withoutScheme(h: HostPortPath): HostPortPath { + return ( + h.startsWith("http://") + ? h.substring(7) + : h.startsWith("https://") + ? h.substring(8) + : h + ) as HostPortPath; + } /** * Same as `parseHostPortPath2` but only takes one string. * This should be the definitive signature. * https://bugs.gnunet.org/view.php?id=10467 - * + * * @param hostnameAndPath * @returns */ @@ -374,15 +388,16 @@ export namespace Paytos { reservePub: Uint8Array, params: Record<string, string> = {}, ): PaytoTalerReserve { + const path = withoutScheme(exchange); const pub = encodeCrock(reservePub); return { targetType: PaytoType.TalerReserve, exchange, reservePub, params, - normalizedPath: `${exchange.toLocaleLowerCase()}/${pub}`, - fullPath: `${exchange}/${pub}`, - displayName: `${exchange}@${pub}`, + normalizedPath: `${path.toLocaleLowerCase()}${pub}`, + fullPath: `${path}${pub}`, + displayName: `${path}@${pub}`, }; } export function createTalerReserveHttp( @@ -390,30 +405,34 @@ export namespace Paytos { reservePub: Uint8Array, params: Record<string, string> = {}, ): PaytoTalerReserveHttp { + const path = withoutScheme(exchange); const pub = encodeCrock(reservePub); return { targetType: PaytoType.TalerReserveHttp, exchange, reservePub, params, - normalizedPath: `${exchange.toLocaleLowerCase()}/${pub}`, - fullPath: `${exchange}/${pub}`, - displayName: `${exchange}@${pub}`, + normalizedPath: `${path.toLocaleLowerCase()}${pub}`, + fullPath: `${path}${pub}`, + displayName: `${path}@${pub}`, }; } export function createTalerBank( - host: HostPortPath, + url: HostPortPath, account: string, params: Record<string, string> = {}, ): PaytoTalerBank { + const path = withoutScheme(url); + const host = path.endsWith("/") ? path.substring(0, path.length - 1) : path; return { targetType: PaytoType.TalerBank, host, + url, account, params, - normalizedPath: `${host.toLocaleLowerCase()}/${account}`, - fullPath: `${host}/${account}`, - displayName: `${account}@${host}`, + normalizedPath: `${path.toLocaleLowerCase()}${account}`, + fullPath: `${path}${account}`, + displayName: `${account}@${url}`, }; } diff --git a/packages/taler-util/src/paytos.test.ts b/packages/taler-util/src/paytos.test.ts @@ -0,0 +1,91 @@ +/* + This file is part of GNU Taler + (C) 2019 GNUnet e.V. + + 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/> + */ + +import test from "ava"; + +import { HostPortPath, PaytoType, Paytos } from "./payto.js"; +import { succeedOrThrow } from "./index.js"; + +test("basic payto parsing", (t) => { + const r1 = Paytos.fromString("https://example.com/"); + t.is(r1.type, "fail"); + + const r2 = Paytos.fromString("payto:blabla"); + t.is(r2.type, "fail"); + + // this doesn't work because x-taler-bank requires host and account + const r3 = Paytos.fromString("payto:://x-taler-bank/12"); + t.is(r3.type, "fail"); + + const r4 = Paytos.fromString("payto://x-taler-bank/host/account"); + if (r4.type === "fail") { + t.fail(); + throw Error(); + } + if (r4.body.targetType !== PaytoType.TalerBank) { + t.fail(r4.body.targetType); + throw Error(); + } + t.is(r4.body.normalizedPath, "host/account"); +}); + +test("basic x-taler-bank payto string", (t) => { + const result = succeedOrThrow( + Paytos.fromString("payto://x-taler-bank/bank.demo.taler.net/accountName"), + ); + + if (result.targetType !== PaytoType.TalerBank) { + t.fail(); + throw Error(); + } + t.is(result.normalizedPath, "bank.demo.taler.net/accountName"); + t.is(result.host, "bank.demo.taler.net"); + t.is(result.url, "https://bank.demo.taler.net/" as HostPortPath); + t.is(result.account, "accountName"); +}); + +test("parsing payto and stringify again", (t) => { + const payto1 = "payto://iban/DE1231231231?reciever-name=John%20Doe"; + t.is( + Paytos.toFullString(succeedOrThrow(Paytos.fromString(payto1))), + payto1 as Paytos.FullPaytoString, + ); + + const normalized = "payto://iban/de1231231231"; + t.is( + Paytos.toNormalizedString(succeedOrThrow(Paytos.fromString(payto1))), + normalized as Paytos.NormalizedPaytoString, + ); +}); +test("parsing payto with % carh", (t) => { + const payto1 = + "payto://iban/DE7763544441436?receiver-name=Test%20123%2B-%24%25%5E%3Cem%3Ehi%3C%2Fem%3E" as Paytos.FullPaytoString; + + t.is(Paytos.toFullString(succeedOrThrow(Paytos.fromString(payto1))), payto1); +}); + +test("adding payto query params", (t) => { + const payto1 = + "payto://iban/DE1231231231?receiver-name=John%20Doe" as Paytos.FullPaytoString; + const p = succeedOrThrow(Paytos.fromString(payto1)); + + p.params["foo"] = "42"; + + t.deepEqual( + Paytos.toFullString(p), + "payto://iban/DE1231231231?receiver-name=John%20Doe&foo=42", + ); +});