import {UploadedFile} from '../uploaded-file'; import {message} from '../../i18n/message'; import {prettyBytes} from '../utils/pretty-bytes'; import {MessageDescriptor} from '../../i18n/message-descriptor'; import match from 'mime-match'; export interface Restrictions { maxFileSize?: number; allowedFileTypes?: string[]; blockedFileTypes?: string[]; } export function validateUpload( file: UploadedFile, restrictions?: Restrictions ): MessageDescriptor | void { if (!restrictions) return; const {maxFileSize, allowedFileTypes, blockedFileTypes} = restrictions; if (maxFileSize && file.size != null && file.size > maxFileSize) { return message('`:file` exceeds maximum allowed size of :size', { values: {file: file.name, size: prettyBytes(maxFileSize)}, }); } if (allowedFileTypes?.length) { if (!fileMatchesTypes(file, allowedFileTypes)) { return message('This file type is not allowed'); } } if (blockedFileTypes?.length) { if (fileMatchesTypes(file, blockedFileTypes)) { return message('This file type is not allowed'); } } } function fileMatchesTypes(file: UploadedFile, types: string[]): boolean { return ( types // support multiple file types in a string (video/mp4,audio/mp3,image/png) .map(type => type.split(',')) .flat() .some(type => { // check if this is a mime-type if (type.includes('/')) { if (!file.mime) return false; return match(file.mime.replace(/;.*?$/, ''), type); } // otherwise this is likely an extension const extension = type.replace('.', '').toLowerCase(); if (extension && file.extension) { return file.extension.toLowerCase() === extension; } return false; }) ); }