From 88f7338d7c84ac2a774b483ccff25faf6ceeb879 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 30 Aug 2023 15:54:44 +0200 Subject: wallet-core,wallet-cli: properly serialize manual DB export --- packages/taler-wallet-cli/src/index.ts | 99 ++++------------------------------ 1 file changed, 9 insertions(+), 90 deletions(-) (limited to 'packages/taler-wallet-cli/src') diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 9d840e5bb..d7966a9ca 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -257,8 +257,7 @@ async function createLocalWallet( }, cryptoWorkerType: walletCliArgs.wallet.cryptoWorker as any, config: { - features: { - }, + features: {}, testing: { devModeActive: checkEnvFlag("TALER_WALLET_DEV_MODE"), denomselAllowLate: checkEnvFlag( @@ -651,9 +650,12 @@ walletCli }); break; case TalerUriAction.Reward: { - const res = await wallet.client.call(WalletApiOperation.PrepareReward, { - talerRewardUri: uri, - }); + const res = await wallet.client.call( + WalletApiOperation.PrepareReward, + { + talerRewardUri: uri, + }, + ); console.log("tip status", res); await wallet.client.call(WalletApiOperation.AcceptReward, { walletRewardId: res.walletRewardId, @@ -874,96 +876,13 @@ const backupCli = walletCli.subcommand("backupArgs", "backup", { help: "Subcommands for backups", }); -backupCli - .subcommand("setDeviceId", "set-device-id") - .requiredArgument("deviceId", clk.STRING, { - help: "new device ID", - }) - .action(async (args) => { - await withWallet(args, async (wallet) => { - await wallet.client.call(WalletApiOperation.SetWalletDeviceId, { - walletDeviceId: args.setDeviceId.deviceId, - }); - }); - }); - -backupCli.subcommand("exportPlain", "export-plain").action(async (args) => { +backupCli.subcommand("exportDb", "export-db").action(async (args) => { await withWallet(args, async (wallet) => { - const backup = await wallet.client.call( - WalletApiOperation.ExportBackupPlain, - {}, - ); + const backup = await wallet.client.call(WalletApiOperation.ExportDb, {}); console.log(JSON.stringify(backup, undefined, 2)); }); }); -backupCli.subcommand("recoverySave", "save-recovery").action(async (args) => { - await withWallet(args, async (wallet) => { - const recoveryJson = await wallet.client.call( - WalletApiOperation.ExportBackupRecovery, - {}, - ); - console.log(JSON.stringify(recoveryJson, undefined, 2)); - }); -}); - -backupCli.subcommand("run", "run").action(async (args) => { - await withWallet(args, async (wallet) => { - await wallet.client.call(WalletApiOperation.RunBackupCycle, {}); - }); -}); - -backupCli.subcommand("status", "status").action(async (args) => { - await withWallet(args, async (wallet) => { - const status = await wallet.client.call( - WalletApiOperation.GetBackupInfo, - {}, - ); - console.log(JSON.stringify(status, undefined, 2)); - }); -}); - -backupCli - .subcommand("recoveryLoad", "load-recovery") - .maybeOption("strategy", ["--strategy"], clk.STRING, { - help: "Strategy for resolving a conflict with the existing wallet key ('theirs' or 'ours')", - }) - .action(async (args) => { - await withWallet(args, async (wallet) => { - const data = JSON.parse(await read(process.stdin)); - let strategy: RecoveryMergeStrategy | undefined; - const stratStr = args.recoveryLoad.strategy; - if (stratStr) { - if (stratStr === "theirs") { - strategy = RecoveryMergeStrategy.Theirs; - } else if (stratStr === "ours") { - strategy = RecoveryMergeStrategy.Theirs; - } else { - throw Error("invalid recovery strategy"); - } - } - await wallet.client.call(WalletApiOperation.ImportBackupRecovery, { - recovery: data, - strategy, - }); - }); - }); - -backupCli - .subcommand("addProvider", "add-provider") - .requiredArgument("url", clk.STRING) - .maybeArgument("name", clk.STRING) - .flag("activate", ["--activate"]) - .action(async (args) => { - await withWallet(args, async (wallet) => { - await wallet.client.call(WalletApiOperation.AddBackupProvider, { - backupProviderBaseUrl: args.addProvider.url, - activate: args.addProvider.activate, - name: args.addProvider.name || args.addProvider.url, - }); - }); - }); - const depositCli = walletCli.subcommand("depositArgs", "deposit", { help: "Subcommands for depositing money to payto:// accounts", }); -- cgit v1.2.3 From 0a4782a0da631aba31dc0ecef7427df2467cc3e6 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 30 Aug 2023 17:18:18 +0200 Subject: wallet-core: make primitive backup import work --- packages/taler-wallet-cli/src/index.ts | 13 ++++-- packages/taler-wallet-core/src/db.ts | 78 +++++++++------------------------- 2 files changed, 29 insertions(+), 62 deletions(-) (limited to 'packages/taler-wallet-cli/src') diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index d7966a9ca..9652f84f3 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -883,6 +883,16 @@ backupCli.subcommand("exportDb", "export-db").action(async (args) => { }); }); +backupCli.subcommand("importDb", "import-db").action(async (args) => { + await withWallet(args, async (wallet) => { + const dumpRaw = await read(process.stdin); + const dump = JSON.parse(dumpRaw); + await wallet.client.call(WalletApiOperation.ImportDb, { + dump, + }); + }); +}); + const depositCli = walletCli.subcommand("depositArgs", "deposit", { help: "Subcommands for depositing money to payto:// accounts", }); @@ -1600,6 +1610,3 @@ async function read(stream: NodeJS.ReadStream) { export function main() { walletCli.run(); } -function classifyTalerUri(uri: string) { - throw new Error("Function not implemented."); -} diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index efc0333f4..e68385267 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -2890,15 +2890,9 @@ export async function exportDb(idb: IDBFactory): Promise { return dbDump; } -export interface DatabaseDump { - name: string; - stores: { [s: string]: any }; - version: string; -} - async function recoverFromDump( db: IDBDatabase, - dump: DatabaseDump, + dbDump: DbDumpDatabase, ): Promise { return new Promise((resolve, reject) => { const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite"); @@ -2907,67 +2901,33 @@ async function recoverFromDump( }); for (let i = 0; i < db.objectStoreNames.length; i++) { const name = db.objectStoreNames[i]; - const storeDump = dump.stores[name]; + const storeDump = dbDump.stores[name]; if (!storeDump) continue; - Object.keys(storeDump).forEach(async (key) => { - const value = storeDump[key]; - if (!value) return; - tx.objectStore(name).put(value); - }); + for (let rec of storeDump.records) { + tx.objectStore(name).put(rec.value, rec.key); + } } tx.commit(); }); } -export async function importDb(db: IDBDatabase, object: any): Promise { - if ("name" in object && "stores" in object && "version" in object) { - // looks like a database dump - const dump = object as DatabaseDump; - return recoverFromDump(db, dump); - } - - if ("databases" in object && "$types" in object) { - // looks like a IDBDatabase - const someDatabase = object.databases; - - if (TALER_WALLET_META_DB_NAME in someDatabase) { - //looks like a taler database - const currentMainDbValue = - someDatabase[TALER_WALLET_META_DB_NAME].objectStores.metaConfig - .records[0].value.value; - - if (currentMainDbValue !== TALER_WALLET_MAIN_DB_NAME) { - console.log("not the current database version"); - } - - const talerDb = someDatabase[currentMainDbValue]; - - const objectStoreNames = Object.keys(talerDb.objectStores); - - const dump: DatabaseDump = { - name: talerDb.schema.databaseName, - version: talerDb.schema.databaseVersion, - stores: {}, - }; - - for (let i = 0; i < objectStoreNames.length; i++) { - const name = objectStoreNames[i]; - const storeDump = {} as { [s: string]: any }; - dump.stores[name] = storeDump; - talerDb.objectStores[name].records.map((r: any) => { - const pkey = r.primaryKey; - const key = - typeof pkey === "string" || typeof pkey === "number" - ? pkey - : pkey.join(","); - storeDump[key] = r.value; - }); - } +function checkDbDump(x: any): x is DbDump { + return "databases" in x; +} - return recoverFromDump(db, dump); +export async function importDb(db: IDBDatabase, dumpJson: any): Promise { + const d = dumpJson; + if (checkDbDump(d)) { + const walletDb = d.databases[TALER_WALLET_MAIN_DB_NAME]; + if (!walletDb) { + throw Error( + `unable to import, main wallet database (${TALER_WALLET_MAIN_DB_NAME}) not found`, + ); } + await recoverFromDump(db, walletDb); + } else { + throw Error("unable to import, doesn't look like a valid DB dump"); } - throw Error("could not import database"); } export interface FixupDescription { -- cgit v1.2.3 From 8fed5b4b7370431602c0b25f8142009e61f7b906 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 30 Aug 2023 18:33:56 +0200 Subject: wallet-core: allow version change event --- packages/taler-wallet-cli/src/index.ts | 10 +++++++++ packages/taler-wallet-core/src/db.ts | 14 ++++++------- packages/taler-wallet-core/src/util/query.ts | 12 +++++------ packages/taler-wallet-core/src/wallet.ts | 24 ++++++++++++---------- .../taler-wallet-webextension/src/wxBackend.ts | 1 - 5 files changed, 36 insertions(+), 25 deletions(-) (limited to 'packages/taler-wallet-cli/src') diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 9652f84f3..36e7f7768 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -883,6 +883,16 @@ backupCli.subcommand("exportDb", "export-db").action(async (args) => { }); }); +backupCli.subcommand("storeBackup", "store-backup").action(async (args) => { + await withWallet(args, async (wallet) => { + const resp = await wallet.client.call( + WalletApiOperation.CreateStoredBackup, + {}, + ); + console.log(JSON.stringify(resp, undefined, 2)); + }); +}); + backupCli.subcommand("importDb", "import-db").action(async (args) => { await withWallet(args, async (wallet) => { const dumpRaw = await read(process.stdin); diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 1255e8c71..a642c0203 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -114,6 +114,11 @@ export const TALER_WALLET_MAIN_DB_NAME = "taler-wallet-main-v9"; */ export const TALER_WALLET_META_DB_NAME = "taler-wallet-meta"; +/** + * Stored backups, mainly created when manually importing a backup. + */ +export const TALER_WALLET_STORED_BACKUPS_DB_NAME = "taler-wallet-stored-backups"; + export const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; /** @@ -2773,15 +2778,10 @@ export interface StoredBackupMeta { name: string; } -export interface StoredBackupData { - name: string; - data: any; -} - export const StoredBackupStores = { backupMeta: describeStore( "backupMeta", - describeContents({ keyPath: "name" }), + describeContents({ keyPath: "name" }), {}, ), backupData: describeStore("backupData", describeContents({}), {}), @@ -3250,7 +3250,7 @@ export async function openStoredBackupsDatabase( ): Promise> { const backupsDbHandle = await openDatabase( idbFactory, - TALER_WALLET_META_DB_NAME, + TALER_WALLET_STORED_BACKUPS_DB_NAME, 1, () => {}, onStoredBackupsDbUpgradeNeeded, diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts index eb2bddec1..7697ed3db 100644 --- a/packages/taler-wallet-core/src/util/query.ts +++ b/packages/taler-wallet-core/src/util/query.ts @@ -376,8 +376,8 @@ export interface InsertResponse { export interface StoreReadWriteAccessor { get(key: IDBValidKey): Promise; iter(query?: IDBValidKey): ResultStream; - put(r: RecordType): Promise; - add(r: RecordType): Promise; + put(r: RecordType, key?: IDBValidKey): Promise; + add(r: RecordType, key?: IDBValidKey): Promise; delete(key: IDBValidKey): Promise; indexes: GetIndexReadWriteAccess; } @@ -652,15 +652,15 @@ function makeWriteContext( const req = tx.objectStore(storeName).openCursor(query); return new ResultStream(req); }, - async add(r) { - const req = tx.objectStore(storeName).add(r); + async add(r, k) { + const req = tx.objectStore(storeName).add(r, k); const key = await requestToPromise(req); return { key: key, }; }, - async put(r) { - const req = tx.objectStore(storeName).put(r); + async put(r, k) { + const req = tx.objectStore(storeName).put(r, k); const key = await requestToPromise(req); return { key: key, diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 283539a08..626409dd6 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -343,9 +343,8 @@ async function callOperationHandler( return await processRecoupGroup(ws, pending.recoupGroupId); case PendingTaskType.ExchangeCheckRefresh: return await autoRefresh(ws, pending.exchangeBaseUrl); - case PendingTaskType.Deposit: { + case PendingTaskType.Deposit: return await processDepositGroup(ws, pending.depositGroupId); - } case PendingTaskType.Backup: return await processBackupForProvider(ws, pending.backupProviderBaseUrl); case PendingTaskType.PeerPushDebit: @@ -1031,9 +1030,15 @@ async function createStoredBackup( const backup = await exportDb(ws.idb); const backupsDb = await openStoredBackupsDatabase(ws.idb); const name = `backup-${new Date().getTime()}`; - backupsDb.mktxAll().runReadWrite(async (tx) => {}); - - throw Error("not implemented"); + await backupsDb.mktxAll().runReadWrite(async (tx) => { + await tx.backupMeta.add({ + name, + }); + await tx.backupData.add(backup, name); + }); + return { + name, + }; } /** @@ -1634,7 +1639,7 @@ export function getVersion(ws: InternalWalletState): WalletCoreVersion { /** * Handle a request to the wallet-core API. */ -export async function handleCoreApiRequest( +async function handleCoreApiRequest( ws: InternalWalletState, operation: string, id: string, @@ -1849,11 +1854,8 @@ class InternalWalletStateImpl implements InternalWalletState { if (this._db) { return; } - const myVersionChange = (): Promise => { - logger.error("version change requested, should not happen"); - throw Error( - "BUG: wallet DB version change event can't happen with memory IDB", - ); + const myVersionChange = async (): Promise => { + logger.info("version change requested for Taler DB"); }; const myDb = await openTalerDatabase(this.idb, myVersionChange); this._db = myDb; diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index b7484164d..e7385abe5 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -50,7 +50,6 @@ import { exportDb, importDb, openPromise, - openTalerDatabase, } from "@gnu-taler/taler-wallet-core"; import { MessageFromBackend, -- cgit v1.2.3