UNPKG

@vladmandic/piproxy

Version:

Reverse HTTP/HTTPS/HTTP2 Proxy in NodeJS with SSL Certificate Management, Compression, Security Enforcement and Rate Limiting

70 lines (66 loc) 3.04 kB
import * as log from '@vladmandic/pilogger'; import type { TLSSocket } from 'tls'; import * as geoip from './geoip'; import type { Req } from './server'; export class Record { timestamp: Date | undefined; method: string | undefined; protocol: string | undefined; status: number | undefined; scheme: string | undefined; host: string | undefined; url: string | undefined; ip: string | undefined; length: string | undefined; agent: string[] | undefined; device: string | undefined; country: string | undefined; continent: string | undefined; city: string | undefined; asn: string | undefined; lat: number | undefined; lon: number | undefined; accuracy: number | undefined; etag: string | undefined; mime: string | undefined; cookie: boolean | undefined; jwt: boolean | undefined; duration: number | undefined; constructor(clientReq: Req, proxyReq: Req) { const head = clientReq.headers; const agent = (clientReq.headers['user-agent'] || '').replace('(KHTML, like Gecko)', '').replace('Mozilla/5.0', '').replace('/ /g', ' '); const device = agent.match(/\((.*)\)/); this.device = device && device.length > 0 ? device[1] : undefined; this.agent = agent.replace(/\(.*\)/, '').replace(/ /g, ' ').trim().split(' '); // @ts-ignore optional and rare const peer = clientReq.socket._peername; // eslint-disable-line no-underscore-dangle this.ip = peer?.address || clientReq?.socket?.remoteAddress; const geo = geoip.get(this.ip || '127.0.0.1'); this.country = geo.country; this.continent = geo.continent; this.city = geo.city; this.asn = geo.asn; this.lat = geo.lat; this.lon = geo.lon; this.scheme = head[':scheme'] as string || ((clientReq.socket as TLSSocket).encrypted ? 'https' : 'http'); this.host = head[':authority'] as string || head.host; this.length = proxyReq.headers ? (proxyReq.headers['content-length'] || proxyReq.headers['content-size']) as string : undefined; this.etag = proxyReq.headers ? proxyReq.headers['etag'] : undefined; this.mime = proxyReq.headers ? proxyReq.headers['content-type'] : undefined; this.cookie = head['cookie'] ? true : undefined; this.jwt = head['authorization'] ? true : undefined; this.method = clientReq.method; this.protocol = (clientReq.socket as TLSSocket).alpnProtocol || clientReq.httpVersion; // @ts-ignore yes it exists this.status = proxyReq.statusCode; this.url = clientReq.url || ''; if (this.url.length > 64) this.url = this.url.substring(0, 64) + '...'; this.duration = clientReq.headers['timestamp'] ? Number((process.hrtime.bigint() - BigInt(clientReq.headers['timestamp'] as string || 0)) / 1000000n) : 0; } } export default function logger(clientReq: Req, proxyReq: Req) { const record = new Record(clientReq, proxyReq); const data = Object.fromEntries(Object.entries(record).filter(([_key, val]) => val)); // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars log.data(data); return record; }