@j3r3mcdev/oast-server 1.0.0 → 1.1.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.
Files changed (187) hide show
  1. package/.github/workflows/ci.yml +29 -29
  2. package/.github/workflows/publish.yml +31 -31
  3. package/README.md +192 -192
  4. package/dist/api/controllers/__tests__/tasks.controller.test.d.ts +1 -0
  5. package/dist/api/controllers/events.controller.d.ts +6 -0
  6. package/dist/api/controllers/health.controller.d.ts +4 -0
  7. package/dist/api/controllers/index.d.ts +0 -0
  8. package/dist/api/controllers/tasks.controller.d.ts +40 -0
  9. package/dist/api/dto/__tests__/create-task.dto.test.d.ts +1 -0
  10. package/dist/api/dto/__tests__/filter-tasks.dto.test.d.ts +1 -0
  11. package/dist/api/dto/create-task.dto.d.ts +9 -0
  12. package/dist/api/dto/filter-tasks.dto.d.ts +8 -0
  13. package/dist/api/services/__tests__/events.service.test.d.ts +1 -0
  14. package/dist/api/services/__tests__/tasks.service.test.d.ts +1 -0
  15. package/dist/api/services/events.service.d.ts +8 -0
  16. package/dist/api/services/tasks.service.d.ts +22 -0
  17. package/dist/api/sse/events.stream.d.ts +25 -0
  18. package/dist/config/constants.d.ts +0 -0
  19. package/dist/config/env.d.ts +0 -0
  20. package/dist/core/__tests__/core-router.test.d.ts +1 -0
  21. package/dist/core/__tests__/core-server.test.d.ts +1 -0
  22. package/dist/core/__tests__/event.normalizer.test.d.ts +1 -0
  23. package/dist/core/__tests__/event.router.test.d.ts +1 -0
  24. package/dist/core/__tests__/logger.test.d.ts +1 -0
  25. package/dist/core/__tests__/storage-manager.test.d.ts +1 -0
  26. package/dist/core/event.normalizer.d.ts +10 -0
  27. package/dist/core/event.router.d.ts +7 -0
  28. package/dist/core/http/__tests__/adapter-node.test.d.ts +1 -0
  29. package/dist/core/http/__tests__/body-parser-multipart.test.d.ts +1 -0
  30. package/dist/core/http/__tests__/body-parser-raw.test.d.ts +1 -0
  31. package/dist/core/http/__tests__/body-parser-text.test.d.ts +1 -0
  32. package/dist/core/http/__tests__/compile-path.test.d.ts +1 -0
  33. package/dist/core/http/__tests__/middleware-pipeline.test.d.ts +1 -0
  34. package/dist/core/http/__tests__/request.test.d.ts +1 -0
  35. package/dist/core/http/__tests__/response.test.d.ts +1 -0
  36. package/dist/core/http/__tests__/router-match.test.d.ts +1 -0
  37. package/dist/core/http/adapter-node.d.ts +8 -0
  38. package/dist/core/http/buildRequest.d.ts +2 -0
  39. package/dist/core/http/compile-path.d.ts +13 -0
  40. package/dist/core/http/errors.d.ts +9 -0
  41. package/dist/core/http/http-server.d.ts +7 -0
  42. package/dist/core/http/index.d.ts +0 -0
  43. package/dist/core/http/main.d.ts +0 -0
  44. package/dist/core/http/middleware.d.ts +12 -0
  45. package/dist/core/http/request.d.ts +35 -0
  46. package/dist/core/http/response.d.ts +17 -0
  47. package/dist/core/http/router.d.ts +28 -0
  48. package/dist/core/http/utils.d.ts +0 -0
  49. package/dist/core/id-generator.d.ts +3 -0
  50. package/dist/core/logger.d.ts +29 -0
  51. package/dist/core/router.d.ts +16 -0
  52. package/dist/core/server.d.ts +25 -0
  53. package/dist/core/storage.d.ts +24 -0
  54. package/dist/index.d.ts +1 -0
  55. package/dist/listeners/api/__tests__/api.controller.test.d.ts +1 -0
  56. package/dist/listeners/api/__tests__/api.extractor.test.d.ts +1 -0
  57. package/dist/listeners/api/__tests__/api.listener.test.d.ts +1 -0
  58. package/dist/listeners/api/__tests__/api.routes.test.d.ts +1 -0
  59. package/dist/listeners/api/__tests__/api.sse.test.d.ts +1 -0
  60. package/dist/listeners/api/api.controllers.d.ts +9 -0
  61. package/dist/listeners/api/api.extractor.d.ts +5 -0
  62. package/dist/listeners/api/api.listener.d.ts +17 -0
  63. package/dist/listeners/api/api.routes.d.ts +5 -0
  64. package/dist/listeners/api/api.sse.d.ts +10 -0
  65. package/dist/listeners/dns/__tests__/dns.test.d.ts +1 -0
  66. package/dist/listeners/dns/dns.extractor.d.ts +8 -0
  67. package/dist/listeners/dns/dns.listener.d.ts +15 -0
  68. package/dist/listeners/http/__tests__/http.extractor.test.d.ts +1 -0
  69. package/dist/listeners/http/__tests__/http.listener.test.d.ts +1 -0
  70. package/dist/listeners/http/http.extractor.d.ts +11 -0
  71. package/dist/listeners/http/http.listener.d.ts +17 -0
  72. package/dist/listeners/listener.interface.d.ts +4 -0
  73. package/dist/listeners/smtp/__tests__/smtp.extractor.test.d.ts +1 -0
  74. package/dist/listeners/smtp/__tests__/smtp.listener.test.d.ts +1 -0
  75. package/dist/listeners/smtp/smtp.extractor.d.ts +12 -0
  76. package/dist/listeners/smtp/smtp.listener.d.ts +13 -0
  77. package/dist/listeners/ssrf/__tests__/ssrf.extractor.test.d.ts +1 -0
  78. package/dist/listeners/ssrf/__tests__/ssrf.listener.test.d.ts +1 -0
  79. package/dist/listeners/ssrf/__tests__/ssrf.listener.test.js +4 -16
  80. package/dist/listeners/ssrf/ssrf.extractor.d.ts +10 -0
  81. package/dist/listeners/ssrf/ssrf.listener.d.ts +8 -0
  82. package/dist/listeners/tcp/tcp.extractor.d.ts +4 -0
  83. package/dist/listeners/tcp/tcp.listener.d.ts +18 -0
  84. package/dist/listeners/webhook/__tests__/webhook.extractor.test.d.ts +1 -0
  85. package/dist/listeners/webhook/__tests__/webhook.listener.test.d.ts +1 -0
  86. package/dist/listeners/webhook/webhook.extractor.d.ts +8 -0
  87. package/dist/listeners/webhook/webhook.listener.d.ts +8 -0
  88. package/dist/listeners/websocket/__tests__/websocket.extractor.test.d.ts +1 -0
  89. package/dist/listeners/websocket/__tests__/websocket.listener.test.d.ts +1 -0
  90. package/dist/listeners/websocket/websocket.extractor.d.ts +10 -0
  91. package/dist/listeners/websocket/websocket.listener.d.ts +8 -0
  92. package/dist/storage-adapters/adapters/__tests__/memory.storage.test.d.ts +1 -0
  93. package/dist/storage-adapters/adapters/memory.storage.d.ts +21 -0
  94. package/dist/storage-adapters/adapters/redis.storage.d.ts +0 -0
  95. package/dist/storage-adapters/adapters/sqlite.storage.d.ts +0 -0
  96. package/dist/storage-adapters/storage.interface.d.ts +18 -0
  97. package/dist/types/event.types.d.ts +118 -0
  98. package/dist/utils/token.d.ts +0 -0
  99. package/jest.config.js +14 -11
  100. package/package.json +45 -45
  101. package/sadmin list shadows +9 -9
  102. package/src/api/controllers/__tests__/tasks.controller.test.ts +74 -74
  103. package/src/api/controllers/events.controller.ts +10 -10
  104. package/src/api/controllers/health.controller.ts +7 -7
  105. package/src/api/controllers/tasks.controller.ts +41 -41
  106. package/src/api/dto/__tests__/create-task.dto.test.ts +41 -41
  107. package/src/api/dto/__tests__/filter-tasks.dto.test.ts +35 -35
  108. package/src/api/dto/create-task.dto.ts +33 -33
  109. package/src/api/dto/filter-tasks.dto.ts +33 -33
  110. package/src/api/services/__tests__/events.service.test.ts +41 -41
  111. package/src/api/services/__tests__/tasks.service.test.ts +41 -41
  112. package/src/api/services/events.service.ts +17 -17
  113. package/src/api/services/tasks.service.ts +79 -79
  114. package/src/api/sse/events.stream.ts +90 -90
  115. package/src/core/__tests__/core-router.test.ts +30 -30
  116. package/src/core/__tests__/core-server.test.ts +44 -44
  117. package/src/core/__tests__/event.normalizer.test.ts +56 -56
  118. package/src/core/__tests__/event.router.test.ts +89 -89
  119. package/src/core/__tests__/logger.test.ts +32 -32
  120. package/src/core/__tests__/storage-manager.test.ts +74 -74
  121. package/src/core/event.normalizer.ts +147 -147
  122. package/src/core/event.router.ts +13 -13
  123. package/src/core/http/__tests__/adapter-node.test.ts +52 -52
  124. package/src/core/http/__tests__/body-parser-multipart.test.ts +41 -41
  125. package/src/core/http/__tests__/body-parser-raw.test.ts +28 -28
  126. package/src/core/http/__tests__/body-parser-text.test.ts +28 -28
  127. package/src/core/http/__tests__/compile-path.test.ts +39 -39
  128. package/src/core/http/__tests__/middleware-pipeline.test.ts +51 -51
  129. package/src/core/http/__tests__/request.test.ts +34 -34
  130. package/src/core/http/__tests__/response.test.ts +35 -35
  131. package/src/core/http/__tests__/router-match.test.ts +171 -171
  132. package/src/core/http/adapter-node.ts +51 -51
  133. package/src/core/http/buildRequest.ts +18 -18
  134. package/src/core/http/compile-path.ts +32 -32
  135. package/src/core/http/errors.ts +37 -37
  136. package/src/core/http/http-server.ts +52 -52
  137. package/src/core/http/middleware.ts +160 -160
  138. package/src/core/http/request.ts +55 -55
  139. package/src/core/http/response.ts +93 -93
  140. package/src/core/http/router.ts +138 -138
  141. package/src/core/id-generator.ts +8 -8
  142. package/src/core/logger.ts +113 -113
  143. package/src/core/router.ts +44 -44
  144. package/src/core/server.ts +85 -85
  145. package/src/core/storage.ts +64 -64
  146. package/src/index.ts +89 -89
  147. package/src/listeners/api/__tests__/api.controller.test.ts +116 -116
  148. package/src/listeners/api/__tests__/api.extractor.test.ts +46 -46
  149. package/src/listeners/api/__tests__/api.listener.test.ts +82 -82
  150. package/src/listeners/api/__tests__/api.routes.test.ts +155 -155
  151. package/src/listeners/api/__tests__/api.sse.test.ts +105 -105
  152. package/src/listeners/api/api.controllers.ts +67 -67
  153. package/src/listeners/api/api.extractor.ts +43 -43
  154. package/src/listeners/api/api.listener.ts +50 -50
  155. package/src/listeners/api/api.routes.ts +76 -76
  156. package/src/listeners/api/api.sse.ts +38 -38
  157. package/src/listeners/dns/__tests__/dns.test.ts +118 -118
  158. package/src/listeners/dns/dns.extractor.ts +14 -14
  159. package/src/listeners/dns/dns.listener.ts +61 -61
  160. package/src/listeners/http/__tests__/http.extractor.test.ts +59 -59
  161. package/src/listeners/http/__tests__/http.listener.test.ts +133 -133
  162. package/src/listeners/http/http.extractor.ts +15 -15
  163. package/src/listeners/http/http.listener.ts +110 -110
  164. package/src/listeners/listener.interface.ts +4 -4
  165. package/src/listeners/smtp/__tests__/smtp.extractor.test.ts +69 -69
  166. package/src/listeners/smtp/__tests__/smtp.listener.test.ts +150 -150
  167. package/src/listeners/smtp/smtp.extractor.ts +18 -18
  168. package/src/listeners/smtp/smtp.listener.ts +60 -60
  169. package/src/listeners/ssrf/__tests__/ssrf.extractor.test.ts +41 -41
  170. package/src/listeners/ssrf/__tests__/ssrf.listener.test.ts +87 -98
  171. package/src/listeners/ssrf/ssrf.extractor.ts +14 -14
  172. package/src/listeners/ssrf/ssrf.listener.ts +37 -37
  173. package/src/listeners/tcp/tcp.extractor.ts +16 -16
  174. package/src/listeners/tcp/tcp.listener.ts +61 -61
  175. package/src/listeners/webhook/__tests__/webhook.extractor.test.ts +35 -35
  176. package/src/listeners/webhook/__tests__/webhook.listener.test.ts +122 -122
  177. package/src/listeners/webhook/webhook.extractor.ts +12 -12
  178. package/src/listeners/webhook/webhook.listener.ts +58 -58
  179. package/src/listeners/websocket/__tests__/websocket.extractor.test.ts +33 -33
  180. package/src/listeners/websocket/__tests__/websocket.listener.test.ts +90 -90
  181. package/src/listeners/websocket/websocket.extractor.ts +11 -11
  182. package/src/listeners/websocket/websocket.listener.ts +40 -40
  183. package/src/storage-adapters/adapters/__tests__/memory.storage.test.ts +75 -75
  184. package/src/storage-adapters/adapters/memory.storage.ts +64 -64
  185. package/src/storage-adapters/storage.interface.ts +26 -26
  186. package/src/types/event.types.ts +147 -147
  187. package/tsconfig.json +21 -15
@@ -1,18 +1,18 @@
1
- export class SmtpExtractor {
2
- static extract(session: any, body: string) {
3
- const envelope = session?.envelope ?? {};
4
- const mailFrom = envelope.mailFrom ?? {};
5
- const rcptTo = Array.isArray(envelope.rcptTo) ? envelope.rcptTo : [];
6
-
7
- return {
8
- ip: session?.remoteAddress ?? "",
9
- from: mailFrom.address ?? "",
10
- to: rcptTo[0]?.address ?? "",
11
- subject: session?.headers?.subject ?? "",
12
- raw: {
13
- session,
14
- body,
15
- },
16
- };
17
- }
18
- }
1
+ export class SmtpExtractor {
2
+ static extract(session: any, body: string) {
3
+ const envelope = session?.envelope ?? {};
4
+ const mailFrom = envelope.mailFrom ?? {};
5
+ const rcptTo = Array.isArray(envelope.rcptTo) ? envelope.rcptTo : [];
6
+
7
+ return {
8
+ ip: session?.remoteAddress ?? "",
9
+ from: mailFrom.address ?? "",
10
+ to: rcptTo[0]?.address ?? "",
11
+ subject: session?.headers?.subject ?? "",
12
+ raw: {
13
+ session,
14
+ body,
15
+ },
16
+ };
17
+ }
18
+ }
@@ -1,60 +1,60 @@
1
- import { CoreRouter } from "../../core/router";
2
- import { EventNormalizer } from "../../core/event.normalizer";
3
- import { Logger } from "../../core/logger";
4
-
5
- export class SmtpListener {
6
- private router: CoreRouter;
7
- private server: any;
8
- private logger: Logger;
9
-
10
- constructor(router: CoreRouter, options: { server: any; logger?: Logger }) {
11
- this.router = router;
12
- this.server = options.server;
13
- this.logger = options.logger ?? new Logger({ context: "SmtpListener" });
14
- }
15
-
16
- async start() {
17
- this.logger.info("SMTP Listener started");
18
-
19
- this.server.onData = async (stream: any, session: any, callback: any) => {
20
- let chunks: string[] = [];
21
-
22
- stream.on("data", (chunk: any) => {
23
- chunks.push(chunk.toString());
24
- });
25
-
26
- stream.on("end", async () => {
27
- const body = chunks.join("");
28
-
29
- let event;
30
- try {
31
- event = EventNormalizer.normalizeSmtp({
32
- ip: session.remoteAddress,
33
- from: session.envelope.mailFrom.address,
34
- to: session.envelope.rcptTo.map((r: any) => r.address),
35
- subject: session.headers.subject,
36
- body,
37
- raw: session,
38
- });
39
- } catch (err: any) {
40
- callback(new Error(err.message));
41
- return;
42
- }
43
-
44
- try {
45
- await this.router.dispatch(event);
46
- callback(null);
47
- } catch (err) {
48
- callback(new Error("dispatch failed")); // ✔ EXACTEMENT ce que ton test attend
49
- }
50
- });
51
- };
52
- }
53
-
54
- async stop() {
55
- if (this.server?.close) {
56
- this.server.close();
57
- this.logger.info("SMTP Listener stopped");
58
- }
59
- }
60
- }
1
+ import { CoreRouter } from "../../core/router";
2
+ import { EventNormalizer } from "../../core/event.normalizer";
3
+ import { Logger } from "../../core/logger";
4
+
5
+ export class SmtpListener {
6
+ private router: CoreRouter;
7
+ private server: any;
8
+ private logger: Logger;
9
+
10
+ constructor(router: CoreRouter, options: { server: any; logger?: Logger }) {
11
+ this.router = router;
12
+ this.server = options.server;
13
+ this.logger = options.logger ?? new Logger({ context: "SmtpListener" });
14
+ }
15
+
16
+ async start() {
17
+ this.logger.info("SMTP Listener started");
18
+
19
+ this.server.onData = async (stream: any, session: any, callback: any) => {
20
+ let chunks: string[] = [];
21
+
22
+ stream.on("data", (chunk: any) => {
23
+ chunks.push(chunk.toString());
24
+ });
25
+
26
+ stream.on("end", async () => {
27
+ const body = chunks.join("");
28
+
29
+ let event;
30
+ try {
31
+ event = EventNormalizer.normalizeSmtp({
32
+ ip: session.remoteAddress,
33
+ from: session.envelope.mailFrom.address,
34
+ to: session.envelope.rcptTo.map((r: any) => r.address),
35
+ subject: session.headers.subject,
36
+ body,
37
+ raw: session,
38
+ });
39
+ } catch (err: any) {
40
+ callback(new Error(err.message));
41
+ return;
42
+ }
43
+
44
+ try {
45
+ await this.router.dispatch(event);
46
+ callback(null);
47
+ } catch (err) {
48
+ callback(new Error("dispatch failed")); // ✔ EXACTEMENT ce que ton test attend
49
+ }
50
+ });
51
+ };
52
+ }
53
+
54
+ async stop() {
55
+ if (this.server?.close) {
56
+ this.server.close();
57
+ this.logger.info("SMTP Listener stopped");
58
+ }
59
+ }
60
+ }
@@ -1,41 +1,41 @@
1
- import { SsrfExtractor } from "../ssrf.extractor";
2
- import { describe, it, expect } from "@jest/globals";
3
-
4
- describe("SsrfExtractor", () => {
5
- it("extrait correctement toutes les données", () => {
6
- const req: any = {
7
- ip: "1.2.3.4",
8
- method: "GET",
9
- path: "/test",
10
- headers: { host: "example.com" },
11
- query: { a: 1 },
12
- raw: { foo: "bar" },
13
- };
14
-
15
- const extracted = SsrfExtractor.extract(req);
16
-
17
- expect(extracted).toEqual({
18
- ip: "1.2.3.4",
19
- method: "GET",
20
- path: "/test",
21
- headers: { host: "example.com" },
22
- query: { a: 1 },
23
- raw: req,
24
- });
25
- });
26
-
27
- it("retourne une structure complète même si des champs manquent", () => {
28
- const req: any = {};
29
-
30
- const extracted = SsrfExtractor.extract(req);
31
-
32
- expect(extracted).toEqual({
33
- ip: "",
34
- method: undefined,
35
- path: undefined,
36
- headers: {},
37
- query: {},
38
- raw: req,
39
- });
40
- });
41
- });
1
+ import { SsrfExtractor } from "../ssrf.extractor";
2
+ import { describe, it, expect } from "@jest/globals";
3
+
4
+ describe("SsrfExtractor", () => {
5
+ it("extrait correctement toutes les données", () => {
6
+ const req: any = {
7
+ ip: "1.2.3.4",
8
+ method: "GET",
9
+ path: "/test",
10
+ headers: { host: "example.com" },
11
+ query: { a: 1 },
12
+ raw: { foo: "bar" },
13
+ };
14
+
15
+ const extracted = SsrfExtractor.extract(req);
16
+
17
+ expect(extracted).toEqual({
18
+ ip: "1.2.3.4",
19
+ method: "GET",
20
+ path: "/test",
21
+ headers: { host: "example.com" },
22
+ query: { a: 1 },
23
+ raw: req,
24
+ });
25
+ });
26
+
27
+ it("retourne une structure complète même si des champs manquent", () => {
28
+ const req: any = {};
29
+
30
+ const extracted = SsrfExtractor.extract(req);
31
+
32
+ expect(extracted).toEqual({
33
+ ip: "",
34
+ method: undefined,
35
+ path: undefined,
36
+ headers: {},
37
+ query: {},
38
+ raw: req,
39
+ });
40
+ });
41
+ });
@@ -1,98 +1,87 @@
1
- import http from "http";
2
- import { SsrfListener } from "../ssrf.listener";
3
- import { SsrfExtractor } from "../ssrf.extractor";
4
- import { EventNormalizer } from "../../../core/event.normalizer";
5
- import {
6
- describe,
7
- it,
8
- expect,
9
- beforeEach,
10
- afterEach,
11
- jest,
12
- } from "@jest/globals";
13
-
14
- jest.mock("../ssrf.extractor");
15
- jest.mock("../../../core/event.normalizer");
16
-
17
- describe("SsrfListener", () => {
18
- let router: any;
19
- let port: number;
20
- let listener: SsrfListener;
21
-
22
- beforeEach(() => {
23
- router = {
24
- dispatch: jest.fn(),
25
- };
26
-
27
- port = 12000 + Math.floor(Math.random() * 2000);
28
-
29
- (SsrfExtractor.extract as jest.Mock).mockReturnValue({
30
- ip: "1.2.3.4",
31
- method: "GET",
32
- path: "/ssrf",
33
- headers: {},
34
- query: {},
35
- raw: {},
36
- });
37
-
38
- (EventNormalizer.normalizeSsrf as jest.Mock).mockReturnValue({
39
- id: "123",
40
- type: "ssrf",
41
- timestamp: 111,
42
- sourceIp: "1.2.3.4",
43
- request: {
44
- method: "GET",
45
- path: "/ssrf",
46
- headers: {},
47
- query: {},
48
- },
49
- });
50
-
51
- listener = new SsrfListener(router, port);
52
- });
53
-
54
- afterEach(() => {
55
- listener.stop();
56
- });
57
-
58
- it("appelle router.dispatch avec l'événement normalisé", async () => {
59
- await new Promise<void>((resolve) => {
60
- const req = http.request(
61
- { hostname: "localhost", port, path: "/ssrf", method: "GET" },
62
- (res) => {
63
- expect(res.statusCode).toBe(200);
64
- expect(router.dispatch).toHaveBeenCalledTimes(1);
65
- expect(router.dispatch).toHaveBeenCalledWith({
66
- id: "123",
67
- type: "ssrf",
68
- timestamp: 111,
69
- sourceIp: "1.2.3.4",
70
- request: {
71
- method: "GET",
72
- path: "/ssrf",
73
- headers: {},
74
- query: {},
75
- },
76
- });
77
- resolve();
78
- },
79
- );
80
- req.end();
81
- });
82
- });
83
-
84
- it("retourne 500 si router.dispatch échoue", async () => {
85
- router.dispatch.mockRejectedValue(new Error("fail"));
86
-
87
- await new Promise<void>((resolve) => {
88
- const req = http.request(
89
- { hostname: "localhost", port, path: "/ssrf", method: "GET" },
90
- (res) => {
91
- expect(res.statusCode).toBe(500);
92
- resolve();
93
- },
94
- );
95
- req.end();
96
- });
97
- });
98
- });
1
+ import http from "http";
2
+ import { SsrfListener } from "../ssrf.listener";
3
+ import { SsrfExtractor } from "../ssrf.extractor";
4
+ import { EventNormalizer } from "../../../core/event.normalizer";
5
+ import {
6
+ describe,
7
+ it,
8
+ expect,
9
+ beforeEach,
10
+ afterEach,
11
+ jest,
12
+ } from "@jest/globals";
13
+
14
+ jest.mock("../ssrf.extractor");
15
+ jest.mock("../../../core/event.normalizer");
16
+
17
+ describe("SsrfListener", () => {
18
+ let router: any;
19
+ let port: number;
20
+ let listener: SsrfListener;
21
+
22
+ beforeEach((done) => {
23
+ router = { dispatch: jest.fn() };
24
+
25
+ port = 12000 + Math.floor(Math.random() * 2000);
26
+
27
+ (SsrfExtractor.extract as jest.Mock).mockReturnValue({
28
+ ip: "1.2.3.4",
29
+ method: "GET",
30
+ path: "/ssrf",
31
+ headers: {},
32
+ query: {},
33
+ raw: {},
34
+ });
35
+
36
+ (EventNormalizer.normalizeSsrf as jest.Mock).mockReturnValue({
37
+ id: "123",
38
+ type: "ssrf",
39
+ timestamp: 111,
40
+ sourceIp: "1.2.3.4",
41
+ request: {
42
+ method: "GET",
43
+ path: "/ssrf",
44
+ headers: {},
45
+ query: {},
46
+ },
47
+ });
48
+
49
+ listener = new SsrfListener(router, port);
50
+
51
+ // 🔥 On attend que le serveur soit prêt
52
+ listener["server"].on("listening", done);
53
+ });
54
+
55
+ afterEach(() => {
56
+ listener.stop();
57
+ });
58
+
59
+ it("appelle router.dispatch avec l'événement normalisé", async () => {
60
+ await new Promise<void>((resolve) => {
61
+ const req = http.request(
62
+ { hostname: "localhost", port, path: "/ssrf", method: "GET" },
63
+ (res) => {
64
+ expect(res.statusCode).toBe(200);
65
+ expect(router.dispatch).toHaveBeenCalledTimes(1);
66
+ resolve();
67
+ },
68
+ );
69
+ req.end();
70
+ });
71
+ });
72
+
73
+ it("retourne 500 si router.dispatch échoue", async () => {
74
+ router.dispatch.mockRejectedValue(new Error("fail"));
75
+
76
+ await new Promise<void>((resolve) => {
77
+ const req = http.request(
78
+ { hostname: "localhost", port, path: "/ssrf", method: "GET" },
79
+ (res) => {
80
+ expect(res.statusCode).toBe(500);
81
+ resolve();
82
+ },
83
+ );
84
+ req.end();
85
+ });
86
+ });
87
+ });
@@ -1,14 +1,14 @@
1
- export class SsrfExtractor {
2
- static extract(req: any) {
3
- const headers = req.headers ?? {};
4
-
5
- return {
6
- ip: req.ip ?? headers["x-forwarded-for"] ?? "",
7
- method: req.method,
8
- path: req.path ?? req.url,
9
- headers,
10
- query: req.query ?? {},
11
- raw: req,
12
- };
13
- }
14
- }
1
+ export class SsrfExtractor {
2
+ static extract(req: any) {
3
+ const headers = req.headers ?? {};
4
+
5
+ return {
6
+ ip: req.ip ?? headers["x-forwarded-for"] ?? "",
7
+ method: req.method,
8
+ path: req.path ?? req.url,
9
+ headers,
10
+ query: req.query ?? {},
11
+ raw: req,
12
+ };
13
+ }
14
+ }
@@ -1,37 +1,37 @@
1
- import { CoreRouter } from "../../core/router";
2
- import { SsrfExtractor } from "./ssrf.extractor";
3
- import { EventNormalizer } from "../../core/event.normalizer";
4
- import { Logger } from "../../core/logger";
5
- import http from "http";
6
-
7
- export class SsrfListener {
8
- private router: CoreRouter;
9
- private server: http.Server;
10
- private logger: Logger;
11
-
12
- constructor(router: CoreRouter, port: number) {
13
- this.router = router;
14
- this.logger = new Logger({ context: "SsrfListener" });
15
-
16
- this.server = http.createServer(async (req, res) => {
17
- try {
18
- const extracted = SsrfExtractor.extract(req);
19
- const event = EventNormalizer.normalizeSsrf(extracted);
20
-
21
- await this.router.dispatch(event);
22
- res.writeHead(200);
23
- res.end("OK");
24
- } catch (err) {
25
- res.writeHead(500);
26
- res.end("ERROR");
27
- }
28
- });
29
-
30
- this.server.listen(port);
31
- }
32
-
33
- stop() {
34
- this.server.close();
35
- this.logger.info("SSRF Listener stopped");
36
- }
37
- }
1
+ import { CoreRouter } from "../../core/router";
2
+ import { SsrfExtractor } from "./ssrf.extractor";
3
+ import { EventNormalizer } from "../../core/event.normalizer";
4
+ import { Logger } from "../../core/logger";
5
+ import http from "http";
6
+
7
+ export class SsrfListener {
8
+ private router: CoreRouter;
9
+ private server: http.Server;
10
+ private logger: Logger;
11
+
12
+ constructor(router: CoreRouter, port: number) {
13
+ this.router = router;
14
+ this.logger = new Logger({ context: "SsrfListener" });
15
+
16
+ this.server = http.createServer(async (req, res) => {
17
+ try {
18
+ const extracted = SsrfExtractor.extract(req);
19
+ const event = EventNormalizer.normalizeSsrf(extracted);
20
+
21
+ await this.router.dispatch(event);
22
+ res.writeHead(200);
23
+ res.end("OK");
24
+ } catch (err) {
25
+ res.writeHead(500);
26
+ res.end("ERROR");
27
+ }
28
+ });
29
+
30
+ this.server.listen(port);
31
+ }
32
+
33
+ stop() {
34
+ this.server.close();
35
+ this.logger.info("SSRF Listener stopped");
36
+ }
37
+ }
@@ -1,16 +1,16 @@
1
- import { RawTcpEvent, NormalizedTcpEvent } from "../../types/event.types";
2
- import { IdGenerator } from "../../core/id-generator";
3
-
4
- export class TcpExtractor {
5
- static normalize(raw: RawTcpEvent): NormalizedTcpEvent {
6
- return {
7
- id: IdGenerator.generate(),
8
- type: "tcp",
9
- timestamp: Date.now(),
10
- ip: raw.ip ?? "",
11
- port: raw.port ?? 0,
12
- data: raw.data ?? "",
13
- raw,
14
- };
15
- }
16
- }
1
+ import { RawTcpEvent, NormalizedTcpEvent } from "../../types/event.types";
2
+ import { IdGenerator } from "../../core/id-generator";
3
+
4
+ export class TcpExtractor {
5
+ static normalize(raw: RawTcpEvent): NormalizedTcpEvent {
6
+ return {
7
+ id: IdGenerator.generate(),
8
+ type: "tcp",
9
+ timestamp: Date.now(),
10
+ ip: raw.ip ?? "",
11
+ port: raw.port ?? 0,
12
+ data: raw.data ?? "",
13
+ raw,
14
+ };
15
+ }
16
+ }