diff --git a/pkg/web/static/js/jails.js b/pkg/web/static/js/jails.js index f64202b..8a18327 100644 --- a/pkg/web/static/js/jails.js +++ b/pkg/web/static/js/jails.js @@ -75,6 +75,14 @@ function openJailConfigModal(jailName) { // Check if logpath is set in jail config and show test button updateLogpathButtonVisibility(); + // Show hint for local servers + var localServerHint = document.getElementById('localServerLogpathHint'); + if (localServerHint && currentServer && currentServer.type === 'local') { + localServerHint.classList.remove('hidden'); + } else if (localServerHint) { + localServerHint.classList.add('hidden'); + } + // Add listener to update button visibility when jail config changes jailTextArea.addEventListener('input', updateLogpathButtonVisibility); @@ -102,11 +110,22 @@ function updateLogpathButtonVisibility() { var jailConfig = jailTextArea ? jailTextArea.value : ''; var hasLogpath = /logpath\s*=/i.test(jailConfig); var testSection = document.getElementById('testLogpathSection'); + var localServerHint = document.getElementById('localServerLogpathHint'); + if (hasLogpath && testSection) { testSection.classList.remove('hidden'); + // Show hint for local servers + if (localServerHint && currentServer && currentServer.type === 'local') { + localServerHint.classList.remove('hidden'); + } else if (localServerHint) { + localServerHint.classList.add('hidden'); + } } else if (testSection) { testSection.classList.add('hidden'); document.getElementById('logpathResults').classList.add('hidden'); + if (localServerHint) { + localServerHint.classList.add('hidden'); + } } } @@ -149,19 +168,68 @@ function saveJailConfig() { } // Extract logpath from jail config text +// Supports multiple logpaths in a single line (space-separated) or multiple lines +// Fail2ban supports both formats: +// logpath = /var/log/file1.log /var/log/file2.log +// logpath = /var/log/file1.log +// /var/log/file2.log function extractLogpathFromConfig(configText) { if (!configText) return ''; - // Match logpath = value (handles various formats) - var logpathMatch = configText.match(/^logpath\s*=\s*(.+)$/im); - if (logpathMatch && logpathMatch[1]) { - // Trim whitespace and remove quotes if present - var logpath = logpathMatch[1].trim(); - // Remove surrounding quotes - logpath = logpath.replace(/^["']|["']$/g, ''); - return logpath; + var logpaths = []; + var lines = configText.split('\n'); + var inLogpathLine = false; + var currentLogpath = ''; + + for (var i = 0; i < lines.length; i++) { + var line = lines[i].trim(); + // Skip comments + if (line.startsWith('#')) { + continue; + } + + // Check if this line starts with logpath = + var logpathMatch = line.match(/^logpath\s*=\s*(.+)$/i); + if (logpathMatch && logpathMatch[1]) { + // Trim whitespace and remove quotes if present + currentLogpath = logpathMatch[1].trim(); + currentLogpath = currentLogpath.replace(/^["']|["']$/g, ''); + inLogpathLine = true; + } else if (inLogpathLine) { + // Continuation line (indented or starting with space) + // Fail2ban allows continuation lines for logpath + if (line !== '' && !line.includes('=')) { + // This is a continuation line, append to current logpath + currentLogpath += ' ' + line.trim(); + } else { + // End of logpath block, process current logpath + if (currentLogpath) { + // Split by spaces to handle multiple logpaths in one line + var paths = currentLogpath.split(/\s+/).filter(function(p) { return p.length > 0; }); + logpaths = logpaths.concat(paths); + currentLogpath = ''; + } + inLogpathLine = false; + } + } else if (inLogpathLine && line === '') { + // Empty line might end the logpath block + if (currentLogpath) { + var paths = currentLogpath.split(/\s+/).filter(function(p) { return p.length > 0; }); + logpaths = logpaths.concat(paths); + currentLogpath = ''; + } + inLogpathLine = false; + } } - return ''; + + // Process any remaining logpath + if (currentLogpath) { + var paths = currentLogpath.split(/\s+/).filter(function(p) { return p.length > 0; }); + logpaths = logpaths.concat(paths); + } + + // Join multiple logpaths with newlines + return logpaths.join('\n'); } function testLogpath() { @@ -203,39 +271,88 @@ function testLogpath() { } var originalLogpath = data.original_logpath || ''; - var resolvedLogpath = data.resolved_logpath || ''; - var files = data.files || []; + var results = data.results || []; + var isLocalServer = data.is_local_server || false; - // Build output message with better formatting + // Build HTML output with visual indicators var output = ''; - // Show original logpath - if (originalLogpath) { - output += 'Logpath:\n ' + originalLogpath + '\n\n'; + if (results.length === 0) { + output = '
No logpath entries found.
'; + resultsDiv.innerHTML = output; + resultsDiv.classList.add('text-yellow-600'); + return; } - // Show resolved logpath if different from original - if (resolvedLogpath && resolvedLogpath !== originalLogpath) { - output += 'Resolved logpath:\n ' + resolvedLogpath + '\n\n'; - } else if (resolvedLogpath) { - //output += 'Logpath:\n ' + resolvedLogpath + '\n\n'; - } + // Process each logpath result + results.forEach(function(result, idx) { + var logpath = result.logpath || ''; + var resolvedPath = result.resolved_path || ''; + var found = result.found || false; + var files = result.files || []; + var error = result.error || ''; + + if (idx > 0) { + output += '
'; + } + + output += '
'; + output += '
Logpath ' + (idx + 1) + ':
'; + output += '
' + escapeHtml(logpath) + '
'; + + if (resolvedPath && resolvedPath !== logpath) { + output += '
Resolved: ' + escapeHtml(resolvedPath) + '
'; + } + output += '
'; + + // Test results + output += '
'; + output += '
'; + if (isLocalServer) { + output += 'In fail2ban-ui Container:'; + } else { + output += 'On Remote Server:'; + } + if (error) { + output += ''; + output += 'Error: ' + escapeHtml(error) + ''; + } else if (found) { + output += ''; + output += 'Found ' + files.length + ' file(s)'; + } else { + output += ''; + if (isLocalServer) { + output += 'Not found (logs may not be mounted to container)'; + } else { + output += 'Not found'; + } + } + output += '
'; + if (files.length > 0) { + output += '
'; + files.forEach(function(file) { + output += '
• ' + escapeHtml(file) + '
'; + }); + output += '
'; + } + output += '
'; + }); - // Show files found with better formatting - if (files.length === 0) { - output += 'No files found matching the logpath pattern.'; + // Set overall status color + var allFound = results.every(function(r) { return r.found; }); + var anyFound = results.some(function(r) { return r.found; }); + + if (allFound) { + resultsDiv.classList.remove('text-red-600', 'text-yellow-600'); + } else if (anyFound) { resultsDiv.classList.remove('text-red-600'); resultsDiv.classList.add('text-yellow-600'); } else { - output += 'Found ' + files.length + ' file(s):\n\n'; - files.forEach(function(file, index) { - output += ' ' + (index + 1) + '. ' + file + '\n'; - }); - resultsDiv.classList.remove('text-red-600', 'text-yellow-600'); + resultsDiv.classList.remove('text-yellow-600'); + resultsDiv.classList.add('text-red-600'); } - // Use textContent for plain text, but we could also use innerHTML for better formatting - resultsDiv.textContent = output; + resultsDiv.innerHTML = output; // Auto-scroll to results setTimeout(function() { diff --git a/pkg/web/templates/index.html b/pkg/web/templates/index.html index 1716c06..e523b3e 100644 --- a/pkg/web/templates/index.html +++ b/pkg/web/templates/index.html @@ -1028,11 +1028,14 @@