summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts
diff options
context:
space:
mode:
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.ts134
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);