aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/platform
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-03-25 16:57:27 -0300
committerSebastian <sebasjm@gmail.com>2022-03-25 16:58:00 -0300
commitddfb40e50cef0abddc7690b23562b1ca5aeb3fdd (patch)
tree231427a713e86b5fbdcdbc8cbcfc8b6c00392170 /packages/taler-wallet-webextension/src/platform
parent00fb648269c166c4995b38fe640748834fac7b18 (diff)
downloadwallet-core-ddfb40e50cef0abddc7690b23562b1ca5aeb3fdd.tar.xz
new dev environment
Diffstat (limited to 'packages/taler-wallet-webextension/src/platform')
-rw-r--r--packages/taler-wallet-webextension/src/platform/api.ts123
-rw-r--r--packages/taler-wallet-webextension/src/platform/chrome.ts38
-rw-r--r--packages/taler-wallet-webextension/src/platform/dev.ts159
3 files changed, 289 insertions, 31 deletions
diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts
index 9b4e02ffb..112f9721c 100644
--- a/packages/taler-wallet-webextension/src/platform/api.ts
+++ b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -38,7 +38,7 @@ export interface CrossBrowserPermissionsApi {
request(p: Permissions): Promise<boolean>;
remove(p: Permissions): Promise<boolean>;
- addPermissionsListener(callback: (p: Permissions) => void): void;
+ addPermissionsListener(callback: (p: Permissions, lastError?: string) => void): void;
}
@@ -57,31 +57,132 @@ export interface WalletVersion {
*/
export interface PlatformAPI {
/**
+ * FIXME: should not be needed
+ *
* check if the platform is firefox
*/
isFirefox(): boolean;
+
/**
- *
+ * Permission API for checking and add a listener
*/
getPermissionsApi(): CrossBrowserPermissionsApi;
+
+ /**
+ * Backend API
+ *
+ * Register a callback to be called when the wallet is ready to start
+ * @param callback
+ */
notifyWhenAppIsReady(callback: () => void): void;
- openWalletURIFromPopup(uriType: TalerUriType, talerUri: string): void;
+
+ /**
+ * Popup API
+ *
+ * Used when an TalerURI is found and open up from the popup UI.
+ * Closes the popup and open the URI into the wallet UI.
+ *
+ * @param talerUri
+ */
+ openWalletURIFromPopup(talerUri: string): void;
+
+ /**
+ * Backend API
+ *
+ * Open a page into the wallet UI
+ * @param page
+ */
openWalletPage(page: string): void;
+
+ /**
+ * Popup API
+ *
+ * Open a page into the wallet UI and closed the popup
+ * @param page
+ */
openWalletPageFromPopup(page: string): void;
- setMessageToWalletBackground(operation: string, payload: any): Promise<CoreApiResponse>;
- listenToWalletNotifications(listener: (m: any) => void): () => void;
- sendMessageToAllChannels(message: MessageFromBackend): void;
- registerAllIncomingConnections(): void;
- registerOnNewMessage(onNewMessage: (message: any, sender: any, callback: any) => void): void;
- registerReloadOnNewVersion(): void;
+
+ /**
+ * Backend API
+ *
+ * When a tab has been detected to have a Taler action the background process
+ * can use this function to redirect the tab to the wallet UI
+ *
+ * @param tabId
+ * @param page
+ */
redirectTabToWalletPage(tabId: number, page: string): void;
+
+ /**
+ * Get the wallet version from manifest
+ */
getWalletVersion(): WalletVersion;
+
+
+ /**
+ * Backend API
+ */
+ registerAllIncomingConnections(): void;
+ /**
+ * Backend API
+ */
+ registerReloadOnNewVersion(): void;
+ /**
+ * Backend API
+ */
registerTalerHeaderListener(onHeader: (tabId: number, url: string) => void): void;
+ /**
+ * Backend API
+ */
registerOnInstalled(callback: () => void): void;
+
+ /**
+ * Backend API
+ *
+ * Check if background process run as service worker. This is used from the
+ * wallet use different http api and crypto worker.
+ */
useServiceWorkerAsBackgroundProcess(): boolean;
- getLastError(): string | undefined;
- searchForTalerLinks(): string | undefined;
+
+ /**
+ * Popup API
+ *
+ * Read the current tab html and try to find any Taler URI or QR code present.
+ *
+ * @return Taler URI if found
+ */
findTalerUriInActiveTab(): Promise<string | undefined>;
+
+ /**
+ * Used from the frontend to send commands to the wallet
+ *
+ * @param operation
+ * @param payload
+ *
+ * @return response from the backend
+ */
+ sendMessageToWalletBackground(operation: string, payload: any): Promise<CoreApiResponse>;
+
+ /**
+ * Used from the frontend to receive notifications about new information
+ * @param listener
+ * @return function to unsubscribe the listener
+ */
+ listenToWalletBackground(listener: (message: MessageFromBackend) => void): () => void;
+
+ /**
+ * Use by the wallet backend to receive operations from frontend (popup & wallet)
+ * and send a response back.
+ *
+ * @param onNewMessage
+ */
+ listenToAllChannels(onNewMessage: (message: any, sender: any, sendResponse: (r: CoreApiResponse) => void) => void): void;
+
+ /**
+ * Used by the wallet backend to send notification about new information
+ * @param message
+ */
+ sendMessageToAllChannels(message: MessageFromBackend): void;
}
export let platform: PlatformAPI = undefined as any;
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts
index dada23c57..91ccc220d 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -14,17 +14,16 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { TalerUriType } from "@gnu-taler/taler-util";
+import { classifyTalerUri, CoreApiResponse, TalerUriType } from "@gnu-taler/taler-util";
import { getReadRequestPermissions } from "../permissions";
import { CrossBrowserPermissionsApi, MessageFromBackend, Permissions, PlatformAPI } from "./api.js";
const api: PlatformAPI = {
isFirefox,
findTalerUriInActiveTab,
- getLastError,
getPermissionsApi,
getWalletVersion,
- listenToWalletNotifications,
+ listenToWalletBackground,
notifyWhenAppIsReady,
openWalletPage,
openWalletPageFromPopup,
@@ -32,12 +31,11 @@ const api: PlatformAPI = {
redirectTabToWalletPage,
registerAllIncomingConnections,
registerOnInstalled,
- registerOnNewMessage,
+ listenToAllChannels,
registerReloadOnNewVersion,
registerTalerHeaderListener,
- searchForTalerLinks,
sendMessageToAllChannels,
- setMessageToWalletBackground,
+ sendMessageToWalletBackground,
useServiceWorkerAsBackgroundProcess
}
@@ -50,7 +48,7 @@ function isFirefox(): boolean {
export function contains(p: Permissions): Promise<boolean> {
return new Promise((res, rej) => {
chrome.permissions.contains(p, (resp) => {
- const le = getLastError()
+ const le = chrome.runtime.lastError?.message
if (le) {
rej(le)
}
@@ -62,7 +60,7 @@ export function contains(p: Permissions): Promise<boolean> {
export async function request(p: Permissions): Promise<boolean> {
return new Promise((res, rej) => {
chrome.permissions.request(p, (resp) => {
- const le = getLastError()
+ const le = chrome.runtime.lastError?.message
if (le) {
rej(le)
}
@@ -74,7 +72,7 @@ export async function request(p: Permissions): Promise<boolean> {
export async function remove(p: Permissions): Promise<boolean> {
return new Promise((res, rej) => {
chrome.permissions.remove(p, (resp) => {
- const le = getLastError()
+ const le = chrome.runtime.lastError?.message
if (le) {
rej(le)
}
@@ -83,9 +81,12 @@ export async function remove(p: Permissions): Promise<boolean> {
})
}
-function addPermissionsListener(callback: (p: Permissions) => void): void {
+function addPermissionsListener(callback: (p: Permissions, lastError?: string) => void): void {
console.log("addPermissionListener is not supported for Firefox");
- chrome.permissions.onAdded.addListener(callback)
+ chrome.permissions.onAdded.addListener((perm: Permissions) => {
+ const lastError = chrome.runtime.lastError?.message;
+ callback(perm, lastError)
+ })
}
function getPermissionsApi(): CrossBrowserPermissionsApi {
@@ -107,7 +108,9 @@ function notifyWhenAppIsReady(callback: () => void) {
}
-function openWalletURIFromPopup(uriType: TalerUriType, talerUri: string) {
+function openWalletURIFromPopup(talerUri: string) {
+ const uriType = classifyTalerUri(talerUri);
+
let url: string | undefined = undefined;
switch (uriType) {
case TalerUriType.TalerWithdraw:
@@ -150,7 +153,7 @@ function openWalletPageFromPopup(page: string) {
);
}
-async function setMessageToWalletBackground(operation: string, payload: any): Promise<any> {
+async function sendMessageToWalletBackground(operation: string, payload: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
chrome.runtime.sendMessage({ operation, payload, id: "(none)" }, (resp) => {
if (chrome.runtime.lastError) {
@@ -164,7 +167,7 @@ async function setMessageToWalletBackground(operation: string, payload: any): Pr
}
let notificationPort: chrome.runtime.Port | undefined;
-function listenToWalletNotifications(listener: (m: any) => void) {
+function listenToWalletBackground(listener: (m: any) => void) {
if (notificationPort === undefined) {
notificationPort = chrome.runtime.connect({ name: "notifications" })
}
@@ -203,7 +206,7 @@ function registerAllIncomingConnections() {
});
}
-function registerOnNewMessage(cb: (message: any, sender: any, callback: any) => void) {
+function listenToAllChannels(cb: (message: any, sender: any, callback: (r: CoreApiResponse) => void) => void) {
chrome.runtime.onMessage.addListener((m, s, c) => {
cb(m, s, c)
@@ -311,11 +314,6 @@ function useServiceWorkerAsBackgroundProcess() {
return chrome.runtime.getManifest().manifest_version === 3
}
-function getLastError() {
- return chrome.runtime.lastError?.message;
-}
-
-
function searchForTalerLinks(): string | undefined {
let found;
found = document.querySelector("a[href^='taler://'")
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..a761bb014
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/platform/dev.ts
@@ -0,0 +1,159 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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 { classifyTalerUri, CoreApiResponse, TalerUriType } from "@gnu-taler/taler-util";
+import { MessageFromBackend, PlatformAPI } from "./api";
+
+const frames = ["popup", "wallet"]
+
+const api: PlatformAPI = ({
+ isFirefox: () => false,
+ findTalerUriInActiveTab: async () => undefined,
+ getPermissionsApi: () => ({
+ addPermissionsListener: () => undefined, contains: async () => true, remove: async () => false, request: async () => false
+ }),
+ getWalletVersion: () => ({
+ version: 'none'
+ }),
+ notifyWhenAppIsReady: (fn: () => void) => {
+ let total = frames.length
+ function waitAndNotify() {
+ total--
+ if (total < 1) {
+ console.log('done')
+ fn()
+ }
+ }
+ frames.forEach(f => {
+ const theFrame = window.frames[f as any]
+ if (theFrame.location.href === 'about:blank') {
+ waitAndNotify()
+ } else {
+ theFrame.addEventListener("load", waitAndNotify)
+ }
+ })
+ },
+
+ openWalletPage: (page: string) => {
+ window.frames['wallet' as any].location = `/wallet.html#${page}`
+ },
+ openWalletPageFromPopup: (page: string) => {
+ window.parent.frames['wallet' as any].location = `/wallet.html#${page}`
+ window.location.href = "about:blank"
+ },
+ openWalletURIFromPopup: (page: string) => {
+ alert('openWalletURIFromPopup not implemented yet')
+ },
+ redirectTabToWalletPage: (tabId: number, page: string) => {
+ alert('redirectTabToWalletPage not implemented yet')
+ },
+
+ registerAllIncomingConnections: () => undefined,
+ registerOnInstalled: (fn: () => void) => fn(),
+ registerReloadOnNewVersion: () => undefined,
+ registerTalerHeaderListener: () => undefined,
+
+ useServiceWorkerAsBackgroundProcess: () => false,
+
+ listenToAllChannels: (fn: (m: any, s: any, c: (r: CoreApiResponse) => void) => void) => {
+ window.addEventListener("message", (event: MessageEvent<IframeMessageType>) => {
+ if (event.data.type !== 'command') return
+ const sender = event.data.header.replyMe
+ fn(event.data.body, sender, (resp: CoreApiResponse) => {
+ 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>) {
+ if (event.data.type !== 'notification') return
+ onNewMessage(event.data.body)
+ }
+ window.parent.addEventListener("message", listener)
+ return () => {
+ window.parent.removeEventListener("message", listener)
+ }
+ },
+ sendMessageToWalletBackground: async (operation: string, payload: any) => {
+ const replyMe = `reply-${Math.floor(Math.random() * 100000)}`
+ const message: IframeMessageCommand = {
+ type: 'command',
+ header: { replyMe },
+ body: { operation, payload, id: "(none)" }
+ }
+ window.parent.postMessage(message)
+
+ return new Promise((res, rej) => {
+ function listener(event: MessageEvent<IframeMessageType>) {
+ 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, {
+
+ })
+ })
+
+ },
+})
+
+type IframeMessageType = IframeMessageNotification | IframeMessageResponse | IframeMessageCommand;
+interface IframeMessageNotification {
+ type: "notification";
+ header: {
+ },
+ body: MessageFromBackend
+}
+interface IframeMessageResponse {
+ type: "response";
+ header: {
+ responseId: string;
+ },
+ body: CoreApiResponse
+}
+
+interface IframeMessageCommand {
+ type: "command";
+ header: {
+ replyMe: string;
+ },
+ body: {
+ operation: any, id: string, payload: any
+ }
+}
+
+export default api;
+