@j3r3mcdev/oast-server 1.1.6 → 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/dist/index.d.ts +1 -0
- package/dist/index.js +16 -1
- 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 -21
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { Logger, LogEntry } from "../../core/logger";
|
|
2
|
-
import { describe, it, expect, jest } from "@jest/globals";
|
|
3
|
-
|
|
4
|
-
describe("Logger", () => {
|
|
5
|
-
it("appelle les hooks", () => {
|
|
6
|
-
const hook = jest.fn<(entry: LogEntry) => void>();
|
|
7
|
-
const logger = new Logger({ hooks: [hook], enabled: true });
|
|
8
|
-
|
|
9
|
-
logger.info("hello");
|
|
10
|
-
|
|
11
|
-
expect(hook).toHaveBeenCalled();
|
|
12
|
-
expect(hook.mock.calls[0][0].message).toBe("hello");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("respecte le niveau de logs", () => {
|
|
16
|
-
const hook = jest.fn<(entry: LogEntry) => void>();
|
|
17
|
-
const logger = new Logger({ level: "warn", hooks: [hook] });
|
|
18
|
-
|
|
19
|
-
logger.info("should not log");
|
|
20
|
-
logger.error("should log");
|
|
21
|
-
|
|
22
|
-
expect(hook).toHaveBeenCalledTimes(1);
|
|
23
|
-
expect(hook.mock.calls[0][0].level).toBe("error");
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("crée un logger enfant avec contexte", () => {
|
|
27
|
-
const logger = new Logger({ context: "root" });
|
|
28
|
-
const child = logger.withContext("child");
|
|
29
|
-
|
|
30
|
-
expect(child).not.toBe(logger);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
1
|
+
import { Logger, LogEntry } from "../../core/logger";
|
|
2
|
+
import { describe, it, expect, jest } from "@jest/globals";
|
|
3
|
+
|
|
4
|
+
describe("Logger", () => {
|
|
5
|
+
it("appelle les hooks", () => {
|
|
6
|
+
const hook = jest.fn<(entry: LogEntry) => void>();
|
|
7
|
+
const logger = new Logger({ hooks: [hook], enabled: true });
|
|
8
|
+
|
|
9
|
+
logger.info("hello");
|
|
10
|
+
|
|
11
|
+
expect(hook).toHaveBeenCalled();
|
|
12
|
+
expect(hook.mock.calls[0][0].message).toBe("hello");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("respecte le niveau de logs", () => {
|
|
16
|
+
const hook = jest.fn<(entry: LogEntry) => void>();
|
|
17
|
+
const logger = new Logger({ level: "warn", hooks: [hook] });
|
|
18
|
+
|
|
19
|
+
logger.info("should not log");
|
|
20
|
+
logger.error("should log");
|
|
21
|
+
|
|
22
|
+
expect(hook).toHaveBeenCalledTimes(1);
|
|
23
|
+
expect(hook.mock.calls[0][0].level).toBe("error");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("crée un logger enfant avec contexte", () => {
|
|
27
|
+
const logger = new Logger({ context: "root" });
|
|
28
|
+
const child = logger.withContext("child");
|
|
29
|
+
|
|
30
|
+
expect(child).not.toBe(logger);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
import { describe, test, expect } from "@jest/globals";
|
|
2
|
-
import { StorageManager } from "../storage"; // si ton fichier s'appelle storage-manager.ts
|
|
3
|
-
import { NormalizedHttpEvent } from "../../types/event.types";
|
|
4
|
-
|
|
5
|
-
function makeHttpEvent(id: string): NormalizedHttpEvent {
|
|
6
|
-
return {
|
|
7
|
-
id,
|
|
8
|
-
type: "http",
|
|
9
|
-
timestamp: Date.now(),
|
|
10
|
-
sourceIp: "127.0.0.1",
|
|
11
|
-
request: {
|
|
12
|
-
method: "GET",
|
|
13
|
-
path: "/",
|
|
14
|
-
headers: {},
|
|
15
|
-
query: {},
|
|
16
|
-
body: "",
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe("StorageManager", () => {
|
|
22
|
-
test("save + getEvent", async () => {
|
|
23
|
-
const storage = new StorageManager();
|
|
24
|
-
|
|
25
|
-
const event = makeHttpEvent("1");
|
|
26
|
-
await storage.save(event);
|
|
27
|
-
|
|
28
|
-
const found = await storage.getEvent("1");
|
|
29
|
-
expect(found).not.toBeNull();
|
|
30
|
-
expect(found?.id).toBe("1");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("listEvents returns events", async () => {
|
|
34
|
-
const storage = new StorageManager();
|
|
35
|
-
|
|
36
|
-
await storage.save(makeHttpEvent("1"));
|
|
37
|
-
|
|
38
|
-
const list = await storage.listEvents({});
|
|
39
|
-
expect(list.length).toBe(1);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test("deleteEvent removes event", async () => {
|
|
43
|
-
const storage = new StorageManager();
|
|
44
|
-
|
|
45
|
-
await storage.save(makeHttpEvent("1"));
|
|
46
|
-
|
|
47
|
-
let list = await storage.listEvents({});
|
|
48
|
-
expect(list.length).toBe(1);
|
|
49
|
-
|
|
50
|
-
await storage.deleteEvent("1");
|
|
51
|
-
|
|
52
|
-
list = await storage.listEvents({});
|
|
53
|
-
expect(list.length).toBe(0);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("clearEvents empties storage", async () => {
|
|
57
|
-
const storage = new StorageManager();
|
|
58
|
-
|
|
59
|
-
await storage.save(makeHttpEvent("1"));
|
|
60
|
-
await storage.clearEvents();
|
|
61
|
-
|
|
62
|
-
const list = await storage.listEvents({});
|
|
63
|
-
expect(list.length).toBe(0);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("getStats returns correct structure", async () => {
|
|
67
|
-
const storage = new StorageManager();
|
|
68
|
-
|
|
69
|
-
const stats = await storage.getStats();
|
|
70
|
-
|
|
71
|
-
expect(stats.total).toBe(0);
|
|
72
|
-
expect(stats.byType).toEqual({});
|
|
73
|
-
});
|
|
74
|
-
});
|
|
1
|
+
import { describe, test, expect } from "@jest/globals";
|
|
2
|
+
import { StorageManager } from "../storage"; // si ton fichier s'appelle storage-manager.ts
|
|
3
|
+
import { NormalizedHttpEvent } from "../../types/event.types";
|
|
4
|
+
|
|
5
|
+
function makeHttpEvent(id: string): NormalizedHttpEvent {
|
|
6
|
+
return {
|
|
7
|
+
id,
|
|
8
|
+
type: "http",
|
|
9
|
+
timestamp: Date.now(),
|
|
10
|
+
sourceIp: "127.0.0.1",
|
|
11
|
+
request: {
|
|
12
|
+
method: "GET",
|
|
13
|
+
path: "/",
|
|
14
|
+
headers: {},
|
|
15
|
+
query: {},
|
|
16
|
+
body: "",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("StorageManager", () => {
|
|
22
|
+
test("save + getEvent", async () => {
|
|
23
|
+
const storage = new StorageManager();
|
|
24
|
+
|
|
25
|
+
const event = makeHttpEvent("1");
|
|
26
|
+
await storage.save(event);
|
|
27
|
+
|
|
28
|
+
const found = await storage.getEvent("1");
|
|
29
|
+
expect(found).not.toBeNull();
|
|
30
|
+
expect(found?.id).toBe("1");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("listEvents returns events", async () => {
|
|
34
|
+
const storage = new StorageManager();
|
|
35
|
+
|
|
36
|
+
await storage.save(makeHttpEvent("1"));
|
|
37
|
+
|
|
38
|
+
const list = await storage.listEvents({});
|
|
39
|
+
expect(list.length).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("deleteEvent removes event", async () => {
|
|
43
|
+
const storage = new StorageManager();
|
|
44
|
+
|
|
45
|
+
await storage.save(makeHttpEvent("1"));
|
|
46
|
+
|
|
47
|
+
let list = await storage.listEvents({});
|
|
48
|
+
expect(list.length).toBe(1);
|
|
49
|
+
|
|
50
|
+
await storage.deleteEvent("1");
|
|
51
|
+
|
|
52
|
+
list = await storage.listEvents({});
|
|
53
|
+
expect(list.length).toBe(0);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("clearEvents empties storage", async () => {
|
|
57
|
+
const storage = new StorageManager();
|
|
58
|
+
|
|
59
|
+
await storage.save(makeHttpEvent("1"));
|
|
60
|
+
await storage.clearEvents();
|
|
61
|
+
|
|
62
|
+
const list = await storage.listEvents({});
|
|
63
|
+
expect(list.length).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("getStats returns correct structure", async () => {
|
|
67
|
+
const storage = new StorageManager();
|
|
68
|
+
|
|
69
|
+
const stats = await storage.getStats();
|
|
70
|
+
|
|
71
|
+
expect(stats.total).toBe(0);
|
|
72
|
+
expect(stats.byType).toEqual({});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RawEvent,
|
|
3
|
-
RawDnsEvent,
|
|
4
|
-
RawSmtpEvent,
|
|
5
|
-
RawTcpEvent,
|
|
6
|
-
RawSsrfEvent,
|
|
7
|
-
NormalizedHttpEvent,
|
|
8
|
-
NormalizedDnsEvent,
|
|
9
|
-
NormalizedSmtpEvent,
|
|
10
|
-
NormalizedTcpEvent,
|
|
11
|
-
NormalizedSsrfEvent,
|
|
12
|
-
NormalizedWebhookEvent,
|
|
13
|
-
RawWebhookEvent,
|
|
14
|
-
NormalizedWebSocketEvent,
|
|
15
|
-
RawWebSocketEvent,
|
|
16
|
-
} from "../types/event.types";
|
|
17
|
-
|
|
18
|
-
import { IdGenerator } from "./id-generator";
|
|
19
|
-
|
|
20
|
-
export class EventNormalizer {
|
|
21
|
-
//
|
|
22
|
-
// -------------------------
|
|
23
|
-
// DNS
|
|
24
|
-
// -------------------------
|
|
25
|
-
//
|
|
26
|
-
static normalizeDns(event: RawDnsEvent): NormalizedDnsEvent {
|
|
27
|
-
return {
|
|
28
|
-
id: IdGenerator.generate(),
|
|
29
|
-
type: "dns",
|
|
30
|
-
timestamp: Date.now(),
|
|
31
|
-
ip: event.ip ?? "",
|
|
32
|
-
query: event.query ?? "",
|
|
33
|
-
recordType: event.recordType ?? "",
|
|
34
|
-
raw: event.raw,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
// -------------------------
|
|
40
|
-
// HTTP
|
|
41
|
-
// -------------------------
|
|
42
|
-
//
|
|
43
|
-
static normalizeHttp(event: RawEvent): NormalizedHttpEvent {
|
|
44
|
-
const sourceIp = event.ip && event.ip.trim() !== "" ? event.ip : "unknown";
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
id: IdGenerator.generate(),
|
|
48
|
-
type: "http",
|
|
49
|
-
timestamp: Date.now(),
|
|
50
|
-
sourceIp,
|
|
51
|
-
request: {
|
|
52
|
-
method: event.method,
|
|
53
|
-
path: event.path,
|
|
54
|
-
headers: event.headers,
|
|
55
|
-
query: event.query,
|
|
56
|
-
body: event.body,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
// -------------------------
|
|
63
|
-
// SMTP
|
|
64
|
-
// -------------------------
|
|
65
|
-
//
|
|
66
|
-
static normalizeSmtp(event: RawSmtpEvent): NormalizedSmtpEvent {
|
|
67
|
-
return {
|
|
68
|
-
id: IdGenerator.generate(),
|
|
69
|
-
type: "smtp",
|
|
70
|
-
timestamp: Date.now(),
|
|
71
|
-
ip: event.ip ?? "",
|
|
72
|
-
from: event.from ?? "",
|
|
73
|
-
to: event.to ?? [],
|
|
74
|
-
subject: event.subject ?? "",
|
|
75
|
-
body: event.body ?? "",
|
|
76
|
-
raw: event.raw,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
// -------------------------
|
|
82
|
-
// TCP
|
|
83
|
-
// -------------------------
|
|
84
|
-
//
|
|
85
|
-
static normalizeTcp(event: RawTcpEvent): NormalizedTcpEvent {
|
|
86
|
-
return {
|
|
87
|
-
id: IdGenerator.generate(),
|
|
88
|
-
type: "tcp",
|
|
89
|
-
timestamp: Date.now(),
|
|
90
|
-
ip: event.ip ?? "",
|
|
91
|
-
port: event.port ?? 0,
|
|
92
|
-
data: event.data ?? "",
|
|
93
|
-
raw: event.raw,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
// -------------------------
|
|
99
|
-
// SSRF
|
|
100
|
-
// -------------------------
|
|
101
|
-
//
|
|
102
|
-
static normalizeSsrf(raw: RawSsrfEvent): NormalizedSsrfEvent {
|
|
103
|
-
return {
|
|
104
|
-
id: IdGenerator.generate(),
|
|
105
|
-
type: "ssrf",
|
|
106
|
-
timestamp: Date.now(),
|
|
107
|
-
sourceIp: raw.ip,
|
|
108
|
-
request: {
|
|
109
|
-
method: raw.method,
|
|
110
|
-
path: raw.path,
|
|
111
|
-
headers: raw.headers,
|
|
112
|
-
query: raw.query,
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
//
|
|
118
|
-
// -------------------------
|
|
119
|
-
// webhook
|
|
120
|
-
// -------------------------
|
|
121
|
-
//
|
|
122
|
-
static normalizeWebhook(raw: RawWebhookEvent): NormalizedWebhookEvent {
|
|
123
|
-
return {
|
|
124
|
-
id: IdGenerator.generate(),
|
|
125
|
-
type: "webhook",
|
|
126
|
-
timestamp: Date.now(),
|
|
127
|
-
sourceIp: raw.ip,
|
|
128
|
-
headers: raw.headers,
|
|
129
|
-
body: raw.body,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
// -------------------------
|
|
135
|
-
// websocket
|
|
136
|
-
// -------------------------
|
|
137
|
-
//
|
|
138
|
-
static normalizeWebSocket(raw: RawWebSocketEvent): NormalizedWebSocketEvent {
|
|
139
|
-
return {
|
|
140
|
-
id: IdGenerator.generate(),
|
|
141
|
-
type: "websocket",
|
|
142
|
-
timestamp: Date.now(),
|
|
143
|
-
sourceIp: raw.ip,
|
|
144
|
-
message: raw.message,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
RawEvent,
|
|
3
|
+
RawDnsEvent,
|
|
4
|
+
RawSmtpEvent,
|
|
5
|
+
RawTcpEvent,
|
|
6
|
+
RawSsrfEvent,
|
|
7
|
+
NormalizedHttpEvent,
|
|
8
|
+
NormalizedDnsEvent,
|
|
9
|
+
NormalizedSmtpEvent,
|
|
10
|
+
NormalizedTcpEvent,
|
|
11
|
+
NormalizedSsrfEvent,
|
|
12
|
+
NormalizedWebhookEvent,
|
|
13
|
+
RawWebhookEvent,
|
|
14
|
+
NormalizedWebSocketEvent,
|
|
15
|
+
RawWebSocketEvent,
|
|
16
|
+
} from "../types/event.types";
|
|
17
|
+
|
|
18
|
+
import { IdGenerator } from "./id-generator";
|
|
19
|
+
|
|
20
|
+
export class EventNormalizer {
|
|
21
|
+
//
|
|
22
|
+
// -------------------------
|
|
23
|
+
// DNS
|
|
24
|
+
// -------------------------
|
|
25
|
+
//
|
|
26
|
+
static normalizeDns(event: RawDnsEvent): NormalizedDnsEvent {
|
|
27
|
+
return {
|
|
28
|
+
id: IdGenerator.generate(),
|
|
29
|
+
type: "dns",
|
|
30
|
+
timestamp: Date.now(),
|
|
31
|
+
ip: event.ip ?? "",
|
|
32
|
+
query: event.query ?? "",
|
|
33
|
+
recordType: event.recordType ?? "",
|
|
34
|
+
raw: event.raw,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//
|
|
39
|
+
// -------------------------
|
|
40
|
+
// HTTP
|
|
41
|
+
// -------------------------
|
|
42
|
+
//
|
|
43
|
+
static normalizeHttp(event: RawEvent): NormalizedHttpEvent {
|
|
44
|
+
const sourceIp = event.ip && event.ip.trim() !== "" ? event.ip : "unknown";
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
id: IdGenerator.generate(),
|
|
48
|
+
type: "http",
|
|
49
|
+
timestamp: Date.now(),
|
|
50
|
+
sourceIp,
|
|
51
|
+
request: {
|
|
52
|
+
method: event.method,
|
|
53
|
+
path: event.path,
|
|
54
|
+
headers: event.headers,
|
|
55
|
+
query: event.query,
|
|
56
|
+
body: event.body,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//
|
|
62
|
+
// -------------------------
|
|
63
|
+
// SMTP
|
|
64
|
+
// -------------------------
|
|
65
|
+
//
|
|
66
|
+
static normalizeSmtp(event: RawSmtpEvent): NormalizedSmtpEvent {
|
|
67
|
+
return {
|
|
68
|
+
id: IdGenerator.generate(),
|
|
69
|
+
type: "smtp",
|
|
70
|
+
timestamp: Date.now(),
|
|
71
|
+
ip: event.ip ?? "",
|
|
72
|
+
from: event.from ?? "",
|
|
73
|
+
to: event.to ?? [],
|
|
74
|
+
subject: event.subject ?? "",
|
|
75
|
+
body: event.body ?? "",
|
|
76
|
+
raw: event.raw,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//
|
|
81
|
+
// -------------------------
|
|
82
|
+
// TCP
|
|
83
|
+
// -------------------------
|
|
84
|
+
//
|
|
85
|
+
static normalizeTcp(event: RawTcpEvent): NormalizedTcpEvent {
|
|
86
|
+
return {
|
|
87
|
+
id: IdGenerator.generate(),
|
|
88
|
+
type: "tcp",
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
ip: event.ip ?? "",
|
|
91
|
+
port: event.port ?? 0,
|
|
92
|
+
data: event.data ?? "",
|
|
93
|
+
raw: event.raw,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//
|
|
98
|
+
// -------------------------
|
|
99
|
+
// SSRF
|
|
100
|
+
// -------------------------
|
|
101
|
+
//
|
|
102
|
+
static normalizeSsrf(raw: RawSsrfEvent): NormalizedSsrfEvent {
|
|
103
|
+
return {
|
|
104
|
+
id: IdGenerator.generate(),
|
|
105
|
+
type: "ssrf",
|
|
106
|
+
timestamp: Date.now(),
|
|
107
|
+
sourceIp: raw.ip,
|
|
108
|
+
request: {
|
|
109
|
+
method: raw.method,
|
|
110
|
+
path: raw.path,
|
|
111
|
+
headers: raw.headers,
|
|
112
|
+
query: raw.query,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//
|
|
118
|
+
// -------------------------
|
|
119
|
+
// webhook
|
|
120
|
+
// -------------------------
|
|
121
|
+
//
|
|
122
|
+
static normalizeWebhook(raw: RawWebhookEvent): NormalizedWebhookEvent {
|
|
123
|
+
return {
|
|
124
|
+
id: IdGenerator.generate(),
|
|
125
|
+
type: "webhook",
|
|
126
|
+
timestamp: Date.now(),
|
|
127
|
+
sourceIp: raw.ip,
|
|
128
|
+
headers: raw.headers,
|
|
129
|
+
body: raw.body,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//
|
|
134
|
+
// -------------------------
|
|
135
|
+
// websocket
|
|
136
|
+
// -------------------------
|
|
137
|
+
//
|
|
138
|
+
static normalizeWebSocket(raw: RawWebSocketEvent): NormalizedWebSocketEvent {
|
|
139
|
+
return {
|
|
140
|
+
id: IdGenerator.generate(),
|
|
141
|
+
type: "websocket",
|
|
142
|
+
timestamp: Date.now(),
|
|
143
|
+
sourceIp: raw.ip,
|
|
144
|
+
message: raw.message,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
package/src/core/event.router.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { EventNormalizer } from "./event.normalizer";
|
|
2
|
-
import { Storage } from "../storage-adapters/storage.interface";
|
|
3
|
-
import { RawEvent, NormalizedHttpEvent } from "../types/event.types";
|
|
4
|
-
|
|
5
|
-
export class EventRouter {
|
|
6
|
-
constructor(private storage: Storage) {}
|
|
7
|
-
|
|
8
|
-
async handleHttp(event: RawEvent): Promise<NormalizedHttpEvent> {
|
|
9
|
-
const normalized = EventNormalizer.normalizeHttp(event);
|
|
10
|
-
await this.storage.save(normalized);
|
|
11
|
-
return normalized;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
1
|
+
import { EventNormalizer } from "./event.normalizer";
|
|
2
|
+
import { Storage } from "../storage-adapters/storage.interface";
|
|
3
|
+
import { RawEvent, NormalizedHttpEvent } from "../types/event.types";
|
|
4
|
+
|
|
5
|
+
export class EventRouter {
|
|
6
|
+
constructor(private storage: Storage) {}
|
|
7
|
+
|
|
8
|
+
async handleHttp(event: RawEvent): Promise<NormalizedHttpEvent> {
|
|
9
|
+
const normalized = EventNormalizer.normalizeHttp(event);
|
|
10
|
+
await this.storage.save(normalized);
|
|
11
|
+
return normalized;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import { NodeAdapter } from "../adapter-node";
|
|
2
|
-
import { MiddlewarePipeline } from "../middleware";
|
|
3
|
-
import { Router } from "../router";
|
|
4
|
-
import { Request } from "../request";
|
|
5
|
-
import { Response } from "../response";
|
|
6
|
-
import { describe, it, expect, jest } from "@jest/globals";
|
|
7
|
-
import * as Build from "../buildRequest";
|
|
8
|
-
|
|
9
|
-
describe("NodeAdapter.handle", () => {
|
|
10
|
-
it("appelle le handler quand la route match", async () => {
|
|
11
|
-
const router = new Router();
|
|
12
|
-
const pipeline = new MiddlewarePipeline();
|
|
13
|
-
|
|
14
|
-
// mock buildRequest
|
|
15
|
-
const buildRequestMock = jest
|
|
16
|
-
.spyOn(Build, "buildRequest")
|
|
17
|
-
.mockImplementation(
|
|
18
|
-
(raw: any, params?: Record<string, string>) =>
|
|
19
|
-
new Request({
|
|
20
|
-
method: "GET",
|
|
21
|
-
path: "/test",
|
|
22
|
-
headers: {},
|
|
23
|
-
params: params ?? {},
|
|
24
|
-
}),
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const handler = jest.fn();
|
|
28
|
-
|
|
29
|
-
router.match = jest.fn(() => ({
|
|
30
|
-
handler,
|
|
31
|
-
params: { id: "42" },
|
|
32
|
-
middlewares: [],
|
|
33
|
-
})) as any;
|
|
34
|
-
|
|
35
|
-
pipeline.run = jest.fn(async () => {}) as any;
|
|
36
|
-
|
|
37
|
-
const res = {
|
|
38
|
-
writableEnded: false,
|
|
39
|
-
setHeader: jest.fn(),
|
|
40
|
-
end: jest.fn(),
|
|
41
|
-
statusCode: 200,
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const adapter = new NodeAdapter(router, pipeline);
|
|
45
|
-
|
|
46
|
-
await adapter.handle({ url: "/test", method: "GET", headers: {} }, res);
|
|
47
|
-
|
|
48
|
-
expect(handler).toHaveBeenCalled();
|
|
49
|
-
expect(pipeline.run).toHaveBeenCalled();
|
|
50
|
-
expect(buildRequestMock).toHaveBeenCalledTimes(2);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
1
|
+
import { NodeAdapter } from "../adapter-node";
|
|
2
|
+
import { MiddlewarePipeline } from "../middleware";
|
|
3
|
+
import { Router } from "../router";
|
|
4
|
+
import { Request } from "../request";
|
|
5
|
+
import { Response } from "../response";
|
|
6
|
+
import { describe, it, expect, jest } from "@jest/globals";
|
|
7
|
+
import * as Build from "../buildRequest";
|
|
8
|
+
|
|
9
|
+
describe("NodeAdapter.handle", () => {
|
|
10
|
+
it("appelle le handler quand la route match", async () => {
|
|
11
|
+
const router = new Router();
|
|
12
|
+
const pipeline = new MiddlewarePipeline();
|
|
13
|
+
|
|
14
|
+
// mock buildRequest
|
|
15
|
+
const buildRequestMock = jest
|
|
16
|
+
.spyOn(Build, "buildRequest")
|
|
17
|
+
.mockImplementation(
|
|
18
|
+
(raw: any, params?: Record<string, string>) =>
|
|
19
|
+
new Request({
|
|
20
|
+
method: "GET",
|
|
21
|
+
path: "/test",
|
|
22
|
+
headers: {},
|
|
23
|
+
params: params ?? {},
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const handler = jest.fn();
|
|
28
|
+
|
|
29
|
+
router.match = jest.fn(() => ({
|
|
30
|
+
handler,
|
|
31
|
+
params: { id: "42" },
|
|
32
|
+
middlewares: [],
|
|
33
|
+
})) as any;
|
|
34
|
+
|
|
35
|
+
pipeline.run = jest.fn(async () => {}) as any;
|
|
36
|
+
|
|
37
|
+
const res = {
|
|
38
|
+
writableEnded: false,
|
|
39
|
+
setHeader: jest.fn(),
|
|
40
|
+
end: jest.fn(),
|
|
41
|
+
statusCode: 200,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const adapter = new NodeAdapter(router, pipeline);
|
|
45
|
+
|
|
46
|
+
await adapter.handle({ url: "/test", method: "GET", headers: {} }, res);
|
|
47
|
+
|
|
48
|
+
expect(handler).toHaveBeenCalled();
|
|
49
|
+
expect(pipeline.run).toHaveBeenCalled();
|
|
50
|
+
expect(buildRequestMock).toHaveBeenCalledTimes(2);
|
|
51
|
+
});
|
|
52
|
+
});
|