diff options
5 files changed, 111 insertions, 52 deletions
diff --git a/packages/taler-util/src/taleruri.test.ts b/packages/taler-util/src/taleruri.test.ts index a6c4d89fc..ffc56a723 100644 --- a/packages/taler-util/src/taleruri.test.ts +++ b/packages/taler-util/src/taleruri.test.ts @@ -16,14 +16,16 @@ import test from "ava"; import { + parsePayPushUri, + parsePayTemplateUri, parsePayUri, - parseWithdrawUri, parseRefundUri, + parseRestoreUri, parseTipUri, - parsePayPushUri, - constructPayPushUri, - parsePayTemplateUri, - constructPayUri, + parseWithdrawUri, + stringifyPayPushUri, + stringifyPayUri, + stringifyRestoreUri, } from "./taleruri.js"; test("taler pay url parsing: wrong scheme", (t) => { @@ -220,22 +222,46 @@ test("taler peer to peer push URI (http)", (t) => { t.is(r1.contractPriv, "foo"); }); -test("taler peer to peer push URI (construction)", (t) => { - const url = constructPayPushUri({ +test("taler peer to peer push URI (stringify)", (t) => { + const url = stringifyPayPushUri({ exchangeBaseUrl: "https://foo.example.com/bla/", contractPriv: "123", }); t.deepEqual(url, "taler://pay-push/foo.example.com/bla/123"); }); - -test("taler pay URI (construction)", (t) => { - const url1 = constructPayUri("http://localhost:123/", "foo", ""); +test("taler pay URI (stringify)", (t) => { + const url1 = stringifyPayUri({ + merchantBaseUrl: "http://localhost:123/", + orderId: "foo", + sessionId: "", + }); t.deepEqual(url1, "taler+http://pay/localhost:123/foo/"); - const url2 = constructPayUri("http://localhost:123/", "foo", "bla"); + const url2 = stringifyPayUri({ + merchantBaseUrl: "http://localhost:123/", + orderId: "foo", + sessionId: "bla", + }); t.deepEqual(url2, "taler+http://pay/localhost:123/foo/bla"); }); +test("taler pay URI (stringify with https)", (t) => { + const url1 = stringifyPayUri({ + merchantBaseUrl: "https://localhost:123/", + orderId: "foo", + sessionId: "", + }); + t.deepEqual(url1, "taler://pay/localhost:123/foo/"); + + const url2 = stringifyPayUri({ + merchantBaseUrl: "https://localhost/", + orderId: "foo", + sessionId: "bla", + noncePriv: "123", + }); + t.deepEqual(url2, "taler://pay/localhost/foo/bla?n=123"); +}); + test("taler pay template URI (parsing)", (t) => { const url1 = "taler://pay-template/merchant.example.com/FEGHYJY48FEGU6WETYIOIDEDE2QW3OCZVY?amount=KUDOS:5"; @@ -261,3 +287,45 @@ test("taler pay template URI (parsing, http with port)", (t) => { t.deepEqual(r1.templateId, "FEGHYJY48FEGU6WETYIOIDEDE2QW3OCZVY"); t.deepEqual(r1.templateParams.amount, "KUDOS:5"); }); + +test("taler restore URI (parsing, http with port)", (t) => { + const r1 = parseRestoreUri( + "taler+http://restore/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0/prov1.example.com,prov2.example.com:123", + ); + if (!r1) { + t.fail(); + return; + } + t.deepEqual( + r1.walletRootPriv, + "GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0", + ); + t.deepEqual(r1.providers[0], "http://prov1.example.com/"); + t.deepEqual(r1.providers[1], "http://prov2.example.com:123/"); +}); +test("taler restore URI (parsing, https with port)", (t) => { + const r1 = parseRestoreUri( + "taler://restore/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0/prov1.example.com,prov2.example.com:234,https%3A%2F%2Fprov1.example.com%2F", + ); + if (!r1) { + t.fail(); + return; + } + t.deepEqual( + r1.walletRootPriv, + "GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0", + ); + t.deepEqual(r1.providers[0], "https://prov1.example.com/"); + t.deepEqual(r1.providers[1], "https://prov2.example.com:234/"); +}); + +test("taler restore URI (stringify)", (t) => { + const url = stringifyRestoreUri({ + walletRootPriv: "GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0", + providers: ["http://prov1.example.com", "https://prov2.example.com:234/"], + }); + t.deepEqual( + url, + "taler://restore/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0/http%3A%2F%2Fprov1.example.com%2F,https%3A%2F%2Fprov2.example.com%3A234%2F", + ); +}); diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts index e641f1d27..bd63fd103 100644 --- a/packages/taler-util/src/taleruri.ts +++ b/packages/taler-util/src/taleruri.ts @@ -35,8 +35,8 @@ export interface PayUriResult { merchantBaseUrl: string; orderId: string; sessionId: string; - claimToken: string | undefined; - noncePriv: string | undefined; + claimToken?: string; + noncePriv?: string; } export interface PayTemplateUriResult { @@ -96,10 +96,7 @@ export interface DevExperimentUri { export interface BackupRestoreUri { type: TalerUriAction.Restore; walletRootPriv: string; - providers: { - name: string; - url: string; - }[]; + providers: Array<string>; } /** @@ -535,9 +532,9 @@ export function parseRefundUri(s: string): RefundUriResult | undefined { return undefined; } const host = parts[0].toLowerCase(); - // const sessionId = parts[parts.length - 1]; - const orderId = parts[parts.length - 1]; - const pathSegments = parts.slice(1, parts.length - 1); + const sessionId = parts[parts.length - 1]; + const orderId = parts[parts.length - 2]; + const pathSegments = parts.slice(1, parts.length - 2); const hostAndSegments = [host, ...pathSegments].join("/"); const merchantBaseUrl = canonicalizeBaseUrl( `${pi.innerProto}://${hostAndSegments}/`, @@ -576,10 +573,12 @@ export function parseRestoreUri(uri: string): BackupRestoreUri | undefined { const walletRootPriv = parts[0]; if (!walletRootPriv) return undefined; - const providers = new Array<{ name: string; url: string }>(); + const providers = new Array<string>(); parts[1].split(",").map((name) => { - const url = canonicalizeBaseUrl(`${pi.innerProto}://${name}/`); - providers.push({ name, url }); + const url = canonicalizeBaseUrl( + `${pi.innerProto}://${decodeURIComponent(name)}/`, + ); + providers.push(url); }); return { type: TalerUriAction.Restore, @@ -597,10 +596,7 @@ export function parseRestoreUri(uri: string): BackupRestoreUri | undefined { */ export function constructRecoveryUri(args: { walletRootPriv: string; - providers: { - name: string; - url: string; - }[]; + providers: string[]; }): string { return stringifyRestoreUri(args); } @@ -652,26 +648,6 @@ export function stringifyPayUri({ claimToken, noncePriv, }: Omit<PayUriResult, "type">): string { - // const base = canonicalizeBaseUrl(merchantBaseUrl); - // const url = new URL(base); - // const isHttp = base.startsWith("http://"); - // let result = isHttp ? `taler+http://pay/` : `taler://pay/`; - // result += url.hostname; - // if (url.port != "") { - // result += `:${url.port}`; - // } - // result += `${url.pathname}${orderId}/${sessionId}`; - // const qp = new URLSearchParams(); - // if (claimToken) { - // qp.append("c", claimToken); - // } - // if (noncePriv) { - // qp.append("n", noncePriv); - // } - // const queryPart = qp.toString(); - // if (queryPart) { - // result += "?" + queryPart; - // } const { proto, path, query } = getUrlInfo(merchantBaseUrl, { c: claimToken, n: noncePriv, @@ -700,7 +676,9 @@ export function stringifyRestoreUri({ providers, walletRootPriv, }: Omit<BackupRestoreUri, "type">): string { - const list = providers.map((p) => `${new URL(p.url).hostname}`).join("m"); + const list = providers + .map((url) => `${encodeURIComponent(new URL(url).href)}`) + .join(","); return `taler://restore/${walletRootPriv}/${list}`; } diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts index 7814a9233..c0edc4cc1 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.test.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts @@ -25,5 +25,5 @@ function expect(t: ExecutionContext, thing: any): any { } test("should have a test", (t) => { - expect(t, true).equal(true); + expect(t, true).deep.equal(true); }); diff --git a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts index fcf5e309f..aa4942c4e 100644 --- a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts @@ -59,7 +59,13 @@ export function useComponentState({ async function recoverBackup(): Promise<void> { await api.wallet.call(WalletApiOperation.ImportBackupRecovery, { - recovery, + recovery: { + walletRootPriv: recovery.walletRootPriv, + providers: recovery.providers.map((url) => ({ + name: new URL(url).hostname, + url, + })), + }, }); onSuccess(); } diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx index c3abb570b..ea1adbc73 100644 --- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx @@ -14,7 +14,11 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AbsoluteTime, constructRecoveryUri } from "@gnu-taler/taler-util"; +import { + AbsoluteTime, + constructRecoveryUri, + stringifyRestoreUri, +} from "@gnu-taler/taler-util"; import { ProviderInfo, ProviderPaymentPaid, @@ -132,7 +136,10 @@ export function BackupPage({ onAddProvider }: Props): VNode { WalletApiOperation.ExportBackupRecovery, {}, ); - const str = constructRecoveryUri(r); + const str = stringifyRestoreUri({ + walletRootPriv: r.walletRootPriv, + providers: r.providers.map((p) => p.url), + }); setRecoveryInfo(str); } |