Files

166 lines
3.8 KiB
JavaScript
Executable File

// programs/log.js
'use strict';
const fs = require('fs');
const path = require('path');
// --- configuration ---
const LOG_DIR = path.join(__dirname, '..', 'logs');
fs.mkdirSync(LOG_DIR, { recursive: true });
function getLogFilePath(d = new Date()) {
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
return path.join(LOG_DIR, `${yyyy}_${mm}_${dd}.txt`);
}
function write(obj) {
const line = JSON.stringify(obj) + '\n';
fs.appendFile(getLogFilePath(), line, (err) => {
if (err) console.error('[log] write error:', err);
});
}
// --- common extractors ---
function commonFromReq(req) {
try {
const xff = req?.headers?.['x-forwarded-for'];
const xRealIp = req?.headers?.['x-real-ip'];
const ipFromXff = xff ? xff.split(',')[0].trim() : null;
const ip =
ipFromXff ||
xRealIp ||
req?.ip ||
req?.socket?.remoteAddress ||
null;
const tls =
req?.socket?.encrypted
? {
protocol:
typeof req.socket.getProtocol === 'function'
? req.socket.getProtocol()
: null,
cipher:
typeof req.socket.getCipher === 'function'
? (req.socket.getCipher() || {}).name
: null,
}
: null;
// MAC is not available across routed networks
const mac = null;
return {
ip,
ips: Array.isArray(req?.ips) ? req.ips : [],
xff: xff || null,
remoteAddress: req?.socket?.remoteAddress || null,
remoteFamily: req?.socket?.remoteFamily || null,
userAgent: req?.headers?.['user-agent'] || null,
acceptLanguage: req?.headers?.['accept-language'] || null,
secChUa: req?.headers?.['sec-ch-ua'] || null,
secChUaPlatform: req?.headers?.['sec-ch-ua-platform'] || null,
secChUaMobile: req?.headers?.['sec-ch-ua-mobile'] || null,
referer: req?.headers?.['referer'] || null,
tls,
mac,
};
} catch {
return {};
}
}
function commonFromSocket(socket) {
return {
remoteAddress: socket?.remoteAddress || null,
remoteFamily: socket?.remoteFamily || null,
};
}
// --- specific log functions ---
function logHttpRequest(req) {
write({
ts: new Date().toISOString(),
type: 'http',
method: req?.method || null,
url: (req?.originalUrl ?? req?.url) || null,
...commonFromReq(req),
});
}
function logTcpConnection(socket) {
write({
ts: new Date().toISOString(),
type: 'tcp',
...commonFromSocket(socket),
});
}
function logHttpUpgrade(req) {
write({
ts: new Date().toISOString(),
type: 'http-upgrade',
url: req?.url || null,
...commonFromReq(req),
});
}
function logWssConnected(req) {
write({
ts: new Date().toISOString(),
type: 'wss',
url: req?.url || null,
...commonFromReq(req),
});
}
function logWssClosed(req, code, reason) {
write({
ts: new Date().toISOString(),
type: 'wss-close',
url: req?.url || null,
code: typeof code === 'number' ? code : null,
reason: reason ? reason.toString() : null,
...commonFromReq(req),
});
}
function logSnapshot(python, response){
write({
ts: new Date().toISOString(),
type: 'snapshot',
command: python.toString(),
wsResponse: response.toString()
})
}
// --- generic hooks you requested ---
function connected(context = {}) {
write({
ts: new Date().toISOString(),
type: 'connected',
...context,
});
}
function connectionLost(context = {}) {
write({
ts: new Date().toISOString(),
type: 'connection-lost',
...context,
});
}
module.exports = {
logHttpRequest,
logTcpConnection,
logHttpUpgrade,
logWssConnected,
logSnapshot,
logWssClosed,
connected,
connectionLost,
};