@contrast/contrast 1.0.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.
Files changed (88) hide show
  1. package/README.md +109 -0
  2. package/bin/contrast.js +2 -0
  3. package/dist/commands/auth/auth.js +61 -0
  4. package/dist/commands/config/config.js +24 -0
  5. package/dist/commands/scan/processScan.js +23 -0
  6. package/dist/common/HTTPClient.js +192 -0
  7. package/dist/common/errorHandling.js +60 -0
  8. package/dist/constants/constants.js +30 -0
  9. package/dist/constants/lambda.js +31 -0
  10. package/dist/constants/locales.js +259 -0
  11. package/dist/constants.js +150 -0
  12. package/dist/index.js +56 -0
  13. package/dist/lambda/__mocks__/aws.js +21 -0
  14. package/dist/lambda/__mocks__/lambdaConfig.json +42 -0
  15. package/dist/lambda/arn.js +21 -0
  16. package/dist/lambda/aws.js +169 -0
  17. package/dist/lambda/cliError.js +76 -0
  18. package/dist/lambda/constants.js +11 -0
  19. package/dist/lambda/help.js +75 -0
  20. package/dist/lambda/lambda.js +130 -0
  21. package/dist/lambda/logUtils.js +36 -0
  22. package/dist/lambda/scanDetail.js +30 -0
  23. package/dist/lambda/scanDetailCompletion.js +56 -0
  24. package/dist/lambda/scanRequest.js +93 -0
  25. package/dist/lambda/scanResults.js +16 -0
  26. package/dist/lambda/utils.js +90 -0
  27. package/dist/scan/autoDetection.js +76 -0
  28. package/dist/scan/fileFinder.js +15 -0
  29. package/dist/scan/fileUtils.js +31 -0
  30. package/dist/scan/help.js +68 -0
  31. package/dist/scan/populateProjectIdAndProjectName.js +55 -0
  32. package/dist/scan/scan.js +96 -0
  33. package/dist/scan/scanController.js +54 -0
  34. package/dist/scan/scanResults.js +85 -0
  35. package/dist/utils/commonApi.js +45 -0
  36. package/dist/utils/filterProjectPath.js +20 -0
  37. package/dist/utils/getConfig.js +30 -0
  38. package/dist/utils/oraWrapper.js +20 -0
  39. package/dist/utils/paramsUtil/commandlineParams.js +31 -0
  40. package/dist/utils/paramsUtil/configStoreParams.js +18 -0
  41. package/dist/utils/paramsUtil/envVariableParams.js +10 -0
  42. package/dist/utils/paramsUtil/paramHandler.js +28 -0
  43. package/dist/utils/paramsUtil/yamlParams.js +6 -0
  44. package/dist/utils/parsedCLIOptions.js +13 -0
  45. package/dist/utils/requestUtils.js +18 -0
  46. package/dist/utils/validationCheck.js +26 -0
  47. package/package.json +123 -0
  48. package/src/commands/auth/auth.js +73 -0
  49. package/src/commands/config/config.js +25 -0
  50. package/src/commands/scan/processScan.js +29 -0
  51. package/src/common/HTTPClient.js +269 -0
  52. package/src/common/errorHandling.ts +79 -0
  53. package/src/constants/constants.js +34 -0
  54. package/src/constants/lambda.js +41 -0
  55. package/src/constants/locales.js +381 -0
  56. package/src/constants.js +168 -0
  57. package/src/index.ts +69 -0
  58. package/src/lambda/__mocks__/aws.ts +32 -0
  59. package/src/lambda/__mocks__/lambdaConfig.json +42 -0
  60. package/src/lambda/arn.ts +32 -0
  61. package/src/lambda/aws.ts +247 -0
  62. package/src/lambda/cliError.ts +72 -0
  63. package/src/lambda/constants.ts +11 -0
  64. package/src/lambda/help.ts +76 -0
  65. package/src/lambda/lambda.ts +174 -0
  66. package/src/lambda/logUtils.ts +46 -0
  67. package/src/lambda/scanDetailCompletion.ts +78 -0
  68. package/src/lambda/scanRequest.ts +142 -0
  69. package/src/lambda/scanResults.ts +29 -0
  70. package/src/lambda/utils.ts +125 -0
  71. package/src/scan/autoDetection.js +77 -0
  72. package/src/scan/fileUtils.js +33 -0
  73. package/src/scan/help.js +74 -0
  74. package/src/scan/populateProjectIdAndProjectName.js +62 -0
  75. package/src/scan/scan.js +126 -0
  76. package/src/scan/scanController.js +69 -0
  77. package/src/scan/scanResults.js +96 -0
  78. package/src/utils/commonApi.js +54 -0
  79. package/src/utils/filterProjectPath.js +21 -0
  80. package/src/utils/getConfig.ts +42 -0
  81. package/src/utils/oraWrapper.js +24 -0
  82. package/src/utils/paramsUtil/commandlineParams.js +37 -0
  83. package/src/utils/paramsUtil/configStoreParams.js +19 -0
  84. package/src/utils/paramsUtil/envVariableParams.js +10 -0
  85. package/src/utils/paramsUtil/paramHandler.js +28 -0
  86. package/src/utils/parsedCLIOptions.js +17 -0
  87. package/src/utils/requestUtils.js +22 -0
  88. package/src/utils/validationCheck.js +34 -0
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getScanResults = void 0;
4
+ const commonApi_1 = require("../utils/commonApi");
5
+ const cliError_1 = require("./cliError");
6
+ const constants_1 = require("./constants");
7
+ const getScanResults = async (config, params, scanId, functionArn) => {
8
+ const client = (0, commonApi_1.getHttpClient)(config);
9
+ const { statusCode, body } = await client.getFunctionScanResults(config, params, scanId, functionArn);
10
+ if (statusCode === 200) {
11
+ return body;
12
+ }
13
+ const { errorCode } = body || {};
14
+ throw new cliError_1.CliError(constants_1.ERRORS.FAILED_TO_GET_RESULTS, { statusCode, errorCode });
15
+ };
16
+ exports.getScanResults = getScanResults;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.exportedForTesting = exports.prettyPrintResults = exports.toLowerKeys = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const lodash_1 = require("lodash");
9
+ const logUtils_1 = require("./logUtils");
10
+ const groupByCVE = ({ title }) => title.substring(0, title.indexOf('[') - 1);
11
+ const groupByDependency = ({ title }) => title.substring(title.indexOf('[') + 1, title.indexOf(']'));
12
+ const prettyPrintResults = (results) => {
13
+ (0, logUtils_1.log)('');
14
+ const vulnerabs = results.filter(r => r.category === 1 || r.category === 4);
15
+ const sortBySeverity = (0, lodash_1.sortBy)(vulnerabs, ['severity', 'title']);
16
+ const notDependencies = sortBySeverity.filter(r => r.category !== 1);
17
+ const dependencies = sortBySeverity.filter(r => r.category === 1);
18
+ const dependenciesByLibrary = (0, lodash_1.groupBy)(dependencies, groupByDependency);
19
+ const dependenciesCount = Object.keys(dependenciesByLibrary).length;
20
+ notDependencies.forEach(printVulnerability);
21
+ const prevIndex = notDependencies.length + 1;
22
+ Object.entries(dependenciesByLibrary).forEach(([library, group], i) => {
23
+ const maxSeverity = (0, lodash_1.minBy)(group, 'severity');
24
+ const allCves = group.map(groupByCVE);
25
+ (0, logUtils_1.log)(prevIndex + i);
26
+ (0, logUtils_1.log)(`${chalk_1.default.bold((0, lodash_1.capitalize)(maxSeverity.severityText))} | ${chalk_1.default.bold('Vulnerable dependency')} ${library} has ${group.length} known CVEs`);
27
+ (0, logUtils_1.log)(allCves.join(', '));
28
+ if (maxSeverity.remediation?.description) {
29
+ (0, logUtils_1.log)(`${chalk_1.default.bold('Recommendation:')} ${maxSeverity.remediation.description}`);
30
+ }
31
+ (0, logUtils_1.log)('');
32
+ });
33
+ const resultCount = notDependencies.length + dependenciesCount;
34
+ const groupByType = (0, lodash_1.groupBy)(notDependencies, ['categoryText']);
35
+ const summary = Object.values(groupByType).map(group => `${group.length} ${(0, lodash_1.capitalize)(group[0].categoryText)}`);
36
+ (0, logUtils_1.log)(`Found ${resultCount} vulnerabilities`, { bold: true });
37
+ summary.push(`${dependenciesCount} Dependencies`);
38
+ (0, logUtils_1.log)(chalk_1.default.bold(summary.join(' | ')));
39
+ };
40
+ exports.prettyPrintResults = prettyPrintResults;
41
+ const underlineLinks = (text) => {
42
+ if (!text) {
43
+ return text;
44
+ }
45
+ const urlRegex = /(https?:\/\/[^\s]+)/g;
46
+ return text.replace(urlRegex, chalk_1.default.underline('$1'));
47
+ };
48
+ const printVulnerability = (vulnerability, index) => {
49
+ (0, logUtils_1.log)(index + 1);
50
+ const descriptionWithLinks = underlineLinks(vulnerability.description);
51
+ (0, logUtils_1.log)(`${chalk_1.default.bold((0, lodash_1.capitalize)(vulnerability.severityText))} | ${chalk_1.default.bold(vulnerability.title)} ${descriptionWithLinks}`);
52
+ const category = vulnerability?.categoryText;
53
+ switch (category) {
54
+ case 'PERMISSIONS':
55
+ printLeastPrivilegeRemediation(vulnerability);
56
+ break;
57
+ default:
58
+ printRemediation(vulnerability);
59
+ }
60
+ (0, logUtils_1.log)('');
61
+ };
62
+ const printLeastPrivilegeRemediation = (vulnerability) => {
63
+ (0, logUtils_1.log)(`${chalk_1.default.bold('Recommendation:')} Replace the existing policies with the following`);
64
+ const violatingPolicies = vulnerability?.evidence?.leastPrivilege?.violatingPolicies || [];
65
+ violatingPolicies
66
+ .filter((vp) => vp?.suggestedPolicy?.suggestedPolicyCode?.length)
67
+ .map((vp) => vp?.suggestedPolicy?.suggestedPolicyCode)
68
+ .forEach((policies) => {
69
+ policies.forEach((policy) => {
70
+ console.log(policy.snippet);
71
+ });
72
+ });
73
+ };
74
+ const printRemediation = (vulnerability) => {
75
+ (0, logUtils_1.log)(`Remediation - ${vulnerability?.remediation?.description || 'Unknown'}`);
76
+ };
77
+ function toLowerKeys(obj) {
78
+ return Object.keys(obj).reduce((accumulator, key) => {
79
+ const new_key = `${key[0].toLowerCase()}${key.slice(1)}`;
80
+ accumulator[new_key] = obj[key];
81
+ return accumulator;
82
+ }, {});
83
+ }
84
+ exports.toLowerKeys = toLowerKeys;
85
+ exports.exportedForTesting = {
86
+ printLeastPrivilegeRemediation,
87
+ printRemediation,
88
+ printVulnerability,
89
+ underlineLinks
90
+ };
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ const i18n = require('i18n');
3
+ const { zipValidator } = require('./scan');
4
+ const fileFinder = require('./fileUtils');
5
+ const { supportedLanguages } = require('../constants/constants');
6
+ const autoDetectFileAndLanguage = async (configToUse) => {
7
+ const entries = await fileFinder.findFile();
8
+ if (entries.length === 1) {
9
+ console.log(i18n.__('foundScanFile', entries[0]));
10
+ if (hasWhiteSpace(entries[0])) {
11
+ console.log(i18n.__('fileHasWhiteSpacesError'));
12
+ process.exit(1);
13
+ }
14
+ configToUse.file = entries[0];
15
+ if (configToUse.name === undefined) {
16
+ configToUse.name = entries[0];
17
+ }
18
+ zipValidator(configToUse);
19
+ assignLanguage(entries, configToUse);
20
+ }
21
+ else {
22
+ errorOnFileDetection(entries);
23
+ }
24
+ };
25
+ const hasWhiteSpace = s => {
26
+ const filename = s.split('/').pop();
27
+ return filename.indexOf(' ') >= 0;
28
+ };
29
+ const errorOnFileDetection = entries => {
30
+ if (entries.length > 1) {
31
+ console.log(i18n.__('searchingDirectoryScan'));
32
+ for (let file in entries) {
33
+ console.log('-', entries[file]);
34
+ }
35
+ console.log('');
36
+ console.log(i18n.__('specifyFileScanError'));
37
+ }
38
+ else {
39
+ console.log(i18n.__('noFileFoundScan'));
40
+ console.log('');
41
+ console.log(i18n.__('specifyFileScanError'));
42
+ }
43
+ process.exit(1);
44
+ };
45
+ const assignLanguage = (entries, configToUse) => {
46
+ let split = entries[0].split('.');
47
+ const fileType = split[split.length - 1];
48
+ if (fileType === 'war' || fileType === 'jar') {
49
+ console.log('Language is Java');
50
+ configToUse.language = 'JAVA';
51
+ }
52
+ else if (fileType === 'dll') {
53
+ console.log('Language is Dotnet');
54
+ configToUse.language = 'DOTNET';
55
+ }
56
+ else if (fileType === 'js') {
57
+ console.log('Language is Javascript');
58
+ configToUse.language = supportedLanguages.JAVASCRIPT;
59
+ }
60
+ else if (fileType === 'zip') {
61
+ if (configToUse.language !== supportedLanguages.JAVASCRIPT) {
62
+ console.log(i18n.__('zipErrorScan'));
63
+ process.exit(1);
64
+ }
65
+ console.log('Language is Javascript within zip file');
66
+ }
67
+ else {
68
+ console.log(i18n.__('unknownFileErrorScan'));
69
+ process.exit(1);
70
+ }
71
+ };
72
+ module.exports = {
73
+ autoDetectFileAndLanguage,
74
+ assignLanguage,
75
+ errorOnFileDetection
76
+ };
@@ -0,0 +1,15 @@
1
+ 'use strict'
2
+ const fg = require('fast-glob')
3
+ const i18n = require('i18n')
4
+ const findFile = async () => {
5
+ console.log(i18n.__('searchingScanFileDirectory', process.cwd()))
6
+ const entries = fg(['**/*.jar', '**/*.war', '**/*.zip', '**/*.dll'], {
7
+ dot: false,
8
+ deep: 3,
9
+ onlyFiles: true
10
+ })
11
+ return entries
12
+ }
13
+ module.exports = {
14
+ findFile
15
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ const fg = require('fast-glob');
3
+ const fs = require('fs');
4
+ const i18n = require('i18n');
5
+ const findFile = async () => {
6
+ console.log(i18n.__('searchingScanFileDirectory', process.cwd()));
7
+ return fg(['**/*.jar', '**/*.war', '**/*.zip', '**/*.dll'], {
8
+ dot: false,
9
+ deep: 3,
10
+ onlyFiles: true
11
+ });
12
+ };
13
+ const checkFilePermissions = file => {
14
+ let readableFile = false;
15
+ try {
16
+ fs.accessSync(file, fs.constants.R_OK);
17
+ return (readableFile = true);
18
+ }
19
+ catch (err) {
20
+ console.log('Invalid permissions found on ', file);
21
+ process.exit(0);
22
+ }
23
+ };
24
+ const fileExists = path => {
25
+ return fs.existsSync(path);
26
+ };
27
+ module.exports = {
28
+ findFile,
29
+ fileExists,
30
+ checkFilePermissions
31
+ };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ const commandLineUsage = require('command-line-usage');
3
+ const i18n = require('i18n');
4
+ const scanUsageGuide = commandLineUsage([
5
+ {
6
+ header: i18n.__('scanHeader')
7
+ },
8
+ {
9
+ header: i18n.__('constantsPrerequisitesHeader'),
10
+ content: [
11
+ '{bold ' + i18n.__('constantsPrerequisitesContentScanLanguages') + '}',
12
+ i18n.__('constantsPrerequisitesContent'),
13
+ '',
14
+ i18n.__('constantsUsageCommandInfo'),
15
+ i18n.__('constantsUsageCommandInfo24Hours')
16
+ ]
17
+ },
18
+ {
19
+ header: i18n.__('constantsScanOptions'),
20
+ content: [
21
+ {
22
+ name: i18n.__('scanOptionsFileName'),
23
+ summary: '{italic ' +
24
+ i18n.__('constantsOptional') +
25
+ '}: ' +
26
+ i18n.__('scanOptionsFileNameSummary')
27
+ },
28
+ {
29
+ name: i18n.__('scanOptionsLanguage'),
30
+ summary: '{italic ' +
31
+ i18n.__('constantsOptional') +
32
+ '}: ' +
33
+ i18n.__('scanOptionsLanguageSummaryOptional') +
34
+ '{italic ' +
35
+ i18n.__('constantsRequired') +
36
+ '}: ' +
37
+ i18n.__('scanOptionsLanguageSummaryRequired')
38
+ },
39
+ {
40
+ name: i18n.__('scanOptionsName'),
41
+ summary: '{italic ' +
42
+ i18n.__('constantsOptional') +
43
+ '}: ' +
44
+ i18n.__('scanOptionsNameSummary')
45
+ },
46
+ {
47
+ name: i18n.__('scanOptionsTimeout'),
48
+ summary: '{italic ' +
49
+ i18n.__('constantsOptional') +
50
+ '}: ' +
51
+ i18n.__('scanOptionsTimeoutSummary')
52
+ },
53
+ {
54
+ name: i18n.__('scanOptionsVerbose'),
55
+ summary: '{italic ' +
56
+ i18n.__('constantsOptional') +
57
+ '}: ' +
58
+ i18n.__('scanOptionsVerboseSummary')
59
+ }
60
+ ]
61
+ },
62
+ {
63
+ content: '{underline https://www.contrastsecurity.com}'
64
+ }
65
+ ]);
66
+ module.exports = {
67
+ scanUsageGuide
68
+ };
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ const commonApi = require('../utils/commonApi.js');
3
+ const i18n = require('i18n');
4
+ const populateProjectId = async (config) => {
5
+ const client = commonApi.getHttpClient(config);
6
+ let proj = await createProjectId(config, client);
7
+ if (proj === undefined) {
8
+ proj = await getExistingProjectIdByName(config, client).then(res => {
9
+ return res;
10
+ });
11
+ }
12
+ return proj;
13
+ };
14
+ const createProjectId = async (config, client) => {
15
+ return client
16
+ .createProjectId(config)
17
+ .then(res => {
18
+ if (res.statusCode === 409) {
19
+ console.log(i18n.__('foundExistingProjectScan'));
20
+ return;
21
+ }
22
+ if (res.statusCode === 201) {
23
+ console.log(i18n.__('projectCreatedScan'));
24
+ if (config.verbose) {
25
+ console.log(i18n.__('populateProjectIdMessage', res.body.id));
26
+ }
27
+ return res.body.id;
28
+ }
29
+ })
30
+ .catch(err => {
31
+ if (config.verbose) {
32
+ console.log(err);
33
+ }
34
+ console.log(i18n.__('connectionError'));
35
+ process.exit(0);
36
+ });
37
+ };
38
+ const getExistingProjectIdByName = async (config, client) => {
39
+ return client
40
+ .getProjectIdByName(config)
41
+ .then(res => {
42
+ if (res.statusCode === 200) {
43
+ if (config.verbose) {
44
+ console.log(i18n.__('populateProjectIdMessage', res.body.content[0].id));
45
+ }
46
+ return res.body.content[0].id;
47
+ }
48
+ })
49
+ .catch(err => {
50
+ console.log(err);
51
+ });
52
+ };
53
+ module.exports = {
54
+ populateProjectId: populateProjectId
55
+ };
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ const commonApi = require('../utils/commonApi.js');
3
+ const fileUtils = require('../scan/fileUtils');
4
+ const allowedFileTypes = ['.jar', '.war', '.js', '.zip'];
5
+ const i18n = require('i18n');
6
+ const AdmZip = require('adm-zip');
7
+ const oraWrapper = require('../utils/oraWrapper');
8
+ const { supportedLanguages } = require('../constants/constants');
9
+ const isFileAllowed = scanOption => {
10
+ let valid = false;
11
+ allowedFileTypes.forEach(fileType => {
12
+ if (scanOption.endsWith(fileType)) {
13
+ valid = true;
14
+ }
15
+ });
16
+ return valid;
17
+ };
18
+ const sendScan = async (config) => {
19
+ if (!isFileAllowed(config.file)) {
20
+ console.log(i18n.__('scanErrorFileMessage'));
21
+ process.exit(9);
22
+ }
23
+ else {
24
+ fileUtils.checkFilePermissions(config.file);
25
+ const client = commonApi.getHttpClient(config);
26
+ const startUploadSpinner = oraWrapper.returnOra(i18n.__('uploadingScan'));
27
+ oraWrapper.startSpinner(startUploadSpinner);
28
+ return await client
29
+ .sendArtifact(config)
30
+ .then(res => {
31
+ if (res.statusCode === 201) {
32
+ oraWrapper.succeedSpinner(startUploadSpinner, i18n.__('uploadingScanSuccessful'));
33
+ if (config.verbose) {
34
+ console.log(i18n.__('responseMessage', res.body));
35
+ }
36
+ return res.body.id;
37
+ }
38
+ else {
39
+ oraWrapper.failSpinner(startUploadSpinner, i18n.__('uploadingScanFail'));
40
+ process.exit(1);
41
+ }
42
+ })
43
+ .catch(err => {
44
+ console.log(err);
45
+ });
46
+ }
47
+ };
48
+ const zipValidator = configToUse => {
49
+ if (configToUse.file.endsWith('.zip')) {
50
+ let zipFileName = configToUse.file.split('/').pop();
51
+ try {
52
+ let zip = new AdmZip(configToUse.file);
53
+ let zipEntries = zip.getEntries();
54
+ zipEntries.forEach(function (zipEntry) {
55
+ if (!zipEntry.entryName.includes('._') &&
56
+ !zipEntry.entryName.includes('/.')) {
57
+ if (!zipEntry.isDirectory) {
58
+ if (!zipEntry.entryName.endsWith('.js')) {
59
+ console.log(i18n.__('scanZipError', zipFileName));
60
+ process.exit(1);
61
+ }
62
+ }
63
+ }
64
+ });
65
+ configToUse.language = supportedLanguages.JAVASCRIPT;
66
+ }
67
+ catch {
68
+ console.log(i18n.__('zipFileException'));
69
+ }
70
+ }
71
+ };
72
+ const formatScanOutput = (overview, results) => {
73
+ console.log();
74
+ console.log('Here are your top priorities to fix');
75
+ console.log();
76
+ results.content.forEach(entry => {
77
+ console.log(entry.severity, 'ID:', entry.id);
78
+ console.log(entry.ruleId, 'in', entry.locations[0]?.physicalLocation.artifactLocation.uri, '@', entry.codeFlows[0]?.threadFlows[0]?.locations[0]?.location
79
+ ?.physicalLocation?.region?.startLine);
80
+ console.log();
81
+ });
82
+ const totalVulnerabilities = overview.critical +
83
+ overview.high +
84
+ overview.medium +
85
+ overview.low +
86
+ overview.note;
87
+ console.log(`Found ${totalVulnerabilities} vulnerabilities`);
88
+ console.log(i18n.__('foundDetailedVulnerabilities', overview.critical, overview.high, overview.medium, overview.low, overview.note));
89
+ };
90
+ module.exports = {
91
+ sendScan: sendScan,
92
+ allowedFileTypes: allowedFileTypes,
93
+ isFileAllowed: isFileAllowed,
94
+ formatScanOutput: formatScanOutput,
95
+ zipValidator: zipValidator
96
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ const i18n = require('i18n');
3
+ const { returnOra, startSpinner, succeedSpinner } = require('../utils/oraWrapper');
4
+ const populateProjectIdAndProjectName = require('./populateProjectIdAndProjectName');
5
+ const scan = require('./scan');
6
+ const scanResults = require('./scanResults');
7
+ const autoDetection = require('./autoDetection');
8
+ const paramHandler = require('../utils/paramsUtil/paramHandler');
9
+ const fileFunctions = require('./fileUtils');
10
+ const getTimeout = config => {
11
+ if (config.timeout) {
12
+ return config.timeout;
13
+ }
14
+ else {
15
+ if (config.verbose) {
16
+ console.log('Timeout set to 5 minutes');
17
+ }
18
+ return 300;
19
+ }
20
+ };
21
+ const startScan = async () => {
22
+ let paramsAuth = paramHandler.getAuth();
23
+ let getScanSubCommands = paramHandler.getScanSubCommands();
24
+ const configToUse = { ...paramsAuth, ...getScanSubCommands };
25
+ if (configToUse.file === undefined || configToUse.file === null) {
26
+ await autoDetection.autoDetectFileAndLanguage(configToUse);
27
+ }
28
+ else {
29
+ if (fileFunctions.fileExists(configToUse.file)) {
30
+ scan.zipValidator(configToUse);
31
+ autoDetection.assignLanguage([configToUse.file], configToUse);
32
+ }
33
+ else {
34
+ console.log(i18n.__('fileNotExist'));
35
+ process.exit(0);
36
+ }
37
+ }
38
+ if (!configToUse.projectId) {
39
+ configToUse.projectId = await populateProjectIdAndProjectName.populateProjectId(configToUse);
40
+ }
41
+ const codeArtifactId = await scan.sendScan(configToUse);
42
+ if (!configToUse.ff) {
43
+ const startScanSpinner = returnOra('Contrast Scan started');
44
+ startSpinner(startScanSpinner);
45
+ const scanDetail = await scanResults.returnScanResults(configToUse, codeArtifactId, getTimeout(configToUse), startScanSpinner);
46
+ const scanResultsInstances = await scanResults.returnScanResultsInstances(configToUse, scanDetail.id);
47
+ succeedSpinner(startScanSpinner, 'Contrast Scan complete');
48
+ const projectOverview = await scanResults.returnScanProjectById(configToUse);
49
+ return { projectOverview, scanResultsInstances };
50
+ }
51
+ };
52
+ module.exports = {
53
+ startScan: startScan
54
+ };
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ const commonApi = require('../utils/commonApi');
3
+ const requestUtils = require('../../src/utils/requestUtils');
4
+ const i18n = require('i18n');
5
+ const oraFunctions = require('../utils/oraWrapper');
6
+ const getScanId = async (config, codeArtifactId, client) => {
7
+ return client
8
+ .getScanId(config, codeArtifactId)
9
+ .then(res => {
10
+ return res.body.id;
11
+ })
12
+ .catch(err => {
13
+ console.log(err);
14
+ });
15
+ };
16
+ const pollScanResults = async (config, scanId, client) => {
17
+ await requestUtils.sleep(5000);
18
+ return client
19
+ .getSpecificScanResult(config, scanId)
20
+ .then(res => {
21
+ return res;
22
+ })
23
+ .catch(err => {
24
+ console.log(err);
25
+ });
26
+ };
27
+ const returnScanResults = async (config, codeArtifactId, timeout, startScanSpinner) => {
28
+ const client = commonApi.getHttpClient(config);
29
+ let scanId = await getScanId(config, codeArtifactId, client);
30
+ let startTime = new Date();
31
+ let complete = false;
32
+ while (!complete) {
33
+ let result = await pollScanResults(config, scanId, client);
34
+ if (JSON.stringify(result.statusCode) == 200) {
35
+ if (result.body.status === 'COMPLETED') {
36
+ complete = true;
37
+ return result.body;
38
+ }
39
+ if (result.body.status === 'FAILED') {
40
+ complete = true;
41
+ oraFunctions.failSpinner(startScanSpinner, 'Contrast Scan Failed.');
42
+ process.exit(1);
43
+ }
44
+ }
45
+ let endTime = new Date() - startTime;
46
+ if (requestUtils.millisToSeconds(endTime) > timeout) {
47
+ oraFunctions.failSpinner(startScanSpinner, 'Contrast Scan timed out at the specified ' + timeout + ' seconds.');
48
+ console.log('Please try again, allowing more time.');
49
+ process.exit(1);
50
+ }
51
+ }
52
+ };
53
+ const returnScanResultsInstances = async (config, scanId) => {
54
+ const client = commonApi.getHttpClient(config);
55
+ let result;
56
+ try {
57
+ result = await client.getScanResultsInstances(config, scanId);
58
+ if (JSON.stringify(result.statusCode) == 200) {
59
+ return result.body;
60
+ }
61
+ }
62
+ catch (e) {
63
+ console.log(e.message.toString());
64
+ }
65
+ };
66
+ const returnScanProjectById = async (config) => {
67
+ const client = commonApi.getHttpClient(config);
68
+ let result;
69
+ try {
70
+ result = await client.getScanProjectById(config);
71
+ if (JSON.stringify(result.statusCode) == 200) {
72
+ return result.body;
73
+ }
74
+ }
75
+ catch (e) {
76
+ console.log(e.message.toString());
77
+ }
78
+ };
79
+ module.exports = {
80
+ getScanId: getScanId,
81
+ returnScanResults: returnScanResults,
82
+ pollScanResults: pollScanResults,
83
+ returnScanResultsInstances: returnScanResultsInstances,
84
+ returnScanProjectById: returnScanProjectById
85
+ };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ const HttpClient = require('./../common/HTTPClient');
3
+ const { badRequestError, unauthenticatedError, forbiddenError, proxyError, hostWarningError, genericError } = require('../common/errorHandling');
4
+ const handleResponseErrors = (res, api, hostPresent) => {
5
+ if (res.statusCode === 400) {
6
+ api === 'catalogue' ? badRequestError(true) : badRequestError(false);
7
+ }
8
+ else if (res.statusCode === 401) {
9
+ unauthenticatedError();
10
+ }
11
+ else if (res.statusCode === 403) {
12
+ forbiddenError();
13
+ }
14
+ else if (res.statusCode === 407) {
15
+ proxyError();
16
+ }
17
+ else {
18
+ hostPresent === false ? hostWarningError() : genericError();
19
+ }
20
+ };
21
+ const getProtocol = host => {
22
+ const hasProtocol = host.toLowerCase().includes('https://') ||
23
+ host.toLowerCase().includes('http://');
24
+ return hasProtocol ? host : 'https://' + host;
25
+ };
26
+ const getPath = host => {
27
+ const hasContrastPath = host.toLowerCase().endsWith('/contrast');
28
+ return hasContrastPath
29
+ ? host.toLowerCase().substring(0, host.length - 9)
30
+ : host.replace(/\/*$/, '');
31
+ };
32
+ const getValidHost = host => {
33
+ const correctProtocol = getProtocol(host);
34
+ return getPath(correctProtocol);
35
+ };
36
+ const getHttpClient = config => {
37
+ return new HttpClient(config);
38
+ };
39
+ module.exports = {
40
+ getPath: getPath,
41
+ getValidHost: getValidHost,
42
+ getProtocol: getProtocol,
43
+ handleResponseErrors: handleResponseErrors,
44
+ getHttpClient: getHttpClient
45
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ const path = require('path');
3
+ function resolveFilePath(filepath) {
4
+ if (filepath[0] === '~') {
5
+ return path.join(process.env.HOME, filepath.slice(1));
6
+ }
7
+ return filepath;
8
+ }
9
+ const returnProjectPath = () => {
10
+ if (process.env.PWD !== (undefined || null || 'undefined')) {
11
+ return process.env.PWD;
12
+ }
13
+ else {
14
+ return process.argv[process.argv.indexOf('--project_path') + 1];
15
+ }
16
+ };
17
+ module.exports = {
18
+ returnProjectPath: returnProjectPath,
19
+ resolveFilePath: resolveFilePath
20
+ };