aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-wallet-core/src/operations/backup/export.ts72
-rw-r--r--packages/taler-wallet-core/src/operations/backup/index.ts89
2 files changed, 94 insertions, 67 deletions
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts
index ab2262653..eae7995ca 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -24,44 +24,54 @@
/**
* Imports.
*/
-import { hash } from "../../crypto/primitives/nacl-fast.js";
import {
- WalletBackupContentV1,
- BackupExchange,
- BackupCoin,
- BackupDenomination,
- BackupReserve,
- BackupPurchase,
- BackupProposal,
- BackupRefreshGroup,
+ Amounts,
BackupBackupProvider,
- BackupTip,
- BackupRecoupGroup,
- BackupWithdrawalGroup,
BackupBackupProviderTerms,
+ BackupCoin,
BackupCoinSource,
BackupCoinSourceType,
+ BackupDenomination,
+ BackupExchange,
+ BackupExchangeDetails,
BackupExchangeWireFee,
- BackupRefundItem,
- BackupRefundState,
+ BackupProposal,
BackupProposalStatus,
+ BackupPurchase,
+ BackupRecoupGroup,
+ BackupRefreshGroup,
BackupRefreshOldCoin,
BackupRefreshSession,
- BackupExchangeDetails,
+ BackupRefundItem,
+ BackupRefundState,
+ BackupReserve,
+ BackupTip,
+ BackupWithdrawalGroup,
+ canonicalizeBaseUrl,
+ canonicalJson,
+ getTimestampNow,
+ Logger,
+ timestampToIsoString,
+ WalletBackupContentV1,
} from "@gnu-taler/taler-util";
import { InternalWalletState } from "../../common.js";
-import { provideBackupState, getWalletBackupState } from "./state.js";
-import { Amounts, getTimestampNow } from "@gnu-taler/taler-util";
+import { hash } from "../../crypto/primitives/nacl-fast.js";
import {
+ encodeCrock,
+ getRandomBytes,
+ stringToBytes,
+} from "../../crypto/talerCrypto.js";
+import {
+ AbortStatus,
CoinSourceType,
CoinStatus,
- RefundState,
- AbortStatus,
ProposalStatus,
+ RefundState,
WALLET_BACKUP_STATE_KEY,
} from "../../db.js";
-import { encodeCrock, stringToBytes, getRandomBytes } from "../../crypto/talerCrypto.js";
-import { canonicalizeBaseUrl, canonicalJson } from "@gnu-taler/taler-util";
+import { getWalletBackupState, provideBackupState } from "./state.js";
+
+const logger = new Logger("backup/export.ts");
export async function exportBackup(
ws: InternalWalletState,
@@ -444,8 +454,10 @@ export async function exportBackup(
});
});
+ const ts = getTimestampNow();
+
if (!bs.lastBackupTimestamp) {
- bs.lastBackupTimestamp = getTimestampNow();
+ bs.lastBackupTimestamp = ts;
}
const backupBlob: WalletBackupContentV1 = {
@@ -469,18 +481,30 @@ export async function exportBackup(
tombstones: [],
};
- // If the backup changed, we increment our clock.
+ // If the backup changed, we change our nonce and timestamp.
let h = encodeCrock(hash(stringToBytes(canonicalJson(backupBlob))));
- if (h != bs.lastBackupPlainHash) {
+ if (h !== bs.lastBackupPlainHash) {
+ logger.trace(
+ `plain backup hash changed (from ${bs.lastBackupPlainHash}to ${h})`,
+ );
+ bs.lastBackupTimestamp = ts;
+ backupBlob.timestamp = ts;
bs.lastBackupPlainHash = encodeCrock(
hash(stringToBytes(canonicalJson(backupBlob))),
);
bs.lastBackupNonce = encodeCrock(getRandomBytes(32));
+ logger.trace(
+ `setting timestamp to ${timestampToIsoString(ts)} and nonce to ${
+ bs.lastBackupNonce
+ }`,
+ );
await tx.config.put({
key: WALLET_BACKUP_STATE_KEY,
value: bs,
});
+ } else {
+ logger.trace("backup hash did not change");
}
return backupBlob;
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts b/packages/taler-wallet-core/src/operations/backup/index.ts
index 041c927a5..0d3cf5786 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -24,24 +24,39 @@
/**
* Imports.
*/
-import { InternalWalletState } from "../../common.js";
import {
AmountString,
BackupRecovery,
+ buildCodecForObject,
+ canonicalizeBaseUrl,
+ canonicalJson,
+ Codec,
codecForAmountString,
+ codecForBoolean,
+ codecForNumber,
+ codecForString,
+ codecOptional,
+ ConfirmPayResultType,
+ durationFromSpec,
+ getTimestampNow,
+ j2s,
+ Logger,
+ PreparePayResultType,
+ RecoveryLoadRequest,
+ RecoveryMergeStrategy,
+ TalerErrorDetails,
+ Timestamp,
+ timestampAddDuration,
+ URL,
WalletBackupContentV1,
} from "@gnu-taler/taler-util";
+import { gunzipSync, gzipSync } from "fflate";
+import { InternalWalletState } from "../../common.js";
+import { kdf } from "../../crypto/primitives/kdf.js";
import {
- BackupProviderRecord,
- BackupProviderTerms,
- ConfigRecord,
- WalletBackupConfState,
- WALLET_BACKUP_STATE_KEY,
-} from "../../db.js";
-import {
- checkDbInvariant,
- checkLogicInvariant,
-} from "../../util/invariants.js";
+ secretbox,
+ secretbox_open,
+} from "../../crypto/primitives/nacl-fast.js";
import {
bytesToString,
decodeCrock,
@@ -53,43 +68,24 @@ import {
rsaBlind,
stringToBytes,
} from "../../crypto/talerCrypto.js";
-import { canonicalizeBaseUrl, canonicalJson, j2s } from "@gnu-taler/taler-util";
-import {
- durationFromSpec,
- getTimestampNow,
- Timestamp,
- timestampAddDuration,
- URL
-} from "@gnu-taler/taler-util";
+import { CryptoApi } from "../../crypto/workers/cryptoApi.js";
import {
- buildCodecForObject,
- Codec,
- codecForBoolean,
- codecForNumber,
- codecForString,
- codecOptional,
-} from "@gnu-taler/taler-util";
+ BackupProviderRecord,
+ BackupProviderTerms,
+ ConfigRecord,
+ WalletBackupConfState,
+ WALLET_BACKUP_STATE_KEY,
+} from "../../db.js";
import {
HttpResponseStatus,
readSuccessResponseJsonOrThrow,
readTalerErrorResponse,
} from "../../util/http.js";
-import { Logger } from "@gnu-taler/taler-util";
-import { gunzipSync, gzipSync } from "fflate";
-import { kdf } from "../../crypto/primitives/kdf.js";
-import { initRetryInfo } from "../../util/retries.js";
import {
- ConfirmPayResultType,
- PreparePayResultType,
- RecoveryLoadRequest,
- RecoveryMergeStrategy,
- TalerErrorDetails,
-} from "@gnu-taler/taler-util";
-import { CryptoApi } from "../../crypto/workers/cryptoApi.js";
-import {
- secretbox,
- secretbox_open,
-} from "../../crypto/primitives/nacl-fast.js";
+ checkDbInvariant,
+ checkLogicInvariant,
+} from "../../util/invariants.js";
+import { initRetryInfo } from "../../util/retries.js";
import {
checkPaymentByProposalId,
confirmPay,
@@ -97,7 +93,7 @@ import {
} from "../pay.js";
import { exportBackup } from "./export.js";
import { BackupCryptoPrecomputedData, importBackup } from "./import.js";
-import { provideBackupState, getWalletBackupState } from "./state.js";
+import { getWalletBackupState, provideBackupState } from "./state.js";
const logger = new Logger("operations/backup.ts");
@@ -137,7 +133,9 @@ export async function encryptBackup(
chunks.push(nonce);
const backupJsonContent = canonicalJson(blob);
logger.trace("backup JSON size", backupJsonContent.length);
- const compressedContent = gzipSync(stringToBytes(backupJsonContent));
+ const compressedContent = gzipSync(stringToBytes(backupJsonContent), {
+ mtime: 0,
+ });
const secret = deriveBlobSecret(config);
const encrypted = secretbox(compressedContent, nonce.slice(0, 24), secret);
chunks.push(encrypted);
@@ -261,7 +259,12 @@ async function runBackupCycleForProvider(
backupJson,
} = args;
const accountKeyPair = deriveAccountKeyPair(backupConfig, provider.baseUrl);
+
+ const newHash = encodeCrock(currentBackupHash);
+ const oldHash = provider.lastBackupHash;
+
logger.trace(`trying to upload backup to ${provider.baseUrl}`);
+ logger.trace(`old hash ${oldHash}, new hash ${newHash}`);
const syncSig = await ws.cryptoApi.makeSyncSignature({
newHash: encodeCrock(currentBackupHash),