mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 14:09:42 +02:00
- Event-loop blockage: HEIC decode/encode (CPU-synchronous libheif WASM + jpeg-js) now runs in a per-conversion worker_threads Worker (src/web/heic-jpeg-worker.ts, spawned by heic-jpeg-converter.ts) with resourceLimits and a 30s hard timeout that terminates the worker — verified end-to-end under tsx and against compiled dist/ output with a real iPhone HEIC (event-loop max stall 52ms during conversion). - No server-side concurrency cap: conversions now acquire a slot from the existing global runWithConversionLimit() pool (document-conversion-limiter), bounding peak decode memory/CPU across simultaneous uploads. - Decompression bomb: header-declared dimensions are read via heic-decode's allocation-free `.all` path and rejected above 64MP BEFORE decode() can allocate width*height*4 bytes (a <300-byte crafted file can declare 30000x30000 = 3.6GB). Regression-tested with a crafted ISOBMFF fixture against the real heic-decode WASM (test/heic-jpeg-core.test.ts). - Mislabeled HEIC (documented Android/MIUI case): conversion now routes on ftyp magic-byte sniff of the raw buffer regardless of declared ext/Content-Type, so a HEIF uploaded as image/jpeg converts instead of 415ing; the magic-mismatch 415 only fires for genuinely unrecognized bytes. - Brand allowlist narrowed to what heic-decode's isHeic() accepts (heim/heis/hevm/hevs dropped — they could only ever fail conversion). - Converted-output size: the JPEG result is checked against MAX_PASTE_IMAGE_BYTES (jpeg-js can inflate a within-limit HEIC past the cap). - Deps: heic-convert replaced with its underlying heic-decode + jpeg-js (the wrapper could not expose the pre-decode dimension check); lockfile synced, drops pngjs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
25 lines
650 B
TypeScript
25 lines
650 B
TypeScript
declare module 'heic-decode' {
|
|
export interface DecodedHeicImage {
|
|
width: number;
|
|
height: number;
|
|
data: Uint8ClampedArray;
|
|
}
|
|
|
|
/** Handle exposing header-declared dimensions WITHOUT decoding pixels. */
|
|
export interface HeicImageHandle {
|
|
width: number;
|
|
height: number;
|
|
decode(): Promise<DecodedHeicImage>;
|
|
}
|
|
|
|
export type HeicImageHandles = HeicImageHandle[] & { dispose(): void };
|
|
|
|
interface HeicDecode {
|
|
(input: { buffer: Buffer | Uint8Array }): Promise<DecodedHeicImage>;
|
|
all(input: { buffer: Buffer | Uint8Array }): Promise<HeicImageHandles>;
|
|
}
|
|
|
|
const decode: HeicDecode;
|
|
export default decode;
|
|
}
|