Chages that enables testing logpaths before saving and making multiple attempts to create correct patterns

This commit is contained in:
2025-12-06 00:20:20 +01:00
parent f23d202e0d
commit 5a3c59ae0d
3 changed files with 74 additions and 21 deletions

View File

@@ -861,6 +861,7 @@ func equalStringSlices(a, b []string) bool {
// TestLogpathHandler tests a logpath and returns matching files
// Resolves Fail2Ban variables before testing
// Accepts optional logpath in request body, otherwise reads from saved jail config
func TestLogpathHandler(c *gin.Context) {
config.DebugLog("----------------------------")
config.DebugLog("TestLogpathHandler called (handlers.go)") // entry point
@@ -871,22 +872,40 @@ func TestLogpathHandler(c *gin.Context) {
return
}
// Get jail config to extract logpath
jailCfg, err := conn.GetJailConfig(c.Request.Context(), jail)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load jail config: " + err.Error()})
return
var originalLogpath string
// Check if logpath is provided in request body
var reqBody struct {
Logpath string `json:"logpath"`
}
if err := c.ShouldBindJSON(&reqBody); err == nil && reqBody.Logpath != "" {
// Use logpath from request body (from textarea)
originalLogpath = strings.TrimSpace(reqBody.Logpath)
config.DebugLog("Using logpath from request body: %s", originalLogpath)
} else {
// Fall back to reading from saved jail config
jailCfg, err := conn.GetJailConfig(c.Request.Context(), jail)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load jail config: " + err.Error()})
return
}
// Extract logpath from jail config
originalLogpath = fail2ban.ExtractLogpathFromJailConfig(jailCfg)
if originalLogpath == "" {
c.JSON(http.StatusOK, gin.H{
"original_logpath": "",
"resolved_logpath": "",
"files": []string{},
"message": "No logpath configured for this jail",
})
return
}
config.DebugLog("Using logpath from saved jail config: %s", originalLogpath)
}
// Extract logpath from jail config
originalLogpath := fail2ban.ExtractLogpathFromJailConfig(jailCfg)
if originalLogpath == "" {
c.JSON(http.StatusOK, gin.H{
"original_logpath": "",
"resolved_logpath": "",
"files": []string{},
"message": "No logpath configured for this jail",
})
c.JSON(http.StatusBadRequest, gin.H{"error": "No logpath provided"})
return
}

View File

@@ -132,9 +132,35 @@ function saveJailConfig() {
});
}
// Extract logpath from jail config text
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;
}
return '';
}
function testLogpath() {
if (!currentJailForConfig) return;
// Extract logpath from the textarea
var jailTextArea = document.getElementById('jailConfigTextarea');
var jailConfig = jailTextArea ? jailTextArea.value : '';
var logpath = extractLogpathFromConfig(jailConfig);
if (!logpath) {
showToast('No logpath found in jail configuration. Please add a logpath line (e.g., logpath = /var/log/example.log)', 'warning');
return;
}
var resultsDiv = document.getElementById('logpathResults');
resultsDiv.textContent = 'Testing logpath...';
resultsDiv.classList.remove('hidden');
@@ -145,6 +171,7 @@ function testLogpath() {
fetch(withServerParam(url), {
method: 'POST',
headers: serverHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify({ logpath: logpath })
})
.then(function(res) { return res.json(); })
.then(function(data) {
@@ -163,28 +190,35 @@ function testLogpath() {
var resolvedLogpath = data.resolved_logpath || '';
var files = data.files || [];
// Build output message
// Build output message with better formatting
var output = '';
// Show original logpath
if (originalLogpath) {
output += 'Logpath:\n ' + originalLogpath + '\n\n';
}
// Show resolved logpath if different from original
if (resolvedLogpath && resolvedLogpath !== originalLogpath) {
output += 'Resolved logpath: ' + resolvedLogpath + '\n\n';
output += 'Resolved logpath:\n ' + resolvedLogpath + '\n\n';
} else if (resolvedLogpath) {
output += 'Logpath: ' + resolvedLogpath + '\n\n';
} else if (originalLogpath) {
output += 'Logpath: ' + originalLogpath + '\n\n';
//output += 'Logpath:\n ' + resolvedLogpath + '\n\n';
}
// Show files found
// Show files found with better formatting
if (files.length === 0) {
output += 'No files found matching the logpath pattern.';
resultsDiv.classList.remove('text-red-600');
resultsDiv.classList.add('text-yellow-600');
} else {
output += 'Found ' + files.length + ' file(s):\n' + files.join('\n');
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');
}
// Use textContent for plain text, but we could also use innerHTML for better formatting
resultsDiv.textContent = output;
// Auto-scroll to results

View File

@@ -805,7 +805,7 @@
class="inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-600 text-sm font-medium text-white hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"
onclick="testLogpath()"
data-i18n="modal.test_logpath">Test Logpath</button>
<div id="logpathResults" class="mt-2 p-3 bg-gray-100 rounded-md text-sm font-mono max-h-32 overflow-y-auto hidden"></div>
<pre id="logpathResults" class="mt-2 p-3 bg-gray-100 rounded-md text-sm font-mono max-h-32 overflow-y-auto hidden"></pre>
</div>
</div>
</div>