feat(portal): Add Threat Monitor to security cards and stats
- Add threat-monitor app to security section in portal.js - Add security stats RPC call (get_security_stats) - Display packets blocked and alerts on dashboard - Add Threat Monitor to featured quick access apps - Show WAN dropped + firewall rejects in events section - Link to Threat Monitor dashboard from events Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
283f2567be
commit
37b88e47b9
@ -61,6 +61,18 @@ return baseclass.extend({
|
|||||||
service: 'mitmproxy',
|
service: 'mitmproxy',
|
||||||
version: '8.1.1'
|
version: '8.1.1'
|
||||||
},
|
},
|
||||||
|
'threat-monitor': {
|
||||||
|
id: 'threat-monitor',
|
||||||
|
name: 'Threat Monitor',
|
||||||
|
desc: 'Real-time threat detection combining netifyd DPI with CrowdSec intelligence',
|
||||||
|
icon: '\ud83d\udc41\ufe0f',
|
||||||
|
iconBg: 'rgba(239, 68, 68, 0.15)',
|
||||||
|
iconColor: '#ef4444',
|
||||||
|
section: 'security',
|
||||||
|
path: 'admin/secubox/security/threats/dashboard',
|
||||||
|
service: null,
|
||||||
|
version: '1.0.0'
|
||||||
|
},
|
||||||
|
|
||||||
// Network Apps
|
// Network Apps
|
||||||
'bandwidth-manager': {
|
'bandwidth-manager': {
|
||||||
|
|||||||
@ -23,6 +23,11 @@ var callCrowdSecStats = rpc.declare({
|
|||||||
method: 'nftables_stats'
|
method: 'nftables_stats'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var callSecurityStats = rpc.declare({
|
||||||
|
object: 'luci.secubox-security-threats',
|
||||||
|
method: 'get_security_stats'
|
||||||
|
});
|
||||||
|
|
||||||
var callGetServices = rpc.declare({
|
var callGetServices = rpc.declare({
|
||||||
object: 'luci.secubox',
|
object: 'luci.secubox',
|
||||||
method: 'get_services',
|
method: 'get_services',
|
||||||
@ -42,13 +47,16 @@ return view.extend({
|
|||||||
this.loadAppStatuses(),
|
this.loadAppStatuses(),
|
||||||
callCrowdSecStats().catch(function() { return null; }),
|
callCrowdSecStats().catch(function() { return null; }),
|
||||||
portal.checkInstalledApps(),
|
portal.checkInstalledApps(),
|
||||||
callGetServices().catch(function() { return []; })
|
callGetServices().catch(function() { return []; }),
|
||||||
|
callSecurityStats().catch(function() { return null; })
|
||||||
]).then(function(results) {
|
]).then(function(results) {
|
||||||
// Store installed apps info from the last promise
|
// Store installed apps info from the last promise
|
||||||
self.installedApps = results[4] || {};
|
self.installedApps = results[4] || {};
|
||||||
// RPC expect unwraps the services array directly
|
// RPC expect unwraps the services array directly
|
||||||
var svcResult = results[5] || [];
|
var svcResult = results[5] || [];
|
||||||
self.detectedServices = Array.isArray(svcResult) ? svcResult : (svcResult.services || []);
|
self.detectedServices = Array.isArray(svcResult) ? svcResult : (svcResult.services || []);
|
||||||
|
// Security stats
|
||||||
|
self.securityStats = results[6] || {};
|
||||||
return results;
|
return results;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -104,6 +112,7 @@ return view.extend({
|
|||||||
var boardInfo = data[0] || {};
|
var boardInfo = data[0] || {};
|
||||||
var sysInfo = data[1] || {};
|
var sysInfo = data[1] || {};
|
||||||
var crowdSecStats = data[3] || {};
|
var crowdSecStats = data[3] || {};
|
||||||
|
var securityStats = this.securityStats || {};
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Set portal app context and hide LuCI navigation
|
// Set portal app context and hide LuCI navigation
|
||||||
@ -142,7 +151,7 @@ return view.extend({
|
|||||||
this.renderHeader(),
|
this.renderHeader(),
|
||||||
// Content
|
// Content
|
||||||
E('div', { 'class': 'sb-portal-content' }, [
|
E('div', { 'class': 'sb-portal-content' }, [
|
||||||
this.renderDashboardSection(boardInfo, sysInfo, crowdSecStats),
|
this.renderDashboardSection(boardInfo, sysInfo, crowdSecStats, securityStats),
|
||||||
this.renderSecuritySection(),
|
this.renderSecuritySection(),
|
||||||
this.renderNetworkSection(),
|
this.renderNetworkSection(),
|
||||||
this.renderMonitoringSection(),
|
this.renderMonitoringSection(),
|
||||||
@ -228,7 +237,7 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renderDashboardSection: function(boardInfo, sysInfo, crowdSecStats) {
|
renderDashboardSection: function(boardInfo, sysInfo, crowdSecStats, securityStats) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var securityApps = portal.getAppsBySection('security');
|
var securityApps = portal.getAppsBySection('security');
|
||||||
var networkApps = portal.getAppsBySection('network');
|
var networkApps = portal.getAppsBySection('network');
|
||||||
@ -245,6 +254,12 @@ return view.extend({
|
|||||||
var crowdSecHealth = crowdSecStats.firewall_health || {};
|
var crowdSecHealth = crowdSecStats.firewall_health || {};
|
||||||
var crowdSecActive = crowdSecHealth.bouncer_running && crowdSecHealth.decisions_synced;
|
var crowdSecActive = crowdSecHealth.bouncer_running && crowdSecHealth.decisions_synced;
|
||||||
|
|
||||||
|
// Security stats
|
||||||
|
var wanDropped = securityStats.wan_dropped || 0;
|
||||||
|
var fwRejects = securityStats.firewall_rejects || 0;
|
||||||
|
var csBans = securityStats.crowdsec_bans || 0;
|
||||||
|
var csAlerts = securityStats.crowdsec_alerts_24h || 0;
|
||||||
|
|
||||||
return E('div', { 'class': 'sb-portal-section active', 'data-section': 'dashboard' }, [
|
return E('div', { 'class': 'sb-portal-section active', 'data-section': 'dashboard' }, [
|
||||||
E('div', { 'class': 'sb-section-header' }, [
|
E('div', { 'class': 'sb-section-header' }, [
|
||||||
E('h2', { 'class': 'sb-section-title' }, 'SecuBox Dashboard'),
|
E('h2', { 'class': 'sb-section-title' }, 'SecuBox Dashboard'),
|
||||||
@ -275,32 +290,33 @@ return view.extend({
|
|||||||
E('div', { 'class': 'sb-quick-stat-label' }, 'Services Running')
|
E('div', { 'class': 'sb-quick-stat-label' }, 'Services Running')
|
||||||
]),
|
]),
|
||||||
|
|
||||||
// CrowdSec Blocked IPs
|
// Firewall Blocked
|
||||||
E('div', { 'class': 'sb-quick-stat' }, [
|
E('div', { 'class': 'sb-quick-stat' }, [
|
||||||
E('div', { 'class': 'sb-quick-stat-header' }, [
|
E('div', { 'class': 'sb-quick-stat-header' }, [
|
||||||
E('div', { 'class': 'sb-quick-stat-icon security' }, '\ud83d\udeab'),
|
E('div', { 'class': 'sb-quick-stat-icon security' }, '\ud83d\udeab'),
|
||||||
E('span', { 'class': 'sb-quick-stat-status ' + (crowdSecActive ? 'running' : 'warning') },
|
E('span', { 'class': 'sb-quick-stat-status ' + (crowdSecActive ? 'running' : 'warning') },
|
||||||
crowdSecActive ? 'Active' : 'Inactive')
|
crowdSecActive ? 'Protected' : 'Monitoring')
|
||||||
]),
|
]),
|
||||||
E('div', { 'class': 'sb-quick-stat-value' }, totalBlocked.toLocaleString()),
|
E('div', { 'class': 'sb-quick-stat-value' }, (wanDropped + fwRejects).toLocaleString()),
|
||||||
E('div', { 'class': 'sb-quick-stat-label' }, 'IPs Blocked')
|
E('div', { 'class': 'sb-quick-stat-label' }, 'Packets Blocked')
|
||||||
]),
|
]),
|
||||||
|
|
||||||
// Network Apps
|
// Threat Alerts
|
||||||
E('div', { 'class': 'sb-quick-stat' }, [
|
E('div', { 'class': 'sb-quick-stat' }, [
|
||||||
E('div', { 'class': 'sb-quick-stat-header' }, [
|
E('div', { 'class': 'sb-quick-stat-header' }, [
|
||||||
E('div', { 'class': 'sb-quick-stat-icon network' }, '\ud83c\udf10'),
|
E('div', { 'class': 'sb-quick-stat-icon security' }, '\ud83d\udc41\ufe0f'),
|
||||||
E('span', { 'class': 'sb-quick-stat-status running' }, 'Configured')
|
E('span', { 'class': 'sb-quick-stat-status ' + (csAlerts > 0 ? 'warning' : 'running') },
|
||||||
|
csAlerts > 0 ? 'Alerts' : 'Clear')
|
||||||
]),
|
]),
|
||||||
E('div', { 'class': 'sb-quick-stat-value' }, networkApps.length),
|
E('div', { 'class': 'sb-quick-stat-value' }, csBans + '/' + csAlerts),
|
||||||
E('div', { 'class': 'sb-quick-stat-label' }, 'Network Tools')
|
E('div', { 'class': 'sb-quick-stat-label' }, 'Bans / Alerts 24h')
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
|
|
||||||
// Featured Apps
|
// Featured Apps
|
||||||
E('h3', { 'style': 'margin: 1.5rem 0 1rem; color: var(--cyber-text-primary);' }, 'Quick Access'),
|
E('h3', { 'style': 'margin: 1.5rem 0 1rem; color: var(--cyber-text-primary);' }, 'Quick Access'),
|
||||||
E('div', { 'class': 'sb-app-grid' },
|
E('div', { 'class': 'sb-app-grid' },
|
||||||
this.renderFeaturedApps(['crowdsec', 'bandwidth-manager', 'media-flow', 'ndpid'])
|
this.renderFeaturedApps(['crowdsec', 'threat-monitor', 'bandwidth-manager', 'media-flow'])
|
||||||
),
|
),
|
||||||
|
|
||||||
// Recent Events placeholder
|
// Recent Events placeholder
|
||||||
@ -342,6 +358,17 @@ return view.extend({
|
|||||||
(crowdSecStats.ipv4_cscli_count || 0) + ' local) | IPv6: ' + blockedIPv6.toLocaleString()),
|
(crowdSecStats.ipv4_cscli_count || 0) + ' local) | IPv6: ' + blockedIPv6.toLocaleString()),
|
||||||
E('span', { 'class': 'sb-events-meta' }, 'CrowdSec Firewall Protection')
|
E('span', { 'class': 'sb-events-meta' }, 'CrowdSec Firewall Protection')
|
||||||
])
|
])
|
||||||
|
]) : null,
|
||||||
|
wanDropped > 0 ? E('div', { 'class': 'sb-events-item' }, [
|
||||||
|
E('div', { 'class': 'sb-events-icon warning' }, '\ud83d\udc41\ufe0f'),
|
||||||
|
E('div', { 'class': 'sb-events-content' }, [
|
||||||
|
E('p', { 'class': 'sb-events-message' },
|
||||||
|
'WAN Dropped: ' + wanDropped.toLocaleString() + ' | Firewall Rejects: ' + fwRejects),
|
||||||
|
E('span', { 'class': 'sb-events-meta' }, [
|
||||||
|
'Threat Monitor - ',
|
||||||
|
E('a', { 'href': L.url('admin/secubox/security/threats/dashboard') }, 'View Details')
|
||||||
|
])
|
||||||
|
])
|
||||||
]) : null
|
]) : null
|
||||||
].filter(Boolean))
|
].filter(Boolean))
|
||||||
]);
|
]);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user