fix: grep nginx logs directly in /logs/:ip endpoint
Records now works without running a scan first. If logs aren't cached in memory from a scan, the endpoint greps the nginx access logs directly for [Client IP] matches and returns the last 500 lines. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -490,12 +490,29 @@ app.get('/api/f2b/poll', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ── Routes: Nginx log viewer ──────────────────────────────────────────────────
|
// ── Routes: Nginx log viewer ──────────────────────────────────────────────────
|
||||||
app.get('/logs/:ip', (req, res) => {
|
app.get('/logs/:ip', async (req, res) => {
|
||||||
const ip = req.params.ip;
|
const ip = req.params.ip;
|
||||||
const logs = ipLogs.get(ip) || [];
|
|
||||||
const hist = banHistory.get(ip);
|
const hist = banHistory.get(ip);
|
||||||
const esc = s => String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
const esc = s => String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||||
|
|
||||||
|
let logs = ipLogs.get(ip) || [];
|
||||||
|
|
||||||
|
// If no logs in memory, grep nginx logs directly
|
||||||
|
if (logs.length === 0) {
|
||||||
|
try {
|
||||||
|
const files = fs.readdirSync(LOG_DIR)
|
||||||
|
.filter(f => f.startsWith('proxy-host-') && f.endsWith('_access.log'))
|
||||||
|
.map(f => path.join(LOG_DIR, f));
|
||||||
|
|
||||||
|
const ipEscaped = ip.replace(/\./g, '\\.');
|
||||||
|
const grepCmd = `grep -h "\\[Client ${ipEscaped}\\]" ${files.join(' ')} 2>/dev/null || true`;
|
||||||
|
const output = await run(grepCmd);
|
||||||
|
logs = output.trim().split('\n').filter(l => l.trim()).slice(-500); // last 500 lines
|
||||||
|
} catch (e) {
|
||||||
|
logs = [`[Error reading logs: ${e.message}]`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let badge = '';
|
let badge = '';
|
||||||
if (hist) badge = `<div class="hi" style="margin:.5rem 0">⚠ Previously banned ${hist.banCount}x — last ${new Date(hist.lastSeen).toLocaleString()}</div>`;
|
if (hist) badge = `<div class="hi" style="margin:.5rem 0">⚠ Previously banned ${hist.banCount}x — last ${new Date(hist.lastSeen).toLocaleString()}</div>`;
|
||||||
|
|
||||||
@@ -508,8 +525,8 @@ app.get('/logs/:ip', (req, res) => {
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-title">// LOG ENTRIES</div>
|
<div class="box-title">// LOG ENTRIES</div>
|
||||||
${badge}
|
${badge}
|
||||||
<p class="muted">Entries in current scan window: ${logs.length}</p>
|
<p class="muted">Entries found: ${logs.length}</p>
|
||||||
<pre>${logs.map(esc).join('\n') || '(no entries — run a scan first)'}</pre>
|
<pre>${logs.map(esc).join('\n') || '(no entries found)'}</pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="prompt">_ <span class="blink">█</span></div>
|
<div class="prompt">_ <span class="blink">█</span></div>
|
||||||
<footer>F2B Control Center | :${process.env.PORT || 4000}</footer>
|
<footer>F2B Control Center | :${process.env.PORT || 4000}</footer>
|
||||||
|
|||||||
Reference in New Issue
Block a user