From ee1fc03ae82f2f4662041af3d4243113e92ffeaf Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 6 Dec 2019 12:47:28 +0100 Subject: case-insensitive URIs --- src/util/taleruri-test.ts | 55 ++++++++++---------------------- src/util/taleruri.ts | 81 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 82 insertions(+), 54 deletions(-) (limited to 'src/util') diff --git a/src/util/taleruri-test.ts b/src/util/taleruri-test.ts index c687a6717..de4a90697 100644 --- a/src/util/taleruri-test.ts +++ b/src/util/taleruri-test.ts @@ -22,23 +22,6 @@ import { parseTipUri, } from "./taleruri"; -test("taler pay url parsing: http(s)", t => { - const url1 = "https://example.com/bar?spam=eggs"; - const r1 = parsePayUri(url1); - if (!r1) { - t.fail(); - return; - } - t.is(r1.downloadUrl, url1); - t.is(r1.sessionId, undefined); - const url2 = "http://example.com/bar?spam=eggs"; - const r2 = parsePayUri(url2); - if (!r2) { - t.fail(); - return; - } -}); - test("taler pay url parsing: wrong scheme", t => { const url1 = "talerfoo://"; const r1 = parsePayUri(url1); @@ -56,7 +39,7 @@ test("taler pay url parsing: defaults", t => { t.fail(); return; } - t.is(r1.downloadUrl, "https://example.com/public/proposal?order_id=myorder"); + t.is(r1.merchantBaseUrl, "https://example.com/public/"); t.is(r1.sessionId, undefined); const url2 = "taler://pay/example.com/-/-/myorder/mysession"; @@ -65,7 +48,7 @@ test("taler pay url parsing: defaults", t => { t.fail(); return; } - t.is(r2.downloadUrl, "https://example.com/public/proposal?order_id=myorder"); + t.is(r2.merchantBaseUrl, "https://example.com/public/"); t.is(r2.sessionId, "mysession"); }); @@ -76,7 +59,7 @@ test("taler pay url parsing: trailing parts", t => { t.fail(); return; } - t.is(r1.downloadUrl, "https://example.com/public/proposal?order_id=myorder"); + t.is(r1.merchantBaseUrl, "https://example.com/public/"); t.is(r1.sessionId, "mysession"); }); @@ -87,10 +70,8 @@ test("taler pay url parsing: instance", t => { t.fail(); return; } - t.is( - r1.downloadUrl, - "https://example.com/public/instances/myinst/proposal?order_id=myorder", - ); + t.is(r1.merchantBaseUrl, "https://example.com/public/instances/myinst/"); + t.is(r1.orderId, "myorder"); }); test("taler pay url parsing: path prefix and instance", t => { @@ -100,10 +81,7 @@ test("taler pay url parsing: path prefix and instance", t => { t.fail(); return; } - t.is( - r1.downloadUrl, - "https://example.com/mypfx/instances/myinst/proposal?order_id=myorder", - ); + t.is(r1.merchantBaseUrl, "https://example.com/mypfx/instances/myinst/"); }); test("taler pay url parsing: complex path prefix", t => { @@ -113,10 +91,9 @@ test("taler pay url parsing: complex path prefix", t => { t.fail(); return; } - t.is( - r1.downloadUrl, - "https://example.com/mypfx/public/proposal?order_id=myorder", - ); + t.is(r1.merchantBaseUrl, "https://example.com/mypfx/public/"); + t.is(r1.orderId, "myorder"); + t.is(r1.sessionId, undefined); }); test("taler pay url parsing: complex path prefix and instance", t => { @@ -126,10 +103,8 @@ test("taler pay url parsing: complex path prefix and instance", t => { t.fail(); return; } - t.is( - r1.downloadUrl, - "https://example.com/mypfx/public/instances/foo/proposal?order_id=myorder", - ); + t.is(r1.merchantBaseUrl, "https://example.com/mypfx/public/instances/foo/"); + t.is(r1.orderId, "myorder"); }); test("taler pay url parsing: non-https #1", t => { @@ -138,8 +113,9 @@ test("taler pay url parsing: non-https #1", t => { if (!r1) { t.fail(); return; - } - t.is(r1.downloadUrl, "http://example.com/public/proposal?order_id=myorder"); + } + t.is(r1.merchantBaseUrl, "http://example.com/public/"); + t.is(r1.orderId, "myorder") }); test("taler pay url parsing: non-https #2", t => { @@ -149,7 +125,8 @@ test("taler pay url parsing: non-https #2", t => { t.fail(); return; } - t.is(r1.downloadUrl, "https://example.com/public/proposal?order_id=myorder"); + t.is(r1.merchantBaseUrl, "https://example.com/public/"); + t.is(r1.orderId, "myorder"); }); test("taler withdraw uri parsing", t => { diff --git a/src/util/taleruri.ts b/src/util/taleruri.ts index 50886a916..f34b82a59 100644 --- a/src/util/taleruri.ts +++ b/src/util/taleruri.ts @@ -15,7 +15,8 @@ */ export interface PayUriResult { - downloadUrl: string; + merchantBaseUrl: string; + orderId: string; sessionId?: string; } @@ -36,7 +37,7 @@ export interface TipUriResult { export function parseWithdrawUri(s: string): WithdrawUriResult | undefined { const pfx = "taler://withdraw/"; - if (!s.startsWith(pfx)) { + if (!s.toLowerCase().startsWith(pfx)) { return undefined; } @@ -44,6 +45,20 @@ export function parseWithdrawUri(s: string): WithdrawUriResult | undefined { let [host, path, withdrawId] = rest.split("/"); + if (!host) { + return undefined; + } + + host = host.toLowerCase(); + + if (!path) { + return undefined; + } + + if (!withdrawId) { + return undefined; + } + if (path === "-") { path = "api/withdraw-operation"; } @@ -53,15 +68,45 @@ export function parseWithdrawUri(s: string): WithdrawUriResult | undefined { }; } -export function parsePayUri(s: string): PayUriResult | undefined { - if (s.startsWith("https://") || s.startsWith("http://")) { - return { - downloadUrl: s, - sessionId: undefined, - }; +export const enum TalerUriType { + TalerPay = "taler-pay", + TalerWithdraw = "taler-withdraw", + TalerTip = "taler-tip", + TalerRefund = "taler-refund", + TalerNotifyReserve = "taler-notify-reserve", + Unknown = "unknown", +} + +export function classifyTalerUri(s: string): TalerUriType { + const sl = s.toLowerCase(); + if (sl.startsWith("taler://pay/")) { + return TalerUriType.TalerPay; } + if (sl.startsWith("taler://tip/")) { + return TalerUriType.TalerTip; + } + if (sl.startsWith("taler://refund/")) { + return TalerUriType.TalerRefund; + } + if (sl.startsWith("taler://withdraw/")) { + return TalerUriType.TalerWithdraw; + } + if (sl.startsWith("taler://notify-reserve/")) { + return TalerUriType.TalerWithdraw; + } + return TalerUriType.Unknown; + +} + +export function getOrderDownloadUrl(merchantBaseUrl: string, orderId: string) { + const u = new URL("proposal", merchantBaseUrl); + u.searchParams.set("order_id", orderId); + return u.href +} + +export function parsePayUri(s: string): PayUriResult | undefined { const pfx = "taler://pay/"; - if (!s.startsWith(pfx)) { + if (!s.toLowerCase().startsWith(pfx)) { return undefined; } @@ -75,6 +120,8 @@ export function parsePayUri(s: string): PayUriResult | undefined { return undefined; } + host = host.toLowerCase(); + if (!maybePath) { return undefined; } @@ -99,21 +146,21 @@ export function parsePayUri(s: string): PayUriResult | undefined { protocol = "http"; } - const downloadUrl = + const merchantBaseUrl = `${protocol}://${host}/` + decodeURIComponent(maybePath) + - maybeInstancePath + - `proposal?order_id=${orderId}`; + maybeInstancePath; return { - downloadUrl, + merchantBaseUrl, + orderId, sessionId: maybeSessionid, }; } export function parseTipUri(s: string): TipUriResult | undefined { const pfx = "taler://tip/"; - if (!s.startsWith(pfx)) { + if (!s.toLowerCase().startsWith(pfx)) { return undefined; } @@ -125,6 +172,8 @@ export function parseTipUri(s: string): TipUriResult | undefined { return undefined; } + host = host.toLowerCase(); + if (!maybePath) { return undefined; } @@ -155,7 +204,7 @@ export function parseTipUri(s: string): TipUriResult | undefined { export function parseRefundUri(s: string): RefundUriResult | undefined { const pfx = "taler://refund/"; - if (!s.startsWith(pfx)) { + if (!s.toLowerCase().startsWith(pfx)) { return undefined; } @@ -167,6 +216,8 @@ export function parseRefundUri(s: string): RefundUriResult | undefined { return undefined; } + host = host.toLowerCase(); + if (!maybePath) { return undefined; } -- cgit v1.2.3