forked from Lilly-Protocol/lily-backend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.ts
More file actions
108 lines (96 loc) · 2.77 KB
/
Copy pathapp.ts
File metadata and controls
108 lines (96 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import type { IncomingMessage } from "node:http";
import compression from "compression";
import cors from "cors";
import express from "express";
import helmet from "helmet";
import pinoHttp from "pino-http";
import { cacheControlNoStore } from "./common/http/cache-control.middleware";
import { errorHandler } from "./common/http/error.middleware";
import {
methodNotAllowedHandler,
notFoundHandler,
} from "./common/http/not-found.middleware";
import { corsOptions } from "./config/cors";
import { env, securityConfig } from "./config/env";
import { logger } from "./config/logger";
import { apiRateLimiter } from "./config/rate-limit";
import { shouldIgnoreRequestLog } from "./config/request-logging";
import { apiRouter } from "./routes";
const sensitiveQueryKeys = [
"api_key",
"apikey",
"key",
"token",
"secret",
"seed",
"wallet_seed",
"private_key",
];
const redactUrl = (url: string): string => {
try {
const parsed = new URL(url, "http://localhost");
let changed = false;
for (const key of sensitiveQueryKeys) {
if (parsed.searchParams.has(key)) {
parsed.searchParams.set(key, "[REDACTED]");
changed = true;
}
}
return changed ? `${parsed.pathname}${parsed.search}` : url;
} catch {
return url;
}
};
const serializeRequestLog = (request: IncomingMessage & { id?: unknown }) => ({
id: request.id,
method: request.method,
url: redactUrl(request.url ?? ""),
remoteAddress: request.socket?.remoteAddress,
remotePort: request.socket?.remotePort,
});
export const createApp = (): express.Express => {
const app = express();
app.disable("x-powered-by");
app.set("trust proxy", securityConfig.trustProxy);
app.use(
helmet({
crossOriginResourcePolicy: { policy: "cross-origin" },
}),
);
app.use(cors(corsOptions));
app.use(compression());
app.use(express.json({ limit: securityConfig.bodySizeLimit }));
app.use(express.urlencoded({ extended: true }));
app.use(cacheControlNoStore);
app.use(
pinoHttp({
logger,
autoLogging: { ignore: shouldIgnoreRequestLog },
customLogLevel(_request, response, error) {
if (error || response.statusCode >= 500) {
return "error";
}
if (response.statusCode >= 400) {
return "warn";
}
return "info";
},
serializers: {
req: serializeRequestLog as never,
},
}),
);
app.get("/", (_request, response) => {
response.status(200).json({
success: true,
message: `${env.APP_NAME} is active`,
docs: `${env.API_PREFIX}/health`,
});
});
app.use(env.API_PREFIX, apiRateLimiter);
app.use(env.API_PREFIX, apiRouter);
app.use(methodNotAllowedHandler(apiRouter));
app.use(notFoundHandler);
app.use(errorHandler);
return app;
};