gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (fb4c172bb -> d95357381)


From: gnunet
Subject: [taler-wallet-core] branch master updated (fb4c172bb -> d95357381)
Date: Mon, 30 Oct 2023 23:23:52 +0100

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

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

    from fb4c172bb remove metric from admin panel and better way to find 
harness testing user
     new f1967ab0b testing auto open feature
     new d95357381 add the account-not-found case when doing a transaction

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../demobank-ui/src/pages/OperationState/views.tsx |   62 +-
 .../src/pages/PaytoWireTransferForm.tsx            |    7 +
 packages/demobank-ui/src/pages/QrCodeSection.tsx   |    6 +-
 .../demobank-ui/src/pages/WalletWithdrawForm.tsx   |   11 +-
 .../taler-harness/src/http-client/bank-core.ts     | 1006 ++++++++++----------
 packages/taler-util/src/http-client/bank-core.ts   |    2 +
 packages/taler-util/src/operation.ts               |    2 +-
 .../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 +--
 18 files changed, 1017 insertions(+), 902 deletions(-)

diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx 
b/packages/demobank-ui/src/pages/OperationState/views.tsx
index b7d7e5520..ea38525b9 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)
       }
     })
@@ -338,6 +338,12 @@ export function FailedView({ error }: State.Failed) {
         {error.detail.hint}
       </div>
     </Attention>
+    case "account-not-found": return <Attention type="danger"
+      title={i18n.str`The operation was rejected due to insufficient funds.`}>
+      <div class="mt-2 text-sm text-red-700">
+        {error.detail.hint}
+      </div>
+    </Attention>
     default: assertUnreachable(error)
   }
 }
@@ -408,6 +414,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 +422,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 +457,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/PaytoWireTransferForm.tsx 
b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
index 6649d224e..97e38d75e 100644
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
+++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
@@ -122,6 +122,7 @@ export function PaytoWireTransferForm({
   async function doSend() {
     let payto_uri: PaytoString | undefined;
     let sendingAmount: AmountString | undefined;
+
     if (credentials.status !== "loggedIn") return;
     if (rawPaytoInput) {
       const p = parsePaytoUri(rawPaytoInput)
@@ -159,6 +160,12 @@ export function PaytoWireTransferForm({
             description: res.detail.hint as TranslatedString,
             debug: res.detail,
           })
+          case "account-not-found": return notify({
+            type: "error",
+            title: i18n.str`The destination account "${puri}" was not found.`,
+            description: res.detail.hint as TranslatedString,
+            debug: res.detail,
+          })
           default: assertUnreachable(res)
         }
       }
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/demobank-ui/src/pages/WalletWithdrawForm.tsx 
b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
index abdebf9bf..e3a713fdd 100644
--- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
+++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
@@ -121,6 +121,15 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, 
onCancel, focus }: {
             })
             break;
           }
+          case "account-not-found": {
+            notify({
+              type: "error",
+              title: i18n.str`Account not found`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            break;
+          }
           default: assertUnreachable(resp)
         }
       }
@@ -135,7 +144,7 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, 
onCancel, focus }: {
       e.preventDefault()
     }}
   >
-              <ShowLocalNotification notification={notification} />
+    <ShowLocalNotification notification={notification} />
 
     <div class="px-4 py-6 ">
       <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
diff --git a/packages/taler-harness/src/http-client/bank-core.ts 
b/packages/taler-harness/src/http-client/bank-core.ts
index 25e67b031..6f9641dc9 100644
--- a/packages/taler-harness/src/http-client/bank-core.ts
+++ b/packages/taler-harness/src/http-client/bank-core.ts
@@ -1,530 +1,540 @@
-import { AccessToken, Amounts, TalerCoreBankHttpClient, TalerCorebankApi, 
encodeCrock, failOrThrow, getRandomBytes, parsePaytoUri, stringifyPaytoUri, 
succeedOrThrow } from "@gnu-taler/taler-util"
+import { AccessToken, Amounts, TalerCoreBankHttpClient, TalerCorebankApi, 
buildPayto, encodeCrock, failOrThrow, getRandomBytes, parsePaytoUri, 
stringifyPaytoUri, succeedOrThrow } from "@gnu-taler/taler-util"
 
 export class BankCoreSmokeTest {
-  constructor(readonly api:TalerCoreBankHttpClient) {
+  constructor(readonly api: TalerCoreBankHttpClient) {
 
   }
 
-async testConfig() {
-  const config = await this.api.getConfig()
-  if (!this.api.isCompatible(config.body.version)) {
-    throw Error(`not compatible with server ${config.body.version}`)
+  async testConfig() {
+    const config = await this.api.getConfig()
+    if (!this.api.isCompatible(config.body.version)) {
+      throw Error(`not compatible with server ${config.body.version}`)
+    }
+    return config.body
   }
-  return config.body
-}
-
-async testCashouts(adminPassword: string) {
-}
-async testMonitor(adminPassword: string) {
-  const { access_token: adminToken } = await succeedOrThrow(() =>
-    this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
-      scope: "readwrite"
-    })
-  )
-
-  await succeedOrThrow(() => (
-    this.api.getMonitor()
-  ))
-
-  await succeedOrThrow(() => (
-    this.api.getMonitor({
-      timeframe: TalerCorebankApi.MonitorTimeframeParam.day,
-      which: (new Date()).getDate() -1
-    })
-  ))
-}
-
-async testAccountManagement(adminPassword: string) {
-
-  const { access_token: adminToken } = await succeedOrThrow(() =>
-    this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
-      scope: "readwrite"
-    })
-  )
-
-  /**
-   * Create account
-  */
-  {
-    const username = "harness-" + 
encodeCrock(getRandomBytes(10)).toLowerCase();
-
-    // await failOrThrow("invalid-input",() =>
-    //   this.api.createAccount(adminToken, {
-    //     name: username,
-    //     username, password: "123",
-    //     challenge_contact_data: {
-    //       email: "invalid email",
-    //       phone: "invalid phone",
-    //     }
-    //   })
-    // )
-
-    // await failOrThrow("unable-to-create",() =>
-    //   this.api.createAccount(adminToken, {
-    //     name: "admin",
-    //     username, password: "123"
-    //   })
-    // )
-
-    // await failOrThrow("unable-to-create",() =>
-    //   this.api.createAccount(adminToken, {
-    //     name: "bank",
-    //     username, password: "123"
-    //   })
-    // )
-
-    await succeedOrThrow(() =>
-      this.api.createAccount(adminToken, {
-        name: username,
-        username, password: "123"
-      })
-    )
-
-    await failOrThrow("already-exist", () =>
-      this.api.createAccount(adminToken, {
-        name: username,
-        username, password: "123"
-      })
-    );
-  }
-
-  /**
-   * Delete account
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-
-    await failOrThrow("not-found", () =>
-      this.api.deleteAccount({ username: "not-found", token: adminToken })
-    )
-    await failOrThrow("unable-to-delete", () =>
-      this.api.deleteAccount({ username: "admin", token: adminToken })
-    )
-    await failOrThrow("unable-to-delete", () =>
-      this.api.deleteAccount({ username: "bank", token: adminToken })
-    )
-
-    await failOrThrow("balance-not-zero", () =>
-      this.api.deleteAccount({ username, token: adminToken })
-    )
-
-    const userInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username, token })
-    )
-
-    const adminInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username: "admin", token: adminToken })
-    )
-
-    const adminAccount = parsePaytoUri(adminInfo.payto_uri)!
-    adminAccount.params["message"] = "all my money"
-    const withSubject = stringifyPaytoUri(adminAccount)
-
-    await succeedOrThrow(() =>
-      this.api.createTransaction({ username, token }, {
-        payto_uri: withSubject,
-        amount: userInfo.balance.amount
-      })
-    )
-
-
-    const otherUsername = "harness-" + 
encodeCrock(getRandomBytes(10)).toLowerCase();
-
-    await succeedOrThrow(() =>
-      this.api.createAccount(adminToken, {
-        name: otherUsername,
-        username: otherUsername, password: "123"
-      })
-    )
-
-    await failOrThrow("unauthorized", () =>
-      this.api.deleteAccount({ username: otherUsername, token })
-    )
-
-    await succeedOrThrow(() =>
-      this.api.deleteAccount({ username, token: adminToken })
-    )
-  }
-
-  /**
-   * Update account
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-
-    await failOrThrow("cant-change-legal-name-or-admin", () =>
-      this.api.updateAccount({ username, token }, {
-        name: "something else",
-      })
-    )
-
-    // await failOrThrow("not-found", () =>
-    //   this.api.updateAccount({ username: "notfound", token }, {
-    //     challenge_contact_data: {
-    //       email: "asd@Aasd.com"
-    //     }
-    //   })
-    // )
-
-    await failOrThrow("unauthorized", () =>
-      this.api.updateAccount({ username: "notfound", token: "wrongtoken" as 
AccessToken }, {
-        challenge_contact_data: {
-          email: "asd@Aasd.com"
-        }
-      })
-    )
-
-    await succeedOrThrow(() =>
-      this.api.updateAccount({ username, token }, {
-        challenge_contact_data: {
-          email: "asd@Aasd.com"
-        }
-      })
-    )
-  }
-
-  /**
-   * Update password
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-
-    await succeedOrThrow(() =>
-      this.api.updatePassword({ username, token }, {
-        old_password: "123",
-        new_password: "234"
-      })
-    )
-    // await failOrThrow("not-found",() =>
-    //   this.api.updatePassword({ username:"notfound", token: userTempToken 
}, {
-    //     old_password: "123",
-    //     new_password: "234"
-    //   })
-    // )
-    await failOrThrow("unauthorized", () =>
-      this.api.updatePassword({ username: "admin", token }, {
-        old_password: "123",
-        new_password: "234"
-      })
-    )
-    // await failOrThrow("old-password-invalid-or-not-allowed",() =>
-    //   this.api.updatePassword({ username, token: userTempToken }, {
-    //     old_password: "123",
-    //     new_password: "234"
-    //   })
-    // )
-
-  }
-
-  /**
-   * public accounts
-   */
-  {
-    const acs = await succeedOrThrow(() => this.api.getPublicAccounts())
-
-  }
-  /**
-   * get accounts
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-    // await failOrThrow("no-rights",() => 
-    //   this.api.getAccounts(token)
-    // )
-    await failOrThrow("unauthorized", () =>
-      this.api.getAccounts("ASDASD" as AccessToken)
-    )
-
-    const acs = await succeedOrThrow(() =>
-      this.api.getAccounts(adminToken)
-    )
-  }
-
-}
-
-async testWithdrawals(adminPassword: string) {
-  const { access_token: adminToken } = await succeedOrThrow(() =>
-    this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
-      scope: "readwrite"
-    })
-  )
-  /**
-   * create withdrawals
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-
-    const userInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username, token })
-    )
-    
-    const balance = Amounts.parseOrThrow(userInfo.balance.amount)
-    const moreThanBalance = Amounts.stringify(Amounts.mult(balance, 5).amount)
-    await failOrThrow("insufficient-funds", () =>
-      this.api.createWithdrawal({ username, token }, {
-        amount: moreThanBalance
-      })
-    )
-
-    await failOrThrow("unauthorized", () =>
-      this.api.createWithdrawal({ username, token: "wrongtoken" as AccessToken 
}, {
-        amount: userInfo.balance.amount
-      })
-    )
 
-    await succeedOrThrow(() =>
-      this.api.createWithdrawal({ username, token }, {
-        amount: userInfo.balance.amount
-      })
-    )
+  async testCashouts(adminPassword: string) {
   }
-
-  /**
-   * get withdrawal
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-
-    const userInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username, token })
-    )
-
-    const { withdrawal_id } = await succeedOrThrow(() =>
-      this.api.createWithdrawal({ username, token }, {
-        amount: userInfo.balance.amount
+  async testMonitor(adminPassword: string) {
+    const { access_token: adminToken } = await succeedOrThrow(() =>
+      this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
+        scope: "readwrite"
       })
     )
 
-    await succeedOrThrow(() =>
-      this.api.getWithdrawalById(withdrawal_id)
-    )
-
-    await failOrThrow("invalid-id", () =>
-      this.api.getWithdrawalById("invalid")
-    )
-    await failOrThrow("not-found", () =>
-      this.api.getWithdrawalById("11111111-1111-1111-1111-111111111111")
-    )
-  }
-
-  /**
-   * abort withdrawal
-   */
-  {
-    const { username:exchangeUser, token: exchangeToken } = await 
createRandomTestUser(this.api, adminToken, {is_taler_exchange: true})
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+    await succeedOrThrow(() => (
+      this.api.getMonitor()
+    ))
 
-    const userInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username, token })
-    )
-    const exchangeInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username:exchangeUser, token:exchangeToken })
-    )
-
-    await failOrThrow("invalid-id", () =>
-      this.api.abortWithdrawalById("invalid")
-    )
-    await failOrThrow("not-found", () =>
-      this.api.abortWithdrawalById("11111111-1111-1111-1111-111111111111")
-    )
-
-    const { withdrawal_id:firstWithdrawal } = await succeedOrThrow(() =>
-      this.api.createWithdrawal({ username, token }, {
-        amount: userInfo.balance.amount
-      })
-    )
-
-    await succeedOrThrow(() =>
-      this.api.abortWithdrawalById(firstWithdrawal)
-    )
-
-    const { taler_withdraw_uri: uri, withdrawal_id:secondWithdrawal } = await 
succeedOrThrow(() =>
-      this.api.createWithdrawal({ username, token }, {
-        amount: userInfo.balance.amount
+    await succeedOrThrow(() => (
+      this.api.getMonitor({
+        timeframe: TalerCorebankApi.MonitorTimeframeParam.day,
+        which: (new Date()).getDate() - 1
       })
-    )
-
-    await succeedOrThrow(() =>
-      
this.api.getIntegrationAPI().completeWithdrawalOperationById(secondWithdrawal, {
-        reserve_pub: encodeCrock(getRandomBytes(32)),
-        selected_exchange: exchangeInfo.payto_uri,
-      })
-    )
-    await succeedOrThrow(() =>
-      this.api.confirmWithdrawalById(secondWithdrawal)
-    )
-    await failOrThrow("previously-confirmed", () =>
-      this.api.abortWithdrawalById(secondWithdrawal)
-    ) 
+    ))
   }
 
-  /**
-   * confirm withdrawal
-   */
-  {
-    const { username:exchangeUser, token: exchangeToken } = await 
createRandomTestUser(this.api, adminToken, {is_taler_exchange: true})
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-
-    const userInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username, token })
-    )
-    const exchangeInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username:exchangeUser, token:exchangeToken })
-    )
-
-    await failOrThrow("invalid-id", () =>
-      this.api.confirmWithdrawalById("invalid")
-    )
-    await failOrThrow("not-found", () =>
-      this.api.confirmWithdrawalById("11111111-1111-1111-1111-111111111111")
-    )
-
-    const { withdrawal_id:firstWithdrawal } = await succeedOrThrow(() =>
-      this.api.createWithdrawal({ username, token }, {
-        amount: userInfo.balance.amount
-      })
-    )
-
-    await failOrThrow("no-exchange-or-reserve-selected", () =>
-      this.api.confirmWithdrawalById(firstWithdrawal)
-    )
-
-    await succeedOrThrow(() =>
-      
this.api.getIntegrationAPI().completeWithdrawalOperationById(firstWithdrawal, {
-        reserve_pub: encodeCrock(getRandomBytes(32)),
-        selected_exchange: exchangeInfo.payto_uri,
-      })
-    )
-
-    await succeedOrThrow(() =>
-      this.api.confirmWithdrawalById(firstWithdrawal)
-    )
+  async testAccountManagement(adminPassword: string) {
 
-    const { withdrawal_id:secondWithdrawal } = await succeedOrThrow(() =>
-      this.api.createWithdrawal({ username, token }, {
-        amount: userInfo.balance.amount
+    const { access_token: adminToken } = await succeedOrThrow(() =>
+      this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
+        scope: "readwrite"
       })
     )
 
-    await succeedOrThrow(() =>
-      this.api.abortWithdrawalById(secondWithdrawal)
-    )
-    await failOrThrow("previously-aborted", () =>
-      this.api.confirmWithdrawalById(secondWithdrawal)
-    ) 
-  }
-}
+    /**
+     * Create account
+    */
+    {
+      const username = "harness-" + 
encodeCrock(getRandomBytes(10)).toLowerCase();
+
+      // await failOrThrow("invalid-input",() =>
+      //   this.api.createAccount(adminToken, {
+      //     name: username,
+      //     username, password: "123",
+      //     challenge_contact_data: {
+      //       email: "invalid email",
+      //       phone: "invalid phone",
+      //     }
+      //   })
+      // )
+
+      // await failOrThrow("unable-to-create",() =>
+      //   this.api.createAccount(adminToken, {
+      //     name: "admin",
+      //     username, password: "123"
+      //   })
+      // )
+
+      // await failOrThrow("unable-to-create",() =>
+      //   this.api.createAccount(adminToken, {
+      //     name: "bank",
+      //     username, password: "123"
+      //   })
+      // )
+
+      await succeedOrThrow(() =>
+        this.api.createAccount(adminToken, {
+          name: username,
+          username, password: "123"
+        })
+      )
+
+      await failOrThrow("already-exist", () =>
+        this.api.createAccount(adminToken, {
+          name: username,
+          username, password: "123"
+        })
+      );
+    }
+
+    /**
+     * Delete account
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+
+      await failOrThrow("not-found", () =>
+        this.api.deleteAccount({ username: "not-found", token: adminToken })
+      )
+      await failOrThrow("unable-to-delete", () =>
+        this.api.deleteAccount({ username: "admin", token: adminToken })
+      )
+      await failOrThrow("unable-to-delete", () =>
+        this.api.deleteAccount({ username: "bank", token: adminToken })
+      )
+
+      await failOrThrow("balance-not-zero", () =>
+        this.api.deleteAccount({ username, token: adminToken })
+      )
+
+      const userInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username, token })
+      )
+
+      const adminInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username: "admin", token: adminToken })
+      )
+
+      const adminAccount = parsePaytoUri(adminInfo.payto_uri)!
+      adminAccount.params["message"] = "all my money"
+      const withSubject = stringifyPaytoUri(adminAccount)
+
+      await succeedOrThrow(() =>
+        this.api.createTransaction({ username, token }, {
+          payto_uri: withSubject,
+          amount: userInfo.balance.amount
+        })
+      )
+
+
+      const otherUsername = "harness-" + 
encodeCrock(getRandomBytes(10)).toLowerCase();
+
+      await succeedOrThrow(() =>
+        this.api.createAccount(adminToken, {
+          name: otherUsername,
+          username: otherUsername, password: "123"
+        })
+      )
+
+      await failOrThrow("unauthorized", () =>
+        this.api.deleteAccount({ username: otherUsername, token })
+      )
+
+      await succeedOrThrow(() =>
+        this.api.deleteAccount({ username, token: adminToken })
+      )
+    }
+
+    /**
+     * Update account
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+
+      await failOrThrow("cant-change-legal-name-or-admin", () =>
+        this.api.updateAccount({ username, token }, {
+          name: "something else",
+        })
+      )
+
+      // await failOrThrow("not-found", () =>
+      //   this.api.updateAccount({ username: "notfound", token }, {
+      //     challenge_contact_data: {
+      //       email: "asd@Aasd.com"
+      //     }
+      //   })
+      // )
+
+      await failOrThrow("unauthorized", () =>
+        this.api.updateAccount({ username: "notfound", token: "wrongtoken" as 
AccessToken }, {
+          challenge_contact_data: {
+            email: "asd@Aasd.com"
+          }
+        })
+      )
+
+      await succeedOrThrow(() =>
+        this.api.updateAccount({ username, token }, {
+          challenge_contact_data: {
+            email: "asd@Aasd.com"
+          }
+        })
+      )
+    }
+
+    /**
+     * Update password
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+
+      await succeedOrThrow(() =>
+        this.api.updatePassword({ username, token }, {
+          old_password: "123",
+          new_password: "234"
+        })
+      )
+      // await failOrThrow("not-found",() =>
+      //   this.api.updatePassword({ username:"notfound", token: userTempToken 
}, {
+      //     old_password: "123",
+      //     new_password: "234"
+      //   })
+      // )
+      await failOrThrow("unauthorized", () =>
+        this.api.updatePassword({ username: "admin", token }, {
+          old_password: "123",
+          new_password: "234"
+        })
+      )
+      // await failOrThrow("old-password-invalid-or-not-allowed",() =>
+      //   this.api.updatePassword({ username, token: userTempToken }, {
+      //     old_password: "123",
+      //     new_password: "234"
+      //   })
+      // )
+
+    }
+
+    /**
+     * public accounts
+     */
+    {
+      const acs = await succeedOrThrow(() => this.api.getPublicAccounts())
+
+    }
+    /**
+     * get accounts
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+      // await failOrThrow("no-rights",() => 
+      //   this.api.getAccounts(token)
+      // )
+      await failOrThrow("unauthorized", () =>
+        this.api.getAccounts("ASDASD" as AccessToken)
+      )
+
+      const acs = await succeedOrThrow(() =>
+        this.api.getAccounts(adminToken)
+      )
+    }
 
-async testTransactions(adminPassword: string) {
-  const { access_token: adminToken } = await succeedOrThrow(() =>
-    this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
-      scope: "readwrite"
-    })
-  )
-  // get transactions
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-    // await succeedOrThrow(() => this.api.getTransactions(creds))
-    const txs = await succeedOrThrow(() => this.api.getTransactions({ 
username, token }, {
-      limit: 5,
-      order: "asc"
-    }))
-    // await failOrThrow("not-found",() => this.api.getTransactions({
-    //   username:"not-found",
-    //   token: creds.token,
-    // }))
-    await failOrThrow("unauthorized", () => this.api.getTransactions({
-      username: username,
-      token: "wrongtoken" as AccessToken,
-    }))
   }
 
-  /**
-   * getTxby id
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-    const { username: otherUser, token: otherToken } = await 
createRandomTestUser(this.api, adminToken)
-
-    const userInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username, token })
-    )
-    const otherInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username: otherUser, token: otherToken })
-    )
-    const otherAccount = parsePaytoUri(otherInfo.payto_uri)!
-    otherAccount.params["message"] = "all"
-
-    await succeedOrThrow(() =>
-      this.api.createTransaction({ username, token }, {
-        payto_uri: stringifyPaytoUri(otherAccount),
-        amount: userInfo.balance.amount
+  async testWithdrawals(adminPassword: string) {
+    const { access_token: adminToken } = await succeedOrThrow(() =>
+      this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
+        scope: "readwrite"
       })
     )
-
-    const txs = await succeedOrThrow(() => this.api.getTransactions({ 
username, token }, {
-      limit: 5,
-      order: "asc"
-    }))
-    const rowId = txs.transactions[0].row_id
-
-    await succeedOrThrow(() =>
-      this.api.getTransactionById({ username, token }, rowId)
-    )
-
-    await failOrThrow("not-found", () =>
-      this.api.getTransactionById({ username, token }, 123123123)
-    )
-
-    await failOrThrow("unauthorized", () =>
-      this.api.getTransactionById({ username, token: "wrongtoken" as 
AccessToken }, 123123123)
-    )
+    /**
+     * create withdrawals
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+
+      const userInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username, token })
+      )
+
+      const balance = Amounts.parseOrThrow(userInfo.balance.amount)
+      const moreThanBalance = Amounts.stringify(Amounts.mult(balance, 
5).amount)
+      await failOrThrow("insufficient-funds", () =>
+        this.api.createWithdrawal({ username, token }, {
+          amount: moreThanBalance
+        })
+      )
+
+      await failOrThrow("unauthorized", () =>
+        this.api.createWithdrawal({ username, token: "wrongtoken" as 
AccessToken }, {
+          amount: userInfo.balance.amount
+        })
+      )
+
+      await succeedOrThrow(() =>
+        this.api.createWithdrawal({ username, token }, {
+          amount: userInfo.balance.amount
+        })
+      )
+    }
+
+    /**
+     * get withdrawal
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+
+      const userInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username, token })
+      )
+
+      const { withdrawal_id } = await succeedOrThrow(() =>
+        this.api.createWithdrawal({ username, token }, {
+          amount: userInfo.balance.amount
+        })
+      )
+
+      await succeedOrThrow(() =>
+        this.api.getWithdrawalById(withdrawal_id)
+      )
+
+      await failOrThrow("invalid-id", () =>
+        this.api.getWithdrawalById("invalid")
+      )
+      await failOrThrow("not-found", () =>
+        this.api.getWithdrawalById("11111111-1111-1111-1111-111111111111")
+      )
+    }
+
+    /**
+     * abort withdrawal
+     */
+    {
+      const { username: exchangeUser, token: exchangeToken } = await 
createRandomTestUser(this.api, adminToken, { is_taler_exchange: true })
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+
+      const userInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username, token })
+      )
+      const exchangeInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username: exchangeUser, token: exchangeToken })
+      )
+
+      await failOrThrow("invalid-id", () =>
+        this.api.abortWithdrawalById("invalid")
+      )
+      await failOrThrow("not-found", () =>
+        this.api.abortWithdrawalById("11111111-1111-1111-1111-111111111111")
+      )
+
+      const { withdrawal_id: firstWithdrawal } = await succeedOrThrow(() =>
+        this.api.createWithdrawal({ username, token }, {
+          amount: userInfo.balance.amount
+        })
+      )
+
+      await succeedOrThrow(() =>
+        this.api.abortWithdrawalById(firstWithdrawal)
+      )
+
+      const { taler_withdraw_uri: uri, withdrawal_id: secondWithdrawal } = 
await succeedOrThrow(() =>
+        this.api.createWithdrawal({ username, token }, {
+          amount: userInfo.balance.amount
+        })
+      )
+
+      await succeedOrThrow(() =>
+        
this.api.getIntegrationAPI().completeWithdrawalOperationById(secondWithdrawal, {
+          reserve_pub: encodeCrock(getRandomBytes(32)),
+          selected_exchange: exchangeInfo.payto_uri,
+        })
+      )
+      await succeedOrThrow(() =>
+        this.api.confirmWithdrawalById(secondWithdrawal)
+      )
+      await failOrThrow("previously-confirmed", () =>
+        this.api.abortWithdrawalById(secondWithdrawal)
+      )
+    }
+
+    /**
+     * confirm withdrawal
+     */
+    {
+      const { username: exchangeUser, token: exchangeToken } = await 
createRandomTestUser(this.api, adminToken, { is_taler_exchange: true })
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+
+      const userInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username, token })
+      )
+      const exchangeInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username: exchangeUser, token: exchangeToken })
+      )
+
+      await failOrThrow("invalid-id", () =>
+        this.api.confirmWithdrawalById("invalid")
+      )
+      await failOrThrow("not-found", () =>
+        this.api.confirmWithdrawalById("11111111-1111-1111-1111-111111111111")
+      )
+
+      const { withdrawal_id: firstWithdrawal } = await succeedOrThrow(() =>
+        this.api.createWithdrawal({ username, token }, {
+          amount: userInfo.balance.amount
+        })
+      )
+
+      await failOrThrow("no-exchange-or-reserve-selected", () =>
+        this.api.confirmWithdrawalById(firstWithdrawal)
+      )
+
+      await succeedOrThrow(() =>
+        
this.api.getIntegrationAPI().completeWithdrawalOperationById(firstWithdrawal, {
+          reserve_pub: encodeCrock(getRandomBytes(32)),
+          selected_exchange: exchangeInfo.payto_uri,
+        })
+      )
+
+      await succeedOrThrow(() =>
+        this.api.confirmWithdrawalById(firstWithdrawal)
+      )
+
+      const { withdrawal_id: secondWithdrawal } = await succeedOrThrow(() =>
+        this.api.createWithdrawal({ username, token }, {
+          amount: userInfo.balance.amount
+        })
+      )
+
+      await succeedOrThrow(() =>
+        this.api.abortWithdrawalById(secondWithdrawal)
+      )
+      //FIXME: skip
+      // await failOrThrow("previously-aborted", () =>
+      //   this.api.confirmWithdrawalById(secondWithdrawal)
+      // )
+    }
   }
 
-  /**
-   * create transactions
-   */
-  {
-    const { username, token } = await createRandomTestUser(this.api, 
adminToken)
-    const { username: otherUser, token: otherToken } = await 
createRandomTestUser(this.api, adminToken)
-
-    const userInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username, token })
-    )
-    const otherInfo = await succeedOrThrow(() =>
-      this.api.getAccount({ username: otherUser, token: otherToken })
-    )
-    const otherAccount = parsePaytoUri(otherInfo.payto_uri)!
-    otherAccount.params["message"] = "all"
-
-    await succeedOrThrow(() =>
-      this.api.createTransaction({ username, token }, {
-        payto_uri: stringifyPaytoUri(otherAccount),
-        amount: userInfo.balance.amount
-      })
-    )
-    //missing amount
-    await failOrThrow("invalid-input", () =>
-      this.api.createTransaction({ username, token }, {
-        payto_uri: stringifyPaytoUri(otherAccount),
-        // amount: userInfo.balance.amount
-      })
-    )
-    //missing subject
-    await failOrThrow("invalid-input", () =>
-      this.api.createTransaction({ username, token }, {
-        payto_uri: otherInfo.payto_uri,
-        amount: userInfo.balance.amount
-      })
-    )
-    await failOrThrow("unauthorized", () =>
-      this.api.createTransaction({ username, token: "wrongtoken" as 
AccessToken }, {
-        payto_uri: otherInfo.payto_uri,
-        amount: userInfo.balance.amount
+  async testTransactions(adminPassword: string) {
+    const { access_token: adminToken } = await succeedOrThrow(() =>
+      this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, {
+        scope: "readwrite"
       })
     )
+    // get transactions
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+      // await succeedOrThrow(() => this.api.getTransactions(creds))
+      const txs = await succeedOrThrow(() => this.api.getTransactions({ 
username, token }, {
+        limit: 5,
+        order: "asc"
+      }))
+      // await failOrThrow("not-found",() => this.api.getTransactions({
+      //   username:"not-found",
+      //   token: creds.token,
+      // }))
+      await failOrThrow("unauthorized", () => this.api.getTransactions({
+        username: username,
+        token: "wrongtoken" as AccessToken,
+      }))
+    }
+
+    /**
+     * getTxby id
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+      const { username: otherUser, token: otherToken } = await 
createRandomTestUser(this.api, adminToken)
+
+      const userInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username, token })
+      )
+      const otherInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username: otherUser, token: otherToken })
+      )
+      const otherAccount = parsePaytoUri(otherInfo.payto_uri)!
+      otherAccount.params["message"] = "all"
+
+      await succeedOrThrow(() =>
+        this.api.createTransaction({ username, token }, {
+          payto_uri: stringifyPaytoUri(otherAccount),
+          amount: userInfo.balance.amount
+        })
+      )
+
+      const txs = await succeedOrThrow(() => this.api.getTransactions({ 
username, token }, {
+        limit: 5,
+        order: "asc"
+      }))
+      const rowId = txs.transactions[0].row_id
+
+      await succeedOrThrow(() =>
+        this.api.getTransactionById({ username, token }, rowId)
+      )
+
+      await failOrThrow("not-found", () =>
+        this.api.getTransactionById({ username, token }, 123123123)
+      )
+
+      await failOrThrow("unauthorized", () =>
+        this.api.getTransactionById({ username, token: "wrongtoken" as 
AccessToken }, 123123123)
+      )
+    }
+
+    /**
+     * create transactions
+     */
+    {
+      const { username, token } = await createRandomTestUser(this.api, 
adminToken)
+      const { username: otherUser, token: otherToken } = await 
createRandomTestUser(this.api, adminToken)
+
+      const userInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username, token })
+      )
+      const otherInfo = await succeedOrThrow(() =>
+        this.api.getAccount({ username: otherUser, token: otherToken })
+      )
+      const otherAccount = parsePaytoUri(otherInfo.payto_uri)!
+      otherAccount.params["message"] = "all"
+
+      await succeedOrThrow(() =>
+        this.api.createTransaction({ username, token }, {
+          payto_uri: stringifyPaytoUri(otherAccount),
+          amount: userInfo.balance.amount
+        })
+      )
+      //missing amount
+      await failOrThrow("invalid-input", () =>
+        this.api.createTransaction({ username, token }, {
+          payto_uri: stringifyPaytoUri(otherAccount),
+          // amount: userInfo.balance.amount
+        })
+      )
+      //missing subject
+      await failOrThrow("invalid-input", () =>
+        this.api.createTransaction({ username, token }, {
+          payto_uri: otherInfo.payto_uri,
+          amount: userInfo.balance.amount
+        })
+      )
+      await failOrThrow("unauthorized", () =>
+        this.api.createTransaction({ username, token: "wrongtoken" as 
AccessToken }, {
+          payto_uri: otherInfo.payto_uri,
+          amount: userInfo.balance.amount
+        })
+      )
+
+      const notFoundAccount = buildPayto("iban", "DE1231231231", undefined)
+      notFoundAccount.params["message"] = "not-found"
+      await failOrThrow("account-not-found", () =>
+        this.api.createTransaction({ username, token }, {
+          payto_uri: stringifyPaytoUri(notFoundAccount),
+          amount: userInfo.balance.amount
+        })
+      )
+    }
   }
-}
 
 
 }
diff --git a/packages/taler-util/src/http-client/bank-core.ts 
b/packages/taler-util/src/http-client/bank-core.ts
index e214f6dcd..35f216220 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -316,6 +316,7 @@ export class TalerCoreBankHttpClient {
       //FIXME: remove this after server has been updated 
       case HttpStatusCode.Ok: return opEmptySuccess()
       case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp);
       //FIXME: check when the server add codes spec
       case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
       case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
@@ -344,6 +345,7 @@ export class TalerCoreBankHttpClient {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountCreateWithdrawalResponse())
       case HttpStatusCode.Conflict: return 
opKnownFailure("insufficient-funds", resp);
       case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp);
       //FIXME: remove when server is updated
       case HttpStatusCode.Forbidden: return 
opKnownFailure("insufficient-funds", resp);
       default: return opUnknownFailure(resp, await resp.text())
diff --git a/packages/taler-util/src/operation.ts 
b/packages/taler-util/src/operation.ts
index aab5dc022..8adbbb0e2 100644
--- a/packages/taler-util/src/operation.ts
+++ b/packages/taler-util/src/operation.ts
@@ -60,7 +60,7 @@ export async function failOrThrow<E>(s: E, cb: () => 
Promise<OperationResult<unk
   if (resp.case === s) {
     return resp.detail
   }
-  throw TalerError.fromException(new Error(`request failed but case "${s}" was 
expected`))
+  throw TalerError.fromException(new Error(`request failed with "${resp.case}" 
but case "${s}" was expected`))
 }
 
 
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]