whopper 0.5.9 → 0.7.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/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +56 -3
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.test.js +133 -0
- package/dist/browser/index.test.js.map +1 -1
- package/dist/browser/types.d.ts +1 -0
- package/dist/browser/types.d.ts.map +1 -1
- package/dist/commands/detect.d.ts.map +1 -1
- package/dist/commands/detect.js +2 -0
- package/dist/commands/detect.js.map +1 -1
- package/dist/commands/detect.test.js +5 -0
- package/dist/commands/detect.test.js.map +1 -1
- package/dist/commands/detect_utils.d.ts.map +1 -1
- package/dist/commands/detect_utils.js +23 -5
- package/dist/commands/detect_utils.js.map +1 -1
- package/dist/commands/detect_utils.test.js +86 -9
- package/dist/commands/detect_utils.test.js.map +1 -1
- package/dist/signatures/_types.d.ts +1 -0
- package/dist/signatures/_types.d.ts.map +1 -1
- package/dist/signatures/index.d.ts.map +1 -1
- package/dist/signatures/index.js +4 -0
- package/dist/signatures/index.js.map +1 -1
- package/dist/signatures/signatures.test.js +16 -0
- package/dist/signatures/signatures.test.js.map +1 -1
- package/dist/signatures/technologies/drupal.d.ts.map +1 -1
- package/dist/signatures/technologies/drupal.js +17 -0
- package/dist/signatures/technologies/drupal.js.map +1 -1
- package/dist/signatures/technologies/drupal.test.d.ts +2 -0
- package/dist/signatures/technologies/drupal.test.d.ts.map +1 -0
- package/dist/signatures/technologies/drupal.test.js +76 -0
- package/dist/signatures/technologies/drupal.test.js.map +1 -0
- package/dist/signatures/technologies/power_cms.d.ts +3 -0
- package/dist/signatures/technologies/power_cms.d.ts.map +1 -0
- package/dist/signatures/technologies/power_cms.js +51 -0
- package/dist/signatures/technologies/power_cms.js.map +1 -0
- package/dist/signatures/technologies/power_cms.test.d.ts +2 -0
- package/dist/signatures/technologies/power_cms.test.d.ts.map +1 -0
- package/dist/signatures/technologies/power_cms.test.js +83 -0
- package/dist/signatures/technologies/power_cms.test.js.map +1 -0
- package/dist/signatures/technologies/thinkphp.d.ts +3 -0
- package/dist/signatures/technologies/thinkphp.d.ts.map +1 -0
- package/dist/signatures/technologies/thinkphp.js +41 -0
- package/dist/signatures/technologies/thinkphp.js.map +1 -0
- package/dist/signatures/technologies/thinkphp.test.d.ts +2 -0
- package/dist/signatures/technologies/thinkphp.test.d.ts.map +1 -0
- package/dist/signatures/technologies/thinkphp.test.js +132 -0
- package/dist/signatures/technologies/thinkphp.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { movableTypeSignature } from "./movable_type.js";
|
|
2
|
+
import { perlSignature } from "./perl.js";
|
|
3
|
+
// PowerCMS is an Alfasado CMS built on top of Movable Type, so it shares the
|
|
4
|
+
// mt.cgi admin script and mt-static asset path with MT. Detection keys off the
|
|
5
|
+
// PowerCMS-specific plugin static path to tell it apart from plain MT, and the
|
|
6
|
+
// active mt.cgi admin probe captures the version from the admin footer when
|
|
7
|
+
// available (best-effort; admin pages are not always reachable).
|
|
8
|
+
const adminPageRegexes = [
|
|
9
|
+
// Admin footer version text, e.g. "PowerCMS version 5.43" / "PowerCMS 4.46".
|
|
10
|
+
// Version-bearing patterns come first so the version is captured when present.
|
|
11
|
+
// PowerCMS version numbers have irregular precision (2.0493 / 4.46 / 5.43),
|
|
12
|
+
// so accept an arbitrary number of dot-separated groups.
|
|
13
|
+
"PowerCMS version ([0-9]+(?:\\.[0-9]+)*)", // v5 footer
|
|
14
|
+
"PowerCMS ([0-9]+(?:\\.[0-9]+)*)", // v4 footer
|
|
15
|
+
// v6/v7 dropped the product-name prefix and show just "version 6.83". This
|
|
16
|
+
// bare fallback is intentionally last so v4/v5 still match the prefixed forms
|
|
17
|
+
// above (first-hit-wins), limiting its blast radius to v6/v7 pages. Requiring
|
|
18
|
+
// at least one dot avoids picking up single-token "version 3" style noise, and
|
|
19
|
+
// the leading \b prevents matching words that merely end in "version"
|
|
20
|
+
// (e.g. "Subversion 1.14.2").
|
|
21
|
+
"\\bversion ([0-9]+\\.[0-9]+(?:\\.[0-9]+)*)", // v6/v7 footer
|
|
22
|
+
"/mt-static/plugins/PowerCMS/", // PowerCMS-specific marker, confirms even without a version
|
|
23
|
+
];
|
|
24
|
+
const activeRules = [
|
|
25
|
+
"/mt.cgi?__mode=logout", // root install (common)
|
|
26
|
+
"/mt/mt.cgi?__mode=logout",
|
|
27
|
+
"/cgi-bin/mt/mt.cgi?__mode=logout",
|
|
28
|
+
"/blog/mt.cgi?__mode=logout",
|
|
29
|
+
].map((path) => ({ path, bodyRegexes: adminPageRegexes }));
|
|
30
|
+
// Detects PowerCMS from the PowerCMS-specific plugin static path on public
|
|
31
|
+
// pages, then confirms/extracts the version via the mt.cgi admin probe. When
|
|
32
|
+
// PowerCMS is detected, Movable Type is excluded from the output to avoid the
|
|
33
|
+
// underlying MT being reported alongside the actual product.
|
|
34
|
+
export const powerCmsSignature = {
|
|
35
|
+
name: "PowerCMS",
|
|
36
|
+
description: "PowerCMS is a Movable Type-based content management system by Alfasado Inc.",
|
|
37
|
+
cpe: "cpe:/a:alfasado:powercms", // CPE 2.2
|
|
38
|
+
rule: {
|
|
39
|
+
confidence: "high",
|
|
40
|
+
urls: [
|
|
41
|
+
"/mt-static/plugins/PowerCMS/", // distinguishes PowerCMS from plain Movable Type
|
|
42
|
+
],
|
|
43
|
+
bodies: [
|
|
44
|
+
"/mt-static/plugins/PowerCMS/", // same path referenced inline in public HTML
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
activeRules,
|
|
48
|
+
excludes: [movableTypeSignature.name], // PowerCMS supersedes the underlying Movable Type
|
|
49
|
+
impliedSoftwares: [perlSignature.name], // PowerCMS is a Perl application (like MT)
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=power_cms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power_cms.js","sourceRoot":"","sources":["../../../src/signatures/technologies/power_cms.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,iEAAiE;AACjE,MAAM,gBAAgB,GAAG;IACvB,6EAA6E;IAC7E,+EAA+E;IAC/E,4EAA4E;IAC5E,yDAAyD;IACzD,yCAAyC,EAAE,YAAY;IACvD,iCAAiC,EAAE,YAAY;IAC/C,2EAA2E;IAC3E,8EAA8E;IAC9E,8EAA8E;IAC9E,+EAA+E;IAC/E,sEAAsE;IACtE,8BAA8B;IAC9B,4CAA4C,EAAE,eAAe;IAC7D,8BAA8B,EAAE,4DAA4D;CAC7F,CAAC;AAEF,MAAM,WAAW,GAAiB;IAChC,uBAAuB,EAAE,wBAAwB;IACjD,0BAA0B;IAC1B,kCAAkC;IAClC,4BAA4B;CAC7B,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;AAE3D,2EAA2E;AAC3E,6EAA6E;AAC7E,8EAA8E;AAC9E,6DAA6D;AAC7D,MAAM,CAAC,MAAM,iBAAiB,GAAc;IAC1C,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,6EAA6E;IAC/E,GAAG,EAAE,0BAA0B,EAAE,UAAU;IAC3C,IAAI,EAAE;QACJ,UAAU,EAAE,MAAM;QAClB,IAAI,EAAE;YACJ,8BAA8B,EAAE,iDAAiD;SAClF;QACD,MAAM,EAAE;YACN,8BAA8B,EAAE,6CAA6C;SAC9E;KACF;IACD,WAAW;IACX,QAAQ,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,kDAAkD;IACzF,gBAAgB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,2CAA2C;CACpF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power_cms.test.d.ts","sourceRoot":"","sources":["../../../src/signatures/technologies/power_cms.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { matchString } from "../../analyzer/match.js";
|
|
3
|
+
import { powerCmsSignature } from "./power_cms.js";
|
|
4
|
+
import { movableTypeSignature } from "./movable_type.js";
|
|
5
|
+
describe("powerCmsSignature", () => {
|
|
6
|
+
describe("rule (passive, public-facing marker)", () => {
|
|
7
|
+
const urls = powerCmsSignature.rule?.urls ?? [];
|
|
8
|
+
const bodies = powerCmsSignature.rule?.bodies ?? [];
|
|
9
|
+
it("matches the PowerCMS plugin static path in URLs", () => {
|
|
10
|
+
const url = "https://example.com/mt-static/plugins/PowerCMS/css/style.css";
|
|
11
|
+
expect(urls.some((r) => matchString(url, r).hit)).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
it("matches the PowerCMS plugin static path inline in HTML", () => {
|
|
14
|
+
const html = '<link rel="stylesheet" href="/mt-static/plugins/PowerCMS/x.css">';
|
|
15
|
+
expect(bodies.some((r) => matchString(html, r).hit)).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
it("does not match a plain Movable Type asset path", () => {
|
|
18
|
+
const url = "https://example.com/mt-static/themes-base/blog.css";
|
|
19
|
+
expect(urls.some((r) => matchString(url, r).hit)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe("activeRules (mt.cgi admin probe)", () => {
|
|
23
|
+
const rules = powerCmsSignature.activeRules ?? [];
|
|
24
|
+
it("probes the root and common install dirs with logout mode", () => {
|
|
25
|
+
expect(rules.map((r) => r.path)).toEqual([
|
|
26
|
+
"/mt.cgi?__mode=logout",
|
|
27
|
+
"/mt/mt.cgi?__mode=logout",
|
|
28
|
+
"/cgi-bin/mt/mt.cgi?__mode=logout",
|
|
29
|
+
"/blog/mt.cgi?__mode=logout",
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
it("extracts the version from the 'PowerCMS version X.Y' footer", () => {
|
|
33
|
+
const regex = rules[0].bodyRegexes.find((r) => r.includes("PowerCMS version"));
|
|
34
|
+
const result = matchString("<p>PowerCMS version 5.43</p>", regex);
|
|
35
|
+
expect(result.hit).toBe(true);
|
|
36
|
+
expect(result.version).toBe("5.43");
|
|
37
|
+
});
|
|
38
|
+
it("extracts the version from the 'PowerCMS X.Y' footer", () => {
|
|
39
|
+
const result = rules[0].bodyRegexes
|
|
40
|
+
.map((r) => matchString("Powered by PowerCMS 4.46", r))
|
|
41
|
+
.find((r) => r.hit);
|
|
42
|
+
expect(result.hit).toBe(true);
|
|
43
|
+
expect(result.version).toBe("4.46");
|
|
44
|
+
});
|
|
45
|
+
it("extracts the version from the v6/v7 'version X.Y' footer (no product prefix)", () => {
|
|
46
|
+
const result = rules[0].bodyRegexes
|
|
47
|
+
.map((r) => matchString("<p>version 6.83</p>", r))
|
|
48
|
+
.find((r) => r.hit);
|
|
49
|
+
expect(result.hit).toBe(true);
|
|
50
|
+
expect(result.version).toBe("6.83");
|
|
51
|
+
});
|
|
52
|
+
it("does not pick up a single-token 'version 3' as a version", () => {
|
|
53
|
+
const bare = rules[0].bodyRegexes.find((r) => r === "\\bversion ([0-9]+\\.[0-9]+(?:\\.[0-9]+)*)");
|
|
54
|
+
expect(matchString("requires version 3", bare).hit).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
it("does not match a word that merely ends in 'version' (e.g. Subversion)", () => {
|
|
57
|
+
const bare = rules[0].bodyRegexes.find((r) => r === "\\bversion ([0-9]+\\.[0-9]+(?:\\.[0-9]+)*)");
|
|
58
|
+
expect(matchString("Subversion 1.14.2", bare).hit).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
it("extracts irregular-precision versions (e.g. 2.0493)", () => {
|
|
61
|
+
const result = rules[0].bodyRegexes
|
|
62
|
+
.map((r) => matchString("PowerCMS 2.0493", r))
|
|
63
|
+
.find((r) => r.hit);
|
|
64
|
+
expect(result.version).toBe("2.0493");
|
|
65
|
+
});
|
|
66
|
+
it("confirms PowerCMS via the plugin path even without a version", () => {
|
|
67
|
+
const regex = rules[0].bodyRegexes.find((r) => r.includes("/mt-static/plugins/PowerCMS/"));
|
|
68
|
+
const result = matchString('<img src="/mt-static/plugins/PowerCMS/logo.png">', regex);
|
|
69
|
+
expect(result.hit).toBe(true);
|
|
70
|
+
expect(result.version).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
it("uses the Alfasado PowerCMS CPE 2.2 identifier", () => {
|
|
74
|
+
expect(powerCmsSignature.cpe).toBe("cpe:/a:alfasado:powercms");
|
|
75
|
+
});
|
|
76
|
+
it("excludes Movable Type so only PowerCMS is reported", () => {
|
|
77
|
+
expect(powerCmsSignature.excludes).toContain(movableTypeSignature.name);
|
|
78
|
+
});
|
|
79
|
+
it("implies Perl as the underlying runtime", () => {
|
|
80
|
+
expect(powerCmsSignature.impliedSoftwares).toContain("Perl");
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=power_cms.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power_cms.test.js","sourceRoot":"","sources":["../../../src/signatures/technologies/power_cms.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinkphp.d.ts","sourceRoot":"","sources":["../../../src/signatures/technologies/thinkphp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,eAAO,MAAM,iBAAiB,EAAE,SAuC/B,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { phpSignature } from "./php.js";
|
|
2
|
+
export const thinkPhpSignature = {
|
|
3
|
+
name: "ThinkPHP",
|
|
4
|
+
description: "ThinkPHP is an open-source PHP framework with an MVC structure, developed and maintained by Shanghai Topthink. It is widely used in China.",
|
|
5
|
+
cpe: "cpe:/a:thinkphp:thinkphp",
|
|
6
|
+
rule: {
|
|
7
|
+
confidence: "high",
|
|
8
|
+
headers: {
|
|
9
|
+
// ThinkPHP advertises itself via X-Powered-By. The version is usually
|
|
10
|
+
// absent but captured when present (e.g. "ThinkPHP/6.0.12").
|
|
11
|
+
"x-powered-by": "thinkphp/?(\\d+\\.\\d+\\.\\d+)?",
|
|
12
|
+
},
|
|
13
|
+
cookies: {
|
|
14
|
+
// Page-trace cookie exposed when debug / page trace is enabled.
|
|
15
|
+
thinkphp_show_page_trace: "",
|
|
16
|
+
},
|
|
17
|
+
bodies: [
|
|
18
|
+
// Distinctive framework banner emitted by older ThinkPHP versions
|
|
19
|
+
// (2.x/3.x), e.g. `ThinkPHP</a><sup>3.1.3</sup> { Fast & Simple OOP PHP
|
|
20
|
+
// Framework }`. The version is captured from the adjacent <sup> tag when
|
|
21
|
+
// present, and the banner still matches (version-less) when it is not.
|
|
22
|
+
// Body matching runs against raw response text with no HTML-entity
|
|
23
|
+
// decoding, so accept both the literal "&" and the "&" entity form.
|
|
24
|
+
"(?:<sup>(\\d+\\.\\d+\\.\\d+)</sup>[\\s{]*)?Fast &(?:amp;)? Simple OOP PHP Framework",
|
|
25
|
+
// Debug exception page footer emitted by newer versions (5.1 / 6 / 8).
|
|
26
|
+
// The footer template renders `App::version()` (the full VERSION
|
|
27
|
+
// constant), e.g. `ThinkPHP</a> <span>V6.0.13</span>`. Requiring three
|
|
28
|
+
// numeric groups means the major-only welcome page ("ThinkPHP V6") is
|
|
29
|
+
// never captured, so no inaccurate major-only CPE is produced. The
|
|
30
|
+
// template puts a newline / indentation between </a> and <span>, so allow
|
|
31
|
+
// whitespace with \s*.
|
|
32
|
+
"ThinkPHP</a>\\s*<span>\\s*V(\\d+\\.\\d+\\.\\d+)",
|
|
33
|
+
// Framework source paths leaked on debug / exception pages (TP5.x).
|
|
34
|
+
"/thinkphp/library/think/",
|
|
35
|
+
// Default welcome page shown by fresh installs (V5 / V6 / V8, ...).
|
|
36
|
+
"ThinkPHP\\s*V[3-8]",
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
impliedSoftwares: [phpSignature.name],
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=thinkphp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinkphp.js","sourceRoot":"","sources":["../../../src/signatures/technologies/thinkphp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,CAAC,MAAM,iBAAiB,GAAc;IAC1C,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,4IAA4I;IAC9I,GAAG,EAAE,0BAA0B;IAC/B,IAAI,EAAE;QACJ,UAAU,EAAE,MAAM;QAClB,OAAO,EAAE;YACP,sEAAsE;YACtE,6DAA6D;YAC7D,cAAc,EAAE,iCAAiC;SAClD;QACD,OAAO,EAAE;YACP,gEAAgE;YAChE,wBAAwB,EAAE,EAAE;SAC7B;QACD,MAAM,EAAE;YACN,kEAAkE;YAClE,wEAAwE;YACxE,yEAAyE;YACzE,uEAAuE;YACvE,mEAAmE;YACnE,wEAAwE;YACxE,qFAAqF;YACrF,uEAAuE;YACvE,iEAAiE;YACjE,uEAAuE;YACvE,sEAAsE;YACtE,mEAAmE;YACnE,0EAA0E;YAC1E,uBAAuB;YACvB,iDAAiD;YACjD,oEAAoE;YACpE,0BAA0B;YAC1B,oEAAoE;YACpE,oBAAoB;SACrB;KACF;IACD,gBAAgB,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC;CACtC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinkphp.test.d.ts","sourceRoot":"","sources":["../../../src/signatures/technologies/thinkphp.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { applySignature } from "../../analyzer/apply.js";
|
|
3
|
+
import { thinkPhpSignature } from "./thinkphp.js";
|
|
4
|
+
function createMockContext(overrides = {}) {
|
|
5
|
+
return {
|
|
6
|
+
browser: {},
|
|
7
|
+
page: {},
|
|
8
|
+
urls: [],
|
|
9
|
+
responses: [],
|
|
10
|
+
cookies: [],
|
|
11
|
+
javascriptVariables: {},
|
|
12
|
+
timeoutMs: 30000,
|
|
13
|
+
timeoutOccurred: false,
|
|
14
|
+
...overrides,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function createMockResponse(overrides = {}) {
|
|
18
|
+
return {
|
|
19
|
+
url: "https://example.com",
|
|
20
|
+
host: "example.com",
|
|
21
|
+
isFirstParty: true,
|
|
22
|
+
status: 200,
|
|
23
|
+
headers: { "content-type": "text/html" },
|
|
24
|
+
body: "",
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
describe("thinkPhpSignature", () => {
|
|
29
|
+
it("detects ThinkPHP from the X-Powered-By header", () => {
|
|
30
|
+
const context = createMockContext({
|
|
31
|
+
responses: [
|
|
32
|
+
createMockResponse({
|
|
33
|
+
headers: { "content-type": "text/html", "x-powered-by": "ThinkPHP" },
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
38
|
+
expect(detection?.name).toBe("ThinkPHP");
|
|
39
|
+
});
|
|
40
|
+
it("captures the version from X-Powered-By when present", () => {
|
|
41
|
+
const context = createMockContext({
|
|
42
|
+
responses: [
|
|
43
|
+
createMockResponse({
|
|
44
|
+
headers: {
|
|
45
|
+
"content-type": "text/html",
|
|
46
|
+
"x-powered-by": "ThinkPHP/6.0.12",
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
52
|
+
expect(detection?.evidences?.some((e) => e.version === "6.0.12")).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
it("detects ThinkPHP from the default welcome page body", () => {
|
|
55
|
+
const context = createMockContext({
|
|
56
|
+
responses: [
|
|
57
|
+
createMockResponse({ body: "<h1>:)</h1><p> ThinkPHP V6<br/></p>" }),
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
61
|
+
expect(detection?.name).toBe("ThinkPHP");
|
|
62
|
+
});
|
|
63
|
+
it("detects ThinkPHP from the legacy framework banner marker", () => {
|
|
64
|
+
const context = createMockContext({
|
|
65
|
+
responses: [
|
|
66
|
+
createMockResponse({
|
|
67
|
+
body: "<!-- Fast & Simple OOP PHP Framework -->",
|
|
68
|
+
}),
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
72
|
+
expect(detection?.name).toBe("ThinkPHP");
|
|
73
|
+
});
|
|
74
|
+
it("captures the version from the legacy framework banner", () => {
|
|
75
|
+
const context = createMockContext({
|
|
76
|
+
responses: [
|
|
77
|
+
createMockResponse({
|
|
78
|
+
body: "ThinkPHP</a><sup>3.1.3</sup> { Fast & Simple OOP PHP Framework } -- [ WE CAN DO IT JUST THINK ]",
|
|
79
|
+
}),
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
83
|
+
expect(detection?.evidences?.some((e) => e.version === "3.1.3")).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
it("detects the legacy banner marker with an HTML-encoded ampersand", () => {
|
|
86
|
+
const context = createMockContext({
|
|
87
|
+
responses: [
|
|
88
|
+
createMockResponse({
|
|
89
|
+
body: "<!-- Fast & Simple OOP PHP Framework -->",
|
|
90
|
+
}),
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
94
|
+
expect(detection?.name).toBe("ThinkPHP");
|
|
95
|
+
});
|
|
96
|
+
it("captures the full version from the debug exception page footer", () => {
|
|
97
|
+
const context = createMockContext({
|
|
98
|
+
responses: [
|
|
99
|
+
createMockResponse({
|
|
100
|
+
body: '<a href="http://www.thinkphp.cn">ThinkPHP</a>\n <span>V6.0.13</span>',
|
|
101
|
+
}),
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
105
|
+
expect(detection?.evidences?.some((e) => e.version === "6.0.13")).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
it("does not capture a major-only version from the welcome page", () => {
|
|
108
|
+
const context = createMockContext({
|
|
109
|
+
responses: [
|
|
110
|
+
createMockResponse({ body: "<h1>:)</h1><p> ThinkPHP V6<br/></p>" }),
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
114
|
+
expect(detection?.name).toBe("ThinkPHP");
|
|
115
|
+
expect(detection?.evidences?.some((e) => e.version)).toBeFalsy();
|
|
116
|
+
});
|
|
117
|
+
it("detects ThinkPHP from the page-trace cookie", () => {
|
|
118
|
+
const context = createMockContext({
|
|
119
|
+
cookies: [
|
|
120
|
+
{
|
|
121
|
+
name: "thinkphp_show_page_trace",
|
|
122
|
+
value: "0|0",
|
|
123
|
+
host: "example.com",
|
|
124
|
+
isFirstParty: true,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
});
|
|
128
|
+
const detection = applySignature(context, thinkPhpSignature);
|
|
129
|
+
expect(detection?.name).toBe("ThinkPHP");
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=thinkphp.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinkphp.test.js","sourceRoot":"","sources":["../../../src/signatures/technologies/thinkphp.test.ts"],"names":[],"mappings":"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"}
|