retire 3.0.7 → 3.1.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 CHANGED
@@ -31,7 +31,7 @@ Options:
31
31
  --noderepo <path|url> Local or internal version of repo
32
32
  --cachedir <path> Path to use for local cache instead of /tmp/.retire-cache
33
33
  --proxy <url> Proxy url (http://some.sever:8080)
34
- --outputformat <format> Valid formats: text, json, jsonsimple, depcheck (experimental) and cyclonedx
34
+ --outputformat <format> Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx and cyclonedxJSON
35
35
  --outputpath <path> File to which output should be written
36
36
  --ignore <paths> Comma delimited list of paths to ignore
37
37
  --ignorefile <path> Custom ignore file, defaults to .retireignore / .retireignore.json
package/bin/retire CHANGED
@@ -54,7 +54,7 @@ program
54
54
  .option('--noderepo <path|url>', 'Local or internal version of repo')
55
55
  .option('--cachedir <path>', 'Path to use for local cache instead of /tmp/.retire-cache')
56
56
  .option('--proxy <url>', 'Proxy url (http://some.sever:8080)')
57
- .option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental) and cyclonedx')
57
+ .option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx and cyclonedxJSON')
58
58
  .option('--outputpath <path>', 'File to which output should be written')
59
59
  .option('--ignore <paths>', 'Comma delimited list of paths to ignore')
60
60
  .option('--ignorefile <path>', 'Custom ignore file, defaults to .retireignore / .retireignore.json')
@@ -113,13 +113,13 @@ if(config.ignorefile) {
113
113
  if (config.ignorefile.substr(-5) === ".json") {
114
114
  try {
115
115
  var ignored = JSON.parse(fs.readFileSync(config.ignorefile).toString());
116
- } catch(e) {
116
+ } catch(e) {
117
117
  exitWithError('Error: Invalid ignore file: ' + config.ignorefile, e);
118
118
  }
119
119
  config.ignore.descriptors = ignored;
120
120
  var ignoredPaths = ignored
121
121
  .map(function(x) { return x.path; })
122
- .filter(function(x) { return x; });
122
+ .filter(function(x) { return x; });
123
123
  config.ignore.paths = config.ignore.paths.concat(ignoredPaths);
124
124
  } else {
125
125
  var lines = fs.readFileSync(config.ignorefile).toString().split(/\r\n|\n/g).filter(function(e) { return e !== ''; });
@@ -191,7 +191,7 @@ events.on('scan-js', function() {
191
191
  scanner.scanJsFile(file, jsRepo, config);
192
192
  })
193
193
  .on('bowerfile', function(bowerfile) {
194
- bowerRepo = bowerRepo || repo.asbowerrepo(jsRepo);
194
+ bowerRepo = bowerRepo || repo.asbowerrepo(jsRepo);
195
195
  scanner.scanBowerFile(bowerfile, bowerRepo, config);
196
196
  })
197
197
  .on('end', function() {
@@ -0,0 +1,68 @@
1
+ /*jshint esversion: 6 */
2
+
3
+ var retire = require('../retire');
4
+ var fs = require('fs');
5
+ var uuidv4 = require('uuid').v4;
6
+
7
+ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
8
+ var vulnsFound = false;
9
+ var finalResults = { version: retire.version, start: new Date(), data: [], messages: [], errors: [] };
10
+ logger.info = finalResults.messages.push;
11
+ logger.debug = config.verbose ? finalResults.messages.push : function() {};
12
+ logger.warn = logger.error = finalResults.errors.push;
13
+ logger.logVulnerableDependency = function(finding) {
14
+ vulnsFound = true;
15
+ finalResults.data.push(finding);
16
+ };
17
+ logger.logDependency = function(finding) {
18
+ if (finding.results.length > 0) {
19
+ finalResults.data.push(finding);
20
+ }
21
+ };
22
+
23
+ logger.close = function(callback) {
24
+ var write = vulnsFound ? writer.err : writer.out;
25
+ finalResults.start = finalResults.start.toISOString();
26
+ var seen = {};
27
+ var components = finalResults.data.filter(d => d.results).map(r => r.results.map(dep => {
28
+ dep.version = (dep.version.split(".").length >= 3 ? dep.version : dep.version + ".0").replace(/-/g, ".");
29
+ var filepath = r.file || dep.file;
30
+ var file = fs.readFileSync(filepath);
31
+ var purl = `pkg:npm/${dep.component}@${dep.version}`;
32
+ if (seen[purl]) return '';
33
+ seen[purl] = true;
34
+ return {
35
+ type: "library",
36
+ name: dep.component,
37
+ version: dep.version,
38
+ purl: purl,
39
+ hashes: [
40
+ { "alg" : "MD5", "content" : hash.md5(file) },
41
+ { "alg" : "SHA-1", "content" : hash.sha1(file) },
42
+ { "alg" : "SHA-256", "content" : hash.sha256(file) },
43
+ { "alg" : "SHA-512", "content" : hash.sha512(file) },
44
+ ]
45
+ };
46
+ }));
47
+ write(JSON.stringify({
48
+ bomFormat : "CycloneDX",
49
+ specVersion : "1.4",
50
+ serialNumber : `urn:uuid:${ uuidv4() }`,
51
+ version : 1,
52
+ components : components,
53
+ metadata : {
54
+ timestamp : finalResults.start,
55
+ tools : [
56
+ {
57
+ vendor : "RetireJS",
58
+ name : "retire.js",
59
+ version : retire.version
60
+ }
61
+ ]
62
+ }
63
+ }, undefined, 2));
64
+ writer.close(callback);
65
+ };
66
+ }
67
+
68
+ exports.configure = configureCycloneDXJSONLogger;
@@ -2,37 +2,37 @@
2
2
 
3
3
  var retire = require('../retire');
4
4
  var fs = require('fs');
5
+ var uuidv4 = require('uuid').v4;
5
6
 
6
7
 
7
8
  function configureCycloneDXLogger(logger, writer, config, hash) {
8
- var vulnsFound = false;
9
- var finalResults = { version: retire.version, start: new Date(), data: [], messages: [], errors: [] };
10
- logger.info = finalResults.messages.push;
11
- logger.debug = config.verbose ? finalResults.messages.push : function() {};
12
- logger.warn = logger.error = finalResults.errors.push;
13
- logger.logVulnerableDependency = function(finding) {
14
- vulnsFound = true;
15
- finalResults.data.push(finding);
16
- };
17
- logger.logDependency = function(finding) {
18
- if (finding.results.length > 0) {
19
- finalResults.data.push(finding);
20
- }
21
- };
9
+ var vulnsFound = false;
10
+ var finalResults = { version: retire.version, start: new Date(), data: [], messages: [], errors: [] };
11
+ logger.info = finalResults.messages.push;
12
+ logger.debug = config.verbose ? finalResults.messages.push : function() {};
13
+ logger.warn = logger.error = finalResults.errors.push;
14
+ logger.logVulnerableDependency = function(finding) {
15
+ vulnsFound = true;
16
+ finalResults.data.push(finding);
17
+ };
18
+ logger.logDependency = function(finding) {
19
+ if (finding.results.length > 0) {
20
+ finalResults.data.push(finding);
21
+ }
22
+ };
22
23
 
23
- logger.close = function(callback) {
24
- var write = vulnsFound ? writer.err : writer.out;
25
- finalResults.start = finalResults.start.toISOString().replace("Z", "+0000");
26
- var seen = {};
27
- var components = finalResults.data.filter(d => d.results).map(r => r.results.map(dep => {
28
- dep.version = (dep.version.split(".").length >= 3 ? dep.version : dep.version + ".0").replace(/-/g, ".");
29
- var filepath = r.file || dep.file;
30
- var filename = filepath.split("/").slice(-1);
31
- var file = fs.readFileSync(filepath);
32
- var purl = `pkg:npm/${dep.component}@${dep.version}`;
33
- if (seen[purl]) return '';
34
- seen[purl] = true;
35
- return `
24
+ logger.close = function(callback) {
25
+ var write = vulnsFound ? writer.err : writer.out;
26
+ var seen = {};
27
+ var components = finalResults.data.filter(d => d.results).map(r => r.results.map(dep => {
28
+ dep.version = (dep.version.split(".").length >= 3 ? dep.version : dep.version + ".0").replace(/-/g, ".");
29
+ var filepath = r.file || dep.file;
30
+ var filename = filepath.split("/").slice(-1);
31
+ var file = fs.readFileSync(filepath);
32
+ var purl = `pkg:npm/${dep.component}@${dep.version}`;
33
+ if (seen[purl]) return '';
34
+ seen[purl] = true;
35
+ return `
36
36
  <component type="library">
37
37
  <name>${dep.component}</name>
38
38
  <version>${dep.version}</version>
@@ -42,18 +42,27 @@ function configureCycloneDXLogger(logger, writer, config, hash) {
42
42
  <hash alg="SHA-256">${hash.sha256(file)}</hash>
43
43
  <hash alg="SHA-512">${hash.sha512(file)}</hash>
44
44
  </hashes>
45
- <licenses><license></license></licenses>
46
45
  <purl>${purl}</purl>
47
46
  <modified>false</modified>
48
47
  </component>`;
49
48
  }).join("")).join("");
50
- write(`<?xml version="1.0"?>
51
- <bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
49
+ write(`<?xml version="1.0"?>
50
+ <bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:${ uuidv4() }" version="1">
51
+ <metadata>
52
+ <timestamp>${finalResults.start.toISOString()}</timestamp>
53
+ <tools>
54
+ <tool>
55
+ <vendor>RetireJS</vendor>
56
+ <name>retire.js</name>
57
+ <version>${ retire.version }</version>
58
+ </tool>
59
+ </tools>
60
+ </metadata>
52
61
  <components>${components}
53
62
  </components>
54
63
  </bom>`);
55
- writer.close(callback);
56
- };
64
+ writer.close(callback);
65
+ };
57
66
  }
58
67
 
59
68
  exports.configure = configureCycloneDXLogger;
@@ -14,7 +14,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
14
14
  vulnsFound = true;
15
15
  finalResults.data.push(finding);
16
16
  };
17
- logger.logDependency = function(finding) { 
17
+ logger.logDependency = function(finding) {
18
18
  if (config.verbose && finding.results.length > 0) {
19
19
  finalResults.data.push(finding);
20
20
  }
@@ -28,7 +28,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
28
28
  <scanInfo>
29
29
  <engineVersion>${retire.version}</engineVersion>
30
30
  <dataSource><name>${config.jsRepo || "Retire.js github js repo"}</name><timestamp>${finalResults.start}</timestamp></dataSource>
31
- <dataSource><name>${config.nodeRepo || "Retire.js github node repo"}</name><timestamp>${finalResults.start}</timestamp></dataSource>
31
+ <dataSource><name>${config.nodeRepo || "Retire.js github node repo"}</name><timestamp>${finalResults.start}</timestamp></dataSource>
32
32
  </scanInfo>
33
33
  <projectInfo>
34
34
  <name>${config.path}</name>
@@ -37,7 +37,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
37
37
  </projectInfo>
38
38
  <dependencies>`);
39
39
  write(finalResults.data.filter(d => d.results).map(r => r.results.map((dep, i) => {
40
- var filepath = r.file || dep.file;
40
+ var filepath = r.file || dep.file;
41
41
  var filename = filepath.split("/").slice(-1);
42
42
  var file = fs.readFileSync(filepath);
43
43
  var md5 = hash.md5(file);
@@ -82,7 +82,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
82
82
  <availabilityImpact>PARTIAL</availabilityImpact>
83
83
  <severity>${v.severity || "medium"}</severity>
84
84
  </cvssV2>
85
- <description>${v.identifiers && v.identifiers.summary || "None"}</description>
85
+ <description>${v.identifiers && v.identifiers.summary || "None"}</description>
86
86
  <references>${references}
87
87
  </references>
88
88
  <vulnerableSoftware>
@@ -13,7 +13,7 @@ function configureJsonLogger(logger, writer, config) {
13
13
  vulnsFound = true;
14
14
  finalResults.data.push(finding);
15
15
  };
16
- logger.logDependency = function(finding) { 
16
+ logger.logDependency = function(finding) {
17
17
  if (config.verbose && finding.results.length > 0) {
18
18
  finalResults.data.push(finding);
19
19
  }
package/lib/reporting.js CHANGED
@@ -6,16 +6,17 @@ var fs = require('fs');
6
6
  var crypto = require('crypto');
7
7
 
8
8
  var loggers = {
9
- console : require("./reporters/console"),
10
- text : require("./reporters/console"),
11
- json : require("./reporters/json"),
12
- depcheck : require("./reporters/depcheck"),
13
- cyclonedx: require("./reporters/cyclonedx")
9
+ console : require("./reporters/console"),
10
+ text : require("./reporters/console"),
11
+ json : require("./reporters/json"),
12
+ depcheck : require("./reporters/depcheck"),
13
+ cyclonedx : require("./reporters/cyclonedx"),
14
+ cyclonedxJSON : require("./reporters/cyclonedx-json")
14
15
  };
16
+
15
17
  loggers.clean = loggers.console;
16
18
  loggers.jsonsimple = loggers.json;
17
19
 
18
-
19
20
  var colorwarn = function(x) { return x; };
20
21
 
21
22
  var verbose = false;
@@ -91,3 +92,5 @@ exports.open = function(config) {
91
92
  }
92
93
  return logger;
93
94
  };
95
+
96
+ exports.hash = hash;
package/lib/retire.js CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  var exports = exports || {};
7
- exports.version = '3.0.7';
7
+ exports.version = '3.1.0';
8
8
 
9
9
  function isDefined(o) {
10
10
  return typeof o !== 'undefined';
package/lib/utils.js CHANGED
@@ -31,8 +31,8 @@ exports.map = function(o, fn) {
31
31
  return Object.keys(o).map(function(k) { return fn(o[k], k); });
32
32
  };
33
33
 
34
- exports.find = function(ar, fn) {
35
- for(var i in ar) {
34
+ exports.find = function(ar, fn) {
35
+ for(var i in ar) {
36
36
  if (fn(ar[i])) return ar[i];
37
37
  }
38
38
  return undefined;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Erlend Oftedal <erlend@oftedal.no>",
3
3
  "name": "retire",
4
4
  "description": "Retire is a tool for detecting use of vulnerable libraries",
5
- "version": "3.0.7",
5
+ "version": "3.1.0",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -17,11 +17,14 @@
17
17
  "commander": "2.5.x",
18
18
  "proxy-agent": "^5.0.0",
19
19
  "read-installed": "^4.0.3",
20
+ "uuid": "^8.3.2",
20
21
  "walkdir": "0.4.1"
21
22
  },
22
23
  "devDependencies": {
23
24
  "chai": "^4.3.4",
24
25
  "jshint": "^2.13.4",
26
+ "jsonschema": "^1.4.1",
27
+ "libxmljs": "^0.19.10",
25
28
  "mocha": "^9.2.0"
26
29
  },
27
30
  "scripts": {