diff options
8 files changed, 235 insertions, 180 deletions
diff --git a/packages/taler-wallet-webextension/src/components/Modal.tsx b/packages/taler-wallet-webextension/src/components/Modal.tsx index f8c0f1651..c5f716c76 100644 --- a/packages/taler-wallet-webextension/src/components/Modal.tsx +++ b/packages/taler-wallet-webextension/src/components/Modal.tsx @@ -52,8 +52,7 @@ const Body = styled.div` export function Modal({ title, children, onClose }: Props): VNode { return ( - <div style={{ top: 0, width: "100%", height: "100%" }}> - + <div style={{ top: 0, position: "fixed", width: "100%", height: "100%" }}> <FullSize onClick={onClose?.onClick}> <div onClick={(e) => e.stopPropagation()} diff --git a/packages/taler-wallet-webextension/src/components/WalletActivity.tsx b/packages/taler-wallet-webextension/src/components/WalletActivity.tsx index f29d0b0f7..b3b1a5c1f 100644 --- a/packages/taler-wallet-webextension/src/components/WalletActivity.tsx +++ b/packages/taler-wallet-webextension/src/components/WalletActivity.tsx @@ -39,6 +39,7 @@ import { WxApiType } from "../wxApi.js"; import { WalletActivityTrack } from "../wxBackend.js"; import { Modal } from "./Modal.js"; import { Time } from "./Time.js"; +import { Checkbox } from "./Checkbox.js"; const OPEN_ACTIVITY_HEIGHT_PX = 250; const CLOSE_ACTIVITY_HEIGHT_PX = 40; @@ -212,7 +213,10 @@ function ShowBackupOperationError({ events, onClick }: MoreInfoPRops): VNode { <dd>{error.hint ?? "--"}</dd> <dt>Time</dt> <dd> - <Time timestamp={error.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time + timestamp={error.when} + format="yyyy/MM/dd HH:mm:ss.SSS" + /> </dd> </dl> <pre @@ -360,28 +364,36 @@ function ShowObservabilityEvent({ events, onClick }: MoreInfoPRops): VNode { const title = (function () { switch (not.event.type) { - case ObservabilityEventType.HttpFetchFinishError: - case ObservabilityEventType.HttpFetchFinishSuccess: case ObservabilityEventType.HttpFetchStart: return "HTTP Request"; - case ObservabilityEventType.DbQueryFinishSuccess: - case ObservabilityEventType.DbQueryFinishError: + case ObservabilityEventType.HttpFetchFinishSuccess: + return "HTTP Request (o)"; + case ObservabilityEventType.HttpFetchFinishError: + return "HTTP Request (x)"; case ObservabilityEventType.DbQueryStart: return "Database"; - case ObservabilityEventType.RequestFinishSuccess: - case ObservabilityEventType.RequestFinishError: + case ObservabilityEventType.DbQueryFinishSuccess: + return "Database (o)"; + case ObservabilityEventType.DbQueryFinishError: + return "Database (x)"; case ObservabilityEventType.RequestStart: return "Wallet"; - case ObservabilityEventType.CryptoFinishSuccess: - case ObservabilityEventType.CryptoFinishError: + case ObservabilityEventType.RequestFinishSuccess: + return "Wallet (o)"; + case ObservabilityEventType.RequestFinishError: + return "Wallet (x)"; case ObservabilityEventType.CryptoStart: return "Crypto"; + case ObservabilityEventType.CryptoFinishSuccess: + return "Crypto (o)"; + case ObservabilityEventType.CryptoFinishError: + return "Crypto (x)"; case ObservabilityEventType.TaskStart: - return "Task start"; + return "Task"; case ObservabilityEventType.TaskStop: - return "Task stop"; + return "Task (s)"; case ObservabilityEventType.TaskReset: - return "Task reset"; + return "Task (r)"; case ObservabilityEventType.ShepherdTaskResult: return "Schedule"; case ObservabilityEventType.DeclareTaskDependency: @@ -401,12 +413,11 @@ function ShowObservabilityEvent({ events, onClick }: MoreInfoPRops): VNode { ); }); return ( - <table> + <table style={{ width: "100%" }}> <thead> <td>Event</td> <td>Info</td> - <td>Start</td> - <td>End</td> + <td>When</td> </thead> <tbody>{asd}</tbody> </table> @@ -417,11 +428,9 @@ function ShowObervavilityDetails({ title, notif, onClick, - prev, }: { title: string; notif: ObservaNotifWithTime; - prev?: ObservaNotifWithTime; onClick: (content: VNode) => void; }): VNode { switch (notif.event.type) { @@ -443,7 +452,7 @@ function ShowObervavilityDetails({ wordBreak: "break-word", }} > - {JSON.stringify({ event: notif, prev }, undefined, 2)} + {JSON.stringify({ event: notif }, undefined, 2)} </pre> </Fragment>, ); @@ -454,21 +463,21 @@ function ShowObervavilityDetails({ </td> <td> {notif.event.url}{" "} - {prev?.event.type === + {notif?.event.type === ObservabilityEventType.HttpFetchFinishSuccess ? ( - `(${prev.event.status})` - ) : prev?.event.type === + `(${notif.event.status})` + ) : notif?.event.type === ObservabilityEventType.HttpFetchFinishError ? ( <a href="#" onClick={(e) => { e.preventDefault(); if ( - prev.event.type !== + notif.event.type !== ObservabilityEventType.HttpFetchFinishError ) return; - const error = prev.event.error; + const error = notif.event.error; onClick( <Fragment> <dl> @@ -482,7 +491,7 @@ function ShowObervavilityDetails({ <dd> <Time timestamp={error.when} - format="yyyy/MM/dd HH:mm:ss" + format="yyyy/MM/dd HH:mm:ss.SSS" /> </dd> </dl> @@ -504,11 +513,7 @@ function ShowObervavilityDetails({ </td> <td> {" "} - <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss" /> - </td> - <td> - {" "} - <Time timestamp={prev?.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss.SSS" /> </td> </tr> ); @@ -531,7 +536,7 @@ function ShowObervavilityDetails({ wordBreak: "break-word", }} > - {JSON.stringify({ event: notif, prev }, undefined, 2)} + {JSON.stringify({ event: notif }, undefined, 2)} </pre> </Fragment>, ); @@ -544,10 +549,7 @@ function ShowObervavilityDetails({ {notif.event.location} {notif.event.name} </td> <td> - <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss" /> - </td> - <td> - <Time timestamp={prev?.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss.SSS" /> </td> </tr> ); @@ -572,7 +574,7 @@ function ShowObervavilityDetails({ wordBreak: "break-word", }} > - {JSON.stringify({ event: notif, prev }, undefined, 2)} + {JSON.stringify({ event: notif }, undefined, 2)} </pre> </Fragment>, ); @@ -583,10 +585,7 @@ function ShowObervavilityDetails({ </td> <td>{notif.event.taskId}</td> <td> - <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss" /> - </td> - <td> - <Time timestamp={prev?.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss.SSS" /> </td> </tr> ); @@ -607,7 +606,7 @@ function ShowObervavilityDetails({ wordBreak: "break-word", }} > - {JSON.stringify({ event: notif, prev }, undefined, 2)} + {JSON.stringify({ event: notif }, undefined, 2)} </pre> </Fragment>, ); @@ -618,10 +617,7 @@ function ShowObervavilityDetails({ </td> <td>{notif.event.resultType}</td> <td> - <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss" /> - </td> - <td> - <Time timestamp={prev?.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss.SSS" /> </td> </tr> ); @@ -644,7 +640,7 @@ function ShowObervavilityDetails({ wordBreak: "break-word", }} > - {JSON.stringify({ event: notif, prev }, undefined, 2)} + {JSON.stringify({ event: notif }, undefined, 2)} </pre> </Fragment>, ); @@ -655,10 +651,7 @@ function ShowObervavilityDetails({ </td> <td>{notif.event.operation}</td> <td> - <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss" /> - </td> - <td> - <Time timestamp={prev?.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss.SSS" /> </td> </tr> ); @@ -681,7 +674,7 @@ function ShowObervavilityDetails({ wordBreak: "break-word", }} > - {JSON.stringify({ event: notif, prev }, undefined, 2)} + {JSON.stringify({ event: notif }, undefined, 2)} </pre> </Fragment>, ); @@ -692,10 +685,7 @@ function ShowObervavilityDetails({ </td> <td>{notif.event.type}</td> <td> - <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss" /> - </td> - <td> - <Time timestamp={prev?.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={notif.when} format="yyyy/MM/dd HH:mm:ss.SSS" /> </td> </tr> ); @@ -706,13 +696,18 @@ function ShowObervavilityDetails({ } } +function createTabId(tab: chrome.tabs.Tab | undefined) { + return !tab ? "popup" : `${tab.windowId}:${tab.id}`; +} + function refresh( api: WxApiType, onUpdate: (list: WalletActivityTrack[]) => void, filter: string, + fromView?: chrome.tabs.Tab, ) { api.background - .call("getNotifications", { filter }) + .call("getNotifications", { filter, operationsFrom: createTabId(fromView) }) .then((notif) => { onUpdate(notif); }) @@ -721,6 +716,15 @@ function refresh( }); } +let currentTab: chrome.tabs.Tab | undefined; +// Allow running outside the extension for testing +// tslint:disable-next-line:no-string-literal +if (typeof chrome !== "undefined") { + chrome.tabs.getCurrent().then((d) => { + currentTab = d; + }); +} + export function ObservabilityEventsTable(): VNode { const { i18n } = useTranslationContext(); const api = useBackendContext(); @@ -728,11 +732,17 @@ export function ObservabilityEventsTable(): VNode { const [notifications, setNotifications] = useState<WalletActivityTrack[]>([]); const [showDetails, setShowDetails] = useState<VNode>(); const [filter, onChangeFilter] = useState(""); + const [onlyThisScreen, setOnlyThisScreen] = useState(true); useEffect(() => { let lastTimeout: ReturnType<typeof setTimeout>; function periodicRefresh() { - refresh(api, setNotifications, filter); + refresh( + api, + setNotifications, + filter, + onlyThisScreen ? currentTab : undefined, + ); lastTimeout = setTimeout(() => { periodicRefresh(); @@ -743,7 +753,7 @@ export function ObservabilityEventsTable(): VNode { }; } return periodicRefresh(); - }, [filter]); + }, [filter, onlyThisScreen]); return ( <div> @@ -754,6 +764,12 @@ export function ObservabilityEventsTable(): VNode { value={filter} onChange={onChangeFilter} /> + <Checkbox + label={i18n.str`All events`} + name="terms" + onToggle={async () => setOnlyThisScreen((v) => !v)} + enabled={!onlyThisScreen} + /> <div style={{ padding: 4, @@ -763,7 +779,12 @@ export function ObservabilityEventsTable(): VNode { }} onClick={() => { api.background.call("clearNotifications", undefined).then(() => { - refresh(api, setNotifications, filter); + refresh( + api, + setNotifications, + filter, + onlyThisScreen ? currentTab : undefined, + ); }); }} > @@ -784,7 +805,7 @@ export function ObservabilityEventsTable(): VNode { )} {notifications.map((not) => { return ( - <details key={not.id}> + <details key={not.groupId}> <summary> <div style={{ @@ -829,10 +850,13 @@ export function ObservabilityEventsTable(): VNode { })()} </div> <div style={{ padding: 4 }}> - <Time timestamp={not.start} format="yyyy/MM/dd HH:mm:ss" /> + <Time + timestamp={not.start} + format="yyyy/MM/dd HH:mm:ss.SSS" + /> </div> <div style={{ padding: 4 }}> - <Time timestamp={not.end} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={not.end} format="yyyy/MM/dd HH:mm:ss.SSS" /> </div> </div> </summary> @@ -936,7 +960,7 @@ function ErroDetailModal({ <dd>{error.hint ?? "--"}</dd> <dt>Time</dt> <dd> - <Time timestamp={error.when} format="yyyy/MM/dd HH:mm:ss" /> + <Time timestamp={error.when} format="yyyy/MM/dd HH:mm:ss.SSS" /> </dd> </dl> <pre style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}> @@ -1009,11 +1033,14 @@ export function ActiveTasksTable(): VNode { <td> <Time timestamp={task.firstTry} - format="yyyy/MM/dd HH:mm:ss" + format="yyyy/MM/dd HH:mm:ss.SSS" /> </td> <td> - <Time timestamp={task.nextTry} format="yyyy/MM/dd HH:mm:ss" /> + <Time + timestamp={task.nextTry} + format="yyyy/MM/dd HH:mm:ss.SSS" + /> </td> <td> {!task.lastError?.code ? ( diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts index 3c116fab2..2388647c1 100644 --- a/packages/taler-wallet-webextension/src/platform/api.ts +++ b/packages/taler-wallet-webextension/src/platform/api.ts @@ -227,6 +227,7 @@ export interface BackgroundPlatformAPI { listenToAllChannels( notifyNewMessage: <Op extends WalletOperations | BackgroundOperations>( message: MessageFromFrontend<Op> & { id: string }, + from: string, ) => Promise<MessageResponse>, ): void; diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index 056351e3f..276d464a0 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -53,7 +53,7 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { redirectTabToWalletPage, registerAllIncomingConnections, registerOnInstalled, - listenToAllChannels , + listenToAllChannels, registerReloadOnNewVersion, sendMessageToAllChannels, openNewURLFromPopup, @@ -276,18 +276,20 @@ async function sendMessageToBackground< Op extends WalletOperations | BackgroundOperations, >(message: MessageFromFrontend<Op>): Promise<MessageResponse> { nextMessageIndex = (nextMessageIndex + 1) % (Number.MAX_SAFE_INTEGER - 100); - const messageWithId = { ...message, id: `id_${nextMessageIndex}` }; + const messageWithId = { ...message, id: `fg:${nextMessageIndex}` }; return new Promise<MessageResponse>((resolve, reject) => { logger.trace("send operation to the wallet background", message); let timedout = false; const timerId = setTimeout(() => { timedout = true; - reject(TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, { - requestMethod: "wallet", - requestUrl: message.operation, - timeoutMs: 20 * 1000, - })); + reject( + TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, { + requestMethod: "wallet", + requestUrl: message.operation, + timeoutMs: 20 * 1000, + }), + ); }, 20 * 1000); chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => { if (timedout) { @@ -309,7 +311,9 @@ async function sendMessageToBackground< * To be used by the foreground */ let notificationPort: chrome.runtime.Port | undefined; -function listenToWalletBackground(listener: (message: MessageFromBackend) => void): () => void { +function listenToWalletBackground( + listener: (message: MessageFromBackend) => void, +): () => void { if (notificationPort === undefined) { notificationPort = chrome.runtime.connect({ name: "notifications" }); } @@ -380,13 +384,18 @@ function registerAllIncomingConnections(): void { }); } +function createTabId(tab: chrome.tabs.Tab | undefined) { + return !tab ? "popup" : `${tab.windowId}:${tab.id}`; +} + function listenToAllChannels( notifyNewMessage: <Op extends WalletOperations | BackgroundOperations>( message: MessageFromFrontend<Op> & { id: string }, + id: string, ) => Promise<MessageResponse>, ): void { chrome.runtime.onMessage.addListener((message, sender, reply) => { - notifyNewMessage(message) + notifyNewMessage(message, createTabId(sender.tab)) .then((apiResponse) => { try { reply(apiResponse); @@ -483,26 +492,26 @@ function setAlertedIcon(): void { interface OffscreenCanvasRenderingContext2D extends CanvasState, - CanvasTransform, - CanvasCompositing, - CanvasImageSmoothing, - CanvasFillStrokeStyles, - CanvasShadowStyles, - CanvasFilters, - CanvasRect, - CanvasDrawPath, - CanvasUserInterface, - CanvasText, - CanvasDrawImage, - CanvasImageData, - CanvasPathDrawingStyles, - CanvasTextDrawingStyles, - CanvasPath { + CanvasTransform, + CanvasCompositing, + CanvasImageSmoothing, + CanvasFillStrokeStyles, + CanvasShadowStyles, + CanvasFilters, + CanvasRect, + CanvasDrawPath, + CanvasUserInterface, + CanvasText, + CanvasDrawImage, + CanvasImageData, + CanvasPathDrawingStyles, + CanvasTextDrawingStyles, + CanvasPath { readonly canvas: OffscreenCanvas; } declare const OffscreenCanvasRenderingContext2D: { prototype: OffscreenCanvasRenderingContext2D; - new(): OffscreenCanvasRenderingContext2D; + new (): OffscreenCanvasRenderingContext2D; }; interface OffscreenCanvas extends EventTarget { @@ -515,7 +524,7 @@ interface OffscreenCanvas extends EventTarget { } declare const OffscreenCanvas: { prototype: OffscreenCanvas; - new(width: number, height: number): OffscreenCanvas; + new (width: number, height: number): OffscreenCanvas; }; function createCanvas(size: number): OffscreenCanvas { @@ -760,7 +769,6 @@ function listenNetworkConnectionState( }; } - function runningOnPrivateMode(): boolean { return chrome.extension.inIncognitoContext; } diff --git a/packages/taler-wallet-webextension/src/platform/dev.ts b/packages/taler-wallet-webextension/src/platform/dev.ts index b53e8f3c4..844a5c517 100644 --- a/packages/taler-wallet-webextension/src/platform/dev.ts +++ b/packages/taler-wallet-webextension/src/platform/dev.ts @@ -95,7 +95,7 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { useServiceWorkerAsBackgroundProcess: () => false, listenToAllChannels: ( - notifyNewMessage: (message: any) => Promise<MessageResponse>, + notifyNewMessage: (message: any, from: string) => Promise<MessageResponse>, ) => { window.addEventListener( "message", @@ -103,7 +103,7 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { if (event.data.type !== "command") return; const sender = event.data.header.replyMe; - notifyNewMessage(event.data.body as any).then((resp) => { + notifyNewMessage(event.data.body as any, sender).then((resp) => { logger.trace(`listenToAllChannels: from ${sender}`, event); if (event.source) { const msg: IframeMessageResponse = { @@ -199,4 +199,3 @@ interface IframeMessageCommand { } export default api; - diff --git a/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts index 3b7cbcbb7..5e781121b 100644 --- a/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts +++ b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts @@ -14,7 +14,11 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { CoreApiResponse, TalerError, TalerErrorCode } from "@gnu-taler/taler-util"; +import { + CoreApiResponse, + TalerError, + TalerErrorCode, +} from "@gnu-taler/taler-util"; import type { MessageFromBackend } from "./platform/api.js"; /** @@ -51,8 +55,6 @@ const rootElementIsHTML = // "meta[name=taler-support]", // ); - - function validateTalerUri(uri: string): boolean { return ( !!uri && (uri.startsWith("taler://") || uri.startsWith("taler+http://")) @@ -61,7 +63,9 @@ function validateTalerUri(uri: string): boolean { function convertURIToWebExtensionPath(uri: string) { const url = new URL( - chrome.runtime.getURL(`static/wallet.html#/taler-uri/${encodeURIComponent(uri)}`), + chrome.runtime.getURL( + `static/wallet.html#/taler-uri/${encodeURIComponent(uri)}`, + ), ); return url.href; } @@ -75,7 +79,7 @@ const shouldNotInject = !rootElementIsHTML; const logger = { - debug: (...msg: any[]) => { }, + debug: (...msg: any[]) => {}, info: (...msg: any[]) => console.log(`${new Date().toISOString()} TALER`, ...msg), error: (...msg: any[]) => @@ -87,7 +91,7 @@ const logger = { /** */ function redirectToTalerActionHandler(element: HTMLMetaElement) { - const name = element.getAttribute("name") + const name = element.getAttribute("name"); if (!name) return; if (name !== "taler-uri") return; const uri = element.getAttribute("content"); @@ -98,20 +102,20 @@ function redirectToTalerActionHandler(element: HTMLMetaElement) { return; } - const walletPage = convertURIToWebExtensionPath(uri) - window.location.replace(walletPage) + const walletPage = convertURIToWebExtensionPath(uri); + window.location.replace(walletPage); } function injectTalerSupportScript(head: HTMLHeadElement, trusted: boolean) { - const meta = head.querySelector("meta[name=taler-support]") + const meta = head.querySelector("meta[name=taler-support]"); if (!meta) return; const content = meta.getAttribute("content"); if (!content) return; - const features = content.split(",") + const features = content.split(","); const debugEnabled = meta.getAttribute("debug") === "true"; - const hijackEnabled = features.indexOf("uri") !== -1 - const talerApiEnabled = features.indexOf("api") !== -1 && trusted + const hijackEnabled = features.indexOf("uri") !== -1; + const talerApiEnabled = features.indexOf("api") !== -1 && trusted; const scriptTag = document.createElement("script"); scriptTag.setAttribute("async", "false"); @@ -131,14 +135,16 @@ function injectTalerSupportScript(head: HTMLHeadElement, trusted: boolean) { scriptTag.src = url.href; try { - head.insertBefore(scriptTag, head.children.length ? head.children[0] : null); + head.insertBefore( + scriptTag, + head.children.length ? head.children[0] : null, + ); } catch (e) { logger.info("inserting link handler failed!"); logger.error(e); } } - export interface ExtensionOperations { isAutoOpenEnabled: { request: void; @@ -177,31 +183,38 @@ async function callBackground<Op extends keyof ExtensionOperations>( return response.result as any; } - let nextMessageIndex = 0; /** - * - * @param message - * @returns + * + * @param message + * @returns */ async function sendMessageToBackground<Op extends keyof ExtensionOperations>( message: MessageFromExtension<Op>, ): Promise<MessageResponse> { - const messageWithId = { ...message, id: `id_${nextMessageIndex++ % 1000}` }; + const messageWithId = { ...message, id: `ld:${nextMessageIndex++ % 1000}` }; if (!chrome.runtime.id) { - return Promise.reject(TalerError.fromDetail(TalerErrorCode.WALLET_CORE_NOT_AVAILABLE, {})) + return Promise.reject( + TalerError.fromDetail(TalerErrorCode.WALLET_CORE_NOT_AVAILABLE, {}), + ); } return new Promise<any>((resolve, reject) => { - logger.debug("send operation to the wallet background", message, chrome.runtime.id); + logger.debug( + "send operation to the wallet background", + message, + chrome.runtime.id, + ); let timedout = false; const timerId = setTimeout(() => { timedout = true; - reject(TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, { - requestMethod: "wallet", - requestUrl: message.operation, - timeoutMs: 20 * 1000, - })) + reject( + TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, { + requestMethod: "wallet", + requestUrl: message.operation, + timeoutMs: 20 * 1000, + }), + ); }, 20 * 1000); //five seconds try { chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => { @@ -218,7 +231,7 @@ async function sendMessageToBackground<Op extends keyof ExtensionOperations>( return true; }); } catch (e) { - console.log(e) + console.log(e); } }); } @@ -240,71 +253,76 @@ function listenToWalletBackground(listener: (m: any) => void): () => void { const loaderSettings = { isAutoOpenEnabled: false, isDomainTrusted: false, -} +}; function start( onTalerMetaTagFound: (listener: (el: HTMLMetaElement) => void) => void, - onHeadReady: (listener: (el: HTMLHeadElement) => void) => void + onHeadReady: (listener: (el: HTMLHeadElement) => void) => void, ) { // do not run everywhere, this is just expected to run on site // that are aware of taler if (shouldNotInject) return; - const isAutoOpenEnabled_promise = callBackground("isAutoOpenEnabled", undefined).then(result => { + const isAutoOpenEnabled_promise = callBackground( + "isAutoOpenEnabled", + undefined, + ).then((result) => { loaderSettings.isAutoOpenEnabled = result; return result; - }) + }); const isDomainTrusted_promise = callBackground("isDomainTrusted", { - domain: window.location.origin - }).then(result => { + domain: window.location.origin, + }).then((result) => { loaderSettings.isDomainTrusted = result; return result; - }) + }); onTalerMetaTagFound(async (el) => { await isAutoOpenEnabled_promise; if (!loaderSettings.isAutoOpenEnabled) { return; } - redirectToTalerActionHandler(el) - }) + redirectToTalerActionHandler(el); + }); onHeadReady(async (el) => { - const trusted = await isDomainTrusted_promise - injectTalerSupportScript(el, trusted) - }) + const trusted = await isDomainTrusted_promise; + injectTalerSupportScript(el, trusted); + }); listenToWalletBackground((e: MessageFromBackend) => { - if (e.type === "web-extension" && e.notification.type === "settings-change") { - const settings = e.notification.currentValue - loaderSettings.isAutoOpenEnabled = settings.autoOpen + if ( + e.type === "web-extension" && + e.notification.type === "settings-change" + ) { + const settings = e.notification.currentValue; + loaderSettings.isAutoOpenEnabled = settings.autoOpen; } - }) - + }); } function isCorrectMetaElement(el: HTMLMetaElement): boolean { - const name = el.getAttribute("name") + const name = el.getAttribute("name"); if (!name) return false; if (name !== "taler-uri") return false; const uri = el.getAttribute("content"); if (!uri) return false; - return true + return true; } /** * Tries to find taler meta tag ASAP and report - * @param notify - * @returns + * @param notify + * @returns */ function notifyWhenTalerUriIsFound(notify: (el: HTMLMetaElement) => void) { if (document.head) { - const element = document.head.querySelector("meta[name=taler-uri]") + const element = document.head.querySelector("meta[name=taler-uri]"); if (!element) return; if (!(element instanceof HTMLMetaElement)) return; if (isCorrectMetaElement(element)) { - notify(element) + notify(element); } return; } @@ -315,34 +333,33 @@ function notifyWhenTalerUriIsFound(notify: (el: HTMLMetaElement) => void) { mut.addedNodes.forEach((added) => { if (added instanceof HTMLMetaElement) { if (isCorrectMetaElement(added)) { - notify(added) - obs.disconnect() + notify(added); + obs.disconnect(); } } }); } }); } catch (e) { - console.error(e) + console.error(e); } - }) + }); obs.observe(document, { childList: true, subtree: true, attributes: false, - }) - + }); } /** * Tries to find HEAD tag ASAP and report - * @param notify - * @returns + * @param notify + * @returns */ function notifyWhenHeadIsFound(notify: (el: HTMLHeadElement) => void) { if (document.head) { - notify(document.head) + notify(document.head); return; } const obs = new MutationObserver(async function (mutations) { @@ -351,22 +368,22 @@ function notifyWhenHeadIsFound(notify: (el: HTMLHeadElement) => void) { if (mut.type === "childList") { mut.addedNodes.forEach((added) => { if (added instanceof HTMLHeadElement) { - notify(added) - obs.disconnect() + notify(added); + obs.disconnect(); } }); } }); } catch (e) { - console.error(e) + console.error(e); } - }) + }); obs.observe(document, { childList: true, subtree: true, attributes: false, - }) + }); } start(notifyWhenTalerUriIsFound, notifyWhenHeadIsFound); diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts index 0fed0a855..57a49f0cb 100644 --- a/packages/taler-wallet-webextension/src/wxApi.ts +++ b/packages/taler-wallet-webextension/src/wxApi.ts @@ -77,6 +77,7 @@ export interface BackgroundOperations { getNotifications: { request: { filter: string; + operationsFrom?: string; }; response: WalletActivityTrack[]; }; diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index 1601f7703..ab3c465c4 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -91,19 +91,15 @@ async function resetDb(): Promise<void> { } export type WalletActivityTrack = { - id: number; + // id: number; events: (WalletNotification & { when: AbsoluteTime })[]; start: AbsoluteTime; type: NotificationType; end: AbsoluteTime; groupId: string; + requestId?: string; //only for request event }; -let counter = 0; -function getUniqueId(): number { - return counter++; -} - //FIXME: maybe circular buffer const activity: WalletActivityTrack[] = []; @@ -123,7 +119,6 @@ function convertWalletActivityNotification( return undefined; } return { - id: getUniqueId(), type: event.type, start: event.when, end: AbsoluteTime.never(), @@ -134,7 +129,6 @@ function convertWalletActivityNotification( case NotificationType.BackupOperationError: { const groupId = ""; return { - id: getUniqueId(), type: event.type, start: event.when, end: AbsoluteTime.never(), @@ -151,7 +145,6 @@ function convertWalletActivityNotification( return undefined; } return { - id: getUniqueId(), type: event.type, start: event.when, end: AbsoluteTime.never(), @@ -171,7 +164,6 @@ function convertWalletActivityNotification( return undefined; } return { - id: getUniqueId(), type: event.type, start: event.when, end: AbsoluteTime.never(), @@ -182,7 +174,6 @@ function convertWalletActivityNotification( case NotificationType.Idle: { const groupId = ""; return { - id: getUniqueId(), type: event.type, start: event.when, end: AbsoluteTime.never(), @@ -199,7 +190,6 @@ function convertWalletActivityNotification( return undefined; } return { - id: getUniqueId(), type: event.type, start: event.when, end: AbsoluteTime.never(), @@ -216,12 +206,12 @@ function convertWalletActivityNotification( return undefined; } return { - id: getUniqueId(), type: event.type, start: event.when, end: AbsoluteTime.never(), events: [event], groupId, + requestId: event.requestId, }; } } @@ -241,14 +231,24 @@ function addNewWalletActivityNotification( async function getNotifications({ filter, + operationFrom, }: { filter: string; + operationFrom?: string; }): Promise<WalletActivityTrack[]> { - if (!filter) return activity; - const rg = new RegExp(`.*${filter}.*`); return activity.filter((event) => { - return rg.test(event.groupId.toLowerCase()); + if (operationFrom) { + if (event.type !== NotificationType.RequestObservabilityEvent) { + return false; + } + if (event.requestId) { + return event.requestId.startsWith(operationFrom); + } + } + if (!filter) return true; + const testFilter = rg.test(event.groupId.toLowerCase()); + return testFilter; }); } @@ -318,7 +318,10 @@ let nextMessageIndex = 0; async function dispatch< Op extends WalletOperations | BackgroundOperations | ExtensionOperations, ->(req: MessageFromFrontend<Op> & { id: string }): Promise<MessageResponse> { +>( + req: MessageFromFrontend<Op> & { id: string }, + from: string, +): Promise<MessageResponse> { nextMessageIndex = (nextMessageIndex + 1) % (Number.MAX_SAFE_INTEGER - 100); switch (req.channel) { @@ -402,7 +405,7 @@ async function dispatch< }; } //multiple client can create the same id, send the wallet an unique key - const newId = `${req.id}_${nextMessageIndex}`; + const newId = `${from}:${req.id}`; const resp = await w.handleCoreApiRequest( req.operation, newId, @@ -516,10 +519,10 @@ export async function wxMain(): Promise<void> { // Handlers for messages coming directly from the content // script on the page logger.trace("listen all channels"); - platform.listenToAllChannels(async (message) => { + platform.listenToAllChannels(async (message, from) => { //wait until wallet is initialized await afterWalletIsInitialized; - const result = await dispatch(message); + const result = await dispatch(message, from); return result; }); |