first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
# `mime.ts`
## Purpose
Cross-checks the declared `Content-Type` against the plugin's configured allow/deny lists AND (optionally) against the magic-bytes signature of the upload's first 4 KiB. This is the spoof-detection layer: a client uploading an `.exe` with `Content-Type: text/plain` is rejected because the sniffed type disagrees with the declared one.
## Features
- Three rejection vectors: denylist, allow-list (when non-empty), and sniff-mismatch.
- Canonical lowercase `type/subtype` form returned so every downstream record stores a normalised value.
- Structured `context.reason` (`"deny-list"`, `"allow-list"`, `"sniff-mismatch"`, `"malformed"`) so handlers and dashboards can branch on rejection cause without parsing message text.
- Treats malformed declared `Content-Type` as a 415 rather than a 400 because the user payload was the data we couldn't accept — not the route shape.
- Sniff comparison only fires when magic bytes produce a confident match (it never blocks unknown formats).
## Usage: Basic
```ts
import { validateMime } from "@suaveplan/api-plugin-file-upload/validators/mime";
const canonical = validateMime({
declaredMimeType: "image/png",
allowedMimeTypes: ["image/png", "image/jpeg"],
deniedMimeTypes: [],
});
```
## Usage: Advanced
```ts
import { validateMime, FileUploadError } from "@suaveplan/api-plugin-file-upload";
const sample = new Uint8Array(buf.slice(0, 4096));
try {
validateMime({
declaredMimeType: "text/plain",
allowedMimeTypes: [],
deniedMimeTypes: [],
sniffSample: sample,
});
} catch (err) {
if (err instanceof FileUploadError) {
// err.context.reason === "sniff-mismatch"
}
}
```
## API Reference
- `ValidateMimeOptions` — `{ declaredMimeType, allowedMimeTypes, deniedMimeTypes, sniffSample? }`.
- `validateMime(opts: ValidateMimeOptions): string` — returns the canonical type; throws `FileUploadError(UPLOAD.MIME_REJECTED)` on any rejection vector.
## Implementation Notes
- `@suaveplan/mime`'s `detectFromMagicBytes` returns `undefined` for unrecognised payloads; we treat that as "no signal" and skip the cross-check, so unknown binary formats still upload successfully if the declared type is otherwise allowed.
- The "allow-list" semantics only engage when the array is non-empty so the default config (`allowedMimeTypes: []`) means "rely on the denylist alone".
- Comparisons are lowercase string-equality, not glob/regex, so callers needing `image/*` semantics should pre-expand the list at config time.