@cyclonedx/cdxgen 9.4.0 → 9.5.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 +19 -50
- package/analyzer.js +29 -4
- package/bin/evinse.js +121 -0
- package/bin/repl.js +121 -7
- package/bin/verify.js +39 -0
- package/db.js +80 -0
- package/display.js +100 -1
- package/docker.test.js +9 -0
- package/evinser.js +827 -0
- package/evinser.test.js +35 -0
- package/index.js +85 -38
- package/package.json +10 -5
- package/utils.js +331 -144
- package/utils.test.js +65 -14
package/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { globSync } from "glob";
|
|
2
|
-
import { tmpdir, platform, freemem } from "node:os";
|
|
2
|
+
import { homedir, tmpdir, platform, freemem } from "node:os";
|
|
3
3
|
import {
|
|
4
4
|
dirname,
|
|
5
5
|
sep as _sep,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
existsSync,
|
|
13
13
|
readFileSync,
|
|
14
|
+
lstatSync,
|
|
14
15
|
mkdtempSync,
|
|
15
16
|
rmSync,
|
|
16
17
|
copyFileSync,
|
|
@@ -26,19 +27,19 @@ let url = import.meta.url;
|
|
|
26
27
|
if (!url.startsWith("file://")) {
|
|
27
28
|
url = new URL(`file://${import.meta.url}`).toString();
|
|
28
29
|
}
|
|
29
|
-
const
|
|
30
|
+
const dirNameStr = import.meta ? dirname(fileURLToPath(url)) : __dirname;
|
|
30
31
|
|
|
31
32
|
const licenseMapping = JSON.parse(
|
|
32
|
-
readFileSync(join(
|
|
33
|
+
readFileSync(join(dirNameStr, "data", "lic-mapping.json"))
|
|
33
34
|
);
|
|
34
35
|
const vendorAliases = JSON.parse(
|
|
35
|
-
readFileSync(join(
|
|
36
|
+
readFileSync(join(dirNameStr, "data", "vendor-alias.json"))
|
|
36
37
|
);
|
|
37
38
|
const spdxLicenses = JSON.parse(
|
|
38
|
-
readFileSync(join(
|
|
39
|
+
readFileSync(join(dirNameStr, "data", "spdx-licenses.json"))
|
|
39
40
|
);
|
|
40
41
|
const knownLicenses = JSON.parse(
|
|
41
|
-
readFileSync(join(
|
|
42
|
+
readFileSync(join(dirNameStr, "data", "known-licenses.json"))
|
|
42
43
|
);
|
|
43
44
|
import { load } from "cheerio";
|
|
44
45
|
import { load as _load } from "js-yaml";
|
|
@@ -49,18 +50,19 @@ import StreamZip from "node-stream-zip";
|
|
|
49
50
|
import { parseEDNString } from "edn-data";
|
|
50
51
|
import { PackageURL } from "packageurl-js";
|
|
51
52
|
import { getTreeWithPlugin } from "./piptree.js";
|
|
53
|
+
import iconv from "iconv-lite";
|
|
52
54
|
|
|
53
|
-
const selfPJson = JSON.parse(readFileSync(join(
|
|
55
|
+
const selfPJson = JSON.parse(readFileSync(join(dirNameStr, "package.json")));
|
|
54
56
|
const _version = selfPJson.version;
|
|
55
57
|
|
|
56
58
|
// Refer to contrib/py-modules.py for a script to generate this list
|
|
57
59
|
// The script needs to be used once every few months to update this list
|
|
58
60
|
const PYTHON_STD_MODULES = JSON.parse(
|
|
59
|
-
readFileSync(join(
|
|
61
|
+
readFileSync(join(dirNameStr, "data", "python-stdlib.json"))
|
|
60
62
|
);
|
|
61
63
|
// Mapping between modules and package names
|
|
62
64
|
const PYPI_MODULE_PACKAGE_MAPPING = JSON.parse(
|
|
63
|
-
readFileSync(join(
|
|
65
|
+
readFileSync(join(dirNameStr, "data", "pypi-pkg-aliases.json"))
|
|
64
66
|
);
|
|
65
67
|
|
|
66
68
|
// Debug mode flag
|
|
@@ -168,10 +170,24 @@ export function getLicenses(pkg, format = "xml") {
|
|
|
168
170
|
} else if (l.startsWith("http")) {
|
|
169
171
|
if (!l.includes("opensource.org")) {
|
|
170
172
|
licenseContent.name = "CUSTOM";
|
|
173
|
+
} else {
|
|
174
|
+
const possibleId = l
|
|
175
|
+
.replace("http://www.opensource.org/licenses/", "")
|
|
176
|
+
.toUpperCase();
|
|
177
|
+
spdxLicenses.forEach((v) => {
|
|
178
|
+
if (v.toUpperCase() === possibleId) {
|
|
179
|
+
licenseContent.id = v;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
171
182
|
}
|
|
172
183
|
if (l.includes("mit-license")) {
|
|
173
184
|
licenseContent.id = "MIT";
|
|
174
185
|
}
|
|
186
|
+
// We always need a name to avoid validation errors
|
|
187
|
+
// Issue: #469
|
|
188
|
+
if (!licenseContent.name && !licenseContent.id) {
|
|
189
|
+
licenseContent.name = "CUSTOM";
|
|
190
|
+
}
|
|
175
191
|
licenseContent.url = l;
|
|
176
192
|
} else {
|
|
177
193
|
licenseContent.name = l;
|
|
@@ -1449,7 +1465,7 @@ export const parseGradleDep = function (
|
|
|
1449
1465
|
}
|
|
1450
1466
|
let stack = [last_purl];
|
|
1451
1467
|
const depRegex =
|
|
1452
|
-
/^.*?--- +(?<
|
|
1468
|
+
/^.*?--- +(?<groupspecified>[^\s:]+) ?:(?<namespecified>[^\s:]+)(?::(?:{strictly [[]?)?(?<versionspecified>[^,\s:}]+))?(?:})?(?:[^->]* +-> +(?:(?<groupoverride>[^\s:]+):(?<nameoverride>[^\s:]+):)?(?<versionoverride>[^\s:]+))?/gm;
|
|
1453
1469
|
for (const rline of rawOutput.split("\n")) {
|
|
1454
1470
|
if (!rline) {
|
|
1455
1471
|
continue;
|
|
@@ -1467,16 +1483,9 @@ export const parseGradleDep = function (
|
|
|
1467
1483
|
rline.startsWith("\\--- ")
|
|
1468
1484
|
) {
|
|
1469
1485
|
last_level = 1;
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
stack = [last_project_purl];
|
|
1474
|
-
last_purl = last_project_purl;
|
|
1475
|
-
} else {
|
|
1476
|
-
last_project_purl = first_purl;
|
|
1477
|
-
last_purl = last_project_purl;
|
|
1478
|
-
stack = [first_purl];
|
|
1479
|
-
}
|
|
1486
|
+
last_project_purl = first_purl;
|
|
1487
|
+
last_purl = last_project_purl;
|
|
1488
|
+
stack = [first_purl];
|
|
1480
1489
|
}
|
|
1481
1490
|
if (rline.includes(" - ")) {
|
|
1482
1491
|
profileName = rline.split(" - ")[0];
|
|
@@ -1489,76 +1498,86 @@ export const parseGradleDep = function (
|
|
|
1489
1498
|
}
|
|
1490
1499
|
}
|
|
1491
1500
|
while ((match = depRegex.exec(rline))) {
|
|
1492
|
-
const [
|
|
1501
|
+
const [
|
|
1502
|
+
line,
|
|
1503
|
+
groupspecified,
|
|
1504
|
+
namespecified,
|
|
1505
|
+
versionspecified,
|
|
1506
|
+
groupoverride,
|
|
1507
|
+
nameoverride,
|
|
1508
|
+
versionoverride
|
|
1509
|
+
] = match;
|
|
1510
|
+
const group = groupoverride || groupspecified;
|
|
1511
|
+
const name = nameoverride || namespecified;
|
|
1493
1512
|
const version = versionoverride || versionspecified;
|
|
1494
|
-
const level = line.split(
|
|
1495
|
-
if (version !== undefined) {
|
|
1513
|
+
const level = line.split(groupspecified)[0].length / 5;
|
|
1514
|
+
if (version !== undefined || group === "project") {
|
|
1496
1515
|
let purlString = new PackageURL(
|
|
1497
1516
|
"maven",
|
|
1498
|
-
group,
|
|
1517
|
+
group !== "project" ? group : rootProjectGroup,
|
|
1499
1518
|
name,
|
|
1500
|
-
version,
|
|
1519
|
+
version !== undefined ? version : rootProjectVersion,
|
|
1501
1520
|
{ type: "jar" },
|
|
1502
1521
|
null
|
|
1503
1522
|
).toString();
|
|
1504
1523
|
purlString = decodeURIComponent(purlString);
|
|
1505
1524
|
keys_cache[purlString + "_" + last_purl] = true;
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
if (profileName) {
|
|
1520
|
-
adep.properties = [
|
|
1521
|
-
{
|
|
1522
|
-
name: "GradleProfileName",
|
|
1523
|
-
value: profileName
|
|
1524
|
-
}
|
|
1525
|
-
];
|
|
1526
|
-
}
|
|
1527
|
-
deps.push(adep);
|
|
1525
|
+
// Filter duplicates
|
|
1526
|
+
if (!deps_keys_cache[purlString]) {
|
|
1527
|
+
deps_keys_cache[purlString] = true;
|
|
1528
|
+
const adep = {
|
|
1529
|
+
group: group !== "project" ? group : rootProjectGroup,
|
|
1530
|
+
name: name,
|
|
1531
|
+
version: version !== undefined ? version : rootProjectVersion,
|
|
1532
|
+
qualifiers: { type: "jar" }
|
|
1533
|
+
};
|
|
1534
|
+
adep["purl"] = purlString;
|
|
1535
|
+
adep["bom-ref"] = purlString;
|
|
1536
|
+
if (scope) {
|
|
1537
|
+
adep["scope"] = scope;
|
|
1528
1538
|
}
|
|
1529
|
-
if (
|
|
1530
|
-
|
|
1539
|
+
if (profileName) {
|
|
1540
|
+
adep.properties = [
|
|
1541
|
+
{
|
|
1542
|
+
name: "GradleProfileName",
|
|
1543
|
+
value: profileName
|
|
1544
|
+
}
|
|
1545
|
+
];
|
|
1531
1546
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
}
|
|
1550
|
-
const last_stack =
|
|
1551
|
-
stack.length > 0 ? stack[stack.length - 1] : last_project_purl;
|
|
1552
|
-
const cnodes = level_trees[last_stack] || [];
|
|
1553
|
-
if (!cnodes.includes(purlString)) {
|
|
1554
|
-
cnodes.push(purlString);
|
|
1555
|
-
}
|
|
1556
|
-
level_trees[last_stack] = cnodes;
|
|
1547
|
+
deps.push(adep);
|
|
1548
|
+
}
|
|
1549
|
+
if (!level_trees[purlString]) {
|
|
1550
|
+
level_trees[purlString] = [];
|
|
1551
|
+
}
|
|
1552
|
+
if (level == 0) {
|
|
1553
|
+
stack = [first_purl];
|
|
1554
|
+
stack.push(purlString);
|
|
1555
|
+
} else if (last_purl === "") {
|
|
1556
|
+
stack.push(purlString);
|
|
1557
|
+
} else if (level > last_level) {
|
|
1558
|
+
const cnodes = level_trees[last_purl] || [];
|
|
1559
|
+
if (!cnodes.includes(purlString)) {
|
|
1560
|
+
cnodes.push(purlString);
|
|
1561
|
+
}
|
|
1562
|
+
level_trees[last_purl] = cnodes;
|
|
1563
|
+
if (stack[stack.length - 1] !== purlString) {
|
|
1557
1564
|
stack.push(purlString);
|
|
1558
1565
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1566
|
+
} else {
|
|
1567
|
+
for (let i = level; i <= last_level; i++) {
|
|
1568
|
+
stack.pop();
|
|
1569
|
+
}
|
|
1570
|
+
const last_stack =
|
|
1571
|
+
stack.length > 0 ? stack[stack.length - 1] : last_project_purl;
|
|
1572
|
+
const cnodes = level_trees[last_stack] || [];
|
|
1573
|
+
if (!cnodes.includes(purlString)) {
|
|
1574
|
+
cnodes.push(purlString);
|
|
1575
|
+
}
|
|
1576
|
+
level_trees[last_stack] = cnodes;
|
|
1577
|
+
stack.push(purlString);
|
|
1561
1578
|
}
|
|
1579
|
+
last_level = level;
|
|
1580
|
+
last_purl = purlString;
|
|
1562
1581
|
}
|
|
1563
1582
|
}
|
|
1564
1583
|
}
|
|
@@ -4118,13 +4137,19 @@ export const parseEdnData = function (rawEdnData) {
|
|
|
4118
4137
|
};
|
|
4119
4138
|
|
|
4120
4139
|
export const parseNupkg = async function (nupkgFile) {
|
|
4121
|
-
const pkgList = [];
|
|
4122
|
-
const pkg = { group: "" };
|
|
4123
4140
|
let nuspecData = await readZipEntry(nupkgFile, ".nuspec");
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
nuspecData = nuspecData.slice(1);
|
|
4141
|
+
if (!nuspecData) {
|
|
4142
|
+
return [];
|
|
4127
4143
|
}
|
|
4144
|
+
if (nuspecData.charCodeAt(0) === 65533) {
|
|
4145
|
+
nuspecData = await readZipEntry(nupkgFile, ".nuspec", "ucs2");
|
|
4146
|
+
}
|
|
4147
|
+
return await parseNuspecData(nupkgFile, nuspecData);
|
|
4148
|
+
};
|
|
4149
|
+
|
|
4150
|
+
export const parseNuspecData = async function (nupkgFile, nuspecData) {
|
|
4151
|
+
const pkgList = [];
|
|
4152
|
+
const pkg = { group: "" };
|
|
4128
4153
|
let npkg = undefined;
|
|
4129
4154
|
try {
|
|
4130
4155
|
npkg = xml2js(nuspecData, {
|
|
@@ -4136,9 +4161,13 @@ export const parseNupkg = async function (nupkgFile) {
|
|
|
4136
4161
|
commentKey: "value"
|
|
4137
4162
|
}).package;
|
|
4138
4163
|
} catch (e) {
|
|
4139
|
-
// If we are parsing with invalid encoding unicode replacement character is used
|
|
4164
|
+
// If we are parsing with invalid encoding, unicode replacement character is used
|
|
4140
4165
|
if (nuspecData.charCodeAt(0) === 65533) {
|
|
4141
4166
|
console.log(`Unable to parse ${nupkgFile} in utf-8 mode`);
|
|
4167
|
+
} else {
|
|
4168
|
+
console.log(
|
|
4169
|
+
"Unable to parse this package. Tried utf-8 and ucs2 encoding."
|
|
4170
|
+
);
|
|
4142
4171
|
}
|
|
4143
4172
|
}
|
|
4144
4173
|
if (!npkg) {
|
|
@@ -4851,48 +4880,100 @@ export const parseSwiftResolved = (resolvedFile) => {
|
|
|
4851
4880
|
*
|
|
4852
4881
|
* @param {string} mavenCmd Maven command to use
|
|
4853
4882
|
* @param {string} basePath Path to the maven project
|
|
4883
|
+
* @param {boolean} cleanup Remove temporary directories
|
|
4884
|
+
* @param {boolean} includeCacheDir Include maven and gradle cache directories
|
|
4854
4885
|
*/
|
|
4855
|
-
export const collectMvnDependencies = function (
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
mavenCmd,
|
|
4862
|
-
[
|
|
4863
|
-
"dependency:copy-dependencies",
|
|
4864
|
-
`-DoutputDirectory=${tempDir}`,
|
|
4865
|
-
"-DexcludeTransitive=true",
|
|
4866
|
-
"-DincludeScope=runtime",
|
|
4867
|
-
"-U",
|
|
4868
|
-
"-Dmdep.prependGroupId=" + (process.env.MAVEN_PREPEND_GROUP || "false"),
|
|
4869
|
-
"-Dmdep.stripVersion=" + (process.env.MAVEN_STRIP_VERSION || "false")
|
|
4870
|
-
],
|
|
4871
|
-
{ cwd: basePath, encoding: "utf-8" }
|
|
4872
|
-
);
|
|
4886
|
+
export const collectMvnDependencies = function (
|
|
4887
|
+
mavenCmd,
|
|
4888
|
+
basePath,
|
|
4889
|
+
cleanup = true,
|
|
4890
|
+
includeCacheDir = false
|
|
4891
|
+
) {
|
|
4873
4892
|
let jarNSMapping = {};
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4893
|
+
const MAVEN_CACHE_DIR =
|
|
4894
|
+
process.env.MAVEN_CACHE_DIR || join(homedir(), ".m2", "repository");
|
|
4895
|
+
const tempDir = mkdtempSync(join(tmpdir(), "mvn-deps-"));
|
|
4896
|
+
const copyArgs = [
|
|
4897
|
+
"dependency:copy-dependencies",
|
|
4898
|
+
`-DoutputDirectory=${tempDir}`,
|
|
4899
|
+
"-U",
|
|
4900
|
+
"-Dmdep.copyPom=true",
|
|
4901
|
+
"-Dmdep.useRepositoryLayout=true",
|
|
4902
|
+
"-Dmdep.includeScope=compile",
|
|
4903
|
+
"-Dmdep.prependGroupId=" + (process.env.MAVEN_PREPEND_GROUP || "false"),
|
|
4904
|
+
"-Dmdep.stripVersion=" + (process.env.MAVEN_STRIP_VERSION || "false")
|
|
4905
|
+
];
|
|
4906
|
+
if (basePath && basePath !== MAVEN_CACHE_DIR) {
|
|
4879
4907
|
console.log(
|
|
4880
|
-
|
|
4908
|
+
`Executing '${mavenCmd} dependency:copy-dependencies ${copyArgs.join(
|
|
4909
|
+
" "
|
|
4910
|
+
)}' in ${basePath}`
|
|
4881
4911
|
);
|
|
4882
|
-
|
|
4883
|
-
|
|
4912
|
+
const result = spawnSync(mavenCmd, copyArgs, {
|
|
4913
|
+
cwd: basePath,
|
|
4914
|
+
encoding: "utf-8"
|
|
4915
|
+
});
|
|
4916
|
+
if (result.status !== 0 || result.error) {
|
|
4917
|
+
console.error(result.stdout, result.stderr);
|
|
4918
|
+
console.log(
|
|
4919
|
+
"Resolve the above maven error. You can try the following remediation tips:\n"
|
|
4920
|
+
);
|
|
4921
|
+
console.log(
|
|
4922
|
+
"1. Check if the correct version of maven is installed and available in the PATH."
|
|
4923
|
+
);
|
|
4924
|
+
console.log(
|
|
4925
|
+
"2. Perform 'mvn compile package' before invoking this command. Fix any errors found during this invocation."
|
|
4926
|
+
);
|
|
4927
|
+
console.log(
|
|
4928
|
+
"3. Ensure the temporary directory is available and has sufficient disk space to copy all the artifacts."
|
|
4929
|
+
);
|
|
4930
|
+
} else {
|
|
4931
|
+
jarNSMapping = collectJarNS(tempDir);
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
if (includeCacheDir || basePath === MAVEN_CACHE_DIR) {
|
|
4935
|
+
// slow operation
|
|
4936
|
+
jarNSMapping = collectJarNS(MAVEN_CACHE_DIR);
|
|
4937
|
+
}
|
|
4938
|
+
|
|
4939
|
+
// Clean up
|
|
4940
|
+
if (cleanup && tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
|
|
4941
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
4942
|
+
}
|
|
4943
|
+
return jarNSMapping;
|
|
4944
|
+
};
|
|
4945
|
+
|
|
4946
|
+
export const collectGradleDependencies = (
|
|
4947
|
+
gradleCmd,
|
|
4948
|
+
basePath,
|
|
4949
|
+
cleanup = true, // eslint-disable-line no-unused-vars
|
|
4950
|
+
includeCacheDir = false // eslint-disable-line no-unused-vars
|
|
4951
|
+
) => {
|
|
4952
|
+
// HELP WANTED: We need an init script that mimics maven copy-dependencies that only collects the project specific jars and poms
|
|
4953
|
+
// Construct gradle cache directory
|
|
4954
|
+
let GRADLE_CACHE_DIR =
|
|
4955
|
+
process.env.GRADLE_CACHE_DIR ||
|
|
4956
|
+
join(homedir(), ".gradle", "caches", "modules-2", "files-2.1");
|
|
4957
|
+
if (process.env.GRADLE_USER_HOME) {
|
|
4958
|
+
GRADLE_CACHE_DIR = join(
|
|
4959
|
+
process.env.GRADLE_USER_HOME,
|
|
4960
|
+
"caches",
|
|
4961
|
+
"modules-2",
|
|
4962
|
+
"files-2.1"
|
|
4884
4963
|
);
|
|
4964
|
+
}
|
|
4965
|
+
if (DEBUG_MODE) {
|
|
4966
|
+
console.log("Collecting jars from", GRADLE_CACHE_DIR);
|
|
4885
4967
|
console.log(
|
|
4886
|
-
"
|
|
4968
|
+
"To improve performance, ensure only the project dependencies are present in this cache location."
|
|
4887
4969
|
);
|
|
4888
|
-
} else {
|
|
4889
|
-
jarNSMapping = collectJarNS(tempDir);
|
|
4890
4970
|
}
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4971
|
+
const pomPathMap = {};
|
|
4972
|
+
const pomFiles = getAllFiles(GRADLE_CACHE_DIR, "**/*.pom");
|
|
4973
|
+
for (const apom of pomFiles) {
|
|
4974
|
+
pomPathMap[basename(apom)] = apom;
|
|
4895
4975
|
}
|
|
4976
|
+
const jarNSMapping = collectJarNS(GRADLE_CACHE_DIR, pomPathMap);
|
|
4896
4977
|
return jarNSMapping;
|
|
4897
4978
|
};
|
|
4898
4979
|
|
|
@@ -4900,10 +4981,11 @@ export const collectMvnDependencies = function (mavenCmd, basePath) {
|
|
|
4900
4981
|
* Method to collect class names from all jars in a directory
|
|
4901
4982
|
*
|
|
4902
4983
|
* @param {string} jarPath Path containing jars
|
|
4984
|
+
* @param {object} pomPathMap Map containing jar to pom names. Required to successful parse gradle cache.
|
|
4903
4985
|
*
|
|
4904
4986
|
* @return object containing jar name and class list
|
|
4905
4987
|
*/
|
|
4906
|
-
export const collectJarNS = function (jarPath) {
|
|
4988
|
+
export const collectJarNS = function (jarPath, pomPathMap = {}) {
|
|
4907
4989
|
const jarNSMapping = {};
|
|
4908
4990
|
console.log(
|
|
4909
4991
|
`About to identify class names for all jars in the path ${jarPath}`
|
|
@@ -4912,31 +4994,72 @@ export const collectJarNS = function (jarPath) {
|
|
|
4912
4994
|
const jarFiles = getAllFiles(jarPath, "**/*.jar");
|
|
4913
4995
|
if (jarFiles && jarFiles.length) {
|
|
4914
4996
|
for (const jf of jarFiles) {
|
|
4915
|
-
const jarname =
|
|
4997
|
+
const jarname = jf;
|
|
4998
|
+
const pomname =
|
|
4999
|
+
pomPathMap[basename(jf).replace(".jar", ".pom")] ||
|
|
5000
|
+
jarname.replace(".jar", ".pom");
|
|
5001
|
+
let pomData = undefined;
|
|
5002
|
+
let purl = undefined;
|
|
5003
|
+
if (existsSync(pomname)) {
|
|
5004
|
+
pomData = parsePomXml(readFileSync(pomname, "utf-8"));
|
|
5005
|
+
if (pomData) {
|
|
5006
|
+
const purlObj = new PackageURL(
|
|
5007
|
+
"maven",
|
|
5008
|
+
pomData.groupId || "",
|
|
5009
|
+
pomData.artifactId,
|
|
5010
|
+
pomData.version,
|
|
5011
|
+
{ type: "jar" },
|
|
5012
|
+
null
|
|
5013
|
+
);
|
|
5014
|
+
purl = purlObj.toString();
|
|
5015
|
+
}
|
|
5016
|
+
} else if (jf.includes(join(".gradle", "caches"))) {
|
|
5017
|
+
// Let's try our best to construct a purl for gradle cache entries of the form
|
|
5018
|
+
// .gradle/caches/modules-2/files-2.1/org.xmlresolver/xmlresolver/4.2.0/f4dbdaa83d636dcac91c9003ffa7fb173173fe8d/xmlresolver-4.2.0-data.jar
|
|
5019
|
+
const tmpA = jf.split(join("files-2.1", ""));
|
|
5020
|
+
if (tmpA && tmpA.length) {
|
|
5021
|
+
let tmpJarPath = tmpA[tmpA.length - 1];
|
|
5022
|
+
// This would yield xmlresolver-4.2.0-data.jar
|
|
5023
|
+
const jarFileName = basename(tmpJarPath);
|
|
5024
|
+
let tmpDirParts = dirname(tmpJarPath).split(_sep);
|
|
5025
|
+
// This would remove the hash from the end of the directory name
|
|
5026
|
+
tmpDirParts.pop();
|
|
5027
|
+
// Retrieve the version
|
|
5028
|
+
const jarVersion = tmpDirParts.pop();
|
|
5029
|
+
// The result would form the group name
|
|
5030
|
+
const jarGroupName = tmpDirParts.join(".").replace(/^\./, "");
|
|
5031
|
+
const purlObj = new PackageURL(
|
|
5032
|
+
"maven",
|
|
5033
|
+
jarGroupName,
|
|
5034
|
+
jarFileName.replace(`-${jarVersion}`, ""),
|
|
5035
|
+
jarVersion,
|
|
5036
|
+
{ type: "jar" },
|
|
5037
|
+
null
|
|
5038
|
+
);
|
|
5039
|
+
purl = purlObj.toString();
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
4916
5042
|
if (DEBUG_MODE) {
|
|
4917
5043
|
console.log(`Executing 'jar tf ${jf}'`);
|
|
4918
5044
|
}
|
|
4919
5045
|
const jarResult = spawnSync("jar", ["-tf", jf], { encoding: "utf-8" });
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
});
|
|
4938
|
-
jarNSMapping[jarname] = nsList;
|
|
4939
|
-
}
|
|
5046
|
+
const consolelines = (jarResult.stdout || "").split("\n");
|
|
5047
|
+
const nsList = consolelines
|
|
5048
|
+
.filter((l) => {
|
|
5049
|
+
return (
|
|
5050
|
+
l.includes(".class") &&
|
|
5051
|
+
!l.includes("-INF") &&
|
|
5052
|
+
!l.includes("module-info")
|
|
5053
|
+
);
|
|
5054
|
+
})
|
|
5055
|
+
.map((e) => {
|
|
5056
|
+
return e.replace(".class", "").replace(/\/$/, "").replace(/\//g, ".");
|
|
5057
|
+
});
|
|
5058
|
+
jarNSMapping[purl || jf] = {
|
|
5059
|
+
jarFile: jf,
|
|
5060
|
+
pom: pomData,
|
|
5061
|
+
namespaces: nsList
|
|
5062
|
+
};
|
|
4940
5063
|
}
|
|
4941
5064
|
if (!jarNSMapping) {
|
|
4942
5065
|
console.log(`Unable to determine class names for the jars in ${jarPath}`);
|
|
@@ -4944,12 +5067,69 @@ export const collectJarNS = function (jarPath) {
|
|
|
4944
5067
|
} else {
|
|
4945
5068
|
console.log(`${jarPath} did not contain any jars.`);
|
|
4946
5069
|
}
|
|
4947
|
-
if (DEBUG_MODE) {
|
|
4948
|
-
console.log("JAR Namespace mapping", jarNSMapping);
|
|
4949
|
-
}
|
|
4950
5070
|
return jarNSMapping;
|
|
4951
5071
|
};
|
|
4952
5072
|
|
|
5073
|
+
export const convertJarNSToPackages = (jarNSMapping) => {
|
|
5074
|
+
let pkgList = [];
|
|
5075
|
+
for (const purl of Object.keys(jarNSMapping)) {
|
|
5076
|
+
let { jarFile, pom, namespaces } = jarNSMapping[purl];
|
|
5077
|
+
if (!pom) {
|
|
5078
|
+
pom = {};
|
|
5079
|
+
}
|
|
5080
|
+
let purlObj = undefined;
|
|
5081
|
+
try {
|
|
5082
|
+
purlObj = PackageURL.fromString(purl);
|
|
5083
|
+
} catch (e) {
|
|
5084
|
+
// ignore
|
|
5085
|
+
purlObj = {};
|
|
5086
|
+
}
|
|
5087
|
+
const name = pom.artifactId || purlObj.name;
|
|
5088
|
+
if (!name) {
|
|
5089
|
+
continue;
|
|
5090
|
+
}
|
|
5091
|
+
const apackage = {
|
|
5092
|
+
name,
|
|
5093
|
+
group: pom.groupId || purlObj.namespace || "",
|
|
5094
|
+
version: pom.version || purlObj.version,
|
|
5095
|
+
description: (pom.description || "").trim(),
|
|
5096
|
+
purl,
|
|
5097
|
+
"bom-ref": purl,
|
|
5098
|
+
evidence: {
|
|
5099
|
+
identity: {
|
|
5100
|
+
field: "purl",
|
|
5101
|
+
confidence: 0.5,
|
|
5102
|
+
methods: [
|
|
5103
|
+
{
|
|
5104
|
+
technique: "filename",
|
|
5105
|
+
confidence: 1,
|
|
5106
|
+
value: jarFile
|
|
5107
|
+
}
|
|
5108
|
+
]
|
|
5109
|
+
}
|
|
5110
|
+
},
|
|
5111
|
+
properties: [
|
|
5112
|
+
{
|
|
5113
|
+
name: "SrcFile",
|
|
5114
|
+
value: jarFile
|
|
5115
|
+
},
|
|
5116
|
+
{
|
|
5117
|
+
name: "Namespaces",
|
|
5118
|
+
value: namespaces.join("\n")
|
|
5119
|
+
}
|
|
5120
|
+
]
|
|
5121
|
+
};
|
|
5122
|
+
if (pom.url) {
|
|
5123
|
+
apackage["homepage"] = { url: pom.url };
|
|
5124
|
+
}
|
|
5125
|
+
if (pom.scm) {
|
|
5126
|
+
apackage["repository"] = { url: pom.scm };
|
|
5127
|
+
}
|
|
5128
|
+
pkgList.push(apackage);
|
|
5129
|
+
}
|
|
5130
|
+
return pkgList;
|
|
5131
|
+
};
|
|
5132
|
+
|
|
4953
5133
|
export const parsePomXml = function (pomXmlData) {
|
|
4954
5134
|
if (!pomXmlData) {
|
|
4955
5135
|
return undefined;
|
|
@@ -5293,10 +5473,15 @@ export const sbtPluginsPath = function (projectPath) {
|
|
|
5293
5473
|
*
|
|
5294
5474
|
* @param {string} zipFile Zip file to read
|
|
5295
5475
|
* @param {string} filePattern File pattern
|
|
5476
|
+
* @param {string} contentEncoding Encoding. Defaults to utf-8
|
|
5296
5477
|
*
|
|
5297
5478
|
* @returns File contents
|
|
5298
5479
|
*/
|
|
5299
|
-
export const readZipEntry = async function (
|
|
5480
|
+
export const readZipEntry = async function (
|
|
5481
|
+
zipFile,
|
|
5482
|
+
filePattern,
|
|
5483
|
+
contentEncoding = "utf-8"
|
|
5484
|
+
) {
|
|
5300
5485
|
let retData = undefined;
|
|
5301
5486
|
try {
|
|
5302
5487
|
const zip = new StreamZip.async({ file: zipFile });
|
|
@@ -5311,7 +5496,7 @@ export const readZipEntry = async function (zipFile, filePattern) {
|
|
|
5311
5496
|
}
|
|
5312
5497
|
if (entry.name.endsWith(filePattern)) {
|
|
5313
5498
|
const fileData = await zip.entryData(entry.name);
|
|
5314
|
-
retData = Buffer.from(fileData)
|
|
5499
|
+
retData = iconv.decode(Buffer.from(fileData), contentEncoding);
|
|
5315
5500
|
break;
|
|
5316
5501
|
}
|
|
5317
5502
|
}
|
|
@@ -5418,7 +5603,7 @@ export const getAtomCommand = () => {
|
|
|
5418
5603
|
}
|
|
5419
5604
|
const NODE_CMD = process.env.NODE_CMD || "node";
|
|
5420
5605
|
const localAtom = join(
|
|
5421
|
-
|
|
5606
|
+
dirNameStr,
|
|
5422
5607
|
"node_modules",
|
|
5423
5608
|
"@appthreat",
|
|
5424
5609
|
"atom",
|
|
@@ -5431,6 +5616,8 @@ export const getAtomCommand = () => {
|
|
|
5431
5616
|
};
|
|
5432
5617
|
|
|
5433
5618
|
export const executeAtom = (src, args) => {
|
|
5619
|
+
let cwd =
|
|
5620
|
+
existsSync(src) && lstatSync(src).isDirectory() ? src : dirname(src);
|
|
5434
5621
|
let ATOM_BIN = getAtomCommand();
|
|
5435
5622
|
if (ATOM_BIN.includes(" ")) {
|
|
5436
5623
|
const tmpA = ATOM_BIN.split(" ");
|
|
@@ -5448,7 +5635,7 @@ export const executeAtom = (src, args) => {
|
|
|
5448
5635
|
JAVA_OPTS: `-Xms${freeMemoryGB}G -Xmx${freeMemoryGB}G`
|
|
5449
5636
|
};
|
|
5450
5637
|
const result = spawnSync(ATOM_BIN, args, {
|
|
5451
|
-
cwd
|
|
5638
|
+
cwd,
|
|
5452
5639
|
encoding: "utf-8",
|
|
5453
5640
|
timeout: TIMEOUT_MS,
|
|
5454
5641
|
env
|