gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 01/02: testing auto open feature


From: gnunet
Subject: [taler-wallet-core] 01/02: testing auto open feature
Date: Mon, 30 Oct 2023 23:23:53 +0100

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

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

commit f1967ab0baf825cdfa767d36bb7cce78521e4e4b
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Oct 30 18:42:39 2023 -0300

    testing auto open feature
---
 .../demobank-ui/src/pages/OperationState/views.tsx |  56 +--
 packages/demobank-ui/src/pages/QrCodeSection.tsx   |   6 +-
 .../taler-wallet-webextension/manifest-v3.json     |  22 +-
 .../src/hooks/useSettings.ts                       |   2 +-
 .../taler-wallet-webextension/src/platform/api.ts  |  18 +-
 .../src/platform/chrome.ts                         | 473 +++++++++++----------
 .../taler-wallet-webextension/src/platform/dev.ts  |   7 +-
 .../src/platform/firefox.ts                        |  12 +-
 .../src/taler-wallet-interaction-loader.ts         | 120 ++++--
 .../src/taler-wallet-interaction-support.ts        |   7 +-
 .../src/wallet/Settings.tsx                        |  32 +-
 packages/taler-wallet-webextension/src/wxApi.ts    |  16 +-
 .../taler-wallet-webextension/src/wxBackend.ts     | 114 ++---
 13 files changed, 483 insertions(+), 402 deletions(-)

diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx 
b/packages/demobank-ui/src/pages/OperationState/views.tsx
index b7d7e5520..4001fd093 100644
--- a/packages/demobank-ui/src/pages/OperationState/views.tsx
+++ b/packages/demobank-ui/src/pages/OperationState/views.tsx
@@ -105,30 +105,30 @@ export function NeedConfirmationView({ error, onAbort: 
doAbort, onConfirm: doCon
         return
       }
       switch (hasError.case) {
-      case "previously-aborted": return notify({
-        type: "error",
-        title: i18n.str`The withdrawal has been aborted previously and can't 
be confirmed`,
-        description: hasError.detail.hint as TranslatedString,
-        debug: hasError.detail,
-      })
-      case "no-exchange-or-reserve-selected": return notify({
-        type: "error",
-        title: i18n.str`The withdraw operation cannot be confirmed because no 
exchange and reserve public key selection happened before`,
-        description: hasError.detail.hint as TranslatedString,
-        debug: hasError.detail,
-      })
-      case "invalid-id": return notify({
-        type: "error",
-        title: i18n.str`The operation id is invalid.`,
-        description: hasError.detail.hint as TranslatedString,
-        debug: hasError.detail,
-      });
-      case "not-found": return notify({
-        type: "error",
-        title: i18n.str`The operation was not found.`,
-        description: hasError.detail.hint as TranslatedString,
-        debug: hasError.detail,
-      });
+        case "previously-aborted": return notify({
+          type: "error",
+          title: i18n.str`The withdrawal has been aborted previously and can't 
be confirmed`,
+          description: hasError.detail.hint as TranslatedString,
+          debug: hasError.detail,
+        })
+        case "no-exchange-or-reserve-selected": return notify({
+          type: "error",
+          title: i18n.str`The withdraw operation cannot be confirmed because 
no exchange and reserve public key selection happened before`,
+          description: hasError.detail.hint as TranslatedString,
+          debug: hasError.detail,
+        })
+        case "invalid-id": return notify({
+          type: "error",
+          title: i18n.str`The operation id is invalid.`,
+          description: hasError.detail.hint as TranslatedString,
+          debug: hasError.detail,
+        });
+        case "not-found": return notify({
+          type: "error",
+          title: i18n.str`The operation was not found.`,
+          description: hasError.detail.hint as TranslatedString,
+          debug: hasError.detail,
+        });
         default: assertUnreachable(hasError)
       }
     })
@@ -408,6 +408,7 @@ export function ReadyView({ uri, onClose: doClose }: 
State.Ready): VNode<{}> {
   const { i18n } = useTranslationContext();
   const [notification, notify, errorHandler] = useLocalNotification()
 
+  const talerWithdrawUri = stringifyWithdrawUri(uri);
   useEffect(() => {
     //Taler Wallet WebExtension is listening to headers response and tab 
updates.
     //In the SPA there is no header response with the Taler URI so
@@ -415,8 +416,11 @@ export function ReadyView({ uri, onClose: doClose }: 
State.Ready): VNode<{}> {
     // WebExtension will be using
     // 
https://developer.chrome.com/docs/extensions/reference/tabs/#event-onUpdated
     document.title = `${document.title} ${uri.withdrawalOperationId}`;
+    const meta = document.createElement("meta")
+    meta.setAttribute("name", "taler-uri")
+    meta.setAttribute("content", talerWithdrawUri)
+    document.head.insertBefore(meta, document.head.children.length ? 
document.head.children[0] : null)
   }, []);
-  const talerWithdrawUri = stringifyWithdrawUri(uri);
 
   async function onClose() {
     errorHandler(async () => {
@@ -447,7 +451,7 @@ export function ReadyView({ uri, onClose: doClose }: 
State.Ready): VNode<{}> {
   }
 
   return <Fragment>
-      <ShowLocalNotification notification={notification} />
+    <ShowLocalNotification notification={notification} />
 
     <div class="flex justify-end mt-4">
       <button type="button"
diff --git a/packages/demobank-ui/src/pages/QrCodeSection.tsx 
b/packages/demobank-ui/src/pages/QrCodeSection.tsx
index ca2a89f48..22bf604f2 100644
--- a/packages/demobank-ui/src/pages/QrCodeSection.tsx
+++ b/packages/demobank-ui/src/pages/QrCodeSection.tsx
@@ -39,6 +39,7 @@ export function QrCodeSection({
   onAborted: () => void;
 }): VNode {
   const { i18n } = useTranslationContext();
+  const talerWithdrawUri = stringifyWithdrawUri(withdrawUri);
   useEffect(() => {
     //Taler Wallet WebExtension is listening to headers response and tab 
updates.
     //In the SPA there is no header response with the Taler URI so
@@ -46,8 +47,11 @@ export function QrCodeSection({
     // WebExtension will be using
     // 
https://developer.chrome.com/docs/extensions/reference/tabs/#event-onUpdated
     document.title = `${document.title} ${withdrawUri.withdrawalOperationId}`;
+    const meta = document.createElement("meta")
+    meta.setAttribute("name", "taler-uri")
+    meta.setAttribute("content", talerWithdrawUri)
+    document.head.insertBefore(meta, document.head.children.length ? 
document.head.children[0] : null)
   }, []);
-  const talerWithdrawUri = stringifyWithdrawUri(withdrawUri);
   const [notification, notify, handleError] = useLocalNotification()
 
   const { api } = useBankCoreApiContext()
diff --git a/packages/taler-wallet-webextension/manifest-v3.json 
b/packages/taler-wallet-webextension/manifest-v3.json
index bdee05539..ae1be5181 100644
--- a/packages/taler-wallet-webextension/manifest-v3.json
+++ b/packages/taler-wallet-webextension/manifest-v3.json
@@ -15,7 +15,6 @@
   "permissions": [
     "unlimitedStorage",
     "storage",
-    "webRequest",
     "activeTab",
     "scripting",
     "declarativeContent",
@@ -28,11 +27,19 @@
       }
     }
   },
-  "content_scripts": [{
-    "id": "taler-wallet-interaction",
-    "matches": ["file://*/*", "http://*/*";, "https://*/*";],
-    "js": ["dist/taler-wallet-interaction-loader.js"]
-  }],
+  "content_scripts": [
+    {
+      "id": "taler-wallet-interaction",
+      "matches": [
+        "http://*/*";,
+        "https://*/*";
+      ],
+      "js": [
+        "dist/taler-wallet-interaction-loader.js"
+      ],
+      "run_at": "document_start"
+    }
+  ],
   "web_accessible_resources": [
     {
       "resources": [
@@ -44,8 +51,7 @@
       ],
       "matches": [
         "https://*/*";,
-        "http://*/*";,
-        "file://*/*"
+        "http://*/*";
       ]
     }
   ],
diff --git a/packages/taler-wallet-webextension/src/hooks/useSettings.ts 
b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
index 563f3628a..dd3822c1a 100644
--- a/packages/taler-wallet-webextension/src/hooks/useSettings.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
@@ -35,7 +35,7 @@ export const codecForSettings = (): Codec<Settings> =>
   buildCodecForObject<Settings>()
     .property("walletAllowHttp", codecForBoolean())
     .property("injectTalerSupport", codecForBoolean())
-    .property("autoOpenByHeader", codecForBoolean())
+    .property("autoOpen", 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 820711ea9..76add93d1 100644
--- a/packages/taler-wallet-webextension/src/platform/api.ts
+++ b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -46,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>;
@@ -100,7 +100,7 @@ type WebexWalletConfig = {
 
 export interface Settings extends WebexWalletConfig {
   injectTalerSupport: boolean;
-  autoOpenByHeader: boolean;
+  autoOpen: boolean;
   advanceMode: boolean;
   backup: boolean;
   langSelector: boolean;
@@ -111,7 +111,7 @@ export interface Settings extends WebexWalletConfig {
 
 export const defaultSettings: Settings = {
   injectTalerSupport: true,
-  autoOpenByHeader: true,
+  autoOpen: true,
   advanceMode: false,
   backup: false,
   langSelector: false,
@@ -207,14 +207,6 @@ export interface BackgroundPlatformAPI {
     ) => 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 fa9ad0522..4fb4bddfd 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -59,8 +59,6 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
   useServiceWorkerAsBackgroundProcess,
   keepAlive,
   listenNetworkConnectionState,
-  registerTalerHeaderListener,
-  containsTalerHeaderListener,
 };
 
 export default api;
@@ -151,9 +149,6 @@ function addPermissionsListener(
 function getPermissionsApi(): CrossBrowserPermissionsApi {
   return {
     addPermissionsListener,
-    containsHostPermissions,
-    requestHostPermissions,
-    removeHostPermissions,
     requestClipboardPermissions,
     removeClipboardPermissions,
     containsClipboardPermissions,
@@ -395,10 +390,17 @@ function registerReloadOnNewVersion(): void {
   });
 }
 
-function redirectTabToWalletPage(tabId: number, page: string): void {
+async function redirectCurrentTabToWalletPage(page: string): Promise<void> {
+  let queryOptions = { active: true, lastFocusedWindow: true };
+  let [tab] = await chrome.tabs.query(queryOptions);
+
+  return redirectTabToWalletPage(tab.id!, page);
+}
+
+async function redirectTabToWalletPage(tabId: number, page: string): 
Promise<void> {
   const url = chrome.runtime.getURL(`/static/wallet.html#${page}`);
   logger.trace("redirecting tabId: ", tabId, " to: ", url);
-  chrome.tabs.update(tabId, { url });
+  await chrome.tabs.update(tabId, { url });
 }
 
 interface WalletVersion {
@@ -709,218 +711,247 @@ function listenNetworkConnectionState(
   };
 }
 
-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 headerListener(
-  details: chrome.webRequest.WebResponseHeadersDetails,
-): void {
-  if (chrome.runtime.lastError) {
-    logger.error(JSON.stringify(chrome.runtime.lastError));
-    return;
-  }
-  console.log("HEADER", details.statusCode, details.url, 
details.responseHeaders)
-  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}`,
-      );
-      redirectTabToWalletPage(details.tabId, values[0]);
-    }
-  }
-  return;
-}
-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 redirectTabToWalletPage(
-    tabId,
-    `/taler-uri/${encodeURIComponent(talerUri)}`,
-  );
-}
-
-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}`);
-    parseTalerUriAndRedirect(tabId, uri);
-  }
-}
-
-function registerTalerHeaderListener(
-  // callback: (tabId: number, url: string) => void,
-): void {
-  logger.info("setting up header listener");
-
-  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)
-      ) {
-        console.log("removming on header listener")
-        chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener);
-        chrome.webRequest.onCompleted.removeListener(prevHeaderListener);
-        chrome.webRequest.onResponseStarted.removeListener(prevHeaderListener);
-        chrome.webRequest.onErrorOccurred.removeListener(prevHeaderListener);
-    }
-      if (
-        prevTabListener &&
-        chrome?.tabs?.onUpdated?.hasListener(prevTabListener)
-      ) {
-        console.log("removming on tab listener")
-        chrome.tabs.onUpdated.removeListener(prevTabListener);
-      }
-
-      //if the result was positive, add the headerListener
-      if (result) {
-        console.log("headers on, disabled:", 
chrome?.webRequest?.onHeadersReceived === undefined)
-        if (chrome?.webRequest) {
-          chrome.webRequest.onHeadersReceived.addListener(headerListener,
-            { urls: ["<all_urls>"] },
-            ["responseHeaders", "extraHeaders"]
-          );
-          chrome.webRequest.onCompleted.addListener(headerListener,
-            { urls: ["<all_urls>"] },
-            ["responseHeaders", "extraHeaders"]
-          );
-          chrome.webRequest.onResponseStarted.addListener(headerListener,
-            { urls: ["<all_urls>"] },
-            ["responseHeaders", "extraHeaders"]
-          );
-          chrome.webRequest.onErrorOccurred.addListener(headerListener,
-            { urls: ["<all_urls>"] },
-            ["extraHeaders"]
-          );
-          currentHeaderListener = headerListener;
-        }
-
-        const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined =
-          chrome?.tabs?.onUpdated;
-        if (tabsEvent) {
-          tabsEvent.addListener(tabListener);
-          currentTabListener = tabListener;
-        }
-      } else {
-        console.log("headers off")
-      }
-
-      //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://*/*";],
-};
+// 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 headerListener(
+//   details: chrome.webRequest.WebResponseHeadersDetails,
+// ): chrome.webRequest.BlockingResponse | undefined {
+//   if (chrome.runtime.lastError) {
+//     logger.error(JSON.stringify(chrome.runtime.lastError));
+//     return;
+//   }
+//   console.log("HEADER", JSON.stringify(details, undefined, 2))
+//   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}`,
+//       );
+//       const redirectUrl = redirectTabToWalletPage(details.tabId, values[0]);
+//       return { redirectUrl }
+//     }
+//   }
+//   return details;
+// }
+// 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;
+//   }
+//   redirectTabToWalletPage(
+//     tabId,
+//     `/taler-uri/${encodeURIComponent(talerUri)}`,
+//   );
+// }
+
+// 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}`);
+//     parseTalerUriAndRedirect(tabId, uri);
+//   }
+// }
 
-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
+/**
+ * unused, declarative redirect is not good enough
+ *
+ */
+// async function registerDeclarativeRedirect() {
+//   await chrome.declarativeNetRequest.updateDynamicRules({
+//     removeRuleIds: [1],
+//     addRules: [
+//       {
+//         id: 1,
+//         priority: 1,
+//         condition: {
+//           urlFilter: "https://developer.chrome.com/docs/extensions/mv2/";,
+//           regexFilter: ".*taler_uri=([^&]*).*",
+//           // isUrlFilterCaseSensitive: false,
+//           // requestMethods: 
[chrome.declarativeNetRequest.RequestMethod.GET]
+//           // resourceTypes: 
[chrome.declarativeNetRequest.ResourceType.MAIN_FRAME],
+//         },
+//         action: {
+//           type: chrome.declarativeNetRequest.RuleActionType.REDIRECT,
+//           redirect: {
+//             regexSubstitution: 
`chrome-extension://${chrome.runtime.id}/static/wallet.html?action=\\1`,
+//           },
+//         },
+//       },
+//     ],
+//   });
+// }
+
+// function registerTalerHeaderListener(
+// ): void {
+//   logger.info("setting up header listener");
+
+//   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)
+//       ) {
+//         console.log("removming on header listener")
+//         
chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener);
+//         // chrome.webRequest.onCompleted.removeListener(prevHeaderListener);
+//         // 
chrome.webRequest.onResponseStarted.removeListener(prevHeaderListener);
+//         // 
chrome.webRequest.onErrorOccurred.removeListener(prevHeaderListener);
+//       }
+//       if (
+//         prevTabListener &&
+//         chrome?.tabs?.onUpdated?.hasListener(prevTabListener)
+//       ) {
+//         console.log("removming on tab listener")
+//         chrome.tabs.onUpdated.removeListener(prevTabListener);
+//       }
+
+//       //if the result was positive, add the headerListener
+//       if (result) {
+//         console.log("headers on, disabled:", 
chrome?.webRequest?.onHeadersReceived === undefined)
+//         if (chrome?.webRequest) {
+//           chrome.webRequest.onHeadersReceived.addListener(headerListener,
+//             { urls: ["<all_urls>"] },
+//             ["responseHeaders", "extraHeaders"]
+//           );
+//           // chrome.webRequest.onCompleted.addListener(headerListener,
+//           //   { urls: ["<all_urls>"] },
+//           //   ["responseHeaders", "extraHeaders"]
+//           // );
+//           // chrome.webRequest.onResponseStarted.addListener(headerListener,
+//           //   { urls: ["<all_urls>"] },
+//           //   ["responseHeaders", "extraHeaders"]
+//           // );
+//           // chrome.webRequest.onErrorOccurred.addListener(headerListener,
+//           //   { urls: ["<all_urls>"] },
+//           //   ["extraHeaders"]
+//           // );
+//           currentHeaderListener = headerListener;
+//         }
+
+//         const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined =
+//           chrome?.tabs?.onUpdated;
+//         if (tabsEvent) {
+//           tabsEvent.addListener(tabListener);
+//           currentTabListener = tabListener;
+//         }
+//       } else {
+//         console.log("headers off")
+//       }
+
+//       //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 218422ded..02d11566a 100644
--- a/packages/taler-wallet-webextension/src/platform/dev.ts
+++ b/packages/taler-wallet-webextension/src/platform/dev.ts
@@ -44,8 +44,10 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
     removeClipboardPermissions: async () => false,
     requestClipboardPermissions: async () => false,
   }),
-  registerTalerHeaderListener: () => false,
-  containsTalerHeaderListener: () => false,
+
+  // registerDeclarativeRedirect: () => false,
+  // registerTalerHeaderListener: () => false,
+  // containsTalerHeaderListener: () => false,
   getWalletWebExVersion: () => ({
     version: "none",
   }),
@@ -88,7 +90,6 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
   redirectTabToWalletPage: (tabId: number, page: string) => {
     alert("redirectTabToWalletPage not implemented yet");
   },
-
   registerAllIncomingConnections: () => undefined,
   registerOnInstalled: () => Promise.resolve(),
   registerReloadOnNewVersion: () => undefined,
diff --git a/packages/taler-wallet-webextension/src/platform/firefox.ts 
b/packages/taler-wallet-webextension/src/platform/firefox.ts
index cc734ebf7..cca2833ad 100644
--- a/packages/taler-wallet-webextension/src/platform/firefox.ts
+++ b/packages/taler-wallet-webextension/src/platform/firefox.ts
@@ -26,9 +26,9 @@ import chromePlatform, {
   containsClipboardPermissions as chromeClipContains,
   removeClipboardPermissions as chromeClipRemove,
   requestClipboardPermissions as chromeClipRequest,
-  containsHostPermissions as chromeHostContains,
-  requestHostPermissions as chromeHostRequest,
-  removeHostPermissions as chromeHostRemove,
+  // containsHostPermissions as chromeHostContains,
+  // requestHostPermissions as chromeHostRequest,
+  // removeHostPermissions as chromeHostRemove,
 } from "./chrome.js";
 
 const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
@@ -54,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/taler-wallet-interaction-loader.ts 
b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts
index 8ea071fb6..10b1f521b 100644
--- a/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts
+++ b/packages/taler-wallet-webextension/src/taler-wallet-interaction-loader.ts
@@ -46,54 +46,86 @@ const suffixIsNotXMLorPDF =
 const rootElementIsHTML =
   document.documentElement.nodeName &&
   document.documentElement.nodeName.toLowerCase() === "html";
-const pageAcceptsTalerSupport = document.head.querySelector(
-  "meta[name=taler-support]",
-);
+
+/**
+ * Listen to any HTML Element and react to it.
+ *  - <meta name="taler-suport" /> will inject taler-support-lib
+ *  - <meta name="taler-uri" /> will redirect to call to action
+ */
+function listenToHeaderMutation() {
+  new MutationObserver(async function (mutations) {
+    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)
+            }
+          }
+        });
+      }
+    });
+  }).observe(document, {
+    childList: true,
+    subtree: true,
+    attributes: false,
+  })
+}
+
+function validateTalerUri(uri: string): boolean {
+  return (
+    !!uri && (uri.startsWith("taler://") || uri.startsWith("taler+http://";))
+  );
+}
+
+function convertURIToWebExtensionPath(uri: string) {
+  const url = new URL(
+    
chrome.runtime.getURL(`static/wallet.html#/taler-uri/${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 || FIXME: removing this before release for 
testing
   !rootElementIsHTML;
+
 const logger = {
-  debug: (...msg: any[]) => {},
+  debug: (...msg: any[]) => { },
   info: (...msg: any[]) =>
     console.log(`${new Date().toISOString()} TALER`, ...msg),
   error: (...msg: any[]) =>
     console.error(`${new Date().toISOString()} TALER`, ...msg),
 };
 
-async function start() {
-  if (shouldNotInject) {
-    return;
-  }
-  const debugEnabled =
-    pageAcceptsTalerSupport?.getAttribute("debug") === "true";
-  if (debugEnabled) {
-    logger.debug = logger.info;
-  }
-  createBridgeWithExtension();
-  logger.debug("bridged created");
+// logger.debug = logger.info
 
-  const shouldInject = await callBackground("isInjectionEnabled", undefined);
+/**
+ */
+function redirectToTalerActionHandler(element: HTMLMetaElement) {
+  const uri = element.getAttribute("content");
+  if (!uri) return;
 
-  if (shouldInject) {
-    injectTalerSupportScript(debugEnabled);
-    logger.debug("injection completed");
-  } else {
-    logger.debug("injection is not enabled");
+  if (!validateTalerUri(uri)) {
+    logger.error(`taler:// URI is invalid: ${uri}`);
+    return;
   }
+
+  location.href = convertURIToWebExtensionPath(uri)
 }
 
-/**
- * Create a <script /> element that load the support in the page context.
- * The interaction support script will create the API to send message
- * that will be received by this loader and be redirected to the extension
- * using the bridge.
- */
-function injectTalerSupportScript(debugEnabled: boolean) {
-  const container = document.head || document.documentElement;
+function injectTalerSupportScript(head: HTMLHeadElement) {
+  const meta = head.querySelector("meta[name=taler-support]")
+
+  const debugEnabled = meta?.getAttribute("debug") === "true";
+
   const scriptTag = document.createElement("script");
 
   scriptTag.setAttribute("async", "false");
@@ -105,12 +137,17 @@ function injectTalerSupportScript(debugEnabled: boolean) {
     url.searchParams.set("debug", "true");
   }
   scriptTag.src = url.href;
-  try {
-    container.insertBefore(scriptTag, container.children[0]);
-  } catch (e) {
-    logger.info("inserting link handler failed!");
-    logger.error(e);
-  }
+
+  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);
+    }
+  });
 }
 
 /**
@@ -146,6 +183,10 @@ export interface ExtensionOperations {
     request: void;
     response: boolean;
   };
+  isAutoOpenEnabled: {
+    request: void;
+    response: boolean;
+  };
 }
 
 export type MessageFromExtension<Op extends keyof ExtensionOperations> = {
@@ -201,4 +242,11 @@ async function sendMessageToBackground<Op extends keyof 
ExtensionOperations>(
   });
 }
 
+function start() {
+  if (shouldNotInject) return;
+  listenToHeaderMutation();
+  createBridgeWithExtension();
+  logger.debug("bridged created");
+}
+
 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
index 34687306b..33c2bc249 100644
--- a/packages/taler-wallet-webextension/src/taler-wallet-interaction-support.ts
+++ b/packages/taler-wallet-webextension/src/taler-wallet-interaction-support.ts
@@ -22,7 +22,7 @@
  */
 
 const logger = {
-  debug: (...msg: any[]) => {},
+  debug: (...msg: any[]) => { },
   info: (...msg: any[]) =>
     console.log(`${new Date().toISOString()} TALER`, ...msg),
   error: (...msg: any[]) =>
@@ -103,11 +103,6 @@ function buildApi(config: Readonly<Info>): API {
     ev.preventDefault();
     ev.stopPropagation();
     ev.stopImmediatePropagation();
-    // another possibility is to change the location when the click is made
-    // or when the anchor is found
-    // hrefAttr.value = page
-    // TODO: explore different possibilities and maybe allow the configuration
-    // using the meta-tag
     return false;
   }
 
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx 
b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 2319fe30a..b27413a96 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -73,10 +73,10 @@ export function SettingsPage(): VNode {
       deviceName={name}
       setDeviceName={update}
       autoOpenToggle={{
-        value: settings.autoOpenByHeader,
+        value: settings.autoOpen,
         button: {
           onClick: safely("update support injection", async () => {
-            updateSettings("autoOpenByHeader", !settings.autoOpenByHeader);
+            updateSettings("autoOpen", !settings.autoOpen);
           }),
         },
       }}
@@ -217,23 +217,6 @@ 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 :
@@ -305,6 +288,17 @@ export function SettingsView({
           enabled={injectTalerToggle.value!}
           onToggle={injectTalerToggle.button.onClick!}
         />
+        <Checkbox
+          label={i18n.str`Automatically open wallet`}
+          name="autoOpen"
+          description={
+            <i18n.Translate>
+              Open the wallet when a payment action is found.
+            </i18n.Translate>
+          }
+          enabled={autoOpenToggle.value!}
+          onToggle={autoOpenToggle.button.onClick!}
+        />
         <SubTitle>
           <i18n.Translate>Version</i18n.Translate>
         </SubTitle>
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index 8fb8211ae..9683bf34b 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -83,14 +83,14 @@ export interface BackgroundOperations {
     };
     response: void;
   };
-  containsHeaderListener: {
-    request: void;
-    response: ExtendedPermissionsResponse;
-  };
-  toggleHeaderListener: {
-    request: boolean;
-    response: ExtendedPermissionsResponse;
-  };
+  // 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 60b071716..f3d2375c5 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -27,18 +27,12 @@ import {
   LogLevel,
   Logger,
   TalerErrorCode,
-  WalletDiagnostics,
-  WalletNotification,
   getErrorDetailFromException,
   makeErrorDetail,
-  parseTalerUri,
   setGlobalLogLevelFromString,
-  setLogLevelFromString,
+  setLogLevelFromString
 } from "@gnu-taler/taler-util";
-import {
-  ServiceWorkerHttpLib,
-  BrowserHttpLib,
-} from "@gnu-taler/web-util/browser";
+import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
 import {
   DbAccess,
   OpenedPromise,
@@ -52,11 +46,14 @@ import {
   importDb,
   openPromise,
 } from "@gnu-taler/taler-wallet-core";
+import {
+  BrowserHttpLib,
+  ServiceWorkerHttpLib,
+} from "@gnu-taler/web-util/browser";
 import { MessageFromFrontend, MessageResponse } from "./platform/api.js";
 import { platform } from "./platform/background.js";
 import { ExtensionOperations } from "./taler-wallet-interaction-loader.js";
-import { BackgroundOperations, ExtendedPermissionsResponse } from "./wxApi.js";
-import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
+import { BackgroundOperations } from "./wxApi.js";
 
 /**
  * Currently active wallet instance.  Might be unloaded and
@@ -126,6 +123,7 @@ async function sum(ns: Array<number>): Promise<number> {
 
 const extensionHandlers: ExtensionHandlerType = {
   isInjectionEnabled,
+  isAutoOpenEnabled,
 };
 
 async function isInjectionEnabled(): Promise<boolean> {
@@ -133,9 +131,9 @@ async function isInjectionEnabled(): Promise<boolean> {
   return settings.injectTalerSupport === true;
 }
 
-async function isHeaderListenerEnabled(): Promise<boolean> {
+async function isAutoOpenEnabled(): Promise<boolean> {
   const settings = await platform.getSettingsFromStorage();
-  return settings.autoOpenByHeader === true;
+  return settings.autoOpen === true;
 }
 
 const backendHandlers: BackendHandlerType = {
@@ -144,14 +142,12 @@ const backendHandlers: BackendHandlerType = {
   resetDb,
   runGarbageCollector,
   setLoggingLevel,
-  containsHeaderListener,
-  toggleHeaderListener,
 };
 
-async function containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
-  const result = await platform.containsTalerHeaderListener();
-  return { newValue: result };
-}
+// async function containsHeaderListener(): 
Promise<ExtendedPermissionsResponse> {
+//   const result = await platform.containsTalerHeaderListener();
+//   return { newValue: result };
+// }
 
 async function setLoggingLevel({
   tag,
@@ -353,45 +349,55 @@ 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();
-  });
 
-  if (await isHeaderListenerEnabled()) {
-    if (await platform.getPermissionsApi().containsHostPermissions()) {
-      try {
-        platform.registerTalerHeaderListener();
-      } catch (e) {
-        logger.error("could not register header listener", e);
-      }
-    } else {
-      await platform.getPermissionsApi().requestHostPermissions()
-    }
-  }
+  // platform.registerDeclarativeRedirect();
+  // if (false) {
+  /**
+   * this is not working reliable on chrome, just
+   * intercepts queries after the user clicks the popups
+   * which doesn't make sense, keeping it to make more tests 
+   */
+
+  // if (await isHeaderListenerEnabled()) {
+  //   if (await platform.getPermissionsApi().containsHostPermissions()) {
+  //     try {
+  //       platform.registerTalerHeaderListener();
+  //     } catch (e) {
+  //       logger.error("could not register header listener", e);
+  //     }
+  //   } else {
+  //     await platform.getPermissionsApi().requestHostPermissions()
+  //   }
+  // }
 
+  // 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();
+  // });
+
+  // }
 }
 
 
-async function toggleHeaderListener(
-  newVal: boolean,
-): Promise<ExtendedPermissionsResponse> {
-  logger.trace("new extended permissions value", newVal);
-  if (newVal) {
-    platform.registerTalerHeaderListener();
-    return { newValue: true };
-  }
+// async function toggleHeaderListener(
+//   newVal: boolean,
+// ): Promise<ExtendedPermissionsResponse> {
+//   logger.trace("new extended permissions value", newVal);
+//   if (newVal) {
+//     platform.registerTalerHeaderListener();
+//     return { newValue: true };
+//   }
 
-  const rem = await platform.getPermissionsApi().removeHostPermissions();
-  logger.trace("permissions removed:", rem);
-  return { newValue: false };
-}
+//   const rem = await platform.getPermissionsApi().removeHostPermissions();
+//   logger.trace("permissions removed:", rem);
+//   return { newValue: false };
+// }

-- 
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]