| import { |
| BadRequestException, |
| Injectable, |
| PipeTransform, |
| } from '@nestjs/common'; |
| |
| const { fromBuffer } = require('file-type'); |
|
|
| const ALLOWED_MIME_TYPES = new Set<string>([ |
| 'image/jpeg', |
| 'image/png', |
| 'image/gif', |
| 'image/webp', |
| 'image/avif', |
| 'image/bmp', |
| 'image/tiff', |
| 'video/mp4', |
| ]); |
|
|
| @Injectable() |
| export class CustomFileValidationPipe implements PipeTransform { |
| async transform(value: any) { |
| if (!value || typeof value !== 'object') { |
| return value; |
| } |
|
|
| |
| if (!('buffer' in value) && !('mimetype' in value) && !('fieldname' in value)) { |
| return value; |
| } |
|
|
| if (!value.buffer || !Buffer.isBuffer(value.buffer)) { |
| throw new BadRequestException('Invalid file upload.'); |
| } |
|
|
| const detected = await fromBuffer(value.buffer); |
| if (!detected || !ALLOWED_MIME_TYPES.has(detected.mime)) { |
| throw new BadRequestException('Unsupported file type.'); |
| } |
|
|
| const maxSize = getMaxSize(detected.mime); |
| if (value.size > maxSize) { |
| throw new BadRequestException( |
| `File size exceeds the maximum allowed size of ${maxSize} bytes.` |
| ); |
| } |
|
|
| value.mimetype = detected.mime; |
| const safeBase = (value.originalname || 'upload') |
| .replace(/\.[^./\\]*$/, '') |
| .replace(/[\\/]/g, '_') |
| .slice(0, 100) || 'upload'; |
| value.originalname = `${safeBase}.${detected.ext}`; |
|
|
| return value; |
| } |
|
|
| } |
|
|
| export function getMaxSize(mimeType: string): number { |
| if (mimeType.startsWith('image/')) { |
| return 10 * 1024 * 1024; |
| } else if (mimeType.startsWith('video/')) { |
| return 1024 * 1024 * 1024; |
| } else { |
| throw new BadRequestException('Unsupported file type.'); |
| } |
| } |
|
|