@mitre/inspec-objects 0.0.3 → 0.0.4
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/lib/parsers/xccdf.js +1 -1
- package/mitre-inspec-objects-v0.0.1.tgz +0 -0
- package/mitre-inspec-objects-v0.0.3.tgz +0 -0
- package/package.json +1 -1
- package/lib/utilities/CciNistMappingData.d.ts +0 -5100
- package/lib/utilities/CciNistMappingData.js +0 -5103
- package/src/index.ts +0 -5
- package/src/mappings/CciNistMappingData.ts +0 -5100
- package/src/objects/control.ts +0 -148
- package/src/objects/profile.ts +0 -93
- package/src/parsers/json.ts +0 -92
- package/src/parsers/oval.ts +0 -18
- package/src/parsers/xccdf.ts +0 -252
- package/src/types/diff.d.ts +0 -9
- package/src/types/oval.d.ts +0 -609
- package/src/types/xccdf.d.ts +0 -883
- package/src/utilities/diff.ts +0 -71
- package/src/utilities/global.ts +0 -52
- package/src/utilities/xccdf.ts +0 -119
package/src/utilities/diff.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { diff } from 'json-diff';
|
|
2
|
-
import Profile from '../objects/profile';
|
|
3
|
-
import { ProfileDiff } from '../types/diff';
|
|
4
|
-
import _ from 'lodash'
|
|
5
|
-
|
|
6
|
-
export function removeNewlines(control?: Record<string, unknown>): Record<string, unknown> {
|
|
7
|
-
if (!control) {
|
|
8
|
-
return {};
|
|
9
|
-
}
|
|
10
|
-
return _.mapValues(control, (value) => {
|
|
11
|
-
if (typeof value === 'string') {
|
|
12
|
-
return value.replace(/\n/g, '{{{{newlineHERE}}}}').trim();
|
|
13
|
-
} else if (typeof value === 'object' && value !== null) {
|
|
14
|
-
return removeNewlines(value as Record<string, unknown>);
|
|
15
|
-
}
|
|
16
|
-
return value;
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function diffProfile(fromProfile: Profile, toProfile: Profile): ProfileDiff {
|
|
21
|
-
const profileDiff: ProfileDiff = {
|
|
22
|
-
addedControlIDs: [],
|
|
23
|
-
removedControlIDs: [],
|
|
24
|
-
changedControls: {}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const fromControlIDs = fromProfile.controls.map((control) => control.id).sort();
|
|
28
|
-
const toControlIDs = toProfile.controls.map((control) => control.id).sort();
|
|
29
|
-
|
|
30
|
-
// Find new controls
|
|
31
|
-
const controlIDDiff: string[][] | undefined = diff(fromControlIDs, toControlIDs)
|
|
32
|
-
|
|
33
|
-
controlIDDiff?.forEach((diffValue) => {
|
|
34
|
-
if (diffValue[0] === '-') {
|
|
35
|
-
profileDiff.removedControlIDs.push(diffValue[1])
|
|
36
|
-
} else if (diffValue[0] === '+') {
|
|
37
|
-
profileDiff.addedControlIDs.push(diffValue[1])
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
// Add new controls to changedControls
|
|
42
|
-
profileDiff.addedControlIDs.forEach((addedControl) => {
|
|
43
|
-
const newControl = toProfile.controls.find((control) => addedControl === control.id)
|
|
44
|
-
if (newControl) {
|
|
45
|
-
profileDiff.changedControls[addedControl] = newControl
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
// Find changed controls
|
|
50
|
-
for (const fromControl of fromProfile.controls) {
|
|
51
|
-
const toControl = toProfile.controls.find((control) => control.id === fromControl.id)
|
|
52
|
-
if (toControl) {
|
|
53
|
-
const controlDiff: Record<string, any> | undefined = diff(fromControl, toControl);
|
|
54
|
-
console.log(controlDiff)
|
|
55
|
-
if (controlDiff) {
|
|
56
|
-
Object.entries(controlDiff).forEach(([key, value]) => {
|
|
57
|
-
console.log(value)
|
|
58
|
-
if (_.has(value, '__new')) {
|
|
59
|
-
_.set(profileDiff, 'changedControls.'+fromControl.id +'.'+key.replace('.', '\\.'), _.get(controlDiff, key+'.__new'))
|
|
60
|
-
} else if (typeof value === 'object') {
|
|
61
|
-
Object.entries(value).forEach(([subKey]) => {
|
|
62
|
-
_.set(profileDiff, 'changedControls.'+fromControl.id +'.'+key.replace('.', '\\.')+'.'+subKey.replace('.', '\\.'), _.get(controlDiff, key+'.'+subKey+'.__new'))
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return profileDiff
|
|
71
|
-
}
|
package/src/utilities/global.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import _ from "lodash";
|
|
2
|
-
|
|
3
|
-
// Breaks lines down to lineLength number of characters
|
|
4
|
-
export function wrap(s: string, lineLength = 80): string {
|
|
5
|
-
return s.replace(
|
|
6
|
-
new RegExp(`(?![^\n]{1,${lineLength}}$)([^\n]{1,${lineLength}})`, "g"),
|
|
7
|
-
"$1\n"
|
|
8
|
-
);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function unformatText(s: string): string {
|
|
12
|
-
return s.replace(/\n/g, ' ').replace(/\\n/g, ' ').replace(/( +|\t)/g, ' ')
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const escapeQuotes = (s: string) =>
|
|
16
|
-
s.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); // Escape backslashes and quotes
|
|
17
|
-
const escapeDoubleQuotes = (s: string) =>
|
|
18
|
-
s.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); // Escape backslashes and double quotes
|
|
19
|
-
|
|
20
|
-
const wrapAndEscapeQuotes = (s: string, lineLength?: number) =>
|
|
21
|
-
escapeDoubleQuotes(wrap(s, lineLength)); // Escape backslashes and quotes, and wrap long lines
|
|
22
|
-
|
|
23
|
-
export { escapeQuotes, escapeDoubleQuotes, wrapAndEscapeQuotes };
|
|
24
|
-
|
|
25
|
-
export function getFirstPath(
|
|
26
|
-
object: Record<string, unknown>,
|
|
27
|
-
paths: string[]
|
|
28
|
-
): string {
|
|
29
|
-
const index = _.findIndex(paths, (p) => hasPath(object, p));
|
|
30
|
-
|
|
31
|
-
if (index === -1) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
`Attestation is missing one of these paths: ${paths.join(', ')}`
|
|
34
|
-
);
|
|
35
|
-
} else {
|
|
36
|
-
return _.get(object, paths[index]) as string;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function hasPath(
|
|
41
|
-
file: Record<string, unknown>,
|
|
42
|
-
path: string | string[]
|
|
43
|
-
): boolean {
|
|
44
|
-
let pathArray;
|
|
45
|
-
if (typeof path === 'string') {
|
|
46
|
-
pathArray = [path];
|
|
47
|
-
} else {
|
|
48
|
-
pathArray = path;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return _.some(pathArray, (p) => _.has(file, p));
|
|
52
|
-
}
|
package/src/utilities/xccdf.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import parser from 'fast-xml-parser'
|
|
2
|
-
import * as htmlparser from 'htmlparser2'
|
|
3
|
-
import _ from 'lodash'
|
|
4
|
-
import { DecodedDescription } from '../types/xccdf'
|
|
5
|
-
import fs from 'fs'
|
|
6
|
-
import { randomUUID } from 'crypto'
|
|
7
|
-
|
|
8
|
-
export function convertEncodedXmlIntoJson(
|
|
9
|
-
encodedXml: string
|
|
10
|
-
): any {
|
|
11
|
-
return parser.parse(encodedXml, {
|
|
12
|
-
ignoreAttributes: false,
|
|
13
|
-
ignoreNameSpace: true,
|
|
14
|
-
attributeNamePrefix: '@_',
|
|
15
|
-
arrayMode: true
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function removeXMLSpecialCharacters(input: string): string {
|
|
20
|
-
return input.replace(/&/gm, '&').replace(/</gm, '<').replace(/>/gm, '>')
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function severityStringToImpact(string: string, id: string): number {
|
|
24
|
-
if (string.match(/none|na|n\/a|not[\s()*_|]?applicable/i)?.length) {
|
|
25
|
-
return 0.0
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (string.match(/low|cat(egory)?\s*(iii|3)/i)?.length) {
|
|
29
|
-
return 0.3
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (string.match(/med(ium)?|cat(egory)?\s*(ii|2)/)?.length) {
|
|
33
|
-
return 0.5
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (string.match(/high|cat(egory)?\s*(i|1)/)?.length) {
|
|
37
|
-
return 0.7
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (string.match(/crit(ical)?|severe/)?.length) {
|
|
41
|
-
return 1.0
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
console.log(`${string} is not a valid severity value. It should be one of the approved keywords. ${id} will be treated as medium severity`)
|
|
45
|
-
return 0.5;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function impactNumberToSeverityString(impact: number): string {
|
|
49
|
-
// Impact must be 0.0 - 1.0
|
|
50
|
-
if (impact < 0.0 || impact > 1.0) {
|
|
51
|
-
throw new Error('Impact cannot be less than 0.0 or greater than 1.0')
|
|
52
|
-
} else {
|
|
53
|
-
if (impact >= 0.9) {
|
|
54
|
-
return 'critical'
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (impact >= 0.7) {
|
|
58
|
-
return 'high'
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (impact >= 0.4) {
|
|
62
|
-
return 'medium'
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (impact >= 0.1) {
|
|
66
|
-
return 'low'
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return 'none'
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function convertEncodedHTMLIntoJson(encodedHTML?: string): DecodedDescription {
|
|
74
|
-
if (encodedHTML) {
|
|
75
|
-
// Some STIGs regarding XSS put the < character inside of the description which breaks parsing
|
|
76
|
-
const patchedHTML = encodedHTML.replace(/"<"/g, '[[[REPLACE_LESS_THAN]]]')
|
|
77
|
-
|
|
78
|
-
const xmlChunks: string[] = []
|
|
79
|
-
const htmlParser = new htmlparser.Parser({
|
|
80
|
-
ontext(text: string) {
|
|
81
|
-
xmlChunks.push(text)
|
|
82
|
-
},
|
|
83
|
-
})
|
|
84
|
-
htmlParser.write(patchedHTML)
|
|
85
|
-
htmlParser.end()
|
|
86
|
-
const converted = convertEncodedXmlIntoJson(xmlChunks.join(''))
|
|
87
|
-
let cleaned: Record<string, string | boolean | undefined> = {}
|
|
88
|
-
|
|
89
|
-
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
|
|
90
|
-
let extractedVulnDescription = ''
|
|
91
|
-
const remainingFields = _.omit(converted.VulnDiscussion, ['FalsePositives', 'FalseNegatives', 'Documentable', 'Mitigations', 'SeverityOverrideGuidance', 'PotentialImpacts', 'ThirdPartyTools', 'MitigationControl', 'Responsibility', 'IAControls'])
|
|
92
|
-
Object.entries(remainingFields).forEach(([field, value]) => {
|
|
93
|
-
extractedVulnDescription += `<${field}> ${value}`
|
|
94
|
-
})
|
|
95
|
-
cleaned = {
|
|
96
|
-
VulnDiscussion: extractedVulnDescription.replace(/\[\[\[REPLACE_LESS_THAN]]]/, '"<"'),
|
|
97
|
-
}
|
|
98
|
-
Object.entries(converted.VulnDiscussion).forEach(([key, value]) => {
|
|
99
|
-
if (typeof value === 'string') {
|
|
100
|
-
cleaned[key] = value.replace(/\[\[\[REPLACE_LESS_THAN]]]/, '"<"')
|
|
101
|
-
} else {
|
|
102
|
-
cleaned[key] = (value as boolean)
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
} else {
|
|
106
|
-
Object.entries(converted).forEach(([key, value]) => {
|
|
107
|
-
if (typeof value === 'string') {
|
|
108
|
-
cleaned[key] = value.replace(/\[\[\[REPLACE_LESS_THAN]]]/, '"<"')
|
|
109
|
-
} else {
|
|
110
|
-
cleaned[key] = (value as boolean)
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return cleaned
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return {}
|
|
119
|
-
}
|