diff options
author | Florian Dold <florian.dold@gmail.com> | 2020-08-03 13:00:48 +0530 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2020-08-03 13:01:05 +0530 |
commit | ffd2a62c3f7df94365980302fef3bc3376b48182 (patch) | |
tree | 270af6f16b4cc7f5da2afdba55c8bc9dbea5eca5 /packages/taler-wallet-core/src/util/taleruri.ts | |
parent | aa481e42675fb7c4dcbbeec0ba1c61e1953b9596 (diff) | |
download | wallet-core-ffd2a62c3f7df94365980302fef3bc3376b48182.tar.xz |
modularize repo, use pnpm, improve typechecking
Diffstat (limited to 'packages/taler-wallet-core/src/util/taleruri.ts')
-rw-r--r-- | packages/taler-wallet-core/src/util/taleruri.ts | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/packages/taler-wallet-core/src/util/taleruri.ts b/packages/taler-wallet-core/src/util/taleruri.ts new file mode 100644 index 000000000..43a869afe --- /dev/null +++ b/packages/taler-wallet-core/src/util/taleruri.ts @@ -0,0 +1,215 @@ +/* + This file is part of GNU Taler + (C) 2019-2020 Taler Systems S.A. + + 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 + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { URLSearchParams } from "./url"; + +export interface PayUriResult { + merchantBaseUrl: string; + orderId: string; + sessionId: string; + claimToken: string | undefined; +} + +export interface WithdrawUriResult { + bankIntegrationApiBaseUrl: string; + withdrawalOperationId: string; +} + +export interface RefundUriResult { + merchantBaseUrl: string; + orderId: string; +} + +export interface TipUriResult { + merchantTipId: string; + merchantBaseUrl: string; +} + +/** + * Parse a taler[+http]://withdraw URI. + * Return undefined if not passed a valid URI. + */ +export function parseWithdrawUri(s: string): WithdrawUriResult | undefined { + const pi = parseProtoInfo(s, "withdraw"); + if (!pi) { + return undefined; + } + const parts = pi.rest.split("/"); + + if (parts.length < 2) { + return undefined; + } + + const host = parts[0].toLowerCase(); + const pathSegments = parts.slice(1, parts.length - 1); + const withdrawId = parts[parts.length - 1]; + const p = [host, ...pathSegments].join("/"); + + return { + bankIntegrationApiBaseUrl: `${pi.innerProto}://${p}/`, + withdrawalOperationId: withdrawId, + }; +} + +export const enum TalerUriType { + TalerPay = "taler-pay", + TalerWithdraw = "taler-withdraw", + TalerTip = "taler-tip", + TalerRefund = "taler-refund", + TalerNotifyReserve = "taler-notify-reserve", + Unknown = "unknown", +} + +/** + * Classify a taler:// URI. + */ +export function classifyTalerUri(s: string): TalerUriType { + const sl = s.toLowerCase(); + if (sl.startsWith("taler://pay/")) { + return TalerUriType.TalerPay; + } + if (sl.startsWith("taler+http://pay/")) { + return TalerUriType.TalerPay; + } + if (sl.startsWith("taler://tip/")) { + return TalerUriType.TalerTip; + } + if (sl.startsWith("taler+http://tip/")) { + return TalerUriType.TalerTip; + } + if (sl.startsWith("taler://refund/")) { + return TalerUriType.TalerRefund; + } + if (sl.startsWith("taler+http://refund/")) { + return TalerUriType.TalerRefund; + } + if (sl.startsWith("taler://withdraw/")) { + return TalerUriType.TalerWithdraw; + } + if (sl.startsWith("taler://notify-reserve/")) { + return TalerUriType.TalerNotifyReserve; + } + 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 { + const pi = parseProtoInfo(s, "pay"); + if (!pi) { + return undefined; + } + const c = pi?.rest.split("?"); + const q = new URLSearchParams(c[1] ?? ""); + const claimToken = q.get("c") ?? undefined; + const parts = c[0].split("/"); + if (parts.length < 3) { + 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 = `${pi.innerProto}://${p}/`; + + return { + merchantBaseUrl, + orderId, + sessionId: sessionId, + claimToken, + }; +} + +/** + * Parse a taler[+http]://tip URI. + * Return undefined if not passed a valid URI. + */ +export function parseTipUri(s: string): TipUriResult | undefined { + const pi = parseProtoInfo(s, "tip"); + 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 tipId = parts[parts.length - 1]; + const pathSegments = parts.slice(1, parts.length - 1); + const p = [host, ...pathSegments].join("/"); + const merchantBaseUrl = `${pi.innerProto}://${p}/`; + + return { + merchantBaseUrl, + merchantTipId: tipId, + }; +} + +/** + * Parse a taler[+http]://refund URI. + * Return undefined if not passed a valid URI. + */ +export function parseRefundUri(s: string): RefundUriResult | undefined { + const pi = parseProtoInfo(s, "refund"); + 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 orderId = parts[parts.length - 1]; + const pathSegments = parts.slice(1, parts.length - 1); + const p = [host, ...pathSegments].join("/"); + const merchantBaseUrl = `${pi.innerProto}://${p}/`; + + return { + merchantBaseUrl, + orderId, + }; +} |