gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 03/03: wallet-core: implement enabling/disabling dev


From: gnunet
Subject: [taler-wallet-core] 03/03: wallet-core: implement enabling/disabling dev mode
Date: Wed, 12 Oct 2022 22:27:56 +0200

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

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

commit ded00b680a776d03cd8c928354c87c0be8690f56
Author: Florian Dold <florian@dold.me>
AuthorDate: Wed Oct 12 22:27:50 2022 +0200

    wallet-core: implement enabling/disabling dev mode
---
 packages/taler-util/src/walletTypes.ts             |   1 +
 packages/taler-wallet-core/src/db.ts               |  11 +-
 packages/taler-wallet-core/src/dev-experiments.ts  | 118 ++++++++++++++++++++-
 .../taler-wallet-core/src/internal-wallet-state.ts |   2 +
 .../src/operations/backup/export.ts                |   4 +-
 .../src/operations/backup/index.ts                 |   8 +-
 .../src/operations/backup/state.ts                 |  20 ++--
 packages/taler-wallet-core/src/util/http.ts        |   4 +
 packages/taler-wallet-core/src/wallet.ts           |   9 +-
 9 files changed, 156 insertions(+), 21 deletions(-)

diff --git a/packages/taler-util/src/walletTypes.ts 
b/packages/taler-util/src/walletTypes.ts
index 05b18fe6d..a1fa9b439 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -605,6 +605,7 @@ export interface WalletCoreVersion {
   exchange: string;
   merchant: string;
   bank: string;
+  devMode?: boolean;
 }
 
 export interface KnownBankAccountsInfo {
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 539a925c1..f4cdb68c1 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1240,7 +1240,11 @@ export interface PurchaseRecord {
   refundAmountAwaiting: AmountJson | undefined;
 }
 
-export const WALLET_BACKUP_STATE_KEY = "walletBackupState";
+export enum ConfigRecordKey {
+  WalletBackupState = "walletBackupState",
+  CurrencyDefaultsApplied = "currencyDefaultsApplied",
+  DevMode = "devMode",
+}
 
 /**
  * Configuration key/value entries to configure
@@ -1248,10 +1252,11 @@ export const WALLET_BACKUP_STATE_KEY = 
"walletBackupState";
  */
 export type ConfigRecord =
   | {
-      key: typeof WALLET_BACKUP_STATE_KEY;
+      key: ConfigRecordKey.WalletBackupState;
       value: WalletBackupConfState;
     }
-  | { key: "currencyDefaultsApplied"; value: boolean };
+  | { key: ConfigRecordKey.CurrencyDefaultsApplied; value: boolean }
+  | { key: ConfigRecordKey.DevMode; value: boolean };
 
 export interface WalletBackupConfState {
   deviceId: string;
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts 
b/packages/taler-wallet-core/src/dev-experiments.ts
index 8e2ce5882..c3167b3e4 100644
--- a/packages/taler-wallet-core/src/dev-experiments.ts
+++ b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -25,14 +25,130 @@
  * Imports.
  */
 
-import { Logger } from "@gnu-taler/taler-util";
+import { Logger, parseDevExperimentUri } from "@gnu-taler/taler-util";
+import { ConfigRecordKey } from "./db.js";
 import { InternalWalletState } from "./internal-wallet-state.js";
+import {
+  HttpRequestLibrary,
+  HttpRequestOptions,
+  HttpResponse,
+} from "./util/http.js";
 
 const logger = new Logger("dev-experiments.ts");
 
+/**
+ * Apply a dev experiment to the wallet database / state.
+ */
 export async function applyDevExperiment(
   ws: InternalWalletState,
   uri: string,
 ): Promise<void> {
   logger.info(`applying dev experiment ${uri}`);
+  const parsedUri = parseDevExperimentUri(uri);
+  if (!parsedUri) {
+    logger.info("unable to parse dev experiment URI");
+    return;
+  }
+  if (parsedUri.devExperimentId == "enable-devmode") {
+    logger.info("enabling devmode");
+    await ws.db
+      .mktx((x) => [x.config])
+      .runReadWrite(async (tx) => {
+        tx.config.put({
+          key: ConfigRecordKey.DevMode,
+          value: true,
+        });
+      });
+    await maybeInitDevMode(ws);
+    return;
+  }
+  if (parsedUri.devExperimentId === "disable-devmode") {
+    logger.info("disabling devmode");
+    await ws.db
+      .mktx((x) => [x.config])
+      .runReadWrite(async (tx) => {
+        tx.config.put({
+          key: ConfigRecordKey.DevMode,
+          value: false,
+        });
+      });
+    await leaveDevMode(ws);
+    return;
+  }
+  if (!ws.devModeActive) {
+    throw Error(
+      "can't handle devmode URI (other than enable-devmode) unless devmode is 
active",
+    );
+  }
+  throw Error(`dev-experiment id not understood ${parsedUri.devExperimentId}`);
+}
+
+/**
+ * Enter dev mode, if the wallet's config entry in the DB demands it.
+ */
+export async function maybeInitDevMode(ws: InternalWalletState): Promise<void> 
{
+  const devMode = await ws.db
+    .mktx((x) => [x.config])
+    .runReadOnly(async (tx) => {
+      const rec = await tx.config.get(ConfigRecordKey.DevMode);
+      if (!rec || rec.key !== ConfigRecordKey.DevMode) {
+        return false;
+      }
+      return rec.value;
+    });
+  if (!devMode) {
+    ws.devModeActive = false;
+    return;
+  }
+  ws.devModeActive = true;
+  if (ws.http instanceof DevExperimentHttpLib) {
+    return;
+  }
+  ws.http = new DevExperimentHttpLib(ws.http);
+}
+
+export async function leaveDevMode(ws: InternalWalletState): Promise<void> {
+  if (ws.http instanceof DevExperimentHttpLib) {
+    ws.http = ws.http.underlyingLib;
+  }
+  ws.devModeActive = false;
+}
+
+export class DevExperimentHttpLib implements HttpRequestLibrary {
+  _isDevExperimentLib = true;
+  underlyingLib: HttpRequestLibrary;
+
+  constructor(lib: HttpRequestLibrary) {
+    this.underlyingLib = lib;
+  }
+
+  get(
+    url: string,
+    opt?: HttpRequestOptions | undefined,
+  ): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "GET",
+      ...opt,
+    });
+  }
+
+  postJson(
+    url: string,
+    body: any,
+    opt?: HttpRequestOptions | undefined,
+  ): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "POST",
+      body,
+      ...opt,
+    });
+  }
+
+  fetch(
+    url: string,
+    opt?: HttpRequestOptions | undefined,
+  ): Promise<HttpResponse> {
+    logger.info(`devexperiment httplib ${url}`);
+    return this.underlyingLib.fetch(url, opt);
+  }
 }
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts 
b/packages/taler-wallet-core/src/internal-wallet-state.ts
index 6c7d943cb..bc956bd17 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -191,6 +191,8 @@ export interface InternalWalletState {
   merchantOps: MerchantOperations;
   refreshOps: RefreshOperations;
 
+  devModeActive: boolean;
+
   getDenomInfo(
     ws: InternalWalletState,
     tx: GetReadOnlyAccess<{
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts 
b/packages/taler-wallet-core/src/operations/backup/export.ts
index a3c4c8d99..c7890b5d8 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -64,11 +64,11 @@ import {
 import {
   CoinSourceType,
   CoinStatus,
+  ConfigRecordKey,
   DenominationRecord,
   PurchaseStatus,
   RefreshCoinStatus,
   RefundState,
-  WALLET_BACKUP_STATE_KEY,
   WithdrawalGroupStatus,
   WithdrawalRecordType,
 } from "../../db.js";
@@ -547,7 +547,7 @@ export async function exportBackup(
           )} and nonce to ${bs.lastBackupNonce}`,
         );
         await tx.config.put({
-          key: WALLET_BACKUP_STATE_KEY,
+          key: ConfigRecordKey.WalletBackupState,
           value: bs,
         });
       } else {
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts 
b/packages/taler-wallet-core/src/operations/backup/index.ts
index 3d3ebf04a..8e5e69097 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -74,8 +74,8 @@ import {
   BackupProviderStateTag,
   BackupProviderTerms,
   ConfigRecord,
+  ConfigRecordKey,
   WalletBackupConfState,
-  WALLET_BACKUP_STATE_KEY,
 } from "../../db.js";
 import { InternalWalletState } from "../../internal-wallet-state.js";
 import {
@@ -861,10 +861,12 @@ async function backupRecoveryTheirs(
     .mktx((x) => [x.config, x.backupProviders])
     .runReadWrite(async (tx) => {
       let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
-        WALLET_BACKUP_STATE_KEY,
+        ConfigRecordKey.WalletBackupState,
       );
       checkDbInvariant(!!backupStateEntry);
-      checkDbInvariant(backupStateEntry.key === WALLET_BACKUP_STATE_KEY);
+      checkDbInvariant(
+        backupStateEntry.key === ConfigRecordKey.WalletBackupState,
+      );
       backupStateEntry.value.lastBackupNonce = undefined;
       backupStateEntry.value.lastBackupTimestamp = undefined;
       backupStateEntry.value.lastBackupCheckTimestamp = undefined;
diff --git a/packages/taler-wallet-core/src/operations/backup/state.ts 
b/packages/taler-wallet-core/src/operations/backup/state.ts
index 2efd9be8e..b8dbb15c1 100644
--- a/packages/taler-wallet-core/src/operations/backup/state.ts
+++ b/packages/taler-wallet-core/src/operations/backup/state.ts
@@ -17,9 +17,9 @@
 import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
 import {
   ConfigRecord,
+  ConfigRecordKey,
   WalletBackupConfState,
   WalletStoresV1,
-  WALLET_BACKUP_STATE_KEY,
 } from "../../db.js";
 import { checkDbInvariant } from "../../util/invariants.js";
 import { GetReadOnlyAccess } from "../../util/query.js";
@@ -31,10 +31,10 @@ export async function provideBackupState(
   const bs: ConfigRecord | undefined = await ws.db
     .mktx((stores) => [stores.config])
     .runReadOnly(async (tx) => {
-      return await tx.config.get(WALLET_BACKUP_STATE_KEY);
+      return await tx.config.get(ConfigRecordKey.WalletBackupState);
     });
   if (bs) {
-    checkDbInvariant(bs.key === WALLET_BACKUP_STATE_KEY);
+    checkDbInvariant(bs.key === ConfigRecordKey.WalletBackupState);
     return bs.value;
   }
   // We need to generate the key outside of the transaction
@@ -48,11 +48,11 @@ export async function provideBackupState(
     .mktx((x) => [x.config])
     .runReadWrite(async (tx) => {
       let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
-        WALLET_BACKUP_STATE_KEY,
+        ConfigRecordKey.WalletBackupState,
       );
       if (!backupStateEntry) {
         backupStateEntry = {
-          key: WALLET_BACKUP_STATE_KEY,
+          key: ConfigRecordKey.WalletBackupState,
           value: {
             deviceId,
             walletRootPub: k.pub,
@@ -62,7 +62,7 @@ export async function provideBackupState(
         };
         await tx.config.put(backupStateEntry);
       }
-      checkDbInvariant(backupStateEntry.key === WALLET_BACKUP_STATE_KEY);
+      checkDbInvariant(backupStateEntry.key === 
ConfigRecordKey.WalletBackupState);
       return backupStateEntry.value;
     });
 }
@@ -71,9 +71,9 @@ export async function getWalletBackupState(
   ws: InternalWalletState,
   tx: GetReadOnlyAccess<{ config: typeof WalletStoresV1.config }>,
 ): Promise<WalletBackupConfState> {
-  const bs = await tx.config.get(WALLET_BACKUP_STATE_KEY);
+  const bs = await tx.config.get(ConfigRecordKey.WalletBackupState);
   checkDbInvariant(!!bs, "wallet backup state should be in DB");
-  checkDbInvariant(bs.key === WALLET_BACKUP_STATE_KEY);
+  checkDbInvariant(bs.key === ConfigRecordKey.WalletBackupState);
   return bs.value;
 }
 
@@ -86,11 +86,11 @@ export async function setWalletDeviceId(
     .mktx((x) => [x.config])
     .runReadWrite(async (tx) => {
       let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
-        WALLET_BACKUP_STATE_KEY,
+        ConfigRecordKey.WalletBackupState,
       );
       if (
         !backupStateEntry ||
-        backupStateEntry.key !== WALLET_BACKUP_STATE_KEY
+        backupStateEntry.key !== ConfigRecordKey.WalletBackupState
       ) {
         return;
       }
diff --git a/packages/taler-wallet-core/src/util/http.ts 
b/packages/taler-wallet-core/src/util/http.ts
index 58edd289b..0489f920b 100644
--- a/packages/taler-wallet-core/src/util/http.ts
+++ b/packages/taler-wallet-core/src/util/http.ts
@@ -111,11 +111,15 @@ export class Headers {
 export interface HttpRequestLibrary {
   /**
    * Make an HTTP GET request.
+   *
+   * FIXME: Get rid of this, we want the API surface to be minimal.
    */
   get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
 
   /**
    * Make an HTTP POST request with a JSON body.
+   *
+   * FIXME: Get rid of this, we want the API surface to be minimal.
    */
   postJson(
     url: string,
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index e25b4bd95..48d379931 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -105,12 +105,13 @@ import {
   AuditorTrustRecord,
   CoinSourceType,
   CoinStatus,
+  ConfigRecordKey,
   DenominationRecord,
   exportDb,
   importDb,
   WalletStoresV1,
 } from "./db.js";
-import { applyDevExperiment } from "./dev-experiments.js";
+import { applyDevExperiment, maybeInitDevMode } from "./dev-experiments.js";
 import { getErrorDetailFromException, TalerError } from "./errors.js";
 import {
   ActiveLongpollInfo,
@@ -476,7 +477,7 @@ async function fillDefaults(ws: InternalWalletState): 
Promise<void> {
         provideExchangeRecordInTx(ws, tx, baseUrl, now);
       }
       await tx.config.put({
-        key: "currencyDefaultsApplied",
+        key: ConfigRecordKey.CurrencyDefaultsApplied,
         value: true,
       });
     });
@@ -970,6 +971,7 @@ async function dispatchRequestInternal(
         logger.trace("filling defaults");
         await fillDefaults(ws);
       }
+      await maybeInitDevMode(ws);
       return {};
     }
     case "withdrawTestkudos": {
@@ -1339,6 +1341,7 @@ async function dispatchRequestInternal(
         exchange: WALLET_EXCHANGE_PROTOCOL_VERSION,
         merchant: WALLET_MERCHANT_PROTOCOL_VERSION,
         bank: WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
+        devMode: ws.devModeActive,
       };
       return version;
     }
@@ -1480,6 +1483,8 @@ class InternalWalletStateImpl implements 
InternalWalletState {
 
   initCalled = false;
 
+  devModeActive = false;
+
   exchangeOps: ExchangeOperations = {
     getExchangeDetails,
     getExchangeTrust,

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