@sectester/reporter 0.16.1

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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +85 -0
  3. package/package.json +57 -0
  4. package/src/__fixtures__/issues.d.ts +71 -0
  5. package/src/__fixtures__/issues.js +64 -0
  6. package/src/__fixtures__/issues.js.map +1 -0
  7. package/src/formatters/PlainTextFormatter.d.ts +13 -0
  8. package/src/formatters/PlainTextFormatter.js +51 -0
  9. package/src/formatters/PlainTextFormatter.js.map +1 -0
  10. package/src/formatters/index.d.ts +1 -0
  11. package/src/formatters/index.js +5 -0
  12. package/src/formatters/index.js.map +1 -0
  13. package/src/index.d.ts +3 -0
  14. package/src/index.js +11 -0
  15. package/src/index.js.map +1 -0
  16. package/src/lib/Formatter.d.ts +5 -0
  17. package/src/lib/Formatter.js +5 -0
  18. package/src/lib/Formatter.js.map +1 -0
  19. package/src/lib/Reporter.d.ts +5 -0
  20. package/src/lib/Reporter.js +5 -0
  21. package/src/lib/Reporter.js.map +1 -0
  22. package/src/lib/index.d.ts +2 -0
  23. package/src/lib/index.js +6 -0
  24. package/src/lib/index.js.map +1 -0
  25. package/src/models/IssuesGroup.d.ts +6 -0
  26. package/src/models/IssuesGroup.js +3 -0
  27. package/src/models/IssuesGroup.js.map +1 -0
  28. package/src/models/index.d.ts +1 -0
  29. package/src/models/index.js +3 -0
  30. package/src/models/index.js.map +1 -0
  31. package/src/std/StdReporter.d.ts +13 -0
  32. package/src/std/StdReporter.js +91 -0
  33. package/src/std/StdReporter.js.map +1 -0
  34. package/src/std/index.d.ts +1 -0
  35. package/src/std/index.js +6 -0
  36. package/src/std/index.js.map +1 -0
  37. package/src/utils/index.d.ts +1 -0
  38. package/src/utils/index.js +6 -0
  39. package/src/utils/index.js.map +1 -0
  40. package/src/utils/issues-grouper.d.ts +6 -0
  41. package/src/utils/issues-grouper.js +30 -0
  42. package/src/utils/issues-grouper.js.map +1 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Bright Security
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # @sectester/reporter
2
+
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/a5f72ececc9b0f402802/maintainability)](https://codeclimate.com/github/NeuraLegion/sectester-js/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/a5f72ececc9b0f402802/test_coverage)](https://codeclimate.com/github/NeuraLegion/sectester-js/test_coverage)
5
+ ![Build Status](https://github.com/NeuraLegion/sectester-js/actions/workflows/coverage.yml/badge.svg?branch=master&event=push)
6
+ ![NPM Downloads](https://img.shields.io/npm/dw/@sectester/core)
7
+
8
+ Provide an abstraction for generating test results as part of the particular test frameworks.
9
+
10
+ ## Setup
11
+
12
+ ```bash
13
+ npm i -s @sectester/reporter
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ The package provides an implementation of the `Reporter` that lets to get results to stdout, i.e. `StdReporter`:
19
+
20
+ ```ts
21
+ import { Reporter, StdReporter } from '@sectester/reporter';
22
+
23
+ const reporter: Reporter = new StdReporter();
24
+ ```
25
+
26
+ You just need to call the `report` method to send findings to stdout:
27
+
28
+ ```ts
29
+ await reporter.report(scan);
30
+ ```
31
+
32
+ <details>
33
+ <summary>Sample console output</summary>
34
+
35
+ ![reporter-sample](reporter-sample.png)
36
+
37
+ </details>
38
+
39
+ In addition, the package exposes a `PlainTextFormatter` that implements a `Formatter` interface:
40
+
41
+ ```ts
42
+ import { Formatter, PlainTextFormatter } from '@sectester/reporter';
43
+
44
+ const formatter: Formatter = new PlainTextFormatter();
45
+ ```
46
+
47
+ To convert an issue into text, you just need to call the `format` method:
48
+
49
+ ```ts
50
+ formatter.format(issue);
51
+ ```
52
+
53
+ <details>
54
+ <summary>Sample output</summary>
55
+
56
+ ```
57
+ Issue in Bright UI: https://app.neuralegion.com/scans/djoqtSDRJYaR6sH8pfYpDX/issues/8iacauN1FH9vFvDCLoo42v
58
+ Name: Missing Strict-Transport-Security Header
59
+ Severity: Low
60
+ Remediation:
61
+ Make sure to proprely set and configure headers on your application - missing strict-transport-security header
62
+ Details:
63
+ The engine detected a missing strict-transport-security header. Headers are used to outline communication and
64
+ improve security of application.
65
+ Extra Details:
66
+ ● Missing Strict-Transport-Security Header
67
+ The engine detected a missing Strict-Transport-Security header, which might cause data to be sent insecurely from the client to the server.
68
+ Remedy:
69
+ - Make sure to set this header to one of the following options:
70
+ 1. Strict-Transport-Security: max-age=<expire-time>
71
+ 2. Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
72
+ 3. Strict-Transport-Security: max-age=<expire-time>; preload
73
+ Resources:
74
+ - https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts
75
+ Issues found on the following URLs:
76
+ - [GET] https://qa.brokencrystals.com/
77
+ ```
78
+
79
+ </details>
80
+
81
+ ## License
82
+
83
+ Copyright © 2022 [Bright Security](https://brightsec.com/).
84
+
85
+ This project is licensed under the MIT License - see the [LICENSE file](LICENSE) for details.
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@sectester/reporter",
3
+ "version": "0.16.1",
4
+ "description": "Provide an abstraction for generating test results as part of the particular test frameworks.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/NeuraLegion/sectester-js.git"
8
+ },
9
+ "engines": {
10
+ "node": ">=16",
11
+ "npm": "^8.1.0"
12
+ },
13
+ "author": {
14
+ "name": "Artem Derevnjuk",
15
+ "email": "artem.derevnjuk@brightsec.com"
16
+ },
17
+ "license": "MIT",
18
+ "bugs": {
19
+ "url": "https://github.com/NeuraLegion/sectester-js/issues"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "keywords": [
25
+ "security",
26
+ "testing",
27
+ "e2e",
28
+ "test",
29
+ "typescript",
30
+ "appsec",
31
+ "pentesting",
32
+ "qa",
33
+ "brightsec",
34
+ "reporter"
35
+ ],
36
+ "peerDependencies": {
37
+ "@sectester/scan": ">=0.16.0 <1.0.0"
38
+ },
39
+ "main": "./src/index.js",
40
+ "typings": "./src/index.d.ts",
41
+ "dependencies": {
42
+ "@sectester/bus": "0.16.1",
43
+ "@sectester/core": "0.16.1",
44
+ "reflect-metadata": "^0.1.13",
45
+ "uuid": "^8.3.2",
46
+ "tsyringe": "^4.6.0",
47
+ "chalk": "^4.1.2",
48
+ "form-data": "^4.0.0",
49
+ "axios": "^0.26.1",
50
+ "axios-rate-limit": "^1.3.0",
51
+ "amqp-connection-manager": "^4.1.1",
52
+ "amqplib": "^0.8.0",
53
+ "@har-sdk/core": "^1.4.3",
54
+ "ci-info": "^3.3.0",
55
+ "tty-table": "^4.1.5"
56
+ }
57
+ }
@@ -0,0 +1,71 @@
1
+ import { HttpMethod, Severity } from '@sectester/scan';
2
+ export declare const issueWithoutResourcesText = "Issue in Bright UI: http://app.neuralegion.com/scans/pDzxcEXQC8df1fcz1QwPf9/issues/pDzxcEXQC8df1fcz1QwPf9\nName: Database connection crashed\nSeverity: Medium\nRemediation:\nThe best way to protect against those kind of issues is making sure the Database resources are sufficient\nDetails:\nCross-site request forgery is a type of malicious website exploit.";
3
+ export declare const issueWithoutResources: {
4
+ id: string;
5
+ order: number;
6
+ details: string;
7
+ name: string;
8
+ severity: Severity;
9
+ protocol: string;
10
+ remedy: string;
11
+ cvss: string;
12
+ time: Date;
13
+ originalRequest: {
14
+ method: HttpMethod;
15
+ url: string;
16
+ };
17
+ request: {
18
+ method: HttpMethod;
19
+ url: string;
20
+ };
21
+ link: string;
22
+ };
23
+ export declare const fullyDescribedIssueText: string;
24
+ export declare const fullyDescribedIssue: {
25
+ comments: {
26
+ headline: string;
27
+ text: string;
28
+ links: string[];
29
+ }[];
30
+ resources: string[];
31
+ id: string;
32
+ order: number;
33
+ details: string;
34
+ name: string;
35
+ severity: Severity;
36
+ protocol: string;
37
+ remedy: string;
38
+ cvss: string;
39
+ time: Date;
40
+ originalRequest: {
41
+ method: HttpMethod;
42
+ url: string;
43
+ };
44
+ request: {
45
+ method: HttpMethod;
46
+ url: string;
47
+ };
48
+ link: string;
49
+ };
50
+ export declare const issueWithoutExtraInfoText: string;
51
+ export declare const issueWithoutExtraInfo: {
52
+ resources: string[];
53
+ id: string;
54
+ order: number;
55
+ details: string;
56
+ name: string;
57
+ severity: Severity;
58
+ protocol: string;
59
+ remedy: string;
60
+ cvss: string;
61
+ time: Date;
62
+ originalRequest: {
63
+ method: HttpMethod;
64
+ url: string;
65
+ };
66
+ request: {
67
+ method: HttpMethod;
68
+ url: string;
69
+ };
70
+ link: string;
71
+ };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.issueWithoutExtraInfo = exports.issueWithoutExtraInfoText = exports.fullyDescribedIssue = exports.fullyDescribedIssueText = exports.issueWithoutResources = exports.issueWithoutResourcesText = void 0;
4
+ const scan_1 = require("@sectester/scan");
5
+ exports.issueWithoutResourcesText = `Issue in Bright UI: http://app.neuralegion.com/scans/pDzxcEXQC8df1fcz1QwPf9/issues/pDzxcEXQC8df1fcz1QwPf9
6
+ Name: Database connection crashed
7
+ Severity: Medium
8
+ Remediation:
9
+ The best way to protect against those kind of issues is making sure the Database resources are sufficient
10
+ Details:
11
+ Cross-site request forgery is a type of malicious website exploit.`;
12
+ exports.issueWithoutResources = {
13
+ id: 'pDzxcEXQC8df1fcz1QwPf9',
14
+ order: 1,
15
+ details: 'Cross-site request forgery is a type of malicious website exploit.',
16
+ name: 'Database connection crashed',
17
+ severity: scan_1.Severity.MEDIUM,
18
+ protocol: 'http',
19
+ remedy: 'The best way to protect against those kind of issues is making sure the Database resources are sufficient',
20
+ cvss: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L',
21
+ time: new Date(),
22
+ originalRequest: {
23
+ method: scan_1.HttpMethod.GET,
24
+ url: 'https://brokencrystals.com/'
25
+ },
26
+ request: {
27
+ method: scan_1.HttpMethod.GET,
28
+ url: 'https://brokencrystals.com/'
29
+ },
30
+ link: 'http://app.neuralegion.com/scans/pDzxcEXQC8df1fcz1QwPf9/issues/pDzxcEXQC8df1fcz1QwPf9'
31
+ };
32
+ exports.fullyDescribedIssueText = `${exports.issueWithoutResourcesText}
33
+ Extra Details:
34
+ ● Missing Strict-Transport-Security Header
35
+ \tThe engine detected a missing Strict-Transport-Security header, which might cause data to be sent insecurely from the client to the server.
36
+ \tLinks:
37
+ \t● https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts
38
+ References:
39
+ ● https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts`;
40
+ exports.fullyDescribedIssue = {
41
+ ...exports.issueWithoutResources,
42
+ comments: [
43
+ {
44
+ headline: 'Missing Strict-Transport-Security Header',
45
+ text: 'The engine detected a missing Strict-Transport-Security header, which might cause data to be sent insecurely from the client to the server.',
46
+ links: [
47
+ 'https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts'
48
+ ]
49
+ }
50
+ ],
51
+ resources: [
52
+ 'https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts'
53
+ ]
54
+ };
55
+ exports.issueWithoutExtraInfoText = `${exports.issueWithoutResourcesText}
56
+ References:
57
+ ● https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts`;
58
+ exports.issueWithoutExtraInfo = {
59
+ ...exports.issueWithoutResources,
60
+ resources: [
61
+ 'https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts'
62
+ ]
63
+ };
64
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/__fixtures__/issues.ts"],"names":[],"mappings":";;;AAAA,0CAAuD;AAE1C,QAAA,yBAAyB,GAAG;;;;;;mEAM0B,CAAC;AACvD,QAAA,qBAAqB,GAAG;IACnC,EAAE,EAAE,wBAAwB;IAC5B,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,oEAAoE;IAC7E,IAAI,EAAE,6BAA6B;IACnC,QAAQ,EAAE,eAAQ,CAAC,MAAM;IACzB,QAAQ,EAAE,MAAM;IAChB,MAAM,EACJ,2GAA2G;IAC7G,IAAI,EAAE,8CAA8C;IACpD,IAAI,EAAE,IAAI,IAAI,EAAE;IAChB,eAAe,EAAE;QACf,MAAM,EAAE,iBAAU,CAAC,GAAG;QACtB,GAAG,EAAE,6BAA6B;KACnC;IACD,OAAO,EAAE;QACP,MAAM,EAAE,iBAAU,CAAC,GAAG;QACtB,GAAG,EAAE,6BAA6B;KACnC;IACD,IAAI,EAAE,uFAAuF;CAC9F,CAAC;AAEW,QAAA,uBAAuB,GAAG,GAAG,iCAAyB;;;;;;;oEAOC,CAAC;AACxD,QAAA,mBAAmB,GAAG;IACjC,GAAG,6BAAqB;IACxB,QAAQ,EAAE;QACR;YACE,QAAQ,EAAE,0CAA0C;YACpD,IAAI,EAAE,6IAA6I;YACnJ,KAAK,EAAE;gBACL,mEAAmE;aACpE;SACF;KACF;IACD,SAAS,EAAE;QACT,mEAAmE;KACpE;CACF,CAAC;AACW,QAAA,yBAAyB,GAAG,GAAG,iCAAyB;;qEAEA,CAAC;AACzD,QAAA,qBAAqB,GAAG;IACnC,GAAG,6BAAqB;IACxB,SAAS,EAAE;QACT,mEAAmE;KACpE;CACF,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Formatter } from '../lib';
2
+ import { Issue } from '@sectester/scan';
3
+ export declare class PlainTextFormatter implements Formatter {
4
+ private readonly BULLET_POINT;
5
+ private readonly NEW_LINE;
6
+ private readonly TABULATION;
7
+ format(issue: Issue): string;
8
+ private generateTemplate;
9
+ private formatExtraInfo;
10
+ private indent;
11
+ private formatList;
12
+ private combineList;
13
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PlainTextFormatter = void 0;
4
+ const util_1 = require("util");
5
+ class PlainTextFormatter {
6
+ constructor() {
7
+ this.BULLET_POINT = '●';
8
+ this.NEW_LINE = '\n';
9
+ this.TABULATION = '\t';
10
+ }
11
+ format(issue) {
12
+ const { link, name, severity, remedy, details, comments = [], resources = [] } = issue;
13
+ const template = this.generateTemplate({
14
+ extraInfo: comments.length > 0,
15
+ references: resources.length > 0
16
+ });
17
+ const message = (0, util_1.format)(template, link, name, severity, remedy, details, this.formatList(comments, comment => this.formatExtraInfo(comment)), this.formatList(resources));
18
+ return message.trim();
19
+ }
20
+ generateTemplate(options) {
21
+ return `
22
+ Issue in Bright UI: %s
23
+ Name: %s
24
+ Severity: %s
25
+ Remediation:
26
+ %s
27
+ Details:
28
+ %s${options.extraInfo ? `\nExtra Details:\n%s` : ''}${options.references ? `\nReferences:\n%s` : ''}`.trim();
29
+ }
30
+ formatExtraInfo({ headline, text = '', links = [] }) {
31
+ const footer = links.length
32
+ ? this.combineList(['Links:', this.formatList(links)])
33
+ : '';
34
+ const blocks = [text, footer].map(x => this.indent(x));
35
+ const document = this.combineList(blocks);
36
+ return this.combineList([headline, document]);
37
+ }
38
+ indent(x, length = 1) {
39
+ const lines = x.split(this.NEW_LINE);
40
+ return this.combineList(lines.map(line => `${this.TABULATION.repeat(length)}${line}`));
41
+ }
42
+ formatList(list, map) {
43
+ const items = list.map(x => `${this.BULLET_POINT} ${typeof map == 'function' ? map(x) : x}`);
44
+ return this.combineList(items);
45
+ }
46
+ combineList(list, sep) {
47
+ return list.join(sep !== null && sep !== void 0 ? sep : this.NEW_LINE);
48
+ }
49
+ }
50
+ exports.PlainTextFormatter = PlainTextFormatter;
51
+ //# sourceMappingURL=PlainTextFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlainTextFormatter.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/formatters/PlainTextFormatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export * from './PlainTextFormatter';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ (0, tslib_1.__exportStar)(require("./PlainTextFormatter"), exports);
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/formatters/index.ts"],"names":[],"mappings":";;;AAAA,oEAAqC"}
package/src/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { PlainTextFormatter } from './formatters';
2
+ export { Reporter, Formatter } from './lib';
3
+ export { StdReporter } from './std';
package/src/index.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StdReporter = exports.Formatter = exports.Reporter = exports.PlainTextFormatter = void 0;
4
+ var formatters_1 = require("./formatters");
5
+ Object.defineProperty(exports, "PlainTextFormatter", { enumerable: true, get: function () { return formatters_1.PlainTextFormatter; } });
6
+ var lib_1 = require("./lib");
7
+ Object.defineProperty(exports, "Reporter", { enumerable: true, get: function () { return lib_1.Reporter; } });
8
+ Object.defineProperty(exports, "Formatter", { enumerable: true, get: function () { return lib_1.Formatter; } });
9
+ var std_1 = require("./std");
10
+ Object.defineProperty(exports, "StdReporter", { enumerable: true, get: function () { return std_1.StdReporter; } });
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/reporter/src/index.ts"],"names":[],"mappings":";;;AAAA,2CAAkD;AAAzC,gHAAA,kBAAkB,OAAA;AAC3B,6BAA4C;AAAnC,+FAAA,QAAQ,OAAA;AAAE,gGAAA,SAAS,OAAA;AAC5B,6BAAoC;AAA3B,kGAAA,WAAW,OAAA"}
@@ -0,0 +1,5 @@
1
+ import { Issue } from '@sectester/scan';
2
+ export interface Formatter {
3
+ format(issue: Issue): string;
4
+ }
5
+ export declare const Formatter: unique symbol;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Formatter = void 0;
4
+ exports.Formatter = Symbol('Formatter');
5
+ //# sourceMappingURL=Formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Formatter.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/lib/Formatter.ts"],"names":[],"mappings":";;;AAMa,QAAA,SAAS,GAAkB,MAAM,CAAC,WAAW,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Scan } from '@sectester/scan';
2
+ export interface Reporter {
3
+ report(scan: Scan): Promise<void>;
4
+ }
5
+ export declare const Reporter: unique symbol;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Reporter = void 0;
4
+ exports.Reporter = Symbol('Reporter');
5
+ //# sourceMappingURL=Reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reporter.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/lib/Reporter.ts"],"names":[],"mappings":";;;AAMa,QAAA,QAAQ,GAAkB,MAAM,CAAC,UAAU,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './Reporter';
2
+ export * from './Formatter';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ (0, tslib_1.__exportStar)(require("./Reporter"), exports);
5
+ (0, tslib_1.__exportStar)(require("./Formatter"), exports);
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/lib/index.ts"],"names":[],"mappings":";;;AAAA,0DAA2B;AAC3B,2DAA4B"}
@@ -0,0 +1,6 @@
1
+ import { Issue, Severity } from '@sectester/scan';
2
+ export interface IssuesGroup {
3
+ severity: Severity;
4
+ name: string;
5
+ issues: Issue[];
6
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IssuesGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IssuesGroup.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/models/IssuesGroup.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export { IssuesGroup } from './IssuesGroup';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/models/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import { Reporter } from '../lib';
2
+ import { Scan } from '@sectester/scan';
3
+ export declare class StdReporter implements Reporter {
4
+ private readonly severityColorFn;
5
+ private readonly severityPrintFn;
6
+ report(scan: Scan): Promise<void>;
7
+ private formatFindingsMessage;
8
+ private renderDetailsTable;
9
+ private getHeaderConfig;
10
+ private pluralize;
11
+ private colorize;
12
+ private print;
13
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StdReporter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const utils_1 = require("../utils");
6
+ const scan_1 = require("@sectester/scan");
7
+ const tty_table_1 = (0, tslib_1.__importDefault)(require("tty-table"));
8
+ const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
9
+ class StdReporter {
10
+ constructor() {
11
+ this.severityColorFn = {
12
+ [scan_1.Severity.HIGH]: chalk_1.default.red,
13
+ [scan_1.Severity.MEDIUM]: chalk_1.default.yellow,
14
+ [scan_1.Severity.LOW]: chalk_1.default.blue
15
+ };
16
+ this.severityPrintFn = {
17
+ /* eslint-disable no-console */
18
+ [scan_1.Severity.HIGH]: console.error,
19
+ [scan_1.Severity.MEDIUM]: console.warn,
20
+ [scan_1.Severity.LOW]: console.log
21
+ /* eslint-enable no-console */
22
+ };
23
+ }
24
+ async report(scan) {
25
+ const issues = await scan.issues();
26
+ if (!issues.length) {
27
+ return;
28
+ }
29
+ [scan_1.Severity.HIGH, scan_1.Severity.MEDIUM, scan_1.Severity.LOW].forEach((severity) => {
30
+ const message = this.formatFindingsMessage(issues, severity);
31
+ if (message) {
32
+ this.print(message, severity);
33
+ }
34
+ });
35
+ // eslint-disable-next-line no-console
36
+ console.log(this.renderDetailsTable(issues));
37
+ }
38
+ formatFindingsMessage(issues, severity) {
39
+ const filtered = issues.filter(issue => issue.severity === severity);
40
+ if (filtered.length) {
41
+ return this.colorize(`Found ${filtered.length} ${severity} severity ${this.pluralize('issue', filtered.length)}.`, severity);
42
+ }
43
+ }
44
+ renderDetailsTable(issues) {
45
+ const issueGroups = utils_1.IssuesGrouper.group(issues);
46
+ return (0, tty_table_1.default)([
47
+ this.getHeaderConfig('severity', {
48
+ formatter: x => this.colorize(x, x),
49
+ width: 12
50
+ }),
51
+ this.getHeaderConfig('name'),
52
+ this.getHeaderConfig('issues', {
53
+ alias: 'Quantity',
54
+ formatter: items => items.length,
55
+ align: 'center',
56
+ width: 12
57
+ }),
58
+ this.getHeaderConfig('issues', {
59
+ alias: 'Targets',
60
+ formatter: (items) => items
61
+ .map((item, idx) => `${idx + 1}.\u00A0${item.request.url}`)
62
+ .join('\n')
63
+ })
64
+ ], issueGroups).render();
65
+ }
66
+ getHeaderConfig(fieldName, options = {}) {
67
+ const defaultHeaderConfig = {
68
+ width: '',
69
+ headerColor: '',
70
+ align: 'left',
71
+ headerAlign: 'left',
72
+ value: fieldName,
73
+ alias: `${fieldName.charAt(0).toUpperCase()}${fieldName.substring(1)}`
74
+ };
75
+ return {
76
+ ...defaultHeaderConfig,
77
+ ...options
78
+ };
79
+ }
80
+ pluralize(word, quantity) {
81
+ return quantity > 1 ? `${word}s` : word;
82
+ }
83
+ colorize(message, severity) {
84
+ return this.severityColorFn[severity](message);
85
+ }
86
+ print(message, severity) {
87
+ return this.severityPrintFn[severity](message);
88
+ }
89
+ }
90
+ exports.StdReporter = StdReporter;
91
+ //# sourceMappingURL=StdReporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdReporter.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/std/StdReporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { StdReporter } from './StdReporter';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StdReporter = void 0;
4
+ var StdReporter_1 = require("./StdReporter");
5
+ Object.defineProperty(exports, "StdReporter", { enumerable: true, get: function () { return StdReporter_1.StdReporter; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/std/index.ts"],"names":[],"mappings":";;;AAAA,6CAA4C;AAAnC,0GAAA,WAAW,OAAA"}
@@ -0,0 +1 @@
1
+ export { IssuesGrouper } from './issues-grouper';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IssuesGrouper = void 0;
4
+ var issues_grouper_1 = require("./issues-grouper");
5
+ Object.defineProperty(exports, "IssuesGrouper", { enumerable: true, get: function () { return issues_grouper_1.IssuesGrouper; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/utils/index.ts"],"names":[],"mappings":";;;AAAA,mDAAiD;AAAxC,+GAAA,aAAa,OAAA"}
@@ -0,0 +1,6 @@
1
+ import { IssuesGroup } from '../models';
2
+ import { Issue } from '@sectester/scan';
3
+ export declare class IssuesGrouper {
4
+ static group(issues: Issue[]): IssuesGroup[];
5
+ static groupComparator(a: IssuesGroup, b: IssuesGroup): number;
6
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IssuesGrouper = void 0;
4
+ const scan_1 = require("@sectester/scan");
5
+ class IssuesGrouper {
6
+ static group(issues) {
7
+ const grouped = issues.reduce((res, issue) => {
8
+ const issuesGroup = res.find((group) => group.severity === issue.severity && group.name === issue.name);
9
+ if (issuesGroup) {
10
+ issuesGroup.issues.push(issue);
11
+ }
12
+ else {
13
+ res.push({
14
+ severity: issue.severity,
15
+ name: issue.name,
16
+ issues: [issue]
17
+ });
18
+ }
19
+ return res;
20
+ }, []);
21
+ grouped.sort(this.groupComparator);
22
+ return grouped;
23
+ }
24
+ static groupComparator(a, b) {
25
+ const res = (0, scan_1.severityComparator)(a.severity, b.severity);
26
+ return res ? res : b.issues.length - a.issues.length;
27
+ }
28
+ }
29
+ exports.IssuesGrouper = IssuesGrouper;
30
+ //# sourceMappingURL=issues-grouper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues-grouper.js","sourceRoot":"","sources":["../../../../../packages/reporter/src/utils/issues-grouper.ts"],"names":[],"mappings":";;;AACA,0CAA4D;AAE5D,MAAa,aAAa;IACjB,MAAM,CAAC,KAAK,CAAC,MAAe;QACjC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAC3B,CAAC,GAAkB,EAAE,KAAY,EAAiB,EAAE;YAClD,MAAM,WAAW,GAA4B,GAAG,CAAC,IAAI,CACnD,CAAC,KAAkB,EAAE,EAAE,CACrB,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CACjE,CAAC;YACF,IAAI,WAAW,EAAE;gBACf,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aAChC;iBAAM;gBACL,GAAG,CAAC,IAAI,CAAC;oBACP,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,MAAM,EAAE,CAAC,KAAK,CAAC;iBAChB,CAAC,CAAC;aACJ;YAED,OAAO,GAAG,CAAC;QACb,CAAC,EACD,EAAE,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAEnC,OAAO,OAAO,CAAC;IACjB,CAAC;IAEM,MAAM,CAAC,eAAe,CAAC,CAAc,EAAE,CAAc;QAC1D,MAAM,GAAG,GAAG,IAAA,yBAAkB,EAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;QAEvD,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;IACvD,CAAC;CACF;AAjCD,sCAiCC"}