gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 01/05: taleruri sync with the spec


From: gnunet
Subject: [taler-wallet-core] 01/05: taleruri sync with the spec
Date: Mon, 03 Apr 2023 17:29:36 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit defdfd769749354ec3aba9436a3bcb5cd39bdd83
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Apr 3 12:12:35 2023 -0300

    taleruri sync with the spec
---
 packages/taler-util/src/taleruri.ts | 555 ++++++++++++++++++++++++++++--------
 1 file changed, 438 insertions(+), 117 deletions(-)

diff --git a/packages/taler-util/src/taleruri.ts 
b/packages/taler-util/src/taleruri.ts
index 4d55d4c98..e641f1d27 100644
--- a/packages/taler-util/src/taleruri.ts
+++ b/packages/taler-util/src/taleruri.ts
@@ -14,11 +14,24 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { BackupRecovery } from "./backup-types.js";
 import { canonicalizeBaseUrl } from "./helpers.js";
 import { URLSearchParams, URL } from "./url.js";
 
+export type TalerUri =
+  | PayUriResult
+  | PayTemplateUriResult
+  | DevExperimentUri
+  | PayPullUriResult
+  | PayPushUriResult
+  | BackupRestoreUri
+  | RefundUriResult
+  | TipUriResult
+  | WithdrawUriResult
+  | ExchangeUri
+  | AuditorUri;
+
 export interface PayUriResult {
+  type: TalerUriAction.Pay;
   merchantBaseUrl: string;
   orderId: string;
   sessionId: string;
@@ -27,40 +40,68 @@ export interface PayUriResult {
 }
 
 export interface PayTemplateUriResult {
+  type: TalerUriAction.PayTemplate;
   merchantBaseUrl: string;
   templateId: string;
   templateParams: Record<string, string>;
 }
 
 export interface WithdrawUriResult {
+  type: TalerUriAction.Withdraw;
   bankIntegrationApiBaseUrl: string;
   withdrawalOperationId: string;
 }
 
 export interface RefundUriResult {
+  type: TalerUriAction.Refund;
   merchantBaseUrl: string;
   orderId: string;
 }
 
 export interface TipUriResult {
-  merchantTipId: string;
+  type: TalerUriAction.Tip;
   merchantBaseUrl: string;
+  merchantTipId: string;
+}
+
+export interface ExchangeUri {
+  type: TalerUriAction.Exchange;
+  exchangeBaseUrl: string;
+  exchangePub: string;
+}
+
+export interface AuditorUri {
+  type: TalerUriAction.Auditor;
+  auditorBaseUrl: string;
+  auditorPub: string;
 }
 
 export interface PayPushUriResult {
+  type: TalerUriAction.PayPush;
   exchangeBaseUrl: string;
   contractPriv: string;
 }
 
 export interface PayPullUriResult {
+  type: TalerUriAction.PayPull;
   exchangeBaseUrl: string;
   contractPriv: string;
 }
 
 export interface DevExperimentUri {
+  type: TalerUriAction.DevExperiment;
   devExperimentId: string;
 }
 
+export interface BackupRestoreUri {
+  type: TalerUriAction.Restore;
+  walletRootPriv: string;
+  providers: {
+    name: string;
+    url: string;
+  }[];
+}
+
 /**
  * Parse a taler[+http]://withdraw URI.
  * Return undefined if not passed a valid URI.
@@ -89,11 +130,15 @@ export function parseWithdrawUri(s: string): 
WithdrawUriResult | undefined {
   const p = [host, ...pathSegments].join("/");
 
   return {
+    type: TalerUriAction.Withdraw,
     bankIntegrationApiBaseUrl: canonicalizeBaseUrl(`${pi.innerProto}://${p}/`),
     withdrawalOperationId: withdrawId,
   };
 }
 
+/**
+ * @deprecated use TalerUriAction
+ */
 export enum TalerUriType {
   TalerPay = "taler-pay",
   TalerTemplate = "taler-template",
@@ -112,15 +157,30 @@ const talerActionPayPull = "pay-pull";
 const talerActionPayPush = "pay-push";
 const talerActionPayTemplate = "pay-template";
 
+export enum TalerUriAction {
+  Pay = "pay",
+  Withdraw = "withdraw",
+  Refund = "refund",
+  Tip = "tip",
+  PayPull = "pay-pull",
+  PayPush = "pay-push",
+  PayTemplate = "pay-template",
+  Exchange = "exchange",
+  Auditor = "auditor",
+  Restore = "restore",
+  DevExperiment = "dev-experiment",
+}
+
 /**
  * Classify a taler:// URI.
+ * @deprecated use parseTalerUri
  */
 export function classifyTalerUri(s: string): TalerUriType {
   const sl = s.toLowerCase();
-  if (sl.startsWith("taler://recovery/")) {
+  if (sl.startsWith("taler://restore/")) {
     return TalerUriType.TalerRecovery;
   }
-  if (sl.startsWith("taler+http://recovery/";)) {
+  if (sl.startsWith("taler+http://restore/";)) {
     return TalerUriType.TalerRecovery;
   }
   if (sl.startsWith("taler://pay/")) {
@@ -197,6 +257,71 @@ function parseProtoInfo(
   }
 }
 
+type Parser = (s: string) => TalerUri | undefined;
+const parsers: { [A in TalerUriAction]: Parser } = {
+  [TalerUriAction.Pay]: parsePayUri,
+  [TalerUriAction.PayPull]: parsePayPullUri,
+  [TalerUriAction.PayPush]: parsePayPushUri,
+  [TalerUriAction.PayTemplate]: parsePayTemplateUri,
+  [TalerUriAction.Restore]: parseRestoreUri,
+  [TalerUriAction.Refund]: parseRefundUri,
+  [TalerUriAction.Tip]: parseTipUri,
+  [TalerUriAction.Withdraw]: parseWithdrawUri,
+  [TalerUriAction.DevExperiment]: parseDevExperimentUri,
+  [TalerUriAction.Exchange]: parseExchangeUri,
+  [TalerUriAction.Auditor]: parseAuditorUri,
+};
+
+export function parseTalerUri(string: string): TalerUri | undefined {
+  const https = string.startsWith("taler://");
+  const http = string.startsWith("taler+http://";);
+  if (!https && !http) return undefined;
+  const actionStart = https ? 8 : 13;
+  const actionEnd = string.indexOf("/", actionStart + 1);
+  const action = string.substring(actionStart, actionEnd);
+  const found = Object.values(TalerUriAction).find((x) => x === action);
+  if (!found) return undefined;
+  return parsers[found](string);
+}
+
+export function stringifyTalerUri(uri: TalerUri): string {
+  switch (uri.type) {
+    case TalerUriAction.DevExperiment: {
+      return stringifyDevExperimentUri(uri);
+    }
+    case TalerUriAction.Pay: {
+      return stringifyPayUri(uri);
+    }
+    case TalerUriAction.PayPull: {
+      return stringifyPayPullUri(uri);
+    }
+    case TalerUriAction.PayPush: {
+      return stringifyPayPushUri(uri);
+    }
+    case TalerUriAction.PayTemplate: {
+      return stringifyPayTemplateUri(uri);
+    }
+    case TalerUriAction.Restore: {
+      return stringifyRestoreUri(uri);
+    }
+    case TalerUriAction.Refund: {
+      return stringifyRefundUri(uri);
+    }
+    case TalerUriAction.Tip: {
+      return stringifyTipUri(uri);
+    }
+    case TalerUriAction.Withdraw: {
+      return stringifyWithdrawUri(uri);
+    }
+    case TalerUriAction.Exchange: {
+      return stringifyExchangeUri(uri);
+    }
+    case TalerUriAction.Auditor: {
+      return stringifyAuditorUri(uri);
+    }
+  }
+}
+
 /**
  * Parse a taler[+http]://pay URI.
  * Return undefined if not passed a valid URI.
@@ -222,76 +347,51 @@ export function parsePayUri(s: string): PayUriResult | 
undefined {
   const merchantBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
 
   return {
+    type: TalerUriAction.Pay,
     merchantBaseUrl,
     orderId,
-    sessionId: sessionId,
+    sessionId,
     claimToken,
     noncePriv,
   };
 }
 
 export function parsePayTemplateUri(
-  s: string,
+  uriString: string,
 ): PayTemplateUriResult | undefined {
-  const pi = parseProtoInfo(s, talerActionPayTemplate);
+  const pi = parseProtoInfo(uriString, talerActionPayTemplate);
   if (!pi) {
     return undefined;
   }
-  const c = pi?.rest.split("?");
-  const q = new URLSearchParams(c[1] ?? "");
+  const c = pi.rest.split("?");
+
   const parts = c[0].split("/");
   if (parts.length < 2) {
     return undefined;
   }
-  const host = parts[0].toLowerCase();
-  const templateId = parts[parts.length - 1];
-  const pathSegments = parts.slice(1, parts.length - 1);
-  const p = [host, ...pathSegments].join("/");
-  const merchantBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
 
+  const q = new URLSearchParams(c[1] ?? "");
   const params: Record<string, string> = {};
-
   q.forEach((v, k) => {
     params[k] = v;
   });
 
+  const host = parts[0].toLowerCase();
+  const templateId = parts[parts.length - 1];
+  const pathSegments = parts.slice(1, parts.length - 1);
+  const hostAndSegments = [host, ...pathSegments].join("/");
+  const merchantBaseUrl = canonicalizeBaseUrl(
+    `${pi.innerProto}://${hostAndSegments}/`,
+  );
+
   return {
+    type: TalerUriAction.PayTemplate,
     merchantBaseUrl,
     templateId,
     templateParams: params,
   };
 }
 
-export function constructPayUri(
-  merchantBaseUrl: string,
-  orderId: string,
-  sessionId: string,
-  claimToken?: string,
-  noncePriv?: string,
-): 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;
-  }
-  return result;
-}
-
 export function parsePayPushUri(s: string): PayPushUriResult | undefined {
   const pi = parseProtoInfo(s, talerActionPayPush);
   if (!pi) {
@@ -305,10 +405,13 @@ export function parsePayPushUri(s: string): 
PayPushUriResult | undefined {
   const host = parts[0].toLowerCase();
   const contractPriv = parts[parts.length - 1];
   const pathSegments = parts.slice(1, parts.length - 1);
-  const p = [host, ...pathSegments].join("/");
-  const exchangeBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
+  const hostAndSegments = [host, ...pathSegments].join("/");
+  const exchangeBaseUrl = canonicalizeBaseUrl(
+    `${pi.innerProto}://${hostAndSegments}/`,
+  );
 
   return {
+    type: TalerUriAction.PayPush,
     exchangeBaseUrl,
     contractPriv,
   };
@@ -327,10 +430,13 @@ export function parsePayPullUri(s: string): 
PayPullUriResult | undefined {
   const host = parts[0].toLowerCase();
   const contractPriv = parts[parts.length - 1];
   const pathSegments = parts.slice(1, parts.length - 1);
-  const p = [host, ...pathSegments].join("/");
-  const exchangeBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
+  const hostAndSegments = [host, ...pathSegments].join("/");
+  const exchangeBaseUrl = canonicalizeBaseUrl(
+    `${pi.innerProto}://${hostAndSegments}/`,
+  );
 
   return {
+    type: TalerUriAction.PayPull,
     exchangeBaseUrl,
     contractPriv,
   };
@@ -353,15 +459,67 @@ export function parseTipUri(s: string): TipUriResult | 
undefined {
   const host = parts[0].toLowerCase();
   const tipId = parts[parts.length - 1];
   const pathSegments = parts.slice(1, parts.length - 1);
-  const p = [host, ...pathSegments].join("/");
-  const merchantBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
+  const hostAndSegments = [host, ...pathSegments].join("/");
+  const merchantBaseUrl = canonicalizeBaseUrl(
+    `${pi.innerProto}://${hostAndSegments}/`,
+  );
 
   return {
+    type: TalerUriAction.Tip,
     merchantBaseUrl,
     merchantTipId: tipId,
   };
 }
 
+export function parseExchangeUri(s: string): ExchangeUri | undefined {
+  const pi = parseProtoInfo(s, "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}/`,
+  );
+
+  return {
+    type: TalerUriAction.Exchange,
+    exchangeBaseUrl,
+    exchangePub,
+  };
+}
+export function parseAuditorUri(s: string): AuditorUri | undefined {
+  const pi = parseProtoInfo(s, "auditor");
+  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 auditorPub = parts[parts.length - 1];
+  const pathSegments = parts.slice(1, parts.length - 1);
+  const hostAndSegments = [host, ...pathSegments].join("/");
+  const auditorBaseUrl = canonicalizeBaseUrl(
+    `${pi.innerProto}://${hostAndSegments}/`,
+  );
+
+  return {
+    type: TalerUriAction.Auditor,
+    auditorBaseUrl,
+    auditorPub,
+  };
+}
+
 /**
  * Parse a taler[+http]://refund URI.
  * Return undefined if not passed a valid URI.
@@ -377,13 +535,16 @@ 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 - 2];
-  const pathSegments = parts.slice(1, parts.length - 2);
-  const p = [host, ...pathSegments].join("/");
-  const merchantBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
+  // const sessionId = parts[parts.length - 1];
+  const orderId = parts[parts.length - 1];
+  const pathSegments = parts.slice(1, parts.length - 1);
+  const hostAndSegments = [host, ...pathSegments].join("/");
+  const merchantBaseUrl = canonicalizeBaseUrl(
+    `${pi.innerProto}://${hostAndSegments}/`,
+  );
 
   return {
+    type: TalerUriAction.Refund,
     merchantBaseUrl,
     orderId,
   };
@@ -395,89 +556,249 @@ export function parseDevExperimentUri(s: string): 
DevExperimentUri | undefined {
   if (!c) {
     return undefined;
   }
-  // const q = new URLSearchParams(c[1] ?? "");
   const parts = c[0].split("/");
   return {
+    type: TalerUriAction.DevExperiment,
     devExperimentId: parts[0],
   };
 }
 
-export function constructPayPushUri(args: {
-  exchangeBaseUrl: string;
-  contractPriv: string;
-}): string {
-  const url = new URL(args.exchangeBaseUrl);
-  let proto: string;
-  if (url.protocol === "https:") {
-    proto = "taler";
-  } else if (url.protocol === "http:") {
-    proto = "taler+http";
-  } else {
-    throw Error(`Unsupported exchange URL protocol ${args.exchangeBaseUrl}`);
+export function parseRestoreUri(uri: string): BackupRestoreUri | undefined {
+  const pi = parseProtoInfo(uri, "restore");
+  if (!pi) {
+    return undefined;
   }
-  if (!url.pathname.endsWith("/")) {
-    throw Error(
-      `exchange base URL must end with a slash (got 
${args.exchangeBaseUrl}instead)`,
-    );
+  const c = pi.rest.split("?");
+  const parts = c[0].split("/");
+  if (parts.length < 2) {
+    return undefined;
   }
-  return `${proto}://pay-push/${url.host}${url.pathname}${args.contractPriv}`;
+
+  const walletRootPriv = parts[0];
+  if (!walletRootPriv) return undefined;
+  const providers = new Array<{ name: string; url: string }>();
+  parts[1].split(",").map((name) => {
+    const url = canonicalizeBaseUrl(`${pi.innerProto}://${name}/`);
+    providers.push({ name, url });
+  });
+  return {
+    type: TalerUriAction.Restore,
+    walletRootPriv,
+    providers,
+  };
+}
+
+// ================================================
+//  To string functions
+// ================================================
+
+/**
+ * @deprecated use stringifyRecoveryUri
+ */
+export function constructRecoveryUri(args: {
+  walletRootPriv: string;
+  providers: {
+    name: string;
+    url: string;
+  }[];
+}): string {
+  return stringifyRestoreUri(args);
 }
 
+/**
+ * @deprecated stringifyPayPullUri
+ */
 export function constructPayPullUri(args: {
   exchangeBaseUrl: string;
   contractPriv: string;
 }): string {
-  const url = new URL(args.exchangeBaseUrl);
+  return stringifyPayPullUri(args);
+}
+
+/**
+ * @deprecated use stringifyPayPushUri
+ */
+export function constructPayPushUri(args: {
+  exchangeBaseUrl: string;
+  contractPriv: string;
+}): string {
+  return stringifyPayPushUri(args);
+}
+
+/**
+ *
+ * @deprecated use stringifyPayUri
+ */
+export function constructPayUri(
+  merchantBaseUrl: string,
+  orderId: string,
+  sessionId: string,
+  claimToken?: string,
+  noncePriv?: string,
+): string {
+  return stringifyPayUri({
+    merchantBaseUrl,
+    orderId,
+    sessionId,
+    claimToken,
+    noncePriv,
+  });
+}
+
+export function stringifyPayUri({
+  merchantBaseUrl,
+  orderId,
+  sessionId,
+  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,
+  });
+  return `${proto}://pay/${path}${orderId}/${sessionId}${query}`;
+}
+
+export function stringifyPayPullUri({
+  contractPriv,
+  exchangeBaseUrl,
+}: Omit<PayPullUriResult, "type">): string {
+  const { proto, path } = getUrlInfo(exchangeBaseUrl);
+  return `${proto}://pay-pull/${path}${contractPriv}`;
+}
+
+export function stringifyPayPushUri({
+  contractPriv,
+  exchangeBaseUrl,
+}: Omit<PayPushUriResult, "type">): string {
+  const { proto, path } = getUrlInfo(exchangeBaseUrl);
+
+  return `${proto}://pay-push/${path}${contractPriv}`;
+}
+
+export function stringifyRestoreUri({
+  providers,
+  walletRootPriv,
+}: Omit<BackupRestoreUri, "type">): string {
+  const list = providers.map((p) => `${new URL(p.url).hostname}`).join("m");
+  return `taler://restore/${walletRootPriv}/${list}`;
+}
+
+export function stringifyDevExperimentUri({
+  devExperimentId,
+}: Omit<DevExperimentUri, "type">): string {
+  return `taler://dev-experiment/${devExperimentId}`;
+}
+
+export function stringifyPayTemplateUri({
+  merchantBaseUrl,
+  templateId,
+  templateParams,
+}: Omit<PayTemplateUriResult, "type">): string {
+  const { proto, path, query } = getUrlInfo(merchantBaseUrl, templateParams);
+  return `${proto}://pay-template/${path}${templateId}${query}`;
+}
+export function stringifyRefundUri({
+  merchantBaseUrl,
+  orderId,
+}: Omit<RefundUriResult, "type">): string {
+  const { proto, path } = getUrlInfo(merchantBaseUrl);
+  return `${proto}://refund/${path}${orderId}`;
+}
+export function stringifyTipUri({
+  merchantBaseUrl,
+  merchantTipId,
+}: Omit<TipUriResult, "type">): string {
+  const { proto, path } = getUrlInfo(merchantBaseUrl);
+  return `${proto}://tip/${path}${merchantTipId}`;
+}
+
+export function stringifyExchangeUri({
+  exchangeBaseUrl,
+  exchangePub,
+}: Omit<ExchangeUri, "type">): string {
+  const { proto, path } = getUrlInfo(exchangeBaseUrl);
+  return `${proto}://exchange/${path}${exchangePub}`;
+}
+
+export function stringifyAuditorUri({
+  auditorBaseUrl,
+  auditorPub,
+}: Omit<AuditorUri, "type">): string {
+  const { proto, path } = getUrlInfo(auditorBaseUrl);
+  return `${proto}://auditor/${path}${auditorPub}`;
+}
+
+export function stringifyWithdrawUri({
+  bankIntegrationApiBaseUrl,
+  withdrawalOperationId,
+}: Omit<WithdrawUriResult, "type">): string {
+  const { proto, path } = getUrlInfo(bankIntegrationApiBaseUrl);
+  return `${proto}://withdraw/${path}${withdrawalOperationId}`;
+}
+
+/**
+ * Use baseUrl to defined http or https
+ * create path using host+port+pathname
+ * use params to create a query parameter string or empty
+ *
+ * @param baseUrl
+ * @param params
+ * @returns
+ */
+function getUrlInfo(
+  baseUrl: string,
+  params: Record<string, string | undefined> = {},
+): { proto: string; path: string; query: string } {
+  const url = new URL(baseUrl);
   let proto: string;
   if (url.protocol === "https:") {
     proto = "taler";
   } else if (url.protocol === "http:") {
     proto = "taler+http";
   } else {
-    throw Error(`Unsupported exchange URL protocol ${args.exchangeBaseUrl}`);
+    throw Error(`Unsupported URL protocol in ${baseUrl}`);
   }
-  if (!url.pathname.endsWith("/")) {
-    throw Error(
-      `exchange base URL must end with a slash (got 
${args.exchangeBaseUrl}instead)`,
-    );
+  let path = url.hostname;
+  if (url.port) {
+    path = path + ":" + url.port;
   }
-  return `${proto}://pay-pull/${url.host}${url.pathname}${args.contractPriv}`;
-}
-
-export function constructRecoveryUri(args: BackupRecovery): string {
-  const key = args.walletRootPriv;
-  //FIXME: name may contain non valid characters
-  const urls = args.providers
-    .map((p) => `${p.name}=${canonicalizeBaseUrl(p.url)}`)
-    .join("&");
-
-  return `taler://recovery/${key}?${urls}`;
-}
-export function parseRecoveryUri(uri: string): BackupRecovery | undefined {
-  const pi = parseProtoInfo(uri, "recovery");
-  if (!pi) {
-    return undefined;
+  if (url.pathname) {
+    path = path + url.pathname;
   }
-  const idx = pi.rest.indexOf("?");
-  if (idx === -1) {
-    return undefined;
+  if (!path.endsWith("/")) {
+    path = path + "/";
   }
-  const path = pi.rest.slice(0, idx);
-  const params = pi.rest.slice(idx + 1);
-  if (!path || !params) {
-    return undefined;
-  }
-  const parts = path.split("/");
-  const walletRootPriv = parts[0];
-  if (!walletRootPriv) return undefined;
-  const providers = new Array<{ name: string; url: string }>();
-  const args = params.split("&");
-  for (const param in args) {
-    const eq = args[param].indexOf("=");
-    if (eq === -1) return undefined;
-    const name = args[param].slice(0, eq);
-    const url = args[param].slice(eq + 1);
-    providers.push({ name, url });
-  }
-  return { walletRootPriv, providers };
+
+  const qp = new URLSearchParams();
+  let withParams = false;
+  Object.entries(params).forEach(([name, value]) => {
+    if (value) {
+      withParams = true;
+      qp.append(name, value);
+    }
+  });
+  const query = withParams ? "?" + qp.toString() : "";
+
+  return { proto, path, query };
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]