diff --git a/packages/common/pipes/file/file-type.validator.ts b/packages/common/pipes/file/file-type.validator.ts index 33404914992..240d3efe86a 100644 --- a/packages/common/pipes/file/file-type.validator.ts +++ b/packages/common/pipes/file/file-type.validator.ts @@ -1,11 +1,15 @@ import { FileValidator } from './file-validator.interface'; export type FileTypeValidatorOptions = { - fileType: string; + fileType: string | RegExp; }; /** - * Defines the built-in FileType File Validator + * Defines the built-in FileType File Validator. It validates incoming files mime-type + * matching a string or a regular expression. Note that this validator uses a naive strategy + * to check the mime-type and could be fooled if the client provided a file with renamed extension. + * (for instance, renaming a 'malicious.bat' to 'malicious.jpeg'). To handle such security issues + * with more reliability, consider checking against the file's [magic-numbers](https://en.wikipedia.org/wiki/Magic_number_%28programming%29) * * @see [File Validators](https://docs.nestjs.com/techniques/file-upload#validators) * @@ -25,6 +29,8 @@ export class FileTypeValidator extends FileValidator { return false; } - return (file.mimetype as string).endsWith(this.validationOptions.fileType); + return Boolean( + (file.mimetype as string).match(this.validationOptions.fileType), + ); } } diff --git a/packages/common/test/pipes/file/file-type.validator.spec.ts b/packages/common/test/pipes/file/file-type.validator.spec.ts index c4248f66a08..8b58d114033 100644 --- a/packages/common/test/pipes/file/file-type.validator.spec.ts +++ b/packages/common/test/pipes/file/file-type.validator.spec.ts @@ -27,6 +27,18 @@ describe('FileTypeValidator', () => { expect(fileTypeValidator.isValid(requestFile)).to.equal(true); }); + it('should return true when the file mimetype matches the specified regexp', () => { + const fileTypeValidator = new FileTypeValidator({ + fileType: /word/, + }); + + const requestFile = { + mimetype: 'application/msword', + }; + + expect(fileTypeValidator.isValid(requestFile)).to.equal(true); + }); + it('should return false when the file mimetype is different from the specified', () => { const fileTypeValidator = new FileTypeValidator({ fileType: 'image/jpeg', @@ -39,6 +51,18 @@ describe('FileTypeValidator', () => { expect(fileTypeValidator.isValid(requestFile)).to.equal(false); }); + it('should return false when the file mimetype does not match the provided regexp', () => { + const fileTypeValidator = new FileTypeValidator({ + fileType: /mp4/, + }); + + const requestFile = { + mimetype: 'image/png', + }; + + expect(fileTypeValidator.isValid(requestFile)).to.equal(false); + }); + it('should return false when the file mimetype was not provided', () => { const fileTypeValidator = new FileTypeValidator({ fileType: 'image/jpeg',