Files
fail2ban-ui/pkg/web/static/js/console.js

208 lines
7.2 KiB
JavaScript
Raw Normal View History

2026-02-15 23:57:01 +01:00
// Console output handler (websocket log stream and rendering).
"use strict";
2026-02-15 23:57:01 +01:00
// =========================================================================
// Global Variables
// =========================================================================
let consoleOutputContainer = null;
let consoleOutputElement = null;
2026-02-15 23:57:01 +01:00
let maxConsoleLines = 1000;
let wasConsoleEnabledOnLoad = false;
// =========================================================================
// Initialization
// =========================================================================
2026-02-15 23:57:01 +01:00
// Initialize the console output container and connect to the websocket
function initConsoleOutput() {
consoleOutputContainer = document.getElementById('consoleOutputContainer');
consoleOutputElement = document.getElementById('consoleOutputWindow');
2026-02-15 23:57:01 +01:00
if (!consoleOutputContainer || !consoleOutputElement) {
return;
}
if (typeof wsManager !== 'undefined' && wsManager) {
wsManager.onConsoleLog(function(message, timestamp) {
appendConsoleLog(message, timestamp);
});
} else {
2026-02-15 23:57:01 +01:00
// Wait for websocket manager to be available
const wsCheckInterval = setInterval(function() {
if (typeof wsManager !== 'undefined' && wsManager) {
wsManager.onConsoleLog(function(message, timestamp) {
appendConsoleLog(message, timestamp);
});
clearInterval(wsCheckInterval);
}
}, 100);
2026-02-15 23:57:01 +01:00
// Timeout after 5 seconds if websocket manager is not available
setTimeout(function() {
clearInterval(wsCheckInterval);
}, 5000);
}
}
2026-02-15 23:57:01 +01:00
// Toggle the console output container
function toggleConsoleOutput(userClicked) {
const checkbox = document.getElementById('consoleOutput');
const container = document.getElementById('consoleOutputContainer');
2026-02-15 23:57:01 +01:00
if (!checkbox || !container) {
return;
}
2026-02-15 23:57:01 +01:00
if (checkbox.checked) {
2026-02-15 23:57:01 +01:00
// Show the console output container
container.classList.remove('hidden');
if (!consoleOutputElement) {
initConsoleOutput();
} else {
if (typeof wsManager !== 'undefined' && wsManager) {
if (!wsManager.consoleLogCallbacks) {
wsManager.consoleLogCallbacks = [];
}
let callbackExists = false;
for (let i = 0; i < wsManager.consoleLogCallbacks.length; i++) {
if (wsManager.consoleLogCallbacks[i].toString().includes('appendConsoleLog')) {
callbackExists = true;
break;
}
}
if (!callbackExists) {
wsManager.onConsoleLog(function(message, timestamp) {
appendConsoleLog(message, timestamp);
});
}
}
}
2026-02-15 23:57:01 +01:00
const consoleEl = document.getElementById('consoleOutputWindow');
2026-02-15 23:57:01 +01:00
// Show save hint only if user just clicked to enable (not on page load)
if (consoleEl && userClicked && !wasConsoleEnabledOnLoad) {
const placeholder = consoleEl.querySelector('.text-gray-500');
if (placeholder && placeholder.textContent === 'Console output will appear here...') {
placeholder.remove();
}
const hintDiv = document.createElement('div');
hintDiv.className = 'text-yellow-400 italic text-center py-4';
hintDiv.id = 'consoleSaveHint';
const hintText = typeof t !== 'undefined' ? t('settings.console.save_hint', 'Please save your settings first before logs will be displayed here.') : 'Please save your settings first before logs will be displayed here.';
hintDiv.textContent = hintText;
consoleEl.appendChild(hintDiv);
} else if (consoleEl) {
const placeholder = consoleEl.querySelector('.text-gray-500');
2026-02-15 23:57:01 +01:00
// Remove placeholder if it exists
if (placeholder && placeholder.textContent === 'Console output will appear here...') {
placeholder.remove();
}
}
} else {
2026-02-15 23:57:01 +01:00
// Hide the console output container
container.classList.add('hidden');
}
}
2026-02-15 23:57:01 +01:00
// Auto-start console if enabled on load
if (typeof window !== 'undefined') {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
const checkbox = document.getElementById('consoleOutput');
if (checkbox && checkbox.checked) {
wasConsoleEnabledOnLoad = true;
toggleConsoleOutput(false);
}
initConsoleOutput();
});
} else {
const checkbox = document.getElementById('consoleOutput');
if (checkbox && checkbox.checked) {
wasConsoleEnabledOnLoad = true;
toggleConsoleOutput(false);
}
initConsoleOutput();
}
}
// =========================================================================
// Log Rendering / Core Functionality
// =========================================================================
function appendConsoleLog(message, timestamp) {
if (!consoleOutputElement) {
consoleOutputElement = document.getElementById('consoleOutputWindow');
}
if (!consoleOutputElement) {
return;
}
2026-02-15 23:57:01 +01:00
// Remove placeholder if it exists
const placeholder = consoleOutputElement.querySelector('.text-gray-500');
if (placeholder && placeholder.textContent === 'Console output will appear here...') {
placeholder.remove();
}
2026-02-15 23:57:01 +01:00
// Remove save hint if it exists
const saveHint = document.getElementById('consoleSaveHint');
if (saveHint) {
saveHint.remove();
}
2026-02-15 23:57:01 +01:00
// Create new log line element with timestamp
const logLine = document.createElement('div');
logLine.className = 'text-green-400 leading-relaxed';
let timeStr = '';
if (timestamp) {
try {
const date = new Date(timestamp);
timeStr = '<span class="text-gray-500">[' + date.toLocaleTimeString() + ']</span> ';
2026-02-15 23:57:01 +01:00
} catch (e) {}
}
2026-02-15 23:57:01 +01:00
// Escape message to prevent XSS
let escapedMessage = message;
if (typeof escapeHtml === 'function') {
escapedMessage = escapeHtml(escapedMessage);
} else {
escapedMessage = escapedMessage
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
2026-02-15 23:57:01 +01:00
// Set different colors for different log levels using patterns below.
// Default is green.
let logClass = 'text-green-400';
var isConfigDump = /SSH command output\b/.test(message) && /Fail2Ban-UI Managed Configuration|jail\.local|action_mwlg/.test(message);
if (!isConfigDump) {
if (/❌/.test(message) || /\b(?:error|fatal)\s*:/i.test(message) || /\bfailed\s+to\b/i.test(message)) {
logClass = 'text-red-400';
} else if (/⚠️/.test(message) || /\b(?:warning|warn)\s*:/i.test(message)) {
logClass = 'text-yellow-400';
} else if (/✅/.test(message) || /\b(?:info|debug)\s*:/i.test(message) || /\bsuccessfully\b/i.test(message)) {
logClass = 'text-blue-400';
}
}
logLine.className = logClass + ' leading-relaxed';
2026-02-15 23:57:01 +01:00
// Build complete log line with timestamp and message
logLine.innerHTML = timeStr + escapedMessage;
2026-02-15 23:57:01 +01:00
// Add log line to console
consoleOutputElement.appendChild(logLine);
2026-02-15 23:57:01 +01:00
const lines = consoleOutputElement.children;
if (lines.length > maxConsoleLines) {
consoleOutputElement.removeChild(lines[0]);
}
consoleOutputElement.scrollTop = consoleOutputElement.scrollHeight;
}
2026-02-15 23:57:01 +01:00
// Clear the console
function clearConsole() {
if (!consoleOutputElement) {
consoleOutputElement = document.getElementById('consoleOutputWindow');
}
if (consoleOutputElement) {
consoleOutputElement.textContent = '';
}
}