Skip to content

Commit eeb00f1

Browse files
authored
Migrate filevalidator to ESM (#2)
1 parent 307b4f6 commit eeb00f1

File tree

3 files changed

+88
-105
lines changed

3 files changed

+88
-105
lines changed

README.md

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,15 @@ Usage:
88

99

1010
```js
11-
define([
12-
'filevalidator',
13-
],
11+
import { verifyFileType } from 'filevalidator';
1412

15-
function(filevalidator) {
13+
const fileInput = document.getElementById('file-input');
1614

17-
var fileInput = document.getElementById('file-input');
18-
19-
fileInput.addEventListener('change', function(e) {
20-
var file = e.currentTarget.files[0];
21-
filevalidator.verifyFileType(file, ['mp3', 'wav'], function(valid) {
22-
alert('Valid mp3 or wave file: ' + !!valid);
23-
});
15+
fileInput.addEventListener('change', function(e) {
16+
const file = e.currentTarget.files[0];
17+
verifyFileType(file, ['mp3', 'wav'], function(valid) {
18+
alert('Valid mp3 or wave file: ' + !!valid);
2419
});
25-
2620
});
2721
```
2822

filevalidator.js

Lines changed: 80 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,87 @@
1-
define([
2-
'underscore',
3-
],
1+
'use strict';
42

5-
function(_) {
6-
'use strict';
3+
// https://en.wikipedia.org/wiki/List_of_file_signatures
4+
const fileSignatures = {
5+
'mp3': [
6+
// MPEG-1 Layer 3 file without an ID3 tag or with an ID3v1 tag (which's appended at the end of the file)
7+
[0xFF, 0xFB],
8+
// MP3 file with an ID3v2 container
9+
[0x49, 0x44, 0x33],
10+
// Other MP3 files (FF Fx and FF Ex – they may cause false-positives)
11+
// Headers taken from https://www.garykessler.net/library/file_sigs.html
12+
[0xFF, 0xE0], [0xFF, 0xE1], [0xFF, 0xE2], [0xFF, 0xE3], [0xFF, 0xE4],
13+
[0xFF, 0xE5], [0xFF, 0xE6], [0xFF, 0xE7], [0xFF, 0xE8], [0xFF, 0xE9],
14+
[0xFF, 0xEA], [0xFF, 0xEB], [0xFF, 0xEC], [0xFF, 0xED], [0xFF, 0xEE], [0xFF, 0xEF],
15+
[0xFF, 0xF0], [0xFF, 0xF1], [0xFF, 0xF2], [0xFF, 0xF3], [0xFF, 0xF4],
16+
[0xFF, 0xF5], [0xFF, 0xF6], [0xFF, 0xF7], [0xFF, 0xF8], [0xFF, 0xF9],
17+
[0xFF, 0xFA], [0xFF, 0xFB], [0xFF, 0xFC], [0xFF, 0xFD], [0xFF, 0xFE], [0xFF, 0xFF]
18+
],
19+
'wav': [
20+
// Waveform Audio File Format
21+
// Empty slots can be any byte. Can't look at only first 4 or else .avi files match
22+
[0x52, 0x49, 0x46, 0x46, , , , , 0x57, 0x41, 0x56, 0x45]
23+
],
24+
};
725

8-
// https://en.wikipedia.org/wiki/List_of_file_signatures
9-
var fileSignatures = {
10-
'mp3': [
11-
// MPEG-1 Layer 3 file without an ID3 tag or with an ID3v1 tag (which's appended at the end of the file)
12-
[0xFF, 0xFB],
13-
// MP3 file with an ID3v2 container
14-
[0x49, 0x44, 0x33],
15-
// Other MP3 files (FF Fx and FF Ex – they may cause false-positives)
16-
// Headers taken from https://www.garykessler.net/library/file_sigs.html
17-
[0xFF, 0xE0], [0xFF, 0xE1], [0xFF, 0xE2], [0xFF, 0xE3], [0xFF, 0xE4],
18-
[0xFF, 0xE5], [0xFF, 0xE6], [0xFF, 0xE7], [0xFF, 0xE8], [0xFF, 0xE9],
19-
[0xFF, 0xEA], [0xFF, 0xEB], [0xFF, 0xEC], [0xFF, 0xED], [0xFF, 0xEE], [0xFF, 0xEF],
20-
[0xFF, 0xF0], [0xFF, 0xF1], [0xFF, 0xF2], [0xFF, 0xF3], [0xFF, 0xF4],
21-
[0xFF, 0xF5], [0xFF, 0xF6], [0xFF, 0xF7], [0xFF, 0xF8], [0xFF, 0xF9],
22-
[0xFF, 0xFA], [0xFF, 0xFB], [0xFF, 0xFC], [0xFF, 0xFD], [0xFF, 0xFE], [0xFF, 0xFF]
23-
],
24-
'wav': [
25-
// Waveform Audio File Format
26-
// Empty slots can be any byte. Can't look at only first 4 or else .avi files match
27-
[0x52, 0x49, 0x46, 0x46, , , , , 0x57, 0x41, 0x56, 0x45]
28-
],
29-
};
26+
/**
27+
* Compare an Uint8Array with an expected file signature.
28+
* Can't do a direct equality check since some signatures (e.gfor wav files) have wildcard slots.
29+
* @param {array} sig - pattern from fileSignatures
30+
* @param {Uint8Array} actual - bytes from file (should already be sliced to match length of sig)
31+
* @returns {boolean} - do they match
32+
*/
33+
const compareSignature = function(sig, actual) {
34+
if (sig.length !== actual.length) return false;
35+
for (var i = 0, l = sig.length; i < l; i++) {
36+
if (sig[i] !== actual[i] && typeof sig[i] !== 'undefined') return false;
37+
}
38+
return true;
39+
};
3040

31-
/**
32-
* Compare an Uint8Array with an expected file signature.
33-
* Can't do a direct equality check since some signatures (e.gfor wav files) have wildcard slots.
34-
* @param {array} sig - pattern from fileSignatures
35-
* @param {Uint8Array} actual - bytes from file (should already be sliced to match length of sig)
36-
* @returns {boolean} - do they match
37-
*/
38-
var compareSignature = function(sig, actual) {
39-
if (sig.length !== actual.length) return false;
40-
for (var i = 0, l = sig.length; i < l; i++) {
41-
if (sig[i] !== actual[i] && typeof sig[i] !== 'undefined') return false;
42-
}
43-
return true;
44-
};
41+
/**
42+
* @param {Uint8Array} uint8
43+
* @param {string} type
44+
* @returns {boolean}
45+
*/
46+
const matchesFileType = function(uint8, type) {
47+
return fileSignatures[type].find(function(sig) {
48+
return compareSignature(sig, uint8.subarray(0, sig.length));
49+
});
50+
};
4551

46-
/**
47-
* @param {Uint8Array} uint8
48-
* @param {string} type
49-
* @returns {boolean}
50-
*/
51-
var matchesFileType = function(uint8, type) {
52-
return _.find(fileSignatures[type], function(sig) {
53-
return compareSignature(sig, uint8.subarray(0, sig.length));
54-
});
55-
};
56-
57-
/**
58-
* Detect, through file signature / mime sniffing detection, if a given File
59-
* matches an expected type or types. The types supported are the keys in
60-
* fileSignatures above.
61-
* @param {File} file
62-
* @param {(string|string[])} types - e.g. 'mp3' or ['mp3', 'wav']
63-
* @param {function} - callback which is passed a boolean
64-
*/
65-
var verifyFileType = function(file, types, cb) {
66-
if (_.isString(types)) types = [types];
67-
68-
// Calculate the longest file signature for any of the requested
69-
// types, so we know how many bytes of this file to look at.
70-
var bytesNeeded = types.reduce(function(prevMax, type, idx, arr) {
71-
var sigs = fileSignatures[type];
72-
return Math.max.apply(this, [prevMax].concat(sigs.map(function(sig) {
73-
return sig.length;
74-
})));
75-
}, 0);
52+
/**
53+
* Detect, through file signature / mime sniffing detection, if a given File
54+
* matches an expected type or types. The types supported are the keys in
55+
* fileSignatures above.
56+
* @param {File} file
57+
* @param {(string|string[])} types - e.g. 'mp3' or ['mp3', 'wav']
58+
* @param {function} - callback which is passed a boolean
59+
*/
60+
const verifyFileType = function(file, types, cb) {
61+
if (typeof types === 'string') types = [types];
7662

77-
// Load file into ArrayBuffer and see if its first few bytes match
78-
// the signature of any of our requested types. Let callback know.
79-
var reader = new FileReader();
80-
reader.onload = function(e) {
81-
// Load only as many bytes from the array buffer as necessary
82-
var arrayBuffer = e.currentTarget.result;
83-
var bytes = new Uint8Array(arrayBuffer, 0, bytesNeeded);
84-
var match = _.find(types, function(type) {
85-
return matchesFileType(bytes, type);
86-
});
87-
cb(match);
88-
};
89-
reader.readAsArrayBuffer(file);
90-
};
63+
// Calculate the longest file signature for any of the requested
64+
// types, so we know how many bytes of this file to look at.
65+
const bytesNeeded = types.reduce(function(prevMax, type, idx, arr) {
66+
var sigs = fileSignatures[type];
67+
return Math.max.apply(this, [prevMax].concat(sigs.map(function(sig) {
68+
return sig.length;
69+
})));
70+
}, 0);
9171

92-
// Expose public interface
93-
var FileDetector = {
94-
verifyFileType: verifyFileType
95-
};
96-
97-
return FileDetector;
98-
});
72+
// Load file into ArrayBuffer and see if its first few bytes match
73+
// the signature of any of our requested types. Let callback know.
74+
const reader = new FileReader();
75+
reader.addEventListener('load', function(e) {
76+
// Load only as many bytes from the array buffer as necessary
77+
var arrayBuffer = e.currentTarget.result;
78+
var bytes = new Uint8Array(arrayBuffer, 0, bytesNeeded);
79+
var match = _.find(types, function(type) {
80+
return matchesFileType(bytes, type);
81+
});
82+
cb(match);
83+
});
84+
reader.readAsArrayBuffer(file);
85+
};
9986

87+
export { verifyFileType };

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"name": "filevalidator",
3-
"version": "1.0.1",
3+
"version": "2.0.0",
44
"description": "File signature validation in JavaScript",
5+
"type": "module",
56
"main": "filevalidator.js",
67
"author": "Phil Freo <phil@philfreo.com> (http://philfreo.com/)",
78
"license": "MIT"

0 commit comments

Comments
 (0)