diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index e8ee4f475..b73704c70 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -38,6 +38,7 @@ import { useAsyncAsHook } from "./hooks/useAsyncAsHook.js"; import qrIcon from "./svg/qr_code_24px.svg"; import settingsIcon from "./svg/settings_black_24dp.svg"; import warningIcon from "./svg/warning_24px.svg"; +import { parseTalerUri, TalerUriAction } from "@gnu-taler/taler-util"; /** * List of pages used by the wallet @@ -115,6 +116,7 @@ export const Pages = { "/settings/exchange/add/:currency?", ), + defaultCta: pageDefinition<{ uri: string }>("/taler-uri/:uri"), cta: pageDefinition<{ action: string }>("/cta/:action"), ctaPay: "/cta/pay", ctaPayTemplate: "/cta/pay/template", @@ -136,6 +138,34 @@ export const Pages = { ), }; +const talerUriActionToPageName: { + [t in TalerUriAction]: keyof typeof Pages | undefined; +} = { + [TalerUriAction.Withdraw]: "ctaWithdraw", + [TalerUriAction.Pay]: "ctaPay", + [TalerUriAction.Tip]: "ctaTips", + [TalerUriAction.Refund]: "ctaRefund", + [TalerUriAction.PayPull]: "ctaInvoicePay", + [TalerUriAction.PayPush]: "ctaTransferPickup", + [TalerUriAction.Restore]: "ctaRecovery", + [TalerUriAction.PayTemplate]: "ctaPayTemplate", + [TalerUriAction.DevExperiment]: undefined, + [TalerUriAction.Exchange]: undefined, + [TalerUriAction.Auditor]: undefined, +}; + +export function getPathnameForTalerURI(talerUri: string): string | undefined { + const uri = parseTalerUri(talerUri); + if (!uri) { + return undefined; + } + const pageName = talerUriActionToPageName[uri.type]; + if (!pageName) { + return undefined; + } + return `${Pages[pageName]}?talerUri=${encodeURIComponent(talerUri)}`; +} + export type PopupNavBarOptions = "balance" | "backup" | "dev"; export function PopupNavBar({ path }: { path?: PopupNavBarOptions }): VNode { const api = useBackendContext(); diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index 4b0bdbfb7..03259314e 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -15,11 +15,11 @@ */ import { - classifyTalerUri, Logger, TalerErrorCode, - TalerUriType, + TalerUriAction, TalerError, + parseTalerUri, } from "@gnu-taler/taler-util"; import { WalletOperations } from "@gnu-taler/taler-wallet-core"; import { BackgroundOperations } from "../wxApi.js"; @@ -239,80 +239,83 @@ function openWalletURIFromPopup(maybeTalerUri: string): void { const talerUri = maybeTalerUri.startsWith("ext+") ? maybeTalerUri.substring(4) : maybeTalerUri; - const uriType = classifyTalerUri(talerUri); + const uri = parseTalerUri(talerUri); + if (!uri) { + logger.warn( + `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, + ); + return; + } + //FIXME: this should redirect to just one place + // the target pathname should handle what happens if the endpoint is not there + // like "trying to open from popup but this uri is not handled" encodeURIComponent; let url: string | undefined = undefined; - switch (uriType) { - case TalerUriType.TalerWithdraw: + switch (uri.type) { + case TalerUriAction.Withdraw: url = chrome.runtime.getURL( - `static/wallet.html#/cta/withdraw?talerWithdrawUri=${encodeURIComponent( + `static/wallet.html#/cta/withdraw?talerUri=${encodeURIComponent( talerUri, )}`, ); break; - case TalerUriType.TalerRecovery: + case TalerUriAction.Restore: url = chrome.runtime.getURL( - `static/wallet.html#/cta/recovery?talerRecoveryUri=${encodeURIComponent( + `static/wallet.html#/cta/recovery?talerUri=${encodeURIComponent( talerUri, )}`, ); break; - case TalerUriType.TalerPay: + case TalerUriAction.Pay: url = chrome.runtime.getURL( - `static/wallet.html#/cta/pay?talerPayUri=${encodeURIComponent( + `static/wallet.html#/cta/pay?talerUri=${encodeURIComponent(talerUri)}`, + ); + break; + case TalerUriAction.Tip: + url = chrome.runtime.getURL( + `static/wallet.html#/cta/tip?talerUri=${encodeURIComponent(talerUri)}`, + ); + break; + case TalerUriAction.Refund: + url = chrome.runtime.getURL( + `static/wallet.html#/cta/refund?talerUri=${encodeURIComponent( talerUri, )}`, ); break; - case TalerUriType.TalerTip: + case TalerUriAction.PayPull: url = chrome.runtime.getURL( - `static/wallet.html#/cta/tip?talerTipUri=${encodeURIComponent( + `static/wallet.html#/cta/invoice/pay?talerUri=${encodeURIComponent( talerUri, )}`, ); break; - case TalerUriType.TalerRefund: + case TalerUriAction.PayPush: url = chrome.runtime.getURL( - `static/wallet.html#/cta/refund?talerRefundUri=${encodeURIComponent( + `static/wallet.html#/cta/transfer/pickup?talerUri=${encodeURIComponent( talerUri, )}`, ); break; - case TalerUriType.TalerPayPull: + case TalerUriAction.PayTemplate: url = chrome.runtime.getURL( - `static/wallet.html#/cta/invoice/pay?talerPayPullUri=${encodeURIComponent( + `static/wallet.html#/cta/pay/template?talerUri=${encodeURIComponent( talerUri, )}`, ); break; - case TalerUriType.TalerPayPush: - url = chrome.runtime.getURL( - `static/wallet.html#/cta/transfer/pickup?talerPayPushUri=${encodeURIComponent( - talerUri, - )}`, - ); - break; - case TalerUriType.TalerPayTemplate: - url = chrome.runtime.getURL( - `static/wallet.html#/cta/pay/template?talerPayTemplateUri=${encodeURIComponent( - talerUri, - )}`, - ); - break; - case TalerUriType.Unknown: - logger.warn( - `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, - ); - return; - case TalerUriType.TalerDevExperiment: + case TalerUriAction.DevExperiment: logger.warn(`taler://dev-experiment URIs are not allowed in headers`); return; - case TalerUriType.TalerTemplate: - logger.warn(`taler://dev-template URIs are not allowed in headers`); + case TalerUriAction.Exchange: + logger.warn(`taler://exchange not yet supported`); + return; + case TalerUriAction.Auditor: + logger.warn(`taler://auditor not yet supported`); return; default: { - const error: never = uriType; + const error: never = uri; logger.warn( `Response with HTTP 402 the Taler header "${error}", but header value is not a taler:// URI.`, ); diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index 4a5ef30eb..2b03bb947 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -20,7 +20,11 @@ * @author sebasjm */ -import { TranslatedString } from "@gnu-taler/taler-util"; +import { + TalerUriAction, + TranslatedString, + parseTalerUri, +} from "@gnu-taler/taler-util"; import { createHashHistory } from "history"; import { ComponentChildren, Fragment, h, VNode } from "preact"; import { route, Route, Router } from "preact-router"; @@ -55,7 +59,12 @@ import { WithdrawPageFromParams, WithdrawPageFromURI, } from "../cta/Withdraw/index.js"; -import { Pages, WalletNavBar, WalletNavBarOptions } from "../NavigationBar.js"; +import { + Pages, + WalletNavBar, + WalletNavBarOptions, + getPathnameForTalerURI, +} from "../NavigationBar.js"; import { platform } from "../platform/foreground.js"; import CloseIcon from "../svg/close_24px.svg"; import { AddBackupProviderPage } from "./AddBackupProvider/index.js"; @@ -285,12 +294,22 @@ export function Application(): VNode { {/** * CALL TO ACTION */} + { + const path = getPathnameForTalerURI(uri); + if (!path) { + return ; + } + return ; + }} + /> ( + component={({ talerUri }: { talerUri: string }) => ( redirectTo(Pages.receiveCash({ amount })) } @@ -304,14 +323,10 @@ export function Application(): VNode { /> ( + component={({ talerUri }: { talerUri: string }) => ( redirectTo(Pages.receiveCash({ amount })) } @@ -325,10 +340,10 @@ export function Application(): VNode { /> ( + component={({ talerUri }: { talerUri: string }) => ( redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -339,10 +354,10 @@ export function Application(): VNode { /> ( + component={({ talerUri }: { talerUri: string }) => ( redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -353,14 +368,10 @@ export function Application(): VNode { /> ( + component={({ talerUri }: { talerUri: string }) => ( redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -387,15 +398,15 @@ export function Application(): VNode { path={Pages.ctaDeposit} component={({ amount, - talerDepositUri, + talerUri, }: { amount: string; - talerDepositUri: string; + talerUri: string; }) => ( redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -434,10 +445,10 @@ export function Application(): VNode { /> ( + component={({ talerUri }: { talerUri: string }) => ( redirectTo(Pages.receiveCash({ amount })) } @@ -451,10 +462,10 @@ export function Application(): VNode { /> ( + component={({ talerUri }: { talerUri: string }) => ( redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index 3655c5dbc..c50412053 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -34,6 +34,8 @@ import { WalletDiagnostics, makeErrorDetail, getErrorDetailFromException, + parseTalerUri, + TalerUriAction, } from "@gnu-taler/taler-util"; import { DbAccess, @@ -332,69 +334,17 @@ function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void { const talerUri = maybeTalerUri.startsWith("ext+") ? maybeTalerUri.substring(4) : maybeTalerUri; - const uriType = classifyTalerUri(talerUri); - switch (uriType) { - case TalerUriType.TalerWithdraw: - return platform.redirectTabToWalletPage( - tabId, - `/cta/withdraw?talerWithdrawUri=${encodeURIComponent(talerUri)}`, - ); - case TalerUriType.TalerPay: - return platform.redirectTabToWalletPage( - tabId, - `/cta/pay?talerPayUri=${encodeURIComponent(talerUri)}`, - ); - case TalerUriType.TalerTip: - return platform.redirectTabToWalletPage( - tabId, - `/cta/tip?talerTipUri=${encodeURIComponent(talerUri)}`, - ); - case TalerUriType.TalerRefund: - return platform.redirectTabToWalletPage( - tabId, - `/cta/refund?talerRefundUri=${encodeURIComponent(talerUri)}`, - ); - case TalerUriType.TalerPayPull: - return platform.redirectTabToWalletPage( - tabId, - `/cta/invoice/pay?talerPayPullUri=${encodeURIComponent(talerUri)}`, - ); - case TalerUriType.TalerPayPush: - return platform.redirectTabToWalletPage( - tabId, - `/cta/transfer/pickup?talerPayPushUri=${encodeURIComponent(talerUri)}`, - ); - case TalerUriType.TalerRecovery: - return platform.redirectTabToWalletPage( - tabId, - `/cta/transfer/recovery?talerBackupUri=${encodeURIComponent(talerUri)}`, - ); - case TalerUriType.TalerPayTemplate: - return platform.redirectTabToWalletPage( - tabId, - `/cta/pay/template?talerPayTemplateUri=${encodeURIComponent(talerUri)}`, - ); - return; - case TalerUriType.Unknown: - logger.warn( - `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, - ); - return; - case TalerUriType.TalerDevExperiment: - // FIXME: Implement! - logger.warn("not implemented"); - return; - case TalerUriType.TalerTemplate: - logger.warn("not implemented"); - return; - default: { - const error: never = uriType; - logger.warn( - `Response with HTTP 402 the Taler header "${error}", but header value is not a taler:// URI.`, - ); - return; - } + const uri = parseTalerUri(talerUri); + if (!uri) { + logger.warn( + `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, + ); + return; } + return platform.redirectTabToWalletPage( + tabId, + `/taler-uri/${encodeURIComponent(talerUri)}`, + ); } /**