@streamscloud/kit 0.84.0 → 0.84.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -28,10 +28,11 @@ export declare class FileHelper {
|
|
|
28
28
|
* Checks a file's real type against its declared one. The bytes identify images (PNG, JPEG, WebP, GIF, AVIF, HEIC, SVG),
|
|
29
29
|
* MP4, audio (WAV, MP3, M4A, AAC, FLAC), PDF, DOCX, XLSX, ZIP and fonts (WOFF2, WOFF, TTF, OTF); other formats are typed
|
|
30
30
|
* as declared. An equivalent extension (`.jpeg` for `jpg`) and any member of the declared ISO media container family
|
|
31
|
-
* (`.m4a` holding an `isom` MP4, `.heif` for HEIC) is a match, as is
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* (`.m4a` holding an `isom` MP4, `.heif` for HEIC) is a match, as is a declared ZIP, PNG or font whose header carries its
|
|
32
|
+
* format's signature (any ZIP, APNG, Apple `true` TrueType, WOFF / WOFF2 of any flavor). When the name lacks the right
|
|
33
|
+
* extension, it is appended and the original name stays intact: `photo.jpg` holding a PNG → `photo.jpg.png`. Binary
|
|
34
|
+
* formats read only the head; SVG is looked for only when something is declared, and a markup-looking file is then read
|
|
35
|
+
* whole to confirm an SVG root.
|
|
35
36
|
*/
|
|
36
37
|
static checkType(file: File): Promise<FileTypeCheck>;
|
|
37
38
|
static truncateFileName(fileName: string, maxNameLength: number | null | undefined): string;
|
|
@@ -23,17 +23,19 @@ const CONTENT_DETECTABLE_EXTENSIONS = new Set([
|
|
|
23
23
|
'otf'
|
|
24
24
|
]);
|
|
25
25
|
const PREFERRED_EXTENSIONS = { 'video/quicktime': 'mov', 'audio/mpeg': 'mp3', 'audio/aac': 'aac', 'audio/flac': 'flac' };
|
|
26
|
+
const PREFERRED_TYPES = { flac: 'audio/flac' };
|
|
27
|
+
const typeOf = (extension) => PREFERRED_TYPES[extension] ?? mime.getType(extension);
|
|
26
28
|
const SVG_TYPE = { mime: 'image/svg+xml', extension: 'svg' };
|
|
27
29
|
const ISO_MEDIA_CONTAINERS = [new Set(['mp4', 'm4v', 'm4a', 'm4b', 'mov', '3gp', '3g2', 'f4v']), new Set(['heic', 'heif'])];
|
|
28
|
-
const CONTENT_DETECTABLE_MIMES = new Set([...CONTENT_DETECTABLE_EXTENSIONS, 'svg', ...ISO_MEDIA_CONTAINERS.flatMap((family) => [...family])].map(
|
|
30
|
+
const CONTENT_DETECTABLE_MIMES = new Set([...CONTENT_DETECTABLE_EXTENSIONS, 'svg', ...ISO_MEDIA_CONTAINERS.flatMap((family) => [...family])].map(typeOf));
|
|
29
31
|
const sameFormat = (extensionA, extensionB) => {
|
|
30
|
-
const type =
|
|
31
|
-
return type !== null && type ===
|
|
32
|
+
const type = typeOf(extensionA);
|
|
33
|
+
return type !== null && type === typeOf(extensionB);
|
|
32
34
|
};
|
|
33
35
|
const sameContainer = (extensionA, extensionB) => ISO_MEDIA_CONTAINERS.some((family) => family.has(extensionA) && family.has(extensionB));
|
|
34
36
|
const declaredType = (file) => {
|
|
35
37
|
const extension = FileHelper.getFileExtension(file.name).toLowerCase();
|
|
36
|
-
const fromName = extension ?
|
|
38
|
+
const fromName = extension ? typeOf(extension) : null;
|
|
37
39
|
if (fromName) {
|
|
38
40
|
return { mime: fromName, extension, fromName: true };
|
|
39
41
|
}
|
|
@@ -47,9 +49,28 @@ const startsWithMarkup = async (blob) => {
|
|
|
47
49
|
return head.trimStart().startsWith('<');
|
|
48
50
|
};
|
|
49
51
|
const isSvgDocument = async (blob) => (await startsWithMarkup(blob)) && HtmlHelper.sanitizeSvg(await blob.text()) !== null;
|
|
50
|
-
const
|
|
52
|
+
const DECLARED_SIGNATURES = {
|
|
53
|
+
zip: [[0x50, 0x4b, 0x03, 0x04]],
|
|
54
|
+
png: [[0x89, 0x50, 0x4e, 0x47]],
|
|
55
|
+
ttf: [
|
|
56
|
+
[0x00, 0x01, 0x00, 0x00],
|
|
57
|
+
[0x74, 0x72, 0x75, 0x65]
|
|
58
|
+
],
|
|
59
|
+
otf: [[0x4f, 0x54, 0x54, 0x4f]],
|
|
60
|
+
woff: [[0x77, 0x4f, 0x46, 0x46]],
|
|
61
|
+
woff2: [[0x77, 0x4f, 0x46, 0x32]]
|
|
62
|
+
};
|
|
63
|
+
const SIGNATURE_BYTES = 4;
|
|
64
|
+
const hasDeclaredSignature = async (blob, extension) => {
|
|
65
|
+
const signatures = DECLARED_SIGNATURES[extension];
|
|
66
|
+
if (!signatures) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const head = new Uint8Array(await blob.slice(0, SIGNATURE_BYTES).arrayBuffer());
|
|
70
|
+
return signatures.some((signature) => signature.every((byte, index) => head[index] === byte));
|
|
71
|
+
};
|
|
51
72
|
const contentType = async (blob, declared) => {
|
|
52
|
-
if (declared
|
|
73
|
+
if (declared && (await hasDeclaredSignature(blob, declared.extension))) {
|
|
53
74
|
return declared;
|
|
54
75
|
}
|
|
55
76
|
const { fileTypeFromBlob } = await import('file-type');
|
|
@@ -57,7 +78,7 @@ const contentType = async (blob, declared) => {
|
|
|
57
78
|
if (detected && declared && sameContainer(detected.ext, declared.extension)) {
|
|
58
79
|
return declared;
|
|
59
80
|
}
|
|
60
|
-
const detectedMime = detected && CONTENT_DETECTABLE_EXTENSIONS.has(detected.ext) ?
|
|
81
|
+
const detectedMime = detected && CONTENT_DETECTABLE_EXTENSIONS.has(detected.ext) ? typeOf(detected.ext) : null;
|
|
61
82
|
if (detected && detectedMime) {
|
|
62
83
|
return { mime: detectedMime, extension: detected.ext };
|
|
63
84
|
}
|
|
@@ -83,10 +104,11 @@ export class FileHelper {
|
|
|
83
104
|
* Checks a file's real type against its declared one. The bytes identify images (PNG, JPEG, WebP, GIF, AVIF, HEIC, SVG),
|
|
84
105
|
* MP4, audio (WAV, MP3, M4A, AAC, FLAC), PDF, DOCX, XLSX, ZIP and fonts (WOFF2, WOFF, TTF, OTF); other formats are typed
|
|
85
106
|
* as declared. An equivalent extension (`.jpeg` for `jpg`) and any member of the declared ISO media container family
|
|
86
|
-
* (`.m4a` holding an `isom` MP4, `.heif` for HEIC) is a match, as is
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
107
|
+
* (`.m4a` holding an `isom` MP4, `.heif` for HEIC) is a match, as is a declared ZIP, PNG or font whose header carries its
|
|
108
|
+
* format's signature (any ZIP, APNG, Apple `true` TrueType, WOFF / WOFF2 of any flavor). When the name lacks the right
|
|
109
|
+
* extension, it is appended and the original name stays intact: `photo.jpg` holding a PNG → `photo.jpg.png`. Binary
|
|
110
|
+
* formats read only the head; SVG is looked for only when something is declared, and a markup-looking file is then read
|
|
111
|
+
* whole to confirm an SVG root.
|
|
90
112
|
*/
|
|
91
113
|
static async checkType(file) {
|
|
92
114
|
const declared = declaredType(file);
|
|
@@ -101,7 +123,7 @@ export class FileHelper {
|
|
|
101
123
|
if (!declared) {
|
|
102
124
|
return { status: 'unknown' };
|
|
103
125
|
}
|
|
104
|
-
if (CONTENT_DETECTABLE_MIMES.has(
|
|
126
|
+
if (CONTENT_DETECTABLE_MIMES.has(typeOf(declared.extension))) {
|
|
105
127
|
return { status: 'contradicted', declaredExtension: declared.extension };
|
|
106
128
|
}
|
|
107
129
|
return { status: 'unverifiable', file: retyped(file, declared.fromName ? file.name : appended(declared.extension), declared.mime) };
|