@mitre/inspec-objects 1.0.1 → 2.0.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.
@@ -1,7 +1,127 @@
1
1
  import { DecodedDescription } from '../types/xccdf';
2
- export declare function convertEncodedXmlIntoJson(encodedXml: string): any;
2
+ /**
3
+ * Converts an encoded XML string into a JSON object using specified
4
+ * parsing options.
5
+ *
6
+ * @param encodedXml - The encoded XML string to be converted.
7
+ * @param xmlParserOption - The parsing option to be used. Defaults to
8
+ * 'withArrayOption'.
9
+ * Possible values are:
10
+ * - 'withArrayOption': Parses XML with array option enabled.
11
+ * - 'withArrayNoEntitiesOption': Parses XML with array option
12
+ * enabled and processes entities.
13
+ * - Any other value: Parses XML without array option.
14
+ * @returns The JSON representation of the XML string.
15
+ *
16
+ * @remarks
17
+ * This function uses the `fast-xml-parser` library to parse the XML string.
18
+ * The parser options are configured to:
19
+ * - Prevent the parser from converting XML entities (converting &lt into <)
20
+ * - Ignore attributes, allow or disallows attributes to be parsed
21
+ * - Remove namespace prefixes.
22
+ * - Prefix attribute names with '@_'.
23
+ * - Stop parsing 'div' and 'p' tags.
24
+ * - Treat all nodes as arrays or not
25
+ *
26
+ * Options being used for the XML parser (V4) are:
27
+ * - processEntities: true or false (based on xmlParserOption)
28
+ * - ignoreAttributes: false (allow attributes to be parsed)
29
+ * - removeNSPrefix: true (remove namespace prefixes)
30
+ * - attributeNamePrefix: '@_' (prefix all attribute names with @_)
31
+ * - stopNodes: ["*.pre", "*.p"]
32
+ * - isArray(): true or false (based on xmlParserOption)
33
+ *
34
+ * NOTE: The isArray can specify what tags to always convert into an array, we
35
+ * do not specify specific fields as it could break parsing if future
36
+ * fields are added, we parse all fields as an array.
37
+ *
38
+ * For more details on the parser options, see the documentation for the v4 or v5 version of the library:
39
+ * {@link https://github.com/NaturalIntelligence/fast-xml-parser/tree/master/docs/v4}
40
+ */
41
+ /**
42
+ * Converts an encoded XML string into a JSON object using specified parsing options.
43
+ *
44
+ * @param encodedXml - The encoded XML string to be converted.
45
+ * @param xmlParserOption - The parsing option to be used. Defaults to 'withArrayOption'.
46
+ * Possible values are:
47
+ * - 'withArrayOption': Parses XML with array option enabled.
48
+ * - 'withArrayNoEntitiesOption': Parses XML with array option enabled and processes entities.
49
+ * - Any other value: Parses XML without array option.
50
+ * @returns The JSON object resulting from the XML parsing.
51
+ */
52
+ export declare function convertEncodedXmlIntoJson(encodedXml: string, xmlParserOption?: string): any;
53
+ /**
54
+ * Converts a JSON object into an XML string.
55
+ *
56
+ * @param data - The JSON object to be converted.
57
+ * @returns The XML string representation of the JSON object.
58
+ */
3
59
  export declare function convertJsonIntoXML(data: any): string;
60
+ /**
61
+ * Removes XML special characters from a given string.
62
+ *
63
+ * This function decodes any XML special characters in the input string
64
+ * and returns the decoded result.
65
+ *
66
+ * @param str - The input string containing XML special characters.
67
+ * @returns The decoded string with XML special characters removed.
68
+ */
4
69
  export declare function removeXMLSpecialCharacters(str: string): string;
5
- export declare function severityStringToImpact(string: string, id: string): number;
70
+ /**
71
+ * Removes HTML tags from the given input string.
72
+ *
73
+ * @param input - The string from which HTML tags should be removed.
74
+ * @returns A new string with all HTML tags removed.
75
+ */
76
+ export declare function removeHtmlTags(input: string): string;
77
+ /**
78
+ * Converts a severity string to a numerical impact value.
79
+ *
80
+ * The function matches the input string against various regular expressions
81
+ * to determine the corresponding impact value:
82
+ * - "none", "na", "n/a", "not applicable" (case insensitive) -> 0.0
83
+ * - "low", "category iii", "category 3" (case insensitive) -> 0.3
84
+ * - "medium", "category ii", "category 2" -> 0.5
85
+ * - "high", "category i", "category 1" -> 0.7
86
+ * - "critical", "severe" -> 1.0
87
+ *
88
+ * If no match is found, the default impact value is 0.5.
89
+ *
90
+ * @param string - The severity string to be converted.
91
+ * @returns The numerical impact value corresponding to the severity string.
92
+ */
93
+ export declare function severityStringToImpact(string: string): number;
94
+ /**
95
+ * Converts an impact number to a severity string.
96
+ *
97
+ * @param impact - A number representing the impact, which must be between 0.0 and 1.0 inclusive.
98
+ * @returns A string representing the severity level:
99
+ * - 'critical' for impact >= 0.9
100
+ * - 'high' for impact >= 0.7
101
+ * - 'medium' for impact >= 0.4
102
+ * - 'low' for impact >= 0.1
103
+ * - 'none' for impact < 0.1
104
+ * @throws {Error} If the impact is less than 0.0 or greater than 1.0.
105
+ */
6
106
  export declare function impactNumberToSeverityString(impact: number): string;
107
+ /**
108
+ * Converts an encoded HTML string into a JSON object, handling specific edge
109
+ * cases related to XSS and XML tags.
110
+ *
111
+ * This function performs the following steps:
112
+ * 1. Replaces occurrences of `"&lt;"` with a placeholder to avoid
113
+ * breaking parsing.
114
+ * 2. Parses the patched HTML to extract text chunks.
115
+ * 3. Converts the extracted text chunks into JSON.
116
+ * 4. Cleans the converted JSON by replacing placeholders with the original
117
+ * characters and handling nested objects.
118
+ *
119
+ * Note: This function specifically addresses issues found in certain
120
+ * STIGs (Security Technical Implementation Guides) where XML tags are
121
+ * embedded within text fields.
122
+ *
123
+ * @param encodedHTML - The encoded HTML string to be converted.
124
+ * If not provided, an empty object is returned.
125
+ * @returns A `DecodedDescription` object containing the converted JSON data.
126
+ */
7
127
  export declare function convertEncodedHTMLIntoJson(encodedHTML?: string): DecodedDescription;
@@ -1,51 +1,178 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertEncodedHTMLIntoJson = exports.impactNumberToSeverityString = exports.severityStringToImpact = exports.removeXMLSpecialCharacters = exports.convertJsonIntoXML = exports.convertEncodedXmlIntoJson = void 0;
3
+ exports.convertEncodedXmlIntoJson = convertEncodedXmlIntoJson;
4
+ exports.convertJsonIntoXML = convertJsonIntoXML;
5
+ exports.removeXMLSpecialCharacters = removeXMLSpecialCharacters;
6
+ exports.removeHtmlTags = removeHtmlTags;
7
+ exports.severityStringToImpact = severityStringToImpact;
8
+ exports.impactNumberToSeverityString = impactNumberToSeverityString;
9
+ exports.convertEncodedHTMLIntoJson = convertEncodedHTMLIntoJson;
4
10
  const tslib_1 = require("tslib");
5
- const fast_xml_parser_1 = tslib_1.__importDefault(require("fast-xml-parser"));
11
+ const fast_xml_parser_1 = require("fast-xml-parser");
6
12
  const jstoxml_1 = require("jstoxml");
7
13
  const htmlparser = tslib_1.__importStar(require("htmlparser2"));
8
14
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
9
15
  const he_1 = tslib_1.__importDefault(require("he"));
10
- function convertEncodedXmlIntoJson(encodedXml) {
11
- return fast_xml_parser_1.default.parse(encodedXml, {
16
+ /**
17
+ * Converts an encoded XML string into a JSON object using specified
18
+ * parsing options.
19
+ *
20
+ * @param encodedXml - The encoded XML string to be converted.
21
+ * @param xmlParserOption - The parsing option to be used. Defaults to
22
+ * 'withArrayOption'.
23
+ * Possible values are:
24
+ * - 'withArrayOption': Parses XML with array option enabled.
25
+ * - 'withArrayNoEntitiesOption': Parses XML with array option
26
+ * enabled and processes entities.
27
+ * - Any other value: Parses XML without array option.
28
+ * @returns The JSON representation of the XML string.
29
+ *
30
+ * @remarks
31
+ * This function uses the `fast-xml-parser` library to parse the XML string.
32
+ * The parser options are configured to:
33
+ * - Prevent the parser from converting XML entities (converting &lt into <)
34
+ * - Ignore attributes, allow or disallows attributes to be parsed
35
+ * - Remove namespace prefixes.
36
+ * - Prefix attribute names with '@_'.
37
+ * - Stop parsing 'div' and 'p' tags.
38
+ * - Treat all nodes as arrays or not
39
+ *
40
+ * Options being used for the XML parser (V4) are:
41
+ * - processEntities: true or false (based on xmlParserOption)
42
+ * - ignoreAttributes: false (allow attributes to be parsed)
43
+ * - removeNSPrefix: true (remove namespace prefixes)
44
+ * - attributeNamePrefix: '@_' (prefix all attribute names with @_)
45
+ * - stopNodes: ["*.pre", "*.p"]
46
+ * - isArray(): true or false (based on xmlParserOption)
47
+ *
48
+ * NOTE: The isArray can specify what tags to always convert into an array, we
49
+ * do not specify specific fields as it could break parsing if future
50
+ * fields are added, we parse all fields as an array.
51
+ *
52
+ * For more details on the parser options, see the documentation for the v4 or v5 version of the library:
53
+ * {@link https://github.com/NaturalIntelligence/fast-xml-parser/tree/master/docs/v4}
54
+ */
55
+ /**
56
+ * Converts an encoded XML string into a JSON object using specified parsing options.
57
+ *
58
+ * @param encodedXml - The encoded XML string to be converted.
59
+ * @param xmlParserOption - The parsing option to be used. Defaults to 'withArrayOption'.
60
+ * Possible values are:
61
+ * - 'withArrayOption': Parses XML with array option enabled.
62
+ * - 'withArrayNoEntitiesOption': Parses XML with array option enabled and processes entities.
63
+ * - Any other value: Parses XML without array option.
64
+ * @returns The JSON object resulting from the XML parsing.
65
+ */
66
+ function convertEncodedXmlIntoJson(encodedXml, xmlParserOption = 'withArrayOption') {
67
+ const withArrayOption = {
68
+ processEntities: false,
69
+ ignoreAttributes: false,
70
+ removeNSPrefix: true,
71
+ attributeNamePrefix: '@_',
72
+ stopNodes: ['*.div', '*.p'],
73
+ isArray: () => true,
74
+ };
75
+ const withArrayNoEntitiesOption = {
76
+ processEntities: true,
12
77
  ignoreAttributes: false,
13
- ignoreNameSpace: true,
78
+ removeNSPrefix: true,
14
79
  attributeNamePrefix: '@_',
15
- stopNodes: ['div', 'p'],
16
- arrayMode: true
17
- });
80
+ stopNodes: ['*.div', '*.p'],
81
+ isArray: () => true,
82
+ };
83
+ const noArrayOption = {
84
+ processEntities: false,
85
+ ignoreAttributes: false,
86
+ removeNSPrefix: true,
87
+ attributeNamePrefix: '@_',
88
+ stopNodes: ['*.div', '*.p'],
89
+ isArray: () => false,
90
+ };
91
+ const parser = new fast_xml_parser_1.XMLParser(xmlParserOption === 'withArrayOption'
92
+ ? withArrayOption
93
+ : xmlParserOption === 'withArrayNoEntitiesOption'
94
+ ? withArrayNoEntitiesOption
95
+ : noArrayOption);
96
+ return parser.parse(encodedXml);
18
97
  }
19
- exports.convertEncodedXmlIntoJson = convertEncodedXmlIntoJson;
98
+ /**
99
+ * Converts a JSON object into an XML string.
100
+ *
101
+ * @param data - The JSON object to be converted.
102
+ * @returns The XML string representation of the JSON object.
103
+ */
20
104
  function convertJsonIntoXML(data) {
21
105
  return (0, jstoxml_1.toXML)(data);
22
106
  }
23
- exports.convertJsonIntoXML = convertJsonIntoXML;
107
+ /**
108
+ * Removes XML special characters from a given string.
109
+ *
110
+ * This function decodes any XML special characters in the input string
111
+ * and returns the decoded result.
112
+ *
113
+ * @param str - The input string containing XML special characters.
114
+ * @returns The decoded string with XML special characters removed.
115
+ */
24
116
  function removeXMLSpecialCharacters(str) {
25
- return he_1.default.decode(str);
117
+ const result = he_1.default.decode(str);
118
+ return result;
26
119
  }
27
- exports.removeXMLSpecialCharacters = removeXMLSpecialCharacters;
28
- function severityStringToImpact(string, id) {
120
+ /**
121
+ * Removes HTML tags from the given input string.
122
+ *
123
+ * @param input - The string from which HTML tags should be removed.
124
+ * @returns A new string with all HTML tags removed.
125
+ */
126
+ function removeHtmlTags(input) {
127
+ return input.replace(/<\/?[^>]+(>|$)/g, '');
128
+ }
129
+ /**
130
+ * Converts a severity string to a numerical impact value.
131
+ *
132
+ * The function matches the input string against various regular expressions
133
+ * to determine the corresponding impact value:
134
+ * - "none", "na", "n/a", "not applicable" (case insensitive) -> 0.0
135
+ * - "low", "category iii", "category 3" (case insensitive) -> 0.3
136
+ * - "medium", "category ii", "category 2" -> 0.5
137
+ * - "high", "category i", "category 1" -> 0.7
138
+ * - "critical", "severe" -> 1.0
139
+ *
140
+ * If no match is found, the default impact value is 0.5.
141
+ *
142
+ * @param string - The severity string to be converted.
143
+ * @returns The numerical impact value corresponding to the severity string.
144
+ */
145
+ function severityStringToImpact(string) {
29
146
  var _a, _b, _c, _d, _e;
30
- if ((_a = string.match(/none|na|n\/a|not[\s()*_|]?applicable/i)) === null || _a === void 0 ? void 0 : _a.length) {
147
+ if ((_a = RegExp(/none|na|n\/a|not[\s()*_|]?applicable/i).exec(string)) === null || _a === void 0 ? void 0 : _a.length) {
31
148
  return 0.0;
32
149
  }
33
- if ((_b = string.match(/low|cat(egory)?\s*(iii|3)/i)) === null || _b === void 0 ? void 0 : _b.length) {
150
+ if ((_b = RegExp(/low|cat(egory)?\s*(iii|3)/i).exec(string)) === null || _b === void 0 ? void 0 : _b.length) {
34
151
  return 0.3;
35
152
  }
36
- if ((_c = string.match(/med(ium)?|cat(egory)?\s*(ii|2)/)) === null || _c === void 0 ? void 0 : _c.length) {
153
+ if ((_c = RegExp(/med(ium)?|cat(egory)?\s*(ii|2)/).exec(string)) === null || _c === void 0 ? void 0 : _c.length) {
37
154
  return 0.5;
38
155
  }
39
- if ((_d = string.match(/high|cat(egory)?\s*(i|1)/)) === null || _d === void 0 ? void 0 : _d.length) {
156
+ if ((_d = RegExp(/high|cat(egory)?\s*(i|1)/).exec(string)) === null || _d === void 0 ? void 0 : _d.length) {
40
157
  return 0.7;
41
158
  }
42
- if ((_e = string.match(/crit(ical)?|severe/)) === null || _e === void 0 ? void 0 : _e.length) {
159
+ if ((_e = RegExp(/crit(ical)?|severe/).exec(string)) === null || _e === void 0 ? void 0 : _e.length) {
43
160
  return 1.0;
44
161
  }
45
- console.log(`${string} is not a valid severity value. It should be one of the approved keywords. ${id} will be treated as medium severity`);
46
162
  return 0.5;
47
163
  }
48
- exports.severityStringToImpact = severityStringToImpact;
164
+ /**
165
+ * Converts an impact number to a severity string.
166
+ *
167
+ * @param impact - A number representing the impact, which must be between 0.0 and 1.0 inclusive.
168
+ * @returns A string representing the severity level:
169
+ * - 'critical' for impact >= 0.9
170
+ * - 'high' for impact >= 0.7
171
+ * - 'medium' for impact >= 0.4
172
+ * - 'low' for impact >= 0.1
173
+ * - 'none' for impact < 0.1
174
+ * @throws {Error} If the impact is less than 0.0 or greater than 1.0.
175
+ */
49
176
  function impactNumberToSeverityString(impact) {
50
177
  // Impact must be 0.0 - 1.0
51
178
  if (impact < 0.0 || impact > 1.0) {
@@ -67,7 +194,26 @@ function impactNumberToSeverityString(impact) {
67
194
  return 'none';
68
195
  }
69
196
  }
70
- exports.impactNumberToSeverityString = impactNumberToSeverityString;
197
+ /**
198
+ * Converts an encoded HTML string into a JSON object, handling specific edge
199
+ * cases related to XSS and XML tags.
200
+ *
201
+ * This function performs the following steps:
202
+ * 1. Replaces occurrences of `"&lt;"` with a placeholder to avoid
203
+ * breaking parsing.
204
+ * 2. Parses the patched HTML to extract text chunks.
205
+ * 3. Converts the extracted text chunks into JSON.
206
+ * 4. Cleans the converted JSON by replacing placeholders with the original
207
+ * characters and handling nested objects.
208
+ *
209
+ * Note: This function specifically addresses issues found in certain
210
+ * STIGs (Security Technical Implementation Guides) where XML tags are
211
+ * embedded within text fields.
212
+ *
213
+ * @param encodedHTML - The encoded HTML string to be converted.
214
+ * If not provided, an empty object is returned.
215
+ * @returns A `DecodedDescription` object containing the converted JSON data.
216
+ */
71
217
  function convertEncodedHTMLIntoJson(encodedHTML) {
72
218
  if (encodedHTML) {
73
219
  // Some STIGs regarding XSS put the < character inside of the description which breaks parsing
@@ -80,11 +226,17 @@ function convertEncodedHTMLIntoJson(encodedHTML) {
80
226
  });
81
227
  htmlParser.write(patchedHTML);
82
228
  htmlParser.end();
83
- const converted = convertEncodedXmlIntoJson(xmlChunks.join(''));
229
+ const converted = convertEncodedXmlIntoJson(xmlChunks.join(''), 'noArrayOption');
84
230
  let cleaned = {};
85
- if (typeof converted.VulnDiscussion === 'object') { // Some STIGs have xml tags inside of the actual text which breaks processing, e.g U_ASD_STIG_V5R1_Manual-xccdf.xml and all Oracle Database STIGs
231
+ // Some STIGs have xml tags inside of the actual text which breaks processing,
232
+ // e.g U_ASD_STIG_V5R1_Manual-xccdf.xml and all Oracle Database STIGs
233
+ if (typeof converted.VulnDiscussion === 'object') {
86
234
  let extractedVulnDescription = '';
87
- const remainingFields = lodash_1.default.omit(converted.VulnDiscussion, ['FalsePositives', 'FalseNegatives', 'Documentable', 'Mitigations', 'SeverityOverrideGuidance', 'PotentialImpacts', 'ThirdPartyTools', 'MitigationControl', 'Responsibility', 'IAControls']);
235
+ const remainingFields = lodash_1.default.omit(converted.VulnDiscussion, [
236
+ 'FalsePositives', 'FalseNegatives', 'Documentable', 'Mitigations',
237
+ 'SeverityOverrideGuidance', 'PotentialImpacts', 'ThirdPartyTools',
238
+ 'MitigationControl', 'Responsibility', 'IAControls'
239
+ ]);
88
240
  Object.entries(remainingFields).forEach(([field, value]) => {
89
241
  extractedVulnDescription += `<${field}> ${value}`;
90
242
  });
@@ -114,4 +266,3 @@ function convertEncodedHTMLIntoJson(encodedHTML) {
114
266
  }
115
267
  return {};
116
268
  }
117
- exports.convertEncodedHTMLIntoJson = convertEncodedHTMLIntoJson;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mitre/inspec-objects",
3
- "version": "1.0.1",
3
+ "version": "2.0.1",
4
4
  "description": "Typescript objects for normalizing between InSpec profiles and XCCDF benchmarks",
5
5
  "main": "lib/index.js",
6
6
  "publishConfig": {
@@ -24,36 +24,36 @@
24
24
  },
25
25
  "homepage": "https://github.com/mitre/ts-inspec-objects#readme",
26
26
  "dependencies": {
27
- "@types/flat": "^5.0.2",
27
+ "@types/flat": "5.0.2",
28
28
  "@types/he": "^1.1.2",
29
- "@types/json-diff": "^0.7.0",
29
+ "@types/json-diff": "^1.0.0",
30
30
  "@types/jstoxml": "^2.0.2",
31
31
  "@types/lodash": "^4.14.178",
32
32
  "@types/mustache": "^4.2.0",
33
33
  "@types/pretty": "^2.0.1",
34
- "fast-xml-parser": "^3.1.19",
35
- "flat": "^5.0.2",
34
+ "fast-xml-parser": "^4.5.1",
35
+ "flat": "5.0.2",
36
36
  "he": "^1.2.0",
37
- "htmlparser2": "^7.2.0",
37
+ "htmlparser2": "^10.0.0",
38
38
  "inspecjs": "^2.6.6",
39
- "jest": "^28.1.1",
40
- "json-diff": "^0.9.0",
41
- "jstoxml": "^3.2.3",
39
+ "json-diff": "^1.0.6",
40
+ "jstoxml": "^5.0.2",
42
41
  "lodash": "^4.17.21",
43
42
  "mustache": "^4.2.0",
44
43
  "pretty": "^2.0.0",
45
- "ts-jest": "^28.0.4",
46
- "typescript": "^4.5.5",
47
44
  "winston": "^3.8.1",
48
- "yaml": "^1.10.2"
45
+ "yaml": "^2.3.1"
49
46
  },
50
47
  "devDependencies": {
51
- "@types/jest": "^28.1.1",
52
- "@types/node": "^17.0.18",
53
- "@typescript-eslint/eslint-plugin": "^5.47.0",
54
- "@typescript-eslint/parser": "^5.47.0",
48
+ "@types/jest": "^29.5.12",
49
+ "@types/node": "^22.5.2",
50
+ "@typescript-eslint/eslint-plugin": "^6.4.1",
51
+ "@typescript-eslint/parser": "^6.0.0",
55
52
  "eslint": "^8.30.0",
56
- "tslib": "^2.4.0"
53
+ "jest": "^29.7.0",
54
+ "ts-jest": "^29.1.1",
55
+ "tslib": "^2.4.0",
56
+ "typescript": "^5.2.2"
57
57
  },
58
58
  "jest": {
59
59
  "rootDir": ".",