whopper 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/analyzer/apply.d.ts.map +1 -1
  2. package/dist/analyzer/apply.js +31 -2
  3. package/dist/analyzer/apply.js.map +1 -1
  4. package/dist/analyzer/apply.test.js +60 -2
  5. package/dist/analyzer/apply.test.js.map +1 -1
  6. package/dist/analyzer/match.d.ts +8 -0
  7. package/dist/analyzer/match.d.ts.map +1 -1
  8. package/dist/analyzer/match.js +33 -0
  9. package/dist/analyzer/match.js.map +1 -1
  10. package/dist/analyzer/match.test.js +26 -1
  11. package/dist/analyzer/match.test.js.map +1 -1
  12. package/dist/analyzer/scope.d.ts +17 -0
  13. package/dist/analyzer/scope.d.ts.map +1 -0
  14. package/dist/analyzer/scope.js +43 -0
  15. package/dist/analyzer/scope.js.map +1 -0
  16. package/dist/analyzer/scope.test.d.ts +2 -0
  17. package/dist/analyzer/scope.test.d.ts.map +1 -0
  18. package/dist/analyzer/scope.test.js +51 -0
  19. package/dist/analyzer/scope.test.js.map +1 -0
  20. package/dist/analyzer/types.d.ts +1 -0
  21. package/dist/analyzer/types.d.ts.map +1 -1
  22. package/dist/analyzer/utils.d.ts +1 -0
  23. package/dist/analyzer/utils.d.ts.map +1 -1
  24. package/dist/analyzer/utils.js +12 -0
  25. package/dist/analyzer/utils.js.map +1 -1
  26. package/dist/analyzer/utils.test.d.ts +2 -0
  27. package/dist/analyzer/utils.test.d.ts.map +1 -0
  28. package/dist/analyzer/utils.test.js +28 -0
  29. package/dist/analyzer/utils.test.js.map +1 -0
  30. package/dist/commands/detect_utils.d.ts.map +1 -1
  31. package/dist/commands/detect_utils.js +24 -2
  32. package/dist/commands/detect_utils.js.map +1 -1
  33. package/dist/commands/detect_utils.test.js +117 -1
  34. package/dist/commands/detect_utils.test.js.map +1 -1
  35. package/dist/signatures/technologies/neve.js +1 -1
  36. package/dist/signatures/technologies/neve.js.map +1 -1
  37. package/dist/signatures/technologies/neve.test.js +15 -0
  38. package/dist/signatures/technologies/neve.test.js.map +1 -1
  39. package/dist/signatures/technologies/ruby_on_rails.d.ts.map +1 -1
  40. package/dist/signatures/technologies/ruby_on_rails.js +18 -1
  41. package/dist/signatures/technologies/ruby_on_rails.js.map +1 -1
  42. package/dist/signatures/technologies/ruby_on_rails.test.d.ts +2 -0
  43. package/dist/signatures/technologies/ruby_on_rails.test.d.ts.map +1 -0
  44. package/dist/signatures/technologies/ruby_on_rails.test.js +234 -0
  45. package/dist/signatures/technologies/ruby_on_rails.test.js.map +1 -0
  46. package/dist/signatures/technologies/wordpress.test.js +41 -0
  47. package/dist/signatures/technologies/wordpress.test.js.map +1 -1
  48. package/package.json +1 -1
@@ -0,0 +1,234 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { applySignature } from "../../analyzer/apply.js";
3
+ import { rubyOnRailsSignature } from "./ruby_on_rails.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
+ function createMockCookie(overrides = {}) {
29
+ return {
30
+ name: "_session_id",
31
+ value: "abc123",
32
+ domain: "example.com",
33
+ host: "example.com",
34
+ isFirstParty: true,
35
+ path: "/",
36
+ expires: -1,
37
+ httpOnly: true,
38
+ secure: true,
39
+ sameSite: "Lax",
40
+ ...overrides,
41
+ };
42
+ }
43
+ const propshaftDigest = "0a1b2c3d";
44
+ const md5Digest = "0123456789abcdef0123456789abcdef";
45
+ const sha256Digest = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
46
+ // No Rails pipeline emits a full 40-char SHA-1; other stacks do.
47
+ const sha1Digest = "0123456789abcdef0123456789abcdef01234567";
48
+ describe("rubyOnRailsSignature", () => {
49
+ describe("header matching", () => {
50
+ it("detects Rails from a mod_rails Server header", () => {
51
+ const context = createMockContext({
52
+ responses: [
53
+ createMockResponse({
54
+ headers: {
55
+ "content-type": "text/html",
56
+ server: "Apache/2.4.6 mod_rails/4.0.60",
57
+ },
58
+ }),
59
+ ],
60
+ });
61
+ const result = applySignature(context, rubyOnRailsSignature);
62
+ expect(result?.name).toBe("Ruby on Rails");
63
+ });
64
+ it("detects Rails from a mod_rack X-Powered-By header", () => {
65
+ const context = createMockContext({
66
+ responses: [
67
+ createMockResponse({
68
+ headers: {
69
+ "content-type": "text/html",
70
+ "x-powered-by": "Phusion Passenger mod_rack",
71
+ },
72
+ }),
73
+ ],
74
+ });
75
+ const result = applySignature(context, rubyOnRailsSignature);
76
+ expect(result?.name).toBe("Ruby on Rails");
77
+ });
78
+ it("does not match an unrelated Server header", () => {
79
+ const context = createMockContext({
80
+ responses: [
81
+ createMockResponse({
82
+ headers: { "content-type": "text/html", server: "nginx/1.24.0" },
83
+ }),
84
+ ],
85
+ });
86
+ const result = applySignature(context, rubyOnRailsSignature);
87
+ expect(result).toBeUndefined();
88
+ });
89
+ });
90
+ describe("cookie matching", () => {
91
+ it("detects Rails from the _session_id cookie", () => {
92
+ const context = createMockContext({
93
+ cookies: [createMockCookie({ value: "BAh7B0kiD3Nlc3Npb25faWQ" })],
94
+ });
95
+ const result = applySignature(context, rubyOnRailsSignature);
96
+ expect(result?.name).toBe("Ruby on Rails");
97
+ });
98
+ it("does not match an empty _session_id cookie", () => {
99
+ const context = createMockContext({
100
+ cookies: [createMockCookie({ value: "" })],
101
+ });
102
+ const result = applySignature(context, rubyOnRailsSignature);
103
+ expect(result).toBeUndefined();
104
+ });
105
+ });
106
+ describe("body matching", () => {
107
+ it("detects Rails from the csrf-param meta tag", () => {
108
+ const context = createMockContext({
109
+ responses: [
110
+ createMockResponse({
111
+ body: '<meta name="csrf-param" content="authenticity_token" />',
112
+ }),
113
+ ],
114
+ });
115
+ const result = applySignature(context, rubyOnRailsSignature);
116
+ expect(result?.name).toBe("Ruby on Rails");
117
+ });
118
+ it("detects the csrf-param meta tag with single-quoted attributes", () => {
119
+ const context = createMockContext({
120
+ responses: [
121
+ createMockResponse({
122
+ body: "<meta name='csrf-param' content='authenticity_token' />",
123
+ }),
124
+ ],
125
+ });
126
+ const result = applySignature(context, rubyOnRailsSignature);
127
+ expect(result?.name).toBe("Ruby on Rails");
128
+ });
129
+ it("does not match a csrf-token meta tag alone", () => {
130
+ const context = createMockContext({
131
+ responses: [
132
+ createMockResponse({
133
+ body: '<meta name="csrf-token" content="abcdef123456" />',
134
+ }),
135
+ ],
136
+ });
137
+ const result = applySignature(context, rubyOnRailsSignature);
138
+ expect(result).toBeUndefined();
139
+ });
140
+ });
141
+ describe("url matching", () => {
142
+ function detectFromUrl(url) {
143
+ const context = createMockContext({
144
+ responses: [createMockResponse({ url })],
145
+ });
146
+ return applySignature(context, rubyOnRailsSignature);
147
+ }
148
+ it("detects Rails from a Propshaft asset URL", () => {
149
+ const result = detectFromUrl(`https://example.com/assets/application-${propshaftDigest}.js`);
150
+ expect(result?.name).toBe("Ruby on Rails");
151
+ });
152
+ it("detects Rails from a Sprockets MD5 asset URL", () => {
153
+ const result = detectFromUrl(`https://example.com/assets/application-${md5Digest}.js`);
154
+ expect(result?.name).toBe("Ruby on Rails");
155
+ });
156
+ it("detects Rails from a Sprockets SHA-256 asset URL", () => {
157
+ const result = detectFromUrl(`https://example.com/assets/application-${sha256Digest}.js`);
158
+ expect(result?.name).toBe("Ruby on Rails");
159
+ });
160
+ it("detects Rails from a fingerprinted stylesheet", () => {
161
+ const result = detectFromUrl(`https://example.com/assets/application-${sha256Digest}.css`);
162
+ expect(result?.name).toBe("Ruby on Rails");
163
+ });
164
+ it("detects Rails from a fingerprinted sourcemap", () => {
165
+ const result = detectFromUrl(`https://example.com/assets/application-${propshaftDigest}.js.map`);
166
+ expect(result?.name).toBe("Ruby on Rails");
167
+ });
168
+ it("detects Rails from an asset URL carrying the Sprockets debug query", () => {
169
+ const result = detectFromUrl(`https://example.com/assets/application-${md5Digest}.js?body=1`);
170
+ expect(result?.name).toBe("Ruby on Rails");
171
+ });
172
+ it("does not match an unfingerprinted application.js", () => {
173
+ const result = detectFromUrl("https://example.com/assets/application.js");
174
+ expect(result).toBeUndefined();
175
+ });
176
+ it("does not match a full 40-char SHA-1 digest from another pipeline", () => {
177
+ const result = detectFromUrl(`https://example.com/assets/application-${sha1Digest}.js`);
178
+ expect(result).toBeUndefined();
179
+ });
180
+ it("does not match a fingerprinted JSON manifest", () => {
181
+ const result = detectFromUrl(`https://example.com/assets/application-${propshaftDigest}.json`);
182
+ expect(result).toBeUndefined();
183
+ });
184
+ it("does not match a fingerprinted .jsx source", () => {
185
+ const result = detectFromUrl(`https://example.com/assets/application-${propshaftDigest}.jsx`);
186
+ expect(result).toBeUndefined();
187
+ });
188
+ it("does not match an asset path echoed back in a query string", () => {
189
+ const result = detectFromUrl(`https://example.com/login?next=/assets/application-${propshaftDigest}.js`);
190
+ expect(result).toBeUndefined();
191
+ });
192
+ // Known limitation, not signature behaviour: this signature carries headers
193
+ // and cookies, so inferRuntime() classifies it as "server" and the urls loop
194
+ // skips third-party responses. Assets served from a CDN via
195
+ // config.asset_host are therefore never evaluated.
196
+ it("does not evaluate an asset URL served from a third-party CDN host", () => {
197
+ const context = createMockContext({
198
+ responses: [
199
+ createMockResponse({
200
+ url: `https://cdn.example.net/assets/application-${md5Digest}.js`,
201
+ host: "cdn.example.net",
202
+ isFirstParty: false,
203
+ }),
204
+ ],
205
+ });
206
+ const result = applySignature(context, rubyOnRailsSignature);
207
+ expect(result).toBeUndefined();
208
+ });
209
+ });
210
+ describe("javascript variable matching", () => {
211
+ it("detects Rails from the ReactOnRails global", () => {
212
+ const context = createMockContext({
213
+ javascriptVariables: {
214
+ ReactOnRails: {},
215
+ },
216
+ });
217
+ const result = applySignature(context, rubyOnRailsSignature);
218
+ expect(result?.name).toBe("Ruby on Rails");
219
+ });
220
+ it("detects Rails from the React on Rails event handler flag", () => {
221
+ const context = createMockContext({
222
+ javascriptVariables: {
223
+ __REACT_ON_RAILS_EVENT_HANDLERS_RAN_ONCE__: true,
224
+ },
225
+ });
226
+ const result = applySignature(context, rubyOnRailsSignature);
227
+ expect(result?.name).toBe("Ruby on Rails");
228
+ });
229
+ });
230
+ it("implies Ruby", () => {
231
+ expect(rubyOnRailsSignature.impliedSoftwares).toContain("Ruby");
232
+ });
233
+ });
234
+ //# sourceMappingURL=ruby_on_rails.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruby_on_rails.test.js","sourceRoot":"","sources":["../../../src/signatures/technologies/ruby_on_rails.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,SAAS,iBAAiB,CACxB,YAEI,EAAE;IAEN,OAAO;QACL,OAAO,EAAE,EAAwB;QACjC,IAAI,EAAE,EAAqB;QAC3B,IAAI,EAAE,EAAE;QACR,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,mBAAmB,EAAE,EAAE;QACvB,SAAS,EAAE,KAAK;QAChB,eAAe,EAAE,KAAK;QACtB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,YAA+B,EAAE;IAC3D,OAAO;QACL,GAAG,EAAE,qBAAqB;QAC1B,IAAI,EAAE,aAAa;QACnB,YAAY,EAAE,IAAI;QAClB,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE;QACxC,IAAI,EAAE,EAAE;QACR,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,YAA6B,EAAE;IACvD,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,QAAQ;QACf,MAAM,EAAE,aAAa;QACrB,IAAI,EAAE,aAAa;QACnB,YAAY,EAAE,IAAI;QAClB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,KAAK;QACf,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,eAAe,GAAG,UAAU,CAAC;AACnC,MAAM,SAAS,GAAG,kCAAkC,CAAC;AACrD,MAAM,YAAY,GAChB,kEAAkE,CAAC;AACrE,iEAAiE;AACjE,MAAM,UAAU,GAAG,0CAA0C,CAAC;AAE9D,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE;oBACT,kBAAkB,CAAC;wBACjB,OAAO,EAAE;4BACP,cAAc,EAAE,WAAW;4BAC3B,MAAM,EAAE,+BAA+B;yBACxC;qBACF,CAAC;iBACH;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE;oBACT,kBAAkB,CAAC;wBACjB,OAAO,EAAE;4BACP,cAAc,EAAE,WAAW;4BAC3B,cAAc,EAAE,4BAA4B;yBAC7C;qBACF,CAAC;iBACH;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE;oBACT,kBAAkB,CAAC;wBACjB,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE;qBACjE,CAAC;iBACH;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;aAClE,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;aAC3C,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE;oBACT,kBAAkB,CAAC;wBACjB,IAAI,EAAE,yDAAyD;qBAChE,CAAC;iBACH;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;YACvE,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE;oBACT,kBAAkB,CAAC;wBACjB,IAAI,EAAE,yDAAyD;qBAChE,CAAC;iBACH;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE;oBACT,kBAAkB,CAAC;wBACjB,IAAI,EAAE,mDAAmD;qBAC1D,CAAC;iBACH;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,SAAS,aAAa,CAAC,GAAW;YAChC,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;aACzC,CAAC,CAAC;YACH,OAAO,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;QACvD,CAAC;QAED,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,eAAe,KAAK,CAC/D,CAAC;YACF,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,SAAS,KAAK,CACzD,CAAC;YACF,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,YAAY,KAAK,CAC5D,CAAC;YACF,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,YAAY,MAAM,CAC7D,CAAC;YACF,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,eAAe,SAAS,CACnE,CAAC;YACF,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;YAC5E,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,SAAS,YAAY,CAChE,CAAC;YACF,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,MAAM,GAAG,aAAa,CAAC,2CAA2C,CAAC,CAAC;YAC1E,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;YAC1E,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,UAAU,KAAK,CAC1D,CAAC;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,eAAe,OAAO,CACjE,CAAC;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,MAAM,GAAG,aAAa,CAC1B,0CAA0C,eAAe,MAAM,CAChE,CAAC;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;YACpE,MAAM,MAAM,GAAG,aAAa,CAC1B,sDAAsD,eAAe,KAAK,CAC3E,CAAC;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,4EAA4E;QAC5E,6EAA6E;QAC7E,4DAA4D;QAC5D,mDAAmD;QACnD,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;YAC3E,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,SAAS,EAAE;oBACT,kBAAkB,CAAC;wBACjB,GAAG,EAAE,8CAA8C,SAAS,KAAK;wBACjE,IAAI,EAAE,iBAAiB;wBACvB,YAAY,EAAE,KAAK;qBACpB,CAAC;iBACH;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC5C,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,mBAAmB,EAAE;oBACnB,YAAY,EAAE,EAAE;iBACjB;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,OAAO,GAAG,iBAAiB,CAAC;gBAChC,mBAAmB,EAAE;oBACnB,0CAA0C,EAAE,IAAI;iBACjD;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QACtB,MAAM,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -86,6 +86,47 @@ describe("wordpressSignature", () => {
86
86
  const result = applySignature(context, wordpressSignature);
87
87
  expect(result).toBeDefined();
88
88
  });
89
+ it("does not detect WordPress from a third-party URL quoted inside a first-party script", () => {
90
+ const context = createMockContext({
91
+ responses: [
92
+ createMockResponse({
93
+ url: "https://example.com/js/app.min.js",
94
+ host: "example.com",
95
+ headers: { "content-type": "application/javascript" },
96
+ body: '"https://external.example/wp-content/plugins/foo/bar.js"',
97
+ }),
98
+ ],
99
+ });
100
+ const result = applySignature(context, wordpressSignature);
101
+ expect(result).toBeUndefined();
102
+ });
103
+ it("detects WordPress from an in-scope absolute wp-content URL", () => {
104
+ const context = createMockContext({
105
+ responses: [
106
+ createMockResponse({
107
+ body: '<link href="https://example.com/wp-content/themes/foo/style.css">',
108
+ }),
109
+ ],
110
+ });
111
+ const result = applySignature(context, wordpressSignature);
112
+ expect(result).toBeDefined();
113
+ });
114
+ it("does not read a version across an out-of-scope URL between the tokens", () => {
115
+ // "WordPress" and "6.4.2" are separated by an out-of-scope URL. Because
116
+ // the URL is excluded by span (not replaced with whitespace), the version
117
+ // pattern must not bridge the two into a spurious 6.4.2 detection. An
118
+ // in-scope relative path still yields a WordPress detection.
119
+ const context = createMockContext({
120
+ responses: [
121
+ createMockResponse({
122
+ body: '<link href="/wp-content/style.css"> WordPress https://external.example/a/b.js 6.4.2',
123
+ }),
124
+ ],
125
+ });
126
+ const result = applySignature(context, wordpressSignature);
127
+ expect(result).toBeDefined();
128
+ expect(result?.evidences?.every((e) => e.version !== "6.4.2")).toBe(true);
129
+ });
89
130
  });
90
131
  });
91
132
  //# sourceMappingURL=wordpress.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wordpress.test.js","sourceRoot":"","sources":["../../../src/signatures/technologies/wordpress.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wordpress.test.js","sourceRoot":"","sources":["../../../src/signatures/technologies/wordpress.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whopper",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Whopper is a CLI tool that discovers and detects web technologies used on websites.",
5
5
  "scripts": {
6
6
  "build": "tsc -p tsconfig.json",