diff options
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/taler-util/src/taleruri.test.ts | 41 | ||||
| -rw-r--r-- | packages/taler-util/src/taleruri.ts | 56 | 
2 files changed, 97 insertions, 0 deletions
| diff --git a/packages/taler-util/src/taleruri.test.ts b/packages/taler-util/src/taleruri.test.ts index ffc56a723..3244bbbd9 100644 --- a/packages/taler-util/src/taleruri.test.ts +++ b/packages/taler-util/src/taleruri.test.ts @@ -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", +  ); +}); diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts index cb0d74a12..fc140811b 100644 --- a/packages/taler-util/src/taleruri.ts +++ b/packages/taler-util/src/taleruri.ts @@ -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 { | 
