gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (8b0294ee -> bc817a63)


From: gnunet
Subject: [taler-wallet-core] branch master updated (8b0294ee -> bc817a63)
Date: Sun, 16 Jan 2022 21:55:12 +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 8b0294ee better description of coin test selection and using c8 for 
coverage runtime
     new bf0cb6ab splitting syncWorker with the factory so the former do not 
require nodejs runtime
     new f8ae2671 de-duplicating imports and fixing another typescript minor 
issues
     new bc817a63 #7120 manifest v3: first iteration working

The 3 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:
 .../src/crypto/workers/cryptoImplementation.ts     |  63 ++-----
 .../src/crypto/workers/synchronousWorker.ts        | 130 +-------------
 ...ronousWorker.ts => synchronousWorkerFactory.ts} | 123 ++-----------
 packages/taler-wallet-core/src/headless/helpers.ts |  21 ++-
 packages/taler-wallet-core/src/index.ts            |   1 +
 .../taler-wallet-core/src/operations/deposits.ts   |  16 +-
 packages/taler-wallet-core/src/operations/pay.ts   |  87 +++-------
 .../taler-wallet-core/src/util/coinSelection.ts    |   3 +-
 packages/taler-wallet-core/src/wallet.ts           | 190 ++++++++-------------
 .../taler-wallet-webextension/manifest-v3.json     |  25 +--
 packages/taler-wallet-webextension/package.json    |   2 +-
 .../taler-wallet-webextension/src/api/browser.ts   |  30 ++++
 .../taler-wallet-webextension/src/background.ts    |  10 +-
 .../taler-wallet-webextension/src/chromeBadge.ts   |   2 +-
 .../taler-wallet-webextension/src/permissions.ts   |   2 +-
 .../src/popup/DeveloperPage.tsx                    |   2 +-
 .../src/popup/Settings.tsx                         |   4 +-
 .../src/popupEntryPoint.tsx                        |   2 +-
 .../taler-wallet-webextension/src/renderHtml.tsx   |   2 +-
 ...ack.tsx => serviceWorkerCryptoWorkerFactory.ts} |  25 +--
 .../src/serviceWorkerHttpLib.ts                    | 146 ++++++++++++++++
 .../taler-wallet-webextension/src/utils/index.ts   |   2 +-
 .../taler-wallet-webextension/src/wxBackend.ts     |  71 +++++---
 pnpm-lock.yaml                                     |   8 +-
 24 files changed, 411 insertions(+), 556 deletions(-)
 copy packages/taler-wallet-core/src/crypto/workers/{synchronousWorker.ts => 
synchronousWorkerFactory.ts} (58%)
 copy packages/taler-wallet-webextension/src/{cta/payback.tsx => 
serviceWorkerCryptoWorkerFactory.ts} (63%)
 create mode 100644 
packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts

diff --git 
a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
index f9dcc649..bff2e0eb 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
@@ -25,54 +25,24 @@
  */
 
 // FIXME: Crypto should not use DB Types!
-import { DenominationRecord, WireFee } from "../../db.js";
-
 import {
-  buildSigPS,
-  CoinDepositPermission,
-  DenomKeyType,
-  ExchangeProtocolVersion,
-  FreshCoin,
-  hashDenomPub,
-  RecoupRefreshRequest,
+  AmountJson, Amounts, BenchmarkResult, buildSigPS,
+  CoinDepositPermission, createEddsaKeyPair, createHashContext, decodeCrock,
+  DenomKeyType, DepositInfo, eddsaGetPublic, eddsaSign, eddsaVerify,
+  encodeCrock, ExchangeProtocolVersion,
+  FreshCoin, hash, hashDenomPub, kdf, keyExchangeEcdheEddsa,
+  // Logger,
+  MakeSyncSignatureRequest, PlanchetCreationRequest, PlanchetCreationResult,
+  randomBytes, RecoupRefreshRequest,
   RecoupRequest,
-  RefreshPlanchetInfo,
-  TalerSignaturePurpose,
-} from "@gnu-taler/taler-util";
-// FIXME: These types should be internal to the wallet!
-import {
-  BenchmarkResult,
-  PlanchetCreationResult,
-  PlanchetCreationRequest,
-  DepositInfo,
-  MakeSyncSignatureRequest,
-} from "@gnu-taler/taler-util";
-import { AmountJson, Amounts } from "@gnu-taler/taler-util";
-import * as timer from "../../util/timer.js";
-import {
-  encodeCrock,
-  decodeCrock,
-  createEddsaKeyPair,
-  hash,
-  rsaBlind,
-  eddsaVerify,
-  eddsaSign,
-  rsaUnblind,
-  stringToBytes,
-  createHashContext,
-  keyExchangeEcdheEddsa,
-  setupRefreshPlanchet,
-  rsaVerify,
+  RefreshPlanchetInfo, rsaBlind, rsaUnblind, rsaVerify, setupRefreshPlanchet,
   setupRefreshTransferPub,
   setupTipPlanchet,
-  setupWithdrawPlanchet,
-  eddsaGetPublic,
+  setupWithdrawPlanchet, stringToBytes, TalerSignaturePurpose, Timestamp, 
timestampTruncateToSecond
 } from "@gnu-taler/taler-util";
-import { randomBytes } from "@gnu-taler/taler-util";
-import { kdf } from "@gnu-taler/taler-util";
-import { Timestamp, timestampTruncateToSecond } from "@gnu-taler/taler-util";
-
-import { Logger } from "@gnu-taler/taler-util";
+import bigint from "big-integer";
+import { DenominationRecord, WireFee } from "../../db.js";
+import * as timer from "../../util/timer.js";
 import {
   CreateRecoupRefreshReqRequest,
   CreateRecoupReqRequest,
@@ -80,11 +50,10 @@ import {
   DerivedTipPlanchet,
   DeriveRefreshSessionRequest,
   DeriveTipRequest,
-  SignTrackTransactionRequest,
+  SignTrackTransactionRequest
 } from "../cryptoTypes.js";
-import bigint from "big-integer";
 
-const logger = new Logger("cryptoImplementation.ts");
+// const logger = new Logger("cryptoImplementation.ts");
 
 function amountToBuffer(amount: AmountJson): Uint8Array {
   const buffer = new ArrayBuffer(8 + 4 + 12);
@@ -161,7 +130,7 @@ async function myEddsaSign(
 export class CryptoImplementation {
   static enableTracing = false;
 
-  constructor(private primitiveWorker?: PrimitiveWorker) {}
+  constructor(private primitiveWorker?: PrimitiveWorker) { }
 
   /**
    * Create a pre-coin of the given denomination to be withdrawn from then 
given
diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts 
b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
index 9de28dbe..4d341718 100644
--- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
@@ -14,135 +14,16 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { Logger } from "@gnu-taler/taler-util";
 import {
   CryptoImplementation,
-  PrimitiveWorker,
+  PrimitiveWorker
 } from "./cryptoImplementation.js";
 
-import { CryptoWorkerFactory } from "./cryptoApi.js";
-import { CryptoWorker } from "./cryptoWorkerInterface.js";
 
-import child_process from "child_process";
-import type internal from "stream";
-import { OpenedPromise, openPromise } from "../../index.js";
-import { j2s, Logger } from "@gnu-taler/taler-util";
 
 const logger = new Logger("synchronousWorker.ts");
 
-class MyPrimitiveWorker implements PrimitiveWorker {
-  proc: child_process.ChildProcessByStdio<
-    internal.Writable,
-    internal.Readable,
-    null
-  >;
-  requests: Array<{
-    p: OpenedPromise<any>;
-    req: any;
-  }> = [];
-
-  constructor() {
-    const stdoutChunks: Buffer[] = [];
-    this.proc = child_process.spawn("taler-crypto-worker", {
-      //stdio: ["pipe", "pipe", "inherit"],
-      stdio: ["pipe", "pipe", "inherit"],
-      detached: true,
-    });
-    this.proc.on("close", function (code) {
-      logger.error("child process exited");
-    });
-    (this.proc.stdout as any).unref();
-    (this.proc.stdin as any).unref();
-    this.proc.unref();
-
-    this.proc.stdout.on("data", (x) => {
-      // console.log("got chunk", x.toString("utf-8"));
-      if (x instanceof Buffer) {
-        const nlIndex = x.indexOf("\n");
-        if (nlIndex >= 0) {
-          const before = x.slice(0, nlIndex);
-          const after = x.slice(nlIndex + 1);
-          stdoutChunks.push(after);
-          const str = Buffer.concat([...stdoutChunks, before]).toString(
-            "utf-8",
-          );
-          const req = this.requests.shift()!;
-          if (this.requests.length === 0) {
-            this.proc.unref();
-          }
-          //logger.info(`got response: ${str}`);
-          req.p.resolve(JSON.parse(str));
-        } else {
-          stdoutChunks.push(x);
-        }
-      } else {
-        throw Error(`unexpected data chunk type (${typeof x})`);
-      }
-    });
-  }
-
-  async setupRefreshPlanchet(req: {
-    transfer_secret: string;
-    coin_index: number;
-  }): Promise<{
-    coin_pub: string;
-    coin_priv: string;
-    blinding_key: string;
-  }> {
-    return this.queueRequest({
-      op: "setup_refresh_planchet",
-      args: req,
-    });
-  }
-
-  async queueRequest(req: any): Promise<any> {
-    const p = openPromise<any>();
-    if (this.requests.length === 0) {
-      this.proc.ref();
-    }
-    this.requests.push({ req, p });
-    this.proc.stdin.write(JSON.stringify(req) + "\n");
-    return p.promise;
-  }
-
-  async eddsaVerify(req: {
-    msg: string;
-    sig: string;
-    pub: string;
-  }): Promise<{ valid: boolean }> {
-    return this.queueRequest({
-      op: "eddsa_verify",
-      args: req,
-    });
-  }
-
-  async eddsaSign(req: {
-    msg: string;
-    priv: string;
-  }): Promise<{ sig: string }> {
-    return this.queueRequest({
-      op: "eddsa_sign",
-      args: req,
-    });
-  }
-}
-
-/**
- * The synchronous crypto worker produced by this factory doesn't run in the
- * background, but actually blocks the caller until the operation is done.
- */
-export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
-  startWorker(): CryptoWorker {
-    if (typeof require === "undefined") {
-      throw Error("cannot make worker, require(...) not defined");
-    }
-    return new SynchronousCryptoWorker();
-  }
-
-  getConcurrency(): number {
-    return 1;
-  }
-}
-
 /**
  * Worker implementation that uses node subprocesses.
  */
@@ -157,14 +38,9 @@ export class SynchronousCryptoWorker {
    */
   onerror: undefined | ((m: any) => void);
 
-  primitiveWorker: PrimitiveWorker;
-
-  constructor() {
+  constructor(private primitiveWorker?: PrimitiveWorker) {
     this.onerror = undefined;
     this.onmessage = undefined;
-    if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
-      this.primitiveWorker = new MyPrimitiveWorker();
-    }
   }
 
   /**
diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts 
b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts
similarity index 58%
copy from packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
copy to 
packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts
index 9de28dbe..ca63c768 100644
--- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactory.ts
@@ -15,7 +15,6 @@
  */
 
 import {
-  CryptoImplementation,
   PrimitiveWorker,
 } from "./cryptoImplementation.js";
 
@@ -25,9 +24,10 @@ import { CryptoWorker } from "./cryptoWorkerInterface.js";
 import child_process from "child_process";
 import type internal from "stream";
 import { OpenedPromise, openPromise } from "../../index.js";
-import { j2s, Logger } from "@gnu-taler/taler-util";
+import { Logger } from "@gnu-taler/taler-util";
+import { SynchronousCryptoWorker } from "./synchronousWorker.js";
 
-const logger = new Logger("synchronousWorker.ts");
+const logger = new Logger("synchronousWorkerFactory.ts");
 
 class MyPrimitiveWorker implements PrimitiveWorker {
   proc: child_process.ChildProcessByStdio<
@@ -47,7 +47,7 @@ class MyPrimitiveWorker implements PrimitiveWorker {
       stdio: ["pipe", "pipe", "inherit"],
       detached: true,
     });
-    this.proc.on("close", function (code) {
+    this.proc.on("close", (): void => {
       logger.error("child process exited");
     });
     (this.proc.stdout as any).unref();
@@ -65,7 +65,10 @@ class MyPrimitiveWorker implements PrimitiveWorker {
           const str = Buffer.concat([...stdoutChunks, before]).toString(
             "utf-8",
           );
-          const req = this.requests.shift()!;
+          const req = this.requests.shift();
+          if (!req) {
+            throw Error("request was undefined")
+          }
           if (this.requests.length === 0) {
             this.proc.unref();
           }
@@ -100,7 +103,7 @@ class MyPrimitiveWorker implements PrimitiveWorker {
       this.proc.ref();
     }
     this.requests.push({ req, p });
-    this.proc.stdin.write(JSON.stringify(req) + "\n");
+    this.proc.stdin.write(`${JSON.stringify(req)}\n`);
     return p.promise;
   }
 
@@ -135,114 +138,16 @@ export class SynchronousCryptoWorkerFactory implements 
CryptoWorkerFactory {
     if (typeof require === "undefined") {
       throw Error("cannot make worker, require(...) not defined");
     }
-    return new SynchronousCryptoWorker();
-  }
-
-  getConcurrency(): number {
-    return 1;
-  }
-}
-
-/**
- * Worker implementation that uses node subprocesses.
- */
-export class SynchronousCryptoWorker {
-  /**
-   * Function to be called when we receive a message from the worker thread.
-   */
-  onmessage: undefined | ((m: any) => void);
-
-  /**
-   * Function to be called when we receive an error from the worker thread.
-   */
-  onerror: undefined | ((m: any) => void);
-
-  primitiveWorker: PrimitiveWorker;
 
-  constructor() {
-    this.onerror = undefined;
-    this.onmessage = undefined;
+    let primitiveWorker;
     if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
-      this.primitiveWorker = new MyPrimitiveWorker();
+      primitiveWorker = new MyPrimitiveWorker();
     }
-  }
 
-  /**
-   * Add an event listener for either an "error" or "message" event.
-   */
-  addEventListener(event: "message" | "error", fn: (x: any) => void): void {
-    switch (event) {
-      case "message":
-        this.onmessage = fn;
-        break;
-      case "error":
-        this.onerror = fn;
-        break;
-    }
-  }
-
-  private dispatchMessage(msg: any): void {
-    if (this.onmessage) {
-      this.onmessage({ data: msg });
-    }
+    return new SynchronousCryptoWorker(primitiveWorker);
   }
 
-  private async handleRequest(
-    operation: string,
-    id: number,
-    args: string[],
-  ): Promise<void> {
-    const impl = new CryptoImplementation(this.primitiveWorker);
-
-    if (!(operation in impl)) {
-      console.error(`crypto operation '${operation}' not found`);
-      return;
-    }
-
-    let result: any;
-    try {
-      result = await (impl as any)[operation](...args);
-    } catch (e) {
-      logger.error("error during operation", e);
-      return;
-    }
-
-    try {
-      setTimeout(() => this.dispatchMessage({ result, id }), 0);
-    } catch (e) {
-      logger.error("got error during dispatch", e);
-    }
-  }
-
-  /**
-   * Send a message to the worker thread.
-   */
-  postMessage(msg: any): void {
-    const args = msg.args;
-    if (!Array.isArray(args)) {
-      console.error("args must be array");
-      return;
-    }
-    const id = msg.id;
-    if (typeof id !== "number") {
-      console.error("RPC id must be number");
-      return;
-    }
-    const operation = msg.operation;
-    if (typeof operation !== "string") {
-      console.error("RPC operation must be string");
-      return;
-    }
-
-    this.handleRequest(operation, id, args).catch((e) => {
-      console.error("Error while handling crypto request:", e);
-    });
-  }
-
-  /**
-   * Forcibly terminate the worker thread.
-   */
-  terminate(): void {
-    // This is a no-op.
+  getConcurrency(): number {
+    return 1;
   }
 }
diff --git a/packages/taler-wallet-core/src/headless/helpers.ts 
b/packages/taler-wallet-core/src/headless/helpers.ts
index d8616f71..120c4cd4 100644
--- a/packages/taler-wallet-core/src/headless/helpers.ts
+++ b/packages/taler-wallet-core/src/headless/helpers.ts
@@ -22,22 +22,20 @@
 /**
  * Imports.
  */
+import type { IDBFactory } from "@gnu-taler/idb-bridge";
+// eslint-disable-next-line no-duplicate-imports
 import {
-  MemoryBackend,
-  BridgeIDBFactory,
-  shimIndexedDB,
+  BridgeIDBFactory, MemoryBackend, shimIndexedDB
 } from "@gnu-taler/idb-bridge";
+import { AccessStats } from "@gnu-taler/idb-bridge/src/MemoryBackend";
+import { Logger, WalletNotification } from "@gnu-taler/taler-util";
+import * as fs from "fs";
+import { NodeThreadCryptoWorkerFactory } from 
"../crypto/workers/nodeThreadWorker.js";
+import { SynchronousCryptoWorkerFactory } from 
"../crypto/workers/synchronousWorkerFactory.js";
 import { openTalerDatabase } from "../db-utils.js";
 import { HttpRequestLibrary } from "../util/http.js";
-import { NodeThreadCryptoWorkerFactory } from 
"../crypto/workers/nodeThreadWorker.js";
-import { NodeHttpLib } from "./NodeHttpLib.js";
-import { Logger } from "@gnu-taler/taler-util";
-import { SynchronousCryptoWorkerFactory } from 
"../crypto/workers/synchronousWorker.js";
-import type { IDBFactory } from "@gnu-taler/idb-bridge";
-import { WalletNotification } from "@gnu-taler/taler-util";
 import { Wallet } from "../wallet.js";
-import * as fs from "fs";
-import { AccessStats } from "@gnu-taler/idb-bridge/src/MemoryBackend";
+import { NodeHttpLib } from "./NodeHttpLib.js";
 
 const logger = new Logger("headless/helpers.ts");
 
@@ -165,6 +163,7 @@ export async function getDefaultNodeWallet2(
     try {
       // Try if we have worker threads available, fails in older node versions.
       const _r = "require";
+      // eslint-disable-next-line no-unused-vars
       const worker_threads = module[_r]("worker_threads");
       // require("worker_threads");
       workerFactory = new NodeThreadCryptoWorkerFactory();
diff --git a/packages/taler-wallet-core/src/index.ts 
b/packages/taler-wallet-core/src/index.ts
index 5489bd5a..179ba6b8 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -36,6 +36,7 @@ export * from "./db-utils.js";
 export { CryptoImplementation } from 
"./crypto/workers/cryptoImplementation.js";
 export type { CryptoWorker } from "./crypto/workers/cryptoWorkerInterface.js";
 export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi.js";
+export { SynchronousCryptoWorker } from "./crypto/workers/synchronousWorker.js"
 
 export * from "./pending-types.js";
 
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 40a0af31..8a5b3573 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -27,9 +27,7 @@ import {
   CreateDepositGroupRequest,
   CreateDepositGroupResponse,
   DenomKeyType,
-  durationFromSpec,
-  GetFeeForDepositRequest,
-  getTimestampNow,
+  durationFromSpec, encodeCrock, GetFeeForDepositRequest, getRandomBytes, 
getTimestampNow,
   Logger,
   NotificationType,
   parsePaytoUri,
@@ -40,15 +38,9 @@ import {
   timestampTruncateToSecond,
   TrackDepositGroupRequest,
   TrackDepositGroupResponse,
-  URL,
+  URL
 } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../common.js";
-import { kdf } from "@gnu-taler/taler-util";
-import {
-  encodeCrock,
-  getRandomBytes,
-  stringToBytes,
-} from "@gnu-taler/taler-util";
 import { DepositGroupRecord, OperationStatus } from "../db.js";
 import { guardOperationException } from "../errors.js";
 import { PayCoinSelection, selectPayCoins } from "../util/coinSelection.js";
@@ -62,7 +54,7 @@ import {
   getCandidatePayCoins,
   getTotalPaymentCost,
   hashWire,
-  hashWireLegacy,
+  hashWireLegacy
 } from "./pay.js";
 import { getTotalRefreshCost } from "./refresh.js";
 
@@ -168,7 +160,7 @@ export async function processDepositGroup(
 async function processDepositGroupImpl(
   ws: InternalWalletState,
   depositGroupId: string,
-  forceNow: boolean = false,
+  forceNow = false,
 ): Promise<void> {
   if (forceNow) {
     await resetDepositGroupRetry(ws, depositGroupId);
diff --git a/packages/taler-wallet-core/src/operations/pay.ts 
b/packages/taler-wallet-core/src/operations/pay.ts
index 479ab5e1..8f0727c8 100644
--- a/packages/taler-wallet-core/src/operations/pay.ts
+++ b/packages/taler-wallet-core/src/operations/pay.ts
@@ -26,58 +26,14 @@
  */
 import {
   AmountJson,
-  Amounts,
-  timestampIsBetween,
-  getTimestampNow,
-  isTimestampExpired,
-  Timestamp,
-  RefreshReason,
-  CoinDepositPermission,
-  NotificationType,
-  TalerErrorDetails,
-  Duration,
+  Amounts, codecForContractTerms, codecForMerchantPayResponse, 
codecForProposal, CoinDepositPermission, ConfirmPayResult,
+  ConfirmPayResultType, ContractTerms, decodeCrock, DenomKeyType, Duration,
   durationMax,
   durationMin,
-  durationMul,
-  ContractTerms,
-  codecForProposal,
-  TalerErrorCode,
-  codecForContractTerms,
-  timestampAddDuration,
-  ConfirmPayResult,
-  ConfirmPayResultType,
-  codecForMerchantPayResponse,
-  PreparePayResult,
-  PreparePayResultType,
-  parsePayUri,
-  Logger,
-  URL,
-  getDurationRemaining,
-  HttpStatusCode,
-  DenomKeyType,
-  kdf,
-  stringToBytes,
-  decodeCrock,
+  durationMul, encodeCrock, getDurationRemaining, getRandomBytes, 
getTimestampNow, HttpStatusCode, isTimestampExpired, j2s, kdf, Logger, 
NotificationType, parsePayUri, PreparePayResult,
+  PreparePayResultType, RefreshReason, stringToBytes, TalerErrorCode, 
TalerErrorDetails, Timestamp, timestampAddDuration, URL
 } from "@gnu-taler/taler-util";
-import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
-import {
-  PayCoinSelection,
-  CoinCandidateSelection,
-  AvailableCoinInfo,
-  selectPayCoins,
-  PreviousPayCoins,
-} from "../util/coinSelection.js";
-import { j2s } from "@gnu-taler/taler-util";
-import {
-  initRetryInfo,
-  updateRetryInfoTimeout,
-  getRetryDuration,
-} from "../util/retries.js";
-import { getTotalRefreshCost, createRefreshGroup } from "./refresh.js";
-import { InternalWalletState, EXCHANGE_COINS_LOCK } from "../common.js";
-import { ContractTermsUtil } from "../util/contractTerms.js";
-import { getExchangeDetails } from "./exchanges.js";
-import { GetReadWriteAccess } from "../util/query.js";
+import { EXCHANGE_COINS_LOCK, InternalWalletState } from "../common.js";
 import {
   AbortStatus,
   AllowedAuditorInfo,
@@ -90,22 +46,33 @@ import {
   ProposalStatus,
   PurchaseRecord,
   WalletContractData,
-  WalletStoresV1,
+  WalletStoresV1
 } from "../db.js";
+import {
+  guardOperationException,
+  makeErrorDetails,
+  OperationFailedAndReportedError,
+  OperationFailedError
+} from "../errors.js";
+import {
+  AvailableCoinInfo, CoinCandidateSelection, PayCoinSelection, 
PreviousPayCoins, selectPayCoins
+} from "../util/coinSelection.js";
+import { ContractTermsUtil } from "../util/contractTerms.js";
 import {
   getHttpResponseErrorDetails,
   readSuccessResponseJsonOrErrorCode,
   readSuccessResponseJsonOrThrow,
   readTalerErrorResponse,
   readUnexpectedResponseDetails,
-  throwUnexpectedRequestError,
+  throwUnexpectedRequestError
 } from "../util/http.js";
+import { GetReadWriteAccess } from "../util/query.js";
 import {
-  guardOperationException,
-  makeErrorDetails,
-  OperationFailedAndReportedError,
-  OperationFailedError,
-} from "../errors.js";
+  getRetryDuration, initRetryInfo,
+  updateRetryInfoTimeout
+} from "../util/retries.js";
+import { getExchangeDetails } from "./exchanges.js";
+import { createRefreshGroup, getTotalRefreshCost } from "./refresh.js";
 
 /**
  * Logger.
@@ -368,7 +335,7 @@ export async function applyCoinSpend(
   }>,
   coinSelection: PayCoinSelection,
   allocationId: string,
-) {
+): Promise<void> {
   logger.info(`applying coin spend ${j2s(coinSelection)}`);
   for (let i = 0; i < coinSelection.coinPubs.length; i++) {
     const coin = await tx.coins.get(coinSelection.coinPubs[i]);
@@ -530,8 +497,7 @@ async function incrementPurchasePayRetry(
       pr.payRetryInfo.retryCounter++;
       updateRetryInfoTimeout(pr.payRetryInfo);
       logger.trace(
-        `retrying pay in ${
-          getDurationRemaining(pr.payRetryInfo.nextRetry).d_ms
+        `retrying pay in ${getDurationRemaining(pr.payRetryInfo.nextRetry).d_ms
         } ms`,
       );
       pr.lastPayError = err;
@@ -1105,7 +1071,7 @@ async function unblockBackup(
   await ws.db
     .mktx((x) => ({ backupProviders: x.backupProviders }))
     .runReadWrite(async (tx) => {
-      const bp = await tx.backupProviders.indexes.byPaymentProposalId
+      await tx.backupProviders.indexes.byPaymentProposalId
         .iter(proposalId)
         .forEachAsync(async (bp) => {
           if (bp.state.tag === BackupProviderStateTag.Retrying) {
@@ -1143,6 +1109,7 @@ async function submitPay(
 
   logger.trace("paying with session ID", sessionId);
 
+  //FIXME: not used, does it expect a side effect?
   const merchantInfo = await ws.merchantOps.getMerchantInfo(
     ws,
     purchase.download.contractData.merchantBaseUrl,
diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts 
b/packages/taler-wallet-core/src/util/coinSelection.ts
index bfc481ea..9a122a8f 100644
--- a/packages/taler-wallet-core/src/util/coinSelection.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection.ts
@@ -27,9 +27,8 @@ import {
   AmountJson,
   Amounts,
   DenominationPubKey,
-  DenomKeyType,
+  DenomKeyType, Logger, strcmp
 } from "@gnu-taler/taler-util";
-import { strcmp, Logger } from "@gnu-taler/taler-util";
 
 const logger = new Logger("coinSelection.ts");
 
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index 347a1eb0..7bbbb1ff 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -23,30 +23,50 @@
  * Imports.
  */
 import {
-  BalancesResponse,
-  codecForAny,
-  codecForDeleteTransactionRequest,
-  codecForRetryTransactionRequest,
-  codecForSetWalletDeviceIdRequest,
-  codecForGetExchangeWithdrawalInfo,
-  durationFromSpec,
-  durationMin,
-  getDurationRemaining,
-  isTimestampExpired,
-  j2s,
-  TalerErrorCode,
+  AcceptManualWithdrawalResult,
+  AcceptWithdrawalResponse, AmountJson, Amounts, BalancesResponse, 
codecForAbortPayWithRefundRequest,
+  codecForAcceptBankIntegratedWithdrawalRequest,
+  codecForAcceptExchangeTosRequest,
+  codecForAcceptManualWithdrawalRequet,
+  codecForAcceptTipRequest,
+  codecForAddExchangeRequest, codecForAny, codecForApplyRefundRequest,
+  codecForConfirmPayRequest,
+  codecForCreateDepositGroupRequest, codecForDeleteTransactionRequest, 
codecForForceRefreshRequest,
+  codecForGetExchangeTosRequest, codecForGetExchangeWithdrawalInfo, 
codecForGetFeeForDeposit, codecForGetWithdrawalDetailsForAmountRequest,
+  codecForGetWithdrawalDetailsForUri, codecForImportDbRequest, 
codecForIntegrationTestArgs, codecForListKnownBankAccounts, 
codecForPreparePayRequest,
+  codecForPrepareTipRequest, codecForRetryTransactionRequest, 
codecForSetCoinSuspendedRequest, codecForSetWalletDeviceIdRequest, 
codecForTestPayArgs,
+  codecForTrackDepositGroupRequest, codecForTransactionsRequest, 
codecForWithdrawFakebankRequest, codecForWithdrawTestBalance, CoinDumpJson, 
CoreApiResponse, durationFromSpec,
+  durationMin, ExchangeListItem,
+  ExchangesListRespose, getDurationRemaining, GetExchangeTosResult, 
isTimestampExpired,
+  j2s, KnownBankAccounts, Logger, ManualWithdrawalDetails, NotificationType, 
parsePaytoUri, PaytoUri, RefreshReason, TalerErrorCode,
   Timestamp,
-  timestampMin,
-  WalletNotification,
-  codecForWithdrawFakebankRequest,
-  URL,
-  parsePaytoUri,
-  KnownBankAccounts,
-  PaytoUri,
-  codecForGetFeeForDeposit,
-  codecForListKnownBankAccounts,
-  codecForImportDbRequest,
+  timestampMin, URL, WalletNotification
 } from "@gnu-taler/taler-util";
+import {
+  DenomInfo,
+  ExchangeOperations,
+  InternalWalletState,
+  MerchantInfo,
+  MerchantOperations,
+  NotificationListener,
+  RecoupOperations,
+  ReserveOperations
+} from "./common.js";
+import { CryptoApi, CryptoWorkerFactory } from "./crypto/workers/cryptoApi.js";
+import {
+  AuditorTrustRecord,
+  CoinSourceType,
+  exportDb,
+  importDb,
+  ReserveRecordStatus,
+  WalletStoresV1
+} from "./db.js";
+import {
+  makeErrorDetails,
+  OperationFailedAndReportedError,
+  OperationFailedError
+} from "./errors.js";
+import { exportBackup } from "./operations/backup/export.js";
 import {
   addBackupProvider,
   codecForAddBackupProviderRequest,
@@ -57,142 +77,80 @@ import {
   loadBackupRecovery,
   processBackupForProvider,
   removeBackupProvider,
-  runBackupCycle,
+  runBackupCycle
 } from "./operations/backup/index.js";
-import { exportBackup } from "./operations/backup/export.js";
+import { setWalletDeviceId } from "./operations/backup/state.js";
 import { getBalances } from "./operations/balance.js";
 import {
   createDepositGroup,
   getFeeForDeposit,
   processDepositGroup,
-  trackDepositGroup,
+  trackDepositGroup
 } from "./operations/deposits.js";
-import {
-  makeErrorDetails,
-  OperationFailedAndReportedError,
-  OperationFailedError,
-} from "./errors.js";
 import {
   acceptExchangeTermsOfService,
   getExchangeDetails,
   getExchangeTrust,
-  updateExchangeFromUrl,
+  updateExchangeFromUrl
 } from "./operations/exchanges.js";
+import { getMerchantInfo } from "./operations/merchants.js";
 import {
   confirmPay,
   preparePayForUri,
   processDownloadProposal,
-  processPurchasePay,
+  processPurchasePay
 } from "./operations/pay.js";
 import { getPendingOperations } from "./operations/pending.js";
 import { createRecoupGroup, processRecoupGroup } from "./operations/recoup.js";
 import {
   autoRefresh,
   createRefreshGroup,
-  processRefreshGroup,
+  processRefreshGroup
 } from "./operations/refresh.js";
 import {
   abortFailedPayWithRefund,
   applyRefund,
-  processPurchaseQueryRefund,
+  processPurchaseQueryRefund
 } from "./operations/refund.js";
 import {
   createReserve,
   createTalerWithdrawReserve,
   getFundingPaytoUris,
-  processReserve,
+  processReserve
 } from "./operations/reserves.js";
-import {
-  DenomInfo,
-  ExchangeOperations,
-  InternalWalletState,
-  MerchantInfo,
-  MerchantOperations,
-  NotificationListener,
-  RecoupOperations,
-  ReserveOperations,
-} from "./common.js";
 import {
   runIntegrationTest,
   testPay,
-  withdrawTestBalance,
+  withdrawTestBalance
 } from "./operations/testing.js";
 import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
 import {
   deleteTransaction,
   getTransactions,
-  retryTransaction,
+  retryTransaction
 } from "./operations/transactions.js";
 import {
   getExchangeWithdrawalInfo,
   getWithdrawalDetailsForUri,
-  processWithdrawGroup,
+  processWithdrawGroup
 } from "./operations/withdraw.js";
 import {
-  AuditorTrustRecord,
-  CoinSourceType,
-  exportDb,
-  importDb,
-  ReserveRecordStatus,
-  WalletStoresV1,
-} from "./db.js";
-import { NotificationType } from "@gnu-taler/taler-util";
-import {
-  PendingTaskInfo,
-  PendingOperationsResponse,
-  PendingTaskType,
+  PendingOperationsResponse, PendingTaskInfo, PendingTaskType
 } from "./pending-types.js";
-import { CoinDumpJson } from "@gnu-taler/taler-util";
-import { codecForTransactionsRequest } from "@gnu-taler/taler-util";
-import {
-  AcceptManualWithdrawalResult,
-  AcceptWithdrawalResponse,
-  codecForAbortPayWithRefundRequest,
-  codecForAcceptBankIntegratedWithdrawalRequest,
-  codecForAcceptExchangeTosRequest,
-  codecForAcceptManualWithdrawalRequet,
-  codecForAcceptTipRequest,
-  codecForAddExchangeRequest,
-  codecForApplyRefundRequest,
-  codecForConfirmPayRequest,
-  codecForCreateDepositGroupRequest,
-  codecForForceRefreshRequest,
-  codecForGetExchangeTosRequest,
-  codecForGetWithdrawalDetailsForAmountRequest,
-  codecForGetWithdrawalDetailsForUri,
-  codecForIntegrationTestArgs,
-  codecForPreparePayRequest,
-  codecForPrepareTipRequest,
-  codecForSetCoinSuspendedRequest,
-  codecForTestPayArgs,
-  codecForTrackDepositGroupRequest,
-  codecForWithdrawTestBalance,
-  CoreApiResponse,
-  ExchangeListItem,
-  ExchangesListRespose,
-  GetExchangeTosResult,
-  ManualWithdrawalDetails,
-  RefreshReason,
-} from "@gnu-taler/taler-util";
-import { AmountJson, Amounts } from "@gnu-taler/taler-util";
 import { assertUnreachable } from "./util/assertUnreachable.js";
-import { Logger } from "@gnu-taler/taler-util";
-import { setWalletDeviceId } from "./operations/backup/state.js";
-import { WalletCoreApiClient } from "./wallet-api-types.js";
 import { AsyncOpMemoMap, AsyncOpMemoSingle } from "./util/asyncMemo.js";
-import { CryptoApi, CryptoWorkerFactory } from "./crypto/workers/cryptoApi.js";
-import { TimerGroup } from "./util/timer.js";
+import {
+  HttpRequestLibrary,
+  readSuccessResponseJsonOrThrow
+} from "./util/http.js";
 import {
   AsyncCondition,
   OpenedPromise,
-  openPromise,
+  openPromise
 } from "./util/promiseUtils.js";
 import { DbAccess, GetReadWriteAccess } from "./util/query.js";
-import {
-  HttpRequestLibrary,
-  readSuccessResponseJsonOrThrow,
-} from "./util/http.js";
-import { getMerchantInfo } from "./operations/merchants.js";
+import { TimerGroup } from "./util/timer.js";
+import { WalletCoreApiClient } from "./wallet-api-types.js";
 
 const builtinAuditors: AuditorTrustRecord[] = [
   {
@@ -1047,7 +1005,7 @@ export async function handleCoreApiRequest(
       try {
         logger.error("Caught unexpected exception:");
         logger.error(e.stack);
-      } catch (e) {}
+      } catch (e) { }
       return {
         type: "error",
         operation,
@@ -1077,7 +1035,7 @@ export class Wallet {
     this.ws = new InternalWalletStateImpl(db, http, cryptoWorkerFactory);
   }
 
-  get client() {
+  get client(): WalletCoreApiClient {
     return this._client;
   }
 
@@ -1085,7 +1043,7 @@ export class Wallet {
    * Trust the exchange, do not validate signatures.
    * Only used to benchmark the exchange.
    */
-  setInsecureTrustExchange() {
+  setInsecureTrustExchange(): void {
     this.ws.insecureTrustExchange = true;
   }
 
@@ -1107,11 +1065,11 @@ export class Wallet {
     this.ws.stop();
   }
 
-  runPending(forceNow: boolean = false) {
+  runPending(forceNow = false): Promise<void> {
     return runPending(this.ws, forceNow);
   }
 
-  runTaskLoop(opts?: RetryLoopOpts) {
+  runTaskLoop(opts?: RetryLoopOpts): Promise<void> {
     return runTaskLoop(this.ws, opts);
   }
 
@@ -1142,7 +1100,7 @@ class InternalWalletStateImpl implements 
InternalWalletState {
 
   merchantInfoCache: Record<string, MerchantInfo> = {};
 
-  insecureTrustExchange: boolean = false;
+  insecureTrustExchange = false;
 
   timerGroup: TimerGroup = new TimerGroup();
   latch = new AsyncCondition();
@@ -1150,7 +1108,7 @@ class InternalWalletStateImpl implements 
InternalWalletState {
 
   listeners: NotificationListener[] = [];
 
-  initCalled: boolean = false;
+  initCalled = false;
 
   exchangeOps: ExchangeOperations = {
     getExchangeDetails,
@@ -1159,16 +1117,16 @@ class InternalWalletStateImpl implements 
InternalWalletState {
   };
 
   recoupOps: RecoupOperations = {
-    createRecoupGroup: createRecoupGroup,
-    processRecoupGroup: processRecoupGroup,
+    createRecoupGroup,
+    processRecoupGroup,
   };
 
   merchantOps: MerchantOperations = {
-    getMerchantInfo: getMerchantInfo,
+    getMerchantInfo,
   };
 
   reserveOps: ReserveOperations = {
-    processReserve: processReserve,
+    processReserve,
   };
 
   // FIXME: Use an LRU cache here.
@@ -1253,7 +1211,7 @@ class InternalWalletStateImpl implements 
InternalWalletState {
    * Run an async function after acquiring a list of locks, identified
    * by string tokens.
    */
-  async runSequentialized<T>(tokens: string[], f: () => Promise<T>) {
+  async runSequentialized<T>(tokens: string[], f: () => Promise<T>): 
Promise<T> {
     // Make sure locks are always acquired in the same order
     tokens = [...tokens].sort();
 
diff --git a/packages/taler-wallet-webextension/manifest-v3.json 
b/packages/taler-wallet-webextension/manifest-v3.json
index b7f7c902..6024b750 100644
--- a/packages/taler-wallet-webextension/manifest-v3.json
+++ b/packages/taler-wallet-webextension/manifest-v3.json
@@ -1,41 +1,28 @@
 {
   "manifest_version": 3,
-
   "name": "GNU Taler Wallet (git)",
   "description": "Privacy preserving and transparent payments",
   "author": "GNU Taler Developers",
   "version": "0.8.1.15",
   "version_name": "0.8.1-dev.15",
-
   "minimum_chrome_version": "88",
-
-  "applications": {
-    "gecko": {
-      "id": "wallet@taler.net",
-      "strict_min_version": "57.0"
-    }
-  },
-
   "icons": {
     "32": "static/img/icon.png",
     "128": "static/img/logo.png"
   },
-
   "permissions": [
     "unlimitedStorage",
-    "activeTab"
+    "activeTab",
+    "scripting"
   ],
-
   "optional_permissions": [
     "webRequest",
     "webRequestBlocking"
   ],
-
-  "host_permissions":[
+  "host_permissions": [
     "http://*/*";,
     "https://*/*";
   ],
-
   "action": {
     "default_icon": {
       "32": "static/img/icon.png"
@@ -43,9 +30,7 @@
     "default_title": "Taler",
     "default_popup": "static/popup.html"
   },
-
   "background": {
-    "page": "static/background.html",
-    "persistent": true
+    "service_worker": "dist/background.js"
   }
-}
+}
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/package.json 
b/packages/taler-wallet-webextension/package.json
index fd4b0fb4..9b02eee2 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -48,7 +48,7 @@
     "@storybook/preact": "6.4.9",
     "@testing-library/preact": "^2.0.1",
     "@testing-library/preact-hooks": "^1.1.0",
-    "@types/chrome": "^0.0.174",
+    "@types/chrome": "0.0.176",
     "@types/history": "^4.7.8",
     "@types/mocha": "^9.0.0",
     "@types/node": "^17.0.8",
diff --git a/packages/taler-wallet-webextension/src/api/browser.ts 
b/packages/taler-wallet-webextension/src/api/browser.ts
index bc50853f..b69a4968 100644
--- a/packages/taler-wallet-webextension/src/api/browser.ts
+++ b/packages/taler-wallet-webextension/src/api/browser.ts
@@ -1,6 +1,36 @@
+function searchForTalerLinks(): string | undefined {
+  let found;
+  found = document.querySelector("a[href^='taler://'")
+  if (found) return found.toString()
+  found = document.querySelector("a[href^='taler+http://'")
+  if (found) return found.toString()
+  return undefined
+}
+
+async function getCurrentTab() {
+  let queryOptions = { active: true, currentWindow: true };
+  let [tab] = await chrome.tabs.query(queryOptions);
+  return tab;
+}
+
+
 
 export async function findTalerUriInActiveTab(): Promise<string | undefined> {
+  if (chrome.runtime.getManifest().manifest_version === 3) {
+    // manifest v3
+    const tab = await getCurrentTab();
+    const res = await chrome.scripting.executeScript({
+      target: {
+        tabId: tab.id!,
+        allFrames: true,
+      } as any,
+      func: searchForTalerLinks,
+      args: []
+    })
+    return res[0].result
+  }
   return new Promise((resolve, reject) => {
+    //manifest v2
     chrome.tabs.executeScript(
       {
         code: `
diff --git a/packages/taler-wallet-webextension/src/background.ts 
b/packages/taler-wallet-webextension/src/background.ts
index dcbf9613..428cd86f 100644
--- a/packages/taler-wallet-webextension/src/background.ts
+++ b/packages/taler-wallet-webextension/src/background.ts
@@ -25,6 +25,12 @@
  */
 import { wxMain } from "./wxBackend";
 
-window.addEventListener("load", () => {
+const loadedFromWebpage = typeof window !== "undefined"
+
+if (chrome.runtime.getManifest().manifest_version === 3) {
   wxMain();
-});
+} else {
+  window.addEventListener("load", () => {
+    wxMain();
+  });
+}
diff --git a/packages/taler-wallet-webextension/src/chromeBadge.ts 
b/packages/taler-wallet-webextension/src/chromeBadge.ts
index 7bc5d368..60585793 100644
--- a/packages/taler-wallet-webextension/src/chromeBadge.ts
+++ b/packages/taler-wallet-webextension/src/chromeBadge.ts
@@ -198,7 +198,7 @@ export class ChromeBadge {
           this.canvas.width,
           this.canvas.height,
         );
-        chrome.browserAction.setIcon({ imageData });
+        chrome.action.setIcon({ imageData });
       } catch (e) {
         // Might fail if browser has over-eager canvas fingerprinting 
countermeasures.
         // There's nothing we can do then ...
diff --git a/packages/taler-wallet-webextension/src/permissions.ts 
b/packages/taler-wallet-webextension/src/permissions.ts
index bcd357fd..909433bb 100644
--- a/packages/taler-wallet-webextension/src/permissions.ts
+++ b/packages/taler-wallet-webextension/src/permissions.ts
@@ -15,6 +15,6 @@
  */
 
 export const extendedPermissions = {
-  permissions: ["webRequest", "webRequestBlocking"],
+  permissions: ["webRequest"],
   origins: ["http://*/*";, "https://*/*";],
 };
diff --git a/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx 
b/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
index ea87ba01..f4b49c23 100644
--- a/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
@@ -194,7 +194,7 @@ export function openExtensionPage(page: string) {
     // eslint-disable-next-line no-undef
     chrome.tabs.create({
       // eslint-disable-next-line no-undef
-      url: chrome.extension.getURL(page),
+      url: chrome.runtime.getURL(page),
     });
   };
 }
diff --git a/packages/taler-wallet-webextension/src/popup/Settings.tsx 
b/packages/taler-wallet-webextension/src/popup/Settings.tsx
index 3732cf7b..a7cdf9cc 100644
--- a/packages/taler-wallet-webextension/src/popup/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Settings.tsx
@@ -60,9 +60,9 @@ export function SettingsView({
           style={{ color: "darkgreen", textDecoration: "none" }}
           href={
             // eslint-disable-next-line no-undef
-            chrome.extension
+            chrome.runtime
               ? // eslint-disable-next-line no-undef
-                chrome.extension.getURL(`/static/wallet.html#/settings`)
+                chrome.runtime.getURL(`/static/wallet.html#/settings`)
               : "#"
           }
         >
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx 
b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index 908349e8..5cd68b9b 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -173,7 +173,7 @@ function goToWalletPage(page: Pages | string): null {
   chrome.tabs.create({
     active: true,
     // eslint-disable-next-line no-undef
-    url: chrome.extension.getURL(`/static/wallet.html#${page}`),
+    url: chrome.runtime.getURL(`/static/wallet.html#${page}`),
   });
   return null;
 }
diff --git a/packages/taler-wallet-webextension/src/renderHtml.tsx 
b/packages/taler-wallet-webextension/src/renderHtml.tsx
index ba98ae23..1e482cce 100644
--- a/packages/taler-wallet-webextension/src/renderHtml.tsx
+++ b/packages/taler-wallet-webextension/src/renderHtml.tsx
@@ -167,7 +167,7 @@ export function PageLink(props: {
     typeof chrome === "undefined"
       ? undefined
       : // eslint-disable-next-line no-undef
-        chrome.extension?.getURL(`/static/wallet.html#/${props.pageName}`);
+        chrome.runtime?.getURL(`/static/wallet.html#/${props.pageName}`);
   return (
     <a class="actionLink" href={url} target="_blank" rel="noopener noreferrer">
       {props.children}
diff --git a/packages/taler-wallet-webextension/src/cta/payback.tsx 
b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
similarity index 63%
copy from packages/taler-wallet-webextension/src/cta/payback.tsx
copy to 
packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
index 1c81b48a..6084ebae 100644
--- a/packages/taler-wallet-webextension/src/cta/payback.tsx
+++ b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
@@ -1,6 +1,6 @@
 /*
  This file is part of TALER
- (C) 2017 Inria
+ (C) 2016 GNUnet e.V.
 
  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU General Public License as published by the Free Software
@@ -14,18 +14,23 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { h, VNode } from "preact";
-
 /**
- * View and edit auditors.
- *
+ * API to access the Taler crypto worker thread.
  * @author Florian Dold
  */
 
-/**
- * Imports.
- */
+import {
+  CryptoWorker,
+  CryptoWorkerFactory,
+  SynchronousCryptoWorker,
+} from "@gnu-taler/taler-wallet-core";
+
+export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
+  startWorker(): CryptoWorker {
+    return new SynchronousCryptoWorker();
+  }
 
-export function makePaybackPage(): VNode {
-  return <div>not implemented</div>;
+  getConcurrency(): number {
+    return 1;
+  }
 }
diff --git a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts 
b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
new file mode 100644
index 00000000..f8953f73
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
@@ -0,0 +1,146 @@
+/*
+ This file is part of GNU Taler
+ (C) 2020 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Imports.
+ */
+import { Logger, TalerErrorCode } from "@gnu-taler/taler-util";
+import {
+  Headers, HttpRequestLibrary,
+  HttpRequestOptions,
+  HttpResponse,
+  OperationFailedError
+} from "@gnu-taler/taler-wallet-core";
+
+const logger = new Logger("browserHttpLib");
+
+/**
+ * An implementation of the [[HttpRequestLibrary]] using the
+ * browser's XMLHttpRequest.
+ */
+export class ServiceWorkerHttpLib implements HttpRequestLibrary {
+  async fetch(requestUrl: string, options?: HttpRequestOptions): 
Promise<HttpResponse> {
+    const requestMethod = options?.method ?? "GET";
+    const requestBody = options?.body;
+    const requestHeader = options?.headers;
+
+    const response = await fetch(requestUrl, {
+      headers: requestHeader,
+      body: requestBody,
+      method: requestMethod,
+      // timeout: options?.timeout
+    })
+
+    const headerMap = new Headers();
+    response.headers.forEach(addLineToMap(headerMap));
+
+    return {
+      headers: headerMap,
+      status: response.status,
+      requestMethod,
+      requestUrl,
+      json: makeJsonHandler(response, requestUrl),
+      text: makeTextHandler(response, requestUrl),
+      bytes: async () => (await response.blob()).arrayBuffer(),
+    }
+
+  }
+
+
+  get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "GET",
+      ...opt,
+    });
+  }
+
+  postJson(
+    url: string,
+    body: any,
+    opt?: HttpRequestOptions,
+  ): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "POST",
+      body: JSON.stringify(body),
+      ...opt,
+    });
+  }
+
+  stop(): void {
+    // Nothing to do
+  }
+}
+
+function makeTextHandler(response: Response, requestUrl: string) {
+  return async function getJsonFromResponse(): Promise<any> {
+    let respText;
+    try {
+      respText = await response.text()
+    } catch (e) {
+      throw OperationFailedError.fromCode(
+        TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+        "Invalid JSON from HTTP response",
+        {
+          requestUrl,
+          httpStatusCode: response.status,
+        },
+      );
+    }
+    return respText
+  }
+}
+
+function makeJsonHandler(response: Response, requestUrl: string) {
+  return async function getJsonFromResponse(): Promise<any> {
+    let responseJson;
+    try {
+      responseJson = await response.json()
+    } catch (e) {
+      throw OperationFailedError.fromCode(
+        TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+        "Invalid JSON from HTTP response",
+        {
+          requestUrl,
+          httpStatusCode: response.status,
+        },
+      );
+    }
+    if (responseJson === null || typeof responseJson !== "object") {
+      throw OperationFailedError.fromCode(
+        TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+        "Invalid JSON from HTTP response",
+        {
+          requestUrl,
+          httpStatusCode: response.status,
+        },
+      );
+    }
+    return responseJson
+  }
+}
+
+function addLineToMap(map: { set(k: string, v: string): void }) {
+  return (line: string) => {
+    const parts = line.split(": ");
+    const headerName = parts.shift();
+    if (!headerName) {
+      logger.warn("skipping invalid header");
+      return;
+    }
+    const value = parts.join(": ");
+    map.set(headerName, value);
+  }
+}
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/utils/index.ts 
b/packages/taler-wallet-webextension/src/utils/index.ts
index 88f9bc4b..55898d18 100644
--- a/packages/taler-wallet-webextension/src/utils/index.ts
+++ b/packages/taler-wallet-webextension/src/utils/index.ts
@@ -225,7 +225,7 @@ function makeExtensionUrlWithParams(
   params?: { [name: string]: string | undefined },
 ): string {
   // eslint-disable-next-line no-undef
-  const innerUrl = new URL(chrome.extension.getURL("/" + url));
+  const innerUrl = new URL(chrome.runtime.getURL("/" + url));
   if (params) {
     const hParams = Object.keys(params)
       .map((k) => `${k}=${params[k]}`)
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts 
b/packages/taler-wallet-webextension/src/wxBackend.ts
index 10889f78..412f33f1 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -23,18 +23,6 @@
 /**
  * Imports.
  */
-import { isFirefox, getPermissionsApi } from "./compat";
-import { extendedPermissions } from "./permissions";
-import {
-  OpenedPromise,
-  openPromise,
-  openTalerDatabase,
-  makeErrorDetails,
-  deleteTalerDatabase,
-  DbAccess,
-  WalletStoresV1,
-  Wallet,
-} from "@gnu-taler/taler-wallet-core";
 import {
   classifyTalerUri,
   CoreApiResponse,
@@ -42,10 +30,19 @@ import {
   NotificationType,
   TalerErrorCode,
   TalerUriType,
-  WalletDiagnostics,
+  WalletDiagnostics
 } from "@gnu-taler/taler-util";
-import { BrowserHttpLib } from "./browserHttpLib";
+import {
+  DbAccess, deleteTalerDatabase, makeErrorDetails, OpenedPromise,
+  openPromise,
+  openTalerDatabase, Wallet, WalletStoresV1
+} from "@gnu-taler/taler-wallet-core";
 import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
+import { BrowserHttpLib } from "./browserHttpLib";
+import { getPermissionsApi, isFirefox } from "./compat";
+import { extendedPermissions } from "./permissions";
+import { SynchronousCryptoWorkerFactory } from 
"./serviceWorkerCryptoWorkerFactory.js";
+import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib";
 
 /**
  * Currently active wallet instance.  Might be unloaded and
@@ -188,10 +185,10 @@ function getTab(tabId: number): Promise<chrome.tabs.Tab> {
   });
 }
 
-function setBadgeText(options: chrome.browserAction.BadgeTextDetails): void {
+function setBadgeText(options: chrome.action.BadgeTextDetails): void {
   // not supported by all browsers ...
-  if (chrome && chrome.browserAction && chrome.browserAction.setBadgeText) {
-    chrome.browserAction.setBadgeText(options);
+  if (chrome && chrome.action && chrome.action.setBadgeText) {
+    chrome.action.setBadgeText(options);
   } else {
     console.warn("can't set badge text, not supported", options);
   }
@@ -214,7 +211,7 @@ function makeSyncWalletRedirect(
   oldUrl: string,
   params?: { [name: string]: string | undefined },
 ): Record<string, unknown> {
-  const innerUrl = new URL(chrome.extension.getURL(url));
+  const innerUrl = new URL(chrome.runtime.getURL(url));
   if (params) {
     const hParams = Object.keys(params)
       .map((k) => `${k}=${params[k]}`)
@@ -256,12 +253,22 @@ async function reinitWallet(): Promise<void> {
     walletInit.reject(e);
     return;
   }
-  const http = new BrowserHttpLib();
+  let httpLib;
+  let cryptoWorker;
+
+  if (chrome.runtime.getManifest().manifest_version === 3) {
+    httpLib = new ServiceWorkerHttpLib()
+    cryptoWorker = new SynchronousCryptoWorkerFactory();
+  } else {
+    httpLib = new BrowserHttpLib()
+    cryptoWorker = new BrowserCryptoWorkerFactory()
+  }
+
   console.log("setting wallet");
   const wallet = await Wallet.create(
     currentDatabase,
-    http,
-    new BrowserCryptoWorkerFactory(),
+    httpLib,
+    cryptoWorker,
   );
   try {
     await wallet.handleCoreApiRequest("initWallet", "native-init", {});
@@ -284,7 +291,9 @@ async function reinitWallet(): Promise<void> {
     console.log("error during wallet task loop", e);
   });
   // Useful for debugging in the background page.
-  (window as any).talerWallet = wallet;
+  if (typeof window !== "undefined") {
+    (window as any).talerWallet = wallet;
+  }
   currentWallet = wallet;
   walletInit.resolve();
 }
@@ -295,8 +304,8 @@ try {
   chrome.runtime.onInstalled.addListener((details) => {
     console.log("onInstalled with reason", details.reason);
     if (details.reason === "install") {
-      const url = chrome.extension.getURL("/static/wallet.html#/welcome");
-      chrome.tabs.create({ active: true, url: url });
+      const url = chrome.runtime.getURL("/static/wallet.html#/welcome");
+      chrome.tabs.create({ active: true, url });
     }
   });
 } catch (e) {
@@ -387,6 +396,10 @@ function headerListener(
 }
 
 function setupHeaderListener(): void {
+  if (chrome.runtime.getManifest().manifest_version === 3) {
+    console.error("cannot block request on manfest v3")
+    return
+  }
   console.log("setting up header listener");
   // Handlers for catching HTTP requests
   getPermissionsApi().contains(extendedPermissions, (result: boolean) => {
@@ -427,12 +440,14 @@ export async function wxMain(): Promise<void> {
     console.log("update available:", details);
     chrome.runtime.reload();
   });
-  reinitWallet();
+  const afterWalletIsInitialized = reinitWallet();
 
   // Handlers for messages coming directly from the content
   // script on the page
   chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
-    dispatch(req, sender, sendResponse);
+    afterWalletIsInitialized.then(() => {
+      dispatch(req, sender, sendResponse);
+    })
     return true;
   });
 
@@ -447,7 +462,9 @@ export async function wxMain(): Promise<void> {
   });
 
   try {
-    setupHeaderListener();
+    if (chrome.runtime.getManifest().manifest_version === 2) {
+      setupHeaderListener();
+    }
   } catch (e) {
     console.log(e);
   }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 33b57d49..c3931343 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -338,7 +338,7 @@ importers:
       '@storybook/preact': 6.4.9
       '@testing-library/preact': ^2.0.1
       '@testing-library/preact-hooks': ^1.1.0
-      '@types/chrome': ^0.0.174
+      '@types/chrome': 0.0.176
       '@types/history': ^4.7.8
       '@types/mocha': ^9.0.0
       '@types/node': ^17.0.8
@@ -393,7 +393,7 @@ importers:
       '@storybook/preact': 6.4.9_7ac135b2eab8a45315147b85be8cb430
       '@testing-library/preact': 2.0.1_preact@10.5.14
       '@testing-library/preact-hooks': 1.1.0_6273b572ba1ed58b8bbb2ee93959f9e4
-      '@types/chrome': 0.0.174
+      '@types/chrome': 0.0.176
       '@types/history': 4.7.9
       '@types/mocha': 9.0.0
       '@types/node': 17.0.8
@@ -9654,8 +9654,8 @@ packages:
       '@types/node': 17.0.8
     dev: true
 
-  /@types/chrome/0.0.174:
-    resolution: {integrity: 
sha512-x5kjvNdwDtOnT+vbnksj69pDl0u9P/WH9LbQWJawLqGgkBRO3AN/xzTxTPgLpp3IqCbuwfp7bRCHqkkaZguzWw==}
+  /@types/chrome/0.0.176:
+    resolution: {integrity: 
sha512-LOveFOMIUhMJjvRzZv5whGBpncP/gdJ4hcxeAqg94wGi6CyKaCmLgFSofgItf85GuLTl/0BQ6J/Y1e8BqZWfEg==}
     dependencies:
       '@types/filesystem': 0.0.32
       '@types/har-format': 1.2.8

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