use /taler-uri as redirection point to all taler uris

This commit is contained in:
Sebastian 2023-04-13 12:21:39 -03:00
parent ebd0041956
commit 7b2de89444
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
4 changed files with 122 additions and 128 deletions

View File

@ -38,6 +38,7 @@ import { useAsyncAsHook } from "./hooks/useAsyncAsHook.js";
import qrIcon from "./svg/qr_code_24px.svg"; import qrIcon from "./svg/qr_code_24px.svg";
import settingsIcon from "./svg/settings_black_24dp.svg"; import settingsIcon from "./svg/settings_black_24dp.svg";
import warningIcon from "./svg/warning_24px.svg"; import warningIcon from "./svg/warning_24px.svg";
import { parseTalerUri, TalerUriAction } from "@gnu-taler/taler-util";
/** /**
* List of pages used by the wallet * List of pages used by the wallet
@ -115,6 +116,7 @@ export const Pages = {
"/settings/exchange/add/:currency?", "/settings/exchange/add/:currency?",
), ),
defaultCta: pageDefinition<{ uri: string }>("/taler-uri/:uri"),
cta: pageDefinition<{ action: string }>("/cta/:action"), cta: pageDefinition<{ action: string }>("/cta/:action"),
ctaPay: "/cta/pay", ctaPay: "/cta/pay",
ctaPayTemplate: "/cta/pay/template", 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 type PopupNavBarOptions = "balance" | "backup" | "dev";
export function PopupNavBar({ path }: { path?: PopupNavBarOptions }): VNode { export function PopupNavBar({ path }: { path?: PopupNavBarOptions }): VNode {
const api = useBackendContext(); const api = useBackendContext();

View File

@ -15,11 +15,11 @@
*/ */
import { import {
classifyTalerUri,
Logger, Logger,
TalerErrorCode, TalerErrorCode,
TalerUriType, TalerUriAction,
TalerError, TalerError,
parseTalerUri,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { WalletOperations } from "@gnu-taler/taler-wallet-core"; import { WalletOperations } from "@gnu-taler/taler-wallet-core";
import { BackgroundOperations } from "../wxApi.js"; import { BackgroundOperations } from "../wxApi.js";
@ -239,80 +239,83 @@ function openWalletURIFromPopup(maybeTalerUri: string): void {
const talerUri = maybeTalerUri.startsWith("ext+") const talerUri = maybeTalerUri.startsWith("ext+")
? maybeTalerUri.substring(4) ? maybeTalerUri.substring(4)
: maybeTalerUri; : maybeTalerUri;
const uriType = classifyTalerUri(talerUri); const uri = parseTalerUri(talerUri);
if (!uri) {
encodeURIComponent;
let url: string | undefined = undefined;
switch (uriType) {
case TalerUriType.TalerWithdraw:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/withdraw?talerWithdrawUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriType.TalerRecovery:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/recovery?talerRecoveryUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriType.TalerPay:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/pay?talerPayUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriType.TalerTip:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/tip?talerTipUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriType.TalerRefund:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/refund?talerRefundUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriType.TalerPayPull:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/invoice/pay?talerPayPullUri=${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( logger.warn(
`Response with HTTP 402 the Taler header but could not classify ${talerUri}`, `Response with HTTP 402 the Taler header but could not classify ${talerUri}`,
); );
return; return;
case TalerUriType.TalerDevExperiment: }
//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 (uri.type) {
case TalerUriAction.Withdraw:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/withdraw?talerUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriAction.Restore:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/recovery?talerUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriAction.Pay:
url = chrome.runtime.getURL(
`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 TalerUriAction.PayPull:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/invoice/pay?talerUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriAction.PayPush:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/transfer/pickup?talerUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriAction.PayTemplate:
url = chrome.runtime.getURL(
`static/wallet.html#/cta/pay/template?talerUri=${encodeURIComponent(
talerUri,
)}`,
);
break;
case TalerUriAction.DevExperiment:
logger.warn(`taler://dev-experiment URIs are not allowed in headers`); logger.warn(`taler://dev-experiment URIs are not allowed in headers`);
return; return;
case TalerUriType.TalerTemplate: case TalerUriAction.Exchange:
logger.warn(`taler://dev-template URIs are not allowed in headers`); logger.warn(`taler://exchange not yet supported`);
return;
case TalerUriAction.Auditor:
logger.warn(`taler://auditor not yet supported`);
return; return;
default: { default: {
const error: never = uriType; const error: never = uri;
logger.warn( logger.warn(
`Response with HTTP 402 the Taler header "${error}", but header value is not a taler:// URI.`, `Response with HTTP 402 the Taler header "${error}", but header value is not a taler:// URI.`,
); );

View File

@ -20,7 +20,11 @@
* @author sebasjm * @author sebasjm
*/ */
import { TranslatedString } from "@gnu-taler/taler-util"; import {
TalerUriAction,
TranslatedString,
parseTalerUri,
} from "@gnu-taler/taler-util";
import { createHashHistory } from "history"; import { createHashHistory } from "history";
import { ComponentChildren, Fragment, h, VNode } from "preact"; import { ComponentChildren, Fragment, h, VNode } from "preact";
import { route, Route, Router } from "preact-router"; import { route, Route, Router } from "preact-router";
@ -55,7 +59,12 @@ import {
WithdrawPageFromParams, WithdrawPageFromParams,
WithdrawPageFromURI, WithdrawPageFromURI,
} from "../cta/Withdraw/index.js"; } 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 { platform } from "../platform/foreground.js";
import CloseIcon from "../svg/close_24px.svg"; import CloseIcon from "../svg/close_24px.svg";
import { AddBackupProviderPage } from "./AddBackupProvider/index.js"; import { AddBackupProviderPage } from "./AddBackupProvider/index.js";
@ -285,12 +294,22 @@ export function Application(): VNode {
{/** {/**
* CALL TO ACTION * CALL TO ACTION
*/} */}
<Route
path={Pages.defaultCta.pattern}
component={({ uri }: { uri: string }) => {
const path = getPathnameForTalerURI(uri);
if (!path) {
return <Redirect to={Pages.balance} />;
}
return <Redirect to={path} />;
}}
/>
<Route <Route
path={Pages.ctaPay} path={Pages.ctaPay}
component={({ talerPayUri }: { talerPayUri: string }) => ( component={({ talerUri }: { talerUri: string }) => (
<CallToActionTemplate title={i18n.str`Digital cash payment`}> <CallToActionTemplate title={i18n.str`Digital cash payment`}>
<PaymentPage <PaymentPage
talerPayUri={decodeURIComponent(talerPayUri)} talerPayUri={decodeURIComponent(talerUri)}
goToWalletManualWithdraw={(amount?: string) => goToWalletManualWithdraw={(amount?: string) =>
redirectTo(Pages.receiveCash({ amount })) redirectTo(Pages.receiveCash({ amount }))
} }
@ -304,14 +323,10 @@ export function Application(): VNode {
/> />
<Route <Route
path={Pages.ctaPayTemplate} path={Pages.ctaPayTemplate}
component={({ component={({ talerUri }: { talerUri: string }) => (
talerPayTemplateUri,
}: {
talerPayTemplateUri: string;
}) => (
<CallToActionTemplate title={i18n.str`Digital cash payment`}> <CallToActionTemplate title={i18n.str`Digital cash payment`}>
<PaymentTemplatePage <PaymentTemplatePage
talerTemplateUri={decodeURIComponent(talerPayTemplateUri)} talerTemplateUri={decodeURIComponent(talerUri)}
goToWalletManualWithdraw={(amount?: string) => goToWalletManualWithdraw={(amount?: string) =>
redirectTo(Pages.receiveCash({ amount })) redirectTo(Pages.receiveCash({ amount }))
} }
@ -325,10 +340,10 @@ export function Application(): VNode {
/> />
<Route <Route
path={Pages.ctaRefund} path={Pages.ctaRefund}
component={({ talerRefundUri }: { talerRefundUri: string }) => ( component={({ talerUri }: { talerUri: string }) => (
<CallToActionTemplate title={i18n.str`Digital cash refund`}> <CallToActionTemplate title={i18n.str`Digital cash refund`}>
<RefundPage <RefundPage
talerRefundUri={decodeURIComponent(talerRefundUri)} talerRefundUri={decodeURIComponent(talerUri)}
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid: string) => onSuccess={(tid: string) =>
redirectTo(Pages.balanceTransaction({ tid })) redirectTo(Pages.balanceTransaction({ tid }))
@ -339,10 +354,10 @@ export function Application(): VNode {
/> />
<Route <Route
path={Pages.ctaTips} path={Pages.ctaTips}
component={({ talerTipUri }: { talerTipUri: string }) => ( component={({ talerUri }: { talerUri: string }) => (
<CallToActionTemplate title={i18n.str`Digital cash tip`}> <CallToActionTemplate title={i18n.str`Digital cash tip`}>
<TipPage <TipPage
talerTipUri={decodeURIComponent(talerTipUri)} talerTipUri={decodeURIComponent(talerUri)}
onCancel={() => redirectTo(Pages.balance)} onCancel={() => redirectTo(Pages.balance)}
onSuccess={(tid: string) => onSuccess={(tid: string) =>
redirectTo(Pages.balanceTransaction({ tid })) redirectTo(Pages.balanceTransaction({ tid }))
@ -353,14 +368,10 @@ export function Application(): VNode {
/> />
<Route <Route
path={Pages.ctaWithdraw} path={Pages.ctaWithdraw}
component={({ component={({ talerUri }: { talerUri: string }) => (
talerWithdrawUri,
}: {
talerWithdrawUri: string;
}) => (
<CallToActionTemplate title={i18n.str`Digital cash withdrawal`}> <CallToActionTemplate title={i18n.str`Digital cash withdrawal`}>
<WithdrawPageFromURI <WithdrawPageFromURI
talerWithdrawUri={decodeURIComponent(talerWithdrawUri)} talerWithdrawUri={decodeURIComponent(talerUri)}
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid: string) => onSuccess={(tid: string) =>
redirectTo(Pages.balanceTransaction({ tid })) redirectTo(Pages.balanceTransaction({ tid }))
@ -387,15 +398,15 @@ export function Application(): VNode {
path={Pages.ctaDeposit} path={Pages.ctaDeposit}
component={({ component={({
amount, amount,
talerDepositUri, talerUri,
}: { }: {
amount: string; amount: string;
talerDepositUri: string; talerUri: string;
}) => ( }) => (
<CallToActionTemplate title={i18n.str`Digital cash deposit`}> <CallToActionTemplate title={i18n.str`Digital cash deposit`}>
<DepositPageCTA <DepositPageCTA
amountStr={amount} amountStr={amount}
talerDepositUri={decodeURIComponent(talerDepositUri)} talerDepositUri={decodeURIComponent(talerUri)}
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid: string) => onSuccess={(tid: string) =>
redirectTo(Pages.balanceTransaction({ tid })) redirectTo(Pages.balanceTransaction({ tid }))
@ -434,10 +445,10 @@ export function Application(): VNode {
/> />
<Route <Route
path={Pages.ctaInvoicePay} path={Pages.ctaInvoicePay}
component={({ talerPayPullUri }: { talerPayPullUri: string }) => ( component={({ talerUri }: { talerUri: string }) => (
<CallToActionTemplate title={i18n.str`Digital cash invoice`}> <CallToActionTemplate title={i18n.str`Digital cash invoice`}>
<InvoicePayPage <InvoicePayPage
talerPayPullUri={decodeURIComponent(talerPayPullUri)} talerPayPullUri={decodeURIComponent(talerUri)}
goToWalletManualWithdraw={(amount?: string) => goToWalletManualWithdraw={(amount?: string) =>
redirectTo(Pages.receiveCash({ amount })) redirectTo(Pages.receiveCash({ amount }))
} }
@ -451,10 +462,10 @@ export function Application(): VNode {
/> />
<Route <Route
path={Pages.ctaTransferPickup} path={Pages.ctaTransferPickup}
component={({ talerPayPushUri }: { talerPayPushUri: string }) => ( component={({ talerUri }: { talerUri: string }) => (
<CallToActionTemplate title={i18n.str`Digital cash transfer`}> <CallToActionTemplate title={i18n.str`Digital cash transfer`}>
<TransferPickupPage <TransferPickupPage
talerPayPushUri={decodeURIComponent(talerPayPushUri)} talerPayPushUri={decodeURIComponent(talerUri)}
onClose={() => redirectTo(Pages.balance)} onClose={() => redirectTo(Pages.balance)}
onSuccess={(tid: string) => onSuccess={(tid: string) =>
redirectTo(Pages.balanceTransaction({ tid })) redirectTo(Pages.balanceTransaction({ tid }))

View File

@ -34,6 +34,8 @@ import {
WalletDiagnostics, WalletDiagnostics,
makeErrorDetail, makeErrorDetail,
getErrorDetailFromException, getErrorDetailFromException,
parseTalerUri,
TalerUriAction,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import {
DbAccess, DbAccess,
@ -332,69 +334,17 @@ function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void {
const talerUri = maybeTalerUri.startsWith("ext+") const talerUri = maybeTalerUri.startsWith("ext+")
? maybeTalerUri.substring(4) ? maybeTalerUri.substring(4)
: maybeTalerUri; : maybeTalerUri;
const uriType = classifyTalerUri(talerUri); const uri = parseTalerUri(talerUri);
switch (uriType) { if (!uri) {
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( logger.warn(
`Response with HTTP 402 the Taler header but could not classify ${talerUri}`, `Response with HTTP 402 the Taler header but could not classify ${talerUri}`,
); );
return; return;
case TalerUriType.TalerDevExperiment: }
// FIXME: Implement! return platform.redirectTabToWalletPage(
logger.warn("not implemented"); tabId,
return; `/taler-uri/${encodeURIComponent(talerUri)}`,
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;
}
}
} }
/** /**