mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-02 00:07:56 +01:00
Allow incremental playback for attachments with plaintextHash
This commit is contained in:
@@ -25,6 +25,7 @@ import { access } from 'node:fs/promises';
|
|||||||
import {
|
import {
|
||||||
type DecryptAttachmentToSinkOptionsType,
|
type DecryptAttachmentToSinkOptionsType,
|
||||||
decryptAttachmentV2ToSink,
|
decryptAttachmentV2ToSink,
|
||||||
|
type IntegrityCheckType,
|
||||||
} from '../ts/AttachmentCrypto.node.js';
|
} from '../ts/AttachmentCrypto.node.js';
|
||||||
import * as Bytes from '../ts/Bytes.std.js';
|
import * as Bytes from '../ts/Bytes.std.js';
|
||||||
import type { MessageAttachmentsCursorType } from '../ts/sql/Interface.std.js';
|
import type { MessageAttachmentsCursorType } from '../ts/sql/Interface.std.js';
|
||||||
@@ -68,6 +69,7 @@ import {
|
|||||||
getStickersPath,
|
getStickersPath,
|
||||||
getTempPath,
|
getTempPath,
|
||||||
} from './attachments.node.js';
|
} from './attachments.node.js';
|
||||||
|
import { isValidDigest, isValidPlaintextHash } from '../ts/types/Crypto.std.js';
|
||||||
|
|
||||||
const { isNumber } = lodash;
|
const { isNumber } = lodash;
|
||||||
|
|
||||||
@@ -98,7 +100,7 @@ type RangeFinderContextType = Readonly<
|
|||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'incremental';
|
type: 'incremental';
|
||||||
digest: Uint8Array<ArrayBuffer>;
|
integrityCheck: IntegrityCheckType;
|
||||||
incrementalMac: Uint8Array<ArrayBuffer>;
|
incrementalMac: Uint8Array<ArrayBuffer>;
|
||||||
chunkSize: number;
|
chunkSize: number;
|
||||||
keysBase64: string;
|
keysBase64: string;
|
||||||
@@ -154,10 +156,7 @@ async function safeDecryptToSink(
|
|||||||
theirChunkSize: ctx.chunkSize,
|
theirChunkSize: ctx.chunkSize,
|
||||||
theirIncrementalMac: ctx.incrementalMac,
|
theirIncrementalMac: ctx.incrementalMac,
|
||||||
type: 'standard',
|
type: 'standard',
|
||||||
integrityCheck: {
|
integrityCheck: ctx.integrityCheck,
|
||||||
type: 'encrypted',
|
|
||||||
digest: ctx.digest,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
@@ -703,9 +702,26 @@ export async function handleAttachmentRequest(req: Request): Promise<Response> {
|
|||||||
// When trying to view in-progress downloads, we need more information
|
// When trying to view in-progress downloads, we need more information
|
||||||
// to validate the file before returning data.
|
// to validate the file before returning data.
|
||||||
|
|
||||||
const digestBase64 = url.searchParams.get('digest');
|
const digestBase64 = url.searchParams.get('digest') ?? undefined;
|
||||||
if (digestBase64 == null) {
|
const plaintextHashHex =
|
||||||
return new Response('Missing digest', { status: 400 });
|
url.searchParams.get('plaintextHash') ?? undefined;
|
||||||
|
|
||||||
|
let integrityCheck: IntegrityCheckType;
|
||||||
|
|
||||||
|
if (isValidPlaintextHash(plaintextHashHex)) {
|
||||||
|
integrityCheck = {
|
||||||
|
type: 'plaintext',
|
||||||
|
plaintextHash: Bytes.fromHex(plaintextHashHex),
|
||||||
|
};
|
||||||
|
} else if (isValidDigest(digestBase64)) {
|
||||||
|
integrityCheck = {
|
||||||
|
type: 'encrypted',
|
||||||
|
digest: Bytes.fromBase64(digestBase64),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return new Response('Missing/invalid plaintextHash or digest', {
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const incrementalMacBase64 = url.searchParams.get('incrementalMac');
|
const incrementalMacBase64 = url.searchParams.get('incrementalMac');
|
||||||
@@ -724,7 +740,7 @@ export async function handleAttachmentRequest(req: Request): Promise<Response> {
|
|||||||
context = {
|
context = {
|
||||||
type: 'incremental',
|
type: 'incremental',
|
||||||
chunkSize,
|
chunkSize,
|
||||||
digest: Bytes.fromBase64(digestBase64),
|
integrityCheck,
|
||||||
incrementalMac: Bytes.fromBase64(incrementalMacBase64),
|
incrementalMac: Bytes.fromBase64(incrementalMacBase64),
|
||||||
keysBase64,
|
keysBase64,
|
||||||
path,
|
path,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export function getLocalAttachmentUrl(
|
|||||||
AttachmentType,
|
AttachmentType,
|
||||||
| 'contentType'
|
| 'contentType'
|
||||||
| 'digest'
|
| 'digest'
|
||||||
|
| 'plaintextHash'
|
||||||
| 'downloadPath'
|
| 'downloadPath'
|
||||||
| 'incrementalMac'
|
| 'incrementalMac'
|
||||||
| 'chunkSize'
|
| 'chunkSize'
|
||||||
@@ -87,10 +88,17 @@ export function getLocalAttachmentUrl(
|
|||||||
}
|
}
|
||||||
url.searchParams.set('key', attachment.key);
|
url.searchParams.set('key', attachment.key);
|
||||||
|
|
||||||
if (!attachment.digest) {
|
// Attachments restored from backup / link & sync may have plaintextHash but not
|
||||||
throw new Error('getLocalAttachmentUrl: Missing attachment digest!');
|
// digest
|
||||||
|
if (attachment.plaintextHash) {
|
||||||
|
url.searchParams.set('plaintextHash', attachment.plaintextHash);
|
||||||
|
} else if (attachment.digest) {
|
||||||
|
url.searchParams.set('digest', attachment.digest);
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'getLocalAttachmentUrl: Missing attachment plaintextHash and digest!'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
url.searchParams.set('digest', attachment.digest);
|
|
||||||
|
|
||||||
if (!attachment.incrementalMac) {
|
if (!attachment.incrementalMac) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
Reference in New Issue
Block a user