aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/platform
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-10-26 15:26:58 -0300
committerSebastian <sebasjm@gmail.com>2023-10-26 15:26:58 -0300
commitc19aa60d3687260d01404f94e0902fe1943f16df (patch)
tree027723116667ad0a9f22a92ff472f41b0947da7c /packages/taler-wallet-webextension/src/platform
parenta4c7bc4b284fe7dc4c65ceaad96fc67c40c9a708 (diff)
downloadwallet-core-c19aa60d3687260d01404f94e0902fe1943f16df.tar.xz
first take on adding auto open again, WIP
Diffstat (limited to 'packages/taler-wallet-webextension/src/platform')
-rw-r--r--packages/taler-wallet-webextension/src/platform/api.ts25
-rw-r--r--packages/taler-wallet-webextension/src/platform/chrome.ts268
-rw-r--r--packages/taler-wallet-webextension/src/platform/dev.ts2
-rw-r--r--packages/taler-wallet-webextension/src/platform/firefox.ts9
4 files changed, 212 insertions, 92 deletions
diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts
index 44b5959a8..56d668a97 100644
--- a/packages/taler-wallet-webextension/src/platform/api.ts
+++ b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -16,20 +16,18 @@
import {
CoreApiResponse,
- NotificationType,
TalerUri,
- WalletNotification,
+ WalletNotification
} from "@gnu-taler/taler-util";
import {
WalletConfig,
- WalletConfigParameter,
- WalletOperations,
+ WalletOperations
} from "@gnu-taler/taler-wallet-core";
-import { BackgroundOperations } from "../wxApi.js";
import {
ExtensionOperations,
MessageFromExtension,
} from "../taler-wallet-interaction-loader.js";
+import { BackgroundOperations } from "../wxApi.js";
export interface Permissions {
/**
@@ -48,9 +46,9 @@ export interface Permissions {
* Compatibility API that works on multiple browsers.
*/
export interface CrossBrowserPermissionsApi {
- // containsHostPermissions(): Promise<boolean>;
- // requestHostPermissions(): Promise<boolean>;
- // removeHostPermissions(): Promise<boolean>;
+ containsHostPermissions(): Promise<boolean>;
+ requestHostPermissions(): Promise<boolean>;
+ removeHostPermissions(): Promise<boolean>;
containsClipboardPermissions(): Promise<boolean>;
requestClipboardPermissions(): Promise<boolean>;
@@ -102,6 +100,7 @@ type WebexWalletConfig = {
export interface Settings extends WebexWalletConfig {
injectTalerSupport: boolean;
+ autoOpenByHeader: boolean;
advanceMode: boolean;
backup: boolean;
langSelector: boolean;
@@ -112,6 +111,7 @@ export interface Settings extends WebexWalletConfig {
export const defaultSettings: Settings = {
injectTalerSupport: true,
+ autoOpenByHeader: true,
advanceMode: false,
backup: false,
langSelector: false,
@@ -206,6 +206,15 @@ export interface BackgroundPlatformAPI {
message: MessageFromFrontend<Op> & { id: string },
) => Promise<MessageResponse>,
): void;
+
+ /**
+ * Backend API
+ */
+ registerTalerHeaderListener(
+ onHeader: (tabId: number, url: string) => void,
+ ): 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 b0934f107..3151bd6ab 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -59,6 +59,8 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
useServiceWorkerAsBackgroundProcess,
keepAlive,
listenNetworkConnectionState,
+ registerTalerHeaderListener,
+ containsTalerHeaderListener,
};
export default api;
@@ -95,10 +97,6 @@ function isFirefox(): boolean {
return false;
}
-// const hostPermissions = {
-// permissions: ["webRequest"],
-// origins: ["http://*/*", "https://*/*"],
-// };
export function containsClipboardPermissions(): Promise<boolean> {
return new Promise((res, rej) => {
@@ -113,18 +111,6 @@ export function containsClipboardPermissions(): Promise<boolean> {
});
}
-// 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 requestClipboardPermissions(): Promise<boolean> {
return new Promise((res, rej) => {
res(false);
@@ -138,67 +124,7 @@ export async function requestClipboardPermissions(): Promise<boolean> {
});
}
-// 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);
-// });
-// });
-// }
-
-// 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;
-
-// 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);
-// });
-// });
-// }
+
export function removeClipboardPermissions(): Promise<boolean> {
return new Promise((res, rej) => {
@@ -225,9 +151,9 @@ function addPermissionsListener(
function getPermissionsApi(): CrossBrowserPermissionsApi {
return {
addPermissionsListener,
- // containsHostPermissions,
- // requestHostPermissions,
- // removeHostPermissions,
+ containsHostPermissions,
+ requestHostPermissions,
+ removeHostPermissions,
requestClipboardPermissions,
removeClipboardPermissions,
containsClipboardPermissions,
@@ -365,7 +291,7 @@ async function sendMessageToBackground<
const timerId = setTimeout(() => {
timedout = true;
reject(TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, {}) );
- }, 20 * 1000); //five seconds
+ }, 20 * 1000);
chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
if (timedout) {
return false; //already rejected
@@ -782,3 +708,183 @@ function listenNetworkConnectionState(
window.removeEventListener("online", notifyOnline);
};
}
+
+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 registerTalerHeaderListener(
+ callback: (tabId: number, url: string) => void,
+): void {
+ logger.info("setting up header listener");
+
+ function headerListener(
+ details: chrome.webRequest.WebResponseHeadersDetails,
+ ): void {
+ 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);
+ if (values.length > 0) {
+ logger.info(
+ `Found a Taler URI in a response header for the request ${details.url} from tab ${details.tabId}`,
+ );
+ callback(details.tabId, values[0]);
+ }
+ }
+ return;
+ }
+
+ 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}`);
+ callback(tabId, uri);
+ }
+ }
+
+ const prevHeaderListener = currentHeaderListener;
+ const prevTabListener = currentTabListener;
+
+ getPermissionsApi()
+ .containsHostPermissions()
+ .then((result) => {
+ //if there is a handler already, remove it
+ if (
+ prevHeaderListener &&
+ chrome?.webRequest?.onHeadersReceived?.hasListener(prevHeaderListener)
+ ) {
+ chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener);
+ }
+ if (
+ prevTabListener &&
+ chrome?.tabs?.onUpdated?.hasListener(prevTabListener)
+ ) {
+ chrome.tabs.onUpdated.removeListener(prevTabListener);
+ }
+
+ //if the result was positive, add the headerListener
+ if (result) {
+ const headersEvent:
+ | chrome.webRequest.WebResponseHeadersEvent
+ | undefined = chrome?.webRequest?.onHeadersReceived;
+ if (headersEvent) {
+ headersEvent.addListener(headerListener, { urls: ["<all_urls>"] }, [
+ "responseHeaders",
+ ]);
+ 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 976ac05f5..218422ded 100644
--- a/packages/taler-wallet-webextension/src/platform/dev.ts
+++ b/packages/taler-wallet-webextension/src/platform/dev.ts
@@ -44,6 +44,8 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
removeClipboardPermissions: async () => false,
requestClipboardPermissions: async () => 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 9f666e7ae..cc734ebf7 100644
--- a/packages/taler-wallet-webextension/src/platform/firefox.ts
+++ b/packages/taler-wallet-webextension/src/platform/firefox.ts
@@ -26,6 +26,9 @@ 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 = {
@@ -51,9 +54,9 @@ function addPermissionsListener(callback: (p: Permissions) => void): void {
function getPermissionsApi(): CrossBrowserPermissionsApi {
return {
addPermissionsListener,
- // containsHostPermissions: chromeHostContains,
- // requestHostPermissions: chromeHostRequest,
- // removeHostPermissions: chromeHostRemove,
+ containsHostPermissions: chromeHostContains,
+ requestHostPermissions: chromeHostRequest,
+ removeHostPermissions: chromeHostRemove,
containsClipboardPermissions: chromeClipContains,
removeClipboardPermissions: chromeClipRemove,
requestClipboardPermissions: chromeClipRequest,