pentest-tool-lite 3.10.6 → 3.10.8
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/dist/Pentest.js +46 -0
- package/dist/{src/Test.js → Test.js} +11 -24
- package/dist/commands/Sitemap.js +79 -0
- package/dist/dns/A.js +49 -0
- package/dist/dns/DMARC.js +59 -0
- package/dist/dns/NS.js +36 -0
- package/dist/dns/RegistrationDate.js +39 -0
- package/dist/dns/index.js +47 -0
- package/dist/functions/parseSitemap.js +12 -0
- package/dist/html/Anchor.js +56 -0
- package/dist/html/CSS.js +92 -0
- package/dist/html/DuplicateId.js +35 -0
- package/dist/html/Generator.js +31 -0
- package/dist/html/Image.js +79 -0
- package/dist/html/JavaScript.js +107 -0
- package/dist/{src/html → html}/__TESTS__/Generator.test.js +10 -19
- package/dist/html/index.js +51 -0
- package/dist/{src/index → index} +21 -20
- package/dist/{src/logger → logger}/Console.js +1 -3
- package/dist/metadata/HTML.js +26 -0
- package/dist/metadata/Markdown.js +28 -0
- package/dist/metadata/ResponseTime.js +25 -0
- package/dist/metadata/index.js +45 -0
- package/dist/request/NodeFetch.js +58 -0
- package/dist/{src/request → request}/cache/UnlimitedCache.js +2 -0
- package/dist/security/ContentEncoding.js +44 -0
- package/dist/security/ContentSecurityPolicy.js +32 -0
- package/dist/security/Cookies.js +44 -0
- package/dist/security/FingerPrint.js +37 -0
- package/dist/security/GoogleWebRisk.js +44 -0
- package/dist/security/HSTS.js +48 -0
- package/dist/security/HTTPS.js +78 -0
- package/dist/security/HTTPVersion.js +50 -0
- package/dist/security/PermissionsPolicy.js +53 -0
- package/dist/security/Redirect.js +37 -0
- package/dist/security/ReferrerPolicy.js +32 -0
- package/dist/security/RobotsTXT.js +28 -0
- package/dist/security/SSL.js +36 -0
- package/dist/security/XFrameOptions.js +32 -0
- package/dist/security/XXSSProtection.js +32 -0
- package/dist/{src/security → security}/__TESTS__/ContentSecurityPolicy.test.js +10 -19
- package/dist/{src/security → security}/__TESTS__/FingerPrint.test.js +10 -19
- package/dist/{src/security → security}/__TESTS__/HSTS.test.js +15 -24
- package/dist/{src/security → security}/__TESTS__/HTTPS.test.js +15 -24
- package/dist/{src/security → security}/__TESTS__/XFrameOptions.test.js +10 -19
- package/dist/{src/security → security}/__TESTS__/XXSSProtection.test.js +10 -19
- package/dist/{src/security → security}/index.js +20 -31
- package/dist/seo/Heading.js +51 -0
- package/dist/seo/Robots.js +21 -0
- package/dist/seo/Sitemap.js +32 -0
- package/dist/seo/Title.js +44 -0
- package/dist/seo/index.js +47 -0
- package/dist/wordpress/DefaultFiles.js +50 -0
- package/dist/wordpress/Generator.js +58 -0
- package/dist/wordpress/index.js +43 -0
- package/package.json +10 -2
- package/dist/package.json +0 -61
- package/dist/src/Pentest.js +0 -57
- package/dist/src/commands/Sitemap.js +0 -96
- package/dist/src/dns/A.js +0 -65
- package/dist/src/dns/DMARC.js +0 -73
- package/dist/src/dns/NS.js +0 -52
- package/dist/src/dns/RegistrationDate.js +0 -55
- package/dist/src/dns/index.js +0 -58
- package/dist/src/functions/parseSitemap.js +0 -23
- package/dist/src/html/Anchor.js +0 -72
- package/dist/src/html/CSS.js +0 -108
- package/dist/src/html/DuplicateId.js +0 -49
- package/dist/src/html/Generator.js +0 -45
- package/dist/src/html/Image.js +0 -95
- package/dist/src/html/JavaScript.js +0 -123
- package/dist/src/html/index.js +0 -62
- package/dist/src/metadata/HTML.js +0 -40
- package/dist/src/metadata/Markdown.js +0 -42
- package/dist/src/metadata/ResponseTime.js +0 -39
- package/dist/src/metadata/index.js +0 -56
- package/dist/src/request/NodeFetch.js +0 -68
- package/dist/src/security/ContentEncoding.js +0 -58
- package/dist/src/security/ContentSecurityPolicy.js +0 -46
- package/dist/src/security/Cookies.js +0 -58
- package/dist/src/security/FingerPrint.js +0 -51
- package/dist/src/security/GoogleWebRisk.js +0 -58
- package/dist/src/security/HSTS.js +0 -62
- package/dist/src/security/HTTPS.js +0 -92
- package/dist/src/security/HTTPVersion.js +0 -64
- package/dist/src/security/PermissionsPolicy.js +0 -67
- package/dist/src/security/Redirect.js +0 -51
- package/dist/src/security/ReferrerPolicy.js +0 -46
- package/dist/src/security/RobotsTXT.js +0 -42
- package/dist/src/security/SSL.js +0 -50
- package/dist/src/security/XFrameOptions.js +0 -46
- package/dist/src/security/XXSSProtection.js +0 -46
- package/dist/src/seo/Heading.js +0 -65
- package/dist/src/seo/Robots.js +0 -35
- package/dist/src/seo/Sitemap.js +0 -46
- package/dist/src/seo/Title.js +0 -58
- package/dist/src/seo/index.js +0 -58
- package/dist/src/wordpress/DefaultFiles.js +0 -66
- package/dist/src/wordpress/Generator.js +0 -76
- package/dist/src/wordpress/index.js +0 -54
- /package/dist/{src/Pentest.d.ts → Pentest.d.ts} +0 -0
- /package/dist/{src/Test.d.ts → Test.d.ts} +0 -0
- /package/dist/{src/commands → commands}/Sitemap.d.ts +0 -0
- /package/dist/{src/config.d.ts → config.d.ts} +0 -0
- /package/dist/{src/config.js → config.js} +0 -0
- /package/dist/{src/dns → dns}/A.d.ts +0 -0
- /package/dist/{src/dns → dns}/DMARC.d.ts +0 -0
- /package/dist/{src/dns → dns}/NS.d.ts +0 -0
- /package/dist/{src/dns → dns}/RegistrationDate.d.ts +0 -0
- /package/dist/{src/dns → dns}/index.d.ts +0 -0
- /package/dist/{src/functions → functions}/findEvery.d.ts +0 -0
- /package/dist/{src/functions → functions}/findEvery.js +0 -0
- /package/dist/{src/functions → functions}/getAnchors.d.ts +0 -0
- /package/dist/{src/functions → functions}/getAnchors.js +0 -0
- /package/dist/{src/functions → functions}/getDomain.d.ts +0 -0
- /package/dist/{src/functions → functions}/getDomain.js +0 -0
- /package/dist/{src/functions → functions}/getDuplicates.d.ts +0 -0
- /package/dist/{src/functions → functions}/getDuplicates.js +0 -0
- /package/dist/{src/functions → functions}/getGenerator.d.ts +0 -0
- /package/dist/{src/functions → functions}/getGenerator.js +0 -0
- /package/dist/{src/functions → functions}/getHeading.d.ts +0 -0
- /package/dist/{src/functions → functions}/getHeading.js +0 -0
- /package/dist/{src/functions → functions}/getImages.d.ts +0 -0
- /package/dist/{src/functions → functions}/getImages.js +0 -0
- /package/dist/{src/functions → functions}/getObject.d.ts +0 -0
- /package/dist/{src/functions → functions}/getObject.js +0 -0
- /package/dist/{src/functions → functions}/getScripts.d.ts +0 -0
- /package/dist/{src/functions → functions}/getScripts.js +0 -0
- /package/dist/{src/functions → functions}/getStylesheets.d.ts +0 -0
- /package/dist/{src/functions → functions}/getStylesheets.js +0 -0
- /package/dist/{src/functions → functions}/getTitle.d.ts +0 -0
- /package/dist/{src/functions → functions}/getTitle.js +0 -0
- /package/dist/{src/functions → functions}/index.d.ts +0 -0
- /package/dist/{src/functions → functions}/index.js +0 -0
- /package/dist/{src/functions → functions}/parseHtml.d.ts +0 -0
- /package/dist/{src/functions → functions}/parseHtml.js +0 -0
- /package/dist/{src/functions → functions}/parseSitemap.d.ts +0 -0
- /package/dist/{src/functions → functions}/parseXml.d.ts +0 -0
- /package/dist/{src/functions → functions}/parseXml.js +0 -0
- /package/dist/{src/html → html}/Anchor.d.ts +0 -0
- /package/dist/{src/html → html}/CSS.d.ts +0 -0
- /package/dist/{src/html → html}/DuplicateId.d.ts +0 -0
- /package/dist/{src/html → html}/Generator.d.ts +0 -0
- /package/dist/{src/html → html}/Image.d.ts +0 -0
- /package/dist/{src/html → html}/JavaScript.d.ts +0 -0
- /package/dist/{src/html → html}/__TESTS__/Generator.test.d.ts +0 -0
- /package/dist/{src/html → html}/index.d.ts +0 -0
- /package/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{src/logger → logger}/Console.d.ts +0 -0
- /package/dist/{src/logger → logger}/Logger.d.ts +0 -0
- /package/dist/{src/logger → logger}/Logger.js +0 -0
- /package/dist/{src/logger → logger}/index.d.ts +0 -0
- /package/dist/{src/logger → logger}/index.js +0 -0
- /package/dist/{src/metadata → metadata}/HTML.d.ts +0 -0
- /package/dist/{src/metadata → metadata}/Markdown.d.ts +0 -0
- /package/dist/{src/metadata → metadata}/ResponseTime.d.ts +0 -0
- /package/dist/{src/metadata → metadata}/index.d.ts +0 -0
- /package/dist/{src/report → report}/CommandLine.d.ts +0 -0
- /package/dist/{src/report → report}/CommandLine.js +0 -0
- /package/dist/{src/report → report}/Json.d.ts +0 -0
- /package/dist/{src/report → report}/Json.js +0 -0
- /package/dist/{src/report → report}/Report.d.ts +0 -0
- /package/dist/{src/report → report}/Report.js +0 -0
- /package/dist/{src/report → report}/Symbols.d.ts +0 -0
- /package/dist/{src/report → report}/Symbols.js +0 -0
- /package/dist/{src/report → report}/index.d.ts +0 -0
- /package/dist/{src/report → report}/index.js +0 -0
- /package/dist/{src/request → request}/NodeFetch.d.ts +0 -0
- /package/dist/{src/request → request}/Request.d.ts +0 -0
- /package/dist/{src/request → request}/Request.js +0 -0
- /package/dist/{src/request → request}/cache/BlackHoleCache.d.ts +0 -0
- /package/dist/{src/request → request}/cache/BlackHoleCache.js +0 -0
- /package/dist/{src/request → request}/cache/UnlimitedCache.d.ts +0 -0
- /package/dist/{src/request → request}/index.d.ts +0 -0
- /package/dist/{src/request → request}/index.js +0 -0
- /package/dist/{src/security → security}/ContentEncoding.d.ts +0 -0
- /package/dist/{src/security → security}/ContentSecurityPolicy.d.ts +0 -0
- /package/dist/{src/security → security}/Cookies.d.ts +0 -0
- /package/dist/{src/security → security}/FingerPrint.d.ts +0 -0
- /package/dist/{src/security → security}/GoogleWebRisk.d.ts +0 -0
- /package/dist/{src/security → security}/HSTS.d.ts +0 -0
- /package/dist/{src/security → security}/HTTPS.d.ts +0 -0
- /package/dist/{src/security → security}/HTTPVersion.d.ts +0 -0
- /package/dist/{src/security → security}/PermissionsPolicy.d.ts +0 -0
- /package/dist/{src/security → security}/Redirect.d.ts +0 -0
- /package/dist/{src/security → security}/ReferrerPolicy.d.ts +0 -0
- /package/dist/{src/security → security}/RobotsTXT.d.ts +0 -0
- /package/dist/{src/security → security}/SSL.d.ts +0 -0
- /package/dist/{src/security → security}/XFrameOptions.d.ts +0 -0
- /package/dist/{src/security → security}/XXSSProtection.d.ts +0 -0
- /package/dist/{src/security → security}/__TESTS__/ContentSecurityPolicy.test.d.ts +0 -0
- /package/dist/{src/security → security}/__TESTS__/FingerPrint.test.d.ts +0 -0
- /package/dist/{src/security → security}/__TESTS__/HSTS.test.d.ts +0 -0
- /package/dist/{src/security → security}/__TESTS__/HTTPS.test.d.ts +0 -0
- /package/dist/{src/security → security}/__TESTS__/XFrameOptions.test.d.ts +0 -0
- /package/dist/{src/security → security}/__TESTS__/XXSSProtection.test.d.ts +0 -0
- /package/dist/{src/security → security}/index.d.ts +0 -0
- /package/dist/{src/seo → seo}/Heading.d.ts +0 -0
- /package/dist/{src/seo → seo}/Robots.d.ts +0 -0
- /package/dist/{src/seo → seo}/Sitemap.d.ts +0 -0
- /package/dist/{src/seo → seo}/Title.d.ts +0 -0
- /package/dist/{src/seo → seo}/index.d.ts +0 -0
- /package/dist/{src/wordpress → wordpress}/DefaultFiles.d.ts +0 -0
- /package/dist/{src/wordpress → wordpress}/Generator.d.ts +0 -0
- /package/dist/{src/wordpress → wordpress}/index.d.ts +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
class Cookies extends Test_1.default {
|
|
10
|
+
name = 'Cookies';
|
|
11
|
+
async test({ url }) {
|
|
12
|
+
logger_1.default.info('Starting Cookies test...');
|
|
13
|
+
const response = await request_1.default.get(url);
|
|
14
|
+
let subChecks = [];
|
|
15
|
+
if (Object.prototype.hasOwnProperty.call(response.headers, 'set-cookie')) {
|
|
16
|
+
const cookies = response.headers['set-cookie'];
|
|
17
|
+
subChecks = this.checkCookies(cookies);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
status: subChecks.some(check => check.status === 'WARNING') ? 'WARNING' : 'SUCCESS',
|
|
21
|
+
title: 'Cookies',
|
|
22
|
+
description: '',
|
|
23
|
+
results: subChecks,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
checkCookies(cookies) {
|
|
27
|
+
const regx = new RegExp('.*(secure; HttpOnly)$', 'i');
|
|
28
|
+
return cookies.map((cookie) => {
|
|
29
|
+
if (!regx.test(cookie)) {
|
|
30
|
+
return {
|
|
31
|
+
status: 'WARNING',
|
|
32
|
+
title: cookie.substr(0, cookie.indexOf('=')),
|
|
33
|
+
description: '',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
status: 'SUCCESS',
|
|
38
|
+
title: cookie.substr(0, cookie.indexOf('=')),
|
|
39
|
+
description: '',
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.default = Cookies;
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @see https://www.owasp.org/index.php/Fingerprint_Web_Server_(OTG-INFO-002)
|
|
12
|
+
* @see https://www.owasp.org/index.php/Fingerprint_Web_Application_Framework_(OTG-INFO-008)
|
|
13
|
+
*/
|
|
14
|
+
class FingerPrint extends Test_1.default {
|
|
15
|
+
name = 'FingerPrint';
|
|
16
|
+
knownHeaders = ['x-powered-by', 'x-generator', 'server'];
|
|
17
|
+
async test({ url }) {
|
|
18
|
+
logger_1.default.info('Starting FingerPrint test...');
|
|
19
|
+
const response = await request_1.default.get(url);
|
|
20
|
+
if (this.hasFingerPrintHeader(response.headers)) {
|
|
21
|
+
return {
|
|
22
|
+
status: 'ERROR',
|
|
23
|
+
title: 'FingerPrint',
|
|
24
|
+
description: 'Response headers includes at least one of finger print headers!',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
status: 'SUCCESS',
|
|
29
|
+
title: 'FingerPrint',
|
|
30
|
+
description: `Response headers don't inlcude any of finger print headers.`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
hasFingerPrintHeader(headers) {
|
|
34
|
+
return Object.keys(headers).filter((header) => this.knownHeaders.includes(header)).length > 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.default = FingerPrint;
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
const web_risk_1 = require("@google-cloud/web-risk");
|
|
7
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @see https://cloud.google.com/web-risk
|
|
12
|
+
* @see https://safebrowsing.google.com
|
|
13
|
+
* @see https://transparencyreport.google.com/safe-browsing/search
|
|
14
|
+
*/
|
|
15
|
+
class GoogleWebRisk extends Test_1.default {
|
|
16
|
+
name = 'GoogleWebRisk';
|
|
17
|
+
async test({ url }) {
|
|
18
|
+
logger_1.default.info('Starting Google Web Risk test...');
|
|
19
|
+
const client = new web_risk_1.WebRiskServiceClient();
|
|
20
|
+
const request = {
|
|
21
|
+
uri: url,
|
|
22
|
+
threatTypes: [
|
|
23
|
+
web_risk_1.protos.google.cloud.webrisk.v1.ThreatType.MALWARE,
|
|
24
|
+
web_risk_1.protos.google.cloud.webrisk.v1.ThreatType.SOCIAL_ENGINEERING,
|
|
25
|
+
web_risk_1.protos.google.cloud.webrisk.v1.ThreatType.UNWANTED_SOFTWARE,
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
const response = await client.searchUris(request);
|
|
29
|
+
const { threat } = response[0];
|
|
30
|
+
if (threat !== null) {
|
|
31
|
+
return {
|
|
32
|
+
status: 'ERROR',
|
|
33
|
+
title: this.name,
|
|
34
|
+
description: `This url contains ${threat.threatTypes.join(', ').toLowerCase()}!`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
status: 'SUCCESS',
|
|
39
|
+
title: this.name,
|
|
40
|
+
description: 'This URL is safe.',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.default = GoogleWebRisk;
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
* HTTP Strict Transport Security
|
|
11
|
+
*
|
|
12
|
+
* Recommended value is at least one year (31536000).
|
|
13
|
+
*
|
|
14
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
|
|
15
|
+
* @see https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
|
|
16
|
+
*/
|
|
17
|
+
class HSTS extends Test_1.default {
|
|
18
|
+
name = 'HSTS';
|
|
19
|
+
minValue = 31536000;
|
|
20
|
+
async test({ url }) {
|
|
21
|
+
logger_1.default.info('Starting HSTS test...');
|
|
22
|
+
const response = await request_1.default.get(url);
|
|
23
|
+
if (!Object.prototype.hasOwnProperty.call(response.headers, 'strict-transport-security')) {
|
|
24
|
+
return {
|
|
25
|
+
status: 'ERROR',
|
|
26
|
+
title: 'HSTS',
|
|
27
|
+
description: 'The strict-transport-security header is not present!',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const attributes = response.headers['strict-transport-security'].replace(' ', '').split(';');
|
|
31
|
+
const maxAge = attributes.filter((attribute) => {
|
|
32
|
+
return attribute.startsWith('max-age');
|
|
33
|
+
}).shift().replace('max-age=', '');
|
|
34
|
+
if (parseInt(maxAge, 10) < this.minValue) {
|
|
35
|
+
return {
|
|
36
|
+
status: 'ERROR',
|
|
37
|
+
title: 'HSTS',
|
|
38
|
+
description: `The value of strict-transport-security header is ${maxAge}. Minimum value is ${this.minValue}!`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
status: 'SUCCESS',
|
|
43
|
+
title: 'HSTS',
|
|
44
|
+
description: `The value of strict-transport-security header is ${maxAge}.`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.default = HSTS;
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
* Hypertext Transfer Protocol Secure
|
|
11
|
+
*
|
|
12
|
+
* The script first transform the url to be unsecure
|
|
13
|
+
* and then make the request. The answer has to be
|
|
14
|
+
* redirect to secure version.
|
|
15
|
+
*
|
|
16
|
+
* Some sites requires www (or requires version without wwww)
|
|
17
|
+
* and if the request is not as desired, it first redirects
|
|
18
|
+
* to desired version (without https) and then again redirects
|
|
19
|
+
* to version with https. This is also wrong.
|
|
20
|
+
*
|
|
21
|
+
* @see https://en.wikipedia.org/wiki/HTTPS
|
|
22
|
+
*/
|
|
23
|
+
class HTTPS extends Test_1.default {
|
|
24
|
+
name = 'HTTPS';
|
|
25
|
+
async test({ url }) {
|
|
26
|
+
logger_1.default.info('Starting HTTPS test...');
|
|
27
|
+
const unsecureUrl = this.toHttp(url);
|
|
28
|
+
logger_1.default.debug('Unsecure URL', unsecureUrl);
|
|
29
|
+
const response = await request_1.default.get(unsecureUrl, { redirect: 'manual' });
|
|
30
|
+
logger_1.default.debug('Response', { statusCode: response.statusCode, headers: response.headers });
|
|
31
|
+
if (!this.isRedirect(response)) {
|
|
32
|
+
return {
|
|
33
|
+
status: 'ERROR',
|
|
34
|
+
title: 'HTTPS',
|
|
35
|
+
metadata: {
|
|
36
|
+
statusCode: response.statusCode,
|
|
37
|
+
unsecureUrl,
|
|
38
|
+
finalUrl: response.finalUrl,
|
|
39
|
+
},
|
|
40
|
+
description: `Request to not secure url returned ${response.statusCode}!`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (!this.isRedirectSecure(response)) {
|
|
44
|
+
return {
|
|
45
|
+
status: 'ERROR',
|
|
46
|
+
title: 'HTTPS',
|
|
47
|
+
metadata: {
|
|
48
|
+
statusCode: response.statusCode,
|
|
49
|
+
unsecureUrl,
|
|
50
|
+
finalUrl: response.finalUrl,
|
|
51
|
+
},
|
|
52
|
+
description: `Request to not secure url returned non-secure redirect url ${response.headers.location}!`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
status: 'SUCCESS',
|
|
57
|
+
title: 'HTTPS',
|
|
58
|
+
metadata: {
|
|
59
|
+
statusCode: response.statusCode,
|
|
60
|
+
unsecureUrl,
|
|
61
|
+
finalUrl: response.finalUrl,
|
|
62
|
+
},
|
|
63
|
+
description: `Request to not secure url responded with status code ${response.statusCode} and redirect url ${response.headers.location}.`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
67
|
+
isRedirect(response) {
|
|
68
|
+
return Math.floor(response.statusCode / 100) === 3 && 'location' in response.headers;
|
|
69
|
+
}
|
|
70
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
71
|
+
isRedirectSecure(response) {
|
|
72
|
+
return response.headers.location.startsWith('https');
|
|
73
|
+
}
|
|
74
|
+
toHttp(url) {
|
|
75
|
+
return url.replace('https://', 'http://');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.default = HTTPS;
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @see https://en.wikipedia.org/wiki/HTTP/2
|
|
12
|
+
* @see https://en.wikipedia.org/wiki/HTTP/3
|
|
13
|
+
*/
|
|
14
|
+
class HTTPVersion extends Test_1.default {
|
|
15
|
+
name = 'HTTP Version';
|
|
16
|
+
async test({ url }) {
|
|
17
|
+
logger_1.default.info('Starting HTTPVersion test...');
|
|
18
|
+
const response = await request_1.default.get(url);
|
|
19
|
+
if (Object.prototype.hasOwnProperty.call(response.headers, 'upgrade')) {
|
|
20
|
+
const attributes = response.headers['upgrade'].replace(' ', '').split(',');
|
|
21
|
+
const h2 = attributes.indexOf('h2') > -1;
|
|
22
|
+
if (h2) {
|
|
23
|
+
return {
|
|
24
|
+
status: 'WARNING',
|
|
25
|
+
title: 'HTTP/2',
|
|
26
|
+
description: 'The current HTTP version is 2. Can be upgraded to 3.',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (Object.prototype.hasOwnProperty.call(response.headers, 'alt-svc')) {
|
|
31
|
+
const attributes = response.headers['alt-svc'].replace(' ', '').split(',');
|
|
32
|
+
const h3 = attributes.find(a => a.includes('h3'));
|
|
33
|
+
if (typeof h3 !== 'undefined') {
|
|
34
|
+
if (h3) {
|
|
35
|
+
return {
|
|
36
|
+
status: 'SUCCESS',
|
|
37
|
+
title: 'HTTP/3',
|
|
38
|
+
description: 'The value of HTTP/3 header is present.',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
status: 'ERROR',
|
|
45
|
+
title: 'HTTP/1',
|
|
46
|
+
description: 'The current HTTP version is 1. Should be upgraded at least to 2!',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.default = HTTPVersion;
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
|
|
12
|
+
*/
|
|
13
|
+
class PermissionsPolicy extends Test_1.default {
|
|
14
|
+
name = 'Permissions-Policy';
|
|
15
|
+
async test({ url }) {
|
|
16
|
+
logger_1.default.info('Starting PermissionsPolicy test...');
|
|
17
|
+
const response = await request_1.default.get(url);
|
|
18
|
+
if (!Object.prototype.hasOwnProperty.call(response.headers, 'permissions-policy')) {
|
|
19
|
+
return {
|
|
20
|
+
status: 'ERROR',
|
|
21
|
+
title: 'Permissions-Policy',
|
|
22
|
+
description: 'Response headers does not contain permissions-policy header!',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const permissionsArray = ['accelerometer', 'geolocation', 'midi', 'notifications', 'push', 'sync-xhr',
|
|
26
|
+
'microphone', 'camera', 'magnetometer', 'gyroscope', 'speaker', 'vibrate', 'fullscreen', 'payment', 'usb'];
|
|
27
|
+
const attributesList = response.headers['permissions-policy'];
|
|
28
|
+
const subChecks = this.checkPermissions(permissionsArray, attributesList);
|
|
29
|
+
return {
|
|
30
|
+
status: subChecks.some(check => check.status === 'WARNING') ? 'WARNING' : 'SUCCESS',
|
|
31
|
+
title: 'Permissions-Policy',
|
|
32
|
+
description: '',
|
|
33
|
+
results: subChecks,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
checkPermissions(permissions, attributes) {
|
|
37
|
+
return permissions.map((permission) => {
|
|
38
|
+
if (!attributes.includes(permission)) {
|
|
39
|
+
return {
|
|
40
|
+
status: 'WARNING',
|
|
41
|
+
title: permission,
|
|
42
|
+
description: `Permission ${permission} is missing.`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
status: 'SUCCESS',
|
|
47
|
+
title: permission,
|
|
48
|
+
description: `Permission ${permission} is present.`,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.default = PermissionsPolicy;
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
class Redirect extends Test_1.default {
|
|
10
|
+
name = 'Redirect';
|
|
11
|
+
async test({ url }) {
|
|
12
|
+
logger_1.default.info('Starting Redirect test...');
|
|
13
|
+
const response = await request_1.default.get(url, { redirect: 'follow' });
|
|
14
|
+
if (response.response.redirected) {
|
|
15
|
+
const originalUrl = new URL(url);
|
|
16
|
+
const finalUrl = new URL(response.response.url);
|
|
17
|
+
if (originalUrl.hostname !== finalUrl.hostname) {
|
|
18
|
+
return {
|
|
19
|
+
status: 'ERROR',
|
|
20
|
+
title: this.name,
|
|
21
|
+
description: 'URL redirects to different hostname!',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
status: 'SUCCESS',
|
|
26
|
+
title: this.name,
|
|
27
|
+
description: 'Request was redirected but to the same hostname.',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
status: 'SUCCESS',
|
|
32
|
+
title: this.name,
|
|
33
|
+
description: 'Request was not redirected.',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.default = Redirect;
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
|
|
12
|
+
*/
|
|
13
|
+
class ReferrerPolicy extends Test_1.default {
|
|
14
|
+
name = 'Referrer-Policy';
|
|
15
|
+
async test({ url }) {
|
|
16
|
+
logger_1.default.info('Starting ReferrerPolicy test...');
|
|
17
|
+
const response = await request_1.default.get(url);
|
|
18
|
+
if (!Object.prototype.hasOwnProperty.call(response.headers, 'referrer-policy')) {
|
|
19
|
+
return {
|
|
20
|
+
status: 'WARNING',
|
|
21
|
+
title: 'Referrer-Policy',
|
|
22
|
+
description: 'Response headers does not contain referrer-policy header!',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
status: 'SUCCESS',
|
|
27
|
+
title: 'Referrer-Policy',
|
|
28
|
+
description: `The value of referrer-policy header is ${response.headers['referrer-policy']}.`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.default = ReferrerPolicy;
|
|
@@ -0,0 +1,28 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
class RobotsTXT extends Test_1.default {
|
|
10
|
+
name = 'Robots.txt';
|
|
11
|
+
async test({ url }) {
|
|
12
|
+
logger_1.default.info('Starting robotstxt test...');
|
|
13
|
+
const response = await request_1.default.get(url + '/robots.txt');
|
|
14
|
+
if (response !== null && response.statusCode === 200) {
|
|
15
|
+
return {
|
|
16
|
+
status: 'SUCCESS',
|
|
17
|
+
title: 'Robots.txt',
|
|
18
|
+
description: 'Site does contain robots.txt',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
status: 'ERROR',
|
|
23
|
+
title: 'Robots.txt',
|
|
24
|
+
description: 'Site does not contain robots.txt',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.default = RobotsTXT;
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
const ssl_checker_1 = __importDefault(require("ssl-checker"));
|
|
7
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
class SSL extends Test_1.default {
|
|
10
|
+
name = 'SSL';
|
|
11
|
+
async test({ url }) {
|
|
12
|
+
logger_1.default.info('Starting SSL test...');
|
|
13
|
+
const hostname = (new URL(url)).hostname;
|
|
14
|
+
const sslDetails = await (0, ssl_checker_1.default)(hostname);
|
|
15
|
+
if (!sslDetails.valid) {
|
|
16
|
+
return {
|
|
17
|
+
status: 'ERROR',
|
|
18
|
+
title: this.name,
|
|
19
|
+
description: 'SSL certificate is not valid!',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (sslDetails.daysRemaining <= 7) {
|
|
23
|
+
return {
|
|
24
|
+
status: 'WARNING',
|
|
25
|
+
title: this.name,
|
|
26
|
+
description: 'SSL certificate is valid for 7 or less days!',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
status: 'SUCCESS',
|
|
31
|
+
title: this.name,
|
|
32
|
+
description: `SSL certificate is valid until ${sslDetails.validTo}.`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.default = SSL;
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
|
|
12
|
+
*/
|
|
13
|
+
class XFrameOptions extends Test_1.default {
|
|
14
|
+
name = 'X-Frame-Options';
|
|
15
|
+
async test({ url }) {
|
|
16
|
+
logger_1.default.info('Starting X-Frame-Options test...');
|
|
17
|
+
const response = await request_1.default.get(url);
|
|
18
|
+
if (!Object.prototype.hasOwnProperty.call(response.headers, 'x-frame-options')) {
|
|
19
|
+
return {
|
|
20
|
+
status: 'ERROR',
|
|
21
|
+
title: 'X-Frame-Options',
|
|
22
|
+
description: 'Response headers does not contain x-frame-options header!',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
status: 'SUCCESS',
|
|
27
|
+
title: 'X-Frame-Options',
|
|
28
|
+
description: `The value of x-frame-options header is ${response.headers['x-frame-options']}.`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.default = XFrameOptions;
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
7
|
+
const request_1 = __importDefault(require("../request"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
|
|
12
|
+
*/
|
|
13
|
+
class XXSSProtection extends Test_1.default {
|
|
14
|
+
name = 'X-XSS-Protection';
|
|
15
|
+
async test({ url }) {
|
|
16
|
+
logger_1.default.info('Starting X-XSS-Protection test...');
|
|
17
|
+
const response = await request_1.default.get(url);
|
|
18
|
+
if (!Object.prototype.hasOwnProperty.call(response.headers, 'x-xss-protection')) {
|
|
19
|
+
return {
|
|
20
|
+
status: 'ERROR',
|
|
21
|
+
title: 'X-XSS-Protection',
|
|
22
|
+
description: 'Response headers does not contain x-xss-protection header!',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
status: 'SUCCESS',
|
|
27
|
+
title: 'X-XSS-Protection',
|
|
28
|
+
description: `The value of x-xss-protection header is ${response.headers['x-xss-protection']}.`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.default = XXSSProtection;
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
14
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
6
|
const ContentSecurityPolicy_1 = __importDefault(require("../ContentSecurityPolicy"));
|
|
16
7
|
const request_1 = __importDefault(require("../../request"));
|
|
17
|
-
test('Content-Security-Policy test with correct header', () =>
|
|
8
|
+
test('Content-Security-Policy test with correct header', async () => {
|
|
18
9
|
const pentest = new ContentSecurityPolicy_1.default();
|
|
19
10
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
20
|
-
const mock = jest.spyOn(request_1.default, 'get').mockImplementation(() =>
|
|
11
|
+
const mock = jest.spyOn(request_1.default, 'get').mockImplementation(async () => {
|
|
21
12
|
return new Promise((resolve) => {
|
|
22
13
|
resolve({
|
|
23
14
|
headers: {
|
|
@@ -25,22 +16,22 @@ test('Content-Security-Policy test with correct header', () => __awaiter(void 0,
|
|
|
25
16
|
},
|
|
26
17
|
});
|
|
27
18
|
});
|
|
28
|
-
})
|
|
29
|
-
const result =
|
|
19
|
+
});
|
|
20
|
+
const result = await pentest.run({ url: 'https://juffalow.com' });
|
|
30
21
|
expect(result.status).toEqual('SUCCESS');
|
|
31
22
|
mock.mockRestore();
|
|
32
|
-
})
|
|
33
|
-
test('Content-Security-Policy test with missing Content-Security-Policy header', () =>
|
|
23
|
+
});
|
|
24
|
+
test('Content-Security-Policy test with missing Content-Security-Policy header', async () => {
|
|
34
25
|
const pentest = new ContentSecurityPolicy_1.default();
|
|
35
26
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
36
|
-
const mock = jest.spyOn(request_1.default, 'get').mockImplementation(() =>
|
|
27
|
+
const mock = jest.spyOn(request_1.default, 'get').mockImplementation(async () => {
|
|
37
28
|
return new Promise((resolve) => {
|
|
38
29
|
resolve({
|
|
39
30
|
headers: {}
|
|
40
31
|
});
|
|
41
32
|
});
|
|
42
|
-
})
|
|
43
|
-
const result =
|
|
33
|
+
});
|
|
34
|
+
const result = await pentest.run({ url: 'https://juffalow.com' });
|
|
44
35
|
expect(result.status).toEqual('ERROR');
|
|
45
36
|
mock.mockRestore();
|
|
46
|
-
})
|
|
37
|
+
});
|