diff --git a/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/secubox-security-threats/api.js b/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/secubox-security-threats/api.js index c65c94b2..4f458498 100644 --- a/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/secubox-security-threats/api.js +++ b/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/secubox-security-threats/api.js @@ -64,6 +64,12 @@ var callRemoveWhitelist = rpc.declare({ expect: { } }); +var callGetSecurityStats = rpc.declare({ + object: 'luci.secubox-security-threats', + method: 'get_security_stats', + expect: { } +}); + // ============================================================================== // Utility Functions // ============================================================================== @@ -212,13 +218,15 @@ function getDashboardData() { callStatus(), callGetActiveThreats(), callGetStatsByType(), - callGetBlockedIPs() + callGetBlockedIPs(), + callGetSecurityStats() ]).then(function(results) { return { status: results[0] || {}, threats: results[1].threats || [], stats: results[2] || {}, - blocked: results[3].blocked || [] + blocked: results[3].blocked || [], + securityStats: results[4] || {} }; }); } @@ -235,6 +243,7 @@ return baseclass.extend({ getStatsByType: callGetStatsByType, getStatsByHost: callGetStatsByHost, getBlockedIPs: callGetBlockedIPs, + getSecurityStats: callGetSecurityStats, blockThreat: callBlockThreat, whitelistHost: callWhitelistHost, removeWhitelist: callRemoveWhitelist, diff --git a/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/view/secubox-security-threats/dashboard.js b/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/view/secubox-security-threats/dashboard.js index b8a77119..d4a08c92 100644 --- a/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/view/secubox-security-threats/dashboard.js +++ b/package/secubox/luci-app-secubox-security-threats/htdocs/luci-static/resources/view/secubox-security-threats/dashboard.js @@ -16,6 +16,7 @@ return L.view.extend({ var status = data.status || {}; var stats = data.stats || {}; var blocked = data.blocked || []; + var securityStats = data.securityStats || {}; // Calculate statistics var threatStats = { @@ -30,6 +31,7 @@ return L.view.extend({ // Build view elements var statusBanner = this.renderStatusBanner(status); + var fwStatsGrid = this.renderFirewallStats(securityStats); var statsGrid = this.renderStatsGrid(threatStats, blocked.length); var threatDist = this.renderThreatDistribution(stats); var riskGauge = this.renderRiskGauge(threatStats.avg_score); @@ -46,7 +48,11 @@ return L.view.extend({ E('div', { 'class': 'cbi-map-descr' }, _('Real-time threat detection integrating netifyd DPI and CrowdSec intelligence')), statusBanner, E('div', { 'class': 'cbi-section' }, [ - E('h3', {}, _('Overview')), + E('h3', {}, _('Firewall & Network Protection')), + fwStatsGrid + ]), + E('div', { 'class': 'cbi-section' }, [ + E('h3', {}, _('Threat Overview')), statsGrid ]), E('div', { 'class': 'cbi-section', 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;' }, [ @@ -60,6 +66,61 @@ return L.view.extend({ ]); }, + renderFirewallStats: function(stats) { + var formatNumber = function(n) { + if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M'; + if (n >= 1000) return (n / 1000).toFixed(1) + 'K'; + return n.toString(); + }; + + return E('div', { + 'style': 'display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 1rem;' + }, [ + E('div', { + 'style': 'background: linear-gradient(135deg, #1e3a5f 0%, #2d5a87 100%); padding: 1.2rem; border-radius: 12px; color: white; text-align: center;' + }, [ + E('div', { 'style': 'font-size: 2.5rem; font-weight: bold;' }, formatNumber(stats.wan_dropped || 0)), + E('div', { 'style': 'font-size: 0.9rem; opacity: 0.9; margin-top: 0.3rem;' }, _('WAN Dropped')), + E('div', { 'style': 'font-size: 0.75rem; opacity: 0.7; margin-top: 0.2rem;' }, _('Packets blocked at interface')) + ]), + E('div', { + 'style': 'background: linear-gradient(135deg, #c62828 0%, #e53935 100%); padding: 1.2rem; border-radius: 12px; color: white; text-align: center;' + }, [ + E('div', { 'style': 'font-size: 2.5rem; font-weight: bold;' }, formatNumber(stats.firewall_rejects || 0)), + E('div', { 'style': 'font-size: 0.9rem; opacity: 0.9; margin-top: 0.3rem;' }, _('FW Rejects')), + E('div', { 'style': 'font-size: 0.75rem; opacity: 0.7; margin-top: 0.2rem;' }, _('Firewall rule blocks')) + ]), + E('div', { + 'style': 'background: linear-gradient(135deg, #6a1b9a 0%, #8e24aa 100%); padding: 1.2rem; border-radius: 12px; color: white; text-align: center;' + }, [ + E('div', { 'style': 'font-size: 2.5rem; font-weight: bold;' }, formatNumber(stats.crowdsec_bans || 0)), + E('div', { 'style': 'font-size: 0.9rem; opacity: 0.9; margin-top: 0.3rem;' }, _('CrowdSec Bans')), + E('div', { 'style': 'font-size: 0.75rem; opacity: 0.7; margin-top: 0.2rem;' }, _('Active IP bans')) + ]), + E('div', { + 'style': 'background: linear-gradient(135deg, #ef6c00 0%, #ff9800 100%); padding: 1.2rem; border-radius: 12px; color: white; text-align: center;' + }, [ + E('div', { 'style': 'font-size: 2.5rem; font-weight: bold;' }, formatNumber(stats.crowdsec_alerts_24h || 0)), + E('div', { 'style': 'font-size: 0.9rem; opacity: 0.9; margin-top: 0.3rem;' }, _('Alerts 24h')), + E('div', { 'style': 'font-size: 0.75rem; opacity: 0.7; margin-top: 0.2rem;' }, _('CrowdSec detections')) + ]), + E('div', { + 'style': 'background: linear-gradient(135deg, #455a64 0%, #607d8b 100%); padding: 1.2rem; border-radius: 12px; color: white; text-align: center;' + }, [ + E('div', { 'style': 'font-size: 2.5rem; font-weight: bold;' }, formatNumber(stats.invalid_connections || 0)), + E('div', { 'style': 'font-size: 0.9rem; opacity: 0.9; margin-top: 0.3rem;' }, _('Invalid Conns')), + E('div', { 'style': 'font-size: 0.75rem; opacity: 0.7; margin-top: 0.2rem;' }, _('Conntrack anomalies')) + ]), + E('div', { + 'style': 'background: linear-gradient(135deg, #00695c 0%, #00897b 100%); padding: 1.2rem; border-radius: 12px; color: white; text-align: center;' + }, [ + E('div', { 'style': 'font-size: 2.5rem; font-weight: bold;' }, formatNumber(stats.haproxy_connections || 0)), + E('div', { 'style': 'font-size: 0.9rem; opacity: 0.9; margin-top: 0.3rem;' }, _('HAProxy Conns')), + E('div', { 'style': 'font-size: 0.75rem; opacity: 0.7; margin-top: 0.2rem;' }, _('Reverse proxy sessions')) + ]) + ]); + }, + renderStatusBanner: function(status) { var services = []; var hasIssue = false;