diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/platform')
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, |