From e319e99ef9657f68c82e7b37dd928c126d865ecb Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 7 Jan 2021 15:01:23 +0100 Subject: [PATCH] restore denom selection on import --- packages/taler-wallet-cli/src/index.ts | 22 ++++++-- .../src/operations/backup.ts | 53 +++++++++++++++---- .../taler-wallet-core/src/operations/state.ts | 4 ++ .../src/types/backupTypes.ts | 1 + packages/taler-wallet-core/src/wallet.ts | 9 ++++ .../taler-wallet-webextension/manifest.json | 4 +- .../taler-wallet-webextension/package.json | 2 +- 7 files changed, 79 insertions(+), 16 deletions(-) diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index e8e09f8fa..f4970e73d 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -36,9 +36,6 @@ import { NodeThreadCryptoWorkerFactory, CryptoApi, rsaBlind, - encodeCrock, - rsaUnblind, - rsaVerify, } from "taler-wallet-core"; import * as clk from "./clk"; import { deepStrictEqual } from "assert"; @@ -401,6 +398,25 @@ exchangesCli }); }); +const backupCli = walletCli.subcommand("backupArgs", "backup", { + help: "Subcommands for backups", +}); + +backupCli.subcommand("exportPlain", "export-plain").action(async (args) => { + await withWallet(args, async (wallet) => { + const backup = await wallet.exportBackupPlain(); + console.log(JSON.stringify(backup, undefined, 2)); + }); +}); + + +backupCli.subcommand("importPlain", "import-plain").action(async (args) => { + await withWallet(args, async (wallet) => { + const data = JSON.parse(await read(process.stdin)); + await wallet.importBackupPlain(data); + }); +}); + const advancedCli = walletCli.subcommand("advancedArgs", "advanced", { help: "Subcommands for advanced operations (only use if you know what you're doing!).", diff --git a/packages/taler-wallet-core/src/operations/backup.ts b/packages/taler-wallet-core/src/operations/backup.ts index b82e63ff2..4f736c3df 100644 --- a/packages/taler-wallet-core/src/operations/backup.ts +++ b/packages/taler-wallet-core/src/operations/backup.ts @@ -588,10 +588,6 @@ export async function exportBackup( ); } -export interface BackupRequest { - backupBlob: any; -} - export async function encryptBackup( config: WalletBackupConfState, blob: WalletBackupContentV1, @@ -621,7 +617,7 @@ interface BackupCryptoPrecomputedData { /** * Compute cryptographic values for a backup blob. - * + * * FIXME: Take data that we already know from the DB. * FIXME: Move computations into crypto worker. */ @@ -650,7 +646,7 @@ async function computeBackupCryptoData( cryptoData.coinPrivToCompletedCoin[backupCoin.coin_priv] = { coinEvHash: encodeCrock(hash(blindedCoin)), coinPub, - } + }; } cryptoData.denomPubToHash[backupDenom.denom_pub] = encodeCrock( hash(decodeCrock(backupDenom.denom_pub)), @@ -777,16 +773,35 @@ async function recoverPayCoinSelection( }; } -function getDenomSelStateFromBackup( +async function getDenomSelStateFromBackup( tx: TransactionHandle, + exchangeBaseUrl: string, sel: BackupDenomSel, ): Promise { - throw Error("not implemented"); + const d0 = await tx.get(Stores.denominations, [exchangeBaseUrl, sel[0].denom_pub_hash]); + checkBackupInvariant(!!d0); + const selectedDenoms: { + denomPubHash: string; + count: number; + }[] = []; + let totalCoinValue = Amounts.getZero(d0.value.currency); + let totalWithdrawCost = Amounts.getZero(d0.value.currency); + for (const s of sel) { + const d = await tx.get(Stores.denominations, [exchangeBaseUrl, s.denom_pub_hash]); + checkBackupInvariant(!!d); + totalCoinValue = Amounts.add(totalCoinValue, d.value).amount; + totalWithdrawCost = Amounts.add(totalWithdrawCost, d.value, d.feeWithdraw).amount; + } + return { + selectedDenoms, + totalCoinValue, + totalWithdrawCost, + } } export async function importBackup( ws: InternalWalletState, - backupRequest: BackupRequest, + backupBlobArg: any, cryptoComp: BackupCryptoPrecomputedData, ): Promise { await provideBackupState(ws); @@ -807,7 +822,7 @@ export async function importBackup( ], async (tx) => { // FIXME: validate schema! - const backupBlob = backupRequest.backupBlob as WalletBackupContentV1; + const backupBlob = backupBlobArg as WalletBackupContentV1; // FIXME: validate version @@ -993,6 +1008,7 @@ export async function importBackup( reserveStatus: ReserveRecordStatus.QUERYING_STATUS, initialDenomSel: await getDenomSelStateFromBackup( tx, + backupExchange.base_url, backupReserve.initial_selected_denoms, ), }); @@ -1006,6 +1022,7 @@ export async function importBackup( await tx.put(Stores.withdrawalGroups, { denomsSel: await getDenomSelStateFromBackup( tx, + backupExchange.base_url, backupWg.selected_denoms, ), exchangeBaseUrl: backupExchange.base_url, @@ -1300,9 +1317,12 @@ export async function importBackup( | undefined )[] = []; for (const oldCoin of backupRefreshGroup.old_coins) { + const c = await tx.get(Stores.coins, oldCoin.coin_pub); + checkBackupInvariant(!!c); if (oldCoin.refresh_session) { const denomSel = await getDenomSelStateFromBackup( tx, + c.exchangeBaseUrl, oldCoin.refresh_session.new_denoms, ); refreshSessionPerCoin.push({ @@ -1346,6 +1366,7 @@ export async function importBackup( if (!existingTip) { const denomsSel = await getDenomSelStateFromBackup( tx, + backupTip.exchange_base_url, backupTip.selected_denoms, ); await tx.put(Stores.tips, { @@ -1530,6 +1551,18 @@ export interface BackupInfo { providers: ProviderInfo[]; } +export async function importBackupPlain( + ws: InternalWalletState, + blob: any, +): Promise { + // FIXME: parse + const backup: WalletBackupContentV1 = blob; + + const cryptoData = await computeBackupCryptoData(ws.cryptoApi, backup); + + await importBackup(ws, blob, cryptoData); +} + /** * Get information about the current state of wallet backups. */ diff --git a/packages/taler-wallet-core/src/operations/state.ts b/packages/taler-wallet-core/src/operations/state.ts index 11695f6d0..1733f13bb 100644 --- a/packages/taler-wallet-core/src/operations/state.ts +++ b/packages/taler-wallet-core/src/operations/state.ts @@ -55,6 +55,10 @@ export class InternalWalletState { private resourceLocks: Set = new Set(); constructor( + // FIXME: Make this a getter and make + // the actual value nullable. + // Check if we are in a DB migration / garbage collection + // and throw an error in that case. public db: Database, public http: HttpRequestLibrary, cryptoWorkerFactory: CryptoWorkerFactory, diff --git a/packages/taler-wallet-core/src/types/backupTypes.ts b/packages/taler-wallet-core/src/types/backupTypes.ts index fdc244d8f..f7bd8784d 100644 --- a/packages/taler-wallet-core/src/types/backupTypes.ts +++ b/packages/taler-wallet-core/src/types/backupTypes.ts @@ -39,6 +39,7 @@ * 10. Re-denominated payments/refreshes are not shown properly in the total * payment cost. * 11. Failed refunds do not have any information about why they failed. + * => This should go into the general "error reports" * * Questions: * 1. What happens when two backups are merged that have diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index a09bfcc0f..b917246fc 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -161,6 +161,7 @@ import { codecForAddBackupProviderRequest, runBackupCycle, exportBackup, + importBackupPlain, } from "./operations/backup"; const builtinCurrencies: CurrencyRecord[] = [ @@ -933,6 +934,14 @@ export class Wallet { return testPay(this.ws.http, this, args); } + async exportBackupPlain() { + return exportBackup(this.ws); + } + + async importBackupPlain(backup: any) { + return importBackupPlain(this.ws, backup); + } + /** * Implementation of the "wallet-core" API. */ diff --git a/packages/taler-wallet-webextension/manifest.json b/packages/taler-wallet-webextension/manifest.json index 44dfe8cdd..8d25d062e 100644 --- a/packages/taler-wallet-webextension/manifest.json +++ b/packages/taler-wallet-webextension/manifest.json @@ -4,8 +4,8 @@ "name": "GNU Taler Wallet (git)", "description": "Privacy preserving and transparent payments", "author": "GNU Taler Developers", - "version": "0.8.0.5", - "version_name": "0.8.1-dev.1", + "version": "0.8.0.6", + "version_name": "0.8.1-dev.2", "minimum_chrome_version": "51", "minimum_opera_version": "36", diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json index 5dc1f1b04..971cb3bf6 100644 --- a/packages/taler-wallet-webextension/package.json +++ b/packages/taler-wallet-webextension/package.json @@ -1,6 +1,6 @@ { "name": "taler-wallet-webextension", - "version": "0.8.1-dev.1", + "version": "0.8.1-dev.2", "description": "GNU Taler Wallet browser extension", "main": "./build/index.js", "types": "./build/index.d.ts",