nuxt-og-image 7.0.4 → 7.0.6
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.
package/dist/module.json
CHANGED
|
@@ -16,6 +16,7 @@ export type FontBinaryResult = {
|
|
|
16
16
|
export declare function isWoff2Binary(source: BufferSource): boolean;
|
|
17
17
|
/**
|
|
18
18
|
* Parse loaded font bytes into a binary that every Takumi build accepts.
|
|
19
|
-
* TTF, OTF
|
|
19
|
+
* Check TTF, OTF and collection table bounds, plus WOFF2 header and file length.
|
|
20
|
+
* Accepted bytes pass through; WOFF inflates to TTF or OTF.
|
|
20
21
|
*/
|
|
21
22
|
export declare function parseFontBinary(source: BufferSource): Promise<FontBinaryResult>;
|
|
@@ -2,6 +2,9 @@ const WOFF_HEADER_SIZE = 44;
|
|
|
2
2
|
const WOFF_TABLE_ENTRY_SIZE = 20;
|
|
3
3
|
const SFNT_TABLE_RECORD_SIZE = 16;
|
|
4
4
|
const MAX_SFNT_SIZE = 64 * 1024 * 1024;
|
|
5
|
+
function alignTableSize(size) {
|
|
6
|
+
return Math.ceil(size / 4) * 4;
|
|
7
|
+
}
|
|
5
8
|
const SIGNATURES = {
|
|
6
9
|
truetype: 65536,
|
|
7
10
|
appleTrueType: 1953658213,
|
|
@@ -25,6 +28,61 @@ function readSignature(data) {
|
|
|
25
28
|
return void 0;
|
|
26
29
|
return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0);
|
|
27
30
|
}
|
|
31
|
+
function sfntError(data, offset = 0) {
|
|
32
|
+
if (offset + 12 > data.byteLength)
|
|
33
|
+
return "the SFNT header is truncated";
|
|
34
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
35
|
+
const signature = view.getUint32(offset);
|
|
36
|
+
if (signature !== SIGNATURES.truetype && signature !== SIGNATURES.appleTrueType && signature !== SIGNATURES.openType)
|
|
37
|
+
return "the SFNT signature is invalid";
|
|
38
|
+
const numTables = view.getUint16(offset + 4);
|
|
39
|
+
if (numTables === 0)
|
|
40
|
+
return "the SFNT file has no tables";
|
|
41
|
+
if (offset + 12 + numTables * SFNT_TABLE_RECORD_SIZE > data.byteLength)
|
|
42
|
+
return "the SFNT table directory is truncated";
|
|
43
|
+
for (let index = 0; index < numTables; index++) {
|
|
44
|
+
const record = offset + 12 + index * SFNT_TABLE_RECORD_SIZE;
|
|
45
|
+
if (view.getUint32(record + 8) + view.getUint32(record + 12) > data.byteLength)
|
|
46
|
+
return "an SFNT table runs past the end of the file";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function collectionError(data) {
|
|
50
|
+
if (data.byteLength < 12)
|
|
51
|
+
return "the font collection header is truncated";
|
|
52
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
53
|
+
const version = view.getUint32(4);
|
|
54
|
+
if (version !== 65536 && version !== 131072)
|
|
55
|
+
return "the font collection version is invalid";
|
|
56
|
+
const numFonts = view.getUint32(8);
|
|
57
|
+
if (numFonts === 0)
|
|
58
|
+
return "the font collection has no fonts";
|
|
59
|
+
const headerSize = 12 + numFonts * 4 + (version === 131072 ? 12 : 0);
|
|
60
|
+
if (headerSize > data.byteLength)
|
|
61
|
+
return "the font collection directory is truncated";
|
|
62
|
+
for (let index = 0; index < numFonts; index++) {
|
|
63
|
+
const offset = view.getUint32(12 + index * 4);
|
|
64
|
+
if (offset < headerSize)
|
|
65
|
+
return "a font collection offset overlaps its header";
|
|
66
|
+
const error = sfntError(data, offset);
|
|
67
|
+
if (error)
|
|
68
|
+
return error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function woff2Error(data) {
|
|
72
|
+
if (data.byteLength < 48)
|
|
73
|
+
return "the WOFF2 header is truncated";
|
|
74
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
75
|
+
if (view.getUint32(8) !== data.byteLength)
|
|
76
|
+
return "the WOFF2 length does not match the file";
|
|
77
|
+
if (view.getUint16(12) === 0)
|
|
78
|
+
return "the WOFF2 file has no tables";
|
|
79
|
+
const compressedSize = view.getUint32(20);
|
|
80
|
+
if (compressedSize === 0 || compressedSize > data.byteLength - 48)
|
|
81
|
+
return "the WOFF2 compressed data is missing or truncated";
|
|
82
|
+
}
|
|
83
|
+
function checked(data, error) {
|
|
84
|
+
return error ? { _tag: "Err", reason: error } : { _tag: "Ok", data };
|
|
85
|
+
}
|
|
28
86
|
async function inflate(data, size) {
|
|
29
87
|
const output = new Uint8Array(size);
|
|
30
88
|
const reader = new Blob([data]).stream().pipeThrough(new DecompressionStream("deflate")).getReader();
|
|
@@ -71,10 +129,10 @@ async function decodeWoff(woff) {
|
|
|
71
129
|
throw new Error("a WOFF table runs past the end of the file");
|
|
72
130
|
if (table.compLength > table.origLength)
|
|
73
131
|
throw new Error("a WOFF table is larger than its decoded size");
|
|
74
|
-
sfntSize += table.origLength
|
|
132
|
+
sfntSize += alignTableSize(table.origLength);
|
|
133
|
+
if (sfntSize > MAX_SFNT_SIZE)
|
|
134
|
+
throw new Error(`the decoded font exceeds ${MAX_SFNT_SIZE} bytes`);
|
|
75
135
|
}
|
|
76
|
-
if (sfntSize > MAX_SFNT_SIZE)
|
|
77
|
-
throw new Error(`the decoded font exceeds ${MAX_SFNT_SIZE} bytes`);
|
|
78
136
|
const tableData = await Promise.all(tables.map((table) => {
|
|
79
137
|
const stored = woff.subarray(table.offset, table.offset + table.compLength);
|
|
80
138
|
return table.compLength < table.origLength ? inflate(stored, table.origLength) : stored;
|
|
@@ -96,7 +154,7 @@ async function decodeWoff(woff) {
|
|
|
96
154
|
out.setUint32(record + 8, offset);
|
|
97
155
|
out.setUint32(record + 12, table.origLength);
|
|
98
156
|
sfnt.set(tableData[index], offset);
|
|
99
|
-
offset += table.origLength
|
|
157
|
+
offset += alignTableSize(table.origLength);
|
|
100
158
|
});
|
|
101
159
|
return sfnt;
|
|
102
160
|
}
|
|
@@ -109,12 +167,14 @@ export async function parseFontBinary(source) {
|
|
|
109
167
|
case SIGNATURES.truetype:
|
|
110
168
|
case SIGNATURES.appleTrueType:
|
|
111
169
|
case SIGNATURES.openType:
|
|
170
|
+
return checked(data, sfntError(data));
|
|
112
171
|
case SIGNATURES.collection:
|
|
172
|
+
return checked(data, collectionError(data));
|
|
113
173
|
case SIGNATURES.woff2:
|
|
114
|
-
return
|
|
174
|
+
return checked(data, woff2Error(data));
|
|
115
175
|
case SIGNATURES.woff:
|
|
116
176
|
return decodeWoff(data).then(
|
|
117
|
-
(sfnt) => (
|
|
177
|
+
(sfnt) => checked(sfnt, sfntError(sfnt)),
|
|
118
178
|
(error) => ({ _tag: "Err", reason: `it is a WOFF file that could not be decoded: ${error.message}` })
|
|
119
179
|
);
|
|
120
180
|
default:
|