@patrickdk77/office-defuse 0.1.1 → 0.2.0
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 +197 -42
- package/dist/cfb-writer.d.ts +25 -0
- package/dist/cfb-writer.js +314 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +357 -0
- package/dist/contained.d.ts +46 -0
- package/dist/contained.js +152 -0
- package/dist/context.d.ts +107 -12
- package/dist/context.js +101 -24
- package/dist/engine.d.ts +12 -1
- package/dist/engine.js +276 -31
- package/dist/errors.d.ts +17 -0
- package/dist/errors.js +27 -1
- package/dist/fields.d.ts +20 -13
- package/dist/fields.js +65 -23
- package/dist/findings.d.ts +2 -1
- package/dist/findings.js +17 -1
- package/dist/flat.d.ts +33 -0
- package/dist/flat.js +486 -0
- package/dist/formats.d.ts +7 -0
- package/dist/formats.js +5 -1
- package/dist/formulas.d.ts +27 -0
- package/dist/formulas.js +157 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +8 -1
- package/dist/index.mjs +1 -1
- package/dist/io.d.ts +62 -1
- package/dist/io.js +245 -1
- package/dist/links.d.ts +27 -0
- package/dist/links.js +106 -1
- package/dist/msg.d.ts +3 -2
- package/dist/msg.js +172 -18
- package/dist/objects.d.ts +8 -5
- package/dist/objects.js +90 -20
- package/dist/odf.d.ts +65 -1
- package/dist/odf.js +181 -64
- package/dist/offcrypto.d.ts +24 -1
- package/dist/offcrypto.js +308 -69
- package/dist/ole.js +17 -5
- package/dist/oleobj.d.ts +11 -0
- package/dist/oleobj.js +20 -3
- package/dist/ooxml.d.ts +81 -0
- package/dist/ooxml.js +342 -81
- package/dist/plan.d.ts +104 -0
- package/dist/plan.js +73 -0
- package/dist/plugins.d.ts +8 -0
- package/dist/plugins.js +60 -0
- package/dist/ppt.js +45 -5
- package/dist/rewrite-cfb.d.ts +14 -0
- package/dist/rewrite-cfb.js +52 -0
- package/dist/rewrite-rtf.d.ts +9 -0
- package/dist/rewrite-rtf.js +45 -0
- package/dist/rewrite-xml.d.ts +36 -0
- package/dist/rewrite-xml.js +341 -0
- package/dist/rewrite-zip.d.ts +8 -0
- package/dist/rewrite-zip.js +498 -0
- package/dist/rtf.js +214 -41
- package/dist/rtfcomp.d.ts +7 -0
- package/dist/rtfcomp.js +80 -0
- package/dist/score.js +1 -1
- package/dist/sniff.d.ts +5 -0
- package/dist/sniff.js +38 -0
- package/dist/types.d.ts +43 -6
- package/dist/types.js +14 -0
- package/dist/vsd.d.ts +13 -0
- package/dist/vsd.js +689 -0
- package/dist/word.js +51 -17
- package/dist/xls.js +38 -4
- package/dist/xml.d.ts +30 -0
- package/dist/xml.js +45 -23
- package/dist/zip-writer.d.ts +4 -0
- package/dist/zip-writer.js +20 -7
- package/dist/zip.d.ts +9 -2
- package/dist/zip.js +61 -4
- package/package.json +4 -1
package/dist/fields.js
CHANGED
|
@@ -10,68 +10,104 @@ const xml_1 = require("./xml");
|
|
|
10
10
|
/** How much of a field code is kept, counted from its first word, which names the field. */
|
|
11
11
|
const MAX_FIELD_CODE = 4096;
|
|
12
12
|
/**
|
|
13
|
-
* Reports a Word field by its code
|
|
14
|
-
* does not say, as one whose name another field builds does.
|
|
13
|
+
* Reports a Word field by its code, and tells whether any of its findings strips it. A field whose name holds the
|
|
14
|
+
* content of an external entity has a type the file does not say, as one whose name another field builds does. A
|
|
15
|
+
* HYPERLINK field's result is the text the reader sees, and goes with its tooltip into the label check.
|
|
15
16
|
*/
|
|
16
|
-
function evaluateField(ctx, location, code, computed) {
|
|
17
|
+
function evaluateField(ctx, location, code, computed, result = '') {
|
|
17
18
|
const data = { code: (0, context_1.clip)(code.trim()) };
|
|
18
19
|
const words = (0, formulas_1.fieldWords)(code);
|
|
19
20
|
const first = words[0]?.text ?? '';
|
|
20
21
|
const entity = (0, xml_1.unknownEntity)(first);
|
|
22
|
+
const actions = [];
|
|
21
23
|
if (computed || entity !== undefined)
|
|
22
|
-
ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Computed, location, entity === undefined ? data : { ...data, entity: (0, context_1.clip)(entity) });
|
|
24
|
+
actions.push(ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Computed, location, entity === undefined ? data : { ...data, entity: (0, context_1.clip)(entity) }).action);
|
|
23
25
|
const name = first.toUpperCase();
|
|
24
26
|
// An argument comes before any switch, and a switch is an unquoted word starting with a backslash.
|
|
25
27
|
const switchAt = words.findIndex(w => !w.quoted && w.text.startsWith('\\'));
|
|
26
28
|
const arg = (n) => (words[n] !== undefined && (switchAt < 0 || n < switchAt) ? words[n].text : undefined);
|
|
27
29
|
if (name === 'DDE' || name === 'DDEAUTO')
|
|
28
|
-
ctx.report(types_1.OfficeCategory.Dde, types_1.OfficeDetail.Field, location, data);
|
|
30
|
+
actions.push(ctx.report(types_1.OfficeCategory.Dde, types_1.OfficeDetail.Field, location, data).action);
|
|
29
31
|
else if (name === 'MACROBUTTON')
|
|
30
|
-
ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Macrobutton, location, { ...data, macro: (0, context_1.clip)(words[1]?.text ?? '') });
|
|
32
|
+
actions.push(ctx.report(types_1.OfficeCategory.Field, types_1.OfficeDetail.Macrobutton, location, { ...data, macro: (0, context_1.clip)(words[1]?.text ?? '') }).action);
|
|
31
33
|
else if (name === 'INCLUDETEXT' || name === 'INCLUDEPICTURE' || name === 'IMPORT' || name === 'LINK') {
|
|
32
34
|
const target = arg(name === 'LINK' ? 2 : 1);
|
|
33
35
|
if (target === undefined)
|
|
34
|
-
ctx.report(types_1.OfficeCategory.External, types_1.OfficeDetail.Include, location, data);
|
|
36
|
+
actions.push(ctx.report(types_1.OfficeCategory.External, types_1.OfficeDetail.Include, location, data).action);
|
|
35
37
|
else
|
|
36
|
-
ctx.external(types_1.OfficeDetail.Include, target, location, data, 'field');
|
|
38
|
+
actions.push(ctx.external(types_1.OfficeDetail.Include, target, location, data, 'field').action);
|
|
37
39
|
}
|
|
38
40
|
else if (name === 'HYPERLINK') {
|
|
39
41
|
const target = arg(1);
|
|
40
|
-
if (target !== undefined && !(0, links_1.isFragment)(target))
|
|
41
|
-
ctx.link(target, location, { ...data, source: 'HYPERLINK field' });
|
|
42
|
+
if (target !== undefined && !(0, links_1.isFragment)(target)) {
|
|
43
|
+
const r = ctx.link(target, location, { ...data, source: 'HYPERLINK field' });
|
|
44
|
+
actions.push(r.action);
|
|
45
|
+
// The \o switch gives the tooltip.
|
|
46
|
+
const tip = words.findIndex(w => !w.quoted && w.text.toLowerCase() === '\\o');
|
|
47
|
+
const labels = [result, tip >= 0 ? words[tip + 1]?.text : undefined];
|
|
48
|
+
if (r.action !== 'strip') {
|
|
49
|
+
const m = ctx.labelMismatch(target, labels, location, { ...data, source: 'HYPERLINK field' });
|
|
50
|
+
if (m)
|
|
51
|
+
actions.push(m.action);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
42
54
|
}
|
|
55
|
+
return actions.includes('strip');
|
|
43
56
|
}
|
|
44
57
|
/**
|
|
45
58
|
* Word field codes, followed through nested fields as the text of a document arrives: a field begins, its code
|
|
46
59
|
* comes, a separator starts its result, and it ends. Each format says where those marks are.
|
|
47
60
|
*/
|
|
61
|
+
/** The most of a field's result that is kept, for the label check. */
|
|
62
|
+
const MAX_RESULT = 4096;
|
|
48
63
|
class FieldStack {
|
|
49
64
|
ctx;
|
|
50
65
|
location;
|
|
66
|
+
onStrip;
|
|
51
67
|
stack = [];
|
|
52
|
-
|
|
68
|
+
/**
|
|
69
|
+
* `onStrip` hears of each field a strip finding names, with the marks the format gave its begin, separator and end,
|
|
70
|
+
* so the rewrite can find the field again.
|
|
71
|
+
*/
|
|
72
|
+
constructor(ctx, location, onStrip) {
|
|
53
73
|
this.ctx = ctx;
|
|
54
74
|
this.location = location;
|
|
75
|
+
this.onStrip = onStrip;
|
|
55
76
|
}
|
|
56
77
|
/** A field starts. One that starts before its parent's code has a word in it makes that code at run time. */
|
|
57
|
-
begin() {
|
|
78
|
+
begin(mark = -1) {
|
|
58
79
|
this.nest();
|
|
59
|
-
this.stack.push({ code: '', inCode: true, computed: false });
|
|
80
|
+
this.stack.push({ code: '', inCode: true, computed: false, marks: { begin: mark, simple: false }, result: '' });
|
|
60
81
|
}
|
|
61
|
-
/** A field
|
|
62
|
-
|
|
82
|
+
/** A field whose code is given whole, such as OOXML's fldSimple, whose result follows until simpleEnd(). */
|
|
83
|
+
simpleBegin(code, mark = -1) {
|
|
63
84
|
this.nest();
|
|
64
|
-
|
|
85
|
+
this.stack.push({ code, inCode: false, computed: false, marks: { begin: mark, simple: true }, result: '' });
|
|
65
86
|
}
|
|
66
|
-
|
|
87
|
+
simpleEnd() {
|
|
67
88
|
const top = this.stack[this.stack.length - 1];
|
|
68
|
-
if (top)
|
|
69
|
-
|
|
89
|
+
if (!top?.marks.simple)
|
|
90
|
+
return;
|
|
91
|
+
this.stack.pop();
|
|
92
|
+
this.decide(top);
|
|
70
93
|
}
|
|
71
|
-
|
|
94
|
+
separate(mark = -1) {
|
|
95
|
+
const top = this.stack[this.stack.length - 1];
|
|
96
|
+
if (!top)
|
|
97
|
+
return;
|
|
98
|
+
top.inCode = false;
|
|
99
|
+
top.marks.separate ??= mark;
|
|
100
|
+
}
|
|
101
|
+
end(mark = -1) {
|
|
72
102
|
const f = this.stack.pop();
|
|
73
|
-
if (f)
|
|
74
|
-
|
|
103
|
+
if (!f)
|
|
104
|
+
return;
|
|
105
|
+
f.marks.end = mark;
|
|
106
|
+
this.decide(f);
|
|
107
|
+
}
|
|
108
|
+
decide(f) {
|
|
109
|
+
if (evaluateField(this.ctx, this.location, f.code, f.computed, f.result))
|
|
110
|
+
this.onStrip?.(f.marks);
|
|
75
111
|
}
|
|
76
112
|
/** Whether a field's code is being read now. */
|
|
77
113
|
get inCode() {
|
|
@@ -83,10 +119,16 @@ class FieldStack {
|
|
|
83
119
|
if (top?.inCode && top.code.length < MAX_FIELD_CODE)
|
|
84
120
|
top.code = top.code ? top.code + t : t.trimStart();
|
|
85
121
|
}
|
|
122
|
+
/** Text of the innermost field's result, the text the reader sees. */
|
|
123
|
+
result(t) {
|
|
124
|
+
const top = this.stack[this.stack.length - 1];
|
|
125
|
+
if (top && !top.inCode && top.result.length < MAX_RESULT)
|
|
126
|
+
top.result += t;
|
|
127
|
+
}
|
|
86
128
|
/** A document can end inside a field. Word still reads the code it has. */
|
|
87
129
|
finish() {
|
|
88
130
|
for (let f = this.stack.pop(); f; f = this.stack.pop())
|
|
89
|
-
|
|
131
|
+
this.decide(f);
|
|
90
132
|
}
|
|
91
133
|
nest() {
|
|
92
134
|
const top = this.stack[this.stack.length - 1];
|
package/dist/findings.d.ts
CHANGED
|
@@ -19,7 +19,8 @@ export declare function allFindingSpecs(): Array<{
|
|
|
19
19
|
export declare class FindingFactory {
|
|
20
20
|
private readonly overrides;
|
|
21
21
|
constructor(overrides?: OfficeActionOverride[]);
|
|
22
|
-
|
|
22
|
+
/** The action of a kind of finding, after the caller's overrides. */
|
|
23
|
+
actionFor(category: C, detail: D): OfficeFindingAction;
|
|
23
24
|
make(category: C, detail: D, location?: string, data?: Record<string, string | number>): OfficeFinding;
|
|
24
25
|
}
|
|
25
26
|
export {};
|
package/dist/findings.js
CHANGED
|
@@ -26,6 +26,7 @@ def(types_1.OfficeCategory.Container, types_1.OfficeDetail.BadExtraField, 'rejec
|
|
|
26
26
|
def(types_1.OfficeCategory.Container, types_1.OfficeDetail.DataError, 'reject', 0, "An entry's data does not match its declared size or checksum<: {name}|>");
|
|
27
27
|
def(types_1.OfficeCategory.Container, types_1.OfficeDetail.LeadingBytes, 'strip', 10, 'Data before the first entry of the archive');
|
|
28
28
|
def(types_1.OfficeCategory.Container, types_1.OfficeDetail.HiddenData, 'strip', 20, 'Data in the file that no entry or stream covers');
|
|
29
|
+
def(types_1.OfficeCategory.Container, types_1.OfficeDetail.HiddenEntry, 'strip', 40, 'A local file header the central directory does not list, which a reader that walks the file in order extracts<: at offset {offset}|>');
|
|
29
30
|
def(types_1.OfficeCategory.Container, types_1.OfficeDetail.TrailingBytes, 'strip', 10, 'Data after the end of the archive or compound file');
|
|
30
31
|
def(types_1.OfficeCategory.Container, types_1.OfficeDetail.BadHeader, 'reject', 0, 'The compound file header is invalid<: {reason}|>');
|
|
31
32
|
def(types_1.OfficeCategory.Container, types_1.OfficeDetail.BrokenChain, 'reject', 0, 'A sector chain of the compound file runs into a free or reserved sector');
|
|
@@ -49,18 +50,20 @@ def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.XmlEntityDepth, 'reject',
|
|
|
49
50
|
def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.XmlEntityExpansions, 'reject', 0, 'The file exceeds the entity expansion limit');
|
|
50
51
|
def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.XmlEntitySize, 'reject', 0, 'The file exceeds the expanded entity size limit');
|
|
51
52
|
def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.RtfDepth, 'reject', 0, 'The RTF file exceeds the group nesting limit');
|
|
53
|
+
def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.NestingDepth, 'reject', 0, 'The file sits deeper in the upload than the nesting limit allows');
|
|
52
54
|
def(types_1.OfficeCategory.Limit, types_1.OfficeDetail.Time, 'reject', 0, 'The file exceeds the time limit');
|
|
53
55
|
// PACKAGE
|
|
54
56
|
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.Unrecognized, 'reject', 0, 'The file is not a recognized Office or OpenDocument file');
|
|
55
57
|
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.AmbiguousFormat, 'reject', 0, 'The file can be read as more than one format');
|
|
56
58
|
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.Unreadable, 'reject', 0, 'The file could not be read');
|
|
59
|
+
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.UnreadableBody, 'strip', 10, "An Outlook message's RTF body does not decompress<: {stream}|>");
|
|
57
60
|
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.DuplicateEntry, 'reject', 0, 'The package names one thing twice, and readers may pick either');
|
|
58
61
|
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.UntypedPart, 'strip', 10, 'A part has no content type<: {part}|>');
|
|
59
62
|
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.UnreferencedPart, 'strip', 0, 'A part nothing in the package refers to<: {part}|>');
|
|
60
63
|
def(types_1.OfficeCategory.Package, types_1.OfficeDetail.OdfLayout, 'strip', 10, 'The OpenDocument package layout is irregular<: {reason}|>');
|
|
61
64
|
// ENCRYPTED
|
|
62
65
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.PasswordRequired, 'reject', 0, 'The document is encrypted with a password');
|
|
63
|
-
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.DefaultPassword, 'strip', 10, 'The file is encrypted with VelvetSweatshop
|
|
66
|
+
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.DefaultPassword, 'strip', 10, 'The file is encrypted with <{password}|VelvetSweatshop>, the password <{application}|Excel> opens it with without asking');
|
|
64
67
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.UserPassword, 'strip', 0, 'The file was decrypted with the supplied password');
|
|
65
68
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Rc4_40, 'info', 0, 'Encryption is RC4 with a 40-bit key');
|
|
66
69
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Rc4_128, 'info', 0, 'Encryption is RC4 with a 128-bit key');
|
|
@@ -68,6 +71,7 @@ def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Rc4Other, 'info', 0,
|
|
|
68
71
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Aes128, 'info', 0, 'Encryption is AES with a 128-bit key');
|
|
69
72
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Aes192, 'info', 0, 'Encryption is AES with a 192-bit key');
|
|
70
73
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.Aes256, 'info', 0, 'Encryption is AES with a 256-bit key');
|
|
74
|
+
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.XorObfuscation, 'info', 0, 'Encryption is XOR obfuscation');
|
|
71
75
|
def(types_1.OfficeCategory.Encrypted, types_1.OfficeDetail.UnsupportedAlgorithm, 'reject', 0, 'The file is encrypted with an algorithm office-defuse does not decrypt<: {algorithm}|>');
|
|
72
76
|
// MACRO
|
|
73
77
|
def(types_1.OfficeCategory.Macro, types_1.OfficeDetail.VbaProject, 'strip', 70, 'The document holds VBA macros');
|
|
@@ -85,6 +89,7 @@ def(types_1.OfficeCategory.Ui, types_1.OfficeDetail.Callback, 'strip', 30, 'The
|
|
|
85
89
|
def(types_1.OfficeCategory.Ui, types_1.OfficeDetail.OdfConfiguration, 'strip', 10, 'The document carries its own menu, toolbar or key settings, which can call macros');
|
|
86
90
|
// ACTION
|
|
87
91
|
def(types_1.OfficeCategory.Action, types_1.OfficeDetail.RunProgram, 'strip', 80, 'A click or hover runs a program or opens a file');
|
|
92
|
+
def(types_1.OfficeCategory.Action, types_1.OfficeDetail.SubmitForm, 'strip', 40, 'A form sends its data to a URL<: {target}|>');
|
|
88
93
|
def(types_1.OfficeCategory.Action, types_1.OfficeDetail.OleVerb, 'strip', 40, 'A click or hover activates an embedded object');
|
|
89
94
|
def(types_1.OfficeCategory.Action, types_1.OfficeDetail.ObjectUpdate, 'strip', 50, 'An embedded object updates itself as the document opens, which starts the program it belongs to');
|
|
90
95
|
// DDE
|
|
@@ -103,6 +108,7 @@ def(types_1.OfficeCategory.External, types_1.OfficeDetail.Include, 'strip', 40,
|
|
|
103
108
|
def(types_1.OfficeCategory.External, types_1.OfficeDetail.Workbook, 'strip', 30, 'Formulas read another workbook at <{target}|another location>');
|
|
104
109
|
def(types_1.OfficeCategory.External, types_1.OfficeDetail.Reload, 'strip', 40, 'The document loads <{target}|another address> on its own after a delay');
|
|
105
110
|
def(types_1.OfficeCategory.External, types_1.OfficeDetail.Other, 'strip', 30, 'The document refers to <{target}|something outside the file>');
|
|
111
|
+
def(types_1.OfficeCategory.External, types_1.OfficeDetail.DataConnection, 'strip', 40, 'A data connection loads from outside the file<: {target}|>');
|
|
106
112
|
def(types_1.OfficeCategory.External, types_1.OfficeDetail.LocalFile, 'strip', 5, 'The document refers to a local file<: {target}|>');
|
|
107
113
|
// LINK
|
|
108
114
|
def(types_1.OfficeCategory.Link, types_1.OfficeDetail.Safe, 'info', 0, 'Web or email link');
|
|
@@ -116,6 +122,9 @@ def(types_1.OfficeCategory.Link, types_1.OfficeDetail.IpHost, 'strip', 40, 'A li
|
|
|
116
122
|
def(types_1.OfficeCategory.Link, types_1.OfficeDetail.LookalikeHost, 'strip', 40, "A link's host uses punycode or mixed scripts");
|
|
117
123
|
def(types_1.OfficeCategory.Link, types_1.OfficeDetail.EncodedHost, 'strip', 40, "A link's host is percent-encoded");
|
|
118
124
|
def(types_1.OfficeCategory.Link, types_1.OfficeDetail.Relative, 'strip', 30, "A relative link, which resolves against the file's own location");
|
|
125
|
+
def(types_1.OfficeCategory.Link, types_1.OfficeDetail.TextMismatch, 'strip', 40, "A link's text or tooltip names a different site than it opens");
|
|
126
|
+
def(types_1.OfficeCategory.External, types_1.OfficeDetail.Formula, 'strip', 40, 'A formula fetches from outside the file when it is calculated<: {function}|>');
|
|
127
|
+
def(types_1.OfficeCategory.Macro, types_1.OfficeDetail.Formula, 'strip', 60, 'A formula runs code outside the file when it is calculated<: {function}|>');
|
|
119
128
|
// EMBEDDED
|
|
120
129
|
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.OleObject, 'strip', 40, 'An embedded OLE object<, which holds the file {fileName}|>');
|
|
121
130
|
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Package, 'strip', 30, 'An embedded document<: {contentType}|>');
|
|
@@ -124,8 +133,14 @@ def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Applet, 'strip', 60, '
|
|
|
124
133
|
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Plugin, 'strip', 50, 'An embedded browser plug-in object');
|
|
125
134
|
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Equation, 'strip', 70, 'An Equation Editor 3.0 object, which CVE-2017-11882 and CVE-2018-0802 exploit');
|
|
126
135
|
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.Attachment, 'strip', 30, '<An attached file "{name}"|An attached file> (<{type}|unknown type>)');
|
|
136
|
+
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginPassed, 'info', 20, 'An embedded file was kept by <plugin {plugin}|a plugin> with nothing removed');
|
|
137
|
+
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginScrubbed, 'info', 10, 'An embedded file was cleaned and kept by <plugin {plugin}|a plugin>');
|
|
138
|
+
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginFailed, 'strip', 0, '<Plugin {plugin}|A plugin> failed, so the embedded file was removed');
|
|
139
|
+
def(types_1.OfficeCategory.Embedded, types_1.OfficeDetail.PluginRemoved, 'strip', 0, 'An embedded file was removed by <plugin {plugin}|a plugin>');
|
|
127
140
|
// CONTROL
|
|
128
141
|
def(types_1.OfficeCategory.Control, types_1.OfficeDetail.ActiveX, 'strip', 50, 'An ActiveX control');
|
|
142
|
+
// PROCESSING
|
|
143
|
+
def(types_1.OfficeCategory.Processing, types_1.OfficeDetail.VerificationFailed, 'reject', 0, 'The defused output did not pass its own inspection, so nothing was written');
|
|
129
144
|
/** The built-in spec for a kind of finding, or undefined for a kind office-defuse does not make, such as one from another package. */
|
|
130
145
|
function findingSpec(category, detail) {
|
|
131
146
|
return specs.get(`${category}/${detail}`);
|
|
@@ -151,6 +166,7 @@ class FindingFactory {
|
|
|
151
166
|
constructor(overrides = []) {
|
|
152
167
|
this.overrides = overrides;
|
|
153
168
|
}
|
|
169
|
+
/** The action of a kind of finding, after the caller's overrides. */
|
|
154
170
|
actionFor(category, detail) {
|
|
155
171
|
const exact = this.overrides.find(o => o.category === category && o.detail === detail);
|
|
156
172
|
if (exact)
|
package/dist/flat.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Output, type RunContext, type RunState } from './context';
|
|
2
|
+
import type { Format } from './formats';
|
|
3
|
+
import type { PackagePlan } from './plan';
|
|
4
|
+
import { type ByteSink, type ByteSource } from './types';
|
|
5
|
+
import { type XmlLimits } from './xml';
|
|
6
|
+
import { type ZipLimits } from './zip';
|
|
7
|
+
/** The namespace of a Flat OPC package, the single-file form of OOXML that Word, Excel and PowerPoint save as XML. */
|
|
8
|
+
export declare const PKG_NS = "http://schemas.microsoft.com/office/2006/xmlPackage";
|
|
9
|
+
/** The name findings give the one part of a flat OpenDocument file. */
|
|
10
|
+
export declare const FLAT_ODF_PART = "office:document";
|
|
11
|
+
/** Flat OPC has no media type of its own, and Office saves it with the .xml extension. */
|
|
12
|
+
export declare const FLAT_OPC_FORMAT: Format;
|
|
13
|
+
/** Whether the first bytes of a file read as XML: a byte order mark, white space and then "<". */
|
|
14
|
+
export declare function startsAsXml(head: Uint8Array): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Whether the start of an XML file names a flat OpenDocument document or a Flat OPC package as its root element. The
|
|
17
|
+
* reading of the whole file decides; this tells a router which package to try.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isFlatHead(text: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Inspects a flat XML file: flat OpenDocument, read with the OpenDocument rules over its one part, or Flat OPC,
|
|
22
|
+
* which is unpacked into a package of its parts and read with the OOXML rules. Returns what the rewrite needs.
|
|
23
|
+
*/
|
|
24
|
+
export declare function inspectFlat(ctx: RunContext, src: ByteSource, size: number, zipLimits: ZipLimits): Promise<Output | undefined>;
|
|
25
|
+
/** Writes a flat OpenDocument file without what the plan removes. */
|
|
26
|
+
export declare function writeFlatOdf(run: RunState, src: ByteSource, plan: PackagePlan, limits: XmlLimits, sink: ByteSink): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Writes a Flat OPC package without what the plan removes: the package is rewritten as any OOXML package is, and its
|
|
29
|
+
* parts are written back into one XML file, each with its name, content type and attributes.
|
|
30
|
+
*/
|
|
31
|
+
export declare function writeFlatOpc(run: RunState, output: Extract<Output, {
|
|
32
|
+
kind: 'flatopc';
|
|
33
|
+
}>, limits: XmlLimits, zipLimits: ZipLimits, sink: ByteSink): Promise<void>;
|