• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nestjs / nest / 837e18fc-8678-46c2-8d75-8d045ee82c96

21 Apr 2025 08:00AM UTC coverage: 89.318% (-0.003%) from 89.321%
837e18fc-8678-46c2-8d75-8d045ee82c96

Pull #14995

circleci

mag123c
feat(common): Add fallbackToMimetype support in FileTypeValidator

Introduce `fallbackToMimetype` option to allow fallback to mimetype validation
when magic number detection fails (e.g., for small or undetectable buffers like text or CSV files).

Also enhanced `buildErrorMessage()` to reflect precise validation failure reasons
depending on buffer presence and mimetype state.

Added unit tests to cover fallback logic and error message variants.
Pull Request #14995: feat(common): Add fallbackToMimetype support in FileTypeValidator

2690 of 3378 branches covered (79.63%)

11 of 12 new or added lines in 1 file covered. (91.67%)

7166 of 8023 relevant lines covered (89.32%)

16.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.0
/packages/common/pipes/file/file-type.validator.ts
1
import { FileValidator } from './file-validator.interface';
1✔
2
import { IFile } from './interfaces';
3
import { loadEsm } from 'load-esm';
1✔
4

5
export type FileTypeValidatorOptions = {
6
  fileType: string | RegExp;
7

8
  /**
9
   * If `true`, the validator will skip the magic numbers validation.
10
   * This can be useful when you can't identify some files as there are no common magic numbers available for some file types.
11
   * @default false
12
   */
13
  skipMagicNumbersValidation?: boolean;
14

15
  /**
16
   * If `true`, and magic number check fails, fallback to mimetype comparison.
17
   * @default false
18
   */
19
  fallbackToMimetype?: boolean;
20
};
21

22
/**
23
 * Defines the built-in FileTypeValidator. It validates incoming files by examining
24
 * their magic numbers using the file-type package, providing more reliable file type validation
25
 * than just checking the mimetype string.
26
 *
27
 * @see [File Validators](https://docs.nestjs.com/techniques/file-upload#validators)
28
 *
29
 * @publicApi
30
 */
31
export class FileTypeValidator extends FileValidator<
1✔
32
  FileTypeValidatorOptions,
33
  IFile
34
> {
35
  buildErrorMessage(file?: IFile): string {
36
    const expected = this.validationOptions.fileType;
4✔
37

38
    if (file?.mimetype) {
4✔
39
      const baseMessage = `Validation failed (current file type is ${file.mimetype}, expected type is ${expected})`;
3✔
40

41
      /**
42
       * If fallbackToMimetype is enabled, this means the validator failed to detect the file type
43
       * via magic number inspection (e.g. due to an unknown or too short buffer),
44
       * and instead used the mimetype string provided by the client as a fallback.
45
       *
46
       * This message clarifies that fallback logic was used, in case users rely on file signatures.
47
       */
48
      if (this.validationOptions.fallbackToMimetype) {
3!
NEW
49
        return `${baseMessage} - magic number detection failed, used mimetype fallback`;
×
50
      }
51

52
      return baseMessage;
3✔
53
    }
54

55
    return `Validation failed (expected type is ${expected})`;
1✔
56
  }
57

58
  async isValid(file?: IFile): Promise<boolean> {
59
    if (!this.validationOptions) {
18!
60
      return true;
×
61
    }
62

63
    const isFileValid = !!file && 'mimetype' in file;
18✔
64

65
    // Skip magic number validation if set
66
    if (this.validationOptions.skipMagicNumbersValidation) {
18✔
67
      return (
1✔
68
        isFileValid && !!file.mimetype.match(this.validationOptions.fileType)
2✔
69
      );
70
    }
71

72
    if (!isFileValid || !file.buffer) return false;
17✔
73

74
    try {
14✔
75
      const { fileTypeFromBuffer } =
76
        await loadEsm<typeof import('file-type')>('file-type');
14✔
77
      const fileType = await fileTypeFromBuffer(file.buffer);
14✔
78

79
      if (fileType) {
12✔
80
        // Match detected mime type against allowed type
81
        return !!fileType.mime.match(this.validationOptions.fileType);
6✔
82
      }
83

84
      /**
85
       * Fallback logic: If file-type cannot detect magic number (e.g. file too small),
86
       * Optionally fall back to mimetype string for compatibility.
87
       * This is useful for plain text, CSVs, or files without recognizable signatures.
88
       */
89
      if (this.validationOptions.fallbackToMimetype) {
6✔
90
        return !!file.mimetype.match(this.validationOptions.fileType);
2✔
91
      }
92
      return false;
4✔
93
    } catch {
94
      return false;
2✔
95
    }
96
  }
97
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc