Skip to main content

File Plugin

Handles multipart/form-data file uploads with comprehensive security features. Automatically parses uploaded files, validates them, sanitizes filenames, and provides access through req.files and req.file.

Quick Start

import { Server } from 'balda-js';

const server = new Server({
plugins: {
file: {
maxFileSize: '5mb'
}
}
});

Configuration

All options are optional. Defaults: maxFileSize: "1mb", maxFiles: 10, allowedMimeTypes: [] (all types).

maxFileSize

Maximum size for each uploaded file:

file: {
maxFileSize: '5mb' // 5 megabytes (default: 1mb)
}

file: {
maxFileSize: '500kb' // 500 kilobytes
}

maxFiles

Maximum number of files per request:

file: {
maxFiles: 3 // Default: 10
}

allowedMimeTypes

Whitelist of allowed MIME types:

file: {
allowedMimeTypes: [
'image/jpeg',
'image/png',
'image/gif',
'application/pdf'
]
}

// Empty array (default) allows all MIME types
file: {
allowedMimeTypes: []
}

Usage

Single File Upload

@controller('/api')
export class UploadController {
@post('/upload')
async uploadFile(req: Request, res: Response) {
const file = req.file; // Single file

if (!file) {
return res.badRequest({ error: 'No file uploaded' });
}

res.json({
filename: file.filename,
originalFilename: file.originalFilename,
size: file.size,
mimeType: file.mimeType,
path: file.path
});
}
}

Multiple Files Upload

@post('/upload/multiple')
async uploadMultiple(req: Request, res: Response) {
const files = req.files; // Array of files

if (!files || files.length === 0) {
return res.badRequest({ error: 'No files uploaded' });
}

const fileInfos = files.map(f => ({
filename: f.filename,
size: f.size,
mimeType: f.mimeType
}));

res.json({ files: fileInfos });
}

HTML Form Example

<form action="/api/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>

<!-- Multiple files -->
<form action="/api/upload/multiple" method="POST" enctype="multipart/form-data">
<input type="file" name="files" multiple />
<button type="submit">Upload Files</button>
</form>

File Object

Each file object contains:

{
filename: string; // Sanitized filename (e.g., "avatar.png")
originalFilename: string; // Original uploaded filename
path: string; // Temporary file path
size: number; // File size in bytes
mimeType: string; // MIME type (e.g., "image/png")
}

Security Features

Filename Sanitization

Automatically removes:

  • Path traversal (../)
  • Directory separators (/, \)
  • Null bytes
  • Control characters
// Input: "../../../etc/passwd"
// Sanitized: "etcpasswd"

// Input: "file\x00.txt"
// Sanitized: "file.txt"

Cryptographically Secure Temporary Files

Temporary files use UUID-based filenames to prevent:

  • Filename collisions
  • Predictable paths
  • Overwriting attacks

Automatic Cleanup

Temporary files are automatically deleted after request completion, even if errors occur.

Error Responses

File Too Large

// Response: 413 Payload Too Large
{
"error": "File size exceeds limit"
}

Too Many Files

// Response: 400 Bad Request
{
"error": "Too many files. Maximum 10 allowed"
}

Invalid MIME Type

// Response: 400 Bad Request
{
"error": "Invalid file type. Allowed: image/jpeg, image/png"
}

Missing Content-Type

// Response: 400 Bad Request
{
"error": "Content-Type must be multipart/form-data"
}

Complete Example

const server = new Server({
plugins: {
file: {
maxFileSize: '10mb',
maxFiles: 5,
allowedMimeTypes: [
'image/jpeg',
'image/png',
'image/gif',
'application/pdf'
]
}
}
});

@controller('/api')
export class FileController {
@post('/upload')
async handleUpload(req: Request, res: Response) {
const file = req.file;

if (!file) {
return res.badRequest({ error: 'No file provided' });
}

// Process file (e.g., move to permanent storage)
await moveFile(file.path, `uploads/${file.filename}`);

res.json({
success: true,
filename: file.filename,
size: file.size
});
}
}

Common Patterns

Image Upload with Validation

file: {
maxFileSize: '5mb',
maxFiles: 1,
allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp']
}

Document Upload

file: {
maxFileSize: '10mb',
maxFiles: 3,
allowedMimeTypes: [
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
]
}

Profile Picture Upload

file: {
maxFileSize: '2mb',
maxFiles: 1,
allowedMimeTypes: ['image/jpeg', 'image/png']
}

Performance Tips

  • Set reasonable maxFileSize limits
  • Use allowedMimeTypes to prevent unwanted files
  • Store files in object storage (S3, etc.) for production
  • Consider using streaming for very large files
  • Validate file contents, not just MIME types