@j3r3mcdev/oast-server 1.0.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.
- package/.env.example +0 -0
- package/.github/workflows/ci.yml +29 -0
- package/.github/workflows/publish.yml +31 -0
- package/README.md +192 -0
- package/dist/api/controllers/__tests__/tasks.controller.test.js +61 -0
- package/dist/api/controllers/events.controller.js +13 -0
- package/dist/api/controllers/health.controller.js +11 -0
- package/dist/api/controllers/index.js +1 -0
- package/dist/api/controllers/tasks.controller.js +35 -0
- package/dist/api/dto/__tests__/create-task.dto.test.js +33 -0
- package/dist/api/dto/__tests__/filter-tasks.dto.test.js +28 -0
- package/dist/api/dto/create-task.dto.js +26 -0
- package/dist/api/dto/filter-tasks.dto.js +27 -0
- package/dist/api/services/__tests__/events.service.test.js +25 -0
- package/dist/api/services/__tests__/tasks.service.test.js +25 -0
- package/dist/api/services/events.service.js +18 -0
- package/dist/api/services/tasks.service.js +52 -0
- package/dist/api/sse/events.stream.js +63 -0
- package/dist/config/constants.js +1 -0
- package/dist/config/env.js +1 -0
- package/dist/core/__tests__/core-router.test.js +26 -0
- package/dist/core/__tests__/core-server.test.js +39 -0
- package/dist/core/__tests__/event.normalizer.test.js +50 -0
- package/dist/core/__tests__/event.router.test.js +66 -0
- package/dist/core/__tests__/logger.test.js +26 -0
- package/dist/core/__tests__/storage-manager.test.js +57 -0
- package/dist/core/event.normalizer.js +126 -0
- package/dist/core/event.router.js +15 -0
- package/dist/core/http/__tests__/adapter-node.test.js +74 -0
- package/dist/core/http/__tests__/body-parser-multipart.test.js +35 -0
- package/dist/core/http/__tests__/body-parser-raw.test.js +25 -0
- package/dist/core/http/__tests__/body-parser-text.test.js +25 -0
- package/dist/core/http/__tests__/compile-path.test.js +33 -0
- package/dist/core/http/__tests__/middleware-pipeline.test.js +39 -0
- package/dist/core/http/__tests__/request.test.js +32 -0
- package/dist/core/http/__tests__/response.test.js +26 -0
- package/dist/core/http/__tests__/router-match.test.js +117 -0
- package/dist/core/http/adapter-node.js +44 -0
- package/dist/core/http/buildRequest.js +16 -0
- package/dist/core/http/compile-path.js +30 -0
- package/dist/core/http/errors.js +35 -0
- package/dist/core/http/http-server.js +48 -0
- package/dist/core/http/index.js +1 -0
- package/dist/core/http/main.js +1 -0
- package/dist/core/http/middleware.js +133 -0
- package/dist/core/http/request.js +22 -0
- package/dist/core/http/response.js +74 -0
- package/dist/core/http/router.js +111 -0
- package/dist/core/http/utils.js +1 -0
- package/dist/core/id-generator.js +14 -0
- package/dist/core/logger.js +81 -0
- package/dist/core/router.js +30 -0
- package/dist/core/server.js +70 -0
- package/dist/core/storage.js +46 -0
- package/dist/index.js +76 -0
- package/dist/listeners/api/__tests__/api.controller.test.js +88 -0
- package/dist/listeners/api/__tests__/api.extractor.test.js +39 -0
- package/dist/listeners/api/__tests__/api.listener.test.js +66 -0
- package/dist/listeners/api/__tests__/api.routes.test.js +105 -0
- package/dist/listeners/api/__tests__/api.sse.test.js +78 -0
- package/dist/listeners/api/api.controllers.js +39 -0
- package/dist/listeners/api/api.extractor.js +41 -0
- package/dist/listeners/api/api.listener.js +37 -0
- package/dist/listeners/api/api.routes.js +59 -0
- package/dist/listeners/api/api.sse.js +35 -0
- package/dist/listeners/dns/__tests__/dns.test.js +89 -0
- package/dist/listeners/dns/dns.extractor.js +17 -0
- package/dist/listeners/dns/dns.listener.js +48 -0
- package/dist/listeners/http/__tests__/http.extractor.test.js +52 -0
- package/dist/listeners/http/__tests__/http.listener.test.js +106 -0
- package/dist/listeners/http/http.extractor.js +18 -0
- package/dist/listeners/http/http.listener.js +91 -0
- package/dist/listeners/listener.interface.js +2 -0
- package/dist/listeners/smtp/__tests__/smtp.extractor.test.js +62 -0
- package/dist/listeners/smtp/__tests__/smtp.listener.test.js +129 -0
- package/dist/listeners/smtp/smtp.extractor.js +21 -0
- package/dist/listeners/smtp/smtp.listener.js +53 -0
- package/dist/listeners/ssrf/__tests__/ssrf.extractor.test.js +37 -0
- package/dist/listeners/ssrf/__tests__/ssrf.listener.test.js +79 -0
- package/dist/listeners/ssrf/ssrf.extractor.js +17 -0
- package/dist/listeners/ssrf/ssrf.listener.js +35 -0
- package/dist/listeners/tcp/tcp.extractor.js +18 -0
- package/dist/listeners/tcp/tcp.listener.js +47 -0
- package/dist/listeners/webhook/__tests__/webhook.extractor.test.js +30 -0
- package/dist/listeners/webhook/__tests__/webhook.listener.test.js +96 -0
- package/dist/listeners/webhook/webhook.extractor.js +15 -0
- package/dist/listeners/webhook/webhook.listener.js +51 -0
- package/dist/listeners/websocket/__tests__/websocket.extractor.test.js +29 -0
- package/dist/listeners/websocket/__tests__/websocket.listener.test.js +73 -0
- package/dist/listeners/websocket/websocket.extractor.js +14 -0
- package/dist/listeners/websocket/websocket.listener.js +33 -0
- package/dist/storage-adapters/adapters/__tests__/memory.storage.test.js +64 -0
- package/dist/storage-adapters/adapters/memory.storage.js +48 -0
- package/dist/storage-adapters/adapters/redis.storage.js +1 -0
- package/dist/storage-adapters/adapters/sqlite.storage.js +1 -0
- package/dist/storage-adapters/storage.interface.js +2 -0
- package/dist/types/event.types.js +2 -0
- package/dist/utils/token.js +1 -0
- package/image.png +0 -0
- package/jest.config.js +11 -0
- package/package.json +45 -0
- package/sadmin list shadows +9 -0
- package/src/api/controllers/__tests__/tasks.controller.test.ts +74 -0
- package/src/api/controllers/events.controller.ts +10 -0
- package/src/api/controllers/health.controller.ts +7 -0
- package/src/api/controllers/index.ts +0 -0
- package/src/api/controllers/tasks.controller.ts +41 -0
- package/src/api/dto/__tests__/create-task.dto.test.ts +41 -0
- package/src/api/dto/__tests__/filter-tasks.dto.test.ts +35 -0
- package/src/api/dto/create-task.dto.ts +33 -0
- package/src/api/dto/filter-tasks.dto.ts +33 -0
- package/src/api/services/__tests__/events.service.test.ts +41 -0
- package/src/api/services/__tests__/tasks.service.test.ts +41 -0
- package/src/api/services/events.service.ts +17 -0
- package/src/api/services/tasks.service.ts +79 -0
- package/src/api/sse/events.stream.ts +90 -0
- package/src/config/constants.ts +0 -0
- package/src/config/env.ts +0 -0
- package/src/core/__tests__/core-router.test.ts +30 -0
- package/src/core/__tests__/core-server.test.ts +44 -0
- package/src/core/__tests__/event.normalizer.test.ts +56 -0
- package/src/core/__tests__/event.router.test.ts +89 -0
- package/src/core/__tests__/logger.test.ts +32 -0
- package/src/core/__tests__/storage-manager.test.ts +74 -0
- package/src/core/event.normalizer.ts +147 -0
- package/src/core/event.router.ts +13 -0
- package/src/core/http/__tests__/adapter-node.test.ts +52 -0
- package/src/core/http/__tests__/body-parser-multipart.test.ts +41 -0
- package/src/core/http/__tests__/body-parser-raw.test.ts +28 -0
- package/src/core/http/__tests__/body-parser-text.test.ts +28 -0
- package/src/core/http/__tests__/compile-path.test.ts +39 -0
- package/src/core/http/__tests__/middleware-pipeline.test.ts +51 -0
- package/src/core/http/__tests__/request.test.ts +34 -0
- package/src/core/http/__tests__/response.test.ts +35 -0
- package/src/core/http/__tests__/router-match.test.ts +171 -0
- package/src/core/http/adapter-node.ts +51 -0
- package/src/core/http/buildRequest.ts +18 -0
- package/src/core/http/compile-path.ts +32 -0
- package/src/core/http/errors.ts +37 -0
- package/src/core/http/http-server.ts +52 -0
- package/src/core/http/index.ts +0 -0
- package/src/core/http/main.ts +0 -0
- package/src/core/http/middleware.ts +160 -0
- package/src/core/http/request.ts +55 -0
- package/src/core/http/response.ts +93 -0
- package/src/core/http/router.ts +138 -0
- package/src/core/http/utils.ts +0 -0
- package/src/core/id-generator.ts +8 -0
- package/src/core/logger.ts +113 -0
- package/src/core/router.ts +44 -0
- package/src/core/server.ts +85 -0
- package/src/core/storage.ts +64 -0
- package/src/index.ts +89 -0
- package/src/listeners/api/__tests__/api.controller.test.ts +116 -0
- package/src/listeners/api/__tests__/api.extractor.test.ts +46 -0
- package/src/listeners/api/__tests__/api.listener.test.ts +82 -0
- package/src/listeners/api/__tests__/api.routes.test.ts +155 -0
- package/src/listeners/api/__tests__/api.sse.test.ts +105 -0
- package/src/listeners/api/api.controllers.ts +67 -0
- package/src/listeners/api/api.extractor.ts +43 -0
- package/src/listeners/api/api.listener.ts +50 -0
- package/src/listeners/api/api.routes.ts +76 -0
- package/src/listeners/api/api.sse.ts +38 -0
- package/src/listeners/dns/__tests__/dns.test.ts +118 -0
- package/src/listeners/dns/dns.extractor.ts +14 -0
- package/src/listeners/dns/dns.listener.ts +61 -0
- package/src/listeners/http/__tests__/http.extractor.test.ts +59 -0
- package/src/listeners/http/__tests__/http.listener.test.ts +133 -0
- package/src/listeners/http/http.extractor.ts +15 -0
- package/src/listeners/http/http.listener.ts +110 -0
- package/src/listeners/listener.interface.ts +4 -0
- package/src/listeners/smtp/__tests__/smtp.extractor.test.ts +69 -0
- package/src/listeners/smtp/__tests__/smtp.listener.test.ts +150 -0
- package/src/listeners/smtp/smtp.extractor.ts +18 -0
- package/src/listeners/smtp/smtp.listener.ts +60 -0
- package/src/listeners/ssrf/__tests__/ssrf.extractor.test.ts +41 -0
- package/src/listeners/ssrf/__tests__/ssrf.listener.test.ts +98 -0
- package/src/listeners/ssrf/ssrf.extractor.ts +14 -0
- package/src/listeners/ssrf/ssrf.listener.ts +37 -0
- package/src/listeners/tcp/tcp.extractor.ts +16 -0
- package/src/listeners/tcp/tcp.listener.ts +61 -0
- package/src/listeners/webhook/__tests__/webhook.extractor.test.ts +35 -0
- package/src/listeners/webhook/__tests__/webhook.listener.test.ts +122 -0
- package/src/listeners/webhook/webhook.extractor.ts +12 -0
- package/src/listeners/webhook/webhook.listener.ts +58 -0
- package/src/listeners/websocket/__tests__/websocket.extractor.test.ts +33 -0
- package/src/listeners/websocket/__tests__/websocket.listener.test.ts +90 -0
- package/src/listeners/websocket/websocket.extractor.ts +11 -0
- package/src/listeners/websocket/websocket.listener.ts +40 -0
- package/src/storage-adapters/adapters/__tests__/memory.storage.test.ts +75 -0
- package/src/storage-adapters/adapters/memory.storage.ts +64 -0
- package/src/storage-adapters/adapters/redis.storage.ts +0 -0
- package/src/storage-adapters/adapters/sqlite.storage.ts +0 -0
- package/src/storage-adapters/storage.interface.ts +26 -0
- package/src/types/event.types.ts +147 -0
- package/src/utils/token.ts +0 -0
- package/src-api.txt +0 -0
- package/src-architecture.txt +0 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/api/sse/event-stream.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.EventStreamManager = void 0;
|
|
5
|
+
class EventStreamManager {
|
|
6
|
+
constructor(config = {}) {
|
|
7
|
+
this.clients = new Map();
|
|
8
|
+
this.heartbeatTimer = null;
|
|
9
|
+
this.config = {
|
|
10
|
+
retry: config.retry ?? 2000,
|
|
11
|
+
heartbeatInterval: config.heartbeatInterval ?? 15000,
|
|
12
|
+
logger: config.logger ?? console,
|
|
13
|
+
};
|
|
14
|
+
this.startHeartbeat();
|
|
15
|
+
}
|
|
16
|
+
startHeartbeat() {
|
|
17
|
+
if (process.env.NODE_ENV === "test")
|
|
18
|
+
return;
|
|
19
|
+
this.heartbeatTimer = setInterval(() => {
|
|
20
|
+
for (const client of this.clients.values()) {
|
|
21
|
+
client.res.write(`: heartbeat\n\n`);
|
|
22
|
+
}
|
|
23
|
+
}, this.config.heartbeatInterval);
|
|
24
|
+
}
|
|
25
|
+
addClient(res, channels = []) {
|
|
26
|
+
const id = crypto.randomUUID();
|
|
27
|
+
const client = {
|
|
28
|
+
id,
|
|
29
|
+
res,
|
|
30
|
+
channels: new Set(channels),
|
|
31
|
+
connectedAt: Date.now(),
|
|
32
|
+
};
|
|
33
|
+
this.clients.set(id, client);
|
|
34
|
+
res.write(`retry: ${this.config.retry}\n`);
|
|
35
|
+
res.write(`event: connected\ndata: {"id":"${id}"}\n\n`);
|
|
36
|
+
res.on("close", () => this.removeClient(id));
|
|
37
|
+
this.config.logger.info(`SSE client connected: ${id}`);
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
removeClient(id) {
|
|
41
|
+
if (this.clients.has(id)) {
|
|
42
|
+
this.clients.delete(id);
|
|
43
|
+
this.config.logger.info(`SSE client disconnected: ${id}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
broadcast(channel, event, data) {
|
|
47
|
+
const payload = `event: ${event}\n` +
|
|
48
|
+
`data: ${JSON.stringify(data)}\n` +
|
|
49
|
+
`channel: ${channel}\n\n`;
|
|
50
|
+
for (const client of this.clients.values()) {
|
|
51
|
+
if (client.channels.has(channel)) {
|
|
52
|
+
client.res.write(payload);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
broadcastAll(event, data) {
|
|
57
|
+
const payload = `event: ${event}\n` + `data: ${JSON.stringify(data)}\n\n`;
|
|
58
|
+
for (const client of this.clients.values()) {
|
|
59
|
+
client.res.write(payload);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.EventStreamManager = EventStreamManager;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const router_1 = require("../router");
|
|
4
|
+
const memory_storage_1 = require("../../storage-adapters/adapters/memory.storage");
|
|
5
|
+
const globals_1 = require("@jest/globals");
|
|
6
|
+
(0, globals_1.describe)("CoreRouter", () => {
|
|
7
|
+
const event = {
|
|
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
|
+
(0, globals_1.it)("appelle les hooks", async () => {
|
|
21
|
+
const hook = globals_1.jest.fn((e) => { }); // ← FIX
|
|
22
|
+
const router = new router_1.CoreRouter(new memory_storage_1.MemoryStorage(), { hooks: [hook] });
|
|
23
|
+
await router.dispatch(event);
|
|
24
|
+
(0, globals_1.expect)(hook).toHaveBeenCalledWith(event);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const server_1 = require("../../core/server");
|
|
4
|
+
const storage_1 = require("../../core/storage");
|
|
5
|
+
const logger_1 = require("../../core/logger");
|
|
6
|
+
const globals_1 = require("@jest/globals");
|
|
7
|
+
class FakeListener {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.started = false;
|
|
10
|
+
this.stopped = false;
|
|
11
|
+
}
|
|
12
|
+
async start() {
|
|
13
|
+
this.started = true;
|
|
14
|
+
}
|
|
15
|
+
async stop() {
|
|
16
|
+
this.stopped = true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
(0, globals_1.describe)("CoreServer", () => {
|
|
20
|
+
(0, globals_1.it)("démarre et arrête les listeners", async () => {
|
|
21
|
+
const listener = new FakeListener();
|
|
22
|
+
const server = new server_1.CoreServer({
|
|
23
|
+
storage: new storage_1.StorageManager(),
|
|
24
|
+
logger: new logger_1.Logger({ enabled: false }),
|
|
25
|
+
listeners: [listener],
|
|
26
|
+
});
|
|
27
|
+
await server.start();
|
|
28
|
+
(0, globals_1.expect)(listener.started).toBe(true);
|
|
29
|
+
await server.stop();
|
|
30
|
+
(0, globals_1.expect)(listener.stopped).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
(0, globals_1.it)("expose le router", () => {
|
|
33
|
+
const server = new server_1.CoreServer({
|
|
34
|
+
storage: new storage_1.StorageManager(),
|
|
35
|
+
});
|
|
36
|
+
const router = server.getRouter();
|
|
37
|
+
(0, globals_1.expect)(router).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const event_normalizer_1 = require("../event.normalizer");
|
|
4
|
+
const globals_1 = require("@jest/globals");
|
|
5
|
+
const id_generator_1 = require("../id-generator");
|
|
6
|
+
(0, globals_1.describe)("EventNormalizer.normalizeHttp", () => {
|
|
7
|
+
(0, globals_1.it)("normalise correctement une requête HTTP", () => {
|
|
8
|
+
// Mock du timestamp
|
|
9
|
+
const fakeNow = 1234567890;
|
|
10
|
+
globals_1.jest.spyOn(Date, "now").mockReturnValue(fakeNow);
|
|
11
|
+
// Mock de l'ID
|
|
12
|
+
globals_1.jest.spyOn(id_generator_1.IdGenerator, "generate").mockReturnValue("uuid-test");
|
|
13
|
+
const req = {
|
|
14
|
+
ip: "9.9.9.9",
|
|
15
|
+
method: "POST",
|
|
16
|
+
path: "/test",
|
|
17
|
+
headers: { "x-forwarded-for": "9.9.9.9" },
|
|
18
|
+
query: { a: "1" },
|
|
19
|
+
body: { hello: "world" },
|
|
20
|
+
raw: {}, // obligatoire
|
|
21
|
+
};
|
|
22
|
+
const event = event_normalizer_1.EventNormalizer.normalizeHttp(req);
|
|
23
|
+
(0, globals_1.expect)(event).toEqual({
|
|
24
|
+
id: "uuid-test",
|
|
25
|
+
type: "http",
|
|
26
|
+
timestamp: fakeNow,
|
|
27
|
+
sourceIp: "9.9.9.9",
|
|
28
|
+
request: {
|
|
29
|
+
method: "POST",
|
|
30
|
+
path: "/test",
|
|
31
|
+
headers: { "x-forwarded-for": "9.9.9.9" },
|
|
32
|
+
query: { a: "1" },
|
|
33
|
+
body: { hello: "world" },
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
(0, globals_1.it)("retourne 'unknown' si aucune IP n'est trouvée", () => {
|
|
38
|
+
const req = {
|
|
39
|
+
ip: "",
|
|
40
|
+
method: "GET",
|
|
41
|
+
path: "/",
|
|
42
|
+
headers: {},
|
|
43
|
+
query: {},
|
|
44
|
+
body: {},
|
|
45
|
+
raw: {},
|
|
46
|
+
};
|
|
47
|
+
const event = event_normalizer_1.EventNormalizer.normalizeHttp(req);
|
|
48
|
+
(0, globals_1.expect)(event.sourceIp).toBe("unknown");
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const event_router_1 = require("../event.router");
|
|
4
|
+
const event_normalizer_1 = require("../event.normalizer");
|
|
5
|
+
const globals_1 = require("@jest/globals");
|
|
6
|
+
class MockStorage {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.save = globals_1.jest.fn();
|
|
9
|
+
this.getEvent = globals_1.jest.fn();
|
|
10
|
+
this.listEvents = globals_1.jest.fn();
|
|
11
|
+
this.deleteEvent = globals_1.jest.fn();
|
|
12
|
+
this.clearEvents = globals_1.jest.fn();
|
|
13
|
+
this.getStats = globals_1.jest.fn();
|
|
14
|
+
this.getAll = globals_1.jest.fn();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
(0, globals_1.describe)("EventRouter", () => {
|
|
18
|
+
(0, globals_1.it)("enregistre un événement HTTP normalisé", async () => {
|
|
19
|
+
const mockStorage = new MockStorage();
|
|
20
|
+
const fakeEvent = {
|
|
21
|
+
id: "123",
|
|
22
|
+
type: "http",
|
|
23
|
+
timestamp: 111,
|
|
24
|
+
sourceIp: "1.1.1.1",
|
|
25
|
+
request: {
|
|
26
|
+
method: "GET",
|
|
27
|
+
path: "/",
|
|
28
|
+
headers: {},
|
|
29
|
+
query: {},
|
|
30
|
+
body: {},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
globals_1.jest.spyOn(event_normalizer_1.EventNormalizer, "normalizeHttp").mockReturnValue(fakeEvent);
|
|
34
|
+
const router = new event_router_1.EventRouter(mockStorage);
|
|
35
|
+
const req = {
|
|
36
|
+
ip: "1.1.1.1",
|
|
37
|
+
method: "GET",
|
|
38
|
+
path: "/",
|
|
39
|
+
headers: {},
|
|
40
|
+
query: {},
|
|
41
|
+
body: {},
|
|
42
|
+
raw: {},
|
|
43
|
+
};
|
|
44
|
+
const result = await router.handleHttp(req);
|
|
45
|
+
(0, globals_1.expect)(event_normalizer_1.EventNormalizer.normalizeHttp).toHaveBeenCalledWith(req);
|
|
46
|
+
(0, globals_1.expect)(mockStorage.save).toHaveBeenCalledWith(fakeEvent);
|
|
47
|
+
(0, globals_1.expect)(result).toEqual(fakeEvent);
|
|
48
|
+
});
|
|
49
|
+
(0, globals_1.it)("propagate une erreur si normalizeHttp throw", async () => {
|
|
50
|
+
const mockStorage = new MockStorage();
|
|
51
|
+
globals_1.jest.spyOn(event_normalizer_1.EventNormalizer, "normalizeHttp").mockImplementation(() => {
|
|
52
|
+
throw new Error("Boom");
|
|
53
|
+
});
|
|
54
|
+
const router = new event_router_1.EventRouter(mockStorage);
|
|
55
|
+
await (0, globals_1.expect)(router.handleHttp({})).rejects.toThrow("Boom");
|
|
56
|
+
(0, globals_1.expect)(mockStorage.save).not.toHaveBeenCalled();
|
|
57
|
+
});
|
|
58
|
+
(0, globals_1.it)("propagate une erreur si storage.save throw", async () => {
|
|
59
|
+
const mockStorage = new MockStorage();
|
|
60
|
+
const fakeEvent = { id: "x", type: "http" };
|
|
61
|
+
globals_1.jest.spyOn(event_normalizer_1.EventNormalizer, "normalizeHttp").mockReturnValue(fakeEvent);
|
|
62
|
+
mockStorage.save.mockRejectedValue(new Error("DB error"));
|
|
63
|
+
const router = new event_router_1.EventRouter(mockStorage);
|
|
64
|
+
await (0, globals_1.expect)(router.handleHttp({})).rejects.toThrow("DB error");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const logger_1 = require("../../core/logger");
|
|
4
|
+
const globals_1 = require("@jest/globals");
|
|
5
|
+
(0, globals_1.describe)("Logger", () => {
|
|
6
|
+
(0, globals_1.it)("appelle les hooks", () => {
|
|
7
|
+
const hook = globals_1.jest.fn();
|
|
8
|
+
const logger = new logger_1.Logger({ hooks: [hook], enabled: true });
|
|
9
|
+
logger.info("hello");
|
|
10
|
+
(0, globals_1.expect)(hook).toHaveBeenCalled();
|
|
11
|
+
(0, globals_1.expect)(hook.mock.calls[0][0].message).toBe("hello");
|
|
12
|
+
});
|
|
13
|
+
(0, globals_1.it)("respecte le niveau de logs", () => {
|
|
14
|
+
const hook = globals_1.jest.fn();
|
|
15
|
+
const logger = new logger_1.Logger({ level: "warn", hooks: [hook] });
|
|
16
|
+
logger.info("should not log");
|
|
17
|
+
logger.error("should log");
|
|
18
|
+
(0, globals_1.expect)(hook).toHaveBeenCalledTimes(1);
|
|
19
|
+
(0, globals_1.expect)(hook.mock.calls[0][0].level).toBe("error");
|
|
20
|
+
});
|
|
21
|
+
(0, globals_1.it)("crée un logger enfant avec contexte", () => {
|
|
22
|
+
const logger = new logger_1.Logger({ context: "root" });
|
|
23
|
+
const child = logger.withContext("child");
|
|
24
|
+
(0, globals_1.expect)(child).not.toBe(logger);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const globals_1 = require("@jest/globals");
|
|
4
|
+
const storage_1 = require("../storage"); // si ton fichier s'appelle storage-manager.ts
|
|
5
|
+
function makeHttpEvent(id) {
|
|
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
|
+
(0, globals_1.describe)("StorageManager", () => {
|
|
21
|
+
(0, globals_1.test)("save + getEvent", async () => {
|
|
22
|
+
const storage = new storage_1.StorageManager();
|
|
23
|
+
const event = makeHttpEvent("1");
|
|
24
|
+
await storage.save(event);
|
|
25
|
+
const found = await storage.getEvent("1");
|
|
26
|
+
(0, globals_1.expect)(found).not.toBeNull();
|
|
27
|
+
(0, globals_1.expect)(found?.id).toBe("1");
|
|
28
|
+
});
|
|
29
|
+
(0, globals_1.test)("listEvents returns events", async () => {
|
|
30
|
+
const storage = new storage_1.StorageManager();
|
|
31
|
+
await storage.save(makeHttpEvent("1"));
|
|
32
|
+
const list = await storage.listEvents({});
|
|
33
|
+
(0, globals_1.expect)(list.length).toBe(1);
|
|
34
|
+
});
|
|
35
|
+
(0, globals_1.test)("deleteEvent removes event", async () => {
|
|
36
|
+
const storage = new storage_1.StorageManager();
|
|
37
|
+
await storage.save(makeHttpEvent("1"));
|
|
38
|
+
let list = await storage.listEvents({});
|
|
39
|
+
(0, globals_1.expect)(list.length).toBe(1);
|
|
40
|
+
await storage.deleteEvent("1");
|
|
41
|
+
list = await storage.listEvents({});
|
|
42
|
+
(0, globals_1.expect)(list.length).toBe(0);
|
|
43
|
+
});
|
|
44
|
+
(0, globals_1.test)("clearEvents empties storage", async () => {
|
|
45
|
+
const storage = new storage_1.StorageManager();
|
|
46
|
+
await storage.save(makeHttpEvent("1"));
|
|
47
|
+
await storage.clearEvents();
|
|
48
|
+
const list = await storage.listEvents({});
|
|
49
|
+
(0, globals_1.expect)(list.length).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
(0, globals_1.test)("getStats returns correct structure", async () => {
|
|
52
|
+
const storage = new storage_1.StorageManager();
|
|
53
|
+
const stats = await storage.getStats();
|
|
54
|
+
(0, globals_1.expect)(stats.total).toBe(0);
|
|
55
|
+
(0, globals_1.expect)(stats.byType).toEqual({});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventNormalizer = void 0;
|
|
4
|
+
const id_generator_1 = require("./id-generator");
|
|
5
|
+
class EventNormalizer {
|
|
6
|
+
//
|
|
7
|
+
// -------------------------
|
|
8
|
+
// DNS
|
|
9
|
+
// -------------------------
|
|
10
|
+
//
|
|
11
|
+
static normalizeDns(event) {
|
|
12
|
+
return {
|
|
13
|
+
id: id_generator_1.IdGenerator.generate(),
|
|
14
|
+
type: "dns",
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
ip: event.ip ?? "",
|
|
17
|
+
query: event.query ?? "",
|
|
18
|
+
recordType: event.recordType ?? "",
|
|
19
|
+
raw: event.raw,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//
|
|
23
|
+
// -------------------------
|
|
24
|
+
// HTTP
|
|
25
|
+
// -------------------------
|
|
26
|
+
//
|
|
27
|
+
static normalizeHttp(event) {
|
|
28
|
+
const sourceIp = event.ip && event.ip.trim() !== "" ? event.ip : "unknown";
|
|
29
|
+
return {
|
|
30
|
+
id: id_generator_1.IdGenerator.generate(),
|
|
31
|
+
type: "http",
|
|
32
|
+
timestamp: Date.now(),
|
|
33
|
+
sourceIp,
|
|
34
|
+
request: {
|
|
35
|
+
method: event.method,
|
|
36
|
+
path: event.path,
|
|
37
|
+
headers: event.headers,
|
|
38
|
+
query: event.query,
|
|
39
|
+
body: event.body,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//
|
|
44
|
+
// -------------------------
|
|
45
|
+
// SMTP
|
|
46
|
+
// -------------------------
|
|
47
|
+
//
|
|
48
|
+
static normalizeSmtp(event) {
|
|
49
|
+
return {
|
|
50
|
+
id: id_generator_1.IdGenerator.generate(),
|
|
51
|
+
type: "smtp",
|
|
52
|
+
timestamp: Date.now(),
|
|
53
|
+
ip: event.ip ?? "",
|
|
54
|
+
from: event.from ?? "",
|
|
55
|
+
to: event.to ?? [],
|
|
56
|
+
subject: event.subject ?? "",
|
|
57
|
+
body: event.body ?? "",
|
|
58
|
+
raw: event.raw,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//
|
|
62
|
+
// -------------------------
|
|
63
|
+
// TCP
|
|
64
|
+
// -------------------------
|
|
65
|
+
//
|
|
66
|
+
static normalizeTcp(event) {
|
|
67
|
+
return {
|
|
68
|
+
id: id_generator_1.IdGenerator.generate(),
|
|
69
|
+
type: "tcp",
|
|
70
|
+
timestamp: Date.now(),
|
|
71
|
+
ip: event.ip ?? "",
|
|
72
|
+
port: event.port ?? 0,
|
|
73
|
+
data: event.data ?? "",
|
|
74
|
+
raw: event.raw,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//
|
|
78
|
+
// -------------------------
|
|
79
|
+
// SSRF
|
|
80
|
+
// -------------------------
|
|
81
|
+
//
|
|
82
|
+
static normalizeSsrf(raw) {
|
|
83
|
+
return {
|
|
84
|
+
id: id_generator_1.IdGenerator.generate(),
|
|
85
|
+
type: "ssrf",
|
|
86
|
+
timestamp: Date.now(),
|
|
87
|
+
sourceIp: raw.ip,
|
|
88
|
+
request: {
|
|
89
|
+
method: raw.method,
|
|
90
|
+
path: raw.path,
|
|
91
|
+
headers: raw.headers,
|
|
92
|
+
query: raw.query,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//
|
|
97
|
+
// -------------------------
|
|
98
|
+
// webhook
|
|
99
|
+
// -------------------------
|
|
100
|
+
//
|
|
101
|
+
static normalizeWebhook(raw) {
|
|
102
|
+
return {
|
|
103
|
+
id: id_generator_1.IdGenerator.generate(),
|
|
104
|
+
type: "webhook",
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
sourceIp: raw.ip,
|
|
107
|
+
headers: raw.headers,
|
|
108
|
+
body: raw.body,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//
|
|
112
|
+
// -------------------------
|
|
113
|
+
// websocket
|
|
114
|
+
// -------------------------
|
|
115
|
+
//
|
|
116
|
+
static normalizeWebSocket(raw) {
|
|
117
|
+
return {
|
|
118
|
+
id: id_generator_1.IdGenerator.generate(),
|
|
119
|
+
type: "websocket",
|
|
120
|
+
timestamp: Date.now(),
|
|
121
|
+
sourceIp: raw.ip,
|
|
122
|
+
message: raw.message,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.EventNormalizer = EventNormalizer;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventRouter = void 0;
|
|
4
|
+
const event_normalizer_1 = require("./event.normalizer");
|
|
5
|
+
class EventRouter {
|
|
6
|
+
constructor(storage) {
|
|
7
|
+
this.storage = storage;
|
|
8
|
+
}
|
|
9
|
+
async handleHttp(event) {
|
|
10
|
+
const normalized = event_normalizer_1.EventNormalizer.normalizeHttp(event);
|
|
11
|
+
await this.storage.save(normalized);
|
|
12
|
+
return normalized;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.EventRouter = EventRouter;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const adapter_node_1 = require("../adapter-node");
|
|
37
|
+
const middleware_1 = require("../middleware");
|
|
38
|
+
const router_1 = require("../router");
|
|
39
|
+
const request_1 = require("../request");
|
|
40
|
+
const globals_1 = require("@jest/globals");
|
|
41
|
+
const Build = __importStar(require("../buildRequest"));
|
|
42
|
+
(0, globals_1.describe)("NodeAdapter.handle", () => {
|
|
43
|
+
(0, globals_1.it)("appelle le handler quand la route match", async () => {
|
|
44
|
+
const router = new router_1.Router();
|
|
45
|
+
const pipeline = new middleware_1.MiddlewarePipeline();
|
|
46
|
+
// mock buildRequest
|
|
47
|
+
const buildRequestMock = globals_1.jest
|
|
48
|
+
.spyOn(Build, "buildRequest")
|
|
49
|
+
.mockImplementation((raw, params) => new request_1.Request({
|
|
50
|
+
method: "GET",
|
|
51
|
+
path: "/test",
|
|
52
|
+
headers: {},
|
|
53
|
+
params: params ?? {},
|
|
54
|
+
}));
|
|
55
|
+
const handler = globals_1.jest.fn();
|
|
56
|
+
router.match = globals_1.jest.fn(() => ({
|
|
57
|
+
handler,
|
|
58
|
+
params: { id: "42" },
|
|
59
|
+
middlewares: [],
|
|
60
|
+
}));
|
|
61
|
+
pipeline.run = globals_1.jest.fn(async () => { });
|
|
62
|
+
const res = {
|
|
63
|
+
writableEnded: false,
|
|
64
|
+
setHeader: globals_1.jest.fn(),
|
|
65
|
+
end: globals_1.jest.fn(),
|
|
66
|
+
statusCode: 200,
|
|
67
|
+
};
|
|
68
|
+
const adapter = new adapter_node_1.NodeAdapter(router, pipeline);
|
|
69
|
+
await adapter.handle({ url: "/test", method: "GET", headers: {} }, res);
|
|
70
|
+
(0, globals_1.expect)(handler).toHaveBeenCalled();
|
|
71
|
+
(0, globals_1.expect)(pipeline.run).toHaveBeenCalled();
|
|
72
|
+
(0, globals_1.expect)(buildRequestMock).toHaveBeenCalledTimes(2);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const middleware_1 = require("../middleware");
|
|
4
|
+
const request_1 = require("../request");
|
|
5
|
+
const response_1 = require("../response");
|
|
6
|
+
const globals_1 = require("@jest/globals");
|
|
7
|
+
(0, globals_1.describe)("bodyParserMultipart", () => {
|
|
8
|
+
(0, globals_1.it)("parse un champ texte et un fichier", async () => {
|
|
9
|
+
const boundary = "----1234";
|
|
10
|
+
const raw = {
|
|
11
|
+
headers: { "content-type": `multipart/form-data; boundary=${boundary}` },
|
|
12
|
+
[Symbol.asyncIterator]: async function* () {
|
|
13
|
+
yield Buffer.from(`--${boundary}\r\n` +
|
|
14
|
+
`Content-Disposition: form-data; name="username"\r\n\r\n` +
|
|
15
|
+
`jeremy\r\n` +
|
|
16
|
+
`--${boundary}\r\n` +
|
|
17
|
+
`Content-Disposition: form-data; name="file"; filename="test.txt"\r\n` +
|
|
18
|
+
`Content-Type: text/plain\r\n\r\n` +
|
|
19
|
+
`Hello world\r\n` +
|
|
20
|
+
`--${boundary}--`);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const req = new request_1.Request({
|
|
24
|
+
method: "POST",
|
|
25
|
+
path: "/upload",
|
|
26
|
+
headers: raw.headers,
|
|
27
|
+
raw,
|
|
28
|
+
});
|
|
29
|
+
const res = new response_1.Response({});
|
|
30
|
+
await (0, middleware_1.bodyParserMultipart)(req, res);
|
|
31
|
+
(0, globals_1.expect)(req.form?.username).toBe("jeremy");
|
|
32
|
+
(0, globals_1.expect)(req.files?.[0].filename).toBe("test.txt");
|
|
33
|
+
(0, globals_1.expect)(req.files?.[0].data.toString()).toBe("Hello world");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const middleware_1 = require("../middleware");
|
|
4
|
+
const request_1 = require("../request");
|
|
5
|
+
const response_1 = require("../response");
|
|
6
|
+
const globals_1 = require("@jest/globals");
|
|
7
|
+
(0, globals_1.describe)("bodyParserRaw", () => {
|
|
8
|
+
(0, globals_1.it)("lit le body brut", async () => {
|
|
9
|
+
const raw = {
|
|
10
|
+
headers: { "content-type": "application/octet-stream" },
|
|
11
|
+
[Symbol.asyncIterator]: async function* () {
|
|
12
|
+
yield Buffer.from([1, 2, 3, 4]);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const req = new request_1.Request({
|
|
16
|
+
method: "POST",
|
|
17
|
+
path: "/",
|
|
18
|
+
headers: raw.headers,
|
|
19
|
+
raw,
|
|
20
|
+
});
|
|
21
|
+
const res = new response_1.Response({});
|
|
22
|
+
await (0, middleware_1.bodyParserRaw)(req, res);
|
|
23
|
+
(0, globals_1.expect)(req.bodyRaw).toEqual(Buffer.from([1, 2, 3, 4]));
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const middleware_1 = require("../middleware");
|
|
4
|
+
const request_1 = require("../request");
|
|
5
|
+
const response_1 = require("../response");
|
|
6
|
+
const globals_1 = require("@jest/globals");
|
|
7
|
+
(0, globals_1.describe)("bodyParserText", () => {
|
|
8
|
+
(0, globals_1.it)("lit le body text", async () => {
|
|
9
|
+
const raw = {
|
|
10
|
+
headers: { "content-type": "text/plain" },
|
|
11
|
+
[Symbol.asyncIterator]: async function* () {
|
|
12
|
+
yield Buffer.from("Hello world");
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const req = new request_1.Request({
|
|
16
|
+
method: "POST",
|
|
17
|
+
path: "/",
|
|
18
|
+
headers: raw.headers,
|
|
19
|
+
raw,
|
|
20
|
+
});
|
|
21
|
+
const res = new response_1.Response({});
|
|
22
|
+
await (0, middleware_1.bodyParserText)(req, res);
|
|
23
|
+
(0, globals_1.expect)(req.bodyText).toBe("Hello world");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const compile_path_1 = require("../compile-path");
|
|
4
|
+
const globals_1 = require("@jest/globals");
|
|
5
|
+
(0, globals_1.describe)("compilePath", () => {
|
|
6
|
+
(0, globals_1.it)("compile un chemin simple avec segment statique", () => {
|
|
7
|
+
const result = (0, compile_path_1.compilePath)("/tasks");
|
|
8
|
+
(0, globals_1.expect)(result).toEqual([{ type: "static", value: "tasks" }]);
|
|
9
|
+
});
|
|
10
|
+
(0, globals_1.it)("compile un chemin avec paramètre", () => {
|
|
11
|
+
const result = (0, compile_path_1.compilePath)("/tasks/:id");
|
|
12
|
+
(0, globals_1.expect)(result).toEqual([
|
|
13
|
+
{ type: "static", value: "tasks" },
|
|
14
|
+
{ type: "param", name: "id" },
|
|
15
|
+
]);
|
|
16
|
+
});
|
|
17
|
+
(0, globals_1.it)("compile un chemin avec paramètre", () => {
|
|
18
|
+
const result = (0, compile_path_1.compilePath)("/tasks/:id");
|
|
19
|
+
(0, globals_1.expect)(result).toEqual([
|
|
20
|
+
{ type: "static", value: "tasks" },
|
|
21
|
+
{ type: "param", name: "id" },
|
|
22
|
+
]);
|
|
23
|
+
});
|
|
24
|
+
(0, globals_1.it)("compile un chemin complexe avec static, param et wildcard", () => {
|
|
25
|
+
const result = (0, compile_path_1.compilePath)("/a/:b/*/c");
|
|
26
|
+
(0, globals_1.expect)(result).toEqual([
|
|
27
|
+
{ type: "static", value: "a" },
|
|
28
|
+
{ type: "param", name: "b" },
|
|
29
|
+
{ type: "wildcard" },
|
|
30
|
+
{ type: "static", value: "c" },
|
|
31
|
+
]);
|
|
32
|
+
});
|
|
33
|
+
});
|