Skip to content

Commit

Permalink
feat: trust proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
SALTWOOD committed Jan 11, 2025
1 parent ba143a2 commit 5d3de24
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 27 deletions.
16 changes: 11 additions & 5 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,29 @@ export class Config {
};

public readonly server: {
host: string;
port: number;
concurrency: number;
forceNoOpen: boolean;
noWarden: boolean;
forceHttps: boolean;
requestCert: boolean;
} = {
host: "127.0.0.1",
port: 9388,
concurrency: 10,
forceNoOpen: false,
noWarden: false,
forceHttps: false,
requestCert: false
};

public network: {
host: string;
port: number;
trustProxy: boolean;
} = {
host: "127.0.0.1",
port: 9388,
trustProxy: false
};

public readonly security: {
failAttemptsToBan: number;
failAttemptsDuration: number;
Expand All @@ -65,7 +71,7 @@ export class Config {
requestRateLimit: 0
};

public readonly update: {
public readonly data: {
checkInterval: number;
shownDays: number;
} = {
Expand Down
28 changes: 10 additions & 18 deletions src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ import { ApiFactory } from './routes/ApiFactory.js';
//@ts-ignore
await import("express-async-errors")

type Indexable<T> = {
[key: string]: T;
}

// 创建一个中间件函数
const logMiddleware = (req: Request, res: Response, next: NextFunction) => {
// 调用下一个中间件
Expand All @@ -45,14 +41,9 @@ const logMiddleware = (req: Request, res: Response, next: NextFunction) => {
});
};

export const getRealIP = (obj: Indexable<any>): string => {
return (obj[Config.instance.dev.sourceIpHeader] as string).split(',')[0];
}

const logAccess = (req: Request, res: Response) => {
const userAgent = req.headers['user-agent'] || '';
const ip = getRealIP(req.headers) || req.ip;
console.log(`${req.method} ${req.originalUrl} ${req.protocol} <${res.statusCode}> - [${ip}] ${userAgent}`);
console.log(`${req.method} ${req.originalUrl} ${req.protocol} <${res.statusCode}> - [${req.ip}] ${userAgent}`);
};

export class Server {
Expand Down Expand Up @@ -138,6 +129,7 @@ export class Server {

public async init(): Promise<void> {
// 设置中间件
if (Config.instance.network.trustProxy) this.app.set('trust proxy', true);
if (!Config.instance.dev.disableAccessLog) this.app.use(logMiddleware);
if (Config.instance.security.requestRateLimit > 0) this.app.use(rateLimiter);
this.app.use(express.json());
Expand All @@ -147,7 +139,7 @@ export class Server {
await this.updateFiles();
this.setupRoutes();

if (Config.instance.update.checkInterval > 0) setInterval(this.updateFiles.bind(this), Config.instance.update.checkInterval * 60 * 1000);
if (Config.instance.data.checkInterval > 0) setInterval(this.updateFiles.bind(this), Config.instance.data.checkInterval * 60 * 1000);

// 加载证书管理器
if (Config.instance.server.requestCert) {
Expand Down Expand Up @@ -248,8 +240,8 @@ export class Server {

public start(): void {
// 启动 HTTPS 服务器
this.httpServer.listen(Config.instance.server.port, Config.instance.server.host, () => {
console.log(`HTTP Server running on http://${Config.instance.server.host}:${Config.instance.server.port}`);
this.httpServer.listen(Config.instance.network.port, Config.instance.network.host, () => {
console.log(`HTTP Server running on http://${Config.instance.network.host}:${Config.instance.network.port}`);
});
}

Expand Down Expand Up @@ -424,7 +416,7 @@ export class Server {
this.sendFile(req, res, file);
return;
}
let cluster = await this.fileList.randomAvailableCluster(file, file.url ? undefined : this.fileList.clusters.filter(c => !c.isProxyCluster), getRealIP(req.headers) || req.ip);
let cluster = await this.fileList.randomAvailableCluster(file, file.url ? undefined : this.fileList.clusters.filter(c => !c.isProxyCluster), req.ip);
if (!cluster) {
this.sendFile(req, res, file);
return;
Expand Down Expand Up @@ -497,7 +489,7 @@ export class Server {
this.sessionToClusterMap.set(socket.id, cluster);
return next(); // 验证通过,允许连接
}
console.log(`SOCKET [${socket.id}] <ADMIN> - [${getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}>`);
console.log(`SOCKET [${socket.id}] <ADMIN> - [${Utilities.getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}>`);
return next();
}

Expand All @@ -514,7 +506,7 @@ export class Server {
}
if (exp > Date.now() / 1000) {
this.sessionToClusterMap.set(socket.id, cluster);
console.log(`SOCKET ${socket.id} <ACCEPTED> - [${getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}>`);
console.log(`SOCKET ${socket.id} <ACCEPTED> - [${Utilities.getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}>`);
return next(); // 验证通过,允许连接
} else {
throw new Error('Token expired');
Expand All @@ -531,11 +523,11 @@ export class Server {

// 监听 Socket.IO 连接事件
this.io.on('connection', (socket) => {
console.log(`SOCKET [${this.sessionToClusterMap.get(socket.id)?.clusterId}] <CONNECTED> - [${getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}>`);
console.log(`SOCKET [${this.sessionToClusterMap.get(socket.id)?.clusterId}] <CONNECTED> - [${Utilities.getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}>`);

socket.onAny((event: string, data) => {
if (this.sessionToClusterMap.has(socket.id)) {
console.log(`SOCKET [${this.sessionToClusterMap.get(socket.id)?.clusterId}] <${event?.toUpperCase() || 'UNKNOWN'}> - [${getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}> ${`<WITH ${Object.keys(data || []).length || 'NO'} PARAMS>`}`);
console.log(`SOCKET [${this.sessionToClusterMap.get(socket.id)?.clusterId}] <${event?.toUpperCase() || 'UNKNOWN'}> - [${Utilities.getRealIP(socket.handshake.headers) || socket.handshake.address}] <${socket.handshake.headers['user-agent'] || 'null'}> ${`<WITH ${Object.keys(data || []).length || 'NO'} PARAMS>`}`);
const cluster = this.sessionToClusterMap.get(socket.id);
if (cluster) {
cluster.lastSeen = Date.now();
Expand Down
8 changes: 8 additions & 0 deletions src/Utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,17 @@ export const FileListSchema = avsc.Type.forSchema({
},
});

type Indexable<T> = {
[key: string]: T;
}

const bannedCharacters = /[&<>\"'\r\n]/g;

export class Utilities {
public static getRealIP(obj: Indexable<any>): string {
return (obj[Config.instance.dev.sourceIpHeader] as string).split(',')[0];
}

public static isRunningInDocker(): boolean {
return process.env.IS_IN_DOCKER === 'true';
}
Expand Down
4 changes: 2 additions & 2 deletions src/routes/ApiClusters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export class ApiClusters {
inst.app.get("/api/clusters", async (req, res) => {
// 仅显示特定天数内有活动的节点
// 先把节点按照在线和离线分成两部分,然后各自按照 traffic 从大到小排序,最后返回 JSON 字符串
const clusters = Config.instance.update.shownDays > 0
? inst.clusters.filter(c => c.lastSeen > Utilities.getDate(-Config.instance.update.shownDays, "day").getTime())
const clusters = Config.instance.data.shownDays > 0
? inst.clusters.filter(c => c.lastSeen > Utilities.getDate(-Config.instance.data.shownDays, "day").getTime())
: inst.clusters;
const onlineClusters = clusters.filter(c => c.isOnline);
const offlineClusters = clusters.filter(c => !c.isOnline);
Expand Down
3 changes: 1 addition & 2 deletions src/routes/ApiDebug.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ApiFactory } from "./ApiFactory.js";
import { Request, Response } from "express";
import { getRealIP } from "../Server.js";
import { Utilities } from "../Utilities.js";
import { FileList } from "../FileList.js";
import { Config } from "../Config.js";
Expand Down Expand Up @@ -39,7 +38,7 @@ export class ApiDebug {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(Array.from(inst.server.io.sockets.sockets).map(([id, socket]) => ({
session: id,
ip: getRealIP(socket.handshake.headers) || socket.handshake.address,
ip: Utilities.getRealIP(socket.handshake.headers) || socket.handshake.address,
cluster: inst.server.sessionToClusterMap.get(id)?.getJson(true, true)
}))));
});
Expand Down

0 comments on commit 5d3de24

Please sign in to comment.