diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/platform/chrome.ts')
-rw-r--r-- | packages/taler-wallet-webextension/src/platform/chrome.ts | 473 |
1 files changed, 252 insertions, 221 deletions
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index fa9ad0522..4fb4bddfd 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -59,8 +59,6 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { useServiceWorkerAsBackgroundProcess, keepAlive, listenNetworkConnectionState, - registerTalerHeaderListener, - containsTalerHeaderListener, }; export default api; @@ -151,9 +149,6 @@ function addPermissionsListener( function getPermissionsApi(): CrossBrowserPermissionsApi { return { addPermissionsListener, - containsHostPermissions, - requestHostPermissions, - removeHostPermissions, requestClipboardPermissions, removeClipboardPermissions, containsClipboardPermissions, @@ -395,10 +390,17 @@ function registerReloadOnNewVersion(): void { }); } -function redirectTabToWalletPage(tabId: number, page: string): void { +async function redirectCurrentTabToWalletPage(page: string): Promise<void> { + let queryOptions = { active: true, lastFocusedWindow: true }; + let [tab] = await chrome.tabs.query(queryOptions); + + return redirectTabToWalletPage(tab.id!, page); +} + +async function redirectTabToWalletPage(tabId: number, page: string): Promise<void> { const url = chrome.runtime.getURL(`/static/wallet.html#${page}`); logger.trace("redirecting tabId: ", tabId, " to: ", url); - chrome.tabs.update(tabId, { url }); + await chrome.tabs.update(tabId, { url }); } interface WalletVersion { @@ -709,218 +711,247 @@ 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, -): void { - if (chrome.runtime.lastError) { - logger.error(JSON.stringify(chrome.runtime.lastError)); - return; - } - console.log("HEADER", details.statusCode, details.url, details.responseHeaders) - 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}`, - ); - redirectTabToWalletPage(details.tabId, values[0]); - } - } - return; -} -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; - } - return redirectTabToWalletPage( - tabId, - `/taler-uri/${encodeURIComponent(talerUri)}`, - ); -} - -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); - } -} - -function registerTalerHeaderListener( - // callback: (tabId: number, url: string) => void, -): 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: ["<all_urls>"] }, - ["responseHeaders", "extraHeaders"] - ); - 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; - } - } 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)); - } - }); - }); -} - -const hostPermissions = { - permissions: ["webRequest"], - origins: ["http://*/*", "https://*/*"], -}; +// 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 { +// 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)}`, +// ); +// } + +// 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); +// } +// } -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 +/** + * 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; + +// 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: ["<all_urls>"] }, +// ["responseHeaders", "extraHeaders"] +// ); +// // 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; +// } +// } 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)); +// } +// }); +// }); +// } + +// 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 |