set gzip timestamp to 0 in backup blob

This commit is contained in:
Florian Dold 2021-06-23 11:46:10 +02:00
parent 6c14268c1a
commit eaced5ca63
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
2 changed files with 94 additions and 67 deletions

View File

@ -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;

View File

@ -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 { CryptoApi } from "../../crypto/workers/cryptoApi.js";
import {
durationFromSpec,
getTimestampNow,
Timestamp,
timestampAddDuration,
URL
} from "@gnu-taler/taler-util";
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 {
checkDbInvariant,
checkLogicInvariant,
} from "../../util/invariants.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";
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),