Tiptapex.Upload.Validator (Tiptapex v0.1.2)

Copy Markdown View Source

Server-side validation for editor uploads: size limit, content-type verification via magic-byte sniffing, and filename sanitization.

The client's Content-Type header is attacker-controlled; for the sniffable formats (images, videos, PDF) the actual file signature must agree with the claimed type or the upload is rejected. Types without a reliable signature (e.g. text/plain) are accepted based on the allow-list alone.

Summary

Functions

The default allowed MIME list.

The default maximum size in bytes (25 MB).

Sanitizes a client-provided filename: basename only, control characters and path separators stripped, length-capped. Falls back to "file".

Detects the file's MIME type from its magic bytes. Returns {:ok, type} for the known signatures or :unknown.

Functions

default_allowed()

The default allowed MIME list.

default_max_bytes()

The default maximum size in bytes (25 MB).

sanitize_filename(filename)

@spec sanitize_filename(String.t() | nil) :: String.t()

Sanitizes a client-provided filename: basename only, control characters and path separators stripped, length-capped. Falls back to "file".

sniff(path)

@spec sniff(Path.t()) :: {:ok, String.t()} | :unknown

Detects the file's MIME type from its magic bytes. Returns {:ok, type} for the known signatures or :unknown.

validate(upload, opts \\ [])

@spec validate(
  Plug.Upload.t(),
  keyword()
) ::
  {:ok,
   %{content_type: String.t(), size: non_neg_integer(), filename: String.t()}}
  | {:error, :empty | :too_large | :unsupported_type | :content_type_mismatch}

Validates a Plug.Upload.

Options: :max_bytes (default 25 MB) and :allowed (MIME allow-list).

Returns {:ok, %{content_type: type, size: bytes, filename: sanitized}} with the verified content type, or {:error, reason} where reason is :empty, :too_large, :unsupported_type, or :content_type_mismatch.