new taler:// URI syntax
This commit is contained in:
parent
694d913d1f
commit
ae111663f4
@ -66,9 +66,11 @@ export async function getTipStatus(
|
|||||||
|
|
||||||
const amount = Amounts.parseOrThrow(tipPickupStatus.amount);
|
const amount = Amounts.parseOrThrow(tipPickupStatus.amount);
|
||||||
|
|
||||||
|
const merchantOrigin = new URL(res.merchantBaseUrl).origin;
|
||||||
|
|
||||||
let tipRecord = await ws.db.get(Stores.tips, [
|
let tipRecord = await ws.db.get(Stores.tips, [
|
||||||
res.merchantTipId,
|
res.merchantTipId,
|
||||||
res.merchantOrigin,
|
merchantOrigin,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!tipRecord) {
|
if (!tipRecord) {
|
||||||
@ -117,7 +119,7 @@ export async function getTipStatus(
|
|||||||
amountLeft: Amounts.parseOrThrow(tipPickupStatus.amount_left),
|
amountLeft: Amounts.parseOrThrow(tipPickupStatus.amount_left),
|
||||||
exchangeUrl: tipPickupStatus.exchange_url,
|
exchangeUrl: tipPickupStatus.exchange_url,
|
||||||
nextUrl: tipPickupStatus.extra.next_url,
|
nextUrl: tipPickupStatus.extra.next_url,
|
||||||
merchantOrigin: res.merchantOrigin,
|
merchantOrigin: merchantOrigin,
|
||||||
merchantTipId: res.merchantTipId,
|
merchantTipId: res.merchantTipId,
|
||||||
expirationTimestamp: tipPickupStatus.stamp_expire,
|
expirationTimestamp: tipPickupStatus.stamp_expire,
|
||||||
timestamp: tipPickupStatus.stamp_created,
|
timestamp: tipPickupStatus.stamp_created,
|
||||||
|
@ -141,7 +141,11 @@ export async function getBankWithdrawalInfo(
|
|||||||
if (!uriResult) {
|
if (!uriResult) {
|
||||||
throw Error(`can't parse URL ${talerWithdrawUri}`);
|
throw Error(`can't parse URL ${talerWithdrawUri}`);
|
||||||
}
|
}
|
||||||
const resp = await ws.http.get(uriResult.statusUrl);
|
const reqUrl = new URL(
|
||||||
|
`api/withdraw-operations/${uriResult.withdrawalOperationId}`,
|
||||||
|
uriResult.bankIntegrationApiBaseUrl,
|
||||||
|
);
|
||||||
|
const resp = await ws.http.get(reqUrl.href);
|
||||||
const status = await readSuccessResponseJsonOrThrow(
|
const status = await readSuccessResponseJsonOrThrow(
|
||||||
resp,
|
resp,
|
||||||
codecForWithdrawOperationStatusResponse(),
|
codecForWithdrawOperationStatusResponse(),
|
||||||
@ -150,7 +154,7 @@ export async function getBankWithdrawalInfo(
|
|||||||
return {
|
return {
|
||||||
amount: Amounts.parseOrThrow(status.amount),
|
amount: Amounts.parseOrThrow(status.amount),
|
||||||
confirmTransferUrl: status.confirm_transfer_url,
|
confirmTransferUrl: status.confirm_transfer_url,
|
||||||
extractedStatusUrl: uriResult.statusUrl,
|
extractedStatusUrl: uriResult.bankIntegrationApiBaseUrl,
|
||||||
selectionDone: status.selection_done,
|
selectionDone: status.selection_done,
|
||||||
senderWire: status.sender_wire,
|
senderWire: status.sender_wire,
|
||||||
suggestedExchange: status.suggested_exchange,
|
suggestedExchange: status.suggested_exchange,
|
||||||
|
@ -33,136 +33,93 @@ test("taler pay url parsing: wrong scheme", (t) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("taler pay url parsing: defaults", (t) => {
|
test("taler pay url parsing: defaults", (t) => {
|
||||||
const url1 = "taler://pay/example.com/-/-/myorder";
|
const url1 = "taler://pay/example.com/myorder/";
|
||||||
const r1 = parsePayUri(url1);
|
const r1 = parsePayUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.merchantBaseUrl, "https://example.com/public/");
|
t.is(r1.merchantBaseUrl, "https://example.com/");
|
||||||
t.is(r1.sessionId, undefined);
|
t.is(r1.sessionId, "");
|
||||||
|
|
||||||
const url2 = "taler://pay/example.com/-/-/myorder/mysession";
|
const url2 = "taler://pay/example.com/myorder/mysession";
|
||||||
const r2 = parsePayUri(url2);
|
const r2 = parsePayUri(url2);
|
||||||
if (!r2) {
|
if (!r2) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r2.merchantBaseUrl, "https://example.com/public/");
|
t.is(r2.merchantBaseUrl, "https://example.com/");
|
||||||
t.is(r2.sessionId, "mysession");
|
t.is(r2.sessionId, "mysession");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler pay url parsing: trailing parts", (t) => {
|
|
||||||
const url1 = "taler://pay/example.com/-/-/myorder/mysession/spam/eggs";
|
|
||||||
const r1 = parsePayUri(url1);
|
|
||||||
if (!r1) {
|
|
||||||
t.fail();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
t.is(r1.merchantBaseUrl, "https://example.com/public/");
|
|
||||||
t.is(r1.sessionId, "mysession");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("taler pay url parsing: instance", (t) => {
|
test("taler pay url parsing: instance", (t) => {
|
||||||
const url1 = "taler://pay/example.com/-/myinst/myorder";
|
const url1 = "taler://pay/example.com/instances/myinst/myorder/";
|
||||||
const r1 = parsePayUri(url1);
|
const r1 = parsePayUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.merchantBaseUrl, "https://example.com/public/instances/myinst/");
|
t.is(r1.merchantBaseUrl, "https://example.com/instances/myinst/");
|
||||||
t.is(r1.orderId, "myorder");
|
t.is(r1.orderId, "myorder");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler pay url parsing: path prefix and instance", (t) => {
|
|
||||||
const url1 = "taler://pay/example.com/mypfx/myinst/myorder";
|
|
||||||
const r1 = parsePayUri(url1);
|
|
||||||
if (!r1) {
|
|
||||||
t.fail();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
t.is(r1.merchantBaseUrl, "https://example.com/mypfx/instances/myinst/");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("taler pay url parsing: complex path prefix", (t) => {
|
|
||||||
const url1 = "taler://pay/example.com/mypfx%2Fpublic/-/myorder";
|
|
||||||
const r1 = parsePayUri(url1);
|
|
||||||
if (!r1) {
|
|
||||||
t.fail();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
t.is(r1.merchantBaseUrl, "https://example.com/mypfx/public/");
|
|
||||||
t.is(r1.orderId, "myorder");
|
|
||||||
t.is(r1.sessionId, undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("taler pay uri parsing: complex path prefix and instance", (t) => {
|
|
||||||
const url1 = "taler://pay/example.com/mypfx%2Fpublic/foo/myorder";
|
|
||||||
const r1 = parsePayUri(url1);
|
|
||||||
if (!r1) {
|
|
||||||
t.fail();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
t.is(r1.merchantBaseUrl, "https://example.com/mypfx/public/instances/foo/");
|
|
||||||
t.is(r1.orderId, "myorder");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("taler refund uri parsing: non-https #1", (t) => {
|
test("taler refund uri parsing: non-https #1", (t) => {
|
||||||
const url1 = "taler://refund/example.com/-/-/myorder?insecure=1";
|
const url1 = "taler+http://refund/example.com/myorder";
|
||||||
const r1 = parseRefundUri(url1);
|
const r1 = parseRefundUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.merchantBaseUrl, "http://example.com/public/");
|
t.is(r1.merchantBaseUrl, "http://example.com/");
|
||||||
t.is(r1.orderId, "myorder");
|
t.is(r1.orderId, "myorder");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler pay uri parsing: non-https #1", (t) => {
|
test("taler pay uri parsing: non-https", (t) => {
|
||||||
const url1 = "taler://pay/example.com/-/-/myorder?insecure=1";
|
const url1 = "taler+http://pay/example.com/myorder/";
|
||||||
const r1 = parsePayUri(url1);
|
const r1 = parsePayUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.merchantBaseUrl, "http://example.com/public/");
|
t.is(r1.merchantBaseUrl, "http://example.com/");
|
||||||
t.is(r1.orderId, "myorder");
|
t.is(r1.orderId, "myorder");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler pay url parsing: non-https #2", (t) => {
|
test("taler pay uri parsing: missing session component", (t) => {
|
||||||
const url1 = "taler://pay/example.com/-/-/myorder?insecure=2";
|
const url1 = "taler+http://pay/example.com/myorder";
|
||||||
const r1 = parsePayUri(url1);
|
const r1 = parsePayUri(url1);
|
||||||
if (!r1) {
|
if (r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.merchantBaseUrl, "https://example.com/public/");
|
t.pass();
|
||||||
t.is(r1.orderId, "myorder");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler withdraw uri parsing", (t) => {
|
test("taler withdraw uri parsing", (t) => {
|
||||||
const url1 = "taler://withdraw/bank.example.com/-/12345";
|
const url1 = "taler://withdraw/bank.example.com/12345";
|
||||||
const r1 = parseWithdrawUri(url1);
|
const r1 = parseWithdrawUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.statusUrl, "https://bank.example.com/api/withdraw-operation/12345");
|
t.is(r1.withdrawalOperationId, "12345");
|
||||||
|
t.is(r1.bankIntegrationApiBaseUrl, "https://bank.example.com/");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler refund uri parsing", (t) => {
|
test("taler refund uri parsing", (t) => {
|
||||||
const url1 = "taler://refund/merchant.example.com/-/-/1234";
|
const url1 = "taler://refund/merchant.example.com/1234";
|
||||||
const r1 = parseRefundUri(url1);
|
const r1 = parseRefundUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.merchantBaseUrl, "https://merchant.example.com/public/");
|
t.is(r1.merchantBaseUrl, "https://merchant.example.com/");
|
||||||
t.is(r1.orderId, "1234");
|
t.is(r1.orderId, "1234");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler refund uri parsing with instance", (t) => {
|
test("taler refund uri parsing with instance", (t) => {
|
||||||
const url1 = "taler://refund/merchant.example.com/-/myinst/1234";
|
const url1 = "taler://refund/merchant.example.com/instances/myinst/1234";
|
||||||
const r1 = parseRefundUri(url1);
|
const r1 = parseRefundUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
@ -171,22 +128,22 @@ test("taler refund uri parsing with instance", (t) => {
|
|||||||
t.is(r1.orderId, "1234");
|
t.is(r1.orderId, "1234");
|
||||||
t.is(
|
t.is(
|
||||||
r1.merchantBaseUrl,
|
r1.merchantBaseUrl,
|
||||||
"https://merchant.example.com/public/instances/myinst/",
|
"https://merchant.example.com/instances/myinst/",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler tip pickup uri", (t) => {
|
test("taler tip pickup uri", (t) => {
|
||||||
const url1 = "taler://tip/merchant.example.com/-/-/tipid";
|
const url1 = "taler://tip/merchant.example.com/tipid";
|
||||||
const r1 = parseTipUri(url1);
|
const r1 = parseTipUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t.is(r1.merchantBaseUrl, "https://merchant.example.com/public/");
|
t.is(r1.merchantBaseUrl, "https://merchant.example.com/");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler tip pickup uri with instance", (t) => {
|
test("taler tip pickup uri with instance", (t) => {
|
||||||
const url1 = "taler://tip/merchant.example.com/-/tipm/tipid";
|
const url1 = "taler://tip/merchant.example.com/instances/tipm/tipid";
|
||||||
const r1 = parseTipUri(url1);
|
const r1 = parseTipUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
@ -194,13 +151,13 @@ test("taler tip pickup uri with instance", (t) => {
|
|||||||
}
|
}
|
||||||
t.is(
|
t.is(
|
||||||
r1.merchantBaseUrl,
|
r1.merchantBaseUrl,
|
||||||
"https://merchant.example.com/public/instances/tipm/",
|
"https://merchant.example.com/instances/tipm/",
|
||||||
);
|
);
|
||||||
t.is(r1.merchantTipId, "tipid");
|
t.is(r1.merchantTipId, "tipid");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("taler tip pickup uri with instance and prefix", (t) => {
|
test("taler tip pickup uri with instance and prefix", (t) => {
|
||||||
const url1 = "taler://tip/merchant.example.com/my%2fpfx/tipm/tipid";
|
const url1 = "taler://tip/merchant.example.com/my/pfx/tipm/tipid";
|
||||||
const r1 = parseTipUri(url1);
|
const r1 = parseTipUri(url1);
|
||||||
if (!r1) {
|
if (!r1) {
|
||||||
t.fail();
|
t.fail();
|
||||||
@ -208,7 +165,7 @@ test("taler tip pickup uri with instance and prefix", (t) => {
|
|||||||
}
|
}
|
||||||
t.is(
|
t.is(
|
||||||
r1.merchantBaseUrl,
|
r1.merchantBaseUrl,
|
||||||
"https://merchant.example.com/my/pfx/instances/tipm/",
|
"https://merchant.example.com/my/pfx/tipm/",
|
||||||
);
|
);
|
||||||
t.is(r1.merchantTipId, "tipid");
|
t.is(r1.merchantTipId, "tipid");
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of GNU Taler
|
This file is part of GNU Taler
|
||||||
(C) 2019 GNUnet e.V.
|
(C) 2019-2020 Taler Systems S.A.
|
||||||
|
|
||||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
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
|
terms of the GNU General Public License as published by the Free Software
|
||||||
@ -17,11 +17,12 @@
|
|||||||
export interface PayUriResult {
|
export interface PayUriResult {
|
||||||
merchantBaseUrl: string;
|
merchantBaseUrl: string;
|
||||||
orderId: string;
|
orderId: string;
|
||||||
sessionId?: string;
|
sessionId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WithdrawUriResult {
|
export interface WithdrawUriResult {
|
||||||
statusUrl: string;
|
bankIntegrationApiBaseUrl: string;
|
||||||
|
withdrawalOperationId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RefundUriResult {
|
export interface RefundUriResult {
|
||||||
@ -31,10 +32,13 @@ export interface RefundUriResult {
|
|||||||
|
|
||||||
export interface TipUriResult {
|
export interface TipUriResult {
|
||||||
merchantTipId: string;
|
merchantTipId: string;
|
||||||
merchantOrigin: string;
|
|
||||||
merchantBaseUrl: string;
|
merchantBaseUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a taler[+http]://withdraw URI.
|
||||||
|
* Return undefined if not passed a valid URI.
|
||||||
|
*/
|
||||||
export function parseWithdrawUri(s: string): WithdrawUriResult | undefined {
|
export function parseWithdrawUri(s: string): WithdrawUriResult | undefined {
|
||||||
const pfx = "taler://withdraw/";
|
const pfx = "taler://withdraw/";
|
||||||
if (!s.toLowerCase().startsWith(pfx)) {
|
if (!s.toLowerCase().startsWith(pfx)) {
|
||||||
@ -42,29 +46,20 @@ export function parseWithdrawUri(s: string): WithdrawUriResult | undefined {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rest = s.substring(pfx.length);
|
const rest = s.substring(pfx.length);
|
||||||
|
const parts = rest.split("/");
|
||||||
|
|
||||||
let [host, path, withdrawId] = rest.split("/");
|
if (parts.length < 2) {
|
||||||
|
|
||||||
if (!host) {
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
host = host.toLowerCase();
|
const host = parts[0].toLowerCase();
|
||||||
|
const pathSegments = parts.slice(1, parts.length - 1);
|
||||||
if (!path) {
|
const withdrawId = parts[parts.length - 1];
|
||||||
return undefined;
|
const p = [host, ...pathSegments].join("/");
|
||||||
}
|
|
||||||
|
|
||||||
if (!withdrawId) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === "-") {
|
|
||||||
path = "api/withdraw-operation";
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusUrl: `https://${host}/${path}/${withdrawId}`,
|
bankIntegrationApiBaseUrl: `https://${p}/`,
|
||||||
|
withdrawalOperationId: withdrawId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,17 +72,29 @@ export const enum TalerUriType {
|
|||||||
Unknown = "unknown",
|
Unknown = "unknown",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classify a taler:// URI.
|
||||||
|
*/
|
||||||
export function classifyTalerUri(s: string): TalerUriType {
|
export function classifyTalerUri(s: string): TalerUriType {
|
||||||
const sl = s.toLowerCase();
|
const sl = s.toLowerCase();
|
||||||
if (sl.startsWith("taler://pay/")) {
|
if (sl.startsWith("taler://pay/")) {
|
||||||
return TalerUriType.TalerPay;
|
return TalerUriType.TalerPay;
|
||||||
}
|
}
|
||||||
|
if (sl.startsWith("taler+http://pay/")) {
|
||||||
|
return TalerUriType.TalerPay;
|
||||||
|
}
|
||||||
if (sl.startsWith("taler://tip/")) {
|
if (sl.startsWith("taler://tip/")) {
|
||||||
return TalerUriType.TalerTip;
|
return TalerUriType.TalerTip;
|
||||||
}
|
}
|
||||||
|
if (sl.startsWith("taler+http://tip/")) {
|
||||||
|
return TalerUriType.TalerTip;
|
||||||
|
}
|
||||||
if (sl.startsWith("taler://refund/")) {
|
if (sl.startsWith("taler://refund/")) {
|
||||||
return TalerUriType.TalerRefund;
|
return TalerUriType.TalerRefund;
|
||||||
}
|
}
|
||||||
|
if (sl.startsWith("taler+http://refund/")) {
|
||||||
|
return TalerUriType.TalerRefund;
|
||||||
|
}
|
||||||
if (sl.startsWith("taler://withdraw/")) {
|
if (sl.startsWith("taler://withdraw/")) {
|
||||||
return TalerUriType.TalerWithdraw;
|
return TalerUriType.TalerWithdraw;
|
||||||
}
|
}
|
||||||
@ -97,146 +104,103 @@ export function classifyTalerUri(s: string): TalerUriType {
|
|||||||
return TalerUriType.Unknown;
|
return TalerUriType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TalerUriProtoInfo {
|
||||||
|
innerProto: "http" | "https";
|
||||||
|
rest: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function parseProtoInfo(s: string, action: string): TalerUriProtoInfo | undefined {
|
||||||
|
const pfxPlain = `taler://${action}/`;
|
||||||
|
const pfxHttp = `taler+http://${action}/`;
|
||||||
|
if (s.toLowerCase().startsWith(pfxPlain)) {
|
||||||
|
return {
|
||||||
|
innerProto: "https",
|
||||||
|
rest: s.substring(pfxPlain.length),
|
||||||
|
}
|
||||||
|
} else if (s.toLowerCase().startsWith(pfxHttp)) {
|
||||||
|
return {
|
||||||
|
innerProto: "http",
|
||||||
|
rest: s.substring(pfxHttp.length),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a taler[+http]://pay URI.
|
||||||
|
* Return undefined if not passed a valid URI.
|
||||||
|
*/
|
||||||
export function parsePayUri(s: string): PayUriResult | undefined {
|
export function parsePayUri(s: string): PayUriResult | undefined {
|
||||||
const pfx = "taler://pay/";
|
const pi = parseProtoInfo(s, "pay");
|
||||||
if (!s.toLowerCase().startsWith(pfx)) {
|
if (!pi) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const c = pi?.rest.split("?");
|
||||||
const [path, search] = s.slice(pfx.length).split("?");
|
const parts = c[0].split("/");
|
||||||
|
if (parts.length < 3) {
|
||||||
let [host, maybePath, maybeInstance, orderId, maybeSessionid] = path.split(
|
|
||||||
"/",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!host) {
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const host = parts[0].toLowerCase();
|
||||||
host = host.toLowerCase();
|
const sessionId = parts[parts.length - 1];
|
||||||
|
const orderId = parts[parts.length - 2];
|
||||||
if (!maybePath) {
|
const pathSegments = parts.slice(1, parts.length - 2);
|
||||||
return undefined;
|
const p = [host, ...pathSegments].join("/");
|
||||||
}
|
const merchantBaseUrl = `${pi.innerProto}://${p}/`;
|
||||||
|
|
||||||
if (!orderId) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maybePath === "-") {
|
|
||||||
maybePath = "";
|
|
||||||
} else {
|
|
||||||
maybePath = decodeURIComponent(maybePath) + "/";
|
|
||||||
}
|
|
||||||
let maybeInstancePath = "";
|
|
||||||
if (maybeInstance !== "-") {
|
|
||||||
maybeInstancePath = `instances/${maybeInstance}/`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let protocol = "https";
|
|
||||||
const searchParams = new URLSearchParams(search);
|
|
||||||
if (searchParams.get("insecure") === "1") {
|
|
||||||
protocol = "http";
|
|
||||||
}
|
|
||||||
|
|
||||||
const merchantBaseUrl =
|
|
||||||
`${protocol}://${host}/` +
|
|
||||||
decodeURIComponent(maybePath) +
|
|
||||||
maybeInstancePath;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
merchantBaseUrl,
|
merchantBaseUrl,
|
||||||
orderId,
|
orderId,
|
||||||
sessionId: maybeSessionid,
|
sessionId: sessionId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a taler[+http]://tip URI.
|
||||||
|
* Return undefined if not passed a valid URI.
|
||||||
|
*/
|
||||||
export function parseTipUri(s: string): TipUriResult | undefined {
|
export function parseTipUri(s: string): TipUriResult | undefined {
|
||||||
const pfx = "taler://tip/";
|
const pi = parseProtoInfo(s, "tip");
|
||||||
if (!s.toLowerCase().startsWith(pfx)) {
|
if (!pi) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const c = pi?.rest.split("?");
|
||||||
const path = s.slice(pfx.length);
|
const parts = c[0].split("/");
|
||||||
|
if (parts.length < 2) {
|
||||||
let [host, maybePath, maybeInstance, tipId] = path.split("/");
|
|
||||||
|
|
||||||
if (!host) {
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const host = parts[0].toLowerCase();
|
||||||
host = host.toLowerCase();
|
const tipId = parts[parts.length - 1];
|
||||||
|
const pathSegments = parts.slice(1, parts.length - 1);
|
||||||
if (!maybePath) {
|
const p = [host, ...pathSegments].join("/");
|
||||||
return undefined;
|
const merchantBaseUrl = `${pi.innerProto}://${p}/`;
|
||||||
}
|
|
||||||
|
|
||||||
if (!tipId) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maybePath === "-") {
|
|
||||||
maybePath = "public/";
|
|
||||||
} else {
|
|
||||||
maybePath = decodeURIComponent(maybePath) + "/";
|
|
||||||
}
|
|
||||||
let maybeInstancePath = "";
|
|
||||||
if (maybeInstance !== "-") {
|
|
||||||
maybeInstancePath = `instances/${maybeInstance}/`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const merchantBaseUrl = `https://${host}/${maybePath}${maybeInstancePath}`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
merchantTipId: tipId,
|
|
||||||
merchantOrigin: new URL(merchantBaseUrl).origin,
|
|
||||||
merchantBaseUrl,
|
merchantBaseUrl,
|
||||||
|
merchantTipId: tipId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a taler[+http]://refund URI.
|
||||||
|
* Return undefined if not passed a valid URI.
|
||||||
|
*/
|
||||||
export function parseRefundUri(s: string): RefundUriResult | undefined {
|
export function parseRefundUri(s: string): RefundUriResult | undefined {
|
||||||
const pfx = "taler://refund/";
|
const pi = parseProtoInfo(s, "refund");
|
||||||
|
if (!pi) {
|
||||||
if (!s.toLowerCase().startsWith(pfx)) {
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const c = pi?.rest.split("?");
|
||||||
const [path, search] = s.slice(pfx.length).split("?");
|
const parts = c[0].split("/");
|
||||||
|
if (parts.length < 2) {
|
||||||
let [host, maybePath, maybeInstance, orderId] = path.split("/");
|
|
||||||
|
|
||||||
if (!host) {
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const host = parts[0].toLowerCase();
|
||||||
host = host.toLowerCase();
|
const orderId = parts[parts.length - 1];
|
||||||
|
const pathSegments = parts.slice(1, parts.length - 1);
|
||||||
if (!maybePath) {
|
const p = [host, ...pathSegments].join("/");
|
||||||
return undefined;
|
const merchantBaseUrl = `${pi.innerProto}://${p}/`;
|
||||||
}
|
|
||||||
|
|
||||||
if (!orderId) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maybePath === "-") {
|
|
||||||
maybePath = "";
|
|
||||||
} else {
|
|
||||||
maybePath = decodeURIComponent(maybePath) + "/";
|
|
||||||
}
|
|
||||||
let maybeInstancePath = "";
|
|
||||||
if (maybeInstance !== "-") {
|
|
||||||
maybeInstancePath = `instances/${maybeInstance}/`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let protocol = "https";
|
|
||||||
const searchParams = new URLSearchParams(search);
|
|
||||||
if (searchParams.get("insecure") === "1") {
|
|
||||||
protocol = "http";
|
|
||||||
}
|
|
||||||
|
|
||||||
const merchantBaseUrl =
|
|
||||||
`${protocol}://${host}/` + maybePath + maybeInstancePath;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
merchantBaseUrl,
|
merchantBaseUrl,
|
||||||
|
Loading…
Reference in New Issue
Block a user