mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-05-08 17:08:57 +01:00
Backups: use new locatorInfo & mediaName (#10627)
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
signalDecrypt,
|
||||
signalDecryptPreKey,
|
||||
SignalMessage,
|
||||
UsePQRatchet,
|
||||
} from '@signalapp/libsignal-client';
|
||||
|
||||
import {
|
||||
@@ -1777,7 +1778,8 @@ export default class MessageReceiver
|
||||
identityKeyStore,
|
||||
preKeyStore,
|
||||
signedPreKeyStore,
|
||||
kyberPreKeyStore
|
||||
kyberPreKeyStore,
|
||||
UsePQRatchet.No
|
||||
);
|
||||
}
|
||||
return signalDecrypt(
|
||||
@@ -1904,7 +1906,8 @@ export default class MessageReceiver
|
||||
identityKeyStore,
|
||||
preKeyStore,
|
||||
signedPreKeyStore,
|
||||
kyberPreKeyStore
|
||||
kyberPreKeyStore,
|
||||
UsePQRatchet.No
|
||||
)
|
||||
),
|
||||
zone
|
||||
|
||||
@@ -431,7 +431,7 @@ export class Provisioner {
|
||||
.toAppUrl({
|
||||
uuid,
|
||||
pubKey: Bytes.toBase64(cipher.getPublicKey().serialize()),
|
||||
capabilities: isLinkAndSyncEnabled() ? ['backup3'] : [],
|
||||
capabilities: isLinkAndSyncEnabled() ? ['backup3', 'backup4'] : [],
|
||||
})
|
||||
.toString();
|
||||
|
||||
|
||||
Vendored
+1
-2
@@ -6,7 +6,7 @@ import type * as client from '@signalapp/libsignal-client';
|
||||
import type { SignalService as Proto } from '../protobuf';
|
||||
import type { IncomingWebSocketRequest } from './WebsocketResources';
|
||||
import type { ServiceIdString, AciString, PniString } from '../types/ServiceId';
|
||||
import type { AttachmentType, TextAttachmentType } from '../types/Attachment';
|
||||
import type { TextAttachmentType } from '../types/Attachment';
|
||||
import type { GiftBadgeStates } from '../components/conversation/Message';
|
||||
import type { MIMEType } from '../types/MIME';
|
||||
import type { DurationInSeconds } from '../util/durations';
|
||||
@@ -117,7 +117,6 @@ export type ProcessedAttachment = {
|
||||
blurHash?: string;
|
||||
cdnNumber?: number;
|
||||
textAttachment?: Omit<TextAttachmentType, 'preview'>;
|
||||
backupLocator?: AttachmentType['backupLocator'];
|
||||
uploadTimestamp?: number;
|
||||
downloadPath?: string;
|
||||
incrementalMac?: string;
|
||||
|
||||
@@ -14,10 +14,11 @@ import * as Errors from '../types/errors';
|
||||
import { strictAssert } from '../util/assert';
|
||||
import {
|
||||
AttachmentSizeError,
|
||||
mightBeOnBackupTier,
|
||||
type AttachmentType,
|
||||
AttachmentVariant,
|
||||
AttachmentPermanentlyUndownloadableError,
|
||||
hasRequiredInformationForBackup,
|
||||
type BackupableAttachmentType,
|
||||
} from '../types/Attachment';
|
||||
import * as Bytes from '../Bytes';
|
||||
import {
|
||||
@@ -27,6 +28,7 @@ import {
|
||||
type ReencryptedAttachmentV2,
|
||||
decryptAndReencryptLocally,
|
||||
measureSize,
|
||||
type IntegrityCheckType,
|
||||
} from '../AttachmentCrypto';
|
||||
import type { ProcessedAttachment } from './Types.d';
|
||||
import type { WebAPIType } from './WebAPI';
|
||||
@@ -58,7 +60,7 @@ export function getCdnKey(attachment: ProcessedAttachment): string {
|
||||
}
|
||||
|
||||
export function getBackupMediaOuterEncryptionKeyMaterial(
|
||||
attachment: AttachmentType
|
||||
attachment: BackupableAttachmentType
|
||||
): BackupMediaKeyMaterialType {
|
||||
const mediaId = getMediaIdForAttachment(attachment);
|
||||
const backupKey = getBackupMediaRootKey();
|
||||
@@ -66,14 +68,14 @@ export function getBackupMediaOuterEncryptionKeyMaterial(
|
||||
}
|
||||
|
||||
function getBackupThumbnailInnerEncryptionKeyMaterial(
|
||||
attachment: AttachmentType
|
||||
attachment: BackupableAttachmentType
|
||||
): BackupMediaKeyMaterialType {
|
||||
const mediaId = getMediaIdForAttachmentThumbnail(attachment);
|
||||
const backupKey = getBackupMediaRootKey();
|
||||
return deriveBackupMediaKeyMaterial(backupKey, mediaId.bytes);
|
||||
}
|
||||
function getBackupThumbnailOuterEncryptionKeyMaterial(
|
||||
attachment: AttachmentType
|
||||
attachment: BackupableAttachmentType
|
||||
): BackupMediaKeyMaterialType {
|
||||
const mediaId = getMediaIdForAttachmentThumbnail(attachment);
|
||||
const backupKey = getBackupMediaRootKey();
|
||||
@@ -81,13 +83,9 @@ function getBackupThumbnailOuterEncryptionKeyMaterial(
|
||||
}
|
||||
|
||||
export async function getCdnNumberForBackupTier(
|
||||
attachment: ProcessedAttachment
|
||||
attachment: BackupableAttachmentType
|
||||
): Promise<number> {
|
||||
strictAssert(
|
||||
attachment.backupLocator,
|
||||
'Attachment was missing backupLocator'
|
||||
);
|
||||
let backupCdnNumber = attachment.backupLocator.cdnNumber;
|
||||
let { backupCdnNumber } = attachment;
|
||||
|
||||
if (backupCdnNumber == null) {
|
||||
const mediaId = getMediaIdForAttachment(attachment);
|
||||
@@ -106,11 +104,15 @@ export async function getCdnNumberForBackupTier(
|
||||
|
||||
export async function downloadAttachment(
|
||||
server: WebAPIType,
|
||||
attachment: ProcessedAttachment,
|
||||
{
|
||||
attachment,
|
||||
mediaTier,
|
||||
}:
|
||||
| { attachment: AttachmentType; mediaTier: MediaTier.STANDARD }
|
||||
| { attachment: BackupableAttachmentType; mediaTier: MediaTier.BACKUP },
|
||||
options: {
|
||||
disableRetries?: boolean;
|
||||
logPrefix?: string;
|
||||
mediaTier?: MediaTier;
|
||||
onSizeUpdate: (totalBytes: number) => void;
|
||||
timeout?: number;
|
||||
variant: AttachmentVariant;
|
||||
@@ -119,20 +121,20 @@ export async function downloadAttachment(
|
||||
): Promise<ReencryptedAttachmentV2> {
|
||||
const logId = `downloadAttachment/${options.logPrefix ?? ''}`;
|
||||
|
||||
const { digest, incrementalMac, chunkSize, key, size } = attachment;
|
||||
const { digest, plaintextHash, incrementalMac, chunkSize, key, size } =
|
||||
attachment;
|
||||
|
||||
try {
|
||||
strictAssert(digest, `${logId}: missing digest`);
|
||||
strictAssert(
|
||||
digest || plaintextHash,
|
||||
`${logId}: missing digest and plaintextHash`
|
||||
);
|
||||
strictAssert(key, `${logId}: missing key`);
|
||||
strictAssert(isNumber(size), `${logId}: missing size`);
|
||||
} catch (error) {
|
||||
throw new AttachmentPermanentlyUndownloadableError(error.message);
|
||||
}
|
||||
|
||||
const mediaTier =
|
||||
options?.mediaTier ??
|
||||
(mightBeOnBackupTier(attachment) ? MediaTier.BACKUP : MediaTier.STANDARD);
|
||||
|
||||
let downloadResult: Awaited<ReturnType<typeof downloadToDisk>>;
|
||||
|
||||
let { downloadPath } = attachment;
|
||||
@@ -169,6 +171,12 @@ export async function downloadAttachment(
|
||||
if (downloadOffset !== 0) {
|
||||
log.info(`${logId}: resuming from ${downloadOffset}`);
|
||||
}
|
||||
if (mediaTier === MediaTier.BACKUP) {
|
||||
strictAssert(
|
||||
hasRequiredInformationForBackup(attachment),
|
||||
`${logId}: attachment missing critical information for backup tier`
|
||||
);
|
||||
}
|
||||
|
||||
if (mediaTier === MediaTier.STANDARD) {
|
||||
strictAssert(
|
||||
@@ -197,6 +205,8 @@ export async function downloadAttachment(
|
||||
size,
|
||||
});
|
||||
} else {
|
||||
strictAssert(mediaTier === MediaTier.BACKUP, 'backup media tier');
|
||||
|
||||
const mediaId =
|
||||
options.variant === AttachmentVariant.ThumbnailFromBackup
|
||||
? getMediaIdForAttachmentThumbnail(attachment)
|
||||
@@ -244,6 +254,21 @@ export async function downloadAttachment(
|
||||
case AttachmentVariant.Default:
|
||||
case undefined: {
|
||||
const { aesKey, macKey } = splitKeys(Bytes.fromBase64(key));
|
||||
let integrityCheck: IntegrityCheckType;
|
||||
if (plaintextHash) {
|
||||
integrityCheck = {
|
||||
type: 'plaintext',
|
||||
plaintextHash: Bytes.fromHex(plaintextHash),
|
||||
};
|
||||
} else if (digest) {
|
||||
integrityCheck = {
|
||||
type: 'encrypted',
|
||||
digest: Bytes.fromBase64(digest),
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${logId}: missing both digest and plaintextHash`);
|
||||
}
|
||||
|
||||
return await decryptAndReencryptLocally({
|
||||
type: 'standard',
|
||||
ciphertextPath: cipherTextAbsolutePath,
|
||||
@@ -251,7 +276,7 @@ export async function downloadAttachment(
|
||||
aesKey,
|
||||
macKey,
|
||||
size,
|
||||
theirDigest: Bytes.fromBase64(digest),
|
||||
integrityCheck,
|
||||
theirIncrementalMac: incrementalMac
|
||||
? Bytes.fromBase64(incrementalMac)
|
||||
: undefined,
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
processPreKeyBundle,
|
||||
ProtocolAddress,
|
||||
PublicKey,
|
||||
UsePQRatchet,
|
||||
} from '@signalapp/libsignal-client';
|
||||
|
||||
import {
|
||||
@@ -193,7 +194,8 @@ async function handleServerKeys(
|
||||
preKeyBundle,
|
||||
protocolAddress,
|
||||
sessionStore,
|
||||
identityKeyStore
|
||||
identityKeyStore,
|
||||
UsePQRatchet.No
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user