gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: first take on adding auto ope


From: gnunet
Subject: [taler-wallet-core] branch master updated: first take on adding auto open again, WIP
Date: Thu, 26 Oct 2023 20:27:05 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new c19aa60d3 first take on adding auto open again, WIP
c19aa60d3 is described below

commit c19aa60d3687260d01404f94e0902fe1943f16df
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Oct 26 15:26:58 2023 -0300

    first take on adding auto open again, WIP
---
 .../taler-wallet-webextension/manifest-v3.json     |   1 +
 .../src/hooks/useSettings.ts                       |   1 +
 .../taler-wallet-webextension/src/platform/api.ts  |  25 +-
 .../src/platform/chrome.ts                         | 268 ++++++++++++++-------
 .../taler-wallet-webextension/src/platform/dev.ts  |   2 +
 .../src/platform/firefox.ts                        |   9 +-
 .../src/wallet/Settings.stories.tsx                |   5 +
 .../src/wallet/Settings.tsx                        |  32 ++-
 packages/taler-wallet-webextension/src/wxApi.ts    |  10 +-
 .../taler-wallet-webextension/src/wxBackend.ts     |  72 +++++-
 10 files changed, 328 insertions(+), 97 deletions(-)

diff --git a/packages/taler-wallet-webextension/manifest-v3.json 
b/packages/taler-wallet-webextension/manifest-v3.json
index 93a1a7fc8..bdee05539 100644
--- a/packages/taler-wallet-webextension/manifest-v3.json
+++ b/packages/taler-wallet-webextension/manifest-v3.json
@@ -15,6 +15,7 @@
   "permissions": [
     "unlimitedStorage",
     "storage",
+    "webRequest",
     "activeTab",
     "scripting",
     "declarativeContent",
diff --git a/packages/taler-wallet-webextension/src/hooks/useSettings.ts 
b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
index 7332c15bb..563f3628a 100644
--- a/packages/taler-wallet-webextension/src/hooks/useSettings.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
@@ -35,6 +35,7 @@ export const codecForSettings = (): Codec<Settings> =>
   buildCodecForObject<Settings>()
     .property("walletAllowHttp", codecForBoolean())
     .property("injectTalerSupport", codecForBoolean())
+    .property("autoOpenByHeader", codecForBoolean())
     .property("advanceMode", codecForBoolean())
     .property("backup", codecForBoolean())
     .property("langSelector", codecForBoolean())
diff --git a/packages/taler-wallet-webextension/src/platform/api.ts 
b/packages/taler-wallet-webextension/src/platform/api.ts
index 44b5959a8..56d668a97 100644
--- a/packages/taler-wallet-webextension/src/platform/api.ts
+++ b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -16,20 +16,18 @@
 
 import {
   CoreApiResponse,
-  NotificationType,
   TalerUri,
-  WalletNotification,
+  WalletNotification
 } from "@gnu-taler/taler-util";
 import {
   WalletConfig,
-  WalletConfigParameter,
-  WalletOperations,
+  WalletOperations
 } from "@gnu-taler/taler-wallet-core";
-import { BackgroundOperations } from "../wxApi.js";
 import {
   ExtensionOperations,
   MessageFromExtension,
 } from "../taler-wallet-interaction-loader.js";
+import { BackgroundOperations } from "../wxApi.js";
 
 export interface Permissions {
   /**
@@ -48,9 +46,9 @@ export interface Permissions {
  * Compatibility API that works on multiple browsers.
  */
 export interface CrossBrowserPermissionsApi {
-  // containsHostPermissions(): Promise<boolean>;
-  // requestHostPermissions(): Promise<boolean>;
-  // removeHostPermissions(): Promise<boolean>;
+  containsHostPermissions(): Promise<boolean>;
+  requestHostPermissions(): Promise<boolean>;
+  removeHostPermissions(): Promise<boolean>;
 
   containsClipboardPermissions(): Promise<boolean>;
   requestClipboardPermissions(): Promise<boolean>;
@@ -102,6 +100,7 @@ type WebexWalletConfig = {
 
 export interface Settings extends WebexWalletConfig {
   injectTalerSupport: boolean;
+  autoOpenByHeader: boolean;
   advanceMode: boolean;
   backup: boolean;
   langSelector: boolean;
@@ -112,6 +111,7 @@ export interface Settings extends WebexWalletConfig {
 
 export const defaultSettings: Settings = {
   injectTalerSupport: true,
+  autoOpenByHeader: true,
   advanceMode: false,
   backup: false,
   langSelector: false,
@@ -206,6 +206,15 @@ export interface BackgroundPlatformAPI {
       message: MessageFromFrontend<Op> & { id: string },
     ) => Promise<MessageResponse>,
   ): void;
+
+  /**
+   * Backend API
+   */
+  registerTalerHeaderListener(
+    onHeader: (tabId: number, url: string) => void,
+  ): void;
+
+  containsTalerHeaderListener(): boolean;
 }
 export interface ForegroundPlatformAPI {
   /**
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts 
b/packages/taler-wallet-webextension/src/platform/chrome.ts
index b0934f107..3151bd6ab 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -59,6 +59,8 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
   useServiceWorkerAsBackgroundProcess,
   keepAlive,
   listenNetworkConnectionState,
+  registerTalerHeaderListener,
+  containsTalerHeaderListener,
 };
 
 export default api;
@@ -95,10 +97,6 @@ function isFirefox(): boolean {
   return false;
 }
 
-// const hostPermissions = {
-//   permissions: ["webRequest"],
-//   origins: ["http://*/*";, "https://*/*";],
-// };
 
 export function containsClipboardPermissions(): Promise<boolean> {
   return new Promise((res, rej) => {
@@ -113,18 +111,6 @@ export function containsClipboardPermissions(): 
Promise<boolean> {
   });
 }
 
-// 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 requestClipboardPermissions(): Promise<boolean> {
   return new Promise((res, rej) => {
     res(false);
@@ -138,67 +124,7 @@ export async function requestClipboardPermissions(): 
Promise<boolean> {
   });
 }
 
-// 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);
-//     });
-//   });
-// }
-
-// 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;
-
-// 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);
-//     });
-//   });
-// }
+
 
 export function removeClipboardPermissions(): Promise<boolean> {
   return new Promise((res, rej) => {
@@ -225,9 +151,9 @@ function addPermissionsListener(
 function getPermissionsApi(): CrossBrowserPermissionsApi {
   return {
     addPermissionsListener,
-    // containsHostPermissions,
-    // requestHostPermissions,
-    // removeHostPermissions,
+    containsHostPermissions,
+    requestHostPermissions,
+    removeHostPermissions,
     requestClipboardPermissions,
     removeClipboardPermissions,
     containsClipboardPermissions,
@@ -365,7 +291,7 @@ async function sendMessageToBackground<
     const timerId = setTimeout(() => {
       timedout = true;
       reject(TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, {}) );
-    }, 20 * 1000); //five seconds
+    }, 20 * 1000);
     chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
       if (timedout) {
         return false; //already rejected
@@ -782,3 +708,183 @@ function listenNetworkConnectionState(
     window.removeEventListener("online", notifyOnline);
   };
 }
+
+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 registerTalerHeaderListener(
+  callback: (tabId: number, url: string) => void,
+): void {
+  logger.info("setting up header listener");
+
+  function headerListener(
+    details: chrome.webRequest.WebResponseHeadersDetails,
+  ): void {
+    if (chrome.runtime.lastError) {
+      logger.error(JSON.stringify(chrome.runtime.lastError));
+      return;
+    }
+    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}`,
+        );
+        callback(details.tabId, values[0]);
+      }
+    }
+    return;
+  }
+
+  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}`);
+      callback(tabId, uri);
+    }
+  }
+
+  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)
+      ) {
+        chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener);
+      }
+      if (
+        prevTabListener &&
+        chrome?.tabs?.onUpdated?.hasListener(prevTabListener)
+      ) {
+        chrome.tabs.onUpdated.removeListener(prevTabListener);
+      }
+
+      //if the result was positive, add the headerListener
+      if (result) {
+        const headersEvent:
+          | chrome.webRequest.WebResponseHeadersEvent
+          | undefined = chrome?.webRequest?.onHeadersReceived;
+        if (headersEvent) {
+          headersEvent.addListener(headerListener, { urls: ["<all_urls>"] }, [
+            "responseHeaders",
+          ]);
+          currentHeaderListener = headerListener;
+        }
+
+        const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined =
+          chrome?.tabs?.onUpdated;
+        if (tabsEvent) {
+          tabsEvent.addListener(tabListener);
+          currentTabListener = tabListener;
+        }
+      }
+
+      //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
diff --git a/packages/taler-wallet-webextension/src/platform/dev.ts 
b/packages/taler-wallet-webextension/src/platform/dev.ts
index 976ac05f5..218422ded 100644
--- a/packages/taler-wallet-webextension/src/platform/dev.ts
+++ b/packages/taler-wallet-webextension/src/platform/dev.ts
@@ -44,6 +44,8 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
     removeClipboardPermissions: async () => false,
     requestClipboardPermissions: async () => false,
   }),
+  registerTalerHeaderListener: () => false,
+  containsTalerHeaderListener: () => false,
   getWalletWebExVersion: () => ({
     version: "none",
   }),
diff --git a/packages/taler-wallet-webextension/src/platform/firefox.ts 
b/packages/taler-wallet-webextension/src/platform/firefox.ts
index 9f666e7ae..cc734ebf7 100644
--- a/packages/taler-wallet-webextension/src/platform/firefox.ts
+++ b/packages/taler-wallet-webextension/src/platform/firefox.ts
@@ -26,6 +26,9 @@ import chromePlatform, {
   containsClipboardPermissions as chromeClipContains,
   removeClipboardPermissions as chromeClipRemove,
   requestClipboardPermissions as chromeClipRequest,
+  containsHostPermissions as chromeHostContains,
+  requestHostPermissions as chromeHostRequest,
+  removeHostPermissions as chromeHostRemove,
 } from "./chrome.js";
 
 const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
@@ -51,9 +54,9 @@ function addPermissionsListener(callback: (p: Permissions) => 
void): void {
 function getPermissionsApi(): CrossBrowserPermissionsApi {
   return {
     addPermissionsListener,
-    // containsHostPermissions: chromeHostContains,
-    // requestHostPermissions: chromeHostRequest,
-    // removeHostPermissions: chromeHostRemove,
+    containsHostPermissions: chromeHostContains,
+    requestHostPermissions: chromeHostRequest,
+    removeHostPermissions: chromeHostRemove,
     containsClipboardPermissions: chromeClipContains,
     removeClipboardPermissions: chromeClipRemove,
     requestClipboardPermissions: chromeClipRequest,
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
index da4a20437..c18c0d9bb 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
@@ -43,12 +43,14 @@ const version = {
     version: "0.9.0.13",
     hash: "d439c3e1bc743f2aa47de4457953dba6ecb0e20f",
   },
+
 };
 
 export const AllOff = tests.createExample(TestedComponent, {
   deviceName: "this-is-the-device-name",
   advanceToggle: { value: false, button: {} },
   autoOpenToggle: { value: false, button: {} },
+  injectTalerToggle: { value: false, button: {} },
   langToggle: { value: false, button: {} },
   setDeviceName: () => Promise.resolve(),
   ...version,
@@ -58,6 +60,7 @@ export const OneChecked = 
tests.createExample(TestedComponent, {
   deviceName: "this-is-the-device-name",
   advanceToggle: { value: false, button: {} },
   autoOpenToggle: { value: false, button: {} },
+  injectTalerToggle: { value: false, button: {} },
   langToggle: { value: false, button: {} },
   setDeviceName: () => Promise.resolve(),
   ...version,
@@ -67,6 +70,7 @@ export const WithOneExchange = 
tests.createExample(TestedComponent, {
   deviceName: "this-is-the-device-name",
   advanceToggle: { value: false, button: {} },
   autoOpenToggle: { value: false, button: {} },
+  injectTalerToggle: { value: false, button: {} },
   langToggle: { value: false, button: {} },
   setDeviceName: () => Promise.resolve(),
   knownExchanges: [
@@ -91,6 +95,7 @@ export const WithExchangeInDifferentState = 
tests.createExample(
     deviceName: "this-is-the-device-name",
     advanceToggle: { value: false, button: {} },
     autoOpenToggle: { value: false, button: {} },
+    injectTalerToggle: { value: false, button: {} },
     langToggle: { value: false, button: {} },
     setDeviceName: () => Promise.resolve(),
     knownExchanges: [
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx 
b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 45a6db5df..2319fe30a 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -73,6 +73,14 @@ export function SettingsPage(): VNode {
       deviceName={name}
       setDeviceName={update}
       autoOpenToggle={{
+        value: settings.autoOpenByHeader,
+        button: {
+          onClick: safely("update support injection", async () => {
+            updateSettings("autoOpenByHeader", !settings.autoOpenByHeader);
+          }),
+        },
+      }}
+      injectTalerToggle={{
         value: settings.injectTalerSupport,
         button: {
           onClick: safely("update support injection", async () => {
@@ -109,6 +117,7 @@ export interface ViewProps {
   deviceName: string;
   setDeviceName: (s: string) => Promise<void>;
   autoOpenToggle: ToggleHandler;
+  injectTalerToggle: ToggleHandler;
   advanceToggle: ToggleHandler;
   langToggle: ToggleHandler;
   knownExchanges: Array<ExchangeListItem>;
@@ -122,6 +131,7 @@ export interface ViewProps {
 export function SettingsView({
   knownExchanges,
   autoOpenToggle,
+  injectTalerToggle,
   advanceToggle,
   langToggle,
   coreVersion,
@@ -207,7 +217,23 @@ export function SettingsView({
             <i18n.Translate>Add an exchange</i18n.Translate>
           </LinkPrimary>
         </div>
-
+        <EnabledBySettings name="advanceMode">
+          <SubTitle>
+            <i18n.Translate>Navigator</i18n.Translate>
+          </SubTitle>
+          <Checkbox
+            label={i18n.str`Automatically open wallet based on page content`}
+            name="autoOpen"
+            description={
+              <i18n.Translate>
+                Enabling this option below will make using the wallet faster,
+                but requires more permissions from your browser.
+              </i18n.Translate>
+            }
+            enabled={autoOpenToggle.value!}
+            onToggle={autoOpenToggle.button.onClick!}
+          />
+        </EnabledBySettings>
 
         {coreVersion && (<Fragment>
           {LibtoolVersion.compare(coreVersion.version, 
WALLET_CORE_SUPPORTED_VERSION)?.compatible ? undefined :
@@ -276,8 +302,8 @@ export function SettingsView({
               open the wallet using the keyboard shortcut
             </i18n.Translate>
           }
-          enabled={autoOpenToggle.value!}
-          onToggle={autoOpenToggle.button.onClick!}
+          enabled={injectTalerToggle.value!}
+          onToggle={injectTalerToggle.button.onClick!}
         />
         <SubTitle>
           <i18n.Translate>Version</i18n.Translate>
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index 21162ccbf..8fb8211ae 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -53,7 +53,7 @@ import { platform } from "./platform/foreground.js";
 
 const logger = new Logger("wxApi");
 
-export const WALLET_CORE_SUPPORTED_VERSION = "0:0:0"
+export const WALLET_CORE_SUPPORTED_VERSION = "1:0:0"
 
 export interface ExtendedPermissionsResponse {
   newValue: boolean;
@@ -83,6 +83,14 @@ export interface BackgroundOperations {
     };
     response: void;
   };
+  containsHeaderListener: {
+    request: void;
+    response: ExtendedPermissionsResponse;
+  };
+  toggleHeaderListener: {
+    request: boolean;
+    response: ExtendedPermissionsResponse;
+  };
 }
 
 export interface BackgroundApiClient {
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts 
b/packages/taler-wallet-webextension/src/wxBackend.ts
index 40b7077af..23d3d64fa 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -31,6 +31,7 @@ import {
   WalletNotification,
   getErrorDetailFromException,
   makeErrorDetail,
+  parseTalerUri,
   setGlobalLogLevelFromString,
   setLogLevelFromString,
 } from "@gnu-taler/taler-util";
@@ -54,7 +55,7 @@ import {
 import { MessageFromFrontend, MessageResponse } from "./platform/api.js";
 import { platform } from "./platform/background.js";
 import { ExtensionOperations } from "./taler-wallet-interaction-loader.js";
-import { BackgroundOperations } from "./wxApi.js";
+import { BackgroundOperations, ExtendedPermissionsResponse } from "./wxApi.js";
 import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
 
 /**
@@ -132,14 +133,26 @@ async function isInjectionEnabled(): Promise<boolean> {
   return settings.injectTalerSupport === true;
 }
 
+async function isHeaderListenerEnabled(): Promise<boolean> {
+  const settings = await platform.getSettingsFromStorage();
+  return settings.autoOpenByHeader === true;
+}
+
 const backendHandlers: BackendHandlerType = {
   freeze,
   sum,
   resetDb,
   runGarbageCollector,
   setLoggingLevel,
+  containsHeaderListener,
+  toggleHeaderListener,
 };
 
+async function containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
+  const result = await platform.containsTalerHeaderListener();
+  return { newValue: result };
+}
+
 async function setLoggingLevel({
   tag,
   level,
@@ -340,4 +353,61 @@ export async function wxMain(): Promise<void> {
   } catch (e) {
     console.error(e);
   }
+  // On platforms that support it, also listen to external
+  // modification of permissions.
+  platform.getPermissionsApi().addPermissionsListener((perm, lastError) => {
+    logger.info(`permission added: ${perm}`, )
+    if (lastError) {
+      logger.error(
+        `there was a problem trying to get permission ${perm}`,
+        lastError,
+      );
+      return;
+    }
+    platform.registerTalerHeaderListener(parseTalerUriAndRedirect);
+  });
+
+  if (await isHeaderListenerEnabled()) {
+    if (await platform.getPermissionsApi().containsHostPermissions()) {
+      try {
+        platform.registerTalerHeaderListener(parseTalerUriAndRedirect);
+      } catch (e) {
+        logger.error("could not register header listener", e);
+      }
+    } else {
+      await platform.getPermissionsApi().requestHostPermissions()
+    }
+  }
+
+}
+
+
+async function toggleHeaderListener(
+  newVal: boolean,
+): Promise<ExtendedPermissionsResponse> {
+  logger.trace("new extended permissions value", newVal);
+  if (newVal) {
+    platform.registerTalerHeaderListener(parseTalerUriAndRedirect);
+    return { newValue: true };
+  }
+
+  const rem = await platform.getPermissionsApi().removeHostPermissions();
+  logger.trace("permissions removed:", rem);
+  return { newValue: false };
 }
+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 platform.redirectTabToWalletPage(
+    tabId,
+    `/taler-uri/${encodeURIComponent(talerUri)}`,
+  );
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]