commit 6e8a9a0e6638ed22533affb18e90e7a45aceeaf6
parent 3b08c7334ef506da9ff7a16011a17c78bd56b219
Author: Florian Dold <florian@dold.me>
Date: Mon, 24 Nov 2025 23:47:39 +0100
webext: overhaul content script injection, support callbacks
Diffstat:
6 files changed, 272 insertions(+), 254 deletions(-)
diff --git a/packages/taler-wallet-webextension/src/background.ts b/packages/taler-wallet-webextension/src/background.ts
@@ -18,6 +18,7 @@
* Entry point for the background page.
*
* @author sebasjm
+ * @author Florian Dold <dold@taler.net>
*/
/**
@@ -40,7 +41,46 @@ if (isFirefox) {
setupPlatform(chromeAPI);
}
-// setGlobalLogLevelFromString("trace")
+const injectIntoTabs = async () => {
+ const urlPatterns = ["https://*/*", "http://*/*"];
+ const tabs = await chrome.tabs.query({ url: urlPatterns });
+ for (const tab of tabs) {
+ if (
+ !tab.id ||
+ !tab.url ||
+ tab.url.startsWith("chrome://") ||
+ tab.url.startsWith("edge://")
+ ) {
+ continue;
+ }
+
+ console.log("injecting content script into tab", tab.url);
+
+ try {
+ await chrome.scripting.executeScript({
+ target: { tabId: tab.id },
+ files: ["dist/taler-wallet-interaction-loader.js"],
+ });
+ } catch (err) {
+ // Catch errors for specific restricted pages (like Chrome Web Store)
+ console.warn(`Failed to inject into tab ${tab.id}:`, err);
+ }
+ }
+};
+
+// Manually run content script in all tabs that are already open.
+try {
+ chrome.runtime.onInstalled.addListener(injectIntoTabs);
+} catch (e) {
+ console.error(e);
+}
+
+// Also run injection directly, in case we're in a service worker.
+try {
+ injectIntoTabs();
+} catch (e) {
+ console.error(e);
+}
async function start() {
await platform.notifyWhenAppIsReady();
diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -21,11 +21,11 @@ import {
WalletRunConfig,
} from "@gnu-taler/taler-util";
import { WalletOperations } from "@gnu-taler/taler-wallet-core";
-import {
+import { BackgroundOperations } from "../wxApi.js";
+import type {
ExtensionOperations,
MessageFromExtension,
-} from "../taler-wallet-interaction-loader.js";
-import { BackgroundOperations } from "../wxApi.js";
+} from "../wxBackend.js";
export interface Permissions {
/**
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -23,6 +23,7 @@ import {
stringifyTalerUri,
} from "@gnu-taler/taler-util";
import { WalletOperations } from "@gnu-taler/taler-wallet-core";
+import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
import { BackgroundOperations } from "../wxApi.js";
import {
BackgroundPlatformAPI,
@@ -35,7 +36,6 @@ import {
Settings,
defaultSettings,
} from "./api.js";
-import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
isFirefox,
@@ -242,7 +242,9 @@ function openWalletURIFromPopup(uri: TalerUri): void {
logger.warn(`taler://dev-experiment URIs are not allowed in headers`);
return;
case TalerUriAction.WithdrawalTransferResult:
- logger.warn(`taler://withdrawal-transfer-result URIs are not allowed in headers`);
+ logger.warn(
+ `taler://withdrawal-transfer-result URIs are not allowed in headers`,
+ );
return;
default: {
const error: never = uri;
@@ -605,8 +607,8 @@ async function registerIconChangeOnTalerContent(): Promise<void> {
return;
}
- //this browser doesn't have declarativeContent
- //we need host_permission and we will check the content for changing the icon
+ // this browser doesn't have declarativeContent
+ // we need host_permission and we will check the content for changing the icon
chrome.tabs.onUpdated.addListener(
async (tabId, info: chrome.tabs.TabChangeInfo) => {
if (tabId < 0) return;
diff --git a/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts
@@ -1,6 +1,6 @@
/*
This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
+ (C) 2022-2025 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -14,24 +14,24 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import {
- CoreApiResponse,
- TalerError,
- TalerErrorCode,
-} from "@gnu-taler/taler-util";
-
-import type { MessageFromBackend } from "./platform/api.js";
-// FIXME: mem leak problems
-// import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
-
-
/**
- * This will modify all the pages that the user load when navigating with Web Extension enabled
+ * This content script injects Taler support into pages that request it.
*
- * Can't do useful integration since it run in ISOLATED (or equivalent) mode.
- *
- * If taler support is expected, it will inject a script which will complete the integration.
+ * Since the content script runs in an isolated context, we inject
+ * Taler support by adding a script tag to the DOM.
+ */
+
+/**
+ * Imports.
+ * Since this script runs as a content script, we want to import
+ * as little as possible.
*/
+import type { MessageFromBackend } from "./platform/api.js";
+import type {
+ ExtensionOperations,
+ MessageFromExtension,
+ MessageResponse,
+} from "./wxBackend.js";
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Chrome_incompatibilities#content_script_environment
@@ -47,17 +47,28 @@ import type { MessageFromBackend } from "./platform/api.js";
// however, window object properties are destroyed.
// In Chrome: Content scripts are destroyed when the user navigates away from a web page.
-const documentDocTypeIsHTML =
- window.document.doctype && window.document.doctype.name === "html";
-const suffixIsNotXMLorPDF =
- !window.location.pathname.endsWith(".xml") &&
- !window.location.pathname.endsWith(".pdf");
-const rootElementIsHTML =
- document.documentElement.nodeName &&
- document.documentElement.nodeName.toLowerCase() === "html";
-// const pageAcceptsTalerSupport = document.head.querySelector(
-// "meta[name=taler-support]",
-// );
+interface TalerSupportStatus {
+ debugEnabled: boolean;
+ talerApiEnabled: boolean;
+ hijackEnabled: boolean;
+ callbackEnabled: boolean;
+}
+
+/** Current set of support flags, if requested by the page. */
+let talerSupportFlags: TalerSupportStatus | undefined;
+/** Currently injected script tag. */
+let interactionSupportElement: HTMLScriptElement | undefined = undefined;
+
+/** Index of the next message we send to the webext backend. */
+let nextMessageIndex = 0;
+
+const logger = {
+ debug: (...msg: any[]) => {},
+ info: (...msg: any[]) =>
+ console.log(`${new Date().toISOString()} TALER`, ...msg),
+ error: (...msg: any[]) =>
+ console.error(`${new Date().toISOString()} TALER`, ...msg),
+};
function validateTalerUri(uri: string): boolean {
return (
@@ -68,34 +79,12 @@ function validateTalerUri(uri: string): boolean {
function convertURIToWebExtensionPath(uri: string) {
const url = new URL(
chrome.runtime.getURL(
- // FIXME: mem leak problems
- // `static/wallet.html#/taler-uri/${encodeCrockForURI(uri)}`,
`static/wallet.html#/taler-uri-simple/${encodeURIComponent(uri)}`,
),
);
return url.href;
}
-// safe check, if one of this is true then taler handler is not useful
-// or not expected
-const shouldNotInject =
- !documentDocTypeIsHTML ||
- !suffixIsNotXMLorPDF ||
- // !pageAcceptsTalerSupport ||
- !rootElementIsHTML;
-
-const logger = {
- debug: (...msg: any[]) => { },
- info: (...msg: any[]) =>
- console.log(`${new Date().toISOString()} TALER`, ...msg),
- error: (...msg: any[]) =>
- console.error(`${new Date().toISOString()} TALER`, ...msg),
-};
-
-// logger.debug = logger.info
-
-/**
- */
function redirectToTalerActionHandler(element: HTMLMetaElement) {
const name = element.getAttribute("name");
if (!name) return;
@@ -112,65 +101,76 @@ function redirectToTalerActionHandler(element: HTMLMetaElement) {
window.location.replace(walletPage);
}
-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 hijackEnabled = features.indexOf("uri") !== -1;
- const talerApiEnabled = features.indexOf("api") !== -1 && trusted;
-
+function loadScript(args: { unload?: boolean } = {}): void {
+ if (interactionSupportElement) {
+ interactionSupportElement.remove();
+ interactionSupportElement = undefined;
+ }
+ if (!talerSupportFlags) {
+ return;
+ }
const scriptTag = document.createElement("script");
scriptTag.setAttribute("async", "false");
const url = new URL(
chrome.runtime.getURL("/dist/taler-wallet-interaction-support.js"),
);
- url.searchParams.set("id", chrome.runtime.id);
- if (debugEnabled) {
- url.searchParams.set("debug", "true");
- }
- if (talerApiEnabled) {
- url.searchParams.set("api", "true");
- }
- if (hijackEnabled) {
- url.searchParams.set("hijack", "true");
- }
+ const setParamBool = (key: string, value: boolean | undefined) => {
+ if (value) {
+ url.searchParams.set(key, "true");
+ }
+ };
+ setParamBool("callback", talerSupportFlags.callbackEnabled);
+ setParamBool("debug", talerSupportFlags.debugEnabled);
+ setParamBool("api", talerSupportFlags.talerApiEnabled);
+ setParamBool("hijack", talerSupportFlags.hijackEnabled);
+ setParamBool("unload", args.unload);
scriptTag.src = url.href;
-
+ const head = document.head;
try {
- head.insertBefore(
+ interactionSupportElement = head.insertBefore(
scriptTag,
head.children.length ? head.children[0] : null,
);
} catch (e) {
logger.info("inserting link handler failed!");
logger.error(e);
+ return undefined;
}
}
-export interface ExtensionOperations {
- isAutoOpenEnabled: {
- request: void;
- response: boolean;
- };
- isDomainTrusted: {
- request: {
- domain: string;
- };
- response: boolean;
- };
+function maybeHandleMetaTalerUri() {
+ const metaTalerUri = document.head.querySelector("meta[name=taler-uri]");
+ if (metaTalerUri && metaTalerUri instanceof HTMLMetaElement) {
+ const uri = metaTalerUri.getAttribute("content");
+ if (!uri) {
+ return;
+ }
+ redirectToTalerActionHandler(metaTalerUri);
+ }
}
-export type MessageFromExtension<Op extends keyof ExtensionOperations> = {
- channel: "extension";
- operation: Op;
- payload: ExtensionOperations[Op]["request"];
-};
-
-export type MessageResponse = CoreApiResponse;
+function maybeHandleMetaTalerSupport() {
+ if (talerSupportFlags) {
+ // Already loaded.
+ return;
+ }
+ const meta = document.head.querySelector("meta[name=taler-support]");
+ if (!meta || !(meta instanceof HTMLMetaElement)) {
+ return;
+ }
+ const content = meta.getAttribute("content");
+ if (!content) {
+ return;
+ }
+ const features = content.split(",");
+ talerSupportFlags = {
+ debugEnabled: meta.getAttribute("debug") === "true",
+ hijackEnabled: features.indexOf("uri") >= 0,
+ callbackEnabled: features.indexOf("callback") >= 0,
+ talerApiEnabled: features.indexOf("api") >= 0,
+ };
+ loadScript();
+}
async function callBackground<Op extends keyof ExtensionOperations>(
operation: Op,
@@ -189,21 +189,13 @@ async function callBackground<Op extends keyof ExtensionOperations>(
return response.result as any;
}
-let nextMessageIndex = 0;
-/**
- *
- * @param message
- * @returns
- */
async function sendMessageToBackground<Op extends keyof ExtensionOperations>(
message: MessageFromExtension<Op>,
): Promise<MessageResponse> {
const messageWithId = { ...message, id: `ld:${nextMessageIndex++ % 1000}` };
if (!chrome.runtime.id) {
- return Promise.reject(
- TalerError.fromDetail(TalerErrorCode.WALLET_CORE_NOT_AVAILABLE, {}),
- );
+ return Promise.reject(new Error("wallet-core not available"));
}
return new Promise<any>((resolve, reject) => {
logger.debug(
@@ -214,18 +206,12 @@ async function sendMessageToBackground<Op extends keyof ExtensionOperations>(
let timedout = false;
const timerId = setTimeout(() => {
timedout = true;
- reject(
- TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, {
- requestMethod: "wallet",
- requestUrl: message.operation,
- timeoutMs: 20 * 1000,
- }),
- );
- }, 20 * 1000); //five seconds
+ reject(new Error(`wallet-core timeout ${message.operation}`));
+ }, 20 * 1000);
try {
chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
if (timedout) {
- return false; //already rejected
+ return false; // already rejected
}
clearTimeout(timerId);
if (chrome.runtime.lastError) {
@@ -242,154 +228,113 @@ 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,
-) {
+async function start() {
+ const documentDocTypeIsHTML =
+ window.document.doctype && window.document.doctype.name === "html";
+ const suffixIsNotXMLorPDF =
+ !window.location.pathname.endsWith(".xml") &&
+ !window.location.pathname.endsWith(".pdf");
+ const rootElementIsHTML =
+ document.documentElement.nodeName &&
+ document.documentElement.nodeName.toLowerCase() === "html";
+
+ // safe check, if one of this is true then taler handler is not useful
+ // or not expected
+ const shouldNotInject =
+ !documentDocTypeIsHTML || !suffixIsNotXMLorPDF || !rootElementIsHTML;
// 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",
+ const injectSettings = await callBackground(
+ "getInjectionSettings",
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) => {
- await isAutoOpenEnabled_promise;
- if (!loaderSettings.isAutoOpenEnabled) {
- return;
+ await waitHeadReady();
+
+ const checkMeta = () => {
+ if (injectSettings.autoOpen) {
+ maybeHandleMetaTalerUri();
}
- redirectToTalerActionHandler(el);
- });
+ if (injectSettings.injectTalerSupport) {
+ maybeHandleMetaTalerSupport();
+ }
+ };
- onHeadReady(async (el) => {
- const trusted = await isDomainTrusted_promise;
- injectTalerSupportScript(el, trusted);
- });
+ checkMeta();
+
+ const observerCallback = function (
+ mutationsList: MutationRecord[],
+ observer: MutationObserver,
+ ) {
+ for (const mutation of mutationsList) {
+ if (mutation.type === "childList") {
+ mutation.addedNodes.forEach((node) => {
+ if (node instanceof Element && node.tagName === "META") {
+ checkMeta();
+ }
+ if (talerSupportFlags) {
+ observer.disconnect();
+ return;
+ }
+ });
+ }
+ }
+ };
+ const observer = new MutationObserver(observerCallback);
+ observer.observe(document.head, { childList: true, subtree: false });
- listenToWalletBackground((e: MessageFromBackend) => {
+ // Listen for notifications from the webext
+ const notificationPort = chrome.runtime.connect({ name: "notifications" });
+ notificationPort.onMessage.addListener((e: MessageFromBackend) => {
if (
e.type === "web-extension" &&
e.notification.type === "settings-change"
) {
const settings = e.notification.currentValue;
- loaderSettings.isAutoOpenEnabled = settings.autoOpen;
+ injectSettings.autoOpen = settings.autoOpen;
+ checkMeta();
}
});
-}
-
-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 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;
-
- if (isCorrectMetaElement(element)) {
- 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) {
- if (isCorrectMetaElement(added)) {
- notify(added);
- obs.disconnect();
- }
- }
- });
- }
- });
- } catch (e) {
- console.error(e);
- }
- });
-
- obs.observe(document, {
- childList: true,
- subtree: true,
- attributes: false,
+ notificationPort.onDisconnect.addListener(() => {
+ loadScript({
+ unload: true,
+ });
});
}
/**
- * Tries to find HEAD tag ASAP and report
- * @param notify
- * @returns
+ * Tries to find HEAD tag ASAP and report.
*/
-function notifyWhenHeadIsFound(notify: (el: HTMLHeadElement) => void) {
+async function waitHeadReady(): Promise<void> {
if (document.head) {
- notify(document.head);
return;
}
- const obs = new MutationObserver(async function (mutations) {
- try {
+ return new Promise((resolve, reject) => {
+ const obs = new MutationObserver(async function (mutations) {
mutations.forEach((mut) => {
- if (mut.type === "childList") {
- mut.addedNodes.forEach((added) => {
- if (added instanceof HTMLHeadElement) {
- notify(added);
- obs.disconnect();
- }
- });
+ if (mut.type !== "childList") {
+ return;
}
+ mut.addedNodes.forEach((added) => {
+ if (added instanceof HTMLHeadElement) {
+ resolve();
+ obs.disconnect();
+ }
+ });
});
- } catch (e) {
- console.error(e);
- }
- });
+ });
- obs.observe(document, {
- childList: true,
- subtree: true,
- attributes: false,
+ obs.observe(document, {
+ childList: true,
+ subtree: true,
+ attributes: false,
+ });
});
}
-start(notifyWhenTalerUriIsFound, notifyWhenHeadIsFound);
+if (!("contentScriptDidRun" in window)) {
+ (window as any).contentScriptDidRun = true;
+ start();
+}
diff --git a/packages/taler-wallet-webextension/src/taler-wallet-interaction-support.ts b/packages/taler-wallet-webextension/src/taler-wallet-interaction-support.ts
@@ -14,8 +14,6 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
-
/**
* WARNING
*
@@ -24,7 +22,7 @@ import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
*/
(() => {
const logger = {
- debug: (..._msg: unknown[]) => { },
+ debug: (..._msg: unknown[]) => {},
info: (...msg: unknown[]) =>
console.log(`${new Date().toISOString()} TALER`, ...msg),
error: (...msg: unknown[]) =>
@@ -78,9 +76,9 @@ import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
return undefined;
}
const host = `${config.protocol}//${config.hostname}`;
- // FIXME: mem leak problems
- // const path = `static/wallet.html#/taler-uri/${encodeCrockForURI(uri)}`;
- const path = `static/wallet.html#/taler-uri-simple/${encodeURIComponent(uri)}`;
+ const path = `static/wallet.html#/taler-uri-simple/${encodeURIComponent(
+ uri,
+ )}`;
return `${host}/${path}`;
}
@@ -170,6 +168,15 @@ import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
const debugEnabled = searchParams.get("debug") === "true";
const apiEnabled = searchParams.get("api") === "true";
const hijackEnabled = searchParams.get("hijack") === "true";
+ const callbackEnabled = searchParams.get("callback") === "true";
+ const unloadEnabled = searchParams.get("unload") === "true";
+
+ if (unloadEnabled) {
+ if (callbackEnabled && "talercb" in window) {
+ (window as any).talercb({ present: false });
+ }
+ return;
+ }
const info: Info = Object.freeze({
extensionId,
@@ -187,7 +194,7 @@ import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
};
if (apiEnabled) {
- // @ts-expect-error we now that `taler` doesn't exist.
+ // @ts-expect-error we now that `taler` doesn't exist.
// we are creating the property
window.taler = taler;
}
@@ -195,6 +202,12 @@ import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
if (hijackEnabled) {
taler.__internal.registerProtocolHandler();
}
+
+ if (callbackEnabled) {
+ if ("talercb" in window) {
+ (window as any).talercb({ present: true });
+ }
+ }
}
// utils functions
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -25,6 +25,7 @@
*/
import {
AbsoluteTime,
+ CoreApiResponse,
LogLevel,
Logger,
NotificationType,
@@ -56,9 +57,8 @@ import {
} from "@gnu-taler/taler-wallet-core";
import { BrowserFetchHttpLib } from "@gnu-taler/web-util/browser";
import { BridgeIDBFactory } from "../../idb-bridge/src/bridge-idb.js";
-import { MessageFromFrontend, MessageResponse } from "./platform/api.js";
+import { MessageFromFrontend } from "./platform/api.js";
import { platform } from "./platform/background.js";
-import { ExtensionOperations } from "./taler-wallet-interaction-loader.js";
import { BackgroundOperations } from "./wxApi.js";
/**
@@ -75,6 +75,24 @@ const walletInit: OpenedPromise<void> = openPromise<void>();
const logger = new Logger("wxBackend.ts");
+export interface ExtensionOperations {
+ getInjectionSettings: {
+ request: void;
+ response: {
+ autoOpen: boolean;
+ injectTalerSupport: boolean;
+ };
+ };
+}
+
+export type MessageFromExtension<Op extends keyof ExtensionOperations> = {
+ channel: "extension";
+ operation: Op;
+ payload: ExtensionOperations[Op]["request"];
+};
+
+export type MessageResponse = CoreApiResponse;
+
type BackendHandlerType = {
[Op in keyof BackgroundOperations]: (
req: BackgroundOperations[Op]["request"],
@@ -277,18 +295,18 @@ async function runGarbageCollector(): Promise<void> {
}
const extensionHandlers: ExtensionHandlerType = {
- isAutoOpenEnabled,
- isDomainTrusted,
+ getInjectionSettings,
};
-async function isAutoOpenEnabled(): Promise<boolean> {
+async function getInjectionSettings(): Promise<{
+ autoOpen: boolean;
+ injectTalerSupport: boolean;
+}> {
const settings = await platform.getSettingsFromStorage();
- return settings.autoOpen === true;
-}
-
-async function isDomainTrusted(): Promise<boolean> {
- const settings = await platform.getSettingsFromStorage();
- return settings.injectTalerSupport === true;
+ return {
+ autoOpen: settings.autoOpen,
+ injectTalerSupport: settings.injectTalerSupport,
+ };
}
const backendHandlers: BackendHandlerType = {