Review a file-upload MIME policy

src/upload-policy.tsTypeScript
@@ -0,0 +1,38 @@
1+const MAX_UPLOAD_BYTES = 5 * 1024 * 1024;
2+
3+export interface UploadCandidate {
4+ filename: string;
5+ claimedMime: string;
6+ declaredSize: number;
7+ bytes: Uint8Array;
8+}
9+
10+export interface MimeSniffer {
11+ sniff(bytes: Uint8Array): "image/jpeg" | "image/png" | "application/pdf" | "unknown";
12+}
13+
14+export type ValidationResult =
15+ | { valid: true; mime: string }
16+ | { valid: false; reason: string };
17+
18+export function validateUpload(
19+ candidate: UploadCandidate,
20+ _sniffer: MimeSniffer,
21+): ValidationResult {
22+ if (candidate.declaredSize > MAX_UPLOAD_BYTES) {
23+ return { valid: false, reason: "File is too large" };
24+ }
25+
26+ if (
27+ !candidate.claimedMime.startsWith("image/") &&
28+ candidate.claimedMime !== "application/pdf"
29+ ) {
30+ return { valid: false, reason: "Unsupported file type" };
31+ }
32+
33+ if (candidate.filename.endsWith(".exe")) {
34+ return { valid: false, reason: "Unsupported extension" };
35+ }
36+
37+ return { valid: true, mime: candidate.claimedMime };
38+}