24 lines
1.1 KiB
TypeScript
24 lines
1.1 KiB
TypeScript
import sharp from "sharp";
|
|
|
|
import { HttpError } from "@/lib/security/http";
|
|
import { hasValidImageSignature, MAX_MEDIA_BYTES, type IMAGE_MIME_TYPES } from "./validation";
|
|
|
|
export const MAX_IMAGE_PIXELS = 40_000_000;
|
|
|
|
export async function inspectImage(bytes: Uint8Array, mimeType: (typeof IMAGE_MIME_TYPES)[number]) {
|
|
if (bytes.byteLength > MAX_MEDIA_BYTES) throw new HttpError(413, "image-too-large");
|
|
if (!hasValidImageSignature(bytes.subarray(0, 16), mimeType)) throw new HttpError(422, "invalid-image");
|
|
try {
|
|
const image = sharp(bytes, { limitInputPixels: MAX_IMAGE_PIXELS, failOn: "warning", animated: true });
|
|
const metadata = await image.metadata();
|
|
const width = metadata.autoOrient.width || metadata.width;
|
|
const height = metadata.autoOrient.height || metadata.height;
|
|
if (!width || !height || width * height > MAX_IMAGE_PIXELS) throw new Error("invalid dimensions");
|
|
// Metadata alone accepts truncated images; decode pixels before publishing.
|
|
await image.stats();
|
|
return { width, height };
|
|
} catch {
|
|
throw new HttpError(422, "invalid-image");
|
|
}
|
|
}
|