@j3r3mcdev/oast-server 1.1.7 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +29 -29
- package/.github/workflows/publish.yml +31 -31
- package/README.md +192 -192
- package/dist/core/router.d.ts +1 -0
- package/dist/core/router.js +3 -3
- package/jest.config.js +14 -14
- package/package.json +45 -45
- package/sadmin list shadows +9 -9
- package/src/api/controllers/__tests__/tasks.controller.test.ts +74 -74
- package/src/api/controllers/events.controller.ts +10 -10
- package/src/api/controllers/health.controller.ts +7 -7
- package/src/api/controllers/tasks.controller.ts +41 -41
- package/src/api/dto/__tests__/create-task.dto.test.ts +41 -41
- package/src/api/dto/__tests__/filter-tasks.dto.test.ts +35 -35
- package/src/api/dto/create-task.dto.ts +33 -33
- package/src/api/dto/filter-tasks.dto.ts +33 -33
- package/src/api/services/__tests__/events.service.test.ts +41 -41
- package/src/api/services/__tests__/tasks.service.test.ts +41 -41
- package/src/api/services/events.service.ts +17 -17
- package/src/api/services/tasks.service.ts +79 -79
- package/src/api/sse/events.stream.ts +90 -90
- package/src/bootstrap.ts +89 -89
- package/src/core/__tests__/core-router.test.ts +30 -30
- package/src/core/__tests__/core-server.test.ts +44 -44
- package/src/core/__tests__/event.normalizer.test.ts +56 -56
- package/src/core/__tests__/event.router.test.ts +89 -89
- package/src/core/__tests__/logger.test.ts +32 -32
- package/src/core/__tests__/storage-manager.test.ts +74 -74
- package/src/core/event.normalizer.ts +147 -147
- package/src/core/event.router.ts +13 -13
- package/src/core/http/__tests__/adapter-node.test.ts +52 -52
- package/src/core/http/__tests__/body-parser-multipart.test.ts +41 -41
- package/src/core/http/__tests__/body-parser-raw.test.ts +28 -28
- package/src/core/http/__tests__/body-parser-text.test.ts +28 -28
- package/src/core/http/__tests__/compile-path.test.ts +39 -39
- package/src/core/http/__tests__/middleware-pipeline.test.ts +51 -51
- package/src/core/http/__tests__/request.test.ts +34 -34
- package/src/core/http/__tests__/response.test.ts +35 -35
- package/src/core/http/__tests__/router-match.test.ts +171 -171
- package/src/core/http/adapter-node.ts +51 -51
- package/src/core/http/buildRequest.ts +18 -18
- package/src/core/http/compile-path.ts +32 -32
- package/src/core/http/errors.ts +37 -37
- package/src/core/http/http-server.ts +52 -52
- package/src/core/http/middleware.ts +160 -160
- package/src/core/http/request.ts +55 -55
- package/src/core/http/response.ts +93 -93
- package/src/core/http/router.ts +138 -138
- package/src/core/id-generator.ts +8 -8
- package/src/core/logger.ts +113 -113
- package/src/core/router.ts +44 -44
- package/src/core/server.ts +85 -85
- package/src/core/storage.ts +64 -64
- package/src/index.ts +14 -14
- package/src/listeners/api/__tests__/api.controller.test.ts +116 -116
- package/src/listeners/api/__tests__/api.extractor.test.ts +46 -46
- package/src/listeners/api/__tests__/api.listener.test.ts +82 -82
- package/src/listeners/api/__tests__/api.routes.test.ts +155 -155
- package/src/listeners/api/__tests__/api.sse.test.ts +105 -105
- package/src/listeners/api/api.controllers.ts +67 -67
- package/src/listeners/api/api.extractor.ts +43 -43
- package/src/listeners/api/api.listener.ts +50 -50
- package/src/listeners/api/api.routes.ts +76 -76
- package/src/listeners/api/api.sse.ts +38 -38
- package/src/listeners/dns/__tests__/dns.test.ts +118 -118
- package/src/listeners/dns/dns.extractor.ts +14 -14
- package/src/listeners/dns/dns.listener.ts +61 -61
- package/src/listeners/http/__tests__/http.extractor.test.ts +59 -59
- package/src/listeners/http/__tests__/http.listener.test.ts +133 -133
- package/src/listeners/http/http.extractor.ts +15 -15
- package/src/listeners/http/http.listener.ts +110 -110
- package/src/listeners/listener.interface.ts +4 -4
- package/src/listeners/smtp/__tests__/smtp.extractor.test.ts +69 -69
- package/src/listeners/smtp/__tests__/smtp.listener.test.ts +150 -150
- package/src/listeners/smtp/smtp.extractor.ts +18 -18
- package/src/listeners/smtp/smtp.listener.ts +60 -60
- package/src/listeners/ssrf/__tests__/ssrf.extractor.test.ts +41 -41
- package/src/listeners/ssrf/__tests__/ssrf.listener.test.ts +87 -87
- package/src/listeners/ssrf/ssrf.extractor.ts +14 -14
- package/src/listeners/ssrf/ssrf.listener.ts +37 -37
- package/src/listeners/tcp/tcp.extractor.ts +16 -16
- package/src/listeners/tcp/tcp.listener.ts +61 -61
- package/src/listeners/webhook/__tests__/webhook.extractor.test.ts +35 -35
- package/src/listeners/webhook/__tests__/webhook.listener.test.ts +122 -122
- package/src/listeners/webhook/webhook.extractor.ts +12 -12
- package/src/listeners/webhook/webhook.listener.ts +58 -58
- package/src/listeners/websocket/__tests__/websocket.extractor.test.ts +33 -33
- package/src/listeners/websocket/__tests__/websocket.listener.test.ts +90 -90
- package/src/listeners/websocket/websocket.extractor.ts +11 -11
- package/src/listeners/websocket/websocket.listener.ts +40 -40
- package/src/storage-adapters/adapters/__tests__/memory.storage.test.ts +75 -75
- package/src/storage-adapters/adapters/memory.storage.ts +64 -64
- package/src/storage-adapters/storage.interface.ts +26 -26
- package/src/types/event.types.ts +147 -147
- package/tsconfig.json +20 -20
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
import {
|
|
2
|
-
describe,
|
|
3
|
-
it,
|
|
4
|
-
expect,
|
|
5
|
-
jest,
|
|
6
|
-
beforeEach,
|
|
7
|
-
afterEach,
|
|
8
|
-
} from "@jest/globals";
|
|
9
|
-
|
|
10
|
-
import http from "http";
|
|
11
|
-
import { WebhookListener } from "../webhook.listener";
|
|
12
|
-
import { WebhookExtractor } from "../webhook.extractor";
|
|
13
|
-
import { EventNormalizer } from "../../../core/event.normalizer";
|
|
14
|
-
|
|
15
|
-
jest.mock("../webhook.extractor");
|
|
16
|
-
jest.mock("../../../core/event.normalizer");
|
|
17
|
-
|
|
18
|
-
describe("WebhookListener", () => {
|
|
19
|
-
let router: any;
|
|
20
|
-
let port: number;
|
|
21
|
-
let listener: WebhookListener;
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
router = {
|
|
25
|
-
dispatch: jest.fn(),
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
port = 13000 + Math.floor(Math.random() * 2000);
|
|
29
|
-
|
|
30
|
-
(WebhookExtractor.extract as jest.Mock).mockReturnValue({
|
|
31
|
-
ip: "1.2.3.4",
|
|
32
|
-
headers: { "x-test": "ok" },
|
|
33
|
-
body: { hello: "world" },
|
|
34
|
-
raw: {},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
(EventNormalizer.normalizeWebhook as jest.Mock).mockReturnValue({
|
|
38
|
-
id: "abc",
|
|
39
|
-
type: "webhook",
|
|
40
|
-
timestamp: 111,
|
|
41
|
-
sourceIp: "1.2.3.4",
|
|
42
|
-
headers: { "x-test": "ok" },
|
|
43
|
-
body: { hello: "world" },
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
listener = new WebhookListener(router, port);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
afterEach(() => {
|
|
50
|
-
listener.stop();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("appelle router.dispatch avec l'événement normalisé", async () => {
|
|
54
|
-
await new Promise<void>((resolve) => {
|
|
55
|
-
const req = http.request(
|
|
56
|
-
{
|
|
57
|
-
hostname: "localhost",
|
|
58
|
-
port,
|
|
59
|
-
path: "/",
|
|
60
|
-
method: "POST",
|
|
61
|
-
headers: { "content-type": "application/json" },
|
|
62
|
-
},
|
|
63
|
-
(res) => {
|
|
64
|
-
expect(res.statusCode).toBe(200);
|
|
65
|
-
expect(router.dispatch).toHaveBeenCalledTimes(1);
|
|
66
|
-
expect(router.dispatch).toHaveBeenCalledWith({
|
|
67
|
-
id: "abc",
|
|
68
|
-
type: "webhook",
|
|
69
|
-
timestamp: 111,
|
|
70
|
-
sourceIp: "1.2.3.4",
|
|
71
|
-
headers: { "x-test": "ok" },
|
|
72
|
-
body: { hello: "world" },
|
|
73
|
-
});
|
|
74
|
-
resolve();
|
|
75
|
-
},
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
req.write(JSON.stringify({ hello: "world" }));
|
|
79
|
-
req.end();
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("retourne 500 si router.dispatch échoue", async () => {
|
|
84
|
-
router.dispatch.mockRejectedValue(new Error("fail"));
|
|
85
|
-
|
|
86
|
-
await new Promise<void>((resolve) => {
|
|
87
|
-
const req = http.request(
|
|
88
|
-
{
|
|
89
|
-
hostname: "localhost",
|
|
90
|
-
port,
|
|
91
|
-
path: "/",
|
|
92
|
-
method: "POST",
|
|
93
|
-
},
|
|
94
|
-
(res) => {
|
|
95
|
-
expect(res.statusCode).toBe(500);
|
|
96
|
-
resolve();
|
|
97
|
-
},
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
req.write("{}");
|
|
101
|
-
req.end();
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("retourne 405 si la méthode n'est pas POST", async () => {
|
|
106
|
-
await new Promise<void>((resolve) => {
|
|
107
|
-
const req = http.request(
|
|
108
|
-
{
|
|
109
|
-
hostname: "localhost",
|
|
110
|
-
port,
|
|
111
|
-
path: "/",
|
|
112
|
-
method: "GET",
|
|
113
|
-
},
|
|
114
|
-
(res) => {
|
|
115
|
-
expect(res.statusCode).toBe(405);
|
|
116
|
-
resolve();
|
|
117
|
-
},
|
|
118
|
-
);
|
|
119
|
-
req.end();
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
});
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
it,
|
|
4
|
+
expect,
|
|
5
|
+
jest,
|
|
6
|
+
beforeEach,
|
|
7
|
+
afterEach,
|
|
8
|
+
} from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
import http from "http";
|
|
11
|
+
import { WebhookListener } from "../webhook.listener";
|
|
12
|
+
import { WebhookExtractor } from "../webhook.extractor";
|
|
13
|
+
import { EventNormalizer } from "../../../core/event.normalizer";
|
|
14
|
+
|
|
15
|
+
jest.mock("../webhook.extractor");
|
|
16
|
+
jest.mock("../../../core/event.normalizer");
|
|
17
|
+
|
|
18
|
+
describe("WebhookListener", () => {
|
|
19
|
+
let router: any;
|
|
20
|
+
let port: number;
|
|
21
|
+
let listener: WebhookListener;
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
router = {
|
|
25
|
+
dispatch: jest.fn(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
port = 13000 + Math.floor(Math.random() * 2000);
|
|
29
|
+
|
|
30
|
+
(WebhookExtractor.extract as jest.Mock).mockReturnValue({
|
|
31
|
+
ip: "1.2.3.4",
|
|
32
|
+
headers: { "x-test": "ok" },
|
|
33
|
+
body: { hello: "world" },
|
|
34
|
+
raw: {},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
(EventNormalizer.normalizeWebhook as jest.Mock).mockReturnValue({
|
|
38
|
+
id: "abc",
|
|
39
|
+
type: "webhook",
|
|
40
|
+
timestamp: 111,
|
|
41
|
+
sourceIp: "1.2.3.4",
|
|
42
|
+
headers: { "x-test": "ok" },
|
|
43
|
+
body: { hello: "world" },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
listener = new WebhookListener(router, port);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
listener.stop();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("appelle router.dispatch avec l'événement normalisé", async () => {
|
|
54
|
+
await new Promise<void>((resolve) => {
|
|
55
|
+
const req = http.request(
|
|
56
|
+
{
|
|
57
|
+
hostname: "localhost",
|
|
58
|
+
port,
|
|
59
|
+
path: "/",
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: { "content-type": "application/json" },
|
|
62
|
+
},
|
|
63
|
+
(res) => {
|
|
64
|
+
expect(res.statusCode).toBe(200);
|
|
65
|
+
expect(router.dispatch).toHaveBeenCalledTimes(1);
|
|
66
|
+
expect(router.dispatch).toHaveBeenCalledWith({
|
|
67
|
+
id: "abc",
|
|
68
|
+
type: "webhook",
|
|
69
|
+
timestamp: 111,
|
|
70
|
+
sourceIp: "1.2.3.4",
|
|
71
|
+
headers: { "x-test": "ok" },
|
|
72
|
+
body: { hello: "world" },
|
|
73
|
+
});
|
|
74
|
+
resolve();
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
req.write(JSON.stringify({ hello: "world" }));
|
|
79
|
+
req.end();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("retourne 500 si router.dispatch échoue", async () => {
|
|
84
|
+
router.dispatch.mockRejectedValue(new Error("fail"));
|
|
85
|
+
|
|
86
|
+
await new Promise<void>((resolve) => {
|
|
87
|
+
const req = http.request(
|
|
88
|
+
{
|
|
89
|
+
hostname: "localhost",
|
|
90
|
+
port,
|
|
91
|
+
path: "/",
|
|
92
|
+
method: "POST",
|
|
93
|
+
},
|
|
94
|
+
(res) => {
|
|
95
|
+
expect(res.statusCode).toBe(500);
|
|
96
|
+
resolve();
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
req.write("{}");
|
|
101
|
+
req.end();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("retourne 405 si la méthode n'est pas POST", async () => {
|
|
106
|
+
await new Promise<void>((resolve) => {
|
|
107
|
+
const req = http.request(
|
|
108
|
+
{
|
|
109
|
+
hostname: "localhost",
|
|
110
|
+
port,
|
|
111
|
+
path: "/",
|
|
112
|
+
method: "GET",
|
|
113
|
+
},
|
|
114
|
+
(res) => {
|
|
115
|
+
expect(res.statusCode).toBe(405);
|
|
116
|
+
resolve();
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
req.end();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export class WebhookExtractor {
|
|
2
|
-
static extract(req: any, body: any) {
|
|
3
|
-
const headers = req.headers ?? {};
|
|
4
|
-
|
|
5
|
-
return {
|
|
6
|
-
ip: req.ip ?? headers["x-forwarded-for"] ?? "",
|
|
7
|
-
headers,
|
|
8
|
-
body,
|
|
9
|
-
raw: req,
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
}
|
|
1
|
+
export class WebhookExtractor {
|
|
2
|
+
static extract(req: any, body: any) {
|
|
3
|
+
const headers = req.headers ?? {};
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
ip: req.ip ?? headers["x-forwarded-for"] ?? "",
|
|
7
|
+
headers,
|
|
8
|
+
body,
|
|
9
|
+
raw: req,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import http from "http";
|
|
2
|
-
import { CoreRouter } from "../../core/router";
|
|
3
|
-
import { WebhookExtractor } from "./webhook.extractor";
|
|
4
|
-
import { EventNormalizer } from "../../core/event.normalizer";
|
|
5
|
-
import { Logger } from "../../core/logger";
|
|
6
|
-
|
|
7
|
-
export class WebhookListener {
|
|
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: "WebhookListener" });
|
|
15
|
-
|
|
16
|
-
this.server = http.createServer(async (req, res) => {
|
|
17
|
-
if (req.method !== "POST") {
|
|
18
|
-
res.writeHead(405);
|
|
19
|
-
return res.end("Method Not Allowed");
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let chunks: Buffer[] = [];
|
|
23
|
-
|
|
24
|
-
req.on("data", (chunk) => chunks.push(chunk));
|
|
25
|
-
|
|
26
|
-
req.on("end", async () => {
|
|
27
|
-
try {
|
|
28
|
-
const bodyRaw = Buffer.concat(chunks).toString();
|
|
29
|
-
let body: any = null;
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
body = JSON.parse(bodyRaw);
|
|
33
|
-
} catch {
|
|
34
|
-
body = bodyRaw;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const extracted = WebhookExtractor.extract(req, body);
|
|
38
|
-
const event = EventNormalizer.normalizeWebhook(extracted);
|
|
39
|
-
|
|
40
|
-
await this.router.dispatch(event);
|
|
41
|
-
|
|
42
|
-
res.writeHead(200);
|
|
43
|
-
res.end("OK");
|
|
44
|
-
} catch (err) {
|
|
45
|
-
res.writeHead(500);
|
|
46
|
-
res.end("ERROR");
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
this.server.listen(port);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
stop() {
|
|
55
|
-
this.server.close();
|
|
56
|
-
this.logger.info("Webhook Listener stopped");
|
|
57
|
-
}
|
|
58
|
-
}
|
|
1
|
+
import http from "http";
|
|
2
|
+
import { CoreRouter } from "../../core/router";
|
|
3
|
+
import { WebhookExtractor } from "./webhook.extractor";
|
|
4
|
+
import { EventNormalizer } from "../../core/event.normalizer";
|
|
5
|
+
import { Logger } from "../../core/logger";
|
|
6
|
+
|
|
7
|
+
export class WebhookListener {
|
|
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: "WebhookListener" });
|
|
15
|
+
|
|
16
|
+
this.server = http.createServer(async (req, res) => {
|
|
17
|
+
if (req.method !== "POST") {
|
|
18
|
+
res.writeHead(405);
|
|
19
|
+
return res.end("Method Not Allowed");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let chunks: Buffer[] = [];
|
|
23
|
+
|
|
24
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
25
|
+
|
|
26
|
+
req.on("end", async () => {
|
|
27
|
+
try {
|
|
28
|
+
const bodyRaw = Buffer.concat(chunks).toString();
|
|
29
|
+
let body: any = null;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
body = JSON.parse(bodyRaw);
|
|
33
|
+
} catch {
|
|
34
|
+
body = bodyRaw;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const extracted = WebhookExtractor.extract(req, body);
|
|
38
|
+
const event = EventNormalizer.normalizeWebhook(extracted);
|
|
39
|
+
|
|
40
|
+
await this.router.dispatch(event);
|
|
41
|
+
|
|
42
|
+
res.writeHead(200);
|
|
43
|
+
res.end("OK");
|
|
44
|
+
} catch (err) {
|
|
45
|
+
res.writeHead(500);
|
|
46
|
+
res.end("ERROR");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
this.server.listen(port);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
stop() {
|
|
55
|
+
this.server.close();
|
|
56
|
+
this.logger.info("Webhook Listener stopped");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { WebSocketExtractor } from "../websocket.extractor";
|
|
3
|
-
|
|
4
|
-
describe("WebSocketExtractor", () => {
|
|
5
|
-
it("extrait correctement les données", () => {
|
|
6
|
-
const ws: any = {};
|
|
7
|
-
const req: any = {
|
|
8
|
-
socket: { remoteAddress: "1.2.3.4" },
|
|
9
|
-
headers: { host: "example.com" },
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const extracted = WebSocketExtractor.extract(ws, req, "hello");
|
|
13
|
-
|
|
14
|
-
expect(extracted).toEqual({
|
|
15
|
-
ip: "1.2.3.4",
|
|
16
|
-
message: "hello",
|
|
17
|
-
raw: { ws, req },
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("retourne une structure complète même si des champs manquent", () => {
|
|
22
|
-
const ws: any = {};
|
|
23
|
-
const req: any = {};
|
|
24
|
-
|
|
25
|
-
const extracted = WebSocketExtractor.extract(ws, req, "test");
|
|
26
|
-
|
|
27
|
-
expect(extracted).toEqual({
|
|
28
|
-
ip: "",
|
|
29
|
-
message: "test",
|
|
30
|
-
raw: { ws, req },
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
});
|
|
1
|
+
import { describe, it, expect } from "@jest/globals";
|
|
2
|
+
import { WebSocketExtractor } from "../websocket.extractor";
|
|
3
|
+
|
|
4
|
+
describe("WebSocketExtractor", () => {
|
|
5
|
+
it("extrait correctement les données", () => {
|
|
6
|
+
const ws: any = {};
|
|
7
|
+
const req: any = {
|
|
8
|
+
socket: { remoteAddress: "1.2.3.4" },
|
|
9
|
+
headers: { host: "example.com" },
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const extracted = WebSocketExtractor.extract(ws, req, "hello");
|
|
13
|
+
|
|
14
|
+
expect(extracted).toEqual({
|
|
15
|
+
ip: "1.2.3.4",
|
|
16
|
+
message: "hello",
|
|
17
|
+
raw: { ws, req },
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("retourne une structure complète même si des champs manquent", () => {
|
|
22
|
+
const ws: any = {};
|
|
23
|
+
const req: any = {};
|
|
24
|
+
|
|
25
|
+
const extracted = WebSocketExtractor.extract(ws, req, "test");
|
|
26
|
+
|
|
27
|
+
expect(extracted).toEqual({
|
|
28
|
+
ip: "",
|
|
29
|
+
message: "test",
|
|
30
|
+
raw: { ws, req },
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
import {
|
|
2
|
-
describe,
|
|
3
|
-
it,
|
|
4
|
-
expect,
|
|
5
|
-
jest,
|
|
6
|
-
beforeEach,
|
|
7
|
-
afterEach,
|
|
8
|
-
} from "@jest/globals";
|
|
9
|
-
|
|
10
|
-
import { WebSocketServer } from "ws";
|
|
11
|
-
import WebSocket from "ws";
|
|
12
|
-
import { WebSocketListener } from "../websocket.listener";
|
|
13
|
-
import { WebSocketExtractor } from "../websocket.extractor";
|
|
14
|
-
import { EventNormalizer } from "../../../core/event.normalizer";
|
|
15
|
-
|
|
16
|
-
jest.mock("../websocket.extractor");
|
|
17
|
-
jest.mock("../../../core/event.normalizer");
|
|
18
|
-
|
|
19
|
-
describe("WebSocketListener", () => {
|
|
20
|
-
let router: any;
|
|
21
|
-
let port: number;
|
|
22
|
-
let listener: WebSocketListener;
|
|
23
|
-
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
router = {
|
|
26
|
-
dispatch: jest.fn(),
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
port = 14000 + Math.floor(Math.random() * 2000);
|
|
30
|
-
|
|
31
|
-
(WebSocketExtractor.extract as jest.Mock).mockReturnValue({
|
|
32
|
-
ip: "1.2.3.4",
|
|
33
|
-
message: "hello",
|
|
34
|
-
raw: {},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
(EventNormalizer.normalizeWebSocket as jest.Mock).mockReturnValue({
|
|
38
|
-
id: "ws123",
|
|
39
|
-
type: "websocket",
|
|
40
|
-
timestamp: 111,
|
|
41
|
-
sourceIp: "1.2.3.4",
|
|
42
|
-
message: "hello",
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
listener = new WebSocketListener(router, port);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
listener.stop();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("appelle router.dispatch quand un message est reçu", async () => {
|
|
53
|
-
const client = new WebSocket(`ws://localhost:${port}`);
|
|
54
|
-
|
|
55
|
-
await new Promise<void>((resolve) => {
|
|
56
|
-
client.on("open", () => {
|
|
57
|
-
client.send("hello");
|
|
58
|
-
setTimeout(() => {
|
|
59
|
-
expect(router.dispatch).toHaveBeenCalledTimes(1);
|
|
60
|
-
expect(router.dispatch).toHaveBeenCalledWith({
|
|
61
|
-
id: "ws123",
|
|
62
|
-
type: "websocket",
|
|
63
|
-
timestamp: 111,
|
|
64
|
-
sourceIp: "1.2.3.4",
|
|
65
|
-
message: "hello",
|
|
66
|
-
});
|
|
67
|
-
client.close();
|
|
68
|
-
resolve();
|
|
69
|
-
}, 50);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("ne plante pas si dispatch échoue", async () => {
|
|
75
|
-
router.dispatch.mockRejectedValue(new Error("fail"));
|
|
76
|
-
|
|
77
|
-
const client = new WebSocket(`ws://localhost:${port}`);
|
|
78
|
-
|
|
79
|
-
await new Promise<void>((resolve) => {
|
|
80
|
-
client.on("open", () => {
|
|
81
|
-
client.send("hello");
|
|
82
|
-
setTimeout(() => {
|
|
83
|
-
expect(router.dispatch).toHaveBeenCalledTimes(1);
|
|
84
|
-
client.close();
|
|
85
|
-
resolve();
|
|
86
|
-
}, 50);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
});
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
it,
|
|
4
|
+
expect,
|
|
5
|
+
jest,
|
|
6
|
+
beforeEach,
|
|
7
|
+
afterEach,
|
|
8
|
+
} from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
import { WebSocketServer } from "ws";
|
|
11
|
+
import WebSocket from "ws";
|
|
12
|
+
import { WebSocketListener } from "../websocket.listener";
|
|
13
|
+
import { WebSocketExtractor } from "../websocket.extractor";
|
|
14
|
+
import { EventNormalizer } from "../../../core/event.normalizer";
|
|
15
|
+
|
|
16
|
+
jest.mock("../websocket.extractor");
|
|
17
|
+
jest.mock("../../../core/event.normalizer");
|
|
18
|
+
|
|
19
|
+
describe("WebSocketListener", () => {
|
|
20
|
+
let router: any;
|
|
21
|
+
let port: number;
|
|
22
|
+
let listener: WebSocketListener;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
router = {
|
|
26
|
+
dispatch: jest.fn(),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
port = 14000 + Math.floor(Math.random() * 2000);
|
|
30
|
+
|
|
31
|
+
(WebSocketExtractor.extract as jest.Mock).mockReturnValue({
|
|
32
|
+
ip: "1.2.3.4",
|
|
33
|
+
message: "hello",
|
|
34
|
+
raw: {},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
(EventNormalizer.normalizeWebSocket as jest.Mock).mockReturnValue({
|
|
38
|
+
id: "ws123",
|
|
39
|
+
type: "websocket",
|
|
40
|
+
timestamp: 111,
|
|
41
|
+
sourceIp: "1.2.3.4",
|
|
42
|
+
message: "hello",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
listener = new WebSocketListener(router, port);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
listener.stop();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("appelle router.dispatch quand un message est reçu", async () => {
|
|
53
|
+
const client = new WebSocket(`ws://localhost:${port}`);
|
|
54
|
+
|
|
55
|
+
await new Promise<void>((resolve) => {
|
|
56
|
+
client.on("open", () => {
|
|
57
|
+
client.send("hello");
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
expect(router.dispatch).toHaveBeenCalledTimes(1);
|
|
60
|
+
expect(router.dispatch).toHaveBeenCalledWith({
|
|
61
|
+
id: "ws123",
|
|
62
|
+
type: "websocket",
|
|
63
|
+
timestamp: 111,
|
|
64
|
+
sourceIp: "1.2.3.4",
|
|
65
|
+
message: "hello",
|
|
66
|
+
});
|
|
67
|
+
client.close();
|
|
68
|
+
resolve();
|
|
69
|
+
}, 50);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("ne plante pas si dispatch échoue", async () => {
|
|
75
|
+
router.dispatch.mockRejectedValue(new Error("fail"));
|
|
76
|
+
|
|
77
|
+
const client = new WebSocket(`ws://localhost:${port}`);
|
|
78
|
+
|
|
79
|
+
await new Promise<void>((resolve) => {
|
|
80
|
+
client.on("open", () => {
|
|
81
|
+
client.send("hello");
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
expect(router.dispatch).toHaveBeenCalledTimes(1);
|
|
84
|
+
client.close();
|
|
85
|
+
resolve();
|
|
86
|
+
}, 50);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export class WebSocketExtractor {
|
|
2
|
-
static extract(ws: any, req: any, message: string) {
|
|
3
|
-
const headers = req.headers ?? {};
|
|
4
|
-
|
|
5
|
-
return {
|
|
6
|
-
ip: req.socket?.remoteAddress ?? headers["x-forwarded-for"] ?? "",
|
|
7
|
-
message,
|
|
8
|
-
raw: { ws, req },
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
}
|
|
1
|
+
export class WebSocketExtractor {
|
|
2
|
+
static extract(ws: any, req: any, message: string) {
|
|
3
|
+
const headers = req.headers ?? {};
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
ip: req.socket?.remoteAddress ?? headers["x-forwarded-for"] ?? "",
|
|
7
|
+
message,
|
|
8
|
+
raw: { ws, req },
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|