set gzip timestamp to 0 in backup blob
This commit is contained in:
parent
6c14268c1a
commit
eaced5ca63
@ -24,44 +24,54 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { hash } from "../../crypto/primitives/nacl-fast.js";
|
|
||||||
import {
|
import {
|
||||||
WalletBackupContentV1,
|
Amounts,
|
||||||
BackupExchange,
|
|
||||||
BackupCoin,
|
|
||||||
BackupDenomination,
|
|
||||||
BackupReserve,
|
|
||||||
BackupPurchase,
|
|
||||||
BackupProposal,
|
|
||||||
BackupRefreshGroup,
|
|
||||||
BackupBackupProvider,
|
BackupBackupProvider,
|
||||||
BackupTip,
|
|
||||||
BackupRecoupGroup,
|
|
||||||
BackupWithdrawalGroup,
|
|
||||||
BackupBackupProviderTerms,
|
BackupBackupProviderTerms,
|
||||||
|
BackupCoin,
|
||||||
BackupCoinSource,
|
BackupCoinSource,
|
||||||
BackupCoinSourceType,
|
BackupCoinSourceType,
|
||||||
|
BackupDenomination,
|
||||||
|
BackupExchange,
|
||||||
|
BackupExchangeDetails,
|
||||||
BackupExchangeWireFee,
|
BackupExchangeWireFee,
|
||||||
BackupRefundItem,
|
BackupProposal,
|
||||||
BackupRefundState,
|
|
||||||
BackupProposalStatus,
|
BackupProposalStatus,
|
||||||
|
BackupPurchase,
|
||||||
|
BackupRecoupGroup,
|
||||||
|
BackupRefreshGroup,
|
||||||
BackupRefreshOldCoin,
|
BackupRefreshOldCoin,
|
||||||
BackupRefreshSession,
|
BackupRefreshSession,
|
||||||
BackupExchangeDetails,
|
BackupRefundItem,
|
||||||
|
BackupRefundState,
|
||||||
|
BackupReserve,
|
||||||
|
BackupTip,
|
||||||
|
BackupWithdrawalGroup,
|
||||||
|
canonicalizeBaseUrl,
|
||||||
|
canonicalJson,
|
||||||
|
getTimestampNow,
|
||||||
|
Logger,
|
||||||
|
timestampToIsoString,
|
||||||
|
WalletBackupContentV1,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { InternalWalletState } from "../../common.js";
|
import { InternalWalletState } from "../../common.js";
|
||||||
import { provideBackupState, getWalletBackupState } from "./state.js";
|
import { hash } from "../../crypto/primitives/nacl-fast.js";
|
||||||
import { Amounts, getTimestampNow } from "@gnu-taler/taler-util";
|
|
||||||
import {
|
import {
|
||||||
|
encodeCrock,
|
||||||
|
getRandomBytes,
|
||||||
|
stringToBytes,
|
||||||
|
} from "../../crypto/talerCrypto.js";
|
||||||
|
import {
|
||||||
|
AbortStatus,
|
||||||
CoinSourceType,
|
CoinSourceType,
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
RefundState,
|
|
||||||
AbortStatus,
|
|
||||||
ProposalStatus,
|
ProposalStatus,
|
||||||
|
RefundState,
|
||||||
WALLET_BACKUP_STATE_KEY,
|
WALLET_BACKUP_STATE_KEY,
|
||||||
} from "../../db.js";
|
} from "../../db.js";
|
||||||
import { encodeCrock, stringToBytes, getRandomBytes } from "../../crypto/talerCrypto.js";
|
import { getWalletBackupState, provideBackupState } from "./state.js";
|
||||||
import { canonicalizeBaseUrl, canonicalJson } from "@gnu-taler/taler-util";
|
|
||||||
|
const logger = new Logger("backup/export.ts");
|
||||||
|
|
||||||
export async function exportBackup(
|
export async function exportBackup(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
@ -444,8 +454,10 @@ export async function exportBackup(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ts = getTimestampNow();
|
||||||
|
|
||||||
if (!bs.lastBackupTimestamp) {
|
if (!bs.lastBackupTimestamp) {
|
||||||
bs.lastBackupTimestamp = getTimestampNow();
|
bs.lastBackupTimestamp = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
const backupBlob: WalletBackupContentV1 = {
|
const backupBlob: WalletBackupContentV1 = {
|
||||||
@ -469,18 +481,30 @@ export async function exportBackup(
|
|||||||
tombstones: [],
|
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))));
|
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(
|
bs.lastBackupPlainHash = encodeCrock(
|
||||||
hash(stringToBytes(canonicalJson(backupBlob))),
|
hash(stringToBytes(canonicalJson(backupBlob))),
|
||||||
);
|
);
|
||||||
bs.lastBackupNonce = encodeCrock(getRandomBytes(32));
|
bs.lastBackupNonce = encodeCrock(getRandomBytes(32));
|
||||||
|
logger.trace(
|
||||||
|
`setting timestamp to ${timestampToIsoString(ts)} and nonce to ${
|
||||||
|
bs.lastBackupNonce
|
||||||
|
}`,
|
||||||
|
);
|
||||||
await tx.config.put({
|
await tx.config.put({
|
||||||
key: WALLET_BACKUP_STATE_KEY,
|
key: WALLET_BACKUP_STATE_KEY,
|
||||||
value: bs,
|
value: bs,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
logger.trace("backup hash did not change");
|
||||||
}
|
}
|
||||||
|
|
||||||
return backupBlob;
|
return backupBlob;
|
||||||
|
@ -24,24 +24,39 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { InternalWalletState } from "../../common.js";
|
|
||||||
import {
|
import {
|
||||||
AmountString,
|
AmountString,
|
||||||
BackupRecovery,
|
BackupRecovery,
|
||||||
|
buildCodecForObject,
|
||||||
|
canonicalizeBaseUrl,
|
||||||
|
canonicalJson,
|
||||||
|
Codec,
|
||||||
codecForAmountString,
|
codecForAmountString,
|
||||||
|
codecForBoolean,
|
||||||
|
codecForNumber,
|
||||||
|
codecForString,
|
||||||
|
codecOptional,
|
||||||
|
ConfirmPayResultType,
|
||||||
|
durationFromSpec,
|
||||||
|
getTimestampNow,
|
||||||
|
j2s,
|
||||||
|
Logger,
|
||||||
|
PreparePayResultType,
|
||||||
|
RecoveryLoadRequest,
|
||||||
|
RecoveryMergeStrategy,
|
||||||
|
TalerErrorDetails,
|
||||||
|
Timestamp,
|
||||||
|
timestampAddDuration,
|
||||||
|
URL,
|
||||||
WalletBackupContentV1,
|
WalletBackupContentV1,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { gunzipSync, gzipSync } from "fflate";
|
||||||
|
import { InternalWalletState } from "../../common.js";
|
||||||
|
import { kdf } from "../../crypto/primitives/kdf.js";
|
||||||
import {
|
import {
|
||||||
BackupProviderRecord,
|
secretbox,
|
||||||
BackupProviderTerms,
|
secretbox_open,
|
||||||
ConfigRecord,
|
} from "../../crypto/primitives/nacl-fast.js";
|
||||||
WalletBackupConfState,
|
|
||||||
WALLET_BACKUP_STATE_KEY,
|
|
||||||
} from "../../db.js";
|
|
||||||
import {
|
|
||||||
checkDbInvariant,
|
|
||||||
checkLogicInvariant,
|
|
||||||
} from "../../util/invariants.js";
|
|
||||||
import {
|
import {
|
||||||
bytesToString,
|
bytesToString,
|
||||||
decodeCrock,
|
decodeCrock,
|
||||||
@ -53,43 +68,24 @@ import {
|
|||||||
rsaBlind,
|
rsaBlind,
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
} from "../../crypto/talerCrypto.js";
|
} from "../../crypto/talerCrypto.js";
|
||||||
import { canonicalizeBaseUrl, canonicalJson, j2s } from "@gnu-taler/taler-util";
|
import { CryptoApi } from "../../crypto/workers/cryptoApi.js";
|
||||||
import {
|
import {
|
||||||
durationFromSpec,
|
BackupProviderRecord,
|
||||||
getTimestampNow,
|
BackupProviderTerms,
|
||||||
Timestamp,
|
ConfigRecord,
|
||||||
timestampAddDuration,
|
WalletBackupConfState,
|
||||||
URL
|
WALLET_BACKUP_STATE_KEY,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "../../db.js";
|
||||||
import {
|
|
||||||
buildCodecForObject,
|
|
||||||
Codec,
|
|
||||||
codecForBoolean,
|
|
||||||
codecForNumber,
|
|
||||||
codecForString,
|
|
||||||
codecOptional,
|
|
||||||
} from "@gnu-taler/taler-util";
|
|
||||||
import {
|
import {
|
||||||
HttpResponseStatus,
|
HttpResponseStatus,
|
||||||
readSuccessResponseJsonOrThrow,
|
readSuccessResponseJsonOrThrow,
|
||||||
readTalerErrorResponse,
|
readTalerErrorResponse,
|
||||||
} from "../../util/http.js";
|
} from "../../util/http.js";
|
||||||
import { Logger } from "@gnu-taler/taler-util";
|
import {
|
||||||
import { gunzipSync, gzipSync } from "fflate";
|
checkDbInvariant,
|
||||||
import { kdf } from "../../crypto/primitives/kdf.js";
|
checkLogicInvariant,
|
||||||
|
} from "../../util/invariants.js";
|
||||||
import { initRetryInfo } from "../../util/retries.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 {
|
import {
|
||||||
checkPaymentByProposalId,
|
checkPaymentByProposalId,
|
||||||
confirmPay,
|
confirmPay,
|
||||||
@ -97,7 +93,7 @@ import {
|
|||||||
} from "../pay.js";
|
} from "../pay.js";
|
||||||
import { exportBackup } from "./export.js";
|
import { exportBackup } from "./export.js";
|
||||||
import { BackupCryptoPrecomputedData, importBackup } from "./import.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");
|
const logger = new Logger("operations/backup.ts");
|
||||||
|
|
||||||
@ -137,7 +133,9 @@ export async function encryptBackup(
|
|||||||
chunks.push(nonce);
|
chunks.push(nonce);
|
||||||
const backupJsonContent = canonicalJson(blob);
|
const backupJsonContent = canonicalJson(blob);
|
||||||
logger.trace("backup JSON size", backupJsonContent.length);
|
logger.trace("backup JSON size", backupJsonContent.length);
|
||||||
const compressedContent = gzipSync(stringToBytes(backupJsonContent));
|
const compressedContent = gzipSync(stringToBytes(backupJsonContent), {
|
||||||
|
mtime: 0,
|
||||||
|
});
|
||||||
const secret = deriveBlobSecret(config);
|
const secret = deriveBlobSecret(config);
|
||||||
const encrypted = secretbox(compressedContent, nonce.slice(0, 24), secret);
|
const encrypted = secretbox(compressedContent, nonce.slice(0, 24), secret);
|
||||||
chunks.push(encrypted);
|
chunks.push(encrypted);
|
||||||
@ -261,7 +259,12 @@ async function runBackupCycleForProvider(
|
|||||||
backupJson,
|
backupJson,
|
||||||
} = args;
|
} = args;
|
||||||
const accountKeyPair = deriveAccountKeyPair(backupConfig, provider.baseUrl);
|
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(`trying to upload backup to ${provider.baseUrl}`);
|
||||||
|
logger.trace(`old hash ${oldHash}, new hash ${newHash}`);
|
||||||
|
|
||||||
const syncSig = await ws.cryptoApi.makeSyncSignature({
|
const syncSig = await ws.cryptoApi.makeSyncSignature({
|
||||||
newHash: encodeCrock(currentBackupHash),
|
newHash: encodeCrock(currentBackupHash),
|
||||||
|
Loading…
Reference in New Issue
Block a user