166 lines
3.8 KiB
JavaScript
Executable File
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,
|
|
};
|