pentest-tool-lite 3.6.4 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/Pentest.d.ts +1 -0
- package/src/Pentest.js +4 -0
- package/src/Test.d.ts +3 -3
- package/src/functions/getHeading.d.ts +2 -0
- package/src/functions/getHeading.js +14 -0
- package/src/functions/getTitle.d.ts +2 -0
- package/src/functions/getTitle.js +14 -0
- package/src/functions/index.d.ts +2 -0
- package/src/functions/index.js +5 -1
- package/src/functions/parseXml.js +3 -0
- package/src/index +1 -1
- package/src/request/Request.d.ts +2 -2
- package/src/security/GoogleWebRisk.d.ts +12 -0
- package/src/security/GoogleWebRisk.js +58 -0
- package/src/security/index.js +2 -0
- package/src/seo/Heading.d.ts +7 -0
- package/src/seo/Heading.js +58 -0
- package/src/seo/Robots.d.ts +6 -0
- package/src/seo/Robots.js +35 -0
- package/src/seo/Sitemap.d.ts +6 -0
- package/src/seo/Sitemap.js +46 -0
- package/src/seo/Title.d.ts +7 -0
- package/src/seo/Title.js +58 -0
- package/src/seo/index.d.ts +6 -0
- package/src/seo/index.js +58 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pentest-tool-lite",
|
|
3
3
|
"description": "Check your website ( or any other website ) for common vulnerabilities.",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.8.0",
|
|
5
5
|
"homepage": "https://pentest-tool-lite.com",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"pentest-tool-lite": "./src/index"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
+
"@google-cloud/web-risk": "^4.0.1",
|
|
16
17
|
"commander": "^6.0.0",
|
|
17
18
|
"csso": "^5.0.5",
|
|
18
19
|
"domhandler": "^4.2.2",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@types/jest": "^27.0.2",
|
|
40
|
-
"@types/node": "^
|
|
41
|
+
"@types/node": "^18.18.4",
|
|
41
42
|
"@types/node-fetch": "^2.5.7",
|
|
42
43
|
"@types/uglify-js": "^3.0.4",
|
|
43
44
|
"@types/xml2js": "^0.4.5",
|
package/src/Pentest.d.ts
CHANGED
package/src/Pentest.js
CHANGED
|
@@ -14,19 +14,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const security_1 = __importDefault(require("./security"));
|
|
16
16
|
const html_1 = __importDefault(require("./html"));
|
|
17
|
+
const seo_1 = __importDefault(require("./seo"));
|
|
17
18
|
const wordpress_1 = __importDefault(require("./wordpress"));
|
|
18
19
|
class Pentest {
|
|
19
20
|
run(url) {
|
|
20
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
22
|
const security = new security_1.default();
|
|
22
23
|
const html = new html_1.default();
|
|
24
|
+
const seo = new seo_1.default();
|
|
23
25
|
const wordPress = new wordpress_1.default();
|
|
24
26
|
const securityResult = yield security.run({ url });
|
|
25
27
|
const htmlResult = yield html.run({ url });
|
|
28
|
+
const seoResult = yield seo.run({ url });
|
|
26
29
|
const wordPressResult = yield wordPress.run({ url });
|
|
27
30
|
return {
|
|
28
31
|
security: securityResult,
|
|
29
32
|
html: htmlResult,
|
|
33
|
+
seo: seoResult,
|
|
30
34
|
wordpress: wordPressResult,
|
|
31
35
|
};
|
|
32
36
|
});
|
package/src/Test.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type TestParameters = {
|
|
2
2
|
url: string;
|
|
3
3
|
};
|
|
4
|
-
export
|
|
5
|
-
export
|
|
4
|
+
export type Status = 'FATAL' | 'ERROR' | 'WARNING' | 'SUCCESS';
|
|
5
|
+
export type Result = {
|
|
6
6
|
status: Status;
|
|
7
7
|
title: string;
|
|
8
8
|
description: string;
|
|
@@ -0,0 +1,14 @@
|
|
|
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 getObject_1 = __importDefault(require("./getObject"));
|
|
7
|
+
const getHeading = (result) => {
|
|
8
|
+
const titles = (0, getObject_1.default)(result.html, 'name', 'h1')
|
|
9
|
+
.map((title) => {
|
|
10
|
+
return title.children[0].data;
|
|
11
|
+
});
|
|
12
|
+
return titles.length > 1 ? titles : titles.shift();
|
|
13
|
+
};
|
|
14
|
+
exports.default = getHeading;
|
|
@@ -0,0 +1,14 @@
|
|
|
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 getObject_1 = __importDefault(require("./getObject"));
|
|
7
|
+
const getTitle = (result) => {
|
|
8
|
+
const titles = (0, getObject_1.default)(result.html, 'name', 'title')
|
|
9
|
+
.map((title) => {
|
|
10
|
+
return title.children[0].data;
|
|
11
|
+
});
|
|
12
|
+
return titles.length > 1 ? titles : titles.shift();
|
|
13
|
+
};
|
|
14
|
+
exports.default = getTitle;
|
package/src/functions/index.d.ts
CHANGED
|
@@ -9,3 +9,5 @@ export { default as getGenerator } from './getGenerator';
|
|
|
9
9
|
export { default as parseHtml } from './parseHtml';
|
|
10
10
|
export { default as parseSitemap } from './parseSitemap';
|
|
11
11
|
export { default as parseXml } from './parseXml';
|
|
12
|
+
export { default as getTitle } from './getTitle';
|
|
13
|
+
export { default as getHeading } from './getHeading';
|
package/src/functions/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parseXml = exports.parseSitemap = exports.parseHtml = exports.getGenerator = exports.getObject = exports.getStylesheets = exports.getScripts = exports.getImages = exports.getDuplicates = exports.getAnchors = exports.findEvery = void 0;
|
|
6
|
+
exports.getHeading = exports.getTitle = exports.parseXml = exports.parseSitemap = exports.parseHtml = exports.getGenerator = exports.getObject = exports.getStylesheets = exports.getScripts = exports.getImages = exports.getDuplicates = exports.getAnchors = exports.findEvery = void 0;
|
|
7
7
|
var findEvery_1 = require("./findEvery");
|
|
8
8
|
Object.defineProperty(exports, "findEvery", { enumerable: true, get: function () { return __importDefault(findEvery_1).default; } });
|
|
9
9
|
var getAnchors_1 = require("./getAnchors");
|
|
@@ -26,3 +26,7 @@ var parseSitemap_1 = require("./parseSitemap");
|
|
|
26
26
|
Object.defineProperty(exports, "parseSitemap", { enumerable: true, get: function () { return __importDefault(parseSitemap_1).default; } });
|
|
27
27
|
var parseXml_1 = require("./parseXml");
|
|
28
28
|
Object.defineProperty(exports, "parseXml", { enumerable: true, get: function () { return __importDefault(parseXml_1).default; } });
|
|
29
|
+
var getTitle_1 = require("./getTitle");
|
|
30
|
+
Object.defineProperty(exports, "getTitle", { enumerable: true, get: function () { return __importDefault(getTitle_1).default; } });
|
|
31
|
+
var getHeading_1 = require("./getHeading");
|
|
32
|
+
Object.defineProperty(exports, "getHeading", { enumerable: true, get: function () { return __importDefault(getHeading_1).default; } });
|
package/src/index
CHANGED
|
@@ -70,7 +70,7 @@ program
|
|
|
70
70
|
const pentest = new Pentest_1.default();
|
|
71
71
|
const results = yield pentest.run(url);
|
|
72
72
|
const report = report_1.default.get(config_1.default.report.format);
|
|
73
|
-
report.write([results.security, results.html, results.wordpress]);
|
|
73
|
+
report.write([results.security, results.html, results.seo, results.wordpress]);
|
|
74
74
|
}));
|
|
75
75
|
program
|
|
76
76
|
.command('sitemap <URL>')
|
package/src/request/Request.d.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Test, { TestParameters, Result } from '../Test';
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @see https://cloud.google.com/web-risk
|
|
5
|
+
* @see https://safebrowsing.google.com
|
|
6
|
+
* @see https://transparencyreport.google.com/safe-browsing/search
|
|
7
|
+
*/
|
|
8
|
+
declare class GoogleWebRisk extends Test {
|
|
9
|
+
name: string;
|
|
10
|
+
test({ url }: TestParameters): Promise<Result>;
|
|
11
|
+
}
|
|
12
|
+
export default GoogleWebRisk;
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const web_risk_1 = require("@google-cloud/web-risk");
|
|
16
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
17
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @see https://cloud.google.com/web-risk
|
|
21
|
+
* @see https://safebrowsing.google.com
|
|
22
|
+
* @see https://transparencyreport.google.com/safe-browsing/search
|
|
23
|
+
*/
|
|
24
|
+
class GoogleWebRisk extends Test_1.default {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
this.name = 'GoogleWebRisk';
|
|
28
|
+
}
|
|
29
|
+
test({ url }) {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
logger_1.default.info('Starting Google Web Risk test...');
|
|
32
|
+
const client = new web_risk_1.WebRiskServiceClient();
|
|
33
|
+
const request = {
|
|
34
|
+
uri: url,
|
|
35
|
+
threatTypes: [
|
|
36
|
+
web_risk_1.protos.google.cloud.webrisk.v1.ThreatType.MALWARE,
|
|
37
|
+
web_risk_1.protos.google.cloud.webrisk.v1.ThreatType.SOCIAL_ENGINEERING,
|
|
38
|
+
web_risk_1.protos.google.cloud.webrisk.v1.ThreatType.UNWANTED_SOFTWARE,
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
const response = yield client.searchUris(request);
|
|
42
|
+
const { threat } = response[0];
|
|
43
|
+
if (threat !== null) {
|
|
44
|
+
return {
|
|
45
|
+
status: 'ERROR',
|
|
46
|
+
title: this.name,
|
|
47
|
+
description: `This url contains ${threat.threatTypes.join(', ').toLowerCase()}!`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
status: 'SUCCESS',
|
|
52
|
+
title: this.name,
|
|
53
|
+
description: 'This URL is safe.',
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.default = GoogleWebRisk;
|
package/src/security/index.js
CHANGED
|
@@ -26,6 +26,7 @@ const ReferrerPolicy_1 = __importDefault(require("./ReferrerPolicy"));
|
|
|
26
26
|
const RobotsTXT_1 = __importDefault(require("./RobotsTXT"));
|
|
27
27
|
const PermissionsPolicy_1 = __importDefault(require("./PermissionsPolicy"));
|
|
28
28
|
const SSL_1 = __importDefault(require("./SSL"));
|
|
29
|
+
const GoogleWebRisk_1 = __importDefault(require("./GoogleWebRisk"));
|
|
29
30
|
class Security extends Test_1.default {
|
|
30
31
|
constructor() {
|
|
31
32
|
super();
|
|
@@ -44,6 +45,7 @@ class Security extends Test_1.default {
|
|
|
44
45
|
new ContentEncoding_1.default(),
|
|
45
46
|
new RobotsTXT_1.default(),
|
|
46
47
|
new SSL_1.default(),
|
|
48
|
+
new GoogleWebRisk_1.default(),
|
|
47
49
|
];
|
|
48
50
|
}
|
|
49
51
|
test(params) {
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
16
|
+
const request_1 = __importDefault(require("../request"));
|
|
17
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
18
|
+
const functions_1 = require("../functions");
|
|
19
|
+
class Heading extends Test_1.default {
|
|
20
|
+
constructor() {
|
|
21
|
+
super(...arguments);
|
|
22
|
+
this.name = 'Heading';
|
|
23
|
+
}
|
|
24
|
+
test({ url }) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
27
|
+
const response = yield request_1.default.get(url);
|
|
28
|
+
const html = yield (0, functions_1.parseHtml)(response);
|
|
29
|
+
const heading = (0, functions_1.getHeading)(html);
|
|
30
|
+
const subTests = this.checkHeading(heading);
|
|
31
|
+
return {
|
|
32
|
+
status: this.getStatus(subTests.map(test => test.status)),
|
|
33
|
+
title: this.constructor.name,
|
|
34
|
+
description: '',
|
|
35
|
+
results: subTests,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
checkHeading(title) {
|
|
40
|
+
const results = [];
|
|
41
|
+
results.push({
|
|
42
|
+
status: typeof title !== undefined && title.length > 0 ? 'SUCCESS' : 'WARNING',
|
|
43
|
+
title: 'H1 tag',
|
|
44
|
+
});
|
|
45
|
+
results.push({
|
|
46
|
+
status: Array.isArray(title) ? 'ERROR' : 'SUCCESS',
|
|
47
|
+
title: 'Duplicate H1 tag',
|
|
48
|
+
description: `HTML should contain just one title tag.`,
|
|
49
|
+
});
|
|
50
|
+
results.push({
|
|
51
|
+
status: title.length <= 60 ? 'SUCCESS' : 'WARNING',
|
|
52
|
+
title: 'Title length',
|
|
53
|
+
description: `Title length should be under 60 characters and it is ${title.length}.`,
|
|
54
|
+
});
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.default = Heading;
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
16
|
+
const request_1 = __importDefault(require("../request"));
|
|
17
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
18
|
+
class Robots extends Test_1.default {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this.name = 'Robots';
|
|
22
|
+
}
|
|
23
|
+
test({ url }) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
26
|
+
const response = yield request_1.default.get(`${url}/robots.txt`);
|
|
27
|
+
return {
|
|
28
|
+
status: Math.floor(response.statusCode / 100) === 2 ? 'SUCCESS' : 'WARNING',
|
|
29
|
+
title: 'Robots.txt',
|
|
30
|
+
description: '',
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.default = Robots;
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
16
|
+
const request_1 = __importDefault(require("../request"));
|
|
17
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
18
|
+
const functions_1 = require("../functions");
|
|
19
|
+
class Sitemap extends Test_1.default {
|
|
20
|
+
constructor() {
|
|
21
|
+
super(...arguments);
|
|
22
|
+
this.name = 'Sitemap';
|
|
23
|
+
}
|
|
24
|
+
test({ url }) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
27
|
+
const robotsResponse = yield request_1.default.get(`${url}/robots.txt`);
|
|
28
|
+
let sitemapUrl = `${url}/sitemap.xml`;
|
|
29
|
+
if (Math.floor(robotsResponse.statusCode / 100) === 2) {
|
|
30
|
+
const lines = robotsResponse.body.split(/\r?\n/);
|
|
31
|
+
const sitemap = lines.find(line => line.startsWith('Sitemap'));
|
|
32
|
+
if (typeof sitemap !== 'undefined') {
|
|
33
|
+
sitemapUrl = sitemap.split(' ')[1];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const response = yield request_1.default.get(sitemapUrl);
|
|
37
|
+
const xml = yield (0, functions_1.parseXml)(response);
|
|
38
|
+
return {
|
|
39
|
+
status: 'sitemapindex' in xml || 'urlset' in xml ? 'SUCCESS' : 'WARNING',
|
|
40
|
+
title: this.constructor.name,
|
|
41
|
+
description: '',
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = Sitemap;
|
package/src/seo/Title.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
16
|
+
const request_1 = __importDefault(require("../request"));
|
|
17
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
18
|
+
const functions_1 = require("../functions");
|
|
19
|
+
class Title extends Test_1.default {
|
|
20
|
+
constructor() {
|
|
21
|
+
super(...arguments);
|
|
22
|
+
this.name = 'Title';
|
|
23
|
+
}
|
|
24
|
+
test({ url }) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
logger_1.default.info(`Starting ${this.constructor.name} test...`);
|
|
27
|
+
const response = yield request_1.default.get(url);
|
|
28
|
+
const html = yield (0, functions_1.parseHtml)(response);
|
|
29
|
+
const title = (0, functions_1.getTitle)(html);
|
|
30
|
+
const subTests = this.checkTitle(title);
|
|
31
|
+
return {
|
|
32
|
+
status: this.getStatus(subTests.map(test => test.status)),
|
|
33
|
+
title: this.constructor.name,
|
|
34
|
+
description: '',
|
|
35
|
+
results: subTests,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
checkTitle(title) {
|
|
40
|
+
const results = [];
|
|
41
|
+
results.push({
|
|
42
|
+
status: typeof title !== undefined && title.length > 0 ? 'SUCCESS' : 'WARNING',
|
|
43
|
+
title: 'Title tag',
|
|
44
|
+
});
|
|
45
|
+
results.push({
|
|
46
|
+
status: Array.isArray(title) ? 'ERROR' : 'SUCCESS',
|
|
47
|
+
title: 'Duplicate title tag',
|
|
48
|
+
description: `HTML should contain just one title tag.`,
|
|
49
|
+
});
|
|
50
|
+
results.push({
|
|
51
|
+
status: title.length <= 60 ? 'SUCCESS' : 'WARNING',
|
|
52
|
+
title: 'Title length',
|
|
53
|
+
description: `Title length should be under 60 characters and it is ${title.length}.`,
|
|
54
|
+
});
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.default = Title;
|
package/src/seo/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const Test_1 = __importDefault(require("../Test"));
|
|
16
|
+
const Title_1 = __importDefault(require("./Title"));
|
|
17
|
+
const Heading_1 = __importDefault(require("./Heading"));
|
|
18
|
+
const Sitemap_1 = __importDefault(require("./Sitemap"));
|
|
19
|
+
const Robots_1 = __importDefault(require("./Robots"));
|
|
20
|
+
class SEO extends Test_1.default {
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
this.name = 'SEO';
|
|
24
|
+
this.tests = [
|
|
25
|
+
new Title_1.default(),
|
|
26
|
+
new Heading_1.default(),
|
|
27
|
+
new Sitemap_1.default(),
|
|
28
|
+
new Robots_1.default(),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
test(params) {
|
|
32
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
const tests = this.getTests();
|
|
34
|
+
const results = [];
|
|
35
|
+
for (const test of tests) {
|
|
36
|
+
let result = null;
|
|
37
|
+
try {
|
|
38
|
+
result = yield test.run(params);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
result = {
|
|
42
|
+
status: 'ERROR',
|
|
43
|
+
title: test.name,
|
|
44
|
+
description: 'Test failed or cannot be run!',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
results.push(result);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
status: this.getStatus(results.map(result => result.status)),
|
|
51
|
+
title: this.name,
|
|
52
|
+
description: '',
|
|
53
|
+
results,
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.default = SEO;
|