typed_file_validator
typed_file_validator is a dependency-free Dart 3 library for validating uploaded files by their binary signature. It detects JPEG, PNG, and PDF files from magic bytes instead of trusting a user-controlled filename or MIME header.
Why use it
File extensions and request headers can be forged. This package inspects the beginning of the content and compares it with known signatures. Header inspection uses a bounded buffer, so validation does not load an entire file into memory.
The package is suitable for Dart Frog, Shelf, Serverpod, Flutter, and command-line applications. It has no runtime dependencies outside the Dart SDK.
Installation
Add the package to pubspec.yaml:
dependencies:
typed_file_validator: ^0.1.0-beta.1
Then run dart pub get.
Quick start
import 'dart:typed_data';
import 'package:typed_file_validator/typed_file_validator.dart';
Future<void> main() async {
final validator = FileValidator()
.allow([FileType.jpeg, FileType.png])
.maxSizeInMB(10)
.checkExtensionSpoofing(true);
final result = await validator.validateBytes(
Uint8List.fromList([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]),
fileName: 'avatar.png',
);
switch (result) {
case ValidFile(:final fileType, :final size):
print('Accepted ${fileType.mimeType}; $size bytes.');
case InvalidFile(:final error):
print('Rejected: ${error.message}');
}
}
Sources
MemoryBinarySource validates a Uint8List, FileBinarySource reads a header from a dart:io file, and StreamBinarySource reads only the bounded header from a stream. All sources implement BinarySource, so applications can provide their own source abstraction.
final result = await FileValidator().validate(
FileBinarySource(File('/tmp/upload.pdf')),
fileName: 'upload.pdf',
);
final streamResult = await FileValidator().validateStream(
request,
fileName: 'upload.pdf',
);
For stream sources, the length is not known unless the application supplies it through a custom source. Consequently, a stream result reports the inspected header length. Enforce request or content-length limits at the HTTP boundary when a stream length is unavailable.
Supported types
| Type | Extensions | MIME type | Signature |
|---|---|---|---|
| JPEG | .jpg, .jpeg |
image/jpeg |
FF D8 FF |
| PNG | .png |
image/png |
89 50 4E 47 0D 0A 1A 0A |
.pdf |
application/pdf |
%PDF- |
Results and errors
A successful validation returns ValidFile, including the detected FileType and known size. A failed validation returns InvalidFile with one of FileTooLargeError, ExtensionSpoofingError, UnrecognizedFileType, DisallowedFileType, or FileReadError.
Security notes
Magic-byte validation identifies the format indicated by the beginning of a file; it is not a full parser or malware scanner. Continue to apply authentication, authorization, storage isolation, quotas, antivirus scanning, and safe content-disposition policies appropriate to the application.
Development
Run the following commands from the package root:
dart pub get
dart format .
dart analyze
dart test
License
This package is distributed under the MIT License. See LICENSE.