├── .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 | ![Detection GIF](https://github.com/nir11/file-type-checker/blob/main/src/assets/detection.gif) 38 | 39 | ### Validation sample: 40 | 41 | ![Detection GIF](https://github.com/nir11/file-type-checker/blob/main/src/assets/validation.gif) 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 of a doc file and using the isDoc() function", () => { 25 | const fileArrayNumber: Array = [ 26 | 208, 207, 17, 224, 161, 177, 26, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27 | 0, 0, 0, 0, 59, 0, 3, 0, 254, 255, 9, 0, 28 | ]; 29 | const isDOC: boolean = fileTypeChecker.isDOC(fileArrayNumber); 30 | expect(isDOC).toBeTruthy(); 31 | }); 32 | 33 | it("should return true when given an Array of a pcap file and using the isPCAP() function", () => { 34 | const fileArrayNumber: Array = [ 35 | 212, 195, 178, 161, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 1, 36 | 0, 0, 0, 72, 244, 159, 69, 105, 94, 3, 0, 37 | ]; 38 | const isPCAP: boolean = fileTypeChecker.isPCAP(fileArrayNumber); 39 | expect(isPCAP).toBeTruthy(); 40 | }); 41 | 42 | it("should return true when given an Array of a pcap file and using the isEXE() function", () => { 43 | const fileArrayNumber: Array = [ 44 | 77, 90, 144, 0, 3, 0, 0, 0, 4, 0, 0, 0, 255, 255, 0, 0, 184, 0, 0, 0, 0, 45 | 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 46 | ]; 47 | const isEXE: boolean = fileTypeChecker.isEXE(fileArrayNumber); 48 | expect(isEXE).toBeTruthy(); 49 | }); 50 | 51 | it("should return true when given an Array of a pcap file and using the isMACHO() function", () => { 52 | const fileArrayNumber: Array = [ 53 | 207, 250, 237, 254, 7, 0, 0, 1, 3, 0, 0, 128, 2, 0, 0, 0, 16, 0, 0, 0, 54 | 216, 7, 0, 0, 133, 0, 32, 0, 0, 0, 0, 0, 55 | ]; 56 | const isMACHO: boolean = fileTypeChecker.isMACHO(fileArrayNumber); 57 | expect(isMACHO).toBeTruthy(); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /test/validation/validation.spec.ts: -------------------------------------------------------------------------------- 1 | import fileTypeChecker from "../../src/index"; 2 | 3 | describe("validateFileType", () => { 4 | it("should return true when given an Array of a png file and a list of accepted types that contains its type", () => { 5 | const fileArrayNumber: Array = [ 6 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 7 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 8 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 9 | 82, 71, 66, 0, 174, 10 | ]; 11 | const detectedFile: boolean = fileTypeChecker.validateFileType( 12 | fileArrayNumber, 13 | ["gif", "jpeg", "png"] 14 | ); 15 | expect(detectedFile).toBeTruthy(); 16 | }); 17 | 18 | it("should return false when given an Array of a png file and a list of accepted types that not contains its type", () => { 19 | const fileArrayNumber: Array = [ 20 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 21 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 22 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 23 | 82, 71, 66, 0, 174, 24 | ]; 25 | const detectedFile: boolean = fileTypeChecker.validateFileType( 26 | fileArrayNumber, 27 | ["gif", "jpeg"] 28 | ); 29 | expect(detectedFile).toBeFalsy(); 30 | }); 31 | 32 | it("should return true when given an ArrayBuffer of a png file and a list of accepted types that contains its type", () => { 33 | const fileUint8Array = new Uint8Array([ 34 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 35 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 36 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 37 | 82, 71, 66, 0, 174, 38 | ]).buffer; 39 | const detectedFile: boolean = fileTypeChecker.validateFileType( 40 | fileUint8Array, 41 | ["gif", "jpeg", "png"] 42 | ); 43 | expect(detectedFile).toBeTruthy(); 44 | }); 45 | 46 | it("should return false when given an ArrayBuffer of a png file and a list of accepted types that not contains its type", () => { 47 | const fileUint8Array = new Uint8Array([ 48 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 49 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 50 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 51 | 82, 71, 66, 0, 174, 52 | ]).buffer; 53 | const detectedFile: boolean = fileTypeChecker.validateFileType( 54 | fileUint8Array, 55 | ["gif", "jpeg"] 56 | ); 57 | expect(detectedFile).toBeFalsy(); 58 | }); 59 | 60 | it("should return true when given an Uint8Array of a png file and a list of accepted types that contains its type", () => { 61 | const fileUint8Array = new Uint8Array([ 62 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 63 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 64 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 65 | 82, 71, 66, 0, 174, 66 | ]); 67 | const detectedFile: boolean = fileTypeChecker.validateFileType( 68 | fileUint8Array, 69 | ["gif", "jpeg", "png"] 70 | ); 71 | expect(detectedFile).toBeTruthy(); 72 | }); 73 | 74 | it("should return false when given an Uint8Array of a png file and a list of accepted types that not contains its type", () => { 75 | const fileUint8Array = new Uint8Array([ 76 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 77 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 78 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 79 | 82, 71, 66, 0, 174, 80 | ]); 81 | const detectedFile: boolean = fileTypeChecker.validateFileType( 82 | fileUint8Array, 83 | ["gif", "jpeg"] 84 | ); 85 | expect(detectedFile).toBeFalsy(); 86 | }); 87 | 88 | it("should return false when given an Array of a png file and an empty list of accepted types", () => { 89 | const file: Array = [ 90 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 91 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 92 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 93 | 82, 71, 66, 0, 174, 94 | ]; 95 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, []); 96 | expect(detectedFile).toBeFalsy(); 97 | }); 98 | 99 | it("should throw an error when given a corrupted Array", () => { 100 | const file: any = [ 101 | null, 102 | 80, 103 | 78, 104 | 71, 105 | 13, 106 | 10, 107 | 26, 108 | null, 109 | 0, 110 | 0, 111 | 0, 112 | null, 113 | 73, 114 | 72, 115 | 68, 116 | 82, 117 | 0, 118 | 0, 119 | null, 120 | 0, 121 | 0, 122 | 89, 123 | 115, 124 | 0, 125 | 0, 126 | `46`, 127 | 35, 128 | 0, 129 | 0, 130 | true, 131 | 35, 132 | 1, 133 | 120, 134 | 165, 135 | 63, 136 | false, 137 | 0, 138 | 0, 139 | "0", 140 | 1, 141 | 115, 142 | 82, 143 | 71, 144 | 66, 145 | 0, 146 | 174, 147 | ]; 148 | 149 | const func = () => { 150 | fileTypeChecker.validateFileType(file, ["png", "jpeg"]); 151 | }; 152 | expect(func).toThrow(TypeError); 153 | }); 154 | 155 | it("should throw an error when given an unsupported file type in the list of accepted types", () => { 156 | const file: Array = [ 157 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 158 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 159 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 160 | 82, 71, 66, 0, 174, 161 | ]; 162 | const func = () => { 163 | fileTypeChecker.validateFileType(file, [ 164 | "gifz", 165 | "mp4", 166 | "avi", 167 | "png", 168 | "wavb", // intentional typo 169 | ]); 170 | }; 171 | expect(func).toThrow(TypeError); 172 | }); 173 | 174 | it("should return true when given an Array of a png file and a list of accepted types that contains a duplicates of its type", () => { 175 | const file: Array = [ 176 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 4, 0, 177 | 0, 0, 1, 244, 8, 6, 0, 0, 0, 163, 38, 95, 43, 0, 0, 0, 9, 112, 72, 89, 178 | 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, 165, 63, 118, 0, 0, 0, 1, 115, 179 | 82, 71, 66, 0, 174, 180 | ]; 181 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 182 | "gif", 183 | "mp4", 184 | "png", 185 | "avi", 186 | "png", 187 | ]); 188 | expect(detectedFile).toBeTruthy(); 189 | }); 190 | 191 | it("should return true when given an Array of a mkv file and a list that contains its type without 'webm''", () => { 192 | const file: Array = [ 193 | 26, 69, 223, 163, 163, 66, 134, 129, 1, 66, 247, 129, 1, 66, 242, 129, 4, 194 | 66, 243, 129, 8, 66, 130, 136, 109, 97, 116, 114, 111, 115, 107, 97, 66, 195 | 135, 129, 4, 66, 133, 129, 2, 24, 83, 128, 103, 1, 0, 0, 0, 0, 74, 238, 196 | 203, 17, 77, 155, 116, 193, 191, 132, 254, 50, 76, 130, 77, 197 | ]; 198 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 199 | "mkv", 200 | "gif", 201 | ]); 202 | expect(detectedFile).toBeTruthy(); 203 | }); 204 | 205 | it("should return false when given an Array of a mkv file and a list that contains 'webm' without 'mkv'", () => { 206 | const file: Array = [ 207 | 26, 69, 223, 163, 163, 66, 134, 129, 1, 66, 247, 129, 1, 66, 242, 129, 4, 208 | 66, 243, 129, 8, 66, 130, 136, 109, 97, 116, 114, 111, 115, 107, 97, 66, 209 | 135, 129, 4, 66, 133, 129, 2, 24, 83, 128, 103, 1, 0, 0, 0, 0, 74, 238, 210 | 203, 17, 77, 155, 116, 193, 191, 132, 254, 50, 76, 130, 77, 211 | ]; 212 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 213 | "webm", 214 | "gif", 215 | ]); 216 | expect(detectedFile).toBeFalsy(); 217 | }); 218 | 219 | it("should return true when given an Array of a webm file and a list that contains 'webm' without 'mkv'", () => { 220 | const file: Array = [ 221 | 26, 69, 223, 163, 159, 66, 134, 129, 1, 66, 247, 129, 1, 66, 242, 129, 4, 222 | 66, 243, 129, 8, 66, 130, 132, 119, 101, 98, 109, 66, 135, 129, 2, 66, 223 | 133, 129, 2, 24, 83, 128, 103, 1, 0, 0, 0, 0, 128, 92, 20, 17, 77, 155, 224 | 116, 187, 77, 187, 139, 83, 171, 132, 21, 73, 169, 102, 83, 225 | ]; 226 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 227 | "webm", 228 | "gif", 229 | ]); 230 | expect(detectedFile).toBeTruthy(); 231 | }); 232 | 233 | it("should return false when given an Array of a webm file and a list that contains 'mkv' without 'webm'", () => { 234 | const file: Array = [ 235 | 26, 69, 223, 163, 159, 66, 134, 129, 1, 66, 247, 129, 1, 66, 242, 129, 4, 236 | 66, 243, 129, 8, 66, 130, 132, 119, 101, 98, 109, 66, 135, 129, 2, 66, 237 | 133, 129, 2, 24, 83, 128, 103, 1, 0, 0, 0, 0, 128, 92, 20, 17, 77, 155, 238 | 116, 187, 77, 187, 139, 83, 171, 132, 21, 73, 169, 102, 83, 239 | ]; 240 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 241 | "mkv", 242 | "gif", 243 | ]); 244 | expect(detectedFile).toBeFalsy(); 245 | }); 246 | 247 | it("should return true when given an Array of a m4v file and a list that contains 'm4v' without 'flv'", () => { 248 | const file: Array = [ 249 | 26, 69, 223, 163, 159, 66, 134, 129, 1, 66, 247, 129, 1, 66, 242, 129, 4, 250 | 66, 243, 129, 8, 66, 130, 132, 119, 101, 98, 109, 66, 135, 129, 2, 66, 251 | 133, 129, 2, 24, 83, 128, 103, 1, 0, 0, 0, 0, 128, 92, 20, 17, 77, 155, 252 | 116, 187, 77, 187, 139, 83, 171, 132, 21, 73, 169, 102, 83, 253 | ]; 254 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 255 | "webm", 256 | "m4v", 257 | ]); 258 | expect(detectedFile).toBeTruthy(); 259 | }); 260 | 261 | it("should return false when given an Array of a m4v file and a list that contains 'flv' without 'm4v'", () => { 262 | const file: Array = [ 263 | 26, 69, 223, 163, 159, 66, 134, 129, 1, 66, 247, 129, 1, 66, 242, 129, 4, 264 | 66, 243, 129, 8, 66, 130, 132, 119, 101, 98, 109, 66, 135, 129, 2, 66, 265 | 133, 129, 2, 24, 83, 128, 103, 1, 0, 0, 0, 0, 128, 92, 20, 17, 77, 155, 266 | 116, 187, 77, 187, 139, 83, 171, 132, 21, 73, 169, 102, 83, 267 | ]; 268 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 269 | "flv", 270 | "gif", 271 | ]); 272 | expect(detectedFile).toBeFalsy(); 273 | }); 274 | 275 | it("should return true when given an Array of a m4a file and a list that contains 'aac' (very similar to m4a)'", () => { 276 | const file: Array = [ 277 | 0, 0, 0, 24, 102, 116, 121, 112, 77, 52, 65, 32, 0, 0, 2, 0, 105, 115, 278 | 111, 109, 105, 115, 111, 50, 0, 0, 0, 8, 102, 114, 101, 101, 279 | ]; 280 | const detectedFile: boolean = fileTypeChecker.validateFileType(file, [ 281 | "aac", 282 | "gif", 283 | ]); 284 | expect(detectedFile).toBeTruthy(); 285 | }); 286 | 287 | it("should return false when given an Array of a m4a file and a list that contains 'aac' (very similar to m4a)' and 'excludeSimilarTypes' is true", () => { 288 | const file: Array = [ 289 | 0, 0, 0, 24, 102, 116, 121, 112, 77, 52, 65, 32, 0, 0, 2, 0, 105, 115, 290 | 111, 109, 105, 115, 111, 50, 0, 0, 0, 8, 102, 114, 101, 101, 291 | ]; 292 | const detectedFile: boolean = fileTypeChecker.validateFileType( 293 | file, 294 | ["aac", "gif"], 295 | { excludeSimilarTypes: true } 296 | ); 297 | expect(detectedFile).toBeFalsy(); 298 | }); 299 | }); 300 | 301 | it("should return false when validating an m4v file signature that shares the same signature as a heic file, with only 'heic' as the accepted type", () => { 302 | const fileArrayNumber: Array = [ 303 | 0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32, 0, 0, 0, 32, 304 | 102, 116, 121, 112, 77, 52, 86, 72, 0, 0, 0, 1, 77, 52, 86, 72, 77, 52, 65, 305 | 32, 109, 112, 52, 50, 105, 115, 111, 109, 306 | ]; 307 | 308 | const isM4v: boolean = fileTypeChecker.validateFileType(fileArrayNumber, [ 309 | "heic", 310 | ]); 311 | expect(isM4v).toBeFalsy(); 312 | }); 313 | 314 | it("should return true when validating an m4v file signature with 'm4v' as the accepted type", () => { 315 | const fileArrayNumber: Array = [ 316 | 0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32, 0, 0, 0, 32, 317 | 102, 116, 121, 112, 77, 52, 86, 72, 0, 0, 0, 1, 77, 52, 86, 72, 77, 52, 65, 318 | 32, 109, 112, 52, 50, 105, 115, 111, 109, 319 | ]; 320 | 321 | const isM4v: boolean = fileTypeChecker.validateFileType(fileArrayNumber, [ 322 | "m4v", 323 | ]); 324 | expect(isM4v).toBeTruthy(); 325 | }); 326 | -------------------------------------------------------------------------------- /test/validation/video/videos.spec.ts: -------------------------------------------------------------------------------- 1 | import fileTypeChecker from "../../../src/index"; 2 | 3 | describe("validateFileType", () => { 4 | it("should return true when given an Array of a m4v file and using the isMP4() function without excluding similar files", () => { 5 | const fileArrayNumber: Array = [ 6 | 0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32, 0, 0, 0, 32, 7 | 102, 116, 121, 112, 77, 52, 86, 72, 0, 0, 0, 1, 77, 52, 86, 72, 77, 52, 8 | 65, 32, 109, 112, 52, 50, 105, 115, 111, 109, 9 | ]; 10 | 11 | const isMp4: boolean = fileTypeChecker.isMP4(fileArrayNumber); 12 | expect(isMp4).toBeTruthy(); 13 | }); 14 | 15 | it("should return false when given an Array of a m4v file and using the isMP4() function with excluding similar files", () => { 16 | const fileArrayNumber: Array = [ 17 | 0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32, 0, 0, 0, 32, 18 | 102, 116, 121, 112, 77, 52, 86, 72, 0, 0, 0, 1, 77, 52, 86, 72, 77, 52, 19 | 65, 32, 109, 112, 52, 50, 105, 115, 111, 109, 20 | ]; 21 | 22 | const isMp4: boolean = fileTypeChecker.isMP4(fileArrayNumber, { 23 | excludeSimilarTypes: true, 24 | }); 25 | expect(isMp4).toBeFalsy(); 26 | }); 27 | 28 | it("should return true when given an Array of a mp4 file and using the validateFileType() function with excluding similar files", () => { 29 | const fileArrayNumber: Array = [ 30 | 0, 0, 0, 32, 102, 116, 121, 112, 105, 115, 111, 109, 0, 0, 2, 0, 105, 115, 31 | 111, 109, 105, 115, 111, 50, 97, 118, 99, 49, 109, 112, 52, 49, 32 | ]; 33 | 34 | const isMp4: boolean = fileTypeChecker.validateFileType( 35 | fileArrayNumber, 36 | ["mp4"], 37 | { 38 | excludeSimilarTypes: true, 39 | } 40 | ); 41 | expect(isMp4).toBeTruthy(); 42 | }); 43 | 44 | it("should return true when given an Array of a avi file and using the isAVI()", () => { 45 | const fileArrayNumber: Array = [ 46 | 82, 73, 70, 70, 226, 213, 22, 0, 65, 86, 73, 32, 76, 73, 83, 84, 192, 0, 47 | 0, 0, 104, 100, 114, 108, 97, 118, 105, 104, 56, 0, 0, 0, 48 | ]; 49 | 50 | const isAvi: boolean = fileTypeChecker.isAVI(fileArrayNumber); 51 | expect(isAvi).toBeTruthy(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "lib": ["es6"], 5 | "module": "commonjs", 6 | "rootDir": "src", 7 | "outDir": "dist", 8 | "resolveJsonModule": true, 9 | "allowJs": true, 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "strict": true, 13 | "noImplicitAny": true, 14 | "skipLibCheck": true, 15 | "strictPropertyInitialization": false 16 | }, 17 | "exclude": ["node_modules", "**/__tests__"], 18 | "include": ["./src"] 19 | } 20 | --------------------------------------------------------------------------------