Merge pull request #1664 from master3395/v2.5.5-dev

…tent-type, fix IP validation, and add comprehensive logging

- Fixed IP validation logic in blockIPAddress function
- Added proper JSON content-type header in firewallManager.py addBannedIP response
- Improved error handling with try-catch wrapper
- Added comprehensive console logging for debugging
- Fixed button onclick handler interference with ng-click
- Added $scope.$apply() calls for proper AngularJS view updates
- Enhanced error message parsing and display
- Fixed duplicate error notification prevention
This commit is contained in:
Master3395
2026-01-29 01:05:12 +01:00
committed by GitHub
3 changed files with 377 additions and 43 deletions

View File

@@ -1011,8 +1011,84 @@ app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
};
$scope.blockIPAddress = function(ipAddress) {
if (!$scope.blockingIP) {
$scope.blockingIP = ipAddress;
try {
console.log('========================================');
console.log('=== blockIPAddress CALLED ===');
console.log('========================================');
console.log('blockIPAddress called with:', ipAddress);
console.log('ipAddress type:', typeof ipAddress);
console.log('ipAddress value:', ipAddress);
console.log('$scope:', $scope);
console.log('$scope.blockIPAddress:', typeof $scope.blockIPAddress);
// Validate IP address parameter
if (!ipAddress) {
console.error('No IP address provided:', ipAddress);
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error',
text: 'No IP address provided',
type: 'error',
delay: 5000
});
}
return;
}
// Ensure it's a string and trim it
ipAddress = String(ipAddress).trim();
// Validate after trimming
if (!ipAddress || ipAddress === '' || ipAddress === 'undefined' || ipAddress === 'null') {
console.error('IP address is empty or invalid after trim:', ipAddress);
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error',
text: 'Invalid IP address provided: ' + ipAddress,
type: 'error',
delay: 5000
});
}
return;
}
// Basic IP format validation
var ipPattern = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/;
if (!ipPattern.test(ipAddress)) {
console.error('IP address format is invalid:', ipAddress);
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error',
text: 'Invalid IP address format: ' + ipAddress,
type: 'error',
delay: 5000
});
}
return;
}
// Prevent duplicate requests
if ($scope.blockingIP === ipAddress) {
console.log('Already processing IP:', ipAddress);
return; // Already processing this IP
}
// Check if already blocked
if ($scope.blockedIPs && $scope.blockedIPs[ipAddress]) {
console.log('IP already blocked:', ipAddress);
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Info',
text: `IP address ${ipAddress} is already banned`,
type: 'info',
delay: 3000
});
}
return;
}
// Set blocking flag to prevent duplicate requests
$scope.blockingIP = ipAddress;
// Use the new Banned IPs system instead of the old blockIPAddress
var data = {
@@ -1027,48 +1103,265 @@ app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
}
};
console.log('Sending ban IP request:', data);
console.log('CSRF Token:', getCookie('csrftoken'));
console.log('Config:', config);
$http.post('/firewall/addBannedIP', data, config).then(function (response) {
console.log('=== addBannedIP SUCCESS ===');
console.log('Full response:', response);
console.log('response.data:', response.data);
console.log('response.data type:', typeof response.data);
console.log('response.status:', response.status);
// Reset blocking flag
$scope.blockingIP = null;
if (response.data && response.data.status === 1) {
// Apply scope changes
if (!$scope.$$phase && !$scope.$root.$$phase) {
$scope.$apply();
}
// Handle both JSON string and object responses
var responseData = response.data;
if (typeof responseData === 'string') {
try {
responseData = JSON.parse(responseData);
console.log('Parsed responseData from string:', responseData);
} catch (e) {
console.error('Failed to parse response as JSON:', e);
console.error('Raw response string:', responseData);
// Try to extract error from string
if (responseData.includes('error')) {
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error',
text: 'Failed to block IP address: ' + responseData,
type: 'error',
delay: 5000
});
}
return;
}
}
}
console.log('Final responseData:', responseData);
console.log('responseData.status:', responseData ? responseData.status : 'undefined');
console.log('responseData.message:', responseData ? responseData.message : 'undefined');
console.log('responseData.error_message:', responseData ? responseData.error_message : 'undefined');
// Check for success (status === 1 or status === '1')
if (responseData && (responseData.status === 1 || responseData.status === '1')) {
// Mark IP as blocked
if (!$scope.blockedIPs) {
$scope.blockedIPs = {};
}
$scope.blockedIPs[ipAddress] = true;
// Show success notification
new PNotify({
title: 'IP Address Banned',
text: `IP address ${ipAddress} has been permanently banned and added to the firewall. You can manage it in the Firewall > Banned IPs section.`,
type: 'success',
delay: 5000
});
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'IP Address Banned',
text: `IP address ${ipAddress} has been permanently banned and added to the firewall. You can manage it in the Firewall > Banned IPs section.`,
type: 'success',
delay: 5000
});
}
// Refresh security analysis to update alerts
$scope.analyzeSSHSecurity();
if ($scope.analyzeSSHSecurity) {
$scope.analyzeSSHSecurity();
}
// Apply scope changes
if (!$scope.$$phase && !$scope.$root.$$phase) {
$scope.$apply();
}
} else {
// Show error notification
var errorMsg = 'Failed to block IP address';
if (responseData && responseData.error_message) {
errorMsg = responseData.error_message;
} else if (responseData && responseData.error) {
errorMsg = responseData.error;
} else if (responseData && responseData.message) {
errorMsg = responseData.message;
} else if (responseData) {
errorMsg = JSON.stringify(responseData);
}
console.error('Ban IP failed:', errorMsg);
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error',
text: errorMsg,
type: 'error',
delay: 5000
});
}
}
}, function (err) {
$scope.blockingIP = null;
console.error('addBannedIP error:', err);
console.error('Error status:', err.status);
console.error('Error statusText:', err.statusText);
console.error('Error data:', err.data);
// Prevent showing duplicate error notifications
if ($scope.lastErrorIP === ipAddress && $scope.lastErrorTime && (Date.now() - $scope.lastErrorTime) < 2000) {
console.log('Skipping duplicate error notification for IP:', ipAddress);
return;
}
$scope.lastErrorIP = ipAddress;
$scope.lastErrorTime = Date.now();
var errorMessage = 'Failed to block IP address';
if (err.data) {
var errData = err.data;
if (typeof errData === 'string') {
try {
errData = JSON.parse(errData);
} catch (e) {
errorMessage = errData || errorMessage;
}
}
if (errData && typeof errData === 'object') {
if (errData.error_message) {
errorMessage = errData.error_message;
} else if (errData.error) {
errorMessage = errData.error;
} else if (errData.message) {
errorMessage = errData.message;
}
}
} else if (err.statusText) {
errorMessage = err.statusText;
} else if (err.status) {
errorMessage = `HTTP ${err.status}: ${err.statusText || 'Unknown error'}`;
}
console.error('Final error message:', errorMessage);
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error',
text: response.data && response.data.error ? response.data.error : 'Failed to block IP address',
text: errorMessage,
type: 'error',
delay: 5000
});
}
}, function (err) {
$scope.blockingIP = null;
var errorMessage = 'Failed to block IP address';
if (err.data && err.data.error) {
errorMessage = err.data.error;
} else if (err.data && err.data.message) {
errorMessage = err.data.message;
});
} catch (e) {
console.error('========================================');
console.error('=== ERROR in blockIPAddress ===');
console.error('========================================');
console.error('Error:', e);
console.error('Error message:', e.message);
console.error('Error stack:', e.stack);
$scope.blockingIP = null;
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error',
text: 'An error occurred while trying to ban the IP address: ' + (e.message || String(e)),
type: 'error',
delay: 5000
});
}
}
};
// Ban IP from SSH Logs
$scope.banIPFromSSHLog = function(ipAddress) {
if (!ipAddress) {
new PNotify({
title: 'Error',
text: 'No IP address provided',
type: 'error',
delay: 5000
});
return;
}
if ($scope.blockingIP === ipAddress) {
return; // Already processing
}
if ($scope.blockedIPs[ipAddress]) {
new PNotify({
title: 'Info',
text: `IP address ${ipAddress} is already banned`,
type: 'info',
delay: 3000
});
return;
}
$scope.blockingIP = ipAddress;
// Use the Banned IPs system
var data = {
ip: ipAddress,
reason: 'Suspicious activity detected from SSH logs',
duration: 'permanent'
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post('/firewall/addBannedIP', data, config).then(function (response) {
$scope.blockingIP = null;
if (response.data && response.data.status === 1) {
// Mark IP as blocked
$scope.blockedIPs[ipAddress] = true;
// Show success notification
new PNotify({
title: 'IP Address Banned',
text: `IP address ${ipAddress} has been permanently banned and added to the firewall. You can manage it in the Firewall > Banned IPs section.`,
type: 'success',
delay: 5000
});
// Refresh SSH logs to update the UI
$scope.refreshSSHLogs();
} else {
// Show error notification
var errorMsg = 'Failed to ban IP address';
if (response.data && response.data.error_message) {
errorMsg = response.data.error_message;
} else if (response.data && response.data.error) {
errorMsg = response.data.error;
}
new PNotify({
title: 'Error',
text: errorMessage,
text: errorMsg,
type: 'error',
delay: 5000
});
}
}, function (err) {
$scope.blockingIP = null;
var errorMessage = 'Failed to ban IP address';
if (err.data && err.data.error_message) {
errorMessage = err.data.error_message;
} else if (err.data && err.data.error) {
errorMessage = err.data.error;
} else if (err.data && err.data.message) {
errorMessage = err.data.message;
}
new PNotify({
title: 'Error',
text: errorMessage,
type: 'error',
delay: 5000
});
}
});
};
// Initial fetch

View File

@@ -972,22 +972,23 @@
<strong style="font-size: 12px; color: #1e293b;">Recommendation:</strong>
<p style="margin: 4px 0 0 0; font-size: 12px; color: #475569; white-space: pre-line;">{$ alert.recommendation $}</p>
</div>
<!-- Add to Firewall Button for Brute Force Attacks -->
<div ng-if="alert.title === 'Brute Force Attack Detected' && alert.details && alert.details['IP Address']" style="margin-top: 12px;">
<button ng-click="blockIPAddress(alert.details['IP Address'])"
ng-disabled="blockingIP === alert.details['IP Address']"
<!-- Add to Firewall Button for Brute Force Attacks and Root Login Attempts -->
<div ng-if="(alert.title === 'Brute Force Attack Detected' && alert.details && alert.details['IP Address']) || (alert.title === 'Root Login Attempts Detected' && alert.details && alert.details['Top IP'])" style="margin-top: 12px;">
<button ng-click="blockIPAddress(alert.details['IP Address'] || alert.details['Top IP']); $event.stopPropagation(); return false;"
ng-disabled="blockingIP === (alert.details['IP Address'] || alert.details['Top IP'])"
style="background: #dc2626; color: white; border: none; padding: 8px 16px; border-radius: 6px; font-size: 12px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;"
onmouseover="this.style.background='#b91c1c'"
onmouseout="this.style.background='#dc2626'">
<i class="fas fa-ban" ng-if="blockingIP !== alert.details['IP Address']"></i>
<i class="fas fa-spinner fa-spin" ng-if="blockingIP === alert.details['IP Address']"></i>
<span ng-if="blockingIP !== alert.details['IP Address']">Ban IP Permanently</span>
<span ng-if="blockingIP === alert.details['IP Address']">Banning...</span>
onmouseout="this.style.background='#dc2626'"
type="button">
<i class="fas fa-ban" ng-if="blockingIP !== (alert.details['IP Address'] || alert.details['Top IP'])"></i>
<i class="fas fa-spinner fa-spin" ng-if="blockingIP === (alert.details['IP Address'] || alert.details['Top IP'])"></i>
<span ng-if="blockingIP !== (alert.details['IP Address'] || alert.details['Top IP'])">Ban IP</span>
<span ng-if="blockingIP === (alert.details['IP Address'] || alert.details['Top IP'])">Banning...</span>
</button>
<a href="/firewall/" target="_blank" style="margin-left: 10px; color: #5b5fcf; font-size: 12px; text-decoration: none;">
<i class="fas fa-external-link-alt"></i> Manage in Firewall
</a>
<span ng-if="blockedIPs && blockedIPs[alert.details['IP Address']]"
<span ng-if="blockedIPs && blockedIPs[alert.details['IP Address'] || alert.details['Top IP']]"
style="margin-left: 10px; color: #10b981; font-size: 12px; font-weight: 600;">
<i class="fas fa-check-circle"></i> Blocked
</span>
@@ -1015,12 +1016,43 @@
<tr>
<th>TIMESTAMP</th>
<th>MESSAGE</th>
<th>IP ADDRESS</th>
<th>ACTIONS</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="log in sshLogs">
<td>{$ log.timestamp $}</td>
<td>{$ log.message $}</td>
<td>
<span ng-if="log.ip_address" style="font-family: monospace; color: #5b5fcf; font-weight: 600;">
{$ log.ip_address $}
</span>
<span ng-if="!log.ip_address" style="color: #8893a7;">-</span>
</td>
<td>
<button ng-if="log.ip_address && blockingIP !== log.ip_address && !blockedIPs[log.ip_address]"
ng-click="banIPFromSSHLog(log.ip_address)"
style="background: #dc2626; color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 11px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; gap: 4px;"
onmouseover="this.style.background='#b91c1c'"
onmouseout="this.style.background='#dc2626'"
title="Ban this IP address permanently">
<i class="fas fa-ban"></i>
Ban IP
</button>
<button ng-if="log.ip_address && blockingIP === log.ip_address"
disabled
style="background: #9ca3af; color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 11px; font-weight: 600; cursor: not-allowed; display: inline-flex; align-items: center; gap: 4px;">
<i class="fas fa-spinner fa-spin"></i>
Banning...
</button>
<span ng-if="log.ip_address && blockedIPs[log.ip_address]"
style="color: #10b981; font-size: 11px; font-weight: 600; display: inline-flex; align-items: center; gap: 4px;">
<i class="fas fa-check-circle"></i>
Banned
</span>
<span ng-if="!log.ip_address" style="color: #8893a7; font-size: 11px;">-</span>
</td>
</tr>
</tbody>
</table>

View File

@@ -2014,7 +2014,7 @@ class FirewallManager:
try:
admin = Administrator.objects.get(pk=userID)
if admin.acl.adminStatus != 1:
return ACLManager.loadError()
return ACLManager.loadErrorJson('status', 0)
ip = data.get('ip', '').strip()
reason = data.get('reason', '').strip()
@@ -2095,23 +2095,32 @@ class FirewallManager:
command = f'chmod 644 {banned_ips_file} && chown root:root {banned_ips_file}'
ProcessUtilities.executioner(command, None, True)
# Apply firewall rule to block the IP
# Apply firewall rule to block the IP using ProcessUtilities (handles sudo)
try:
# Add iptables rule to block the IP
if '/' in ip:
# CIDR notation
subprocess.run(['iptables', '-A', 'INPUT', '-s', ip, '-j', 'DROP'], check=True)
else:
# Single IP
subprocess.run(['iptables', '-A', 'INPUT', '-s', ip, '-j', 'DROP'], check=True)
# Check if rule already exists to avoid duplicate rules
check_command = f"iptables -C INPUT -s {ip} -j DROP 2>&1"
check_result = ProcessUtilities.executioner(check_command, None, True)
logging.CyberCPLogFileWriter.writeToFile(f'Banned IP {ip} with reason: {reason}')
except subprocess.CalledProcessError as e:
logging.CyberCPLogFileWriter.writeToFile(f'Failed to add iptables rule for {ip}: {str(e)}')
# If rule doesn't exist (check returns non-zero), add it
if check_result != 0:
# Add iptables rule to block the IP using ProcessUtilities (handles sudo)
command = f"iptables -A INPUT -s {ip} -j DROP"
result = ProcessUtilities.executioner(command, None, True)
if result == 0:
logging.CyberCPLogFileWriter.writeToFile(f'Successfully added iptables rule to ban IP {ip} with reason: {reason}')
else:
logging.CyberCPLogFileWriter.writeToFile(f'Warning: Failed to add iptables rule for {ip} (exit code: {result}), but IP was added to banned list')
# Don't fail the entire operation - IP is still in banned list
else:
logging.CyberCPLogFileWriter.writeToFile(f'IPTables rule already exists for {ip}, skipping')
except Exception as e:
logging.CyberCPLogFileWriter.writeToFile(f'Error adding iptables rule for {ip}: {str(e)}, but IP was added to banned list')
# Don't fail the entire operation - IP is still in banned list
final_dic = {'status': 1, 'message': f'IP address {ip} has been banned successfully'}
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
return HttpResponse(final_json, content_type='application/json')
except BaseException as msg:
final_dic = {'status': 0, 'error_message': str(msg)}