withdraw exchange URI

This commit is contained in:
Sebastian 2023-06-26 12:54:54 -03:00
parent 4b61945f6b
commit 74579ac2f2
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
2 changed files with 97 additions and 0 deletions

View File

@ -22,10 +22,12 @@ import {
parseRefundUri,
parseRestoreUri,
parseTipUri,
parseWithdrawExchangeUri,
parseWithdrawUri,
stringifyPayPushUri,
stringifyPayUri,
stringifyRestoreUri,
stringifyWithdrawExchange,
} from "./taleruri.js";
test("taler pay url parsing: wrong scheme", (t) => {
@ -329,3 +331,42 @@ test("taler restore URI (stringify)", (t) => {
"taler://restore/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0/http%3A%2F%2Fprov1.example.com%2F,https%3A%2F%2Fprov2.example.com%3A234%2F",
);
});
test("taler withdraw exchange URI (parse)", (t) => {
const r1 = parseWithdrawExchangeUri(
"taler://withdraw-exchange/exchange.demo.taler.net/someroot/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0?a=KUDOS%3A2",
);
if (!r1) {
t.fail();
return;
}
t.deepEqual(
r1.exchangePub,
"GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0",
);
t.deepEqual(r1.exchangeBaseUrl, "https://exchange.demo.taler.net/someroot/");
t.deepEqual(r1.amount, "KUDOS:2");
});
test("taler withdraw exchange URI (stringify)", (t) => {
const url = stringifyWithdrawExchange({
exchangeBaseUrl: "https://exchange.demo.taler.net",
exchangePub: "GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0",
});
t.deepEqual(
url,
"taler://withdraw-exchange/exchange.demo.taler.net/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0",
);
});
test("taler withdraw exchange URI with amount (stringify)", (t) => {
const url = stringifyWithdrawExchange({
exchangeBaseUrl: "https://exchange.demo.taler.net",
exchangePub: "GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0",
amount: "KUDOS:19",
});
t.deepEqual(
url,
"taler://withdraw-exchange/exchange.demo.taler.net/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0?a=KUDOS%3A19",
);
});

View File

@ -15,6 +15,7 @@
*/
import { canonicalizeBaseUrl } from "./helpers.js";
import { AmountString } from "./taler-types.js";
import { URLSearchParams, URL } from "./url.js";
export type TalerUri =
@ -28,6 +29,7 @@ export type TalerUri =
| TipUriResult
| WithdrawUriResult
| ExchangeUri
| WithdrawExchangeUri
| AuditorUri;
export interface PayUriResult {
@ -99,6 +101,13 @@ export interface BackupRestoreUri {
providers: Array<string>;
}
export interface WithdrawExchangeUri {
type: TalerUriAction.WithdrawExchange;
exchangeBaseUrl: string;
exchangePub: string;
amount?: AmountString;
}
/**
* Parse a taler[+http]://withdraw URI.
* Return undefined if not passed a valid URI.
@ -166,6 +175,7 @@ export enum TalerUriAction {
Auditor = "auditor",
Restore = "restore",
DevExperiment = "dev-experiment",
WithdrawExchange = "withdraw-exchange",
}
interface TalerUriProtoInfo {
@ -207,6 +217,7 @@ const parsers: { [A in TalerUriAction]: Parser } = {
[TalerUriAction.DevExperiment]: parseDevExperimentUri,
[TalerUriAction.Exchange]: parseExchangeUri,
[TalerUriAction.Auditor]: parseAuditorUri,
[TalerUriAction.WithdrawExchange]: parseWithdrawExchangeUri,
};
export function parseTalerUri(string: string): TalerUri | undefined {
@ -253,6 +264,9 @@ export function stringifyTalerUri(uri: TalerUri): string {
case TalerUriAction.Exchange: {
return stringifyExchangeUri(uri);
}
case TalerUriAction.WithdrawExchange: {
return stringifyWithdrawExchange(uri);
}
case TalerUriAction.Auditor: {
return stringifyAuditorUri(uri);
}
@ -432,6 +446,37 @@ export function parseExchangeUri(s: string): ExchangeUri | undefined {
exchangePub,
};
}
export function parseWithdrawExchangeUri(
s: string,
): WithdrawExchangeUri | undefined {
const pi = parseProtoInfo(s, "withdraw-exchange");
if (!pi) {
return undefined;
}
const c = pi?.rest.split("?");
const parts = c[0].split("/");
if (parts.length < 2) {
return undefined;
}
const host = parts[0].toLowerCase();
const exchangePub = parts[parts.length - 1];
const pathSegments = parts.slice(1, parts.length - 1);
const hostAndSegments = [host, ...pathSegments].join("/");
const exchangeBaseUrl = canonicalizeBaseUrl(
`${pi.innerProto}://${hostAndSegments}/`,
);
const q = new URLSearchParams(c[1] ?? "");
const amount = q.get("a") ?? undefined;
return {
type: TalerUriAction.WithdrawExchange,
exchangeBaseUrl,
exchangePub,
amount,
};
}
export function parseAuditorUri(s: string): AuditorUri | undefined {
const pi = parseProtoInfo(s, "auditor");
if (!pi) {
@ -622,6 +667,17 @@ export function stringifyRestoreUri({
return `taler://restore/${walletRootPriv}/${list}`;
}
export function stringifyWithdrawExchange({
exchangeBaseUrl,
exchangePub,
amount,
}: Omit<WithdrawExchangeUri, "type">): string {
const { proto, path, query } = getUrlInfo(exchangeBaseUrl, {
a: amount,
});
return `${proto}://withdraw-exchange/${path}${exchangePub}${query}`;
}
export function stringifyDevExperimentUri({
devExperimentId,
}: Omit<DevExperimentUri, "type">): string {