From b99ef78dea6c43d430e3aad4c9f3f8cff0a06844 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 15 Dec 2023 00:45:01 -0300 Subject: testing header listener --- .../src/platform/chrome.ts | 416 +++++++++++---------- 1 file changed, 210 insertions(+), 206 deletions(-) (limited to 'packages/taler-wallet-webextension/src/platform/chrome.ts') diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index 04ecd80cc..7f384f7d4 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -60,6 +60,8 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { useServiceWorkerAsBackgroundProcess, keepAlive, listenNetworkConnectionState, + registerTalerHeaderListener, + containsTalerHeaderListener, }; export default api; @@ -149,6 +151,9 @@ function addPermissionsListener( function getPermissionsApi(): CrossBrowserPermissionsApi { return { + containsHostPermissions, + requestHostPermissions, + removeHostPermissions, addPermissionsListener, requestClipboardPermissions, removeClipboardPermissions, @@ -718,79 +723,81 @@ function listenNetworkConnectionState( }; } -// type HeaderListenerFunc = ( -// details: chrome.webRequest.WebResponseHeadersDetails, -// ) => void; -// let currentHeaderListener: HeaderListenerFunc | undefined = undefined; +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; +type TabListenerFunc = (tabId: number, info: chrome.tabs.TabChangeInfo) => void; +let currentTabListener: TabListenerFunc | undefined = undefined; -// function containsTalerHeaderListener(): boolean { -// return ( -// currentHeaderListener !== undefined || currentTabListener !== undefined -// ); -// } +function containsTalerHeaderListener(): boolean { + return ( + currentHeaderListener !== undefined || currentTabListener !== undefined + ); +} -// function headerListener( -// details: chrome.webRequest.WebResponseHeadersDetails, -// ): chrome.webRequest.BlockingResponse | undefined { -// if (chrome.runtime.lastError) { -// logger.error(JSON.stringify(chrome.runtime.lastError)); -// return; -// } -// console.log("HEADER", JSON.stringify(details, undefined, 2)) -// 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}`, -// ); -// const redirectUrl = redirectTabToWalletPage(details.tabId, values[0]); -// return { redirectUrl } -// } -// } -// 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)}`, -// ); -// } +function headerListener( + details: chrome.webRequest.WebResponseHeadersDetails, +): chrome.webRequest.BlockingResponse | undefined { + if (chrome.runtime.lastError) { + logger.error(JSON.stringify(chrome.runtime.lastError)); + return; + } -// async function tabListener( -// tabId: number, -// info: chrome.tabs.TabChangeInfo, -// ): Promise { -// 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); -// } -// } + 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)}`, + ); +} + +async function tabListener( + tabId: number, + info: chrome.tabs.TabChangeInfo, +): Promise { + 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 @@ -821,144 +828,141 @@ function listenNetworkConnectionState( // }); // } -// function registerTalerHeaderListener( -// ): void { -// logger.info("setting up header listener"); - -// 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) -// ) { -// 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); -// } - -// //if the result was positive, add the headerListener -// if (result) { -// console.log("headers on, disabled:", chrome?.webRequest?.onHeadersReceived === undefined) -// if (chrome?.webRequest) { -// chrome.webRequest.onHeadersReceived.addListener(headerListener, -// { urls: [""] }, -// ["responseHeaders", "extraHeaders"] -// ); -// // chrome.webRequest.onCompleted.addListener(headerListener, -// // { urls: [""] }, -// // ["responseHeaders", "extraHeaders"] -// // ); -// // chrome.webRequest.onResponseStarted.addListener(headerListener, -// // { urls: [""] }, -// // ["responseHeaders", "extraHeaders"] -// // ); -// // chrome.webRequest.onErrorOccurred.addListener(headerListener, -// // { urls: [""] }, -// // ["extraHeaders"] -// // ); -// currentHeaderListener = headerListener; -// } - -// const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined = -// chrome?.tabs?.onUpdated; -// if (tabsEvent) { -// tabsEvent.addListener(tabListener); -// currentTabListener = tabListener; -// } -// } else { -// console.log("headers off") -// } - -// //notify the browser about this change, this operation is expensive -// chrome?.webRequest?.handlerBehaviorChanged(() => { -// if (chrome.runtime.lastError) { -// logger.error(JSON.stringify(chrome.runtime.lastError)); -// } -// }); -// }); -// } +function registerTalerHeaderListener(): void { + logger.info("setting up header listener"); + + const prevHeaderListener = currentHeaderListener; + const prevTabListener = currentTabListener; + + if ( + prevHeaderListener && + chrome?.webRequest?.onHeadersReceived?.hasListener(prevHeaderListener) + ) { + 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); + } -// const hostPermissions = { -// permissions: ["webRequest"], -// origins: ["http://*/*", "https://*/*"], -// }; - -// export function containsHostPermissions(): Promise { -// return new Promise((res, rej) => { -// chrome.permissions.contains(hostPermissions, (resp) => { -// const le = chrome.runtime.lastError?.message; -// if (le) { -// rej(le); -// } -// res(resp); -// }); -// }); -// } + console.log("headers on, disabled:", chrome?.webRequest?.onHeadersReceived === undefined) + if (chrome?.webRequest) { + if (extensionIsManifestV3()) { + chrome.webRequest.onHeadersReceived.addListener(headerListener, + { urls: [""] }, + ["responseHeaders", "extraHeaders"] + ); + } else { + //Firefox doesnt support extra headers + chrome.webRequest.onHeadersReceived.addListener(headerListener, + { urls: [""] }, + ["responseHeaders"] + ); + } + // chrome.webRequest.onCompleted.addListener(headerListener, + // { urls: [""] }, + // ["responseHeaders", "extraHeaders"] + // ); + // chrome.webRequest.onResponseStarted.addListener(headerListener, + // { urls: [""] }, + // ["responseHeaders", "extraHeaders"] + // ); + // chrome.webRequest.onErrorOccurred.addListener(headerListener, + // { urls: [""] }, + // ["extraHeaders"] + // ); + currentHeaderListener = headerListener; + } -// export async function requestHostPermissions(): Promise { -// return new Promise((res, rej) => { -// chrome.permissions.request(hostPermissions, (resp) => { -// const le = chrome.runtime.lastError?.message; -// if (le) { -// rej(le); -// } -// res(resp); -// }); -// }); -// } + const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined = + chrome?.tabs?.onUpdated; + if (tabsEvent) { + tabsEvent.addListener(tabListener); + currentTabListener = tabListener; + } -// export async function removeHostPermissions(): Promise { -// //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 + //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 { + 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 { + 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 { + //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 -- cgit v1.2.3