@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
package/src/bootstrap.ts
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import { Logger } from "./core/logger";
|
|
2
|
-
import { StorageManager } from "./core/storage";
|
|
3
|
-
import { CoreRouter } from "./core/router";
|
|
4
|
-
import { CoreServer } from "./core/server";
|
|
5
|
-
|
|
6
|
-
// Listeners
|
|
7
|
-
import { ApiListener } from "./listeners/api/api.listener";
|
|
8
|
-
import { HttpListener } from "./listeners/http/http.listener";
|
|
9
|
-
import { DnsListener } from "./listeners/dns/dns.listener";
|
|
10
|
-
import { SmtpListener } from "./listeners/smtp/smtp.listener";
|
|
11
|
-
import { TcpListener } from "./listeners/tcp/tcp.listener";
|
|
12
|
-
|
|
13
|
-
async function main() {
|
|
14
|
-
const logger = new Logger({ context: "Bootstrap" });
|
|
15
|
-
|
|
16
|
-
// Core components
|
|
17
|
-
const storage = new StorageManager({
|
|
18
|
-
logger: logger.withContext("Storage"),
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const router = new CoreRouter(storage, {
|
|
22
|
-
logger: logger.withContext("CoreRouter"),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// ---------------------------
|
|
26
|
-
// LISTENERS
|
|
27
|
-
// ---------------------------
|
|
28
|
-
|
|
29
|
-
// API → (router, storage, options)
|
|
30
|
-
const apiListener = new ApiListener(storage, {
|
|
31
|
-
port: 3100,
|
|
32
|
-
logger: logger.withContext("ApiListener"),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// HTTP → (router, options)
|
|
36
|
-
const httpListener = new HttpListener(router, {
|
|
37
|
-
port: 8080,
|
|
38
|
-
logger: logger.withContext("HttpListener"),
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// DNS → (router, options)
|
|
42
|
-
const dnsListener = new DnsListener(router, {
|
|
43
|
-
server: {} as any,
|
|
44
|
-
logger: logger.withContext("DnsListener"),
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const smtpListener = new SmtpListener(router, {
|
|
48
|
-
server: {} as any,
|
|
49
|
-
logger: logger.withContext("SmtpListener"),
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// TCP → (router, storage, options)
|
|
53
|
-
const tcpListener = new TcpListener(router, storage, {
|
|
54
|
-
port: 9000,
|
|
55
|
-
logger: logger.withContext("TcpListener"),
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// ---------------------------
|
|
59
|
-
// CORE SERVER
|
|
60
|
-
// ---------------------------
|
|
61
|
-
const server = new CoreServer({
|
|
62
|
-
logger: logger.withContext("CoreServer"),
|
|
63
|
-
storage,
|
|
64
|
-
listeners: [
|
|
65
|
-
apiListener,
|
|
66
|
-
httpListener,
|
|
67
|
-
dnsListener,
|
|
68
|
-
smtpListener,
|
|
69
|
-
tcpListener,
|
|
70
|
-
],
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
await server.start();
|
|
74
|
-
|
|
75
|
-
// Graceful shutdown
|
|
76
|
-
const shutdown = async () => {
|
|
77
|
-
logger.warn("Received shutdown signal, stopping server...");
|
|
78
|
-
await server.stop();
|
|
79
|
-
process.exit(0);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
process.on("SIGINT", shutdown);
|
|
83
|
-
process.on("SIGTERM", shutdown);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
main().catch((err) => {
|
|
87
|
-
console.error("Fatal error in bootstrap:", err);
|
|
88
|
-
process.exit(1);
|
|
89
|
-
});
|
|
1
|
+
import { Logger } from "./core/logger";
|
|
2
|
+
import { StorageManager } from "./core/storage";
|
|
3
|
+
import { CoreRouter } from "./core/router";
|
|
4
|
+
import { CoreServer } from "./core/server";
|
|
5
|
+
|
|
6
|
+
// Listeners
|
|
7
|
+
import { ApiListener } from "./listeners/api/api.listener";
|
|
8
|
+
import { HttpListener } from "./listeners/http/http.listener";
|
|
9
|
+
import { DnsListener } from "./listeners/dns/dns.listener";
|
|
10
|
+
import { SmtpListener } from "./listeners/smtp/smtp.listener";
|
|
11
|
+
import { TcpListener } from "./listeners/tcp/tcp.listener";
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
const logger = new Logger({ context: "Bootstrap" });
|
|
15
|
+
|
|
16
|
+
// Core components
|
|
17
|
+
const storage = new StorageManager({
|
|
18
|
+
logger: logger.withContext("Storage"),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const router = new CoreRouter(storage, {
|
|
22
|
+
logger: logger.withContext("CoreRouter"),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// ---------------------------
|
|
26
|
+
// LISTENERS
|
|
27
|
+
// ---------------------------
|
|
28
|
+
|
|
29
|
+
// API → (router, storage, options)
|
|
30
|
+
const apiListener = new ApiListener(storage, {
|
|
31
|
+
port: 3100,
|
|
32
|
+
logger: logger.withContext("ApiListener"),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// HTTP → (router, options)
|
|
36
|
+
const httpListener = new HttpListener(router, {
|
|
37
|
+
port: 8080,
|
|
38
|
+
logger: logger.withContext("HttpListener"),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// DNS → (router, options)
|
|
42
|
+
const dnsListener = new DnsListener(router, {
|
|
43
|
+
server: {} as any,
|
|
44
|
+
logger: logger.withContext("DnsListener"),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const smtpListener = new SmtpListener(router, {
|
|
48
|
+
server: {} as any,
|
|
49
|
+
logger: logger.withContext("SmtpListener"),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// TCP → (router, storage, options)
|
|
53
|
+
const tcpListener = new TcpListener(router, storage, {
|
|
54
|
+
port: 9000,
|
|
55
|
+
logger: logger.withContext("TcpListener"),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// ---------------------------
|
|
59
|
+
// CORE SERVER
|
|
60
|
+
// ---------------------------
|
|
61
|
+
const server = new CoreServer({
|
|
62
|
+
logger: logger.withContext("CoreServer"),
|
|
63
|
+
storage,
|
|
64
|
+
listeners: [
|
|
65
|
+
apiListener,
|
|
66
|
+
httpListener,
|
|
67
|
+
dnsListener,
|
|
68
|
+
smtpListener,
|
|
69
|
+
tcpListener,
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await server.start();
|
|
74
|
+
|
|
75
|
+
// Graceful shutdown
|
|
76
|
+
const shutdown = async () => {
|
|
77
|
+
logger.warn("Received shutdown signal, stopping server...");
|
|
78
|
+
await server.stop();
|
|
79
|
+
process.exit(0);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
process.on("SIGINT", shutdown);
|
|
83
|
+
process.on("SIGTERM", shutdown);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
main().catch((err) => {
|
|
87
|
+
console.error("Fatal error in bootstrap:", err);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
});
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { CoreRouter, RouterHook } from "../router";
|
|
2
|
-
import { MemoryStorage } from "../../storage-adapters/adapters/memory.storage";
|
|
3
|
-
import { AnyNormalizedEvent } from "../../types/event.types";
|
|
4
|
-
import { describe, it, expect, jest } from "@jest/globals";
|
|
5
|
-
|
|
6
|
-
describe("CoreRouter", () => {
|
|
7
|
-
const event: AnyNormalizedEvent = {
|
|
8
|
-
id: "abc",
|
|
9
|
-
type: "http",
|
|
10
|
-
timestamp: 111,
|
|
11
|
-
sourceIp: "1.1.1.1",
|
|
12
|
-
request: {
|
|
13
|
-
method: "GET",
|
|
14
|
-
path: "/",
|
|
15
|
-
headers: {},
|
|
16
|
-
query: {},
|
|
17
|
-
body: {},
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
it("appelle les hooks", async () => {
|
|
22
|
-
const hook: RouterHook = jest.fn((e: AnyNormalizedEvent) => {}); // ← FIX
|
|
23
|
-
|
|
24
|
-
const router = new CoreRouter(new MemoryStorage(), { hooks: [hook] });
|
|
25
|
-
|
|
26
|
-
await router.dispatch(event);
|
|
27
|
-
|
|
28
|
-
expect(hook).toHaveBeenCalledWith(event);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
1
|
+
import { CoreRouter, RouterHook } from "../router";
|
|
2
|
+
import { MemoryStorage } from "../../storage-adapters/adapters/memory.storage";
|
|
3
|
+
import { AnyNormalizedEvent } from "../../types/event.types";
|
|
4
|
+
import { describe, it, expect, jest } from "@jest/globals";
|
|
5
|
+
|
|
6
|
+
describe("CoreRouter", () => {
|
|
7
|
+
const event: AnyNormalizedEvent = {
|
|
8
|
+
id: "abc",
|
|
9
|
+
type: "http",
|
|
10
|
+
timestamp: 111,
|
|
11
|
+
sourceIp: "1.1.1.1",
|
|
12
|
+
request: {
|
|
13
|
+
method: "GET",
|
|
14
|
+
path: "/",
|
|
15
|
+
headers: {},
|
|
16
|
+
query: {},
|
|
17
|
+
body: {},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
it("appelle les hooks", async () => {
|
|
22
|
+
const hook: RouterHook = jest.fn((e: AnyNormalizedEvent) => {}); // ← FIX
|
|
23
|
+
|
|
24
|
+
const router = new CoreRouter(new MemoryStorage(), { hooks: [hook] });
|
|
25
|
+
|
|
26
|
+
await router.dispatch(event);
|
|
27
|
+
|
|
28
|
+
expect(hook).toHaveBeenCalledWith(event);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { CoreServer } from "../../core/server";
|
|
2
|
-
import { StorageManager } from "../../core/storage";
|
|
3
|
-
import { Logger } from "../../core/logger";
|
|
4
|
-
import { describe, it, expect } from "@jest/globals";
|
|
5
|
-
|
|
6
|
-
class FakeListener {
|
|
7
|
-
started = false;
|
|
8
|
-
stopped = false;
|
|
9
|
-
|
|
10
|
-
async start() {
|
|
11
|
-
this.started = true;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async stop() {
|
|
15
|
-
this.stopped = true;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
describe("CoreServer", () => {
|
|
20
|
-
it("démarre et arrête les listeners", async () => {
|
|
21
|
-
const listener = new FakeListener();
|
|
22
|
-
|
|
23
|
-
const server = new CoreServer({
|
|
24
|
-
storage: new StorageManager(),
|
|
25
|
-
logger: new Logger({ enabled: false }),
|
|
26
|
-
listeners: [listener],
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
await server.start();
|
|
30
|
-
expect(listener.started).toBe(true);
|
|
31
|
-
|
|
32
|
-
await server.stop();
|
|
33
|
-
expect(listener.stopped).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("expose le router", () => {
|
|
37
|
-
const server = new CoreServer({
|
|
38
|
-
storage: new StorageManager(),
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const router = server.getRouter();
|
|
42
|
-
expect(router).toBeDefined();
|
|
43
|
-
});
|
|
44
|
-
});
|
|
1
|
+
import { CoreServer } from "../../core/server";
|
|
2
|
+
import { StorageManager } from "../../core/storage";
|
|
3
|
+
import { Logger } from "../../core/logger";
|
|
4
|
+
import { describe, it, expect } from "@jest/globals";
|
|
5
|
+
|
|
6
|
+
class FakeListener {
|
|
7
|
+
started = false;
|
|
8
|
+
stopped = false;
|
|
9
|
+
|
|
10
|
+
async start() {
|
|
11
|
+
this.started = true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async stop() {
|
|
15
|
+
this.stopped = true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("CoreServer", () => {
|
|
20
|
+
it("démarre et arrête les listeners", async () => {
|
|
21
|
+
const listener = new FakeListener();
|
|
22
|
+
|
|
23
|
+
const server = new CoreServer({
|
|
24
|
+
storage: new StorageManager(),
|
|
25
|
+
logger: new Logger({ enabled: false }),
|
|
26
|
+
listeners: [listener],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await server.start();
|
|
30
|
+
expect(listener.started).toBe(true);
|
|
31
|
+
|
|
32
|
+
await server.stop();
|
|
33
|
+
expect(listener.stopped).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("expose le router", () => {
|
|
37
|
+
const server = new CoreServer({
|
|
38
|
+
storage: new StorageManager(),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const router = server.getRouter();
|
|
42
|
+
expect(router).toBeDefined();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import { EventNormalizer } from "../event.normalizer";
|
|
2
|
-
import { describe, it, expect, jest } from "@jest/globals";
|
|
3
|
-
import { IdGenerator } from "../id-generator";
|
|
4
|
-
|
|
5
|
-
describe("EventNormalizer.normalizeHttp", () => {
|
|
6
|
-
it("normalise correctement une requête HTTP", () => {
|
|
7
|
-
// Mock du timestamp
|
|
8
|
-
const fakeNow = 1234567890;
|
|
9
|
-
jest.spyOn(Date, "now").mockReturnValue(fakeNow);
|
|
10
|
-
|
|
11
|
-
// Mock de l'ID
|
|
12
|
-
jest.spyOn(IdGenerator, "generate").mockReturnValue("uuid-test");
|
|
13
|
-
|
|
14
|
-
const req = {
|
|
15
|
-
ip: "9.9.9.9",
|
|
16
|
-
method: "POST",
|
|
17
|
-
path: "/test",
|
|
18
|
-
headers: { "x-forwarded-for": "9.9.9.9" },
|
|
19
|
-
query: { a: "1" },
|
|
20
|
-
body: { hello: "world" },
|
|
21
|
-
raw: {}, // obligatoire
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const event = EventNormalizer.normalizeHttp(req);
|
|
25
|
-
|
|
26
|
-
expect(event).toEqual({
|
|
27
|
-
id: "uuid-test",
|
|
28
|
-
type: "http",
|
|
29
|
-
timestamp: fakeNow,
|
|
30
|
-
sourceIp: "9.9.9.9",
|
|
31
|
-
request: {
|
|
32
|
-
method: "POST",
|
|
33
|
-
path: "/test",
|
|
34
|
-
headers: { "x-forwarded-for": "9.9.9.9" },
|
|
35
|
-
query: { a: "1" },
|
|
36
|
-
body: { hello: "world" },
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("retourne 'unknown' si aucune IP n'est trouvée", () => {
|
|
42
|
-
const req = {
|
|
43
|
-
ip: "",
|
|
44
|
-
method: "GET",
|
|
45
|
-
path: "/",
|
|
46
|
-
headers: {},
|
|
47
|
-
query: {},
|
|
48
|
-
body: {},
|
|
49
|
-
raw: {},
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const event = EventNormalizer.normalizeHttp(req);
|
|
53
|
-
|
|
54
|
-
expect(event.sourceIp).toBe("unknown");
|
|
55
|
-
});
|
|
56
|
-
});
|
|
1
|
+
import { EventNormalizer } from "../event.normalizer";
|
|
2
|
+
import { describe, it, expect, jest } from "@jest/globals";
|
|
3
|
+
import { IdGenerator } from "../id-generator";
|
|
4
|
+
|
|
5
|
+
describe("EventNormalizer.normalizeHttp", () => {
|
|
6
|
+
it("normalise correctement une requête HTTP", () => {
|
|
7
|
+
// Mock du timestamp
|
|
8
|
+
const fakeNow = 1234567890;
|
|
9
|
+
jest.spyOn(Date, "now").mockReturnValue(fakeNow);
|
|
10
|
+
|
|
11
|
+
// Mock de l'ID
|
|
12
|
+
jest.spyOn(IdGenerator, "generate").mockReturnValue("uuid-test");
|
|
13
|
+
|
|
14
|
+
const req = {
|
|
15
|
+
ip: "9.9.9.9",
|
|
16
|
+
method: "POST",
|
|
17
|
+
path: "/test",
|
|
18
|
+
headers: { "x-forwarded-for": "9.9.9.9" },
|
|
19
|
+
query: { a: "1" },
|
|
20
|
+
body: { hello: "world" },
|
|
21
|
+
raw: {}, // obligatoire
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const event = EventNormalizer.normalizeHttp(req);
|
|
25
|
+
|
|
26
|
+
expect(event).toEqual({
|
|
27
|
+
id: "uuid-test",
|
|
28
|
+
type: "http",
|
|
29
|
+
timestamp: fakeNow,
|
|
30
|
+
sourceIp: "9.9.9.9",
|
|
31
|
+
request: {
|
|
32
|
+
method: "POST",
|
|
33
|
+
path: "/test",
|
|
34
|
+
headers: { "x-forwarded-for": "9.9.9.9" },
|
|
35
|
+
query: { a: "1" },
|
|
36
|
+
body: { hello: "world" },
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("retourne 'unknown' si aucune IP n'est trouvée", () => {
|
|
42
|
+
const req = {
|
|
43
|
+
ip: "",
|
|
44
|
+
method: "GET",
|
|
45
|
+
path: "/",
|
|
46
|
+
headers: {},
|
|
47
|
+
query: {},
|
|
48
|
+
body: {},
|
|
49
|
+
raw: {},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const event = EventNormalizer.normalizeHttp(req);
|
|
53
|
+
|
|
54
|
+
expect(event.sourceIp).toBe("unknown");
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AnyNormalizedEvent,
|
|
3
|
-
NormalizedHttpEvent,
|
|
4
|
-
} from "../../types/event.types";
|
|
5
|
-
import {
|
|
6
|
-
StorageListParams,
|
|
7
|
-
Storage,
|
|
8
|
-
} from "../../storage-adapters/storage.interface";
|
|
9
|
-
import { EventRouter } from "../event.router";
|
|
10
|
-
import { EventNormalizer } from "../event.normalizer";
|
|
11
|
-
import { describe, it, expect, jest } from "@jest/globals";
|
|
12
|
-
|
|
13
|
-
class MockStorage implements Storage {
|
|
14
|
-
save = jest.fn<(event: AnyNormalizedEvent) => Promise<void>>();
|
|
15
|
-
getEvent = jest.fn<(id: string) => Promise<AnyNormalizedEvent | null>>();
|
|
16
|
-
listEvents =
|
|
17
|
-
jest.fn<(params: StorageListParams) => Promise<AnyNormalizedEvent[]>>();
|
|
18
|
-
deleteEvent = jest.fn<(id: string) => Promise<boolean>>();
|
|
19
|
-
clearEvents = jest.fn<() => Promise<void>>();
|
|
20
|
-
getStats =
|
|
21
|
-
jest.fn<() => Promise<{ total: number; byType: Record<string, number> }>>();
|
|
22
|
-
getAll = jest.fn<() => Promise<AnyNormalizedEvent[]>>();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
describe("EventRouter", () => {
|
|
26
|
-
it("enregistre un événement HTTP normalisé", async () => {
|
|
27
|
-
const mockStorage = new MockStorage();
|
|
28
|
-
|
|
29
|
-
const fakeEvent: NormalizedHttpEvent = {
|
|
30
|
-
id: "123",
|
|
31
|
-
type: "http",
|
|
32
|
-
timestamp: 111,
|
|
33
|
-
sourceIp: "1.1.1.1",
|
|
34
|
-
request: {
|
|
35
|
-
method: "GET",
|
|
36
|
-
path: "/",
|
|
37
|
-
headers: {},
|
|
38
|
-
query: {},
|
|
39
|
-
body: {},
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
jest.spyOn(EventNormalizer, "normalizeHttp").mockReturnValue(fakeEvent);
|
|
44
|
-
|
|
45
|
-
const router = new EventRouter(mockStorage);
|
|
46
|
-
|
|
47
|
-
const req = {
|
|
48
|
-
ip: "1.1.1.1",
|
|
49
|
-
method: "GET",
|
|
50
|
-
path: "/",
|
|
51
|
-
headers: {},
|
|
52
|
-
query: {},
|
|
53
|
-
body: {},
|
|
54
|
-
raw: {},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const result = await router.handleHttp(req);
|
|
58
|
-
|
|
59
|
-
expect(EventNormalizer.normalizeHttp).toHaveBeenCalledWith(req);
|
|
60
|
-
expect(mockStorage.save).toHaveBeenCalledWith(fakeEvent);
|
|
61
|
-
expect(result).toEqual(fakeEvent);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("propagate une erreur si normalizeHttp throw", async () => {
|
|
65
|
-
const mockStorage = new MockStorage();
|
|
66
|
-
|
|
67
|
-
jest.spyOn(EventNormalizer, "normalizeHttp").mockImplementation(() => {
|
|
68
|
-
throw new Error("Boom");
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const router = new EventRouter(mockStorage);
|
|
72
|
-
|
|
73
|
-
await expect(router.handleHttp({} as any)).rejects.toThrow("Boom");
|
|
74
|
-
expect(mockStorage.save).not.toHaveBeenCalled();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("propagate une erreur si storage.save throw", async () => {
|
|
78
|
-
const mockStorage = new MockStorage();
|
|
79
|
-
|
|
80
|
-
const fakeEvent = { id: "x", type: "http" } as any;
|
|
81
|
-
|
|
82
|
-
jest.spyOn(EventNormalizer, "normalizeHttp").mockReturnValue(fakeEvent);
|
|
83
|
-
mockStorage.save.mockRejectedValue(new Error("DB error"));
|
|
84
|
-
|
|
85
|
-
const router = new EventRouter(mockStorage);
|
|
86
|
-
|
|
87
|
-
await expect(router.handleHttp({} as any)).rejects.toThrow("DB error");
|
|
88
|
-
});
|
|
89
|
-
});
|
|
1
|
+
import {
|
|
2
|
+
AnyNormalizedEvent,
|
|
3
|
+
NormalizedHttpEvent,
|
|
4
|
+
} from "../../types/event.types";
|
|
5
|
+
import {
|
|
6
|
+
StorageListParams,
|
|
7
|
+
Storage,
|
|
8
|
+
} from "../../storage-adapters/storage.interface";
|
|
9
|
+
import { EventRouter } from "../event.router";
|
|
10
|
+
import { EventNormalizer } from "../event.normalizer";
|
|
11
|
+
import { describe, it, expect, jest } from "@jest/globals";
|
|
12
|
+
|
|
13
|
+
class MockStorage implements Storage {
|
|
14
|
+
save = jest.fn<(event: AnyNormalizedEvent) => Promise<void>>();
|
|
15
|
+
getEvent = jest.fn<(id: string) => Promise<AnyNormalizedEvent | null>>();
|
|
16
|
+
listEvents =
|
|
17
|
+
jest.fn<(params: StorageListParams) => Promise<AnyNormalizedEvent[]>>();
|
|
18
|
+
deleteEvent = jest.fn<(id: string) => Promise<boolean>>();
|
|
19
|
+
clearEvents = jest.fn<() => Promise<void>>();
|
|
20
|
+
getStats =
|
|
21
|
+
jest.fn<() => Promise<{ total: number; byType: Record<string, number> }>>();
|
|
22
|
+
getAll = jest.fn<() => Promise<AnyNormalizedEvent[]>>();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe("EventRouter", () => {
|
|
26
|
+
it("enregistre un événement HTTP normalisé", async () => {
|
|
27
|
+
const mockStorage = new MockStorage();
|
|
28
|
+
|
|
29
|
+
const fakeEvent: NormalizedHttpEvent = {
|
|
30
|
+
id: "123",
|
|
31
|
+
type: "http",
|
|
32
|
+
timestamp: 111,
|
|
33
|
+
sourceIp: "1.1.1.1",
|
|
34
|
+
request: {
|
|
35
|
+
method: "GET",
|
|
36
|
+
path: "/",
|
|
37
|
+
headers: {},
|
|
38
|
+
query: {},
|
|
39
|
+
body: {},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
jest.spyOn(EventNormalizer, "normalizeHttp").mockReturnValue(fakeEvent);
|
|
44
|
+
|
|
45
|
+
const router = new EventRouter(mockStorage);
|
|
46
|
+
|
|
47
|
+
const req = {
|
|
48
|
+
ip: "1.1.1.1",
|
|
49
|
+
method: "GET",
|
|
50
|
+
path: "/",
|
|
51
|
+
headers: {},
|
|
52
|
+
query: {},
|
|
53
|
+
body: {},
|
|
54
|
+
raw: {},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const result = await router.handleHttp(req);
|
|
58
|
+
|
|
59
|
+
expect(EventNormalizer.normalizeHttp).toHaveBeenCalledWith(req);
|
|
60
|
+
expect(mockStorage.save).toHaveBeenCalledWith(fakeEvent);
|
|
61
|
+
expect(result).toEqual(fakeEvent);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("propagate une erreur si normalizeHttp throw", async () => {
|
|
65
|
+
const mockStorage = new MockStorage();
|
|
66
|
+
|
|
67
|
+
jest.spyOn(EventNormalizer, "normalizeHttp").mockImplementation(() => {
|
|
68
|
+
throw new Error("Boom");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const router = new EventRouter(mockStorage);
|
|
72
|
+
|
|
73
|
+
await expect(router.handleHttp({} as any)).rejects.toThrow("Boom");
|
|
74
|
+
expect(mockStorage.save).not.toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("propagate une erreur si storage.save throw", async () => {
|
|
78
|
+
const mockStorage = new MockStorage();
|
|
79
|
+
|
|
80
|
+
const fakeEvent = { id: "x", type: "http" } as any;
|
|
81
|
+
|
|
82
|
+
jest.spyOn(EventNormalizer, "normalizeHttp").mockReturnValue(fakeEvent);
|
|
83
|
+
mockStorage.save.mockRejectedValue(new Error("DB error"));
|
|
84
|
+
|
|
85
|
+
const router = new EventRouter(mockStorage);
|
|
86
|
+
|
|
87
|
+
await expect(router.handleHttp({} as any)).rejects.toThrow("DB error");
|
|
88
|
+
});
|
|
89
|
+
});
|