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
package/dist/Pentest.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
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 security_1 = __importDefault(require("./security"));
|
|
7
|
+
const dns_1 = __importDefault(require("./dns"));
|
|
8
|
+
const html_1 = __importDefault(require("./html"));
|
|
9
|
+
const seo_1 = __importDefault(require("./seo"));
|
|
10
|
+
const wordpress_1 = __importDefault(require("./wordpress"));
|
|
11
|
+
const metadata_1 = __importDefault(require("./metadata"));
|
|
12
|
+
class Pentest {
|
|
13
|
+
async run(url) {
|
|
14
|
+
const general = new dns_1.default();
|
|
15
|
+
const security = new security_1.default();
|
|
16
|
+
const html = new html_1.default();
|
|
17
|
+
const seo = new seo_1.default();
|
|
18
|
+
const wordPress = new wordpress_1.default();
|
|
19
|
+
const metadata = new metadata_1.default();
|
|
20
|
+
const [generalResult, securityResult, htmlResult, seoResult, wordPressResult, metadataResult] = await Promise.all([
|
|
21
|
+
general.run({ url }),
|
|
22
|
+
security.run({ url }),
|
|
23
|
+
html.run({ url }),
|
|
24
|
+
seo.run({ url }),
|
|
25
|
+
wordPress.run({ url }),
|
|
26
|
+
metadata.run({ url }),
|
|
27
|
+
]);
|
|
28
|
+
// const [ generalResult, securityResult, htmlResult, seoResult, wordPressResult ] = result.map(promise => promise.status === 'fulfilled' ? promise.value : {});
|
|
29
|
+
// const [ generalResult, securityResult, htmlResult, seoResult, wordPressResult ] = result;
|
|
30
|
+
// const generalResult = <Result> await general.run({ url });
|
|
31
|
+
// const securityResult = <Result> await security.run({ url });
|
|
32
|
+
// const htmlResult = <Result> await html.run({ url });
|
|
33
|
+
// const seoResult = <Result> await seo.run({ url });
|
|
34
|
+
// const wordPressResult = <Result> await wordPress.run({ url });
|
|
35
|
+
// console.log(metadataResult);
|
|
36
|
+
return {
|
|
37
|
+
security: securityResult,
|
|
38
|
+
dns: generalResult,
|
|
39
|
+
html: htmlResult,
|
|
40
|
+
seo: seoResult,
|
|
41
|
+
wordpress: wordPressResult,
|
|
42
|
+
metadata: metadataResult,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = Pentest;
|
|
@@ -1,13 +1,4 @@
|
|
|
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
|
};
|
|
@@ -19,22 +10,18 @@ const logger_1 = __importDefault(require("./logger"));
|
|
|
19
10
|
*/
|
|
20
11
|
delete require.cache[__filename];
|
|
21
12
|
class Test {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
title: test.name,
|
|
33
|
-
description: 'Test failed or cannot be run!',
|
|
34
|
-
};
|
|
35
|
-
});
|
|
36
|
-
return result;
|
|
13
|
+
tests = [];
|
|
14
|
+
async run(params) {
|
|
15
|
+
logger_1.default.debug(`Running ${this.name} tests...`);
|
|
16
|
+
const result = await this.test(params).catch((err) => {
|
|
17
|
+
console.error(err);
|
|
18
|
+
return {
|
|
19
|
+
status: 'ERROR',
|
|
20
|
+
title: test.name,
|
|
21
|
+
description: 'Test failed or cannot be run!',
|
|
22
|
+
};
|
|
37
23
|
});
|
|
24
|
+
return result;
|
|
38
25
|
}
|
|
39
26
|
getTests() {
|
|
40
27
|
return this.tests.filter((test) => {
|
|
@@ -0,0 +1,79 @@
|
|
|
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 request_1 = __importDefault(require("../request"));
|
|
7
|
+
const functions_1 = require("../functions");
|
|
8
|
+
/**
|
|
9
|
+
* Check URL if contains sitemap data. If URL is not direct link
|
|
10
|
+
* to *.xml file, it will try to search it. For example by default
|
|
11
|
+
* it is located in the root of the page (/sitemap.xml) or it can
|
|
12
|
+
* be mentioned in /robots.txt.
|
|
13
|
+
*
|
|
14
|
+
* There are 2 types of sitemap. One is common, which starts with
|
|
15
|
+
* <urlset> tag and then there is sitemap index, wich is used
|
|
16
|
+
* to group multiple sitemap files. This starts with <sitemapindex>
|
|
17
|
+
* tag.
|
|
18
|
+
*
|
|
19
|
+
* Example:
|
|
20
|
+
*
|
|
21
|
+
* <?xml version="1.0" encoding="utf-8"?>
|
|
22
|
+
* <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
23
|
+
* <url>
|
|
24
|
+
* <loc>http://example.com/</loc>
|
|
25
|
+
* </url>
|
|
26
|
+
* </urlset>
|
|
27
|
+
*
|
|
28
|
+
* <?xml version="1.0" encoding="UTF-8"?>
|
|
29
|
+
* <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
30
|
+
* <sitemap>
|
|
31
|
+
* <loc>http://www.example.com/sitemap.xml</loc>
|
|
32
|
+
* </sitemap>
|
|
33
|
+
* </sitemapindex>
|
|
34
|
+
*
|
|
35
|
+
* @see https://en.wikipedia.org/wiki/Sitemaps
|
|
36
|
+
* @see https://www.sitemaps.org/protocol.html
|
|
37
|
+
* @see https://technicalseo.com/tools/docs/robots-txt/
|
|
38
|
+
*/
|
|
39
|
+
class Sitemap {
|
|
40
|
+
async run(url) {
|
|
41
|
+
/*
|
|
42
|
+
if (!url.endsWith('.xml')) {}
|
|
43
|
+
*/
|
|
44
|
+
const sitemap = await this.loadSitemap(url);
|
|
45
|
+
// console.log(sitemap);
|
|
46
|
+
return sitemap.urlset.url.map((line) => line.loc[0]);
|
|
47
|
+
}
|
|
48
|
+
async searchSitemaps() {
|
|
49
|
+
// check /sitemap.xml
|
|
50
|
+
// check /robots.txt
|
|
51
|
+
}
|
|
52
|
+
async loadSitemap(url) {
|
|
53
|
+
const xml = await request_1.default.get(url);
|
|
54
|
+
const sitemap = await (0, functions_1.parseXml)(xml);
|
|
55
|
+
if (!this.isIndex(sitemap)) {
|
|
56
|
+
return sitemap;
|
|
57
|
+
}
|
|
58
|
+
const sitemapUrls = this.getSitemapUrls(sitemap);
|
|
59
|
+
return this.loadMultiple(sitemapUrls);
|
|
60
|
+
}
|
|
61
|
+
isIndex(sitemap) {
|
|
62
|
+
return 'sitemapindex' in sitemap;
|
|
63
|
+
}
|
|
64
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
65
|
+
getSitemapUrls(sitemapIndex) {
|
|
66
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
67
|
+
return sitemapIndex.sitemapindex.sitemap.map((sitemap) => sitemap.loc[0]);
|
|
68
|
+
}
|
|
69
|
+
async loadMultiple(sitemapUrls) {
|
|
70
|
+
const sitemaps = await Promise.all(sitemapUrls.map(async (sitemapUrl) => await this.loadSitemap(sitemapUrl)));
|
|
71
|
+
const urls = sitemaps.map((s) => s.urlset.url).reduce((arr, s) => arr.concat(s), []);
|
|
72
|
+
return {
|
|
73
|
+
urlset: {
|
|
74
|
+
url: urls,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.default = Sitemap;
|
package/dist/dns/A.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
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 dns_1 = __importDefault(require("dns"));
|
|
7
|
+
const whois_1 = __importDefault(require("whois"));
|
|
8
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
9
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
10
|
+
class A extends Test_1.default {
|
|
11
|
+
name = 'A';
|
|
12
|
+
async test({ url }) {
|
|
13
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
14
|
+
const response = await new Promise((resolve, reject) => {
|
|
15
|
+
dns_1.default.lookup((new URL(url).hostname), { all: true }, (err, addresses) => {
|
|
16
|
+
if (err) {
|
|
17
|
+
return reject(err);
|
|
18
|
+
}
|
|
19
|
+
resolve(addresses);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
23
|
+
const addresses = await Promise.all(response.map(async (address) => {
|
|
24
|
+
const organization = await this.getOrganization(address.address);
|
|
25
|
+
return `${address.address} - ${organization}`;
|
|
26
|
+
}));
|
|
27
|
+
return {
|
|
28
|
+
status: 'SUCCESS',
|
|
29
|
+
title: this.constructor.name,
|
|
30
|
+
description: addresses.join('\n'),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async getOrganization(ip) {
|
|
34
|
+
const organization = await new Promise((resolve, reject) => {
|
|
35
|
+
whois_1.default.lookup(ip, function (err, data) {
|
|
36
|
+
if (err) {
|
|
37
|
+
return reject(err);
|
|
38
|
+
}
|
|
39
|
+
const organization = (typeof data === 'string' ? data.split('\n') : data)
|
|
40
|
+
.filter((line) => line.includes('OrgName'))
|
|
41
|
+
.map((line) => line.split(':')[1].trim())
|
|
42
|
+
.pop();
|
|
43
|
+
resolve(organization);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
return organization;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.default = A;
|
|
@@ -0,0 +1,59 @@
|
|
|
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 dns_1 = __importDefault(require("dns"));
|
|
7
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
const getDomain_1 = __importDefault(require("../functions/getDomain"));
|
|
10
|
+
class DMARC extends Test_1.default {
|
|
11
|
+
name = 'DMARC';
|
|
12
|
+
async test({ url }) {
|
|
13
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
14
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
15
|
+
const response = await new Promise((resolve, reject) => {
|
|
16
|
+
dns_1.default.resolveTxt(`_dmarc.${(0, getDomain_1.default)(url)}`, (err, records) => {
|
|
17
|
+
if (err) {
|
|
18
|
+
return reject(err);
|
|
19
|
+
}
|
|
20
|
+
resolve(records);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
if (response.length === 0) {
|
|
24
|
+
return {
|
|
25
|
+
status: 'WARNING',
|
|
26
|
+
title: this.constructor.name,
|
|
27
|
+
description: 'No DMARC record found for this domain.',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const record = response.shift().shift();
|
|
31
|
+
if (record.includes('p=none')) {
|
|
32
|
+
return {
|
|
33
|
+
status: 'ERROR',
|
|
34
|
+
title: this.constructor.name,
|
|
35
|
+
description: 'Email that fails DMARC Compliance tests will be delivered to the recipient\'s inbox.',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (record.includes('p=quarantine')) {
|
|
39
|
+
return {
|
|
40
|
+
status: 'WARNING',
|
|
41
|
+
title: this.constructor.name,
|
|
42
|
+
description: 'Email that fails DMARC Compliance tests will be marked as spam.',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (record.includes('p=reject')) {
|
|
46
|
+
return {
|
|
47
|
+
status: 'SUCCESS',
|
|
48
|
+
title: this.constructor.name,
|
|
49
|
+
description: 'Email that fails DMARC Compliance tests will be rejected.',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
status: 'ERROR',
|
|
54
|
+
title: this.constructor.name,
|
|
55
|
+
description: 'Invalid DMARC policy found!',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.default = DMARC;
|
package/dist/dns/NS.js
ADDED
|
@@ -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 whois_1 = __importDefault(require("whois"));
|
|
7
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
const getDomain_1 = __importDefault(require("../functions/getDomain"));
|
|
10
|
+
class NS extends Test_1.default {
|
|
11
|
+
name = 'NS';
|
|
12
|
+
async test({ url }) {
|
|
13
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
14
|
+
const nameServers = await this.getNameServers((0, getDomain_1.default)(url));
|
|
15
|
+
return {
|
|
16
|
+
status: 'SUCCESS',
|
|
17
|
+
title: this.constructor.name,
|
|
18
|
+
description: nameServers.join('\n'),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async getNameServers(domain) {
|
|
22
|
+
const nameServers = await new Promise((resolve, reject) => {
|
|
23
|
+
whois_1.default.lookup(domain, function (err, data) {
|
|
24
|
+
if (err) {
|
|
25
|
+
return reject(err);
|
|
26
|
+
}
|
|
27
|
+
const nameServers = (typeof data === 'string' ? data.split('\n') : data)
|
|
28
|
+
.filter((line) => line.includes('Name Server'))
|
|
29
|
+
.map((line) => line.split(':')[1].trim());
|
|
30
|
+
resolve(nameServers);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
return nameServers;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.default = NS;
|
|
@@ -0,0 +1,39 @@
|
|
|
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 whois_1 = __importDefault(require("whois"));
|
|
7
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
const getDomain_1 = __importDefault(require("../functions/getDomain"));
|
|
10
|
+
class RegistrationDate extends Test_1.default {
|
|
11
|
+
name = 'RegistrationDate';
|
|
12
|
+
async test({ url }) {
|
|
13
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
14
|
+
const registrationDate = await this.getRegistrationDate((0, getDomain_1.default)(url));
|
|
15
|
+
const diffInMs = (new Date(registrationDate)).getTime() - (new Date()).getTime();
|
|
16
|
+
const diffInDays = diffInMs / (1000 * 60 * 60 * 24);
|
|
17
|
+
return {
|
|
18
|
+
status: diffInDays < 7 ? 'ERROR' : diffInDays < 30 ? 'WARNING' : 'SUCCESS',
|
|
19
|
+
title: this.constructor.name,
|
|
20
|
+
description: `Approximately ${Math.floor(diffInDays)} days until domain expires.`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async getRegistrationDate(domain) {
|
|
24
|
+
const date = await new Promise((resolve, reject) => {
|
|
25
|
+
whois_1.default.lookup(domain, function (err, data) {
|
|
26
|
+
if (err) {
|
|
27
|
+
return reject(err);
|
|
28
|
+
}
|
|
29
|
+
const d = (typeof data === 'string' ? data.split('\n') : data)
|
|
30
|
+
.filter((line) => line.includes('Expiration Date') || line.includes('Valid Until'))
|
|
31
|
+
.map((line) => line.split(': ')[1].trim())
|
|
32
|
+
.shift();
|
|
33
|
+
resolve(d);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
return date;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.default = RegistrationDate;
|
|
@@ -0,0 +1,47 @@
|
|
|
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 A_1 = __importDefault(require("./A"));
|
|
8
|
+
const NS_1 = __importDefault(require("./NS"));
|
|
9
|
+
const DMARC_1 = __importDefault(require("./DMARC"));
|
|
10
|
+
const RegistrationDate_1 = __importDefault(require("./RegistrationDate"));
|
|
11
|
+
class DNS extends Test_1.default {
|
|
12
|
+
name = 'DNS';
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.tests = [
|
|
16
|
+
new RegistrationDate_1.default(),
|
|
17
|
+
new NS_1.default(),
|
|
18
|
+
new A_1.default(),
|
|
19
|
+
new DMARC_1.default(),
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
async test(params) {
|
|
23
|
+
const tests = this.getTests();
|
|
24
|
+
const results = [];
|
|
25
|
+
for (const test of tests) {
|
|
26
|
+
let result = null;
|
|
27
|
+
try {
|
|
28
|
+
result = await test.run(params);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
result = {
|
|
32
|
+
status: 'ERROR',
|
|
33
|
+
title: test.name,
|
|
34
|
+
description: 'Test failed or cannot be run!',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
results.push(result);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
status: this.getStatus(results.map(result => result.status)),
|
|
41
|
+
title: this.name,
|
|
42
|
+
description: '',
|
|
43
|
+
results,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.default = DNS;
|
|
@@ -0,0 +1,12 @@
|
|
|
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.default = default_1;
|
|
7
|
+
const parseXml_1 = __importDefault(require("./parseXml"));
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
9
|
+
async function default_1(sitemap) {
|
|
10
|
+
const data = await (0, parseXml_1.default)(sitemap);
|
|
11
|
+
return data.urlset.url.map((url) => url.loc[0]);
|
|
12
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
const functions_1 = require("../functions");
|
|
10
|
+
class Anchor extends Test_1.default {
|
|
11
|
+
name = 'Anchor';
|
|
12
|
+
async test({ url }) {
|
|
13
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
14
|
+
const response = await request_1.default.get(url);
|
|
15
|
+
const html = await (0, functions_1.parseHtml)(response);
|
|
16
|
+
const anchors = (0, functions_1.getAnchors)(html);
|
|
17
|
+
const subTests = await this.check(anchors);
|
|
18
|
+
return {
|
|
19
|
+
status: this.getStatus(subTests.map(test => test.status)),
|
|
20
|
+
title: this.constructor.name,
|
|
21
|
+
description: '',
|
|
22
|
+
results: subTests,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async check(anchors) {
|
|
26
|
+
const results = [];
|
|
27
|
+
for (const anchor of anchors) {
|
|
28
|
+
logger_1.default.verbose(`Checking ${anchor}...`);
|
|
29
|
+
const result = await request_1.default.get(anchor);
|
|
30
|
+
const isFileAvailabe = {
|
|
31
|
+
status: this.isFileAvailable(result) ? 'SUCCESS' : 'ERROR',
|
|
32
|
+
title: 'Available',
|
|
33
|
+
description: '',
|
|
34
|
+
};
|
|
35
|
+
results.push({
|
|
36
|
+
status: this.getStatus([
|
|
37
|
+
isFileAvailabe.status,
|
|
38
|
+
]), // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
39
|
+
title: anchor,
|
|
40
|
+
description: '',
|
|
41
|
+
results: [
|
|
42
|
+
isFileAvailabe,
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
48
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
49
|
+
isFileAvailable(result) {
|
|
50
|
+
if (result.response.statusCode === 404 || result.response.statusCode === 500) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.default = Anchor;
|
package/dist/html/CSS.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
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 csso_1 = __importDefault(require("csso"));
|
|
7
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
8
|
+
const request_1 = __importDefault(require("../request"));
|
|
9
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
10
|
+
const functions_1 = require("../functions");
|
|
11
|
+
class CSS extends Test_1.default {
|
|
12
|
+
name = 'CSS';
|
|
13
|
+
async test({ url }) {
|
|
14
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
15
|
+
const response = await request_1.default.get(url);
|
|
16
|
+
const html = await (0, functions_1.parseHtml)(response);
|
|
17
|
+
const stylesheets = (0, functions_1.getStylesheets)(html);
|
|
18
|
+
const subTests = await this.check(stylesheets);
|
|
19
|
+
return {
|
|
20
|
+
status: this.getStatus(subTests.map(test => test.status)),
|
|
21
|
+
title: this.constructor.name,
|
|
22
|
+
description: '',
|
|
23
|
+
results: subTests,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async check(stylesheets) {
|
|
27
|
+
const results = [];
|
|
28
|
+
for (const stylesheet of stylesheets) {
|
|
29
|
+
const filename = stylesheet.substring(stylesheet.lastIndexOf('/') + 1);
|
|
30
|
+
logger_1.default.verbose(`Checking ${filename}...`);
|
|
31
|
+
const result = await request_1.default.get(stylesheet);
|
|
32
|
+
const isFileAvailabe = {
|
|
33
|
+
status: this.isFileAvailable(result) ? 'SUCCESS' : 'ERROR',
|
|
34
|
+
title: 'Available',
|
|
35
|
+
description: '',
|
|
36
|
+
};
|
|
37
|
+
const isCached = {
|
|
38
|
+
status: this.isCached(result) ? 'SUCCESS' : 'ERROR',
|
|
39
|
+
title: 'Cached',
|
|
40
|
+
description: '',
|
|
41
|
+
};
|
|
42
|
+
const hasXContentTypeOptionsHeader = {
|
|
43
|
+
status: this.hasXContentTypeOptionsHeader(result) ? 'SUCCESS' : 'WARNING',
|
|
44
|
+
title: 'X-Content-Type-Options',
|
|
45
|
+
description: '',
|
|
46
|
+
};
|
|
47
|
+
const isMinified = {
|
|
48
|
+
status: this.isMinified(result) ? 'SUCCESS' : 'WARNING',
|
|
49
|
+
title: 'Minified',
|
|
50
|
+
description: '',
|
|
51
|
+
};
|
|
52
|
+
results.push({
|
|
53
|
+
status: this.getStatus([
|
|
54
|
+
isFileAvailabe.status,
|
|
55
|
+
isCached.status,
|
|
56
|
+
hasXContentTypeOptionsHeader.status,
|
|
57
|
+
isMinified.status,
|
|
58
|
+
]), // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
59
|
+
title: filename,
|
|
60
|
+
description: '',
|
|
61
|
+
results: [
|
|
62
|
+
isFileAvailabe,
|
|
63
|
+
isCached,
|
|
64
|
+
hasXContentTypeOptionsHeader,
|
|
65
|
+
isMinified,
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
72
|
+
isFileAvailable(result) {
|
|
73
|
+
if (result.response.statusCode === 404 || result.response.statusCode === 500) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
79
|
+
isCached(result) {
|
|
80
|
+
return result.response.headers.has('cache-control');
|
|
81
|
+
}
|
|
82
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
83
|
+
hasXContentTypeOptionsHeader(result) {
|
|
84
|
+
return result.response.headers.has('x-content-type-options');
|
|
85
|
+
}
|
|
86
|
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
87
|
+
isMinified(result) {
|
|
88
|
+
const r = csso_1.default.minify(result.body, { restructure: false }).css;
|
|
89
|
+
return r.length === result.body.length;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.default = CSS;
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
const functions_1 = require("../functions");
|
|
10
|
+
class DuplicateId extends Test_1.default {
|
|
11
|
+
name = 'Duplicate ID';
|
|
12
|
+
async test({ url }) {
|
|
13
|
+
logger_1.default.info('Starting DuplicateId test...');
|
|
14
|
+
const response = await request_1.default.get(url);
|
|
15
|
+
const duplicates = await (0, functions_1.getDuplicates)(response);
|
|
16
|
+
if (duplicates.length > 0) {
|
|
17
|
+
return {
|
|
18
|
+
status: 'WARNING',
|
|
19
|
+
title: 'Duplicate IDs',
|
|
20
|
+
description: '',
|
|
21
|
+
results: duplicates.map(duplicate => ({
|
|
22
|
+
status: 'WARNING',
|
|
23
|
+
title: `<${duplicate.name} id="${duplicate.attribs.id}" ... />`,
|
|
24
|
+
description: '',
|
|
25
|
+
}))
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
status: 'SUCCESS',
|
|
30
|
+
title: 'Duplicate IDs',
|
|
31
|
+
description: ''
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.default = DuplicateId;
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
const functions_1 = require("../functions");
|
|
10
|
+
class Generator extends Test_1.default {
|
|
11
|
+
name = 'Generator';
|
|
12
|
+
async test({ url }) {
|
|
13
|
+
logger_1.default.info('Starting DuplicateId test...');
|
|
14
|
+
const response = await request_1.default.get(url);
|
|
15
|
+
const html = await (0, functions_1.parseHtml)(response);
|
|
16
|
+
const generators = await (0, functions_1.getGenerator)(html);
|
|
17
|
+
if (generators.length > 0) {
|
|
18
|
+
return {
|
|
19
|
+
status: 'WARNING',
|
|
20
|
+
title: this.name,
|
|
21
|
+
description: 'Page contains inmformation about its generator!',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
status: 'SUCCESS',
|
|
26
|
+
title: this.name,
|
|
27
|
+
description: 'Page doesn\t contain any information about its generator.',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.default = Generator;
|