@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 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);
@@ -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
- if (drops.has(k) || sheets.has(k) || plan.replace.has(k) || !(0, ooxml_1.isXmlType)(p.contentType) || (!removed && !own && !xpsDrops))
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
- const ok = this.encoding === 'utf-8' ? declared === 'utf-8' || declared === 'utf8' : declared === 'utf-16' || declared === this.encoding;
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.1",
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",