@contrast/contrast 1.0.9 → 1.0.12

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.
Files changed (108) hide show
  1. package/README.md +2 -2
  2. package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +17 -17
  3. package/dist/audit/{languageAnalysisEngine/report → report}/commonReportingFunctions.js +56 -35
  4. package/dist/audit/report/models/reportGuidanceModel.js +6 -0
  5. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportLibraryModel.js +0 -0
  6. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportListModel.js +0 -0
  7. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportOutputModel.js +1 -2
  8. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportSeverityModel.js +0 -0
  9. package/dist/audit/{languageAnalysisEngine/report → report}/models/severityCountModel.js +1 -0
  10. package/dist/audit/{languageAnalysisEngine/report → report}/reportingFeature.js +12 -8
  11. package/dist/audit/{languageAnalysisEngine/report → report}/utils/reportUtils.js +3 -4
  12. package/dist/commands/audit/auditConfig.js +3 -3
  13. package/dist/commands/audit/help.js +3 -1
  14. package/dist/commands/audit/processAudit.js +4 -2
  15. package/dist/commands/auth/auth.js +1 -1
  16. package/dist/commands/config/config.js +2 -2
  17. package/dist/commands/scan/processScan.js +11 -4
  18. package/dist/commands/scan/sca/scaAnalysis.js +20 -9
  19. package/dist/common/HTTPClient.js +9 -0
  20. package/dist/common/commonHelp.js +19 -0
  21. package/dist/common/errorHandling.js +2 -2
  22. package/dist/common/fail.js +66 -0
  23. package/dist/common/versionChecker.js +4 -2
  24. package/dist/constants/constants.js +2 -2
  25. package/dist/constants/locales.js +26 -11
  26. package/dist/constants.js +52 -5
  27. package/dist/index.js +5 -2
  28. package/dist/lambda/help.js +2 -3
  29. package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
  30. package/dist/scaAnalysis/common/treeUpload.js +20 -5
  31. package/dist/scaAnalysis/dotnet/analysis.js +15 -3
  32. package/dist/scaAnalysis/go/goAnalysis.js +8 -2
  33. package/dist/scaAnalysis/java/analysis.js +10 -6
  34. package/dist/scaAnalysis/java/index.js +7 -1
  35. package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
  36. package/dist/scaAnalysis/javascript/index.js +3 -0
  37. package/dist/scaAnalysis/php/analysis.js +1 -1
  38. package/dist/scaAnalysis/php/index.js +12 -6
  39. package/dist/scaAnalysis/php/phpNewServicesMapper.js +62 -0
  40. package/dist/scaAnalysis/python/analysis.js +43 -5
  41. package/dist/scaAnalysis/python/index.js +7 -2
  42. package/dist/scaAnalysis/ruby/analysis.js +14 -4
  43. package/dist/scan/autoDetection.js +5 -13
  44. package/dist/scan/formatScanOutput.js +6 -5
  45. package/dist/scan/help.js +2 -3
  46. package/dist/scan/populateProjectIdAndProjectName.js +5 -0
  47. package/dist/scan/scan.js +4 -0
  48. package/dist/scan/scanConfig.js +4 -4
  49. package/dist/scan/scanResults.js +46 -3
  50. package/dist/telemetry/telemetry.js +137 -0
  51. package/dist/utils/commonApi.js +1 -1
  52. package/dist/utils/getConfig.js +2 -4
  53. package/dist/utils/parsedCLIOptions.js +3 -1
  54. package/dist/utils/requestUtils.js +7 -1
  55. package/package.json +4 -2
  56. package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +22 -29
  57. package/src/audit/{languageAnalysisEngine/report → report}/commonReportingFunctions.ts +80 -44
  58. package/src/audit/report/models/reportGuidanceModel.ts +5 -0
  59. package/src/audit/{languageAnalysisEngine/report → report}/models/reportLibraryModel.ts +0 -0
  60. package/src/audit/{languageAnalysisEngine/report → report}/models/reportListModel.ts +0 -0
  61. package/src/audit/{languageAnalysisEngine/report → report}/models/reportOutputModel.ts +1 -7
  62. package/src/audit/{languageAnalysisEngine/report → report}/models/reportSeverityModel.ts +0 -0
  63. package/src/audit/{languageAnalysisEngine/report → report}/models/severityCountModel.ts +2 -0
  64. package/src/audit/{languageAnalysisEngine/report → report}/reportingFeature.ts +16 -9
  65. package/src/audit/{languageAnalysisEngine/report → report}/utils/reportUtils.ts +4 -4
  66. package/src/commands/audit/auditConfig.ts +10 -3
  67. package/src/commands/audit/help.ts +3 -1
  68. package/src/commands/audit/processAudit.ts +16 -2
  69. package/src/commands/auth/auth.js +3 -1
  70. package/src/commands/config/config.js +4 -2
  71. package/src/commands/scan/processScan.js +18 -4
  72. package/src/commands/scan/sca/scaAnalysis.js +27 -10
  73. package/src/common/HTTPClient.js +15 -0
  74. package/src/common/commonHelp.ts +13 -0
  75. package/src/common/errorHandling.ts +2 -3
  76. package/src/common/fail.js +75 -0
  77. package/src/common/versionChecker.ts +4 -4
  78. package/src/constants/constants.js +2 -2
  79. package/src/constants/locales.js +35 -13
  80. package/src/constants.js +56 -6
  81. package/src/index.ts +17 -2
  82. package/src/lambda/help.ts +2 -3
  83. package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
  84. package/src/scaAnalysis/common/treeUpload.js +21 -5
  85. package/src/scaAnalysis/dotnet/analysis.js +21 -3
  86. package/src/scaAnalysis/go/goAnalysis.js +9 -2
  87. package/src/scaAnalysis/java/analysis.js +11 -6
  88. package/src/scaAnalysis/java/index.js +9 -1
  89. package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
  90. package/src/scaAnalysis/javascript/index.js +3 -0
  91. package/src/scaAnalysis/php/analysis.js +1 -1
  92. package/src/scaAnalysis/php/index.js +12 -6
  93. package/src/scaAnalysis/php/phpNewServicesMapper.js +77 -0
  94. package/src/scaAnalysis/python/analysis.js +49 -5
  95. package/src/scaAnalysis/python/index.js +7 -2
  96. package/src/scaAnalysis/ruby/analysis.js +16 -4
  97. package/src/scan/autoDetection.js +6 -13
  98. package/src/scan/formatScanOutput.ts +7 -5
  99. package/src/scan/help.js +2 -3
  100. package/src/scan/populateProjectIdAndProjectName.js +5 -1
  101. package/src/scan/scan.ts +4 -0
  102. package/src/scan/scanConfig.js +6 -4
  103. package/src/scan/scanResults.js +52 -3
  104. package/src/telemetry/telemetry.ts +154 -0
  105. package/src/utils/commonApi.js +1 -1
  106. package/src/utils/getConfig.ts +2 -11
  107. package/src/utils/parsedCLIOptions.js +14 -1
  108. package/src/utils/requestUtils.js +8 -1
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  const multiReplace = require('string-multiple-replace');
3
3
  const fs = require('fs');
4
+ const i18n = require('i18n');
4
5
  const readAndParseProjectFile = file => {
5
6
  const filePath = filePathForWindows(file + '/Pipfile');
6
7
  const pipFile = fs.readFileSync(filePath, 'utf8');
@@ -18,11 +19,45 @@ const readAndParseLockFile = file => {
18
19
  delete parsedPipLock['default'];
19
20
  return parsedPipLock;
20
21
  };
21
- const getPythonDeps = config => {
22
+ const readLockFile = file => {
23
+ const filePath = filePathForWindows(file + '/Pipfile.lock');
24
+ const lockFile = fs.readFileSync(filePath, 'utf8');
25
+ let parsedPipLock = JSON.parse(lockFile);
26
+ return parsedPipLock['default'];
27
+ };
28
+ const scaPythonParser = pythonDependencies => {
29
+ let pythonParsedDeps = {};
30
+ for (let key in pythonDependencies) {
31
+ pythonParsedDeps[key] = {};
32
+ pythonParsedDeps[key].version = pythonDependencies[key].version.replace('==', '');
33
+ pythonParsedDeps[key].group = null;
34
+ pythonParsedDeps[key].name = key;
35
+ pythonParsedDeps[key].isProduction = true;
36
+ pythonParsedDeps[key].dependencies = [];
37
+ pythonParsedDeps[key].directDependency = true;
38
+ }
39
+ return pythonParsedDeps;
40
+ };
41
+ const checkForCorrectFiles = languageFiles => {
42
+ if (!languageFiles.includes('Pipfile.lock')) {
43
+ throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'python'));
44
+ }
45
+ if (!languageFiles.includes('Pipfile')) {
46
+ throw new Error(i18n.__('languageAnalysisProjectFileError', 'python'));
47
+ }
48
+ };
49
+ const getPythonDeps = (config, languageFiles) => {
22
50
  try {
23
- const parseProject = readAndParseProjectFile(config.file);
24
- const parsePip = readAndParseLockFile(config.file);
25
- return { pipfileLock: parsePip, pipfilDependanceies: parseProject };
51
+ if (config.experimental) {
52
+ let pythonLockFileContents = readLockFile(config.file);
53
+ return scaPythonParser(pythonLockFileContents);
54
+ }
55
+ else {
56
+ checkForCorrectFiles(languageFiles);
57
+ const parseProject = readAndParseProjectFile(config.file);
58
+ const parsePip = readAndParseLockFile(config.file);
59
+ return { pipfileLock: parsePip, pipfilDependanceies: parseProject };
60
+ }
26
61
  }
27
62
  catch (err) {
28
63
  console.log(err.message.toString());
@@ -37,6 +72,9 @@ const filePathForWindows = path => {
37
72
  };
38
73
  module.exports = {
39
74
  getPythonDeps,
75
+ scaPythonParser,
76
+ readAndParseLockFile,
40
77
  readAndParseProjectFile,
41
- readAndParseLockFile
78
+ checkForCorrectFiles,
79
+ readLockFile
42
80
  };
@@ -1,9 +1,14 @@
1
1
  "use strict";
2
2
  const { createPythonTSMessage } = require('../common/formatMessage');
3
- const { getPythonDeps } = require('./analysis');
3
+ const { getPythonDeps, secondaryParser } = require('./analysis');
4
4
  const pythonAnalysis = (config, languageFiles) => {
5
5
  const pythonDeps = getPythonDeps(config, languageFiles.PYTHON);
6
- return createPythonTSMessage(pythonDeps);
6
+ if (config.experimental) {
7
+ return pythonDeps;
8
+ }
9
+ else {
10
+ return createPythonTSMessage(pythonDeps);
11
+ }
7
12
  };
8
13
  module.exports = {
9
14
  pythonAnalysis
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  const fs = require('fs');
3
+ const i18n = require('i18n');
3
4
  const readAndParseGemfile = file => {
4
5
  const gemFile = fs.readFileSync(file + '/Gemfile', 'utf8');
5
6
  const rubyArray = gemFile.split('\n');
@@ -188,15 +189,23 @@ const buildSourceDependencyWithVersion = (whitespaceRegx, dependencyRegEx, line,
188
189
  }
189
190
  return dependencies;
190
191
  };
191
- const getRubyDeps = config => {
192
+ const getRubyDeps = (config, languageFiles) => {
192
193
  try {
194
+ checkForCorrectFiles(languageFiles);
193
195
  const parsedGem = readAndParseGemfile(config.file);
194
196
  const parsedLock = readAndParseGemLockFile(config.file);
195
197
  return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock };
196
198
  }
197
199
  catch (err) {
198
- console.log(err.message);
199
- process.exit(1);
200
+ throw err;
201
+ }
202
+ };
203
+ const checkForCorrectFiles = languageFiles => {
204
+ if (!languageFiles.includes('Gemfile.lock')) {
205
+ throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'ruby'));
206
+ }
207
+ if (!languageFiles.includes('Gemfile')) {
208
+ throw new Error(i18n.__('languageAnalysisProjectFileError', 'ruby'));
200
209
  }
201
210
  };
202
211
  const trimWhiteSpace = string => {
@@ -214,5 +223,6 @@ module.exports = {
214
223
  getVersion,
215
224
  getPatchLevel,
216
225
  formatSourceArr,
217
- getSourceArray
226
+ getSourceArray,
227
+ checkForCorrectFiles
218
228
  };
@@ -2,6 +2,7 @@
2
2
  const i18n = require('i18n');
3
3
  const fileFinder = require('./fileUtils');
4
4
  const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames');
5
+ const path = require('path');
5
6
  const autoDetectFileAndLanguage = async (configToUse) => {
6
7
  const entries = await fileFinder.findFile();
7
8
  if (entries.length === 1) {
@@ -23,16 +24,9 @@ const autoDetectFileAndLanguage = async (configToUse) => {
23
24
  errorOnFileDetection(entries);
24
25
  }
25
26
  };
26
- const autoDetectAuditFilesAndLanguages = async (file) => {
27
- const filePath = file;
27
+ const autoDetectAuditFilesAndLanguages = async (filePath) => {
28
28
  let languagesFound = [];
29
- if (filePath) {
30
- rootFile.getProjectRootFilenames(filePath);
31
- console.log(i18n.__('searchingAuditFileDirectory', filePath));
32
- }
33
- else {
34
- console.log(i18n.__('searchingAuditFileDirectory', process.cwd()));
35
- }
29
+ console.log(i18n.__('searchingAuditFileDirectory', filePath));
36
30
  await fileFinder.findFilesJava(languagesFound, filePath);
37
31
  await fileFinder.findFilesJavascript(languagesFound, filePath);
38
32
  await fileFinder.findFilesPython(languagesFound, filePath);
@@ -40,12 +34,10 @@ const autoDetectAuditFilesAndLanguages = async (file) => {
40
34
  await fileFinder.findFilesPhp(languagesFound, filePath);
41
35
  await fileFinder.findFilesRuby(languagesFound, filePath);
42
36
  await fileFinder.findFilesDotNet(languagesFound, filePath);
43
- if (languagesFound.length <= 1) {
37
+ if (languagesFound) {
44
38
  return languagesFound;
45
39
  }
46
- else {
47
- console.log('found multiple languages, please specify one using --file to run SCA audit');
48
- }
40
+ return [];
49
41
  };
50
42
  const hasWhiteSpace = s => {
51
43
  const filename = s.split('/').pop();
@@ -53,12 +53,12 @@ function formatScanOutput(scanResults) {
53
53
  });
54
54
  let learnRow = [];
55
55
  let adviceRow = [];
56
+ const headerColour = chalk_1.default.hex(entry.colour);
56
57
  const headerRow = [
57
- chalk_1.default
58
- .hex(entry.colour)
59
- .bold(`CONTRAST-${count.toString().padStart(3, '0')}`),
60
- chalk_1.default.hex(entry.colour).bold('-'),
61
- chalk_1.default.hex(entry.colour).bold(`[${entry.severity}] ${entry.ruleId}`) +
58
+ headerColour(`CONTRAST-${count.toString().padStart(3, '0')}`),
59
+ headerColour(`-`),
60
+ headerColour(`[${entry.severity}] `) +
61
+ headerColour.bold(`${entry.ruleId}`) +
62
62
  entry.message
63
63
  ];
64
64
  const codePath = entry.codePath?.replace(/^@/, '');
@@ -90,6 +90,7 @@ function formatScanOutput(scanResults) {
90
90
  });
91
91
  }
92
92
  printVulnInfo(projectOverview);
93
+ return projectOverview;
93
94
  }
94
95
  exports.formatScanOutput = formatScanOutput;
95
96
  function printVulnInfo(projectOverview) {
package/dist/scan/help.js CHANGED
@@ -2,6 +2,7 @@
2
2
  const commandLineUsage = require('command-line-usage');
3
3
  const i18n = require('i18n');
4
4
  const constants = require('../constants');
5
+ const { commonHelpLinks } = require('../common/commonHelp');
5
6
  const scanUsageGuide = commandLineUsage([
6
7
  {
7
8
  header: i18n.__('scanHeader')
@@ -35,9 +36,7 @@ const scanUsageGuide = commandLineUsage([
35
36
  'application-name'
36
37
  ]
37
38
  },
38
- {
39
- content: '{underline https://www.contrastsecurity.com}'
40
- }
39
+ commonHelpLinks()
41
40
  ]);
42
41
  module.exports = {
43
42
  scanUsageGuide
@@ -25,6 +25,11 @@ const createProjectId = async (config, client) => {
25
25
  process.exit(1);
26
26
  return;
27
27
  }
28
+ if (res.statusCode === 429) {
29
+ console.log(i18n.__('exceededFreeTier'));
30
+ process.exit(1);
31
+ return;
32
+ }
28
33
  if (res.statusCode === 201) {
29
34
  console.log(i18n.__('projectCreatedScan'));
30
35
  if (config.verbose) {
package/dist/scan/scan.js CHANGED
@@ -45,6 +45,10 @@ const sendScan = async (config) => {
45
45
  oraWrapper_1.default.failSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanFail'));
46
46
  console.log(i18n_1.default.__('genericServiceError', res.statusCode));
47
47
  }
48
+ if (res.statusCode === 429) {
49
+ console.log(i18n_1.default.__('exceededFreeTier'));
50
+ process.exit(1);
51
+ }
48
52
  if (res.statusCode === 403) {
49
53
  console.log(i18n_1.default.__('permissionsError'));
50
54
  process.exit(1);
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  const paramHandler = require('../utils/paramsUtil/paramHandler');
3
- const constants = require('../../src/constants.js');
4
- const parsedCLIOptions = require('../../src/utils/parsedCLIOptions');
3
+ const constants = require('../constants.js');
5
4
  const path = require('path');
6
5
  const { supportedLanguagesScan } = require('../constants/constants');
7
6
  const i18n = require('i18n');
8
7
  const { scanUsageGuide } = require('./help');
9
- const getScanConfig = argv => {
10
- let scanParams = parsedCLIOptions.getCommandLineArgsCustom(argv, constants.commandLineDefinitions.scanOptionDefinitions);
8
+ const parsedCLIOptions = require('../utils/parsedCLIOptions');
9
+ const getScanConfig = async (contrastConf, command, argv) => {
10
+ let scanParams = await parsedCLIOptions.getCommandLineArgsCustom(contrastConf, command, argv, constants.commandLineDefinitions.scanOptionDefinitions);
11
11
  if (scanParams.help) {
12
12
  printHelpMessage();
13
13
  process.exit(0);
@@ -5,10 +5,14 @@ const oraFunctions = require('../utils/oraWrapper');
5
5
  const _ = require('lodash');
6
6
  const i18n = require('i18n');
7
7
  const oraWrapper = require('../utils/oraWrapper');
8
+ const readLine = require('readline');
8
9
  const getScanId = async (config, codeArtifactId, client) => {
9
10
  return client
10
11
  .getScanId(config, codeArtifactId)
11
12
  .then(res => {
13
+ if (res.statusCode == 429) {
14
+ throw new Error(i18n.__('exceededFreeTier'));
15
+ }
12
16
  return res.body.id;
13
17
  })
14
18
  .catch(err => {
@@ -61,12 +65,50 @@ const returnScanResults = async (config, codeArtifactId, newProject, timeout, st
61
65
  let endTime = new Date() - startTime;
62
66
  if (requestUtils.millisToSeconds(endTime) > timeout) {
63
67
  oraFunctions.failSpinner(startScanSpinner, 'Contrast Scan timed out at the specified ' + timeout + ' seconds.');
64
- console.log('Please try again, allowing more time.');
65
- process.exit(1);
68
+ const isCI = process.env.CONTRAST_CODESEC_CI
69
+ ? JSON.parse(process.env.CONTRAST_CODESEC_CI)
70
+ : false;
71
+ if (!isCI) {
72
+ const retry = await retryScanPrompt();
73
+ timeout = retry.timeout;
74
+ }
75
+ else {
76
+ console.log('Please try again, allowing more time');
77
+ process.exit(1);
78
+ }
66
79
  }
67
80
  }
68
81
  }
69
82
  };
83
+ const retryScanPrompt = async () => {
84
+ const rl = readLine.createInterface({
85
+ input: process.stdin,
86
+ output: process.stdout
87
+ });
88
+ return new Promise((resolve, reject) => {
89
+ requestUtils.timeOutError(30000, reject);
90
+ rl.question('🔁 Do you want to continue waiting on Scan? [Y/N]\n', async (input) => {
91
+ if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
92
+ console.log('Continuing wait for Scan');
93
+ rl.close();
94
+ resolve({ timeout: 300 });
95
+ }
96
+ else if (input.toLowerCase() === 'no' ||
97
+ input.toLowerCase() === 'n') {
98
+ rl.close();
99
+ console.log('Contrast Scan Retry Cancelled: Exiting');
100
+ resolve(process.exit(1));
101
+ }
102
+ else {
103
+ rl.close();
104
+ console.log('Invalid Input: Exiting');
105
+ resolve(process.exit(1));
106
+ }
107
+ });
108
+ }).catch(e => {
109
+ throw e;
110
+ });
111
+ };
70
112
  const returnScanResultsInstances = async (config, scanId) => {
71
113
  const client = commonApi.getHttpClient(config);
72
114
  let result;
@@ -89,5 +131,6 @@ module.exports = {
89
131
  getScanId: getScanId,
90
132
  returnScanResults: returnScanResults,
91
133
  pollScanResults: pollScanResults,
92
- returnScanResultsInstances: returnScanResultsInstances
134
+ returnScanResultsInstances: returnScanResultsInstances,
135
+ retryScanPrompt
93
136
  };
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.sha1Base64Value = exports.findParamValueFromArgs = exports.paramExists = exports.obfuscateParams = exports.sendTelemetryRequest = exports.sendTelemetryConfigAsObject = exports.sendTelemetryConfigAsConfObj = exports.TELEMETRY_CLI_TIME_TO_AUTH_EVENT = exports.TELEMETRY_CLI_COMMANDS_EVENT = void 0;
27
+ const commonApi_1 = require("../utils/commonApi");
28
+ const crypto = __importStar(require("crypto"));
29
+ exports.TELEMETRY_CLI_COMMANDS_EVENT = 'CLI_COMMANDS';
30
+ exports.TELEMETRY_CLI_TIME_TO_AUTH_EVENT = 'CLI_TIME_TO_AUTH';
31
+ const sendTelemetryConfigAsConfObj = async (config, command, argv, result, language) => {
32
+ const hostParam = '--host';
33
+ const hostParamAlias = '-h';
34
+ const orgIdParam = '--organization-id';
35
+ const orgIdParamAlias = '-o';
36
+ const authParam = '--authorization';
37
+ const apiKeyParam = '--api-key';
38
+ let configToUse;
39
+ if ((0, exports.paramExists)(argv, hostParam, hostParamAlias) &&
40
+ (0, exports.paramExists)(argv, orgIdParam, orgIdParamAlias) &&
41
+ (0, exports.paramExists)(argv, authParam, null) &&
42
+ (0, exports.paramExists)(argv, apiKeyParam, null)) {
43
+ configToUse = {
44
+ host: (0, exports.findParamValueFromArgs)(argv, hostParam, hostParamAlias),
45
+ organizationId: (0, exports.findParamValueFromArgs)(argv, orgIdParam, orgIdParamAlias),
46
+ authorization: (0, exports.findParamValueFromArgs)(argv, authParam, null),
47
+ apiKey: (0, exports.findParamValueFromArgs)(argv, apiKeyParam, null)
48
+ };
49
+ }
50
+ else if (config &&
51
+ config.get('host') &&
52
+ config.get('organizationId') &&
53
+ config.get('authorization') &&
54
+ config.get('apiKey')) {
55
+ configToUse = {
56
+ host: config.get('host')?.slice(0, -1),
57
+ organizationId: config.get('organizationId'),
58
+ authorization: config.get('authorization'),
59
+ apiKey: config.get('apiKey')
60
+ };
61
+ }
62
+ else {
63
+ return;
64
+ }
65
+ return await (0, exports.sendTelemetryConfigAsObject)(configToUse, command, argv, result, language);
66
+ };
67
+ exports.sendTelemetryConfigAsConfObj = sendTelemetryConfigAsConfObj;
68
+ const sendTelemetryConfigAsObject = async (config, command, argv, result, language) => {
69
+ const obfuscatedParams = (0, exports.obfuscateParams)(argv);
70
+ const requestBody = {
71
+ event: exports.TELEMETRY_CLI_COMMANDS_EVENT,
72
+ details: {
73
+ ip_address: '',
74
+ account_name: '',
75
+ account_host: '',
76
+ company_domain: '',
77
+ command: `contrast ${command} ${obfuscatedParams}`,
78
+ app_id: config && config.applicationId
79
+ ? (0, exports.sha1Base64Value)(config.applicationId)
80
+ : 'undefined',
81
+ project_id: config && config.projectId
82
+ ? (0, exports.sha1Base64Value)(config.projectId)
83
+ : 'undefined',
84
+ language: language,
85
+ result: result,
86
+ additional_info: '',
87
+ timestamp: new Date().toUTCString()
88
+ }
89
+ };
90
+ return await (0, exports.sendTelemetryRequest)(config, requestBody);
91
+ };
92
+ exports.sendTelemetryConfigAsObject = sendTelemetryConfigAsObject;
93
+ const sendTelemetryRequest = async (config, requestBody) => {
94
+ const client = (0, commonApi_1.getHttpClient)(config);
95
+ return client
96
+ .postTelemetry(config, requestBody)
97
+ .then((res) => {
98
+ if (res.statusCode !== 200 && config.debug === true) {
99
+ console.log('Telemetry failed to send with status', res.statusCode);
100
+ }
101
+ return { statusCode: res.statusCode, statusMessage: res.statusMessage };
102
+ })
103
+ .catch((err) => {
104
+ return;
105
+ });
106
+ };
107
+ exports.sendTelemetryRequest = sendTelemetryRequest;
108
+ const obfuscateParams = (argv) => {
109
+ return argv
110
+ .join(' ')
111
+ .replace(/--(authorization [A-Z0-9]+)/gi, '--authorization *****')
112
+ .replace(/-(o [A-Z0-9-]+)/gi, '-o *****')
113
+ .replace(/--(organization-id [A-Z0-9-]+)/gi, '--organization-id *****')
114
+ .replace(/--(api-key [A-Z0-9]+)/gi, '--api-key *****');
115
+ };
116
+ exports.obfuscateParams = obfuscateParams;
117
+ const paramExists = (argv, param, paramAlias) => {
118
+ return argv.find((arg) => arg === param || arg === paramAlias);
119
+ };
120
+ exports.paramExists = paramExists;
121
+ const findParamValueFromArgs = (argv, param, paramAlias) => {
122
+ let paramAsValue;
123
+ argv.forEach((arg, index) => {
124
+ if (arg === param ||
125
+ (arg === paramAlias &&
126
+ argv[index + 1] !== undefined &&
127
+ argv[index + 1] !== null)) {
128
+ paramAsValue = argv[index + 1];
129
+ }
130
+ });
131
+ return paramAsValue;
132
+ };
133
+ exports.findParamValueFromArgs = findParamValueFromArgs;
134
+ const sha1Base64Value = (value) => {
135
+ return crypto.createHash('sha1').update(value).digest('base64');
136
+ };
137
+ exports.sha1Base64Value = sha1Base64Value;
@@ -18,7 +18,7 @@ const handleResponseErrors = (res, api) => {
18
18
  maxAppError();
19
19
  }
20
20
  else {
21
- genericError();
21
+ genericError(res);
22
22
  }
23
23
  };
24
24
  const getProtocol = host => {
@@ -5,16 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.setConfigValues = exports.localConfig = void 0;
7
7
  const conf_1 = __importDefault(require("conf"));
8
+ const constants_1 = require("../constants/constants");
8
9
  const localConfig = (name, version) => {
9
10
  const config = new conf_1.default({
10
11
  configName: name
11
12
  });
12
13
  config.set('version', version);
13
- if (process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE) {
14
- config.set('updateMessageHidden', JSON.parse(process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE.toLowerCase()));
15
- }
16
14
  if (!config.has('host')) {
17
- config.set('host', 'https://ce.contrastsecurity.com/');
15
+ config.set('host', constants_1.CE_URL);
18
16
  }
19
17
  return config;
20
18
  };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  const commandLineArgs = require('command-line-args');
3
- const getCommandLineArgsCustom = (parameterList, optionDefinitions) => {
3
+ const { sendTelemetryConfigAsConfObj } = require('../telemetry/telemetry');
4
+ const getCommandLineArgsCustom = async (contrastConf, command, parameterList, optionDefinitions) => {
4
5
  try {
5
6
  return commandLineArgs(optionDefinitions, {
6
7
  argv: parameterList,
@@ -10,6 +11,7 @@ const getCommandLineArgsCustom = (parameterList, optionDefinitions) => {
10
11
  });
11
12
  }
12
13
  catch (e) {
14
+ await sendTelemetryConfigAsConfObj(contrastConf, command, parameterList, 'FAILURE', 'undefined');
13
15
  console.log(e.message.toString());
14
16
  process.exit(1);
15
17
  }
@@ -11,8 +11,14 @@ const millisToSeconds = millis => {
11
11
  const sleep = ms => {
12
12
  return new Promise(resolve => setTimeout(resolve, ms));
13
13
  };
14
+ const timeOutError = (ms, reject) => {
15
+ return setTimeout(() => {
16
+ reject(new Error(`No input detected after 30s`));
17
+ }, ms);
18
+ };
14
19
  module.exports = {
15
20
  sendRequest: sendRequest,
16
21
  sleep: sleep,
17
- millisToSeconds: millisToSeconds
22
+ millisToSeconds: millisToSeconds,
23
+ timeOutError: timeOutError
18
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/contrast",
3
- "version": "1.0.9",
3
+ "version": "1.0.12",
4
4
  "description": "Contrast Security's command line tool",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -23,7 +23,9 @@
23
23
  "test": "jest --testPathIgnorePatterns=./test-integration/",
24
24
  "test-int": "jest ./test-integration/",
25
25
  "test-int-scan": "jest ./test-integration/scan",
26
- "test-int-audit": "jest test-integration/audit/audit-int.spec.js",
26
+ "test-int-audit": "jest test-integration/audit",
27
+ "test-int-audit-reports": "jest test-integration/audit/audit-language-reports.spec.js",
28
+ "test-int-audit-features": "jest test-integration/audit/auditFeatures/",
27
29
  "format": "prettier --write \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
28
30
  "check-format": "prettier --check \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
29
31
  "coverage-local": "nyc --reporter=text mocha './test/**/*.spec.js'",
@@ -2,42 +2,35 @@ const fs = require('fs')
2
2
  const path = require('path')
3
3
  const i18n = require('i18n')
4
4
 
5
- const getProjectRootFilenames = file => {
6
- let projectStats = null
5
+ const getDirectoryFromPathGiven = file => {
6
+ let projectStats = getProjectStats(file)
7
+
8
+ if (projectStats.isFile()) {
9
+ let newPath = path.resolve(file)
10
+ return path.dirname(newPath)
11
+ }
12
+
13
+ if (projectStats.isDirectory()) {
14
+ return file
15
+ }
16
+ }
17
+
18
+ const getProjectStats = file => {
7
19
  try {
8
- projectStats = fs.statSync(file)
20
+ //might not need this
21
+ if (file.endsWith('/')) {
22
+ file = file.slice(0, -1)
23
+ }
24
+ return fs.statSync(file)
9
25
  } catch (err) {
10
26
  throw new Error(
11
27
  i18n.__('languageAnalysisProjectRootFileNameFailure', file) +
12
28
  `${err.message}`
13
29
  )
14
30
  }
15
-
16
- // Return the contents of a directory...
17
- if (projectStats.isDirectory()) {
18
- try {
19
- return fs.readdirSync(file)
20
- } catch (err) {
21
- throw new Error(
22
- i18n.__('languageAnalysisProjectRootFileNameReadError', file) +
23
- `${err.message}`
24
- )
25
- }
26
- }
27
-
28
- // If we are working with a file return it in a list as we do when we work
29
- // with a directory...
30
- if (projectStats.isFile()) {
31
- return [path.basename(file)]
32
- }
33
-
34
- // Error out if we are working with something like a socket file or some
35
- // other craziness...
36
- throw new Error(
37
- i18n.__('languageAnalysisProjectRootFileNameMissingError'),
38
- file
39
- )
40
31
  }
32
+
41
33
  module.exports = {
42
- getProjectRootFilenames
34
+ getProjectStats,
35
+ getDirectoryFromPathGiven: getDirectoryFromPathGiven
43
36
  }