signal-desktop/ts/util/downloadAttachmentFromLocalBackup.ts
2025-09-19 13:05:51 -07:00

56 lines
1.6 KiB
TypeScript

// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { existsSync } from 'node:fs';
import lodash from 'lodash';
import { type BackupableAttachmentType } from '../types/Attachment.js';
import {
decryptAndReencryptLocally,
type ReencryptedAttachmentV2,
} from '../AttachmentCrypto.js';
import { strictAssert } from './assert.js';
const { isNumber } = lodash;
export class AttachmentPermanentlyUndownloadableError extends Error {}
export async function downloadAttachmentFromLocalBackup(
attachment: BackupableAttachmentType,
{ logId }: { logId: string }
): Promise<ReencryptedAttachmentV2> {
return doDownloadFromLocalBackup(attachment, {
logId: `downloadAttachmentFromLocalBackup(${logId})`,
});
}
async function doDownloadFromLocalBackup(
attachment: BackupableAttachmentType,
{
logId,
}: {
logId: string;
}
): Promise<ReencryptedAttachmentV2> {
const { plaintextHash, localBackupPath, localKey, size } = attachment;
strictAssert(plaintextHash, `${logId}: missing plaintextHash`);
strictAssert(localKey, `${logId}: missing localKey`);
strictAssert(localBackupPath, `${logId}: missing localBackupPath`);
strictAssert(isNumber(size), `${logId}: missing size`);
if (!existsSync(localBackupPath)) {
throw new AttachmentPermanentlyUndownloadableError(
'No file at attachment localBackupPath'
);
}
return decryptAndReencryptLocally({
type: 'local',
ciphertextPath: localBackupPath,
idForLogging: logId,
keysBase64: localKey,
size,
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
});
}