diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts')
-rw-r--r-- | packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts | 134 |
1 files changed, 97 insertions, 37 deletions
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 d1b1dc374..3b7cbcbb7 100644 --- a/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts +++ b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts @@ -15,6 +15,7 @@ */ import { CoreApiResponse, TalerError, TalerErrorCode } from "@gnu-taler/taler-util"; +import type { MessageFromBackend } from "./platform/api.js"; /** * This will modify all the pages that the user load when navigating with Web Extension enabled @@ -46,6 +47,9 @@ const suffixIsNotXMLorPDF = const rootElementIsHTML = document.documentElement.nodeName && document.documentElement.nodeName.toLowerCase() === "html"; +// const pageAcceptsTalerSupport = document.head.querySelector( +// "meta[name=taler-support]", +// ); @@ -67,6 +71,7 @@ function convertURIToWebExtensionPath(uri: string) { const shouldNotInject = !documentDocTypeIsHTML || !suffixIsNotXMLorPDF || + // !pageAcceptsTalerSupport || !rootElementIsHTML; const logger = { @@ -93,16 +98,22 @@ function redirectToTalerActionHandler(element: HTMLMetaElement) { return; } - location.href = convertURIToWebExtensionPath(uri) + const walletPage = convertURIToWebExtensionPath(uri) + window.location.replace(walletPage) } -function injectTalerSupportScript(head: HTMLHeadElement) { +function injectTalerSupportScript(head: HTMLHeadElement, trusted: boolean) { const meta = head.querySelector("meta[name=taler-support]") + if (!meta) return; + const content = meta.getAttribute("content"); + if (!content) return; + const features = content.split(",") - const debugEnabled = meta?.getAttribute("debug") === "true"; + const debugEnabled = meta.getAttribute("debug") === "true"; + const hijackEnabled = features.indexOf("uri") !== -1 + const talerApiEnabled = features.indexOf("api") !== -1 && trusted const scriptTag = document.createElement("script"); - scriptTag.setAttribute("async", "false"); const url = new URL( chrome.runtime.getURL("/dist/taler-wallet-interaction-support.js"), @@ -111,6 +122,12 @@ function injectTalerSupportScript(head: HTMLHeadElement) { if (debugEnabled) { url.searchParams.set("debug", "true"); } + if (talerApiEnabled) { + url.searchParams.set("api", "true"); + } + if (hijackEnabled) { + url.searchParams.set("hijack", "true"); + } scriptTag.src = url.href; try { @@ -123,12 +140,14 @@ function injectTalerSupportScript(head: HTMLHeadElement) { export interface ExtensionOperations { - isInjectionEnabled: { + isAutoOpenEnabled: { request: void; response: boolean; }; - isAutoOpenEnabled: { - request: void; + isDomainTrusted: { + request: { + domain: string; + }; response: boolean; }; } @@ -178,7 +197,11 @@ async function sendMessageToBackground<Op extends keyof ExtensionOperations>( let timedout = false; const timerId = setTimeout(() => { timedout = true; - reject(TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, {})) + reject(TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, { + requestMethod: "wallet", + requestUrl: message.operation, + timeoutMs: 20 * 1000, + })) }, 20 * 1000); //five seconds try { chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => { @@ -200,48 +223,89 @@ async function sendMessageToBackground<Op extends keyof ExtensionOperations>( }); } +let notificationPort: chrome.runtime.Port | undefined; +function listenToWalletBackground(listener: (m: any) => void): () => void { + if (notificationPort === undefined) { + notificationPort = chrome.runtime.connect({ name: "notifications" }); + } + notificationPort.onMessage.addListener(listener); + function removeListener(): void { + if (notificationPort !== undefined) { + notificationPort.onMessage.removeListener(listener); + } + } + return removeListener; +} + +const loaderSettings = { + isAutoOpenEnabled: false, + isDomainTrusted: false, +} + function start( - onTalerMetaTagFound: (listener:(el: HTMLMetaElement)=>void) => void, - onHeadReady: (listener:(el: HTMLHeadElement)=>void) => void + 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 + // do not run everywhere, this is just expected to run on site + // that are aware of taler if (shouldNotInject) return; - const isAutoOpenEnabled_promise = callBackground("isAutoOpenEnabled", undefined) - const isInjectionEnabled_promise = callBackground("isInjectionEnabled", undefined) + const isAutoOpenEnabled_promise = callBackground("isAutoOpenEnabled", undefined).then(result => { + loaderSettings.isAutoOpenEnabled = result; + return result; + }) + const isDomainTrusted_promise = callBackground("isDomainTrusted", { + domain: window.location.origin + }).then(result => { + loaderSettings.isDomainTrusted = result; + return result; + }) - onTalerMetaTagFound(async (el)=> { - const enabled = await isAutoOpenEnabled_promise; - if (!enabled) return; + onTalerMetaTagFound(async (el) => { + await isAutoOpenEnabled_promise; + if (!loaderSettings.isAutoOpenEnabled) { + return; + } redirectToTalerActionHandler(el) }) onHeadReady(async (el) => { - const enabled = await isInjectionEnabled_promise; - if (!enabled) return; - injectTalerSupportScript(el) + const trusted = await isDomainTrusted_promise + injectTalerSupportScript(el, trusted) + }) + + listenToWalletBackground((e: MessageFromBackend) => { + if (e.type === "web-extension" && e.notification.type === "settings-change") { + const settings = e.notification.currentValue + loaderSettings.isAutoOpenEnabled = settings.autoOpen + } }) } +function isCorrectMetaElement(el: HTMLMetaElement): boolean { + const name = el.getAttribute("name") + if (!name) return false; + if (name !== "taler-uri") return false; + const uri = el.getAttribute("content"); + if (!uri) return false; + return true +} + /** * Tries to find taler meta tag ASAP and report * @param notify * @returns */ -function onTalerMetaTag(notify: (el: HTMLMetaElement) => void) { +function notifyWhenTalerUriIsFound(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) + if (isCorrectMetaElement(element)) { + notify(element) + } return; } const obs = new MutationObserver(async function (mutations) { @@ -250,13 +314,10 @@ function onTalerMetaTag(notify: (el: HTMLMetaElement) => void) { 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() + if (isCorrectMetaElement(added)) { + notify(added) + obs.disconnect() + } } }); } @@ -279,7 +340,7 @@ function onTalerMetaTag(notify: (el: HTMLMetaElement) => void) { * @param notify * @returns */ -function onHeaderReady(notify: (el: HTMLHeadElement) => void) { +function notifyWhenHeadIsFound(notify: (el: HTMLHeadElement) => void) { if (document.head) { notify(document.head) return; @@ -290,7 +351,6 @@ function onHeaderReady(notify: (el: HTMLHeadElement) => void) { if (mut.type === "childList") { mut.addedNodes.forEach((added) => { if (added instanceof HTMLHeadElement) { - notify(added) obs.disconnect() } @@ -309,4 +369,4 @@ function onHeaderReady(notify: (el: HTMLHeadElement) => void) { }) } -start(onTalerMetaTag, onHeaderReady); +start(notifyWhenTalerUriIsFound, notifyWhenHeadIsFound); |