├── .eslintrc.js
├── .gitignore
├── LICENSE
├── README.md
├── jest.config.js
├── package.json
├── src
├── assets
│ ├── detection.gif
│ └── validation.gif
├── core
│ ├── file-types
│ │ ├── audio.ts
│ │ ├── compressed.ts
│ │ ├── image.ts
│ │ ├── index.ts
│ │ ├── other.ts
│ │ └── video.ts
│ ├── index.ts
│ ├── interfaces
│ │ ├── dto
│ │ │ ├── detected-file-info.ts
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ └── options
│ │ │ ├── detect-file-options.ts
│ │ │ ├── file-validator-options.ts
│ │ │ ├── index.ts
│ │ │ ├── validate-file-type-options.ts
│ │ │ └── zip-validator-options.ts
│ └── types
│ │ ├── file-info.ts
│ │ ├── file-signature.ts
│ │ └── index.ts
├── detection
│ └── index.ts
├── index.ts
├── utils
│ └── index.ts
└── validation
│ ├── audio.ts
│ ├── compressed.ts
│ ├── image.ts
│ ├── index.ts
│ ├── other.ts
│ └── video.ts
├── test
├── detection
│ ├── detection.spec.ts
│ ├── image
│ │ └── image.spec.ts
│ ├── other
│ │ └── other.spec.ts
│ └── video
│ │ └── videos.spec.ts
└── validation
│ ├── audio
│ └── audio.spec.ts
│ ├── image
│ └── images.spec.ts
│ ├── other
│ └── other.spec.ts
│ ├── validation.spec.ts
│ └── video
│ └── videos.spec.ts
├── tsconfig.json
└── yarn.lock
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
3 | parser: "@typescript-eslint/parser",
4 | plugins: ["@typescript-eslint"],
5 | root: true,
6 | plugins: ["jest"],
7 | ignorePatterns: [".eslintrc.js", "jest.config.js", "dist/", ".yarn/"],
8 | overrides: [
9 | {
10 | files: ["**/__tests__/**/*.ts", "**/*.test.ts", "**/*.spec.ts"],
11 | rules: {
12 | "@typescript-eslint/no-explicit-any": "off",
13 | },
14 | },
15 | ],
16 | };
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
106 | .vscode
107 | package-lock.json
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 nir11
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # File Type Checker
2 |
3 |
4 | Detect and validate file types by their signatures (✨magic numbers✨)
5 |
6 |
7 | - Supports a wide range of file types.
8 | - Detects the type of a given file using a detection mechanism.
9 | - Validates files against their requested types using signatures.
10 | - Provides flexibility for the file data type: choose from `Array`, `ArrayBuffer`, or `Uint8Array`.
11 | - Written in TypeScript for full typing support.
12 | - Works on both server and client sides.
13 | - ⚠️ Note: For optimized handling of large files, refer to the [Optimization](#optimization) section.
14 |
15 | ```js
16 | import fileTypeChecker from "file-type-checker";
17 |
18 | // ... Read file as `Array`, `ArrayBuffer`, or `Uint8Array`.
19 |
20 | fileTypeChecker.detectFile(file); // Returns the detected file info
21 | fileTypeChecker.validateFileType(file, ["png", "gif", "jpeg"]); // Returns true if the file includes an image signature from the accepted list
22 | fileTypeChecker.isPNG(file); // Returns true if the file includes a valid PNG image signature
23 |
24 | // ... And many more validator functions for each supported type.
25 | ```
26 |
27 | ## Installation
28 |
29 | Using npm:
30 |
31 | npm i file-type-checker
32 |
33 | ## Quick Overview
34 |
35 | ### Detection sample:
36 |
37 | 
38 |
39 | ### Validation sample:
40 |
41 | 
42 |
43 | ## Resources
44 |
45 | - [GCK'S File Signatures Table](https://www.garykessler.net/library/file_sigs.html)
46 | - [Wikipedia - List of file signatures](https://en.wikipedia.org/wiki/List_of_file_signatures)
47 |
48 | ## Supported Files
49 |
50 | | Type |
51 | | :----- |
52 | | 7z |
53 | | aac |
54 | | amr |
55 | | avi |
56 | | bmp |
57 | | bpg |
58 | | blend |
59 | | cr2 |
60 | | doc |
61 | | elf |
62 | | exe |
63 | | exr |
64 | | flac |
65 | | flv |
66 | | gif |
67 | | heic |
68 | | ico |
69 | | indd |
70 | | jpeg |
71 | | lzh |
72 | | m4a |
73 | | m4v |
74 | | mach-o |
75 | | mkv |
76 | | mov |
77 | | mp3 |
78 | | mp4 |
79 | | ogg |
80 | | pcap |
81 | | pdf |
82 | | pbm |
83 | | pgm |
84 | | png |
85 | | ppm |
86 | | psd |
87 | | ps |
88 | | rar |
89 | | rtf |
90 | | sqlite |
91 | | stl |
92 | | swf |
93 | | ttf |
94 | | wav |
95 | | webm |
96 | | webp |
97 | | zip |
98 |
99 | ## Note
100 |
101 | - Only file signatures are checked; additional validation may be necessary.
102 | - To ensure optimal performance all files should be at least 64 bytes in size.
103 | - For large files, pass only a chunk from the beggining of the file to ensure optimal performance.
104 | - To ensure optimal performance with ZIP files, it is recommended to utilize the 'chunkSize' optional parameter and pass the first 30000 bytes.
105 | - This package assumes little-endian byte order; adjust code for big-endian.
106 |
107 | ## Example Usage
108 |
109 | ⚠️ Note: These examples demonstrate reading the entire file, which may be slow for large files.
110 | For optimized handling of large files, refer to the [Optimization](#optimization) section.
111 |
112 | ### Browser (`React`, `Angular`, `Vanilla JS`, etc.):
113 |
114 | Validate file signature against a list if file types (React app example):
115 |
116 | ```js
117 | import fileTypeChecker from "file-type-checker";
118 |
119 | // Function to handle file input change
120 | const handleFileInputChange = (event) => {
121 | try {
122 | const file = event.target.files[0];
123 | const reader = new FileReader();
124 | const types = ["jpeg", "png", "gif"];
125 |
126 | // When the file is loaded, validate its type
127 | reader.onload = () => {
128 | const isImage = fileTypeChecker.validateFileType(reader.result, types);
129 | console.log(isImage); // Returns true if the file includes an image signature from the accepted list
130 | };
131 |
132 | // Use the FileReader API to read the file as an ArrayBuffer
133 | reader.readAsArrayBuffer(file);
134 | } catch (err) {
135 | console.error("Error: ", err.message);
136 | }
137 | };
138 |
139 | return (
140 |
141 |
142 |
143 | );
144 | ```
145 |
146 | ```js
147 | import fileTypeChecker from "file-type-checker";
148 |
149 | // Function to handle file input change
150 | const handleFileInputChange = (event) => {
151 | try {
152 | const file = event.target.files[0];
153 | const reader = new FileReader();
154 | const types = ["mp4", "avi", "mov"];
155 |
156 | // When the file is loaded, validate its type
157 | reader.onload = () => {
158 | const isVideo = fileTypeChecker.validateFileType(
159 | reader.result,
160 | types,
161 | { excludeSimilarTypes: true } // (optional parameter) if we don't want to validate 'm4a' signature as 'mp4' type
162 | );
163 | console.log(isVideo); // Returns true if the file includes a video signature from the accepted list
164 | };
165 |
166 | // Use the FileReader API to read the file as an ArrayBuffer
167 | reader.readAsArrayBuffer(file);
168 | } catch (err) {
169 | console.error("Error: ", err.message);
170 | }
171 | };
172 |
173 | return (
174 |
175 |
176 |
177 | );
178 | ```
179 |
180 | Validate file signature against a single file type (React app example):
181 |
182 | ```js
183 | import fileTypeChecker from "file-type-checker";
184 |
185 | // Function to handle file input change
186 | const handleFileInputChange = (event) => {
187 | try {
188 | const file = event.target.files[0];
189 | const reader = new FileReader();
190 |
191 | // When the file is loaded, check if its type is PNG
192 | reader.onload = () => {
193 | const isPNG = fileTypeChecker.isPNG(reader.result);
194 | console.log(isPNG); // Returns true if the file includes a vali PNG image signature
195 | };
196 |
197 | // Use the FileReader API to read the file as an ArrayBuffer
198 | reader.readAsArrayBuffer(file);
199 | } catch (err) {
200 | console.error("Error validating file type: ", err.message);
201 | }
202 | };
203 |
204 | return (
205 |
206 |
207 |
208 | );
209 | ```
210 |
211 | Detect file by its signature (React app example):
212 |
213 | ```js
214 | import fileTypeChecker from "file-type-checker";
215 |
216 | // Function to handle file input change
217 | const handleFileInputChange = (event) => {
218 | try {
219 | const file = event.target.files[0];
220 | const reader = new FileReader();
221 |
222 | // When the file is loaded, detect its type
223 | reader.onload = () => {
224 | const detectedFile = fileTypeChecker.detectFile(reader.result);
225 | console.log(detectedFile) >
226 | {
227 | extension: "png",
228 | mimeType: "image/png",
229 | description:
230 | "PNG (Portable Network Graphics) is a lossless image compression format that supports a wide range of color depths and transparency and is widely used for high-quality graphics.",
231 | signature: {
232 | sequence: ["89", "50", "4e", "47", "d", "a", "1a", "a"],
233 | },
234 | };
235 | };
236 |
237 | // Use the FileReader API to read the file as an ArrayBuffer
238 | reader.readAsArrayBuffer(file);
239 | } catch (err) {
240 | console.error("Error: ", err.message);
241 | }
242 | };
243 |
244 | return (
245 |
246 |
247 |
248 | );
249 | ```
250 |
251 | ### Node.js:
252 |
253 | Detect file by its signature (synchronously, will be slow with large files):
254 |
255 | ```js
256 | import fileTypeChecker from "file-type-checker";
257 | import fs from "fs";
258 |
259 | // Read a file as an ArrayBuffer
260 | const file = fs.readFileSync("/path/to/my/file.mp4").buffer;
261 |
262 | const detectedFile = fileTypeChecker.detectFile(file);
263 |
264 | console.log(detectedFile)
265 | > {
266 | "extension": "mp4",
267 | "mimeType": "video/mp4",
268 | "description": "A multimedia container format widely used for storing audio, video, and other data, and is known for its high compression efficiency and compatibility with many devices",
269 | "signature": {
270 | "sequence": ["66","74","79","70","69","73","6f","6d"],
271 | "description" (optional): "ISO Base Media file (MPEG-4) v1",
272 | "offset" (optional): 4
273 | }
274 | }
275 | ```
276 |
277 | Validate file signature against a list of file types:
278 |
279 | ```js
280 | import fileTypeChecker from "file-type-checker";
281 | import fs from "fs";
282 | //const fileTypeChecker = require("file-type-checker"); // legacy way
283 | //const fs = require("fs"); // legacy way
284 |
285 | // Read a file as an ArrayBuffer
286 | const file = fs.readFileSync("/path/to/my/file.png").buffer;
287 |
288 | // A list of accepted image file types
289 | const types = ["jpeg", "png", "gif"];
290 |
291 | const isImage = fileTypeChecker.validateFileType(
292 | file,
293 | types,
294 | { chunkSize: 32 } // (optional parameter) all images signatures exists in the first 32 bytes
295 | );
296 |
297 | console.log(isImage); // Returns true the file includes an image signature from the accepted list
298 | ```
299 |
300 | Validate file signature against a single file type:
301 |
302 | ```js
303 | import fileTypeChecker from "file-type-checker";
304 | import fs from "fs";
305 | //const fileTypeChecker = require("file-type-checker"); // legacy way
306 | //const fs = require("fs"); // legacy way
307 |
308 | // Read a file as an ArrayBuffer
309 | const file = fs.readFileSync("/path/to/my/file.png").buffer;
310 |
311 | const isPNG = fileTypeChecker.isPNG(file);
312 |
313 | console.log(isPNG); // Returns true if the file includes a valid PNG image signature
314 | ```
315 |
316 | ## Optimization
317 |
318 | ### 📌 How to use `file-type-checker` efficiently
319 |
320 | To ensure the best performance and avoid excessive memory usage, follow these best practices:
321 |
322 | 1. Read only the first X bytes when detecting file type.
323 |
324 | - Most file signatures exist in the first 64 bytes, except ZIP files that require 32,000 bytes.
325 | - Before calling `detectFile`, `validateFile` or any other validation function, make sure you only pass a chunk from the beginning of the file content.
326 | - This reduces unnecessary file I/O and memory consumption.
327 | - ✅ Node.js example (read first 64 bytes for detection)
328 |
329 | ```
330 | import fileTypeChecker from "file-type-checker";
331 | import fs from "fs";
332 | import path from "path";
333 |
334 | const file = path.resolve("/path/to/my/large/file.mp4");
335 | const CHUNK_SIZE = 64; // All file signatures except ZIP exist in the first 64 bytes
336 | const fileHandle = await fs.promises.open(file, "r");
337 |
338 | const buffer = Buffer.alloc(CHUNK_SIZE);
339 | await fileHandle.read(buffer, 0, CHUNK_SIZE, 0); // Read only the first 64 bytes
340 |
341 | // Detect file type using the first chunk
342 | const detectedFileInfo = fileTypeChecker.detectFile(buffer, {
343 | chunkSize: 64,
344 | });
345 | ```
346 |
347 | - ✅ Browser example (read first 64 bytes using file.slice() ):
348 |
349 | ```
350 | import fileTypeChecker from "file-type-checker";
351 |
352 | const handleFileInputChange = async (event) => {
353 | try {
354 | const file = event.target.files[0];
355 |
356 | // Read only the first 64 bytes for file type detection (optimization)
357 | const buffer = await file.slice(0, 64).arrayBuffer();
358 |
359 | const detectedFile = fileTypeChecker.detectFile(buffer);
360 | console.log("Detected File Type:", detectedFile);
361 | } catch (err) {
362 | console.error("Error: ", err.message);
363 | }
364 | };
365 |
366 | return ;
367 | ```
368 |
369 | 2. Process large files in chunks.
370 |
371 | - Avoid loading the entire file into memory at once.
372 | - Most file signatures exist in the first 64 bytes, except ZIP files that require 32,000 bytes.
373 | - Process files in small chunks instead of reading everything at once.
374 | - ✅ Node.js example (read large files in chunks)
375 |
376 | ```
377 | import fileTypeChecker from "file-type-checker";
378 | import fs from "fs";
379 |
380 | const readFileInChunks = (filePath, chunkSize = 64 * 1024) => {
381 | const stream = fs.createReadStream(filePath, { highWaterMark: chunkSize });
382 | let isFirstChunk = true; // Flag to track the first chunk
383 |
384 | stream.on("data", (chunk) => {
385 | console.log("Chunk read:", chunk);
386 |
387 | if (isFirstChunk) {
388 | const detectedFile = fileTypeChecker.detectFile(chunk);
389 | console.log("Detected File Type:", detectedFile);
390 | isFirstChunk = false; // Prevent further calls to detectFile
391 | }
392 | });
393 |
394 | stream.on("end", () => console.log("Finished reading file."));
395 | };
396 |
397 | readFileInChunks("/path/to/my/large/file.mp4");
398 | ```
399 |
400 | - ✅ Browser example (read large files using streams)
401 |
402 | ```
403 | import fileTypeChecker from "file-type-checker";
404 |
405 | const readFileInChunks = async (file, chunkSize = 64 * 1024) => {
406 | console.log(`Reading file in chunks of ${chunkSize} bytes`);
407 |
408 | const stream = file.stream();
409 | const reader = stream.getReader();
410 | let isFirstChunk = true;
411 | let done = false;
412 |
413 | while (!done) {
414 | const { value, done: isDone } = await reader.read();
415 | done = isDone; // Update loop condition
416 |
417 | if (value) {
418 | console.log("Chunk read:", value);
419 |
420 | if (isFirstChunk) {
421 | const detectedFile = fileTypeChecker.detectFile(value);
422 | console.log("Detected File Type:", detectedFile);
423 | isFirstChunk = false; // Prevent further calls to detectFile
424 | }
425 | }
426 | }
427 |
428 | console.log("Finished reading file.");
429 | };
430 |
431 | const handleFileInputChange = (event) => {
432 | if (!event.target.files.length) return;
433 | readFileInChunks(event.target.files[0]);
434 | };
435 |
436 | return ;
437 | ```
438 |
439 | ## API
440 |
441 | ### detectFile(file, options?)
442 |
443 | Detect the file type of a given file.
444 |
445 | ```js
446 | import fileTypeChecker from "file-type-checker";
447 |
448 | // ...
449 |
450 | const detectedFile = fileTypeChecker.detectFile(file);
451 | > {
452 | "extension": "png",
453 | "mimeType": "image/png",
454 | "description": "PNG (Portable Network Graphics) is a lossless image compression format that supports a wide range of color depths and transparency and is widely used for high-quality graphics.",
455 | "signature": {
456 | "sequence": ["89","50","4e","47","d","a","1a","a"]
457 | }
458 | }
459 | ```
460 |
461 | Parameters:
462 |
463 | - `file` : `Array`, `ArrayBuffer`, or `Uint8Array`- Binary data represents the file content.
464 | - `options` (optional) : `object` - An object that contains additional actions to perfoem on the file:
465 |
466 | - `chunkSize` (optional) : `number` - Specifies the size of the file chunk to analyze, starting from the beginning of the file. For ZIP files, it is recommended to set this to 30,000 bytes for accurate detection. The default value is 64. The default value is 64.
467 |
468 | ⚠️ Note: For optimized handling of large files, refer to the [Optimization](#optimization) section.
469 |
470 | Returns:
471 |
472 | - `object` - An object with information about a file, including its file extension, MIME type, and file signature. The returned object has the following properties:
473 | - `extension` - A string that represents file extension (e.g., "png").
474 | - `mimeType` - A string that represents the MIME type of the file (e.g., "image/png").
475 | - `description` - A string that provides a short description of the file.
476 | - `signature` - An object that contains information about the file signature, with the following properties:
477 | - `sequence` - An array of hexadecimal strings that represents the bytes in the file signature.
478 | - `description` (optional) - A string that provides a short description of the file signature.
479 | - `offset` (optional) - A number that indicates the offset of the file signature.
480 | - `skippedBytes` (optional) - An array of numbers that indicates the number of bytes that were skipped.
481 | - `compatibleExtensions` (optional): An array of strings that indicates file compatible extensions.
482 | - `undefined` - If no file has found.
483 |
484 | ### validateFileType(file, types, options?)
485 |
486 | Validates the requested file signature against a list of accepted file types.
487 |
488 | ```js
489 | import fileTypeChecker from "file-type-checker";
490 |
491 | // ...
492 |
493 | const isImage = fileTypeChecker.validateFileType(file, ["jpeg", "png", "gif"]);
494 | console.log(isImage); // Returns true the file includes an image signature from the accepted list
495 | ```
496 |
497 | Parameters:
498 |
499 | - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
500 | - `types` : `Array` - A list of accepted file types (from our [supported files](#supported-files)).
501 | - `options` (optional) : `object` - An object that contains additional actions to perfoem on the file:
502 |
503 | - `chunkSize` (optional) : `number` - Specifies the size of the file chunk to analyze, starting from the beginning of the file. For compressed files, it is recommended to set this to 30,000 bytes when validating ZIP files. The default value is 64.
504 |
505 | ⚠️ Note: For optimized handling of large files, refer to the [Optimization](#optimization) section.
506 |
507 | - `excludeSimilarTypes` (optional) : `boolean` - Specifies whether to ignore signatures of similar file types during validation. When validating a `mp4` file, the `m4v` signature will be ignored. When validating a `m4a` file, the `aac` signature will be ignored. The default value is false.
508 |
509 | Returns a `boolean` indicating whether the file is valid.
510 |
511 | ### Validator functions for a single file type:
512 |
513 | All supported files have validator functions that determine if a given file matched the requested type signature.
514 |
515 | ```js
516 | import fileTypeChecker from "file-type-checker";
517 |
518 | // ...
519 |
520 | const is7z = fileTypeChecker.is7z(file); // Returns true if the file includes a valid 7z archive signature
521 | const isAAC = fileTypeChecker.isAAC(file); // Returns true if the file includes a valid AAC audio file signature
522 | const isAMR = fileTypeChecker.isAMR(file); // Returns true if the file includes a valid AMR audio file signature
523 | const isAVI = fileTypeChecker.isAVI(file); // Returns true if the file includes a valid AVI video file signature
524 | const isBMP = fileTypeChecker.isBMP(file); // Returns true if the file includes a valid BMP image signature
525 | const isBPG = fileTypeChecker.isBPG(file); // Returns true if the file includes a valid BPG image signature
526 | const isBLEND = fileTypeChecker.isBLEND(file); // Returns true if the file includes a valid Blender 3D file signature
527 | const isCR2 = fileTypeChecker.isCR2(file); // Returns true if the file includes a valid Canon CR2 raw image signature
528 | const isDOC = fileTypeChecker.isDOC(file); // Returns true if the file includes a valid DOC file signature
529 | const isELF = fileTypeChecker.isELF(file); // Returns true if the file includes a valid ELF executable file signature
530 | const isEXR = fileTypeChecker.isEXR(file); // Returns true if the file includes a valid EXR image signature
531 | const isEXE = fileTypeChecker.isEXE(file); // Returns true if the file includes a valid EXE image signature
532 | const isFLAC = fileTypeChecker.isFLAC(file); // Returns true if the file includes a valid FLAC audio file signature
533 | const isFLV = fileTypeChecker.isFLV(file); // Returns true if the file includes a valid FLV video file signature
534 | const isGIF = fileTypeChecker.isGIF(file); // Returns true if the file includes a valid GIF image signature
535 | const isHEIC = fileTypeChecker.isHEIC(file); // Returns true if the file includes a valid HEIC image signature
536 | const isICO = fileTypeChecker.isICO(file); // Returns true if the file includes a valid ICO image signature
537 | const isINDD = fileTypeChecker.isINDD(file); // Returns true if the file includes a valid Adobe InDesign document signature
538 | const isJPEG = fileTypeChecker.isJPEG(file); // Returns true if the file includes a valid JPEG image signature
539 | const isLZH = fileTypeChecker.isLZH(file); // Returns true if the file includes a valid LZH archive signature
540 | const isM4A = fileTypeChecker.isM4A(file); // Returns true if the file includes a valid M4A audio file signature
541 | const isM4V = fileTypeChecker.isM4V(file); // Returns true if the file includes a valid M4V video file signature
542 | const isMACHO = fileTypeChecker.isMACHO(file); // Returns true if the file includes a valid MACH-O video file
543 | const isMKV = fileTypeChecker.isMKV(file); // Returns true if the file includes a valid MKV video file signature
544 | const isMOV = fileTypeChecker.isMOV(file); // Returns true if the file includes a valid MOV video file signature
545 | const isMP3 = fileTypeChecker.isMP3(file); // Returns true if the file includes a valid MP3 audio file signature
546 | const isMP4 = fileTypeChecker.isMP4(file); // Returns true if the file includes a valid MP4 video file signature
547 | const isOGG = fileTypeChecker.isOGG(file); // Returns true if the file includes a valid OGG audio file signature
548 | const isORC = fileTypeChecker.isORC(file); // Returns true if the file includes a valid ORC file signature
549 | const isPARQUET = fileTypeChecker.isPARQUET(file); // Returns true if the file includes a valid Parquet file signature
550 | const isPBM = fileTypeChecker.isPBM(file); // Returns true if the file includes a valid PBM image signature
551 | const isPCAP = fileTypeChecker.isPCAP(file); // Returns true if the file includes a valid PCAP file signature
552 | const isPDF = fileTypeChecker.isPDF(file); // Returns true if the file includes a valid PDF document signature
553 | const isPGM = fileTypeChecker.isPGM(file); // Returns true if the file includes a valid PGM image signature
554 | const isPNG = fileTypeChecker.isPNG(file); // Returns true if the file includes a valid PNG image signature
555 | const isPPM = fileTypeChecker.isPPM(file); // Returns true if the file includes a valid PPM image
556 | const isPSD = fileTypeChecker.isPSD(file); // Returns true if the file includes a valid PSD image signature
557 | const isPS = fileTypeChecker.isPS(file); // Returns true if the file includes a valid PostScript file signature
558 | const isRAR = fileTypeChecker.isRAR(file); // Returns true if the file includes a valid RAR archive signature
559 | const isRTF = fileTypeChecker.isRTF(file); // Returns true if the file includes a valid RTF document signature
560 | const isSQLite = fileTypeChecker.isSQLite(file); // Returns true if the file includes a valid SQLite database file signature
561 | const isSTL = fileTypeChecker.isSTL(file); // Returns true if the file includes a valid STL 3D model file signature
562 | const isSWF = fileTypeChecker.isSWF(file); // Returns true if the file includes a valid SWF file signature
563 | const isTTF = fileTypeChecker.isTTF(file); // Returns true if the file includes a valid TrueType font file signature
564 | const isWAV = fileTypeChecker.isWAV(file); // Returns true if the file includes a valid WAV audio file signature
565 | const isWEBM = fileTypeChecker.isWEBM(file); // Returns true if the file includes a valid WebM video file signature
566 | const isWEBP = fileTypeChecker.isWEBP(file); // Returns true if the file includes a valid WebP image file signature
567 | const isZIP = fileTypeChecker.isZIP(file); // Returns true if the file includes a valid ZIP archive signature
568 | ```
569 |
570 | #### Image:
571 |
572 | fileTypeChecker.isBMP(file)
573 |
574 | Checks whether a file is a BMP image by inspecting its file signature.
575 |
576 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
577 |
578 | Returns a `boolean` indicating whether the file includes a valid BMP image signature.
579 |
580 |
581 |
582 | fileTypeChecker.isBPG(file)
583 |
584 | Checks whether a file is a BPG image by inspecting its file signature.
585 |
586 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
587 |
588 | Returns a `boolean` indicating whether the file includes a valid BPG image signature.
589 |
590 |
591 |
592 | fileTypeChecker.isCR2(file)
593 |
594 | Checks whether a file is a CR2 image by inspecting its file signature.
595 |
596 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
597 |
598 | Returns a `boolean` indicating whether the file includes a valid CR2 image signature.
599 |
600 |
601 |
602 | fileTypeChecker.isEXR(file)
603 |
604 | Checks whether a file is a EXR image by inspecting its file signature.
605 |
606 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
607 |
608 | Returns a `boolean` indicating whether the file includes a valid EXR image signature.
609 |
610 |
611 |
612 | fileTypeChecker.isGIF(file)
613 |
614 | Checks whether a file is a GIF image by inspecting its file signature.
615 |
616 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
617 |
618 | Returns a `boolean` indicating whether the file includes a valid GIF image signature.
619 |
620 |
621 |
622 | fileTypeChecker.isHEIC(file)
623 |
624 | Checks whether a file is a HEIC image by inspecting its file signature.
625 |
626 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
627 |
628 | Returns a `boolean` indicating whether the file includes a valid HEIC image signature.
629 |
630 |
631 |
632 | fileTypeChecker.isICO(file)
633 |
634 | Checks whether a file is an ICO image by inspecting its file signature.
635 |
636 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
637 |
638 | Returns a `boolean` indicating whether the file includes a valid ICO image signature.
639 |
640 |
641 |
642 | fileTypeChecker.isJPEG(file)
643 |
644 | Checks whether a file is a JPEG image by inspecting its file signature.
645 |
646 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
647 |
648 | Returns a `boolean` indicating whether the file includes a valid JPEG image signature.
649 |
650 |
651 |
652 | fileTypeChecker.isPBM(file)
653 |
654 | Checks whether a file is a PBM image by inspecting its file signature.
655 |
656 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
657 |
658 | Returns a `boolean` indicating whether the file includes a valid PBM image signature.
659 |
660 |
661 |
662 | fileTypeChecker.isPGM(file)
663 |
664 | Checks whether a file is a PGM image by inspecting its file signature.
665 |
666 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
667 |
668 | Returns a `boolean` indicating whether the file includes a valid PGM image signature.
669 |
670 |
671 |
672 | fileTypeChecker.isPNG(file)
673 |
674 | Checks whether a file is a PNG image by inspecting its file signature.
675 |
676 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
677 |
678 | Returns a `boolean` indicating whether the file includes a valid PNG image signature.
679 |
680 |
681 |
682 | fileTypeChecker.isPPM(file)
683 |
684 | Checks whether a file is a PPM image by inspecting its file signature.
685 |
686 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
687 |
688 | Returns a `boolean` indicating whether the file includes a valid PPM image signature.
689 |
690 |
691 |
692 | fileTypeChecker.isPSD(file)
693 |
694 | Checks whether a file is a PSD image by inspecting its file signature.
695 |
696 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
697 |
698 | Returns a `boolean` indicating whether the file includes a valid PSD image signature.
699 |
700 |
701 |
702 | fileTypeChecker.isTTF(file)
703 |
704 | Checks whether a file is a TTF image by inspecting its file signature.
705 |
706 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
707 |
708 | Returns a `boolean` indicating whether the file includes a valid TTF image signature.
709 |
710 |
711 |
712 | #### Video:
713 |
714 | fileTypeChecker.isAVI(file)
715 |
716 | Checks whether a file is an AVI video by inspecting its file signature.
717 |
718 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
719 |
720 | Returns a `boolean` indicating whether the file includes a valid AVI video signature.
721 |
722 |
723 |
724 | fileTypeChecker.isFLV(file)
725 |
726 | Checks whether a file is a FLV video by inspecting its file signature.
727 |
728 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
729 |
730 | Returns a `boolean` indicating whether the file includes a valid FLV video signature.
731 |
732 |
733 |
734 | fileTypeChecker.isM4V(file)
735 |
736 | Checks whether a file is a M4v video by inspecting its file signature.
737 |
738 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
739 |
740 | Returns a `boolean` indicating whether the file includes a valid M4v video signature.
741 |
742 |
743 |
744 | fileTypeChecker.isMKV(file)
745 |
746 | Checks whether a file is a MKV video by inspecting its file signature.
747 |
748 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
749 |
750 | Returns a `boolean` indicating whether the file includes a valid MKV video signature.
751 |
752 |
753 |
754 | fileTypeChecker.isMOV(file)
755 |
756 | Checks whether a file is a MOV video by inspecting its file signature.
757 |
758 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
759 |
760 | Returns a `boolean` indicating whether the file includes a valid MOV video signature.
761 |
762 |
763 |
764 | fileTypeChecker.isMP4(file, options?)
765 |
766 | Checks whether a file is a MP4 video by inspecting its file signature.
767 |
768 | Parameters:
769 |
770 | - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
771 | - `options` (optional) : `object` - An object that contains additional actions to perfoem on the file:
772 |
773 | - `excludeSimilarTypes` (optional) : `boolean` - Specifies whether to ignore signatures of similar file types during validation. When validating a `mp4` file, the `m4v` signature will be ignored. The default value is false.
774 |
775 | Returns a `boolean` indicating whether the file includes a valid MP4 video signature.
776 |
777 |
778 |
779 | fileTypeChecker.isOGG(file)
780 |
781 | Checks whether a file is an OGG video by inspecting its file signature.
782 |
783 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
784 |
785 | Returns a `boolean` indicating whether the file includes a valid OGG video signature.
786 |
787 |
788 |
789 | fileTypeChecker.isSWF(file)
790 |
791 | Checks whether a file is a SWF video by inspecting its file signature.
792 |
793 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
794 |
795 | Returns a `boolean` indicating whether the file includes a valid SWF video signature.
796 |
797 |
798 |
799 | fileTypeChecker.isWEBM(file)
800 |
801 | Checks whether a file is a WEBM video by inspecting its file signature.
802 |
803 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
804 |
805 | Returns a `boolean` indicating whether the file includes a valid WEBM video signature.
806 |
807 |
808 |
809 | #### Audio:
810 |
811 | fileTypeChecker.isAAC(file, options?)
812 |
813 | Checks whether a file is an AAC audio by inspecting its file signature.
814 |
815 | Parameters:
816 |
817 | - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
818 | - `options` (optional) : `object` - An object that contains additional actions to perfoem on the file:
819 |
820 | - `excludeSimilarTypes` (optional) : `boolean` - Specifies whether to ignore signatures of similar file types during validation. When validating a `aac` file, the `m4a` signature will be ignored. The default value is false.
821 |
822 | Returns a `boolean` indicating whether the file includes a valid AAC audio signature.
823 |
824 |
825 |
826 | fileTypeChecker.isAMR(file)
827 |
828 | Checks whether a file is an AMR audio by inspecting its file signature.
829 |
830 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
831 |
832 | Returns a `boolean` indicating whether the file includes a valid AMR audio signature.
833 |
834 |
835 |
836 | fileTypeChecker.isFLAC(file)
837 |
838 | Checks whether a file is a FLAC audio by inspecting its file signature.
839 |
840 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
841 |
842 | Returns a `boolean` indicating whether the file includes a valid FLAC audio signature.
843 |
844 |
845 |
846 | fileTypeChecker.isM4A(file)
847 |
848 | Checks whether a file is a M4A audio by inspecting its file signature.
849 |
850 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
851 |
852 | Returns a `boolean` indicating whether the file includes a valid M4A audio signature.
853 |
854 |
855 |
856 | fileTypeChecker.isMP3(file)
857 |
858 | Checks whether a file is a MP3 audio by inspecting its file signature.
859 |
860 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
861 |
862 | Returns a `boolean` indicating whether the file includes a valid MP3 audio signature.
863 |
864 |
865 |
866 | fileTypeChecker.isWAV(file)
867 |
868 | Checks whether a file is a WAV audio by inspecting its file signature.
869 |
870 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
871 |
872 | Returns a `boolean` indicating whether the file includes a valid WAV audio signature.
873 |
874 |
875 |
876 | #### Compressed:
877 |
878 | fileTypeChecker.is7z(file)
879 |
880 | Checks whether a file is a 7z compressed archive by inspecting its file signature.
881 |
882 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
883 |
884 | Returns a `boolean` indicating whether the file includes a valid 7z file signature.
885 |
886 |
887 |
888 | fileTypeChecker.isLZH(file)
889 |
890 | Checks whether a file is a LZH compressed archive by inspecting its file signature.
891 |
892 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
893 |
894 | Returns a `boolean` indicating whether the file includes a valid LZH file signature.
895 |
896 |
897 |
898 | fileTypeChecker.isRAR(file)
899 |
900 | Checks whether a file is a RAR compressed archive by inspecting its file signature.
901 |
902 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
903 |
904 | Returns a `boolean` indicating whether the file includes a valid RAR file signature.
905 |
906 |
907 |
908 | fileTypeChecker.isZIP(file, options?)
909 |
910 | Checks whether a file is a ZIP compressed archive by inspecting its file signature.
911 |
912 | Parameters:
913 |
914 | - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
915 | - `options` (optional) : `object` - An object that contains additional actions to perfoem on the file:
916 |
917 | - `chunkSize` (optional) : `number` - Specifies the size of the file chunk to analyze, starting from the beginning of the file. For ZIP files, it is recommended to set this to 30,000 bytes. The default value is 64.
918 |
919 | Returns a `boolean` indicating whether the file includes a valid ZIP file signature.
920 |
921 |
922 |
923 | #### Other:
924 |
925 | fileTypeChecker.isBLEND(file)
926 |
927 | Checks whether a file is a BLEND file by inspecting its file signature.
928 |
929 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
930 |
931 | Returns a `boolean` indicating whether the file includes a valid BLEND file signature.
932 |
933 |
934 |
935 | fileTypeChecker.isDOC(file)
936 |
937 | Checks whether a file is a DOC file by inspecting its file signature.
938 |
939 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
940 |
941 | Returns a `boolean` indicating whether the file includes a valid DOC file signature.
942 |
943 |
944 |
945 | fileTypeChecker.isELF(file)
946 |
947 | Checks whether a file is an ELF file by inspecting its file signature.
948 |
949 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
950 |
951 | Returns a `boolean` indicating whether the file includes a valid ELF file signature.
952 |
953 |
954 |
955 | fileTypeChecker.isEXE(file)
956 |
957 | Checks whether a file is an EXE file by inspecting its file signature.
958 |
959 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
960 |
961 | Returns a `boolean` indicating whether the file includes a valid EXE file signature.
962 |
963 |
964 |
965 | fileTypeChecker.isINDD(file)
966 |
967 | Checks whether a file is an INDD file by inspecting its file signature.
968 |
969 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
970 |
971 | Returns a `boolean` indicating whether the file is an INDD file.
972 |
973 |
974 |
975 | fileTypeChecker.isMACHO(file)
976 |
977 | Checks whether a file is an MACH-O file by inspecting its file signature.
978 |
979 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
980 |
981 | Returns a `boolean` indicating whether the file is an MACH-O file.
982 |
983 |
984 |
985 | fileTypeChecker.isORC(file)
986 |
987 | Checks whether a file is a ORC file by inspecting its file signature.
988 |
989 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
990 |
991 | Returns a `boolean` indicating whether the file includes a valid ORC file signature.
992 |
993 |
994 |
995 | fileTypeChecker.isPARQUET(file)
996 |
997 | Checks whether a file is a PARQUET file by inspecting its file signature.
998 |
999 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1000 |
1001 | Returns a `boolean` indicating whether the file includes a valid PARQUET file signature.
1002 |
1003 |
1004 |
1005 | fileTypeChecker.isPCAP(file)
1006 |
1007 | Checks whether a file is a PCAP file by inspecting its file signature.
1008 |
1009 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1010 |
1011 | Returns a `boolean` indicating whether the file includes a valid PCAP file signature.
1012 |
1013 |
1014 |
1015 | fileTypeChecker.isPDF(file)
1016 |
1017 | Checks whether a file is a PDF file by inspecting its file signature.
1018 |
1019 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1020 |
1021 | Returns a `boolean` indicating whether the file includes a valid PDF file signature.
1022 |
1023 |
1024 |
1025 | fileTypeChecker.isPS(file)
1026 |
1027 | Checks whether a file is a PS file by inspecting its file signature.
1028 |
1029 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1030 |
1031 | Returns a `boolean` indicating whether the file includes a valid PS file signature.
1032 |
1033 |
1034 |
1035 | fileTypeChecker.isRTF(file)
1036 |
1037 | Checks whether a file is a RTF file by inspecting its file signature.
1038 |
1039 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1040 |
1041 | Returns a `boolean` indicating whether the file includes a valid RTF file signature.
1042 |
1043 |
1044 |
1045 | fileTypeChecker.isSQLITE(file)
1046 |
1047 | Checks whether a file is a SQLITE file by inspecting its file signature.
1048 |
1049 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1050 |
1051 | Returns a `boolean` indicating whether the file includes a valid SQLITE file signature.
1052 |
1053 |
1054 |
1055 | fileTypeChecker.isSTL(file)
1056 |
1057 | Checks whether a file is a STL file by inspecting its file signature.
1058 |
1059 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1060 |
1061 | Returns a `boolean` indicating whether the file includes a valid STL file signature.
1062 |
1063 |
1064 |
1065 | fileTypeChecker.isTTF(file)
1066 |
1067 | Checks whether a file is a TTF file by inspecting its file signature.
1068 |
1069 | Parameters: - `file` : `Array`, `ArrayBuffer`, or `Uint8Array` - Binary data represents the file content.
1070 |
1071 | Returns a `boolean` indicating whether the file includes a valid TTF file signature.
1072 |
1073 |
1074 |
1075 | # License
1076 |
1077 | [MIT](https://github.com/nir11/file-type-checker/blob/main/LICENSE)
1078 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: "ts-jest",
3 | testEnvironment: "node",
4 | roots: ["/test"],
5 | transform: {
6 | "^.+\\.tsx?$": "ts-jest",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "file-type-checker",
3 | "version": "1.1.4",
4 | "description": "Detect and validate file types by their signatures (✨magic numbers✨)",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "files": [
8 | "dist"
9 | ],
10 | "scripts": {
11 | "build": "tsc --declaration",
12 | "lint": "yarn eslint .",
13 | "test": "jest --config jest.config.js"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/nir11/file-type-checker.git"
18 | },
19 | "keywords": [
20 | "file",
21 | "type",
22 | "checker",
23 | "signature",
24 | "magic",
25 | "numbers",
26 | "detect",
27 | "validate",
28 | "7z",
29 | "aac",
30 | "amr",
31 | "avi",
32 | "bmp",
33 | "bpg",
34 | "blend",
35 | "cr2",
36 | "doc",
37 | "elf",
38 | "exe",
39 | "exr",
40 | "flac",
41 | "flv",
42 | "gif",
43 | "heic",
44 | "ico",
45 | "indd",
46 | "jpeg",
47 | "lzh",
48 | "m4a",
49 | "m4v",
50 | "mach-o",
51 | "mkv",
52 | "mov",
53 | "mp3",
54 | "mp4",
55 | "ogg",
56 | "orc",
57 | "parquet",
58 | "pbm",
59 | "pcap",
60 | "pdf",
61 | "pgm",
62 | "png",
63 | "ppm",
64 | "psd",
65 | "ps",
66 | "rar",
67 | "rtf",
68 | "sqlite",
69 | "stl",
70 | "swf",
71 | "ttf",
72 | "wav",
73 | "webm",
74 | "webp",
75 | "zip"
76 | ],
77 | "author": "Nir Almog",
78 | "license": "MIT",
79 | "bugs": {
80 | "url": "https://github.com/nir11/file-type-checker/issues"
81 | },
82 | "homepage": "https://github.com/nir11/file-type-checker#readme",
83 | "devDependencies": {
84 | "@types/jest": "^29.4.0",
85 | "@types/node": "^18.11.18",
86 | "@typescript-eslint/eslint-plugin": "^6.2.0",
87 | "@typescript-eslint/parser": "^6.2.0",
88 | "eslint": "^8.45.0",
89 | "eslint-plugin-jest": "^27.2.3",
90 | "jest": "^29.7.0",
91 | "ts-jest": "^29.0.5",
92 | "typescript": "^5.1.6"
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/assets/detection.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nir11/file-type-checker/b913f14ff250cf28701831543b4f9c3614765ab3/src/assets/detection.gif
--------------------------------------------------------------------------------
/src/assets/validation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nir11/file-type-checker/b913f14ff250cf28701831543b4f9c3614765ab3/src/assets/validation.gif
--------------------------------------------------------------------------------
/src/core/file-types/audio.ts:
--------------------------------------------------------------------------------
1 | import { FileInfo } from "../types/file-info";
2 |
3 | /**
4 | * Audio files information with their unique signatures
5 | */
6 | export class AudioTypes {
7 | static AAC: FileInfo = {
8 | extension: "aac",
9 | mimeType: "audio/aac",
10 | description:
11 | "Advanced Audio Coding (AAC) is an audio coding standard for lossy digital audio compression",
12 | signatures: [
13 | {
14 | sequence: [0xff, 0xf1],
15 | description:
16 | "MPEG-4 Advanced Audio Coding (AAC) Low Complexity (LC) audio file",
17 | },
18 | {
19 | sequence: [0xff, 0xf9],
20 | description:
21 | "MPEG-2 Advanced Audio Coding (AAC) Low Complexity (LC) audio file",
22 | },
23 | ],
24 | };
25 |
26 | static AMR: FileInfo = {
27 | extension: "amr",
28 | mimeType: "audio/amr",
29 | description:
30 | "Adaptive Multi-Rate ACELP (Algebraic Code Excited Linear Prediction) Codec, commonly audio format with GSM cell phones",
31 | signatures: [
32 | {
33 | sequence: [0x23, 0x21, 0x41, 0x4d, 0x52],
34 | },
35 | ],
36 | };
37 |
38 | static FLAC: FileInfo = {
39 | extension: "flac",
40 | mimeType: "audio/x-flac",
41 | description: "Free Lossless Audio Codec file",
42 | signatures: [
43 | {
44 | sequence: [0x66, 0x4c, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22],
45 | },
46 | ],
47 | };
48 |
49 | static M4A: FileInfo = {
50 | extension: "m4a",
51 | mimeType: "audio/x-m4a",
52 | description: "Apple Lossless Audio Codec file",
53 | signatures: [
54 | {
55 | sequence: [0x66, 0x74, 0x79, 0x70, 0x4d, 0x34, 0x41, 0x20],
56 | offset: 4,
57 | compatibleExtensions: ["aac"],
58 | },
59 | ],
60 | };
61 |
62 | static MP3: FileInfo = {
63 | extension: "mp3",
64 | mimeType: "audio/mpeg",
65 | description:
66 | "A digital audio file format that uses compression to reduce file size while maintaining high quality sound",
67 | signatures: [
68 | {
69 | sequence: [0xff, 0xfb],
70 | description:
71 | "MPEG-1 Layer 3 file without an ID3 tag or with an ID3v1 tag (which is appended at the end of the file)",
72 | },
73 | {
74 | sequence: [0xff, 0xf3],
75 | description:
76 | "MPEG-1 Layer 3 file without an ID3 tag or with an ID3v1 tag (which is appended at the end of the file)",
77 | },
78 | {
79 | sequence: [0xff, 0xf2],
80 | description:
81 | "MPEG-1 Layer 3 file without an ID3 tag or with an ID3v1 tag (which is appended at the end of the file)",
82 | },
83 | {
84 | sequence: [0x49, 0x44, 0x33],
85 | description: "MP3 file with an ID3v2 container",
86 | },
87 | ],
88 | };
89 |
90 | static WAV: FileInfo = {
91 | extension: "wav",
92 | mimeType: "audio/wav",
93 | description: "Waveform Audio File Format",
94 | signatures: [
95 | {
96 | sequence: [
97 | 0x52, 0x49, 0x46, 0x46, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74,
98 | 0x20,
99 | ],
100 | skippedBytes: [4, 5, 6, 7],
101 | },
102 | ],
103 | };
104 | }
105 |
--------------------------------------------------------------------------------
/src/core/file-types/compressed.ts:
--------------------------------------------------------------------------------
1 | import { FileInfo } from "../types/file-info";
2 |
3 | /**
4 | * Compressed files information with their unique signatures
5 | */
6 | export class CompressedTypes {
7 | static _7Z: FileInfo = {
8 | extension: "7z",
9 | mimeType: "application/x-7z-compressed",
10 | description: "7-Zip compressed file",
11 | signatures: [
12 | {
13 | sequence: [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c],
14 | },
15 | ],
16 | };
17 |
18 | static LZH: FileInfo = {
19 | extension: "lzh",
20 | mimeType: "application/x-lzh-compressed",
21 | description:
22 | "Compressed file using Lempel-Ziv and Haruyasu (LZH) compression algorithm",
23 | signatures: [
24 | {
25 | sequence: [0x2d, 0x68, 0x6c, 0x30, 0x2d],
26 | description:
27 | "Lempel Ziv Huffman archive file Method 0 (No compression)",
28 | compatibleExtensions: ["lha"],
29 | },
30 | {
31 | sequence: [0x2d, 0x68, 0x6c, 0x35, 0x2d],
32 | description:
33 | "Lempel Ziv Huffman archive file Method 5 (8KiB sliding window)",
34 | compatibleExtensions: ["lha"],
35 | },
36 | ],
37 | };
38 |
39 | static RAR: FileInfo = {
40 | extension: "rar",
41 | mimeType: "application/x-rar-compressed",
42 | description: "Roshal ARchive compressed archive file",
43 | signatures: [
44 | {
45 | sequence: [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00],
46 | description: "Compressed archive v5.00 onwards",
47 | },
48 | {
49 | sequence: [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00],
50 | description: "Compressed archive v1.50 onwards",
51 | },
52 | ],
53 | };
54 |
55 | static ZIP: FileInfo = {
56 | extension: "zip",
57 | mimeType: "application/zip",
58 | description: "Compressed archive file",
59 | signatures: [
60 | {
61 | sequence: [0x57, 0x69, 0x6e, 0x5a, 0x69, 0x70],
62 | offset: 29152,
63 | description: "WinZip compressed archive",
64 | },
65 | {
66 | sequence: [
67 | 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x01, 0x00, 0x63, 0x00, 0x00,
68 | 0x00, 0x00, 0x00,
69 | ],
70 | description: "ZLock Pro encrypted ZIP",
71 | },
72 | {
73 | sequence: [0x50, 0x4b, 0x4c, 0x49, 0x54, 0x45],
74 | offset: 30,
75 | description: "PKLITE compressed ZIP archive (see also PKZIP)",
76 | },
77 | {
78 | sequence: [0x50, 0x4b, 0x53, 0x70, 0x58],
79 | offset: 526,
80 | description:
81 | "PKSFX self-extracting executable compressed file (see also PKZIP)",
82 | },
83 | {
84 | sequence: [0x50, 0x4b, 0x03, 0x04],
85 | description:
86 | "PKZIP archive file - zip file format and multiple formats based on it",
87 | compatibleExtensions: [
88 | "aar",
89 | "apk",
90 | "docx",
91 | "epub",
92 | "ipa",
93 | "jar",
94 | "kmz",
95 | "maff",
96 | "msix",
97 | "odp",
98 | "ods",
99 | "odt",
100 | "pk3",
101 | "pk4",
102 | "pptx",
103 | "usdz",
104 | "vsdx",
105 | "xlsx",
106 | "xpi",
107 | ],
108 | },
109 | {
110 | sequence: [0x50, 0x4b, 0x05, 0x06],
111 | description:
112 | "PKZIP empty archive file - zip file format and multiple formats based on it",
113 | compatibleExtensions: [
114 | "aar",
115 | "apk",
116 | "docx",
117 | "epub",
118 | "ipa",
119 | "jar",
120 | "kmz",
121 | "maff",
122 | "msix",
123 | "odp",
124 | "ods",
125 | "odt",
126 | "pk3",
127 | "pk4",
128 | "pptx",
129 | "usdz",
130 | "vsdx",
131 | "xlsx",
132 | "xpi",
133 | ],
134 | },
135 | {
136 | sequence: [0x50, 0x4b, 0x07, 0x08],
137 | description:
138 | "PKZIP multivolume archive file - zip file format and multiple formats based on it",
139 | compatibleExtensions: [
140 | "aar",
141 | "apk",
142 | "docx",
143 | "epub",
144 | "ipa",
145 | "jar",
146 | "kmz",
147 | "maff",
148 | "msix",
149 | "odp",
150 | "ods",
151 | "odt",
152 | "pk3",
153 | "pk4",
154 | "pptx",
155 | "usdz",
156 | "vsdx",
157 | "xlsx",
158 | "xpi",
159 | ],
160 | },
161 | ],
162 | };
163 | }
164 |
--------------------------------------------------------------------------------
/src/core/file-types/image.ts:
--------------------------------------------------------------------------------
1 | import { FileInfo } from "../types/file-info";
2 |
3 | /**
4 | * Image files information with their unique signatures
5 | */
6 | export class ImageTypes {
7 | static AVIF: FileInfo = {
8 | extension: "avif",
9 | mimeType: "image/avif",
10 | description: "Alliance for Open Media (AOMedia) Video 1 (AV1) Image File",
11 | signatures: [
12 | {
13 | sequence: [0x00, 0x00, 0x00],
14 | },
15 | ],
16 | };
17 |
18 | static BMP: FileInfo = {
19 | extension: "bmp",
20 | mimeType: "image/bmp",
21 | description: "A bitmap format used mostly in Windows",
22 | signatures: [
23 | {
24 | sequence: [0x42, 0x4d],
25 | compatibleExtensions: ["dib"],
26 | },
27 | ],
28 | };
29 |
30 | static BPG: FileInfo = {
31 | extension: "bpg",
32 | mimeType: "image/bpg",
33 | description: "Better Portable Graphics image format",
34 | signatures: [
35 | {
36 | sequence: [0x42, 0x50, 0x47, 0xfb],
37 | },
38 | ],
39 | };
40 |
41 | static CR2: FileInfo = {
42 | extension: "cr2",
43 | mimeType: "image/x-canon-cr2",
44 | description: "Canon digital camera RAW file",
45 | signatures: [
46 | {
47 | sequence: [0x49, 0x49, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x52],
48 | },
49 | ],
50 | };
51 |
52 | static EXR: FileInfo = {
53 | extension: "exr",
54 | mimeType: "image/x-exr",
55 | description: "OpenEXR bitmap image format",
56 | signatures: [
57 | {
58 | sequence: [0x76, 0x2f, 0x31, 0x01],
59 | },
60 | ],
61 | };
62 |
63 | static GIF: FileInfo = {
64 | extension: "gif",
65 | mimeType: "image/gif",
66 | description: "Image file encoded in the Graphics Interchange Format (GIF)",
67 | signatures: [
68 | {
69 | sequence: [0x47, 0x49, 0x46, 0x38, 0x37, 0x61],
70 | },
71 | {
72 | sequence: [0x47, 0x49, 0x46, 0x38, 0x39, 0x61],
73 | },
74 | ],
75 | };
76 |
77 | static HEIC: FileInfo = {
78 | extension: "heic",
79 | mimeType: "image/heic",
80 | description:
81 | "A variant of the HEIF (High Efficiency Image Format) that store images on the latest Apple devices.",
82 | signatures: [
83 | {
84 | sequence: [0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63],
85 | offset: 4,
86 | },
87 | {
88 | sequence: [0x66, 0x74, 0x79, 0x70, 0x6d],
89 | offset: 4,
90 | },
91 | ],
92 | };
93 |
94 | static ICO: FileInfo = {
95 | extension: "ico",
96 | mimeType: "image/x-icon",
97 | description: "Computer icon encoded in ICO file format",
98 | signatures: [
99 | {
100 | sequence: [0x00, 0x00, 0x01, 0x00],
101 | compatibleExtensions: ["spl"],
102 | },
103 | ],
104 | };
105 |
106 | static JPEG: FileInfo = {
107 | extension: "jpeg",
108 | mimeType: "image/jpeg",
109 | description:
110 | "JPEG (Joint Photographic Experts Group) is a widely used lossy image compression format.",
111 | signatures: [
112 | {
113 | sequence: [0xff, 0xd8, 0xff, 0xe1, 0x45, 0x78, 0x69, 0x66, 0x00],
114 | skippedBytes: [4, 5],
115 | description:
116 | "Digital camera JPG using Exchangeable Image File Format (EXIF)",
117 | },
118 | {
119 | sequence: [0xff, 0xd8, 0xff, 0xe8, 0x53, 0x50, 0x49, 0x46, 0x46, 0x00],
120 | skippedBytes: [4, 5],
121 | description: "Still Picture Interchange File Format (SPIFF)",
122 | },
123 | {
124 | sequence: [
125 | 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00,
126 | 0x00,
127 | ],
128 | description: "JPEG raw or in the JFIF or Exif file format",
129 | },
130 | {
131 | sequence: [0xff, 0xd8, 0xff, 0xee],
132 | description: "JPEG raw or in the JFIF or Exif file format",
133 | },
134 | {
135 | sequence: [0xff, 0xd8, 0xff, 0xe1, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00],
136 | skippedBytes: [4, 5],
137 | description: "JPEG raw or in the JFIF or Exif file format",
138 | },
139 | {
140 | sequence: [0xff, 0xd8, 0xff, 0xe0, 0x4a, 0x46, 0x49, 0x46, 0x00],
141 | skippedBytes: [4, 5],
142 | description: "JPEG/JFIF graphics file",
143 | compatibleExtensions: ["jfif", "jpe"],
144 | },
145 | {
146 | sequence: [0xff, 0xd8, 0xff, 0xe0],
147 | description: "JPEG raw or in the JFIF or Exif file format",
148 | },
149 | {
150 | sequence: [0xff, 0xd8],
151 | description: "Generic JPEGimage file",
152 | compatibleExtensions: ["jpe"],
153 | },
154 | ],
155 | };
156 |
157 | static PBM: FileInfo = {
158 | extension: "pbm",
159 | mimeType: "image/x-portable-bitmap",
160 | description:
161 | "PBM (Portable Bitmap) is a simple monochrome bitmap image format that uses plain text ASCII characters to represent binary image data",
162 | signatures: [
163 | {
164 | sequence: [0x50, 0x31, 0x0a],
165 | description: "Portable bitmap ASCII",
166 | },
167 | {
168 | sequence: [0x50, 0x34, 0x0a],
169 | description: "Portable bitmap binary",
170 | },
171 | ],
172 | };
173 |
174 | static PGM: FileInfo = {
175 | extension: "pgm",
176 | mimeType: "image/x-portable-graymap",
177 | description:
178 | "PGM (Portable Graymap) is a simple grayscale image format that uses ASCII text characters to represent binary image data.",
179 | signatures: [
180 | {
181 | sequence: [0x50, 0x32, 0x0a],
182 | description: "Portable Gray Map ASCII",
183 | },
184 | {
185 | sequence: [0x50, 0x35, 0x0a],
186 | description: "Portable Gray Map binary",
187 | },
188 | ],
189 | };
190 |
191 | static PNG: FileInfo = {
192 | extension: "png",
193 | mimeType: "image/png",
194 | description:
195 | "PNG (Portable Network Graphics) is a lossless image compression format that supports a wide range of color depths and transparency and is widely used for high-quality graphics.",
196 | signatures: [
197 | {
198 | sequence: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
199 | },
200 | ],
201 | };
202 |
203 | static PPM: FileInfo = {
204 | extension: "ppm",
205 | mimeType: "image/x-portable-pixmap",
206 | description:
207 | "PPM (Portable Pixmap) is a simple color image format in the Portable Network Graphics (PNG) suite.",
208 | signatures: [
209 | {
210 | sequence: [0x50, 0x33, 0x0a],
211 | description: "Portable Pixmap ASCII",
212 | },
213 | {
214 | sequence: [0x50, 0x36, 0x0a],
215 | description: "Portable Pixmap binary",
216 | },
217 | ],
218 | };
219 |
220 | static PSD: FileInfo = {
221 | extension: "psd",
222 | mimeType: "image/vnd.adobe.photoshop",
223 | description:
224 | "PSD (Photoshop Document) is an Adobe Photoshop image file format",
225 | signatures: [
226 | {
227 | sequence: [0x38, 0x42, 0x50, 0x53],
228 | },
229 | ],
230 | };
231 |
232 | static WEBP: FileInfo = {
233 | extension: "webp",
234 | mimeType: "image/webp",
235 | description:
236 | "A modern image format that provides superior lossless and lossy compression for images on the web",
237 | signatures: [
238 | {
239 | sequence: [0x52, 0x49, 0x46, 0x46, 0x57, 0x45, 0x42, 0x50],
240 | skippedBytes: [4, 5, 6, 7],
241 | },
242 | ],
243 | };
244 | }
245 |
--------------------------------------------------------------------------------
/src/core/file-types/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | fetchFromObject,
3 | findMatroskaDocTypeElements,
4 | isAvifStringIncluded,
5 | isFlvStringIncluded,
6 | isftypStringIncluded,
7 | } from "../../utils";
8 | import { AudioTypes } from "./audio";
9 | import { CompressedTypes } from "./compressed";
10 | import { OtherTypes } from "./other";
11 | import { ImageTypes } from "./image";
12 | import { VideoTypes } from "./video";
13 | import { DetectedFileInfo } from "../interfaces/dto";
14 | import { isFLV, isHEIC, isM4V, isMKV, isWEBM } from "../../validation";
15 | import { FileInfo, FileSignature } from "../types";
16 |
17 | export const FILE_TYPES_REQUIRED_ADDITIONAL_CHECK: Array = [
18 | "m4v",
19 | "flv",
20 | "mp4",
21 | "mkv",
22 | "webm",
23 | "avif",
24 | "heic",
25 | ];
26 |
27 | /**
28 | * A class hold all supported file typs with their unique signatures
29 | */
30 | export class FileTypes {
31 | // audio
32 | static AAC: FileInfo = AudioTypes.AAC;
33 | static AMR: FileInfo = AudioTypes.AMR;
34 | static FLAC: FileInfo = AudioTypes.FLAC;
35 | static M4A: FileInfo = AudioTypes.M4A;
36 | static MP3: FileInfo = AudioTypes.MP3;
37 | static WAV: FileInfo = AudioTypes.WAV;
38 |
39 | // image
40 | static AVIF: FileInfo = ImageTypes.AVIF;
41 | static BMP: FileInfo = ImageTypes.BMP;
42 | static BPG: FileInfo = ImageTypes.BPG;
43 | static CR2: FileInfo = ImageTypes.CR2;
44 | static EXR: FileInfo = ImageTypes.EXR;
45 | static GIF: FileInfo = ImageTypes.GIF;
46 | static ICO: FileInfo = ImageTypes.ICO;
47 | static JPEG: FileInfo = ImageTypes.JPEG;
48 | static PBM: FileInfo = ImageTypes.PBM;
49 | static PGM: FileInfo = ImageTypes.PGM;
50 | static PNG: FileInfo = ImageTypes.PNG;
51 | static PPM: FileInfo = ImageTypes.PPM;
52 | static PSD: FileInfo = ImageTypes.PSD;
53 | static WEBP: FileInfo = ImageTypes.WEBP;
54 | static HEIC: FileInfo = ImageTypes.HEIC;
55 |
56 | // video
57 | static AVI: FileInfo = VideoTypes.AVI;
58 | static FLV: FileInfo = VideoTypes.FLV;
59 | static M4V: FileInfo = VideoTypes.M4V;
60 | static MKV: FileInfo = VideoTypes.MKV;
61 | static MOV: FileInfo = VideoTypes.MOV;
62 | static MP4: FileInfo = VideoTypes.MP4;
63 | static OGG: FileInfo = VideoTypes.OGG;
64 | static SWF: FileInfo = VideoTypes.SWF;
65 | static WEBM: FileInfo = VideoTypes.WEBM;
66 |
67 | // compressed
68 | static _7Z: FileInfo = CompressedTypes._7Z;
69 | static LZH: FileInfo = CompressedTypes.LZH;
70 | static RAR: FileInfo = CompressedTypes.RAR;
71 | static ZIP: FileInfo = CompressedTypes.ZIP;
72 |
73 | // other
74 | static BLEND: FileInfo = OtherTypes.BLEND;
75 | static DOC: FileInfo = OtherTypes.DOC;
76 | static ELF: FileInfo = OtherTypes.ELF;
77 | static EXE: FileInfo = OtherTypes.EXE;
78 | static INDD: FileInfo = OtherTypes.INDD;
79 | static MACHO: FileInfo = OtherTypes.MACHO;
80 | static ORC: FileInfo = OtherTypes.ORC;
81 | static PARQUET: FileInfo = OtherTypes.PARQUET;
82 | static PCAP: FileInfo = OtherTypes.PCAP;
83 | static PDF: FileInfo = OtherTypes.PDF;
84 | static PS: FileInfo = OtherTypes.PS;
85 | static RTF: FileInfo = OtherTypes.RTF;
86 | static SQLITE: FileInfo = OtherTypes.SQLITE;
87 | static STL: FileInfo = OtherTypes.STL;
88 | static TTF: FileInfo = OtherTypes.TTF;
89 |
90 | /**
91 | * Receive information on a file type by its property name from FileTypes class
92 | *
93 | * @param propertyName Property name from FileTypes class
94 | *
95 | * @returns {FileInfo} File type information
96 | */
97 | public static getInfoByName(propertyName: string): FileInfo {
98 | const file = fetchFromObject(FileTypes, propertyName.toUpperCase());
99 | return file;
100 | }
101 |
102 | /**
103 | * Receive an array of file type signatures by its property name from FileTypes class
104 | *
105 | * @param propertyName Property name from FileTypes class
106 | *
107 | * @returns {Array} All unique signatures with their information
108 | */
109 | public static getSignaturesByName(
110 | propertyName: string
111 | ): Array {
112 | const { signatures } = fetchFromObject(
113 | FileTypes,
114 | propertyName.toUpperCase()
115 | );
116 | return signatures;
117 | }
118 |
119 | /**
120 | * Determine if a valid signature exist in a file chunk
121 | *
122 | * @param fileChunk A chunk from the beginning of a file content, represents in array of numbers
123 | * @param acceptedSignatures Valid signatures to search for in fileChunk
124 | *
125 | * @returns {boolean} True if found a valid signature inside the chunk, otherwise false
126 | */
127 | public static detectSignature(
128 | fileChunk: Array,
129 | acceptedSignatures: Array
130 | ): FileSignature | undefined {
131 | for (const signature of acceptedSignatures) {
132 | let found = true;
133 | const offset = signature.offset || 0;
134 | let skippedBytes = 0;
135 | for (let i = 0; i < signature.sequence.length; i++) {
136 | if (signature.skippedBytes && signature.skippedBytes.includes(i)) {
137 | skippedBytes++;
138 | continue;
139 | }
140 | if (fileChunk[offset + i] !== signature.sequence[i - skippedBytes]) {
141 | found = false;
142 | break;
143 | }
144 | }
145 | if (found) {
146 | return signature;
147 | }
148 | }
149 | return undefined;
150 | }
151 |
152 | /**
153 | * Perfomrs an additional check for detected file types by their unique structure
154 | *
155 | * @param fileChunk A chunk from the beginning of a file content, represents in array of numbers
156 | * @param detectedFiles A list of detected files
157 | * @returns {string | undefined} File type extension if found, otherwise undefined
158 | */
159 | public static detectTypeByAdditionalCheck(
160 | fileChunk: Array,
161 | detectedFiles: Array
162 | ): string | undefined {
163 | const detectedExtensions = detectedFiles.map((df) => df.extension);
164 |
165 | if (
166 | detectedExtensions.some((de) =>
167 | ["m4v", "flv", "mp4", "heic"].includes(de)
168 | )
169 | ) {
170 | if (detectedExtensions.includes("heic") && isHEIC(fileChunk))
171 | return "heic";
172 | const isFlv = isFLV(fileChunk);
173 | if (isFlv) return "flv";
174 | const isM4v = isM4V(fileChunk) && !isHEIC(fileChunk);
175 | if (isM4v) return "m4v";
176 | return "mp4";
177 | } else if (detectedExtensions.some((de) => ["mkv", "webm"].includes(de))) {
178 | const matroskaDocTypeElement = findMatroskaDocTypeElements(fileChunk);
179 | if (matroskaDocTypeElement === "mkv" && isMKV(fileChunk)) return "mkv";
180 | else if (matroskaDocTypeElement === "webm" && isWEBM(fileChunk))
181 | return "webm";
182 | return undefined;
183 | } else if (detectedExtensions.some((de) => ["avif"].includes(de))) {
184 | const isAvif = isAvifStringIncluded(fileChunk);
185 | if (isAvif) return "avif";
186 | }
187 | return undefined;
188 | }
189 |
190 | /**
191 | * Determine if a file chunk contains a valid signature and return the file signature if exist
192 | *
193 | * @param fileChunk A chunk from the beginning of a file content, represents in array of numbers
194 | * @param acceptedSignatures Valid signatures to search for in fileChunk
195 | *
196 | * @returns {FileSignature | undefined } FileSignature if found a valid signature, otherwise undefined
197 | */
198 | public static detectbBySignatures(
199 | fileChunk: Array,
200 | acceptedSignatures: Array
201 | ): FileSignature | undefined {
202 | for (const signature of acceptedSignatures) {
203 | let skippedBytes = 0;
204 | let found = true;
205 | const offset = signature.offset || 0;
206 | const signatureLength = signature?.skippedBytes
207 | ? signature.sequence.length + signature.skippedBytes.length
208 | : signature.sequence.length;
209 | for (let i = 0; i < signatureLength; i++) {
210 | if (signature.skippedBytes && signature.skippedBytes.includes(i)) {
211 | skippedBytes++;
212 | continue;
213 | }
214 | if (fileChunk[offset + i] !== signature.sequence[i - skippedBytes]) {
215 | found = false;
216 | break;
217 | }
218 | }
219 | if (found) {
220 | return signature;
221 | }
222 | }
223 | return undefined;
224 | }
225 |
226 | /**
227 | * Determine if file content contains a valid signature of a required type
228 | *
229 | * @param fileChunk A chunk from the beginning of a file content, represents in array of numbers
230 | * @param type The file type to match against
231 | *
232 | * @returns {boolean} True if found a signature of the type in file content, otherwise false
233 | */
234 | public static checkByFileType(
235 | fileChunk: Array,
236 | type: string
237 | ): boolean {
238 | if (Object.prototype.hasOwnProperty.call(FileTypes, type.toUpperCase())) {
239 | const acceptedSignatures: Array =
240 | FileTypes.getSignaturesByName(type.toUpperCase());
241 |
242 | const detectedSignature = FileTypes.detectSignature(
243 | fileChunk,
244 | acceptedSignatures
245 | );
246 | if (detectedSignature) return true;
247 | }
248 | return false;
249 | }
250 | }
251 |
--------------------------------------------------------------------------------
/src/core/file-types/other.ts:
--------------------------------------------------------------------------------
1 | import { FileInfo } from "../types/file-info";
2 |
3 | /**
4 | * Other files information with their unique signatures
5 | */
6 | export class OtherTypes {
7 | static BLEND: FileInfo = {
8 | extension: "blend",
9 | mimeType: "application/x-blender",
10 | description: "Blender File Format",
11 | signatures: [
12 | {
13 | sequence: [0x42, 0x4c, 0x45, 0x4e, 0x44, 0x45, 0x52],
14 | },
15 | ],
16 | };
17 |
18 | static DOC: FileInfo = {
19 | extension: "doc",
20 | mimeType: "application/msword",
21 | description: "Old Microsoft Word documents",
22 | signatures: [
23 | {
24 | sequence: [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1], // Word 97-2003 for OLECF
25 | compatibleExtensions: [
26 | "xls",
27 | "ppt",
28 | "msi",
29 | "msg",
30 | "dot",
31 | "pps",
32 | "xla",
33 | "wiz",
34 | ],
35 | description:
36 | "An Object Linking and Embedding (OLE) Compound File (CF) (i.e., OLECF) file format, known as Compound Binary File format by Microsoft, used by Microsoft Office 97-2003 applications",
37 | },
38 | {
39 | sequence: [0xdb, 0xa5, 0x2d, 0x00],
40 | description: "Microsoft Word 2.0 file format",
41 | },
42 | ],
43 | };
44 |
45 | static ELF: FileInfo = {
46 | extension: "elf",
47 | mimeType: "application/x-executable",
48 | description: "Executable and Linking Format executable file (Linux/Unix)",
49 | signatures: [
50 | {
51 | sequence: [0x7f, 0x45, 0x4c, 0x46],
52 | },
53 | ],
54 | };
55 |
56 | static EXE: FileInfo = {
57 | extension: "exe",
58 | mimeType: "application/x-msdownload", // 'application/x-dosexec' is a subtype of 'application/x-msdownload', therefore it is not necessary to include it (https://web.archive.org/web/20160629113130/http://www.webarchive.org.uk/interject/types/application/x-dosexec)
59 | description: "Windows/DOS executable file and its descendants",
60 | signatures: [
61 | {
62 | sequence: [0x4d, 0x5a],
63 | compatibleExtensions: [
64 | "acm",
65 | "ax",
66 | "cpl",
67 | "com",
68 | "dll",
69 | "drv",
70 | "efi",
71 | "fon",
72 | "iec",
73 | "ime",
74 | "mui",
75 | "ocx",
76 | "olb",
77 | "pif",
78 | "qts",
79 | "qtx",
80 | "rs",
81 | "sys",
82 | "scr",
83 | "tsp",
84 | "vbx",
85 | "vxd",
86 | ],
87 | },
88 | {
89 | sequence: [0x5a, 0x4d],
90 | description: "DOS ZM executable (rare)",
91 | },
92 | ],
93 | };
94 |
95 | static INDD: FileInfo = {
96 | extension: "indd",
97 | mimeType: "application/x-indesign",
98 | description: "Adobe InDesign document",
99 | signatures: [
100 | {
101 | sequence: [
102 | 0x06, 0x06, 0xed, 0xf5, 0xd8, 0x1d, 0x46, 0xe5, 0xbd, 0x31, 0xef,
103 | 0xe7, 0xfe, 0x74, 0xb7, 0x1d,
104 | ],
105 | compatibleExtensions: ["indt"],
106 | },
107 | ],
108 | };
109 |
110 | static MACHO: FileInfo = {
111 | extension: "macho",
112 | mimeType: "application/x-mach-binary",
113 | description: "Apple OS X ABI Mach-O binary file",
114 | signatures: [
115 | {
116 | sequence: [0xfe, 0xed, 0xfa, 0xce],
117 | description: "32-bit",
118 | },
119 | {
120 | sequence: [0xce, 0xfa, 0xed, 0xfe],
121 | description:
122 | "32-bit, where target system has reverse byte ordering from host running compiler",
123 | },
124 | {
125 | sequence: [0xfe, 0xed, 0xfa, 0xcf],
126 | description: "64-bit",
127 | },
128 | {
129 | sequence: [0xcf, 0xfa, 0xed, 0xfe],
130 | description:
131 | "64-bit, where target system has reverse byte ordering from host running compiler",
132 | },
133 | {
134 | sequence: [0xca, 0xfe, 0xba, 0xbe],
135 | description: "Mach-O Fat Binary",
136 | },
137 | ],
138 | };
139 |
140 | static PDF: FileInfo = {
141 | extension: "pdf",
142 | mimeType: "application/pdf",
143 | description: "Portable Document Format",
144 | signatures: [
145 | {
146 | sequence: [0x25, 0x50, 0x44, 0x46, 0x2d],
147 | },
148 | ],
149 | };
150 |
151 | static ORC: FileInfo = {
152 | extension: "orc",
153 | mimeType: "application/x-orc",
154 | description:
155 | "Apache ORC (Optimized Row Columnar) file format for columnar storage",
156 | signatures: [
157 | {
158 | sequence: [0x4f, 0x52, 0x43],
159 | },
160 | ],
161 | };
162 |
163 | static PARQUET: FileInfo = {
164 | extension: "parquet",
165 | mimeType: "application/vnd.apache.parquet",
166 | description: "Apache Parquet file format for columnar storage",
167 | signatures: [
168 | {
169 | sequence: [0x50, 0x41, 0x52, 0x31],
170 | },
171 | ],
172 | };
173 |
174 | static PS: FileInfo = {
175 | extension: "ps",
176 | mimeType: "application/postscript",
177 | description: "PostScript document",
178 | signatures: [
179 | {
180 | sequence: [0x25, 0x21, 0x50, 0x53],
181 | },
182 | ],
183 | };
184 |
185 | static RTF: FileInfo = {
186 | extension: "rtf",
187 | mimeType: "application/rtf",
188 | description: "Rich Text Format word processing file",
189 | signatures: [
190 | {
191 | sequence: [0x7b, 0x5c, 0x72, 0x74, 0x66, 0x31],
192 | },
193 | ],
194 | };
195 |
196 | static SQLITE: FileInfo = {
197 | extension: "sqlite",
198 | mimeType: "application/x-sqlite3",
199 | description: "SQLite database file",
200 | signatures: [
201 | {
202 | sequence: [
203 | 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d,
204 | 0x61, 0x74, 0x20, 0x33, 0x00,
205 | ],
206 | },
207 | ],
208 | };
209 |
210 | static STL: FileInfo = {
211 | extension: "stl",
212 | mimeType: "application/sla",
213 | description: "ASCII STL (STereoLithography) file for 3D printing",
214 | signatures: [
215 | {
216 | sequence: [0x73, 0x6f, 0x6c, 0x69, 0x64],
217 | },
218 | ],
219 | };
220 |
221 | static TTF: FileInfo = {
222 | extension: "ttf",
223 | mimeType: "application/x-font-ttf",
224 | description: "TrueType font file",
225 | signatures: [
226 | {
227 | sequence: [0x74, 0x72, 0x75, 0x65, 0x00],
228 | },
229 | {
230 | sequence: [0x00, 0x01, 0x00, 0x00, 0x00],
231 | compatibleExtensions: ["tte, dfont"],
232 | },
233 | ],
234 | };
235 |
236 | static PCAP: FileInfo = {
237 | extension: "pcap",
238 | mimeType: "application/vnd.tcpdump.pcap",
239 | description: "Libpcap File Format",
240 | signatures: [
241 | {
242 | sequence: [0xd4, 0xc3, 0xb2, 0xa1],
243 | },
244 | {
245 | sequence: [0x4d, 0x3c, 0xb2, 0xa1],
246 | description: "Nanosecond resolution",
247 | },
248 | ],
249 | };
250 | }
251 |
--------------------------------------------------------------------------------
/src/core/file-types/video.ts:
--------------------------------------------------------------------------------
1 | import { FileInfo } from "../types/file-info";
2 |
3 | /**
4 | * Video files information with their unique signatures
5 | */
6 | export class VideoTypes {
7 | static AVI: FileInfo = {
8 | extension: "avi",
9 | mimeType: "video/x-msvideo",
10 | description: "Audio Video Interleave video format",
11 | signatures: [
12 | {
13 | sequence: [
14 | 0x52, 0x49, 0x46, 0x46, 0x41, 0x56, 0x49, 0x20, 0x4c, 0x49, 0x53,
15 | 0x54,
16 | ],
17 | skippedBytes: [4, 5, 6, 7],
18 | },
19 | ],
20 | };
21 |
22 | static FLV: FileInfo = {
23 | extension: "flv",
24 | mimeType: "video/x-flv",
25 | description: "Flash Video file",
26 | signatures: [
27 | {
28 | sequence: [0x46, 0x4c, 0x56, 0x01],
29 | },
30 | {
31 | sequence: [0x66, 0x74, 0x79, 0x70, 0x4d, 0x34, 0x56, 0x20],
32 | description: "ISO Media, MPEG v4 system, or iTunes AVC-LC file",
33 | offset: 4,
34 | compatibleExtensions: ["mp4", "m4v"],
35 | },
36 | ],
37 | };
38 |
39 | static M4V: FileInfo = {
40 | extension: "m4v",
41 | mimeType: "video/x-m4v",
42 | description: "Apple's video container format, very similar to MP4",
43 | signatures: [
44 | {
45 | sequence: [0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32],
46 | description: "MPEG-4 video | QuickTime file",
47 | offset: 4,
48 | compatibleExtensions: ["mp4"],
49 | },
50 | {
51 | sequence: [0x66, 0x74, 0x79, 0x70, 0x4d, 0x34, 0x56, 0x20],
52 | description: "ISO Media, MPEG v4 system, or iTunes AVC-LC file",
53 | offset: 4,
54 | compatibleExtensions: ["mp4", "flv"],
55 | },
56 | ],
57 | };
58 |
59 | static MKV: FileInfo = {
60 | extension: "mkv",
61 | mimeType: "video/x-matroska",
62 | description:
63 | "MKV (Matroska Video) is a flexible, open-source media container format that supports multiple audio, video, and subtitle streams in a single file",
64 | signatures: [
65 | {
66 | sequence: [0x1a, 0x45, 0xdf, 0xa3],
67 | description: "EBML identifier",
68 | compatibleExtensions: ["webm", "mka", "mks", "mk3d"],
69 | },
70 | ],
71 | };
72 |
73 | static MOV: FileInfo = {
74 | extension: "mov",
75 | mimeType: "video/quicktime",
76 | description: "QuickTime movie file",
77 | signatures: [
78 | {
79 | sequence: [0x66, 0x74, 0x79, 0x70, 0x71, 0x74, 0x20, 0x20],
80 | offset: 4,
81 | },
82 | {
83 | sequence: [0x6d, 0x6f, 0x6f, 0x76],
84 | offset: 4,
85 | },
86 | ],
87 | };
88 |
89 | static MP4: FileInfo = {
90 | extension: "mp4",
91 | mimeType: "video/mp4",
92 | description:
93 | "A multimedia container format widely used for storing audio, video, and other data, and is known for its high compression efficiency and compatibility with many devices",
94 | signatures: [
95 | {
96 | sequence: [0x66, 0x74, 0x79, 0x70, 0x4d, 0x53, 0x4e, 0x56],
97 | description: "MPEG-4 video file",
98 | offset: 4,
99 | },
100 | {
101 | sequence: [0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f, 0x6d],
102 | description: "ISO Base Media file (MPEG-4) v1",
103 | offset: 4,
104 | },
105 | {
106 | sequence: [0x66, 0x74, 0x79, 0x70, 0x4d, 0x34, 0x56, 0x20],
107 | description: "ISO Media, MPEG v4 system, or iTunes AVC-LC file",
108 | offset: 4,
109 | compatibleExtensions: ["m4v", "flv"],
110 | },
111 | ],
112 | };
113 |
114 | static OGG: FileInfo = {
115 | extension: "ogg",
116 | mimeType: "video/ogg",
117 | description: "Ogg Vorbis Codec compressed Multimedia file",
118 | signatures: [
119 | {
120 | sequence: [
121 | 0x4f, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
122 | 0x00, 0x00, 0x00,
123 | ],
124 | compatibleExtensions: ["oga", "ogv", "ogx"],
125 | },
126 | ],
127 | };
128 |
129 | static SWF: FileInfo = {
130 | extension: "swf",
131 | mimeType: "application/x-shockwave-flash",
132 | description:
133 | "SWF (Shockwave Flash) is a file format for multimedia, vector graphics, and ActionScript, used for creating and delivering animations, games, and other interactive web-based content",
134 | signatures: [
135 | {
136 | sequence: [0x43, 0x57, 0x53],
137 | description:
138 | "Macromedia Shockwave Flash player file (zlib compressed, SWF 6 and later)",
139 | },
140 | {
141 | sequence: [0x46, 0x57, 0x53],
142 | description: "Macromedia Shockwave Flash player file (uncompressed)",
143 | },
144 | {
145 | sequence: [0x5a, 0x57, 0x53],
146 | description: "Macromedia Shockwave Flash player file (uncompressed)",
147 | },
148 | ],
149 | };
150 |
151 | static WEBM: FileInfo = {
152 | extension: "webm",
153 | mimeType: "video/webm",
154 | description:
155 | "WebM is a royalty-free, open-source media file format optimized for web delivery, using efficient VP8 video and Vorbis audio codecs",
156 | signatures: [
157 | {
158 | sequence: [0x1a, 0x45, 0xdf, 0xa3],
159 | description: "EBML identifier",
160 | compatibleExtensions: ["mkv"],
161 | },
162 | ],
163 | };
164 | }
165 |
--------------------------------------------------------------------------------
/src/core/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./file-types";
2 | export * from "./interfaces";
3 | export * from "./types";
4 |
--------------------------------------------------------------------------------
/src/core/interfaces/dto/detected-file-info.ts:
--------------------------------------------------------------------------------
1 | import { FileSignature } from "../../types";
2 |
3 | /**
4 | * Information about a detected file based on its signature
5 | */
6 | export interface DetectedFileInfo {
7 | extension: string;
8 | mimeType: string;
9 | description: string;
10 | signature: FileSignature;
11 | }
12 |
--------------------------------------------------------------------------------
/src/core/interfaces/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./detected-file-info";
2 |
--------------------------------------------------------------------------------
/src/core/interfaces/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./dto";
2 | export * from "./options";
3 |
--------------------------------------------------------------------------------
/src/core/interfaces/options/detect-file-options.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Options used to pass to detect file function.
3 | */
4 | export interface DetectFileOptions {
5 | chunkSize?: number;
6 | }
7 |
--------------------------------------------------------------------------------
/src/core/interfaces/options/file-validator-options.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Options used to pass to validators functions.
3 | */
4 | export interface FileValidatorOptions {
5 | excludeSimilarTypes?: boolean;
6 | }
7 |
--------------------------------------------------------------------------------
/src/core/interfaces/options/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./detect-file-options";
2 | export * from "./validate-file-type-options";
3 | export * from "./file-validator-options";
4 | export * from "./zip-validator-options";
5 |
--------------------------------------------------------------------------------
/src/core/interfaces/options/validate-file-type-options.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Options used to pass to validate file type function.
3 | */
4 | export interface ValidateFileTypeOptions {
5 | chunkSize?: number;
6 | excludeSimilarTypes?: boolean;
7 | }
8 |
--------------------------------------------------------------------------------
/src/core/interfaces/options/zip-validator-options.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Options used to pass to izZip function.
3 | */
4 | export interface ZipValidatorOptions {
5 | chunkSize?: number;
6 | }
7 |
--------------------------------------------------------------------------------
/src/core/types/file-info.ts:
--------------------------------------------------------------------------------
1 | import { FileSignature } from "./file-signature";
2 |
3 | /**
4 | * Information about a file
5 | */
6 | export type FileInfo = {
7 | extension: string;
8 | mimeType: string;
9 | description: string;
10 | signatures: Array;
11 | };
12 |
--------------------------------------------------------------------------------
/src/core/types/file-signature.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Information about a unique file signature
3 | */
4 | export type FileSignature = {
5 | sequence: Array;
6 | offset?: number;
7 | skippedBytes?: Array;
8 | description?: string;
9 | compatibleExtensions?: Array;
10 | };
11 |
--------------------------------------------------------------------------------
/src/core/types/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./file-info";
2 | export * from "./file-signature";
3 |
--------------------------------------------------------------------------------
/src/detection/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | DetectedFileInfo,
3 | DetectFileOptions,
4 | FILE_TYPES_REQUIRED_ADDITIONAL_CHECK,
5 | FileInfo,
6 | FileSignature,
7 | FileTypes,
8 | } from "../core";
9 | import { getFileChunk } from "../utils";
10 |
11 | /**
12 | * Detect a file by searching for a valid file signature inside the file content
13 | *
14 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
15 | * @param options Optional parameters for additional actions
16 | *
17 | * @returns {DetectedFileInfo | undefined} DetectedFileInfo if detected a valid signature inside the file contentof, otherwise undefined
18 | */
19 | export function detectFile(
20 | file: Array | ArrayBuffer | Uint8Array,
21 | options?: DetectFileOptions
22 | ): DetectedFileInfo | undefined {
23 | if (
24 | options &&
25 | Object.prototype.hasOwnProperty.call(options, "chunkSize") &&
26 | (options?.chunkSize ?? 0) <= 0
27 | )
28 | throw new RangeError("chunkSize must be bigger than zero");
29 |
30 | const fileChunk: Array = getFileChunk(file, options?.chunkSize || 64); // Take chunk from the beginning of the file
31 | if (fileChunk.length === 0) return undefined;
32 |
33 | const detectedFiles: DetectedFileInfo[] = [];
34 | const filesRequiredAdditionalCheck: string[] = [];
35 |
36 | for (const type in FileTypes) {
37 | if (Object.prototype.hasOwnProperty.call(FileTypes, type)) {
38 | const signatures: Array =
39 | FileTypes.getSignaturesByName(type);
40 | const matchedSignature = FileTypes.detectbBySignatures(
41 | fileChunk,
42 | signatures
43 | );
44 | if (matchedSignature) {
45 | const fileType: FileInfo = FileTypes.getInfoByName(type);
46 | if (FILE_TYPES_REQUIRED_ADDITIONAL_CHECK.includes(fileType.extension)) {
47 | filesRequiredAdditionalCheck.push(fileType.extension);
48 | }
49 | const fileInfo: DetectedFileInfo = {
50 | extension: fileType.extension,
51 | mimeType: fileType.mimeType,
52 | description: fileType.description,
53 | signature: {
54 | ...matchedSignature,
55 | sequence: matchedSignature.sequence.map((num) => num.toString(16)),
56 | },
57 | };
58 | detectedFiles.push(fileInfo);
59 | }
60 | }
61 | }
62 |
63 | if (detectedFiles.length === 0) return undefined;
64 | if (detectedFiles.length === 1 && filesRequiredAdditionalCheck.length === 0)
65 | return detectedFiles[0];
66 |
67 | // Some files share the same signature. Additional check required
68 | const detectedType = FileTypes.detectTypeByAdditionalCheck(
69 | fileChunk,
70 | detectedFiles
71 | );
72 | if (!detectedType) return undefined;
73 |
74 | return detectedFiles.find((df) => df.extension === detectedType);
75 | }
76 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as detectionFunctions from "./detection";
2 | import * as validationFunctions from "./validation";
3 |
4 | const fileTypeChecker = {
5 | ...detectionFunctions,
6 | ...validationFunctions,
7 | };
8 |
9 | export = fileTypeChecker;
10 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { FileInfo } from "../core";
2 |
3 | /**
4 | * Takes a file content in different types, convert it into array of numbers and returns a chunk of the required size
5 | *
6 | * @param file - File content represents in Array / ArrayBuffer / Uint8Array
7 | * @param fileChunkLength - Required file chunk length
8 | *
9 | * @returns {Array} File chunk of the required size represents in Array
10 | */
11 | export function getFileChunk(
12 | file: Array | ArrayBuffer | Uint8Array,
13 | fileChunkLength: number = 32 // default length - 32 bytes
14 | ): Array {
15 | const fileToCheck: Array | Uint8Array =
16 | file instanceof ArrayBuffer ? new Uint8Array(file) : file;
17 | let chunk: Array = [];
18 | if (
19 | (Array.isArray(file) && isArrayofNumbers(file)) ||
20 | file instanceof ArrayBuffer ||
21 | file instanceof Uint8Array
22 | ) {
23 | chunk = Array.from(fileToCheck.slice(0, fileChunkLength));
24 | } else {
25 | throw new TypeError(
26 | `Expected the \`file\` argument to be of type \`Array\`, \`Uint8Array\`, or \`ArrayBuffer\`, got \`${typeof file}\``
27 | );
28 | }
29 |
30 | if (!isLegalChunk(chunk))
31 | throw new TypeError(`File content contains illegal values`);
32 |
33 | return chunk;
34 | }
35 |
36 | /**
37 | * Determine if array of numbers is a legal file chunk
38 | *
39 | * @param fileChunk File content represents in Array
40 | *
41 | * @returns {boolean} True if the file content is verified, otherwise false
42 | */
43 |
44 | function isLegalChunk(fileChunk: Array): boolean {
45 | return fileChunk.every((num) => typeof num === "number" && !isNaN(num));
46 | }
47 |
48 | /**
49 | * Fetch a property of a object by its name
50 | *
51 | * @param obj The required object
52 | * @param prop The property name
53 | *
54 | * @returns {FileInfo} A property of the rquired object
55 | */
56 | // eslint-disable-next-line
57 | export function fetchFromObject(obj: any, prop: string): FileInfo {
58 | const _index = prop.indexOf(".");
59 | if (_index > -1) {
60 | return fetchFromObject(obj[prop.slice(0, _index)], prop.slice(_index + 1));
61 | }
62 | return obj[prop];
63 | }
64 |
65 | /**
66 | * Identify whether a valid 'mkv'/'web' file is 'mkv' or 'webm'.
67 | * By checking for the presence of the "DocType" element in the 'webm' header.
68 | * Or by checking the presence of the "Segment" element in the 'mkv' header.
69 | *
70 | * @param fileChunk - A chunk from the beginning of a file content, represents in array of numbers
71 | *
72 | * @returns {string | undefined} 'webm' if found webm string A property of the rquired object
73 | */
74 | export function findMatroskaDocTypeElements(
75 | fileChunk: Array
76 | ): string | undefined {
77 | const webmString = "webm";
78 | const mkvString = "matroska";
79 |
80 | const byteString = fileChunk.map((num) => String.fromCharCode(num)).join("");
81 |
82 | if (byteString.includes(webmString)) {
83 | return "webm";
84 | }
85 |
86 | if (byteString.includes(mkvString)) {
87 | return "mkv";
88 | }
89 |
90 | return undefined; // File type not identified
91 | }
92 |
93 | /**
94 | * Determine if array of numbers contains the "fytp" string.
95 | * M4V files typically have a "ftyp" box in the first few bytes, which can be checked by searching for the string "ftyp" in the buffer.
96 | *
97 | * @param fileChunk A chunk from the beginning of a file content, represents in array of numbers
98 | *
99 | * @returns {boolean} True if found the "ftyp" string in the fileChunk, otherwise false
100 | */
101 | export function isftypStringIncluded(fileChunk: Array): boolean {
102 | const ftypSignature = [0x66, 0x74, 0x79, 0x70]; // "ftyp" signature
103 |
104 | // Check the first few bytes for the "ftyp" signature
105 | for (let i = 0; i < fileChunk.length - ftypSignature.length; i++) {
106 | let found = true;
107 | for (let j = 0; j < ftypSignature.length; j++) {
108 | if (fileChunk[i + j] !== ftypSignature[j]) {
109 | found = false;
110 | break;
111 | }
112 | }
113 | if (found) {
114 | return true;
115 | }
116 | }
117 | return false;
118 | }
119 |
120 | /**
121 | * Determine if array of numbers contains the "FLV" string.
122 | * FLV files typically have a "FLV" string in the first few bytes of the file, which can be checked using TextDecoder or similar.
123 | *
124 | * @param fileChunk A chunk from the beginning of a file content, represents in array of numbers
125 | *
126 | * @returns {boolean} True if found the "FLV" string in the fileChunk, otherwise false
127 | */
128 | export function isFlvStringIncluded(fileChunk: Array): boolean {
129 | const signature = fileChunk.slice(0, 3);
130 | const signatureString = new TextDecoder().decode(new Uint8Array(signature));
131 | return signatureString.includes("FLV");
132 | }
133 |
134 | export function isFileContaineJfiforExifHeader(file: number[]): boolean {
135 | // Check if the fourth byte is one of the known JFIF or EXIF header markers
136 | const headerMarker = file[3];
137 | if (
138 | headerMarker === 0xe0 || // JFIF
139 | headerMarker === 0xe1 // EXIF
140 | ) {
141 | return true; // It's a JPEG file
142 | }
143 | return false;
144 | }
145 |
146 | /**
147 | * Determine if array of numbers contains the "ftypavif" string.
148 | * AVIF files typically have a "ftypavif" string at bytes 5-12 of the file, which can be checked using TextDecoder or similar.
149 | *
150 | * @param fileChunk A chunk from the beginning of a file content, represents in array of numbers
151 | *
152 | * @returns {boolean} True if found the "AVIF" string in the fileChunk, otherwise false
153 | */
154 | export function isAvifStringIncluded(fileChunk: Array): boolean {
155 | // Convert the relevant slice of the file chunk from hexadecimal to characters
156 | const signature = fileChunk
157 | .slice(4, 12)
158 | .map((hex) => String.fromCharCode(hex))
159 | .join("");
160 | return signature === "ftypavif";
161 | }
162 |
163 | // eslint-disable-next-line
164 | function isArrayofNumbers(arr: any[]): boolean {
165 | return arr.every((element) => typeof element === "number");
166 | }
167 |
168 | /**
169 | * Determine if a file chunk contains a HEIC file box.
170 | * HEIC files typically have an 'ftyp' box with specific major brand signatures
171 | * such as 'heic', 'hevc', 'mif1', and 'msf1' which can be checked by searching
172 | * for these strings in the file chunk.
173 | *
174 | * @param fileChunk A chunk from the beginning of a file content, represented as an array of numbers.
175 | * @returns {boolean} True if found a HEIC signature in the fileChunk, otherwise false.
176 | */
177 | export function isHeicSignatureIncluded(fileChunk: Array): boolean {
178 | // Convert the first part of the file chunk to a string to check for signatures
179 | const byteString = fileChunk.map((num) => String.fromCharCode(num)).join("");
180 |
181 | // List of possible HEIC 'ftyp' signatures
182 | const heicSignatures = ["ftypheic", "ftyphevc", "ftypmif1", "ftypmsf1"];
183 |
184 | // Check if any of the HEIC signatures are included in the byte string
185 | return heicSignatures.some((signature) => byteString.includes(signature));
186 | }
187 |
--------------------------------------------------------------------------------
/src/validation/audio.ts:
--------------------------------------------------------------------------------
1 | import { FileTypes, FileValidatorOptions } from "../core";
2 | import { getFileChunk } from "../utils";
3 |
4 | /**
5 | * Determine if file content contains a valid 'aac' file signature
6 | *
7 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
8 | * @param options parameters for additional actions
9 | *
10 | * @returns {boolean} True if found a signature of type 'aac' in file content, otherwise false
11 | */
12 | export function isAAC(
13 | file: Array | ArrayBuffer | Uint8Array,
14 | options?: FileValidatorOptions
15 | ): boolean {
16 | const fileChunk: Array = getFileChunk(file);
17 | const iaAac = FileTypes.checkByFileType(fileChunk, "aac");
18 |
19 | if (!iaAac) {
20 | if (options?.excludeSimilarTypes) return false;
21 | return isM4A(fileChunk); // since 'm4a' is very similar to 'aac'
22 | }
23 |
24 | return true;
25 | }
26 |
27 | /**
28 | * Determine if file content contains a valid 'amr' file signature
29 | *
30 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
31 | *
32 | * @returns {boolean} True if found a signature of type 'amr' in file content, otherwise false
33 | */
34 | export function isAMR(file: Array | ArrayBuffer | Uint8Array): boolean {
35 | const fileChunk: Array = getFileChunk(file);
36 | return FileTypes.checkByFileType(fileChunk, "amr");
37 | }
38 |
39 | /**
40 | * Determine if file content contains a valid 'flac' file signature
41 | *
42 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
43 | *
44 | * @returns {boolean} True if found a signature of type 'flac' in file content, otherwise false
45 | */
46 | export function isFLAC(
47 | file: Array | ArrayBuffer | Uint8Array
48 | ): boolean {
49 | const fileChunk: Array = getFileChunk(file);
50 | return FileTypes.checkByFileType(fileChunk, "flac");
51 | }
52 |
53 | /**
54 | * Determine if file content contains a valid 'm4a' file signature
55 | *
56 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
57 | *
58 | * @returns {boolean} True if found a signature of type 'm4a' in file content, otherwise false
59 | */
60 | export function isM4A(file: Array | ArrayBuffer | Uint8Array): boolean {
61 | const fileChunk: Array = getFileChunk(file);
62 | return FileTypes.checkByFileType(fileChunk, "m4a");
63 | }
64 |
65 | /**
66 | * Determine if file content contains a valid 'mp3' file signature
67 | *
68 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
69 | *
70 | * @returns {boolean} True if found a signature of type 'mp3' in file content, otherwise false
71 | */
72 | export function isMP3(file: Array | ArrayBuffer | Uint8Array): boolean {
73 | const fileChunk: Array = getFileChunk(file);
74 | return FileTypes.checkByFileType(fileChunk, "mp3");
75 | }
76 |
77 | /**
78 | * Determine if file content contains a valid 'wav' file signature
79 | *
80 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
81 | *
82 | * @returns {boolean} True if found a signature of type 'wav' in file content, otherwise false
83 | */
84 | export function isWAV(file: Array | ArrayBuffer | Uint8Array): boolean {
85 | const fileChunk: Array = getFileChunk(file);
86 | return FileTypes.checkByFileType(fileChunk, "wav");
87 | }
88 |
--------------------------------------------------------------------------------
/src/validation/compressed.ts:
--------------------------------------------------------------------------------
1 | import { FileTypes, ZipValidatorOptions } from "../core";
2 | import { getFileChunk } from "../utils";
3 |
4 | /**
5 | * Determine if file content contains a valid '7z' file signature
6 | *
7 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
8 | *
9 | * @returns {boolean} True if found a signature of type '7z' in file content, otherwise false
10 | */
11 | export function is7Z(file: Array | ArrayBuffer | Uint8Array): boolean {
12 | const fileChunk: Array = getFileChunk(file);
13 | return FileTypes.checkByFileType(fileChunk, "_7z");
14 | }
15 |
16 | /**
17 | * Determine if file content contains a valid 'lzh' file signature
18 | *
19 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
20 | *
21 | * @returns {boolean} True if found a signature of type 'lzh' in file content, otherwise false
22 | */
23 | export function isLZH(file: Array | ArrayBuffer | Uint8Array): boolean {
24 | const fileChunk: Array = getFileChunk(file);
25 | return FileTypes.checkByFileType(fileChunk, "lzh");
26 | }
27 |
28 | /**
29 | * Determine if file content contains a valid 'rar' file signature
30 | *
31 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
32 | *
33 | * @returns {boolean} True if found a signature of type 'rar' in file content, otherwise false
34 | */
35 | export function isRAR(file: Array | ArrayBuffer | Uint8Array): boolean {
36 | const fileChunk: Array = getFileChunk(file);
37 | return FileTypes.checkByFileType(fileChunk, "rar");
38 | }
39 |
40 | /**
41 | * Determine if file content contains a valid 'zip' file signature
42 | *
43 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
44 | * @param options parameters for additional actions
45 | *
46 | * @returns {boolean} True if found a signature of type 'zip' in file content, otherwise false
47 | */
48 | export function isZIP(
49 | file: Array | ArrayBuffer | Uint8Array,
50 | options?: ZipValidatorOptions
51 | ): boolean {
52 | const fileChunk: Array = getFileChunk(file, options?.chunkSize || 64);
53 | return FileTypes.checkByFileType(fileChunk, "zip");
54 | }
55 |
--------------------------------------------------------------------------------
/src/validation/image.ts:
--------------------------------------------------------------------------------
1 | import { FileTypes } from "../core";
2 | import {
3 | getFileChunk,
4 | isAvifStringIncluded,
5 | isHeicSignatureIncluded,
6 | isftypStringIncluded,
7 | } from "../utils";
8 | import { isM4V } from "./video";
9 |
10 | /**
11 | * Determine if file content contains a valid 'avif' file signature
12 | *
13 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
14 | *
15 | * @returns {boolean} True if found a signature of type 'avif' in file content, otherwise false
16 | */
17 | export function isAVIF(
18 | file: Array | ArrayBuffer | Uint8Array
19 | ): boolean {
20 | const fileChunk: Array = getFileChunk(file);
21 | const isAVIF = FileTypes.checkByFileType(fileChunk, "avif");
22 | if (!isAVIF) return false;
23 |
24 | // Search for the presence of the "ftypavif" at bytes 5-12
25 | return isAvifStringIncluded(fileChunk);
26 | }
27 |
28 | /**
29 | * Determine if file content contains a valid 'bmp' file signature
30 | *
31 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
32 | *
33 | * @returns {boolean} True if found a signature of type 'bmp' in file content, otherwise false
34 | */
35 | export function isBMP(file: Array | ArrayBuffer | Uint8Array): boolean {
36 | const fileChunk: Array = getFileChunk(file);
37 | return FileTypes.checkByFileType(fileChunk, "bmp");
38 | }
39 |
40 | /**
41 | * Determine if file content contains a valid 'bpg' file signature
42 | *
43 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
44 | *
45 | * @returns {boolean} True if found a signature of type 'bpg' in file content, otherwise false
46 | */
47 | export function isBPG(file: Array | ArrayBuffer | Uint8Array): boolean {
48 | const fileChunk: Array = getFileChunk(file);
49 | return FileTypes.checkByFileType(fileChunk, "bpg");
50 | }
51 |
52 | /**
53 | * Determine if file content contains a valid 'cr2' file signature
54 | *
55 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
56 | *
57 | * @returns {boolean} True if found a signature of type 'cr2' in file content, otherwise false
58 | */
59 | export function isCR2(file: Array | ArrayBuffer | Uint8Array): boolean {
60 | const fileChunk: Array = getFileChunk(file);
61 | return FileTypes.checkByFileType(fileChunk, "cr2");
62 | }
63 |
64 | /**
65 | * Determine if file content contains a valid 'exr' file signature
66 | *
67 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
68 | *
69 | * @returns {boolean} True if found a signature of type 'exr' in file content, otherwise false
70 | */
71 | export function isEXR(file: Array | ArrayBuffer | Uint8Array): boolean {
72 | const fileChunk: Array = getFileChunk(file);
73 | return FileTypes.checkByFileType(fileChunk, "exr");
74 | }
75 |
76 | /**
77 | * Determine if file content contains a valid 'gif' file signature
78 | *
79 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
80 | *
81 | * @returns {boolean} True if found a signature of type 'gif' in file content, otherwise false
82 | */
83 | export function isGIF(file: Array | ArrayBuffer | Uint8Array): boolean {
84 | const fileChunk: Array = getFileChunk(file);
85 | return FileTypes.checkByFileType(fileChunk, "gif");
86 | }
87 |
88 | /**
89 | * Determine if file content contains a valid 'heic' file signature
90 | *
91 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
92 | *
93 | * @returns {boolean} True if found a signature of type 'heic' in file content, otherwise false
94 | */
95 | export function isHEIC(
96 | file: Array | ArrayBuffer | Uint8Array
97 | ): boolean {
98 | const fileChunk: Array = getFileChunk(file);
99 | const isHEIC = FileTypes.checkByFileType(fileChunk, "avif");
100 | if (!isHEIC) return false;
101 |
102 | // Determine if a file chunk contains a HEIC file box
103 | return isHeicSignatureIncluded(fileChunk);
104 | }
105 |
106 | /**
107 | * Determine if file content contains a valid 'ico' file signature
108 | *
109 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
110 | *
111 | * @returns {boolean} True if found a signature of type 'ico' in file content, otherwise false
112 | */
113 | export function isICO(file: Array | ArrayBuffer | Uint8Array): boolean {
114 | const fileChunk: Array = getFileChunk(file);
115 | return FileTypes.checkByFileType(fileChunk, "ico");
116 | }
117 |
118 | /**
119 | * Determine if file content contains a valid 'jpeg' file signature
120 | *
121 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
122 | *
123 | * @returns {boolean} True if found a signature of type 'jpeg' in file content, otherwise false
124 | */
125 | export function isJPEG(
126 | file: Array | ArrayBuffer | Uint8Array
127 | ): boolean {
128 | const fileChunk: Array = getFileChunk(file);
129 | return FileTypes.checkByFileType(fileChunk, "jpeg");
130 | }
131 |
132 | /**
133 | * Determine if file content contains a valid 'pbm' file signature
134 | *
135 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
136 | *
137 | * @returns {boolean} True if found a signature of type 'pbm' in file content, otherwise false
138 | */
139 | export function isPBM(file: Array | ArrayBuffer | Uint8Array): boolean {
140 | const fileChunk: Array = getFileChunk(file);
141 | return FileTypes.checkByFileType(fileChunk, "pbm");
142 | }
143 |
144 | /**
145 | * Determine if file content contains a valid 'pgm' file signature
146 | *
147 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
148 | *
149 | * @returns {boolean} True if found a signature of type 'pgm' in file content, otherwise false
150 | */
151 | export function isPGM(file: Array | ArrayBuffer | Uint8Array): boolean {
152 | const fileChunk: Array = getFileChunk(file);
153 | return FileTypes.checkByFileType(fileChunk, "pgm");
154 | }
155 |
156 | /**
157 | * Determine if file content contains a valid 'png' file signature
158 | *
159 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
160 | *
161 | * @returns {boolean} True if found a signature of type 'png' in file content, otherwise false
162 | */
163 | export function isPNG(file: Array | ArrayBuffer | Uint8Array): boolean {
164 | const fileChunk: Array = getFileChunk(file);
165 | return FileTypes.checkByFileType(fileChunk, "png");
166 | }
167 |
168 | /**
169 | * Determine if file content contains a valid 'ppm' file signature
170 | *
171 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
172 | *
173 | * @returns {boolean} True if found a signature of type 'ppm' in file content, otherwise false
174 | */
175 | export function isPPM(file: Array | ArrayBuffer | Uint8Array): boolean {
176 | const fileChunk: Array = getFileChunk(file);
177 | return FileTypes.checkByFileType(fileChunk, "ppm");
178 | }
179 |
180 | /**
181 | * Determine if file content contains a valid 'psd' file signature
182 | *
183 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
184 | *
185 | * @returns {boolean} True if found a signature of type 'psd' in file content, otherwise false
186 | */
187 | export function isPSD(file: Array | ArrayBuffer | Uint8Array): boolean {
188 | const fileChunk: Array = getFileChunk(file);
189 | return FileTypes.checkByFileType(fileChunk, "psd");
190 | }
191 |
192 | /**
193 | * Determine if file content contains a valid 'webp' file signature
194 | *
195 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
196 | *
197 | * @returns {boolean} True if found a signature of type 'webp' in file content, otherwise false
198 | */
199 | export function isWEBP(
200 | file: Array | ArrayBuffer | Uint8Array
201 | ): boolean {
202 | const fileChunk: Array = getFileChunk(file);
203 | return FileTypes.checkByFileType(fileChunk, "webp");
204 | }
205 |
--------------------------------------------------------------------------------
/src/validation/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | FileSignature,
3 | FileTypes,
4 | FileInfo,
5 | FILE_TYPES_REQUIRED_ADDITIONAL_CHECK,
6 | ValidateFileTypeOptions,
7 | } from "../core";
8 | import { getFileChunk } from "../utils";
9 |
10 | export * from "./audio";
11 | export * from "./compressed";
12 | export * from "./image";
13 | export * from "./other";
14 | export * from "./video";
15 |
16 | /**
17 | * Validates the requested file signature against a list of accepted file types
18 | *
19 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
20 | * @param types A list of accepted file types
21 | * @param options parameters for additional actions
22 | *
23 | * @returns {boolean} True if found a type signature from the accepted file types, otherwise false
24 | */
25 | export function validateFileType(
26 | file: Array | ArrayBuffer | Uint8Array,
27 | types: Array,
28 | options?: ValidateFileTypeOptions
29 | ): boolean {
30 | let typeExtensions: Array = [];
31 | const uniqueTypes = [
32 | ...new Set(
33 | types.map((type) => {
34 | const normalizedType = type.split(".").join("").toUpperCase();
35 | if (normalizedType === "7Z") return `_${normalizedType}`;
36 | return normalizedType;
37 | })
38 | ),
39 | ];
40 | for (const type of uniqueTypes) {
41 | if (!Object.prototype.hasOwnProperty.call(FileTypes, type))
42 | throw new TypeError(
43 | `Type \`${type.toLowerCase()}\` is not supported. Please make sure that \`types\` list conatins only supported files`
44 | );
45 | typeExtensions.push(type);
46 | }
47 |
48 | if (
49 | options &&
50 | Object.prototype.hasOwnProperty.call(options, "chunkSize") &&
51 | (options?.chunkSize ?? 0) <= 0
52 | )
53 | throw new RangeError("chunkSize must be bigger than zero");
54 |
55 | if (!options || !options?.excludeSimilarTypes) {
56 | const similarTypes: Array = addSimilarTypes(typeExtensions);
57 | if (similarTypes.length > 0)
58 | typeExtensions = typeExtensions.concat(similarTypes);
59 | }
60 |
61 | let acceptedSignatures: Array = [];
62 | const filesRequiredAdditionalCheck: Array = [];
63 | for (const type of typeExtensions) {
64 | const extensionSignatures: Array =
65 | FileTypes.getSignaturesByName(type);
66 | acceptedSignatures = acceptedSignatures.concat(extensionSignatures);
67 | if (FILE_TYPES_REQUIRED_ADDITIONAL_CHECK.includes(type.toLowerCase())) {
68 | filesRequiredAdditionalCheck.push(FileTypes.getInfoByName(type));
69 | }
70 | }
71 |
72 | const fileChunk: Array = getFileChunk(file, options?.chunkSize || 64);
73 |
74 | const detectedSignature = FileTypes.detectSignature(
75 | fileChunk,
76 | acceptedSignatures
77 | );
78 |
79 | if (!detectedSignature) return false;
80 |
81 | if (filesRequiredAdditionalCheck.length > 0) {
82 | const detectedFilesForAdditionalCheck: Array =
83 | filesRequiredAdditionalCheck.filter((frac) =>
84 | frac.signatures.includes(detectedSignature)
85 | );
86 | if (detectedFilesForAdditionalCheck.length > 0) {
87 | // Some files share the same signature. Additional check required
88 | const detectedType = FileTypes.detectTypeByAdditionalCheck(
89 | fileChunk,
90 | detectedFilesForAdditionalCheck
91 | );
92 | if (!detectedType) return false;
93 |
94 | return typeExtensions.some((df) => df.toLowerCase() === detectedType);
95 | }
96 | }
97 |
98 | return true;
99 | }
100 |
101 | function addSimilarTypes(requiredTypes: Array): Array {
102 | if (requiredTypes.some((type) => type === "MP4")) return ["M4V"];
103 | if (requiredTypes.some((type) => type === "AAC")) return ["M4A"];
104 |
105 | return [];
106 | }
107 |
--------------------------------------------------------------------------------
/src/validation/other.ts:
--------------------------------------------------------------------------------
1 | import { FileTypes } from "../core";
2 | import { getFileChunk } from "../utils";
3 |
4 | /**
5 | * Determine if file content contains a valid 'blend' file signature
6 | *
7 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
8 | *
9 | * @returns {boolean} True if found a signature of type 'blend' in file content, otherwise false
10 | */
11 | export function isBLEND(
12 | file: Array | ArrayBuffer | Uint8Array
13 | ): boolean {
14 | const fileChunk: Array = getFileChunk(file);
15 | return FileTypes.checkByFileType(fileChunk, "blend");
16 | }
17 |
18 | /**
19 | * Determine if file content contains a valid 'elf' file signature
20 | *
21 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
22 | *
23 | * @returns {boolean} True if found a signature of type 'elf' in file content, otherwise false
24 | */
25 | export function isELF(file: Array | ArrayBuffer | Uint8Array): boolean {
26 | const fileChunk: Array = getFileChunk(file);
27 | return FileTypes.checkByFileType(fileChunk, "elf");
28 | }
29 |
30 | /**
31 | * Determine if file content contains a valid 'exe' file signature
32 | *
33 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
34 | *
35 | * @returns {boolean} True if found a signature of type 'exe' in file content, otherwise false
36 | */
37 | export function isEXE(file: Array | ArrayBuffer | Uint8Array): boolean {
38 | const fileChunk: Array = getFileChunk(file);
39 | return FileTypes.checkByFileType(fileChunk, "exe");
40 | }
41 |
42 | /**
43 | * Determine if file content contains a valid 'mach-o' file signature
44 | *
45 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
46 | *
47 | * @returns {boolean} True if found a signature of type 'mach-o' in file content, otherwise false
48 | */
49 | export function isMACHO(
50 | file: Array | ArrayBuffer | Uint8Array
51 | ): boolean {
52 | const fileChunk: Array = getFileChunk(file);
53 | return FileTypes.checkByFileType(fileChunk, "macho");
54 | }
55 |
56 | /**
57 | * Determine if file content contains a valid 'indd' file signature
58 | *
59 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
60 | *
61 | * @returns {boolean} True if found a signature of type 'indd' in file content, otherwise false
62 | */
63 | export function isINDD(
64 | file: Array | ArrayBuffer | Uint8Array
65 | ): boolean {
66 | const fileChunk: Array = getFileChunk(file);
67 | return FileTypes.checkByFileType(fileChunk, "indd");
68 | }
69 |
70 | /**
71 | * Determine if file content contains a valid 'orc' file signature
72 | *
73 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
74 | *
75 | * @returns {boolean} True if found a signature of type 'orc' in file content, otherwise false
76 | */
77 | export function isORC(file: Array | ArrayBuffer | Uint8Array): boolean {
78 | const fileChunk: Array = getFileChunk(file);
79 | return FileTypes.checkByFileType(fileChunk, "orc");
80 | }
81 |
82 | /**
83 | * Determine if file content contains a valid 'parquet' file signature
84 | *
85 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
86 | *
87 | * @returns {boolean} True if found a signature of type 'parquet' in file content, otherwise false
88 | */
89 | export function isPARQUET(
90 | file: Array | ArrayBuffer | Uint8Array
91 | ): boolean {
92 | const fileChunk: Array = getFileChunk(file);
93 | return FileTypes.checkByFileType(fileChunk, "parquet");
94 | }
95 |
96 | /**
97 | * Determine if file content contains a valid 'pdf' file signature
98 | *
99 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
100 | *
101 | * @returns {boolean} True if found a signature of type 'pdf' in file content, otherwise false
102 | */
103 | export function isPDF(file: Array | ArrayBuffer | Uint8Array): boolean {
104 | const fileChunk: Array = getFileChunk(file);
105 | return FileTypes.checkByFileType(fileChunk, "pdf");
106 | }
107 |
108 | /**
109 | * Determine if file content contains a valid 'ps' file signature
110 | *
111 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
112 | *
113 | * @returns {boolean} True if found a signature of type 'ps' in file content, otherwise false
114 | */
115 | export function isPS(file: Array | ArrayBuffer | Uint8Array): boolean {
116 | const fileChunk: Array = getFileChunk(file);
117 | return FileTypes.checkByFileType(fileChunk, "ps");
118 | }
119 |
120 | /**
121 | * Determine if file content contains a valid 'rtf' file signature
122 | *
123 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
124 | *
125 | * @returns {boolean} True if found a signature of type 'rtf' in file content, otherwise false
126 | */
127 | export function isRTF(file: Array | ArrayBuffer | Uint8Array): boolean {
128 | const fileChunk: Array = getFileChunk(file);
129 | return FileTypes.checkByFileType(fileChunk, "rtf");
130 | }
131 |
132 | /**
133 | * Determine if file content contains a valid 'sqlite' file signature
134 | *
135 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
136 | *
137 | * @returns {boolean} True if found a signature of type 'sqlite' in file content, otherwise false
138 | */
139 | export function isSQLITE(
140 | file: Array | ArrayBuffer | Uint8Array
141 | ): boolean {
142 | const fileChunk: Array = getFileChunk(file);
143 | return FileTypes.checkByFileType(fileChunk, "sqlite");
144 | }
145 |
146 | /**
147 | * Determine if file content contains a valid 'stl' file signature
148 | *
149 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
150 | *
151 | * @returns {boolean} True if found a signature of type 'stl' in file content, otherwise false
152 | */
153 | export function isSTL(file: Array | ArrayBuffer | Uint8Array): boolean {
154 | const fileChunk: Array = getFileChunk(file);
155 | return FileTypes.checkByFileType(fileChunk, "stl");
156 | }
157 |
158 | /**
159 | * Determine if file content contains a valid 'ttf' file signature
160 | *
161 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
162 | *
163 | * @returns {boolean} True if found a signature of type 'ttf' in file content, otherwise false
164 | */
165 | export function isTTF(file: Array | ArrayBuffer | Uint8Array): boolean {
166 | const fileChunk: Array = getFileChunk(file);
167 | return FileTypes.checkByFileType(fileChunk, "ttf");
168 | }
169 |
170 | /**
171 | * Determine if file content contains a valid 'doc' file signature
172 | *
173 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
174 | *
175 | * @returns {boolean} True if found a signature of type 'doc' in file content, otherwise false
176 | */
177 | export function isDOC(file: Array | ArrayBuffer | Uint8Array): boolean {
178 | const fileChunk: Array = getFileChunk(file);
179 | return FileTypes.checkByFileType(fileChunk, "doc");
180 | }
181 |
182 | /**
183 | * Determine if file content contains a valid 'pcap' file signature
184 | *
185 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
186 | *
187 | * @returns {boolean} True if found a signature of type 'pcap' in file content, otherwise false
188 | */
189 | export function isPCAP(
190 | file: Array | ArrayBuffer | Uint8Array
191 | ): boolean {
192 | const fileChunk: Array = getFileChunk(file);
193 | return FileTypes.checkByFileType(fileChunk, "pcap");
194 | }
195 |
--------------------------------------------------------------------------------
/src/validation/video.ts:
--------------------------------------------------------------------------------
1 | import { FileTypes, FileValidatorOptions } from "../core";
2 | import {
3 | findMatroskaDocTypeElements,
4 | isFlvStringIncluded,
5 | isftypStringIncluded,
6 | getFileChunk,
7 | } from "../utils";
8 |
9 | /**
10 | * Determine if file content contains a valid 'avi' file signature
11 | *
12 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
13 | *
14 | * @returns {boolean} True if found a signature of type 'avi' in file content, otherwise false
15 | */
16 | export function isAVI(file: Array | ArrayBuffer | Uint8Array): boolean {
17 | const fileChunk: Array = getFileChunk(file);
18 | return FileTypes.checkByFileType(fileChunk, "avi");
19 | }
20 |
21 | /**
22 | * Determine if file content contains a valid 'flv' file signature.
23 | * Since 'flv' and 'm4v' share the same signature - additional check required - check if file content contains a "flv" string in the first few bytes of the file
24 | *
25 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
26 | *
27 | * @returns {boolean} True if found a signature of type 'flv' & "flv" string in file content, otherwise false
28 | */
29 | export function isFLV(file: Array | ArrayBuffer | Uint8Array): boolean {
30 | const fileChunk: Array = getFileChunk(file);
31 | const isFlvSignature = FileTypes.checkByFileType(fileChunk, "flv");
32 | if (!isFlvSignature) return false;
33 |
34 | // Check if file content contains a "flv" string
35 | return isFlvStringIncluded(fileChunk);
36 | }
37 |
38 | /**
39 | * Determine if file content contains a valid 'm4v' file signature.
40 | * Since 'flv' and 'm4v' share the same signature - additional check required - check if file content contains a "ftyp" string in the first few bytes of the file
41 | *
42 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
43 | *
44 | * @returns {boolean} True if found a signature of type 'm4v' & "ftyp" string in file content, otherwise false
45 | */
46 | export function isM4V(file: Array | ArrayBuffer | Uint8Array): boolean {
47 | const fileChunk: Array = getFileChunk(file);
48 | const isM4vSignature = FileTypes.checkByFileType(fileChunk, "m4v");
49 | if (!isM4vSignature) return false;
50 |
51 | // Check if file content contains a "ftyp" string
52 | return isftypStringIncluded(fileChunk);
53 | }
54 |
55 | /**
56 | * Determine if file content contains a valid 'mkv' file signature.
57 | * Since 'mkv' and 'webm' share the same signature - additional check required - search for the presence of the "Segment" element in the mkv header
58 | *
59 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
60 | *
61 | * @returns {boolean} True if found a signature of type 'mkv' & "ftyp" string in file content, otherwise false
62 | */
63 | export function isMKV(file: Array | ArrayBuffer | Uint8Array): boolean {
64 | const fileChunk: Array = getFileChunk(file, 64); // Check the first 64 bytes of the file
65 | const isMkvSignature = FileTypes.checkByFileType(fileChunk, "mkv");
66 | if (!isMkvSignature) return false;
67 |
68 | // Search for the presence of the "Segment" element in the mkv header
69 | return findMatroskaDocTypeElements(fileChunk) === "mkv";
70 | }
71 |
72 | /**
73 | * Determine if file content contains a valid 'mov' file signature
74 | *
75 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
76 | *
77 | * @returns {boolean} True if found a signature of type 'mov' in file content, otherwise false
78 | */
79 | export function isMOV(file: Array | ArrayBuffer | Uint8Array): boolean {
80 | const fileChunk: Array = getFileChunk(file);
81 | return FileTypes.checkByFileType(fileChunk, "mov");
82 | }
83 |
84 | /**
85 | * Determine if file content contains a valid 'mp4' file signature.
86 | *
87 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
88 | * @param options parameters for additional actions
89 | *
90 | * @returns {boolean} True if found a signature of type 'mp4' in file content, otherwise false
91 | */
92 | export function isMP4(
93 | file: Array | ArrayBuffer | Uint8Array,
94 | options?: FileValidatorOptions
95 | ): boolean {
96 | const fileChunk: Array = getFileChunk(file);
97 | const isMp4 = FileTypes.checkByFileType(fileChunk, "mp4");
98 |
99 | if (!isMp4) {
100 | if (options?.excludeSimilarTypes) return false;
101 | return isM4V(fileChunk); // since 'm4v' is very similar to 'mp4'
102 | }
103 |
104 | return true;
105 | }
106 |
107 | /**
108 | * Determine if file content contains a valid 'ogg' file signature
109 | *
110 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
111 | *
112 | * @returns {boolean} True if found a signature of type 'ogg' in file content, otherwise false
113 | */
114 | export function isOGG(file: Array | ArrayBuffer | Uint8Array): boolean {
115 | const fileChunk: Array = getFileChunk(file);
116 | return FileTypes.checkByFileType(fileChunk, "ogg");
117 | }
118 |
119 | /**
120 | * Determine if file content contains a valid 'swf' file signature
121 | *
122 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
123 | *
124 | * @returns {boolean} True if found a signature of type 'swf' in file content, otherwise false
125 | */
126 | export function isSWF(file: Array | ArrayBuffer | Uint8Array): boolean {
127 | const fileChunk: Array = getFileChunk(file);
128 | return FileTypes.checkByFileType(fileChunk, "swf");
129 | }
130 |
131 | /**
132 | * Determine if file content contains a valid 'webm' file signature.
133 | * Since 'mkv' and 'webm' share the same signature - additional check required - search for the presence of the "DocType" element in the webm header
134 | *
135 | * @param file File content represents in Array / ArrayBuffer / Uint8Array
136 | *
137 | * @returns {boolean} True if found a signature of type 'webm' & "ftyp" string in file content, otherwise false
138 | */
139 | export function isWEBM(
140 | file: Array | ArrayBuffer | Uint8Array
141 | ): boolean {
142 | const fileChunk: Array = getFileChunk(file, 64); // Check the first 64 bytes of the file
143 | const isWebmSignature = FileTypes.checkByFileType(fileChunk, "webm");
144 | if (!isWebmSignature) return false;
145 |
146 | // Search for the presence of the "DocType" element in the webm header
147 | return findMatroskaDocTypeElements(fileChunk) === "webm";
148 | }
149 |
--------------------------------------------------------------------------------
/test/detection/detection.spec.ts:
--------------------------------------------------------------------------------
1 | import fileTypeChecker from "../../src/index";
2 | import { DetectedFileInfo } from "../../src/core";
3 |
4 | describe("detectFile", () => {
5 | it("should detect the file type of an Array as a png file", () => {
6 | const fileArrayNumber: Array = [
7 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0,
8 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89,
9 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115,
10 | 82, 71, 66, 0, 174,
11 | ];
12 | const detectedFile = fileTypeChecker.detectFile(
13 | fileArrayNumber
14 | ) as DetectedFileInfo;
15 | expect(detectedFile.extension).toBe("png");
16 | expect(detectedFile.mimeType).toBe("image/png");
17 | expect(detectedFile.signature.sequence).toEqual([
18 | "89",
19 | "50",
20 | "4e",
21 | "47",
22 | "d",
23 | "a",
24 | "1a",
25 | "a",
26 | ]);
27 | });
28 |
29 | it("should detect the file type of an ArrayBuffer as a png file", () => {
30 | const fileArrayBuffer = new Uint8Array([
31 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0,
32 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89,
33 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115,
34 | 82, 71, 66, 0, 174,
35 | ]).buffer;
36 | const detectedFile = fileTypeChecker.detectFile(
37 | fileArrayBuffer
38 | ) as DetectedFileInfo;
39 | expect(detectedFile.extension).toBe("png");
40 | expect(detectedFile.mimeType).toBe("image/png");
41 | expect(detectedFile.signature.sequence).toEqual([
42 | "89",
43 | "50",
44 | "4e",
45 | "47",
46 | "d",
47 | "a",
48 | "1a",
49 | "a",
50 | ]);
51 | });
52 |
53 | it("should detect the file type of a fileUint8Array as a png file", () => {
54 | const fileUint8Array = new Uint8Array([
55 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0,
56 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89,
57 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115,
58 | 82, 71, 66, 0, 174,
59 | ]);
60 | const detectedFile = fileTypeChecker.detectFile(
61 | fileUint8Array
62 | ) as DetectedFileInfo;
63 | expect(detectedFile.extension).toBe("png");
64 | expect(detectedFile.mimeType).toBe("image/png");
65 | expect(detectedFile.signature.sequence).toEqual([
66 | "89",
67 | "50",
68 | "4e",
69 | "47",
70 | "d",
71 | "a",
72 | "1a",
73 | "a",
74 | ]);
75 | });
76 |
77 | it("should return undefined if no file type is detected", () => {
78 | const file = [1, 2, 3, 4, 5];
79 | const detectedFile = fileTypeChecker.detectFile(file);
80 | expect(detectedFile).toBeUndefined();
81 | });
82 |
83 | it("should throw a TypeError if the file type is not valid", () => {
84 | const file: any = "10";
85 | const func = () => {
86 | fileTypeChecker.detectFile(file);
87 | };
88 | expect(func).toThrow(TypeError);
89 | });
90 |
91 | it("should return undefined if the Array file is empty", () => {
92 | const file: Array = [];
93 | const detectedFile = fileTypeChecker.detectFile(file);
94 | expect(detectedFile).toBeUndefined();
95 | });
96 |
97 | it("should return undefined if chunkSize is too short", () => {
98 | const file: Array = [
99 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0,
100 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89,
101 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115,
102 | 82, 71, 66, 0, 174,
103 | ];
104 | const detectedFile = fileTypeChecker.detectFile(file, { chunkSize: 4 });
105 | expect(detectedFile).toBeUndefined();
106 | });
107 |
108 | it("should throw a RangeError if chunkSize is zero", () => {
109 | const file: Array = [
110 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0,
111 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89,
112 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115,
113 | 82, 71, 66, 0, 174,
114 | ];
115 | const func = () => {
116 | fileTypeChecker.detectFile(file, { chunkSize: 0 });
117 | };
118 | expect(func).toThrow(RangeError);
119 | });
120 |
121 | it("should throw a RangeError if chunkSize is less than zero", () => {
122 | const file: Array = [
123 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0,
124 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89,
125 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115,
126 | 82, 71, 66, 0, 174,
127 | ];
128 | const func = () => {
129 | fileTypeChecker.detectFile(file, { chunkSize: 0 });
130 | };
131 | expect(func).toThrow(RangeError);
132 | });
133 |
134 | it("should detect the file type of an Array as a png file and chunkSize of 32 bytes", () => {
135 | const file: Array = [
136 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0,
137 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89,
138 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115,
139 | 82, 71, 66, 0, 174,
140 | ];
141 | const detectedFile = fileTypeChecker.detectFile(file, {
142 | chunkSize: 32,
143 | }) as DetectedFileInfo;
144 | expect(detectedFile.extension).toBe("png");
145 | expect(detectedFile.mimeType).toBe("image/png");
146 | expect(detectedFile.signature.sequence).toEqual([
147 | "89",
148 | "50",
149 | "4e",
150 | "47",
151 | "d",
152 | "a",
153 | "1a",
154 | "a",
155 | ]);
156 | });
157 | });
158 |
--------------------------------------------------------------------------------
/test/detection/image/image.spec.ts:
--------------------------------------------------------------------------------
1 | import fileTypeChecker from "../../../src/index";
2 |
3 | import { DetectedFileInfo } from "../../../src/core";
4 |
5 | describe("detectFile", () => {
6 | it("should detect the file type of an Array as a avif file", () => {
7 | const file: Array = [
8 | 0, 0, 0, 20, 102, 116, 121, 112, 97, 118, 105, 102, 0, 0,
9 | ];
10 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
11 | expect(detectedFile.extension).toBe("avif");
12 | expect(detectedFile.mimeType).toBe("image/avif");
13 | expect(detectedFile.signature.sequence).toEqual(["0", "0", "0"]);
14 | });
15 |
16 | it("should detect the file type of an ArrayBuffer as a avif file", () => {
17 | const file: Array = [
18 | 0, 0, 0, 20, 102, 116, 121, 112, 97, 118, 105, 102, 0, 0,
19 | ];
20 | const buffer: ArrayBuffer = new Uint8Array(file).buffer;
21 | const detectedFile = fileTypeChecker.detectFile(buffer) as DetectedFileInfo;
22 | expect(detectedFile.extension).toBe("avif");
23 | expect(detectedFile.mimeType).toBe("image/avif");
24 | expect(detectedFile.signature.sequence).toEqual(["0", "0", "0"]);
25 | });
26 |
27 | it("should not detect a corrupted Array of an avif file which does not include the 'ftypavif' string", () => {
28 | const file: Array = [
29 | 0, 0, 0, 20, 102, 114, 121, 112, 97, 118, 105, 102, 0, 0,
30 | ];
31 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
32 | expect(detectedFile).toBeUndefined();
33 | });
34 |
35 | it("should not detect a m4v file as a heic file, given an Array of an m4v file (since heic files contain the m4v signature within their own signature)", () => {
36 | const file: Array = [
37 | 0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32, 0, 0, 0, 32,
38 | 102, 116, 121, 112, 77, 52, 86, 72, 0, 0, 0, 1, 77, 52, 86, 72, 77, 52,
39 | 65, 32, 109, 112, 52, 50, 105, 115, 111, 109,
40 | ];
41 |
42 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
43 | expect(detectedFile.extension).toBe("m4v");
44 | });
45 |
46 | it("should detect the file type of an Array as a heic file", () => {
47 | const file: Array = [
48 | 0, 0, 0, 24, 0x66, 0x74, 0x79, 0x70, 0x6d, 105, 102, 49, 0, 0, 0, 0, 109,
49 | 105, 102, 49, 104, 101, 105, 99, 0, 0, 1, 254, 109, 101, 116, 97, 0, 0, 0,
50 | 0, 0, 0, 0, 33, 104, 100, 108,
51 | ];
52 |
53 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
54 | expect(detectedFile.extension).toBe("heic");
55 | expect(detectedFile.mimeType).toBe("image/heic");
56 | });
57 | });
58 |
--------------------------------------------------------------------------------
/test/detection/other/other.spec.ts:
--------------------------------------------------------------------------------
1 | import fileTypeChecker from "../../../src/index";
2 |
3 | import { DetectedFileInfo } from "../../../src/core";
4 |
5 | describe("detectFile", () => {
6 | it("should detect the file type of an Array as a orc file", () => {
7 | const file: Array = [
8 | 79, 82, 67, 10, 5, 18, 3, 8, 136, 39, 10, 21, 10, 2, 0, 0, 18, 15, 8, 136,
9 | 39, 18, 10, 8, 2, 16, 144, 78, 24, 200, 151, 246, 11, 10, 20, 10, 2, 0, 0,
10 | 18, 14, 8, 136, 39, 34, 9,
11 | ];
12 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
13 | expect(detectedFile.extension).toBe("orc");
14 | expect(detectedFile.mimeType).toBe("application/x-orc");
15 | expect(detectedFile.signature.sequence).toEqual(["4f", "52", "43"]);
16 | });
17 |
18 | it("should detect the file type of an Array as a parquet file", () => {
19 | const file: Array = [
20 | 80, 65, 82, 49, 21, 0, 21, 238, 45, 21, 128, 20, 44, 21, 220, 5, 21, 0,
21 | 21, 6, 21, 6, 0, 0, 247, 22, 28, 3, 0, 0, 0, 220,
22 | ];
23 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
24 | expect(detectedFile.extension).toBe("parquet");
25 | expect(detectedFile.mimeType).toBe("application/vnd.apache.parquet");
26 | expect(detectedFile.signature.sequence).toEqual(["50", "41", "52", "31"]);
27 | });
28 |
29 | it("should detect the file type of an Array as a doc file", () => {
30 | const file: Array = [
31 | 208, 207, 17, 224, 161, 177, 26, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32 | 0, 0, 0, 0, 59, 0, 3, 0, 254, 255, 9, 0,
33 | ];
34 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
35 | expect(detectedFile.extension).toBe("doc");
36 | expect(detectedFile.mimeType).toBe("application/msword");
37 | expect(detectedFile.signature.sequence).toEqual([
38 | "d0",
39 | "cf",
40 | "11",
41 | "e0",
42 | "a1",
43 | "b1",
44 | "1a",
45 | "e1",
46 | ]);
47 | });
48 |
49 | it("should detect the file type of an Array as a pcap file", () => {
50 | const file: Array = [
51 | 212, 195, 178, 161, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 1,
52 | 0, 0, 0, 72, 244, 159, 69, 105, 94, 3, 0,
53 | ];
54 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
55 | expect(detectedFile.extension).toBe("pcap");
56 | expect(detectedFile.mimeType).toBe("application/vnd.tcpdump.pcap");
57 | expect(detectedFile.signature.sequence).toEqual(["d4", "c3", "b2", "a1"]);
58 | });
59 |
60 | it("should detect the file type of an Array as an exe file", () => {
61 | const file: Array = [
62 | 77, 90, 144, 0, 3, 0, 0, 0, 4, 0, 0, 0, 255, 255, 0, 0, 184, 0, 0, 0, 0,
63 | 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0,
64 | ];
65 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
66 | expect(detectedFile.extension).toBe("exe");
67 | expect(detectedFile.mimeType).toBe("application/x-msdownload");
68 | expect(detectedFile.signature.sequence).toEqual(["4d", "5a"]);
69 | });
70 |
71 | it("should detect the file type of an Array as an mach-o file", () => {
72 | const file: Array = [
73 | 207, 250, 237, 254, 7, 0, 0, 1, 3, 0, 0, 128, 2, 0, 0, 0, 16, 0, 0, 0,
74 | 216, 7, 0, 0, 133, 0, 32, 0, 0, 0, 0, 0,
75 | ];
76 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
77 | expect(detectedFile.extension).toBe("macho");
78 | expect(detectedFile.mimeType).toBe("application/x-mach-binary");
79 | expect(detectedFile.signature.sequence).toEqual(["cf", "fa", "ed", "fe"]);
80 | });
81 | });
82 |
--------------------------------------------------------------------------------
/test/detection/video/videos.spec.ts:
--------------------------------------------------------------------------------
1 | import fileTypeChecker from "../../../src/index";
2 |
3 | import { DetectedFileInfo } from "../../../src/core";
4 |
5 | describe("detectFile", () => {
6 | it("should detect the file type of an Array as a mp4 file", () => {
7 | const file: Array = [
8 | 0, 0, 0, 32, 102, 116, 121, 112, 105, 115, 111, 109, 0, 0, 2, 0, 105, 115,
9 | 111, 109, 105, 115, 111, 50, 97, 118, 99, 49, 109, 112, 52, 49, 0, 0, 53,
10 | 183, 109, 111, 111, 118, 0, 0, 0, 108, 109, 118, 104, 100, 0, 0, 0, 0, 0,
11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 232,
12 | ];
13 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
14 | expect(detectedFile.extension).toBe("mp4");
15 | expect(detectedFile.mimeType).toBe("video/mp4");
16 | expect(detectedFile.signature.sequence).toEqual([
17 | "66",
18 | "74",
19 | "79",
20 | "70",
21 | "69",
22 | "73",
23 | "6f",
24 | "6d",
25 | ]);
26 | });
27 |
28 | it("should detect the file type of an Array as a m4v file", () => {
29 | const file: Array = [
30 | 0, 0, 0, 28, 102, 116, 121, 112, 77, 52, 86, 32, 0, 0, 2, 0, 105, 115,
31 | 111, 109, 105, 115, 111, 50, 97, 118, 99, 49, 0, 0, 0, 8,
32 | ];
33 | const detectedFile = fileTypeChecker.detectFile(file) as DetectedFileInfo;
34 | expect(detectedFile.extension).toBe("m4v");
35 | expect(detectedFile.mimeType).toBe("video/x-m4v");
36 | expect(detectedFile.signature.sequence).toEqual([
37 | "66",
38 | "74",
39 | "79",
40 | "70",
41 | "4d",
42 | "34",
43 | "56",
44 | "20",
45 | ]);
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/test/validation/audio/audio.spec.ts:
--------------------------------------------------------------------------------
1 | import fileTypeChecker from "../../../src/index";
2 |
3 | describe("validateFileType", () => {
4 | it("should return true when given an Array of a m4a file and using the isAAC() function without excluding similar files", () => {
5 | const file: Array = [
6 | 0, 0, 0, 24, 102, 116, 121, 112, 77, 52, 65, 32, 0, 0, 2, 0, 105, 115,
7 | 111, 109, 105, 115, 111, 50, 0, 0, 0, 8, 102, 114, 101, 101,
8 | ];
9 | const detectedFile: boolean = fileTypeChecker.isAAC(file);
10 | expect(detectedFile).toBeTruthy();
11 | });
12 |
13 | it("should return false when given an Array of a m4a file and using the isAAC() function with excluding similar files", () => {
14 | const file: Array = [
15 | 0, 0, 0, 24, 102, 116, 121, 112, 77, 52, 65, 32, 0, 0, 2, 0, 105, 115,
16 | 111, 109, 105, 115, 111, 50, 0, 0, 0, 8, 102, 114, 101, 101,
17 | ];
18 | const detectedFile: boolean = fileTypeChecker.isAAC(file, {
19 | excludeSimilarTypes: true,
20 | });
21 | expect(detectedFile).toBeFalsy();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/test/validation/image/images.spec.ts:
--------------------------------------------------------------------------------
1 | import fileTypeChecker from "../../../src/index";
2 |
3 | describe("image validation", () => {
4 | it("should return false for a corrupted Array of an avif file which does not include the 'ftypavif' string", () => {
5 | const fileArrayNumber: Array = [
6 | 0, 0, 0, 20, 66, 74, 79, 72, 61, 76, 69, 66, 0, 0,
7 | ];
8 | const detectedFile = fileTypeChecker.isAVIF(fileArrayNumber);
9 | expect(detectedFile).toBeFalsy();
10 | });
11 |
12 | it("should detect the type of a given Array to be a bmp file", () => {
13 | const fileArrayNumber: Array = [
14 | 66, 77, 138, 123, 12, 0, 0, 0, 0, 0, 138, 0, 0, 0, 124, 0, 0, 0, 128, 2,
15 | 0, 0, 170, 1, 0, 0, 1, 0, 24, 0, 0, 0, 0, 0, 0, 123, 12, 0, 0, 0, 0, 0, 0,
16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0,
17 | ];
18 | const detectedFile = fileTypeChecker.isBMP(fileArrayNumber);
19 | expect(detectedFile).toBeTruthy();
20 | });
21 |
22 | it("should detect the type of a given Array to be a avif file", () => {
23 | const fileArrayNumber: Array = [
24 | 0, 0, 0, 20, 102, 116, 121, 112, 97, 118, 105, 102, 0, 0,
25 | ];
26 | const detectedFile = fileTypeChecker.isAVIF(fileArrayNumber);
27 | expect(detectedFile).toBeTruthy();
28 | });
29 |
30 | it("should return false for a corrupted Array of an avif file which does not include the 'ftypavif' string", () => {
31 | const fileArrayNumber: Array = [
32 | 0, 0, 0, 20, 66, 74, 79, 72, 61, 76, 69, 66, 0, 0,
33 | ];
34 | const detectedFile = fileTypeChecker.isAVIF(fileArrayNumber);
35 | expect(detectedFile).toBeFalsy();
36 | });
37 |
38 | it("should return false when given an Array of an m4v file and using the isHEIC() function (since heic files contain the m4v signature within their own signature) ", () => {
39 | const fileArrayNumber: Array = [
40 | 0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32, 0, 0, 0, 32,
41 | 102, 116, 121, 112, 77, 52, 86, 72, 0, 0, 0, 1, 77, 52, 86, 72, 77, 52,
42 | 65, 32, 109, 112, 52, 50, 105, 115, 111, 109,
43 | ];
44 |
45 | const isHEIC: boolean = fileTypeChecker.isHEIC(fileArrayNumber);
46 | expect(isHEIC).toBeFalsy();
47 | });
48 |
49 | it("should return true when given an Array of a heic file and using the isHEIC() function", () => {
50 | const fileArrayNumber: Array = [
51 | 0, 0, 0, 24, 0x66, 0x74, 0x79, 0x70, 0x6d, 105, 102, 49, 0, 0, 0, 0, 109,
52 | 105, 102, 49, 104, 101, 105, 99, 0, 0, 1, 254, 109, 101, 116, 97, 0, 0, 0,
53 | 0, 0, 0, 0, 33, 104, 100, 108,
54 | ];
55 |
56 | const isHEIC: boolean = fileTypeChecker.isHEIC(fileArrayNumber);
57 | expect(isHEIC).toBeTruthy();
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/test/validation/other/other.spec.ts:
--------------------------------------------------------------------------------
1 | import fileTypeChecker from "../../../src/index";
2 |
3 | describe("validateFileType", () => {
4 | it("should return true when given an Array of a orc file and using the isORC() function", () => {
5 | const fileArrayNumber: Array = [
6 | 79, 82, 67, 10, 5, 18, 3, 8, 136, 39, 10, 21, 10, 2, 0, 0, 18, 15, 8, 136,
7 | 39, 18, 10, 8, 2, 16, 144, 78, 24, 200, 151, 246, 11, 10, 20, 10, 2, 0, 0,
8 | 18, 14, 8, 136, 39, 34, 9,
9 | ];
10 |
11 | const isORC: boolean = fileTypeChecker.isORC(fileArrayNumber);
12 | expect(isORC).toBeTruthy();
13 | });
14 |
15 | it("should return true when given an Array of a parquet file and using the isPARQUET() function", () => {
16 | const fileArrayNumber: Array = [
17 | 80, 65, 82, 49, 21, 0, 21, 238, 45, 21, 128, 20, 44, 21, 220, 5, 21, 0,
18 | 21, 6, 21, 6, 0, 0, 247, 22, 28, 3, 0, 0, 0, 220,
19 | ];
20 | const isPARQUET: boolean = fileTypeChecker.isPARQUET(fileArrayNumber);
21 | expect(isPARQUET).toBeTruthy();
22 | });
23 |
24 | it("should return true when given an Array