restore denom selection on import
This commit is contained in:
parent
3773a4cdff
commit
e319e99ef9
@ -36,9 +36,6 @@ import {
|
|||||||
NodeThreadCryptoWorkerFactory,
|
NodeThreadCryptoWorkerFactory,
|
||||||
CryptoApi,
|
CryptoApi,
|
||||||
rsaBlind,
|
rsaBlind,
|
||||||
encodeCrock,
|
|
||||||
rsaUnblind,
|
|
||||||
rsaVerify,
|
|
||||||
} from "taler-wallet-core";
|
} from "taler-wallet-core";
|
||||||
import * as clk from "./clk";
|
import * as clk from "./clk";
|
||||||
import { deepStrictEqual } from "assert";
|
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", {
|
const advancedCli = walletCli.subcommand("advancedArgs", "advanced", {
|
||||||
help:
|
help:
|
||||||
"Subcommands for advanced operations (only use if you know what you're doing!).",
|
"Subcommands for advanced operations (only use if you know what you're doing!).",
|
||||||
|
@ -588,10 +588,6 @@ export async function exportBackup(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BackupRequest {
|
|
||||||
backupBlob: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function encryptBackup(
|
export async function encryptBackup(
|
||||||
config: WalletBackupConfState,
|
config: WalletBackupConfState,
|
||||||
blob: WalletBackupContentV1,
|
blob: WalletBackupContentV1,
|
||||||
@ -650,7 +646,7 @@ async function computeBackupCryptoData(
|
|||||||
cryptoData.coinPrivToCompletedCoin[backupCoin.coin_priv] = {
|
cryptoData.coinPrivToCompletedCoin[backupCoin.coin_priv] = {
|
||||||
coinEvHash: encodeCrock(hash(blindedCoin)),
|
coinEvHash: encodeCrock(hash(blindedCoin)),
|
||||||
coinPub,
|
coinPub,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
cryptoData.denomPubToHash[backupDenom.denom_pub] = encodeCrock(
|
cryptoData.denomPubToHash[backupDenom.denom_pub] = encodeCrock(
|
||||||
hash(decodeCrock(backupDenom.denom_pub)),
|
hash(decodeCrock(backupDenom.denom_pub)),
|
||||||
@ -777,16 +773,35 @@ async function recoverPayCoinSelection(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDenomSelStateFromBackup(
|
async function getDenomSelStateFromBackup(
|
||||||
tx: TransactionHandle<typeof Stores.denominations>,
|
tx: TransactionHandle<typeof Stores.denominations>,
|
||||||
|
exchangeBaseUrl: string,
|
||||||
sel: BackupDenomSel,
|
sel: BackupDenomSel,
|
||||||
): Promise<DenomSelectionState> {
|
): Promise<DenomSelectionState> {
|
||||||
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(
|
export async function importBackup(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
backupRequest: BackupRequest,
|
backupBlobArg: any,
|
||||||
cryptoComp: BackupCryptoPrecomputedData,
|
cryptoComp: BackupCryptoPrecomputedData,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await provideBackupState(ws);
|
await provideBackupState(ws);
|
||||||
@ -807,7 +822,7 @@ export async function importBackup(
|
|||||||
],
|
],
|
||||||
async (tx) => {
|
async (tx) => {
|
||||||
// FIXME: validate schema!
|
// FIXME: validate schema!
|
||||||
const backupBlob = backupRequest.backupBlob as WalletBackupContentV1;
|
const backupBlob = backupBlobArg as WalletBackupContentV1;
|
||||||
|
|
||||||
// FIXME: validate version
|
// FIXME: validate version
|
||||||
|
|
||||||
@ -993,6 +1008,7 @@ export async function importBackup(
|
|||||||
reserveStatus: ReserveRecordStatus.QUERYING_STATUS,
|
reserveStatus: ReserveRecordStatus.QUERYING_STATUS,
|
||||||
initialDenomSel: await getDenomSelStateFromBackup(
|
initialDenomSel: await getDenomSelStateFromBackup(
|
||||||
tx,
|
tx,
|
||||||
|
backupExchange.base_url,
|
||||||
backupReserve.initial_selected_denoms,
|
backupReserve.initial_selected_denoms,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
@ -1006,6 +1022,7 @@ export async function importBackup(
|
|||||||
await tx.put(Stores.withdrawalGroups, {
|
await tx.put(Stores.withdrawalGroups, {
|
||||||
denomsSel: await getDenomSelStateFromBackup(
|
denomsSel: await getDenomSelStateFromBackup(
|
||||||
tx,
|
tx,
|
||||||
|
backupExchange.base_url,
|
||||||
backupWg.selected_denoms,
|
backupWg.selected_denoms,
|
||||||
),
|
),
|
||||||
exchangeBaseUrl: backupExchange.base_url,
|
exchangeBaseUrl: backupExchange.base_url,
|
||||||
@ -1300,9 +1317,12 @@ export async function importBackup(
|
|||||||
| undefined
|
| undefined
|
||||||
)[] = [];
|
)[] = [];
|
||||||
for (const oldCoin of backupRefreshGroup.old_coins) {
|
for (const oldCoin of backupRefreshGroup.old_coins) {
|
||||||
|
const c = await tx.get(Stores.coins, oldCoin.coin_pub);
|
||||||
|
checkBackupInvariant(!!c);
|
||||||
if (oldCoin.refresh_session) {
|
if (oldCoin.refresh_session) {
|
||||||
const denomSel = await getDenomSelStateFromBackup(
|
const denomSel = await getDenomSelStateFromBackup(
|
||||||
tx,
|
tx,
|
||||||
|
c.exchangeBaseUrl,
|
||||||
oldCoin.refresh_session.new_denoms,
|
oldCoin.refresh_session.new_denoms,
|
||||||
);
|
);
|
||||||
refreshSessionPerCoin.push({
|
refreshSessionPerCoin.push({
|
||||||
@ -1346,6 +1366,7 @@ export async function importBackup(
|
|||||||
if (!existingTip) {
|
if (!existingTip) {
|
||||||
const denomsSel = await getDenomSelStateFromBackup(
|
const denomsSel = await getDenomSelStateFromBackup(
|
||||||
tx,
|
tx,
|
||||||
|
backupTip.exchange_base_url,
|
||||||
backupTip.selected_denoms,
|
backupTip.selected_denoms,
|
||||||
);
|
);
|
||||||
await tx.put(Stores.tips, {
|
await tx.put(Stores.tips, {
|
||||||
@ -1530,6 +1551,18 @@ export interface BackupInfo {
|
|||||||
providers: ProviderInfo[];
|
providers: ProviderInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function importBackupPlain(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
blob: any,
|
||||||
|
): Promise<void> {
|
||||||
|
// 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.
|
* Get information about the current state of wallet backups.
|
||||||
*/
|
*/
|
||||||
|
@ -55,6 +55,10 @@ export class InternalWalletState {
|
|||||||
private resourceLocks: Set<string> = new Set();
|
private resourceLocks: Set<string> = new Set();
|
||||||
|
|
||||||
constructor(
|
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 db: Database,
|
||||||
public http: HttpRequestLibrary,
|
public http: HttpRequestLibrary,
|
||||||
cryptoWorkerFactory: CryptoWorkerFactory,
|
cryptoWorkerFactory: CryptoWorkerFactory,
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
* 10. Re-denominated payments/refreshes are not shown properly in the total
|
* 10. Re-denominated payments/refreshes are not shown properly in the total
|
||||||
* payment cost.
|
* payment cost.
|
||||||
* 11. Failed refunds do not have any information about why they failed.
|
* 11. Failed refunds do not have any information about why they failed.
|
||||||
|
* => This should go into the general "error reports"
|
||||||
*
|
*
|
||||||
* Questions:
|
* Questions:
|
||||||
* 1. What happens when two backups are merged that have
|
* 1. What happens when two backups are merged that have
|
||||||
|
@ -161,6 +161,7 @@ import {
|
|||||||
codecForAddBackupProviderRequest,
|
codecForAddBackupProviderRequest,
|
||||||
runBackupCycle,
|
runBackupCycle,
|
||||||
exportBackup,
|
exportBackup,
|
||||||
|
importBackupPlain,
|
||||||
} from "./operations/backup";
|
} from "./operations/backup";
|
||||||
|
|
||||||
const builtinCurrencies: CurrencyRecord[] = [
|
const builtinCurrencies: CurrencyRecord[] = [
|
||||||
@ -933,6 +934,14 @@ export class Wallet {
|
|||||||
return testPay(this.ws.http, this, args);
|
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.
|
* Implementation of the "wallet-core" API.
|
||||||
*/
|
*/
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
"name": "GNU Taler Wallet (git)",
|
"name": "GNU Taler Wallet (git)",
|
||||||
"description": "Privacy preserving and transparent payments",
|
"description": "Privacy preserving and transparent payments",
|
||||||
"author": "GNU Taler Developers",
|
"author": "GNU Taler Developers",
|
||||||
"version": "0.8.0.5",
|
"version": "0.8.0.6",
|
||||||
"version_name": "0.8.1-dev.1",
|
"version_name": "0.8.1-dev.2",
|
||||||
|
|
||||||
"minimum_chrome_version": "51",
|
"minimum_chrome_version": "51",
|
||||||
"minimum_opera_version": "36",
|
"minimum_opera_version": "36",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "taler-wallet-webextension",
|
"name": "taler-wallet-webextension",
|
||||||
"version": "0.8.1-dev.1",
|
"version": "0.8.1-dev.2",
|
||||||
"description": "GNU Taler Wallet browser extension",
|
"description": "GNU Taler Wallet browser extension",
|
||||||
"main": "./build/index.js",
|
"main": "./build/index.js",
|
||||||
"types": "./build/index.d.ts",
|
"types": "./build/index.d.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user