From c797d551d9716924120d6ce6f270793c7bb5a4f9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 17 Nov 2023 10:12:25 -0300 Subject: still finding places when the taler support is not handled, fixing firefox with manifest v2 --- .../src/taler-wallet-interaction-loader.ts | 228 ++++++++++++--------- 1 file changed, 133 insertions(+), 95 deletions(-) (limited to 'packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts') diff --git a/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts index 69f508670..d1b1dc374 100644 --- a/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts +++ b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts @@ -47,43 +47,7 @@ const rootElementIsHTML = document.documentElement.nodeName && document.documentElement.nodeName.toLowerCase() === "html"; -/** - * Listen to any HTML Element and react to it. - * - will inject taler-support-lib - * - will redirect to call to action - */ -function listenToHeaderMutation() { - new MutationObserver(async function (mutations) { - try { - const autoOpen = await callBackground("isAutoOpenEnabled", undefined) - mutations.forEach((mut) => { - if (mut.type === "childList") { - mut.addedNodes.forEach((added) => { - if (added instanceof HTMLHeadElement) { - injectTalerSupportScript(added) - } else if (added instanceof HTMLMetaElement) { - const name = added.getAttribute("name") - if (!name) return; - if (autoOpen && name === "taler-uri") { - redirectToTalerActionHandler(added) - } - } - }); - } - }); - } catch (e) { - //disconnected - if (e instanceof TalerError) { - logger.debug(e) - } - } - }).observe(document, { - childList: true, - subtree: true, - attributes: false, - }) -} function validateTalerUri(uri: string): boolean { return ( @@ -118,6 +82,9 @@ const logger = { /** */ function redirectToTalerActionHandler(element: HTMLMetaElement) { + const name = element.getAttribute("name") + if (!name) return; + if (name !== "taler-uri") return; const uri = element.getAttribute("content"); if (!uri) return; @@ -146,49 +113,14 @@ function injectTalerSupportScript(head: HTMLHeadElement) { } scriptTag.src = url.href; - callBackground("isInjectionEnabled", undefined).then(shouldInject => { - if (!shouldInject) return; - - try { - head.insertBefore(scriptTag, head.children.length ? head.children[0] : null); - } catch (e) { - logger.info("inserting link handler failed!"); - logger.error(e); - } - }); + try { + head.insertBefore(scriptTag, head.children.length ? head.children[0] : null); + } catch (e) { + logger.info("inserting link handler failed!"); + logger.error(e); + } } -/** - * Create a bridge connection between the page and the extension. - * - * Useful for API calls and replies. Not yet supported. - */ -function createBridgeWithExtension() { - const port = chrome.runtime.connect(); - - window.addEventListener( - "message", - (event) => { - // logger.debug("message received", event.data); - if (event.source !== window) { - return; - } - if (event.origin !== window.origin) { - return; - } - - if (event.data.type && event.data.type === "FROM_PAGE") { - logger.debug("Content script received: " + event.data.text); - port.postMessage(event.data.text); - } - }, - false, - ); - port.onDisconnect.addListener(function () { - // clean up when content script gets disconnected - }) - -} export interface ExtensionOperations { isInjectionEnabled: { @@ -248,27 +180,133 @@ async function sendMessageToBackground( timedout = true; reject(TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, {})) }, 20 * 1000); //five seconds - chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => { - if (timedout) { - return false; //already rejected - } - clearTimeout(timerId); - if (chrome.runtime.lastError) { - reject(chrome.runtime.lastError.message); - } else { - resolve(backgroundResponse); - } - // return true to keep the channel open - return true; - }); + try { + chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => { + if (timedout) { + return false; //already rejected + } + clearTimeout(timerId); + if (chrome.runtime.lastError) { + reject(chrome.runtime.lastError.message); + } else { + resolve(backgroundResponse); + } + // return true to keep the channel open + return true; + }); + } catch (e) { + console.log(e) + } }); } -function start() { +function start( + onTalerMetaTagFound: (listener:(el: HTMLMetaElement)=>void) => void, + onHeadReady: (listener:(el: HTMLHeadElement)=>void) => void +) { + // do not run everywhere, this is just expected to run on html + // sites if (shouldNotInject) return; - listenToHeaderMutation(); - createBridgeWithExtension(); - logger.debug("bridged created"); + + const isAutoOpenEnabled_promise = callBackground("isAutoOpenEnabled", undefined) + const isInjectionEnabled_promise = callBackground("isInjectionEnabled", undefined) + + onTalerMetaTagFound(async (el)=> { + const enabled = await isAutoOpenEnabled_promise; + if (!enabled) return; + redirectToTalerActionHandler(el) + }) + + onHeadReady(async (el) => { + const enabled = await isInjectionEnabled_promise; + if (!enabled) return; + injectTalerSupportScript(el) + }) + +} + +/** + * Tries to find taler meta tag ASAP and report + * @param notify + * @returns + */ +function onTalerMetaTag(notify: (el: HTMLMetaElement) => void) { + if (document.head) { + const element = document.head.querySelector("meta[name=taler-uri]") + if (!element) return; + if (!(element instanceof HTMLMetaElement)) return; + const name = element.getAttribute("name") + if (!name) return; + if (name !== "taler-uri") return; + const uri = element.getAttribute("content"); + if (!uri) return; + + notify(element) + return; + } + const obs = new MutationObserver(async function (mutations) { + try { + mutations.forEach((mut) => { + if (mut.type === "childList") { + mut.addedNodes.forEach((added) => { + if (added instanceof HTMLMetaElement) { + const name = added.getAttribute("name") + if (!name) return; + if (name !== "taler-uri") return; + const uri = added.getAttribute("content"); + if (!uri) return; + notify(added) + obs.disconnect() + } + }); + } + }); + } catch (e) { + console.error(e) + } + }) + + obs.observe(document, { + childList: true, + subtree: true, + attributes: false, + }) + +} + +/** + * Tries to find HEAD tag ASAP and report + * @param notify + * @returns + */ +function onHeaderReady(notify: (el: HTMLHeadElement) => void) { + if (document.head) { + notify(document.head) + return; + } + const obs = new MutationObserver(async function (mutations) { + try { + mutations.forEach((mut) => { + if (mut.type === "childList") { + mut.addedNodes.forEach((added) => { + if (added instanceof HTMLHeadElement) { + + notify(added) + obs.disconnect() + } + }); + } + }); + } catch (e) { + console.error(e) + } + }) + + obs.observe(document, { + childList: true, + subtree: true, + attributes: false, + }) } -start(); +start(onTalerMetaTag, onHeaderReady); -- cgit v1.2.3