diff --git a/baseTemplate/static/baseTemplate/custom-js/system-status.js b/baseTemplate/static/baseTemplate/custom-js/system-status.js index d32b31dbd..fab9a6274 100644 --- a/baseTemplate/static/baseTemplate/custom-js/system-status.js +++ b/baseTemplate/static/baseTemplate/custom-js/system-status.js @@ -1271,6 +1271,99 @@ app.controller('dashboardStatsController', function ($scope, $http, $timeout) { } }; + // 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: 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 + }); + }); + }; + // Ban IP from SSH Logs $scope.banIPFromSSHLog = function(ipAddress) { if (!ipAddress) { diff --git a/baseTemplate/templates/baseTemplate/homePage.html b/baseTemplate/templates/baseTemplate/homePage.html index 6fe4418c5..2a1aef84f 100644 --- a/baseTemplate/templates/baseTemplate/homePage.html +++ b/baseTemplate/templates/baseTemplate/homePage.html @@ -132,6 +132,16 @@ cursor: pointer; } + a.insight-link { + text-decoration: none; + color: inherit; + display: block; + } + + a.insight-link:hover { + color: inherit; + } + .insight-card:hover { transform: translateY(-5px); box-shadow: 0 5px 20px rgba(91,95,207,0.1); @@ -690,38 +700,38 @@

OVERVIEW

-
+
CPU USAGE - 0% + ({$ cpuUsage $}%)
-
+
-
You've 0 Core(s) CPU.
+
You've {$ cpuCores $} Core(s) CPU.
MEMORY USAGE - 0% + ({$ ramUsage $}%)
-
+
-
You've 0 MB Memory.
+
You've {$ ramTotalMB $} MB Memory.
DISK USAGE - 0% + ({$ diskUsage $}%)
-
+
-
You've 0 GB remaining out of 0 GB.
+
You've {$ diskFreeGB $} GB remaining out of {$ diskTotalGB $} GB.
@@ -729,54 +739,54 @@

INSIGHTS

- @@ -972,17 +982,16 @@ Recommendation:

{$ alert.recommendation $}

- -
- @@ -1324,31 +1333,67 @@ }); } - const formData = { - 'csrfmiddlewaretoken': getCookie('csrftoken'), - 'ip_address': ipAddress, - 'reason': 'Brute force attack detected from dashboard' - }; - - $.post('/base/blockIPAddress', formData, function(data) { - if (data.status === 1) { - showNotification('success', data.message); - // Refresh the page to update the blocked IPs list - setTimeout(() => { - location.reload(); - }, 1000); - } else { - showNotification('error', data.message); - } - }).fail(function() { - showNotification('error', 'Failed to block IP address. Please try again.'); - }).always(function() { - // Clear loading state - if (typeof angular !== 'undefined' && angular.element(document.body).scope()) { - var scope = angular.element(document.body).scope(); - scope.$apply(function() { - scope.blockingIP = null; - }); + $.ajax({ + url: '/base/blockIPAddress', + type: 'POST', + contentType: 'application/json', + headers: { + 'X-CSRFToken': getCookie('csrftoken') + }, + data: JSON.stringify({ + 'ip_address': ipAddress, + 'reason': 'Security alert detected from dashboard' + }), + success: function(data) { + // Handle both success and error responses + if (data.status === 1) { + showNotification('success', data.message || 'IP address blocked successfully'); + // Refresh the page to update the blocked IPs list + setTimeout(() => { + location.reload(); + }, 1000); + } else { + // Handle error response - check for both 'error' and 'error_message' fields + var errorMsg = data.error || data.error_message || data.message || 'Failed to block IP address'; + showNotification('error', errorMsg); + } + }, + error: function(xhr, status, error) { + // Handle network errors and parse JSON errors + console.error('Ban IP error:', xhr, status, error); + var errorMsg = 'Failed to block IP address. Please try again.'; + + // Log full response for debugging + console.log('Response status:', xhr.status); + console.log('Response text:', xhr.responseText); + + if (xhr.responseJSON) { + errorMsg = xhr.responseJSON.error || xhr.responseJSON.error_message || xhr.responseJSON.message || errorMsg; + console.log('Parsed error from JSON:', errorMsg); + } else if (xhr.responseText) { + try { + var errorData = JSON.parse(xhr.responseText); + errorMsg = errorData.error || errorData.error_message || errorData.message || errorMsg; + console.log('Parsed error from text:', errorMsg); + } catch(e) { + console.error('Failed to parse error response:', e); + // If parsing fails, try to extract error from response text + if (xhr.responseText.includes('error')) { + errorMsg = xhr.responseText.substring(0, 200); + } + } + } + + showNotification('error', errorMsg); + }, + complete: function() { + // Clear loading state + if (typeof angular !== 'undefined' && angular.element(document.body).scope()) { + var scope = angular.element(document.body).scope(); + scope.$apply(function() { + scope.blockingIP = null; + }); + } } }); } diff --git a/baseTemplate/templates/baseTemplate/index.html b/baseTemplate/templates/baseTemplate/index.html index f31cb4b17..f00f3828f 100644 --- a/baseTemplate/templates/baseTemplate/index.html +++ b/baseTemplate/templates/baseTemplate/index.html @@ -1,8 +1,8 @@ {% load i18n %} {% get_current_language as LANGUAGE_CODE %} -{% with CP_VERSION="2.5.5-dev-fix" %} +{% with CP_VERSION="2.4.4.1" %} - + @@ -17,43 +17,38 @@ - - + + - - - + + + + + + - - + + - + - + - + + + + +
@@ -18,7 +36,7 @@ FTP Quota Management - CyberPanel
-
+
FTP Quota System
@@ -112,22 +130,35 @@ function enableFTPQuota() { 'csrfmiddlewaretoken': '{{ csrf_token }}' }, function(data) { if (data.status === 1) { - showNotification('success', data.message); + showNotification('success', (data && (data.message || data.error_message)) || 'Success'); refreshQuotas(); } else { - showNotification('error', data.message); + showNotification('error', (data && (data.error_message || data.message)) || 'Unknown error'); } }); } function refreshQuotas() { - $.post('{% url "getFTPQuotas" %}', { - 'csrfmiddlewaretoken': '{{ csrf_token }}' - }, function(data) { - if (data.status === 1) { - displayQuotas(data.quotas); - } else { - showNotification('error', data.message); + var tbody = document.getElementById('quotasTableBody'); + if (tbody) tbody.innerHTML = ' Loading...'; + $.ajax({ + url: '{% url "getFTPQuotas" %}', + type: 'POST', + data: { 'csrfmiddlewaretoken': '{{ csrf_token }}' }, + dataType: 'json', + success: function(data) { + if (data && data.status === 1) { + displayQuotas(data.quotas || []); + } else { + var msg = (data && (data.error_message || data.message)) || 'Unknown error'; + showNotification('error', msg); + if (tbody) tbody.innerHTML = '' + msg + ''; + } + }, + error: function(xhr) { + var msg = (xhr.responseJSON && (xhr.responseJSON.error_message || xhr.responseJSON.message)) || (xhr.statusText || 'Request failed'); + showNotification('error', msg); + if (tbody) tbody.innerHTML = '' + msg + ''; } }); } @@ -190,11 +221,11 @@ function saveQuota() { $.post('{% url "updateFTPQuota" %}', formData, function(data) { if (data.status === 1) { - showNotification('success', data.message); + showNotification('success', (data && (data.message || data.error_message)) || 'Success'); $('#editQuotaModal').modal('hide'); refreshQuotas(); } else { - showNotification('error', data.message); + showNotification('error', (data && (data.error_message || data.message)) || 'Unknown error'); } }); } diff --git a/websiteFunctions/urls.py b/websiteFunctions/urls.py index b6dce054f..74e2cb674 100644 --- a/websiteFunctions/urls.py +++ b/websiteFunctions/urls.py @@ -201,31 +201,33 @@ urlpatterns = [ path('resetVHostConfigToDefault', views.resetVHostConfigToDefault, name='resetVHostConfigToDefault'), path('getTerminalJWT', views.get_terminal_jwt, name='get_terminal_jwt'), - # Catch all for domains - path('/', views.launchChild, name='launchChild'), - path('', views.domain, name='domain'), - path('get_website_resources/', views.get_website_resources, name='get_website_resources'), # Subdomain Log Fix path('fixSubdomainLogs', views.fixSubdomainLogs, name='fixSubdomainLogs'), path('fixSubdomainLogsAction', views.fixSubdomainLogsAction, name='fixSubdomainLogsAction'), - # FTP Quota Management + # FTP Quota Management (API endpoints only; page is at /ftp/quotaManagement) path('enableFTPQuota', views.enableFTPQuota, name='enableFTPQuota'), path('getFTPQuotas', views.getFTPQuotas, name='getFTPQuotas'), path('updateFTPQuota', views.updateFTPQuota, name='updateFTPQuota'), # Bandwidth Management + path('bandwidthManagement', views.bandwidthManagementPage, name='bandwidthManagementPage'), path('resetBandwidth', views.resetBandwidth, name='resetBandwidth'), path('getBandwidthResetLogs', views.getBandwidthResetLogs, name='getBandwidthResetLogs'), path('scheduleBandwidthReset', views.scheduleBandwidthReset, name='scheduleBandwidthReset'), + # Security Management + path('securityManagement', views.securityManagementPage, name='securityManagementPage'), + # IP Blocking path('blockIPAddress', views.blockIPAddress, name='blockIPAddress'), path('unblockIPAddress', views.unblockIPAddress, name='unblockIPAddress'), path('getBlockedIPs', views.getBlockedIPs, name='getBlockedIPs'), path('checkIPStatus', views.checkIPStatus, name='checkIPStatus'), - + # Catch all for domains (must be last) + path('/', views.launchChild, name='launchChild'), + path('', views.domain, name='domain'), ] diff --git a/websiteFunctions/views.py b/websiteFunctions/views.py index 0b123b770..5c65f6d85 100644 --- a/websiteFunctions/views.py +++ b/websiteFunctions/views.py @@ -2236,6 +2236,33 @@ def fixSubdomainLogsAction(request): return redirect(loadLoginPage) # FTP Quota Management Views +def ftpQuotaManagementPage(request): + """Render the FTP Quota Management page.""" + try: + userID = request.session['userID'] + proc = httpProc(request, 'websiteFunctions/ftpQuotaManagement.html', {}, 'admin') + return proc.render() + except KeyError: + return redirect(loadLoginPage) + +def bandwidthManagementPage(request): + """Render the Bandwidth Management page.""" + try: + userID = request.session['userID'] + proc = httpProc(request, 'websiteFunctions/bandwidthManagement.html', {}, 'admin') + return proc.render() + except KeyError: + return redirect(loadLoginPage) + +def securityManagementPage(request): + """Render the Security Management page.""" + try: + userID = request.session['userID'] + proc = httpProc(request, 'websiteFunctions/securityManagement.html', {}, 'admin') + return proc.render() + except KeyError: + return redirect(loadLoginPage) + def enableFTPQuota(request): try: userID = request.session['userID'] diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index 576c272c6..d2bcfee56 100644 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -8744,7 +8744,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) # Backup existing configurations @@ -8811,7 +8811,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) quotas = FTPQuota.objects.all().order_by('-created_at') @@ -8856,7 +8856,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) quota_id = data.get('quota_id') @@ -8899,7 +8899,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) reset_type = data.get('reset_type', 'manual') @@ -8970,7 +8970,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) logs = BandwidthResetLog.objects.all().order_by('-reset_at')[:50] # Last 50 entries @@ -9013,7 +9013,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) schedule_type = data.get('schedule_type', 'monthly') # monthly, weekly, daily @@ -9068,7 +9068,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) ip_address = data.get('ip_address') @@ -9119,7 +9119,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) ip_address = data.get('ip_address') @@ -9169,7 +9169,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) # Import firewall utilities @@ -9203,7 +9203,7 @@ StrictHostKeyChecking no admin = Administrator.objects.get(pk=userID) # Check if user has permission - if not ACLManager.checkIfUserIsAdmin(currentACL): + if not (currentACL.get('admin', 0) == 1): return ACLManager.loadErrorJson('status', 0) ip_address = data.get('ip_address')