aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/platform
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/platform')
-rw-r--r--packages/taler-wallet-webextension/src/platform/api.ts35
-rw-r--r--packages/taler-wallet-webextension/src/platform/chrome.ts300
-rw-r--r--packages/taler-wallet-webextension/src/platform/dev.ts7
-rw-r--r--packages/taler-wallet-webextension/src/platform/firefox.ts11
4 files changed, 47 insertions, 306 deletions
diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts
index a2b26441b..c7d297db9 100644
--- a/packages/taler-wallet-webextension/src/platform/api.ts
+++ b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -46,20 +46,32 @@ export interface Permissions {
* Compatibility API that works on multiple browsers.
*/
export interface CrossBrowserPermissionsApi {
- containsHostPermissions(): Promise<boolean>;
- requestHostPermissions(): Promise<boolean>;
- removeHostPermissions(): Promise<boolean>;
containsClipboardPermissions(): Promise<boolean>;
requestClipboardPermissions(): Promise<boolean>;
removeClipboardPermissions(): Promise<boolean>;
- addPermissionsListener(
- callback: (p: Permissions, lastError?: string) => void,
- ): void;
}
-export type MessageFromBackend = WalletNotification;
+export enum ExtensionNotificationType {
+ SettingsChange = "settings-change",
+}
+
+export interface SettingsChangeNotification {
+ type: ExtensionNotificationType.SettingsChange;
+
+ currentValue: Settings;
+}
+
+export type ExtensionNotification = SettingsChangeNotification
+
+export type MessageFromBackend = {
+ type: "wallet",
+ notification: WalletNotification
+} | {
+ type: "web-extension",
+ notification: ExtensionNotification
+};
export type MessageFromFrontend<
Op extends BackgroundOperations | WalletOperations | ExtensionOperations,
@@ -110,7 +122,7 @@ export interface Settings extends WebexWalletConfig {
}
export const defaultSettings: Settings = {
- injectTalerSupport: true,
+ injectTalerSupport: false,
autoOpen: true,
advanceMode: false,
backup: false,
@@ -207,13 +219,6 @@ export interface BackgroundPlatformAPI {
) => Promise<MessageResponse>,
): void;
- /**
- * Use by the wallet backend to activate the listener of HTTP request
- */
- registerTalerHeaderListener(): void;
-
- containsTalerHeaderListener(): boolean;
-
}
export interface ForegroundPlatformAPI {
/**
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts
index 18d282342..d791a560f 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -28,6 +28,7 @@ import { BackgroundOperations } from "../wxApi.js";
import {
BackgroundPlatformAPI,
CrossBrowserPermissionsApi,
+ ExtensionNotificationType,
ForegroundPlatformAPI,
MessageFromBackend,
MessageFromFrontend,
@@ -60,27 +61,31 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
useServiceWorkerAsBackgroundProcess,
keepAlive,
listenNetworkConnectionState,
- registerTalerHeaderListener,
- containsTalerHeaderListener,
};
export default api;
const logger = new Logger("chrome.ts");
-async function getSettingsFromStorage(): Promise<Settings> {
- const data = await chrome.storage.local.get("wallet-settings");
- if (!data) return defaultSettings;
- const settings = data["wallet-settings"];
- if (!settings) return defaultSettings;
+
+const WALLET_STORAGE_KEY = "wallet-settings";
+
+function jsonParseOrDefault(unparsed: any, def: any) {
+ if (!unparsed) return def
try {
- const parsed = JSON.parse(settings);
- return parsed;
+ return JSON.parse(unparsed);
} catch (e) {
- return defaultSettings;
+ return def;
}
}
+async function getSettingsFromStorage(): Promise<Settings> {
+ const data = await chrome.storage.local.get(WALLET_STORAGE_KEY);
+ if (!data) return defaultSettings;
+ const settings = data[WALLET_STORAGE_KEY];
+ return jsonParseOrDefault(settings, defaultSettings)
+}
+
function keepAlive(callback: any): void {
if (extensionIsManifestV3()) {
chrome.alarms.create("wallet-worker", { periodInMinutes: 1 });
@@ -140,21 +145,8 @@ export function removeClipboardPermissions(): Promise<boolean> {
});
}
-function addPermissionsListener(
- callback: (p: Permissions, lastError?: string) => void,
-): void {
- chrome.permissions.onAdded.addListener((perm: Permissions) => {
- const lastError = chrome.runtime.lastError?.message;
- callback(perm, lastError);
- });
-}
-
function getPermissionsApi(): CrossBrowserPermissionsApi {
return {
- containsHostPermissions,
- requestHostPermissions,
- removeHostPermissions,
- addPermissionsListener,
requestClipboardPermissions,
removeClipboardPermissions,
containsClipboardPermissions,
@@ -363,6 +355,18 @@ function registerAllIncomingConnections(): void {
logger.error("error trying to save incoming connection", e);
}
});
+ chrome.storage.onChanged.addListener((event) => {
+ if (event[WALLET_STORAGE_KEY]) {
+ sendMessageToAllChannels({
+ type: "web-extension",
+ notification: {
+ type: ExtensionNotificationType.SettingsChange,
+ currentValue: jsonParseOrDefault(event[WALLET_STORAGE_KEY], defaultSettings)
+ }
+ })
+ }
+ })
+
}
function listenToAllChannels(
@@ -723,253 +727,3 @@ function listenNetworkConnectionState(
};
}
-type HeaderListenerFunc = (
- details: chrome.webRequest.WebResponseHeadersDetails,
-) => void;
-let currentHeaderListener: HeaderListenerFunc | undefined = undefined;
-
-// type TabListenerFunc = (tabId: number, info: chrome.tabs.TabChangeInfo) => void;
-// let currentTabListener: TabListenerFunc | undefined = undefined;
-
-
-function containsTalerHeaderListener(): boolean {
- return (
- currentHeaderListener !== undefined
- // || currentTabListener !== undefined
- );
-}
-
-function headerListener(
- details: chrome.webRequest.WebResponseHeadersDetails,
-): chrome.webRequest.BlockingResponse | undefined {
- logger.trace("header listener run", details.statusCode, chrome.runtime.lastError)
- if (chrome.runtime.lastError) {
- logger.error(JSON.stringify(chrome.runtime.lastError));
- return;
- }
-
- if (
- details.statusCode === 402 ||
- details.statusCode === 202 ||
- details.statusCode === 200
- ) {
- const values = (details.responseHeaders || [])
- .filter((h) => h.name.toLowerCase() === "taler")
- .map((h) => h.value)
- .filter((value): value is string => !!value);
-
- const talerUri = values.length > 0 ? values[0] : undefined
- if (talerUri) {
- logger.info(
- `Found a Taler URI in a response header for the request ${details.url} from tab ${details.tabId}: ${talerUri}`,
- );
- parseTalerUriAndRedirect(details.tabId, talerUri);
- return;
- }
- }
- return details;
-}
-function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void {
- const talerUri = maybeTalerUri.startsWith("ext+")
- ? maybeTalerUri.substring(4)
- : maybeTalerUri;
- const uri = parseTalerUri(talerUri);
- if (!uri) {
- logger.warn(
- `Response with HTTP 402 the Taler header but could not classify ${talerUri}`,
- );
- return;
- }
- redirectTabToWalletPage(
- tabId,
- `/taler-uri/${encodeURIComponent(talerUri)}`,
- );
-}
-
-/**
- * Not needed anymore since SPA use taler support
- */
-
-// async function tabListener(
-// tabId: number,
-// info: chrome.tabs.TabChangeInfo,
-// ): Promise<void> {
-// if (tabId < 0) return;
-// const tabLocationHasBeenUpdated = info.status === "complete";
-// const tabTitleHasBeenUpdated = info.title !== undefined;
-// if (tabLocationHasBeenUpdated || tabTitleHasBeenUpdated) {
-// const uri = await findTalerUriInTab(tabId);
-// if (!uri) return;
-// logger.info(`Found a Taler URI in the tab ${tabId}`);
-// parseTalerUriAndRedirect(tabId, uri);
-// }
-// }
-
-/**
- * unused, declarative redirect is not good enough
- *
- */
-// async function registerDeclarativeRedirect() {
-// await chrome.declarativeNetRequest.updateDynamicRules({
-// removeRuleIds: [1],
-// addRules: [
-// {
-// id: 1,
-// priority: 1,
-// condition: {
-// urlFilter: "https://developer.chrome.com/docs/extensions/mv2/",
-// regexFilter: ".*taler_uri=([^&]*).*",
-// // isUrlFilterCaseSensitive: false,
-// // requestMethods: [chrome.declarativeNetRequest.RequestMethod.GET]
-// // resourceTypes: [chrome.declarativeNetRequest.ResourceType.MAIN_FRAME],
-// },
-// action: {
-// type: chrome.declarativeNetRequest.RuleActionType.REDIRECT,
-// redirect: {
-// regexSubstitution: `chrome-extension://${chrome.runtime.id}/static/wallet.html?action=\\1`,
-// },
-// },
-// },
-// ],
-// });
-// }
-
-function registerTalerHeaderListener(): void {
- logger.info("setting up header listener");
-
- const prevHeaderListener = currentHeaderListener;
- // const prevTabListener = currentTabListener;
-
- if (
- prevHeaderListener &&
- chrome?.webRequest?.onHeadersReceived?.hasListener(prevHeaderListener)
- ) {
- return;
- // console.log("removming on header listener")
- // chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener);
- // chrome.webRequest.onCompleted.removeListener(prevHeaderListener);
- // chrome.webRequest.onResponseStarted.removeListener(prevHeaderListener);
- // chrome.webRequest.onErrorOccurred.removeListener(prevHeaderListener);
- }
-
- // if (
- // prevTabListener &&
- // chrome?.tabs?.onUpdated?.hasListener(prevTabListener)
- // ) {
- // console.log("removming on tab listener")
- // chrome.tabs.onUpdated.removeListener(prevTabListener);
- // }
-
- console.log("headers on, disabled:", chrome?.webRequest?.onHeadersReceived === undefined)
- if (chrome?.webRequest) {
- if (extensionIsManifestV3()) {
- chrome.webRequest.onHeadersReceived.addListener(headerListener,
- { urls: ["<all_urls>"] },
- ["responseHeaders"]
- );
- } else {
- chrome.webRequest.onHeadersReceived.addListener(headerListener,
- { urls: ["<all_urls>"] },
- ["responseHeaders"]
- );
- }
- // chrome.webRequest.onCompleted.addListener(headerListener,
- // { urls: ["<all_urls>"] },
- // ["responseHeaders", "extraHeaders"]
- // );
- // chrome.webRequest.onResponseStarted.addListener(headerListener,
- // { urls: ["<all_urls>"] },
- // ["responseHeaders", "extraHeaders"]
- // );
- // chrome.webRequest.onErrorOccurred.addListener(headerListener,
- // { urls: ["<all_urls>"] },
- // ["extraHeaders"]
- // );
- currentHeaderListener = headerListener;
- }
-
- // const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined =
- // chrome?.tabs?.onUpdated;
- // if (tabsEvent) {
- // tabsEvent.addListener(tabListener);
- // currentTabListener = tabListener;
- // }
-
- //notify the browser about this change, this operation is expensive
- chrome?.webRequest?.handlerBehaviorChanged(() => {
- if (chrome.runtime.lastError) {
- logger.error(JSON.stringify(chrome.runtime.lastError));
- }
- });
-}
-
-const hostPermissions = {
- permissions: ["webRequest"],
- origins: ["http://*/*", "https://*/*"],
-};
-
-export function containsHostPermissions(): Promise<boolean> {
- return new Promise((res, rej) => {
- chrome.permissions.contains(hostPermissions, (resp) => {
- const le = chrome.runtime.lastError?.message;
- if (le) {
- rej(le);
- }
- res(resp);
- });
- });
-}
-
-export async function requestHostPermissions(): Promise<boolean> {
- return new Promise((res, rej) => {
- chrome.permissions.request(hostPermissions, (resp) => {
- const le = chrome.runtime.lastError?.message;
- if (le) {
- rej(le);
- }
- res(resp);
- });
- });
-}
-
-export async function removeHostPermissions(): Promise<boolean> {
- //if there is a handler already, remove it
- if (
- currentHeaderListener &&
- chrome?.webRequest?.onHeadersReceived?.hasListener(currentHeaderListener)
- ) {
- chrome.webRequest.onHeadersReceived.removeListener(currentHeaderListener);
- }
- // if (
- // currentTabListener &&
- // chrome?.tabs?.onUpdated?.hasListener(currentTabListener)
- // ) {
- // chrome.tabs.onUpdated.removeListener(currentTabListener);
- // }
-
- currentHeaderListener = undefined;
- // currentTabListener = undefined;
-
- //notify the browser about this change, this operation is expensive
- if ("webRequest" in chrome) {
- chrome.webRequest.handlerBehaviorChanged(() => {
- if (chrome.runtime.lastError) {
- logger.error(JSON.stringify(chrome.runtime.lastError));
- }
- });
- }
-
- if (extensionIsManifestV3()) {
- // Trying to remove host permissions with manifest >= v3 throws an error
- return true;
- }
- return new Promise((res, rej) => {
- chrome.permissions.remove(hostPermissions, (resp) => {
- const le = chrome.runtime.lastError?.message;
- if (le) {
- rej(le);
- }
- res(resp);
- });
- });
-} \ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/platform/dev.ts b/packages/taler-wallet-webextension/src/platform/dev.ts
index 51744e318..2993c88bc 100644
--- a/packages/taler-wallet-webextension/src/platform/dev.ts
+++ b/packages/taler-wallet-webextension/src/platform/dev.ts
@@ -37,18 +37,11 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
listenNetworkConnectionState,
openNewURLFromPopup: () => undefined,
getPermissionsApi: () => ({
- addPermissionsListener: () => undefined,
- containsHostPermissions: async () => true,
- removeHostPermissions: async () => false,
- requestHostPermissions: async () => false,
containsClipboardPermissions: async () => true,
removeClipboardPermissions: async () => false,
requestClipboardPermissions: async () => false,
}),
- // registerDeclarativeRedirect: () => false,
- registerTalerHeaderListener: () => false,
- containsTalerHeaderListener: () => false,
getWalletWebExVersion: () => ({
version: "none",
}),
diff --git a/packages/taler-wallet-webextension/src/platform/firefox.ts b/packages/taler-wallet-webextension/src/platform/firefox.ts
index 0bbe805cf..3d67423fd 100644
--- a/packages/taler-wallet-webextension/src/platform/firefox.ts
+++ b/packages/taler-wallet-webextension/src/platform/firefox.ts
@@ -26,9 +26,6 @@ import chromePlatform, {
containsClipboardPermissions as chromeClipContains,
removeClipboardPermissions as chromeClipRemove,
requestClipboardPermissions as chromeClipRequest,
- containsHostPermissions as chromeHostContains,
- requestHostPermissions as chromeHostRequest,
- removeHostPermissions as chromeHostRemove,
} from "./chrome.js";
const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
@@ -47,16 +44,8 @@ function isFirefox(): boolean {
return true;
}
-function addPermissionsListener(callback: (p: Permissions) => void): void {
- // throw Error("addPermissionListener is not supported for Firefox");
-}
-
function getPermissionsApi(): CrossBrowserPermissionsApi {
return {
- addPermissionsListener,
- containsHostPermissions: chromeHostContains,
- requestHostPermissions: chromeHostRequest,
- removeHostPermissions: chromeHostRemove,
containsClipboardPermissions: chromeClipContains,
removeClipboardPermissions: chromeClipRemove,
requestClipboardPermissions: chromeClipRequest,