Backups: update to latest integration tests

This commit is contained in:
trevor-signal 2024-12-11 12:01:45 -05:00 committed by GitHub
parent c7dc4279a1
commit 6f7faf4be8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 239 additions and 88 deletions

View file

@ -139,6 +139,7 @@ import { getRoomIdFromRootKey } from '../../util/callLinksRingrtc';
import { SeenStatus } from '../../MessageSeenStatus';
import { migrateAllMessages } from '../../messages/migrateMessageData';
import { trimBody } from '../../util/longAttachment';
import { generateBackupsSubscriberData } from '../../util/backupSubscriptionData';
const MAX_CONCURRENCY = 10;
@ -258,6 +259,8 @@ export class BackupExportStream extends Readable {
version: Long.fromNumber(BACKUP_VERSION),
backupTimeMs: this.backupTimeMs,
mediaRootBackupKey: getBackupMediaRootKey().serialize(),
firstAppVersion: window.storage.get('restoredBackupFirstAppVersion'),
currentAppVersion: `Desktop ${window.getVersion()}`,
}).finish()
);
@ -660,7 +663,8 @@ export class BackupExportStream extends Readable {
const usernameLink = storage.get('usernameLink');
const subscriberId = storage.get('subscriberId');
const backupsSubscriberId = storage.get('backupsSubscriberId');
const backupsSubscriberData = generateBackupsSubscriberData();
return {
profileKey: storage.get('profileKey'),
@ -676,16 +680,7 @@ export class BackupExportStream extends Readable {
givenName: me.get('profileName'),
familyName: me.get('profileFamilyName'),
avatarUrlPath: storage.get('avatarUrl'),
backupsSubscriberData: Bytes.isNotEmpty(backupsSubscriberId)
? {
subscriberId: backupsSubscriberId,
currencyCode: storage.get('backupsSubscriberCurrencyCode'),
manuallyCancelled: storage.get(
'backupsSubscriptionManuallyCancelled',
false
),
}
: null,
backupsSubscriberData,
donationSubscriberData: Bytes.isNotEmpty(subscriberId)
? {
subscriberId,

View file

@ -122,6 +122,7 @@ import { hasAttachmentDownloads } from '../../util/hasAttachmentDownloads';
import { isNightly } from '../../util/version';
import { ToastType } from '../../types/Toast';
import { isConversationAccepted } from '../../util/isConversationAccepted';
import { saveBackupsSubscriberData } from '../../util/backupSubscriptionData';
const MAX_CONCURRENCY = 10;
@ -262,6 +263,11 @@ export class BackupImportStream extends Writable {
throw new Error('Missing mediaRootBackupKey');
}
await window.storage.put(
'restoredBackupFirstAppVersion',
info.firstAppVersion
);
const theirKey = info.mediaRootBackupKey;
const ourKey = getBackupMediaRootKey().serialize();
if (!constantTimeEqual(theirKey, ourKey)) {
@ -658,22 +664,8 @@ export class BackupImportStream extends Writable {
);
}
}
if (backupsSubscriberData != null) {
const { subscriberId, currencyCode, manuallyCancelled } =
backupsSubscriberData;
if (Bytes.isNotEmpty(subscriberId)) {
await storage.put('backupsSubscriberId', subscriberId);
}
if (currencyCode != null) {
await storage.put('backupsSubscriberCurrencyCode', currencyCode);
}
if (manuallyCancelled != null) {
await storage.put(
'backupsSubscriptionManuallyCancelled',
manuallyCancelled
);
}
}
await saveBackupsSubscriberData(backupsSubscriberData);
await storage.put(
'read-receipt-setting',
@ -1213,6 +1205,7 @@ export class BackupImportStream extends Writable {
if (conversation.active_at == null) {
conversation.active_at = Math.max(chat.id.toNumber(), 1);
}
conversation.isArchived = chat.archived === true;
conversation.isPinned = (chat.pinnedOrder || 0) !== 0;

View file

@ -80,6 +80,10 @@ import { fromAdminKeyBytes, toAdminKeyBytes } from '../util/callLinks';
import { isOlderThan } from '../util/timestamp';
import { getMessageQueueTime } from '../util/getMessageQueueTime';
import { callLinkRefreshJobQueue } from '../jobs/callLinkRefreshJobQueue';
import {
generateBackupsSubscriberData,
saveBackupsSubscriberData,
} from '../util/backupSubscriptionData';
const MY_STORY_BYTES = uuidToBytes(MY_STORY_ID);
@ -406,9 +410,7 @@ export function toAccountRecord(
if (Bytes.isNotEmpty(subscriberId)) {
accountRecord.subscriberId = subscriberId;
}
const subscriberCurrencyCode = window.storage.get(
'backupsSubscriberCurrencyCode'
);
const subscriberCurrencyCode = window.storage.get('subscriberCurrencyCode');
if (typeof subscriberCurrencyCode === 'string') {
accountRecord.subscriberCurrencyCode = subscriberCurrencyCode;
}
@ -419,23 +421,9 @@ export function toAccountRecord(
accountRecord.donorSubscriptionManuallyCancelled =
donorSubscriptionManuallyCancelled;
}
const backupsSubscriberId = window.storage.get('backupsSubscriberId');
if (Bytes.isNotEmpty(backupsSubscriberId)) {
accountRecord.backupsSubscriberId = backupsSubscriberId;
}
const backupsSubscriberCurrencyCode = window.storage.get(
'backupsSubscriberCurrencyCode'
);
if (typeof backupsSubscriberCurrencyCode === 'string') {
accountRecord.backupsSubscriberCurrencyCode = backupsSubscriberCurrencyCode;
}
const backupsSubscriptionManuallyCancelled = window.storage.get(
'backupsSubscriptionManuallyCancelled'
);
if (typeof backupsSubscriptionManuallyCancelled === 'boolean') {
accountRecord.backupsSubscriptionManuallyCancelled =
backupsSubscriptionManuallyCancelled;
}
accountRecord.backupSubscriberData = generateBackupsSubscriberData();
const displayBadgesOnProfile = window.storage.get('displayBadgesOnProfile');
if (displayBadgesOnProfile !== undefined) {
accountRecord.displayBadgesOnProfile = displayBadgesOnProfile;
@ -1327,9 +1315,7 @@ export async function mergeAccountRecord(
subscriberId,
subscriberCurrencyCode,
donorSubscriptionManuallyCancelled,
backupsSubscriberId,
backupsSubscriberCurrencyCode,
backupsSubscriptionManuallyCancelled,
backupSubscriberData,
displayBadgesOnProfile,
keepMutedChatsArchived,
hasCompletedUsernameOnboarding,
@ -1548,21 +1534,9 @@ export async function mergeAccountRecord(
donorSubscriptionManuallyCancelled
);
}
if (Bytes.isNotEmpty(backupsSubscriberId)) {
await window.storage.put('backupsSubscriberId', backupsSubscriberId);
}
if (typeof backupsSubscriberCurrencyCode === 'string') {
await window.storage.put(
'backupsSubscriberCurrencyCode',
backupsSubscriberCurrencyCode
);
}
if (backupsSubscriptionManuallyCancelled != null) {
await window.storage.put(
'backupsSubscriptionManuallyCancelled',
backupsSubscriptionManuallyCancelled
);
}
await saveBackupsSubscriberData(backupSubscriberData);
await window.storage.put(
'displayBadgesOnProfile',
Boolean(displayBadgesOnProfile)

View file

@ -60,6 +60,12 @@ describe('backup/integration', () => {
const files = readdirSync(BACKUP_INTEGRATION_DIR)
.filter(file => file.endsWith('.binproto'))
.filter(
file =>
// TODO (DESKTOP-8025)
!file.startsWith('chat_folder_') &&
!file.startsWith('notification_profile_')
)
.map(file => join(BACKUP_INTEGRATION_DIR, file));
if (files.length === 0) {

View file

@ -175,8 +175,8 @@ export type StorageAccessType = {
subscriberCurrencyCode: string;
donorSubscriptionManuallyCancelled: boolean;
backupsSubscriberId: Uint8Array;
backupsSubscriberCurrencyCode: string;
backupsSubscriptionManuallyCancelled: boolean;
backupsSubscriberPurchaseToken: string;
backupsSubscriberOriginalTransactionId: string;
displayBadgesOnProfile: boolean;
keepMutedChatsArchived: boolean;
usernameLastIntegrityCheck: number;
@ -209,6 +209,9 @@ export type StorageAccessType = {
// If true Desktop message history was restored from backup
isRestoredFromBackup: boolean;
// The `firstAppVersion` present on an BackupInfo from an imported backup.
restoredBackupFirstAppVersion: string;
// Deprecated
'challenge:retry-message-ids': never;
nextSignedKeyRotationTime: number;

View file

@ -0,0 +1,75 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import Long from 'long';
import type { Backups, SignalService } from '../protobuf';
import * as Bytes from '../Bytes';
// These two proto messages (Backups.AccountData.IIAPSubscriberData &&
// SignalService.AccountRecord.IIAPSubscriberData) should remain in sync. If they drift,
// we'll need separate logic for each
export async function saveBackupsSubscriberData(
backupsSubscriberData:
| Backups.AccountData.IIAPSubscriberData
| SignalService.AccountRecord.IIAPSubscriberData
| null
| undefined
): Promise<void> {
if (backupsSubscriberData == null) {
await window.storage.remove('backupsSubscriberId');
await window.storage.remove('backupsSubscriberPurchaseToken');
await window.storage.remove('backupsSubscriberOriginalTransactionId');
return;
}
const { subscriberId, purchaseToken, originalTransactionId } =
backupsSubscriberData;
if (Bytes.isNotEmpty(subscriberId)) {
await window.storage.put('backupsSubscriberId', subscriberId);
} else {
await window.storage.remove('backupsSubscriberId');
}
if (purchaseToken) {
await window.storage.put('backupsSubscriberPurchaseToken', purchaseToken);
} else {
await window.storage.remove('backupsSubscriberPurchaseToken');
}
if (originalTransactionId) {
await window.storage.put(
'backupsSubscriberOriginalTransactionId',
originalTransactionId.toString()
);
} else {
await window.storage.remove('backupsSubscriberOriginalTransactionId');
}
}
export function generateBackupsSubscriberData(): Backups.AccountData.IIAPSubscriberData | null {
const backupsSubscriberId = window.storage.get('backupsSubscriberId');
if (Bytes.isEmpty(backupsSubscriberId)) {
return null;
}
const backupsSubscriberData: Backups.AccountData.IIAPSubscriberData = {
subscriberId: backupsSubscriberId,
};
const purchaseToken = window.storage.get('backupsSubscriberPurchaseToken');
if (purchaseToken) {
backupsSubscriberData.purchaseToken = purchaseToken;
} else {
const originalTransactionId = window.storage.get(
'backupsSubscriberOriginalTransactionId'
);
if (originalTransactionId) {
backupsSubscriberData.originalTransactionId = Long.fromString(
originalTransactionId
);
}
}
return backupsSubscriberData;
}