diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/platform/dev.ts')
-rw-r--r-- | packages/taler-wallet-webextension/src/platform/dev.ts | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/packages/taler-wallet-webextension/src/platform/dev.ts b/packages/taler-wallet-webextension/src/platform/dev.ts new file mode 100644 index 000000000..d6e743147 --- /dev/null +++ b/packages/taler-wallet-webextension/src/platform/dev.ts @@ -0,0 +1,218 @@ +/* + This file is part of GNU Taler + (C) 2022 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 { Logger, TalerUri } from "@gnu-taler/taler-util"; +import { WalletOperations } from "@gnu-taler/taler-wallet-core"; +import { BackgroundOperations } from "../wxApi.js"; +import { + BackgroundPlatformAPI, + ForegroundPlatformAPI, + MessageFromBackend, + MessageFromFrontend, + MessageResponse, + defaultSettings, +} from "./api.js"; + +const logger = new Logger("dev.ts"); + +const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { + runningOnPrivateMode: () => false, + isFirefox: () => false, + getSettingsFromStorage: () => Promise.resolve(defaultSettings), + keepAlive: (cb: VoidFunction) => cb(), + findTalerUriInActiveTab: async () => undefined, + findTalerUriInClipboard: async () => undefined, + listenNetworkConnectionState, + openNewURLFromPopup: () => undefined, + triggerWalletEvent: () => undefined, + setAlertedIcon: () => undefined, + setNormalIcon : () => undefined, + getPermissionsApi: () => ({ + containsClipboardPermissions: async () => true, + removeClipboardPermissions: async () => false, + requestClipboardPermissions: async () => false, + }), + + getWalletWebExVersion: () => ({ + version: "none", + }), + notifyWhenAppIsReady: () => { + const knownFrames = ["popup", "wallet"]; + let total = knownFrames.length; + return new Promise((fn) => { + function waitAndNotify(): void { + total--; + logger.trace(`waitAndNotify ${total}`); + if (total < 1) { + fn(); + } + } + knownFrames.forEach((f) => { + const theFrame = window.frames[f as any]; + if (theFrame.location.href === "about:blank") { + waitAndNotify(); + } else { + theFrame.addEventListener("load", waitAndNotify); + } + }); + }); + }, + + openWalletPage: (page: string) => { + // @ts-ignore + window.parent.redirectWallet(`wallet.html#${page}`); + }, + openWalletPageFromPopup: (page: string) => { + // @ts-ignore + window.parent.redirectWallet(`wallet.html#${page}`); + // close the popup + // @ts-ignore + window.parent.closePopup(); + }, + openWalletURIFromPopup: (page: TalerUri) => { + alert("openWalletURIFromPopup not implemented yet"); + }, + redirectTabToWalletPage: (tabId: number, page: string) => { + alert("redirectTabToWalletPage not implemented yet"); + }, + registerAllIncomingConnections: () => undefined, + registerOnInstalled: () => Promise.resolve(), + registerReloadOnNewVersion: () => undefined, + + useServiceWorkerAsBackgroundProcess: () => false, + + listenToAllChannels: ( + notifyNewMessage: (message: any) => Promise<MessageResponse>, + ) => { + window.addEventListener( + "message", + (event: MessageEvent<IframeMessageType>) => { + if (event.data.type !== "command") return; + const sender = event.data.header.replyMe; + + notifyNewMessage(event.data.body as any).then((resp) => { + logger.trace(`listenToAllChannels: from ${sender}`, event); + if (event.source) { + const msg: IframeMessageResponse = { + type: "response", + header: { responseId: sender }, + body: resp, + }; + window.parent.postMessage(msg); + } + }); + }, + ); + }, + sendMessageToAllChannels: (message: MessageFromBackend) => { + Array.from(window.frames).forEach((w) => { + try { + w.postMessage({ + header: {}, + body: message, + }); + } catch (e) { + console.error(e); + } + }); + }, + listenToWalletBackground: (onNewMessage: (m: MessageFromBackend) => void) => { + function listener(event: MessageEvent<IframeMessageType>): void { + logger.trace(`listenToWalletBackground: `, event); + if (event.data.type !== "notification") return; + onNewMessage(event.data.body); + } + window.parent.addEventListener("message", listener); + return () => { + window.parent.removeEventListener("message", listener); + }; + }, + + sendMessageToBackground: async < + Op extends WalletOperations | BackgroundOperations, + >( + payload: MessageFromFrontend<Op>, + ): Promise<MessageResponse> => { + const replyMe = `reply-${Math.floor(Math.random() * 100000)}`; + const message: IframeMessageCommand = { + type: "command", + header: { replyMe }, + body: payload, + }; + + logger.trace(`sendMessageToBackground: `, message); + + return new Promise((res, rej) => { + function listener(event: MessageEvent<IframeMessageType>): void { + if ( + event.data.type !== "response" || + event.data.header.responseId !== replyMe + ) { + return; + } + res(event.data.body); + window.parent.removeEventListener("message", listener); + } + window.parent.addEventListener("message", listener, {}); + window.parent.postMessage(message); + }); + }, +}; + +type IframeMessageType = + | IframeMessageNotification + | IframeMessageResponse + | IframeMessageCommand; + +interface IframeMessageNotification { + type: "notification"; + header: Record<string, never>; + body: MessageFromBackend; +} +interface IframeMessageResponse { + type: "response"; + header: { + responseId: string; + }; + body: MessageResponse; +} + +interface IframeMessageCommand { + type: "command"; + header: { + replyMe: string; + }; + body: MessageFromFrontend<any>; +} + +export default api; + +function listenNetworkConnectionState( + notify: (state: "on" | "off") => void, +): () => void { + function notifyOffline() { + notify("off"); + } + function notifyOnline() { + notify("on"); + } + window.addEventListener("offline", notifyOffline); + window.addEventListener("online", notifyOnline); + return () => { + window.removeEventListener("offline", notifyOffline); + window.removeEventListener("online", notifyOnline); + }; +} |