@patrickdk77/office-defuse 0.2.1 → 0.2.2
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/README.md +1 -1
- package/dist/ooxml.js +6 -0
- package/dist/rewrite-zip.js +2 -1
- package/dist/xml.d.ts +3 -0
- package/dist/xml.js +19 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -292,7 +292,7 @@ A writer that streams an entry sets the data descriptor flag and may leave the l
|
|
|
292
292
|
|
|
293
293
|
The XML tokenizer reads each part in pieces. It refuses these, and stops the run:
|
|
294
294
|
|
|
295
|
-
- XML/ENCODING: anything but UTF-8 or UTF-16, the two encodings OPC allows, an encoding declaration that disagrees with the bytes, and bytes that are not valid in their encoding.
|
|
295
|
+
- XML/ENCODING: anything but UTF-8 or UTF-16, the two encodings OPC allows, an encoding declaration that disagrees with the bytes, and bytes that are not valid in their encoding. A declaration of us-ascii agrees with UTF-8 bytes as long as every byte is ASCII, since both read them the same. SharePoint writes such declarations into custom XML parts.
|
|
296
296
|
- XML/MALFORMED: markup that breaks XML 1.0 or its namespaces. That covers an undeclared prefix, a duplicate attribute, a mismatched end tag, an element or text outside the root, a malformed name, reference or declaration, and characters XML 1.0 forbids. It also covers what XML 1.0 refuses about entities: a reference to an entity nothing declares, a reference to an external entity in an attribute value, entity text that refers to itself or leaves an element open, and a markup declaration outside the document type declaration.
|
|
297
297
|
|
|
298
298
|
References get expanded and line ends normalized as the XML specification says, so `DDEAUTO` reads as `DDEAUTO`.
|
package/dist/ooxml.js
CHANGED
|
@@ -597,6 +597,8 @@ async function readMain(ctx, { parts, relsOf }, each) {
|
|
|
597
597
|
async function nameOoxml(ctx, contentTypes) {
|
|
598
598
|
return (await readMain(ctx, await readParts(ctx, contentTypes))).format;
|
|
599
599
|
}
|
|
600
|
+
/** The content type of an add-in's presentation part, which PowerPoint writes empty. */
|
|
601
|
+
const PPAM_MAIN = 'application/vnd.ms-powerpoint.addin.macroenabled.main+xml';
|
|
600
602
|
/**
|
|
601
603
|
* Inspects an OOXML package. The package relationships come first, since they name the main part and so the format.
|
|
602
604
|
* Then each part is read in archive order, followed by its relationships, which are reported as they are read and
|
|
@@ -650,6 +652,10 @@ async function inspectOoxml(ctx, contentTypes, outer) {
|
|
|
650
652
|
plan.drop.add(key);
|
|
651
653
|
p.ole = await ctx.drain(p.entry);
|
|
652
654
|
}
|
|
655
|
+
else if (format.format === 'ppam' && p.entry.size === 0 && ct.toLowerCase() === PPAM_MAIN) {
|
|
656
|
+
// PowerPoint writes an add-in's presentation part empty, since an add-in has no slides.
|
|
657
|
+
await ctx.drain(p.entry);
|
|
658
|
+
}
|
|
653
659
|
else if ((0, exports.isXmlType)(ct)) {
|
|
654
660
|
const rules = new PartRules(ctx, p.entry.name);
|
|
655
661
|
await ctx.parse(p.entry, rules, ct === exports.TYPE.vml);
|
package/dist/rewrite-zip.js
CHANGED
|
@@ -281,7 +281,8 @@ async function writeOoxml(run, zip, plan, graph, format, limits, sink) {
|
|
|
281
281
|
for (const [k, p] of graph.parts) {
|
|
282
282
|
const removed = removedIds.get(k);
|
|
283
283
|
const own = plan.parts.get(p.entry.name);
|
|
284
|
-
|
|
284
|
+
// An empty part, such as the presentation part PowerPoint writes into an add-in, refers to nothing.
|
|
285
|
+
if (drops.has(k) || sheets.has(k) || plan.replace.has(k) || !(0, ooxml_1.isXmlType)(p.contentType) || p.entry.size === 0 || (!removed && !own && !xpsDrops))
|
|
285
286
|
continue;
|
|
286
287
|
const rules = {
|
|
287
288
|
element(el) {
|
package/dist/xml.d.ts
CHANGED
|
@@ -159,6 +159,9 @@ export declare class XmlTokenizer {
|
|
|
159
159
|
/** The XML declaration says standalone="yes". */
|
|
160
160
|
private standalone;
|
|
161
161
|
private encoding;
|
|
162
|
+
/** Set by a declaration of US-ASCII, which agrees with UTF-8 only while every byte is ASCII. */
|
|
163
|
+
private asciiDeclared;
|
|
164
|
+
private nonAscii;
|
|
162
165
|
/** Start tags read so far, which numbers the elements. */
|
|
163
166
|
private elements;
|
|
164
167
|
/** An attribute value of the tag being read referred to an entity of the internal subset. */
|
package/dist/xml.js
CHANGED
|
@@ -190,6 +190,9 @@ class XmlTokenizer {
|
|
|
190
190
|
/** The XML declaration says standalone="yes". */
|
|
191
191
|
standalone = false;
|
|
192
192
|
encoding = 'utf-8';
|
|
193
|
+
/** Set by a declaration of US-ASCII, which agrees with UTF-8 only while every byte is ASCII. */
|
|
194
|
+
asciiDeclared = false;
|
|
195
|
+
nonAscii = false;
|
|
193
196
|
/** Start tags read so far, which numbers the elements. */
|
|
194
197
|
elements = 0;
|
|
195
198
|
/** An attribute value of the tag being read referred to an entity of the internal subset. */
|
|
@@ -263,6 +266,14 @@ class XmlTokenizer {
|
|
|
263
266
|
return decoder;
|
|
264
267
|
}
|
|
265
268
|
decode(decoder, bytes, more) {
|
|
269
|
+
if (!this.nonAscii)
|
|
270
|
+
for (const c of bytes)
|
|
271
|
+
if (c >= 0x80) {
|
|
272
|
+
this.nonAscii = true;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
if (this.asciiDeclared && this.nonAscii)
|
|
276
|
+
this.stop(types_1.OfficeDetail.Encoding, 'The declaration says us-ascii, the bytes are not all ASCII');
|
|
266
277
|
try {
|
|
267
278
|
return decoder.decode(bytes, { stream: more });
|
|
268
279
|
}
|
|
@@ -279,9 +290,16 @@ class XmlTokenizer {
|
|
|
279
290
|
const declared = /\bencoding\s*=\s*(["'])([^"']*)\1/.exec(body)?.[2]?.toLowerCase();
|
|
280
291
|
if (declared === undefined)
|
|
281
292
|
return;
|
|
282
|
-
|
|
293
|
+
// SharePoint declares us-ascii on the custom XML it writes. ASCII bytes read the same in UTF-8.
|
|
294
|
+
const ascii = this.encoding === 'utf-8' && (declared === 'us-ascii' || declared === 'ascii');
|
|
295
|
+
const ok = this.encoding === 'utf-8' ? declared === 'utf-8' || declared === 'utf8' || ascii : declared === 'utf-16' || declared === this.encoding;
|
|
283
296
|
if (!ok)
|
|
284
297
|
this.stop(types_1.OfficeDetail.Encoding, `The declaration says ${declared}, the bytes are ${this.encoding.toUpperCase()}`);
|
|
298
|
+
if (ascii) {
|
|
299
|
+
this.asciiDeclared = true;
|
|
300
|
+
if (this.nonAscii)
|
|
301
|
+
this.stop(types_1.OfficeDetail.Encoding, 'The declaration says us-ascii, the bytes are not all ASCII');
|
|
302
|
+
}
|
|
285
303
|
}
|
|
286
304
|
feed(text, final) {
|
|
287
305
|
this.buf = this.pos < this.buf.length ? this.buf.slice(this.pos) + text : text;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patrickdk77/office-defuse",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Inspect Office and OpenDocument files for VBA and Excel 4.0 macros, LibreOffice Basic and scripts, DDE, external templates and links, embedded OLE objects and ActiveX controls, and score the risk. Strict ZIP and XML readers, bounded memory, no runtime dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "patrickdk77",
|