Loading files
import path from "node:path";
import { communityDataDir } from "./db";
// Where a thread's files live on disk.
//
// Split out of map.ts on purpose: that module holds the map's shared rules and
// is imported by client components, and anything reaching `communityDataDir`
// drags better-sqlite3 into the browser bundle behind it. Server code only.
/** Named by opaque id, never by the uploaded filename — that string is display
* text and is never allowed near a path. */
export function attachmentDir(): string {
return path.join(communityDataDir(), "attachments");
}
export function attachmentPath(id: string): string {
// Ids are generated by newId() (hex), so this cannot escape the directory —
// but the check is here rather than assumed, because it is one line and the
// failure mode is arbitrary file read.
if (!/^[a-f0-9]{8,64}$/i.test(id)) throw new Error("Bad attachment id.");
return path.join(attachmentDir(), id);
}
/**
* What these bytes actually are, if they are a raster image.
*
* The serving route uses this to decide between "render inline as an image"
* and "download as an opaque file" — and it reads the BYTES, not the filename,
* because the filename is whatever the uploader typed. Only the four raster
* families are recognised: they are the ones a browser can decode without
* executing anything. SVG never appears here — it is XML with a script tag,
* and there is no magic number that makes that safe.
*/
export function sniffImage(bytes: Buffer): string | null {
if (bytes.length < 12) return null;
// PNG: ‰PNG\r\n\x1a\n
if (bytes.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
return "image/png";
}
// JPEG: FF D8 FF
if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
return "image/jpeg";
}
// GIF: GIF87a / GIF89a
const head6 = bytes.subarray(0, 6).toString("latin1");
if (head6 === "GIF87a" || head6 === "GIF89a") {
return "image/gif";
}
// WebP: RIFF....WEBP
if (
bytes.subarray(0, 4).toString("latin1") === "RIFF" &&
bytes.subarray(8, 12).toString("latin1") === "WEBP"
) {
return "image/webp";
}
return null;
}
07e931b46This file is pinned to the selected release. Download the original to open it in your design tool.