import * as plugins from '../../plugins.js'; /** * WrappedSocket wraps a regular net.Socket to provide transparent access * to the real client IP and port when behind a proxy using PROXY protocol. * * This is the FOUNDATION for all PROXY protocol support and must be implemented * before any protocol parsing can occur. * * This implementation uses a Proxy to delegate all properties and methods * to the underlying socket while allowing override of specific properties. */ export class WrappedSocket { public readonly socket: plugins.net.Socket; private realClientIP?: string; private realClientPort?: number; // Make TypeScript happy by declaring the Socket methods that will be proxied [key: string]: any; constructor( socket: plugins.net.Socket, realClientIP?: string, realClientPort?: number ) { this.socket = socket; this.realClientIP = realClientIP; this.realClientPort = realClientPort; // Create a proxy that delegates everything to the underlying socket return new Proxy(this, { get(target, prop, receiver) { // Override specific properties if (prop === 'remoteAddress') { return target.remoteAddress; } if (prop === 'remotePort') { return target.remotePort; } if (prop === 'socket') { return target.socket; } if (prop === 'realClientIP') { return target.realClientIP; } if (prop === 'realClientPort') { return target.realClientPort; } if (prop === 'isFromTrustedProxy') { return target.isFromTrustedProxy; } if (prop === 'setProxyInfo') { return target.setProxyInfo.bind(target); } // For all other properties/methods, delegate to the underlying socket const value = target.socket[prop as keyof plugins.net.Socket]; if (typeof value === 'function') { return value.bind(target.socket); } return value; }, set(target, prop, value) { // Set on the underlying socket (target.socket as any)[prop] = value; return true; } }) as any; } /** * Returns the real client IP if available, otherwise the socket's remote address */ get remoteAddress(): string | undefined { return this.realClientIP || this.socket.remoteAddress; } /** * Returns the real client port if available, otherwise the socket's remote port */ get remotePort(): number | undefined { return this.realClientPort || this.socket.remotePort; } /** * Indicates if this connection came through a trusted proxy */ get isFromTrustedProxy(): boolean { return !!this.realClientIP; } /** * Updates the real client information (called after parsing PROXY protocol) */ setProxyInfo(ip: string, port: number): void { this.realClientIP = ip; this.realClientPort = port; } }