crowdswc full
This commit is contained in:
parent
ff20666817
commit
eb72e12a72
@ -4,7 +4,9 @@
|
||||
"Bash(done)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash(xargs:*)"
|
||||
"Bash(xargs:*)",
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(shellcheck:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"anthropic.claude-code"
|
||||
]
|
||||
}
|
||||
@ -1,22 +1,75 @@
|
||||
# SecuBox - Security Suite for OpenWrt
|
||||
# SecuBox Central Hub
|
||||
|
||||
Unified security dashboard providing central management for:
|
||||
Central management dashboard for the SecuBox security and network management suite for OpenWrt.
|
||||
|
||||
- **CrowdSec** - Collaborative intrusion prevention
|
||||
## Features
|
||||
|
||||
### Dashboard Overview
|
||||
- Real-time system health monitoring (CPU, Memory, Disk, Network)
|
||||
- Visual gauges with color-coded status indicators
|
||||
- Module status grid with quick access links
|
||||
- Aggregated alerts from all modules
|
||||
- Quick action buttons for common tasks
|
||||
|
||||
### System Health Monitoring
|
||||
- **CPU**: Load average and percentage with multi-core support
|
||||
- **Memory**: RAM usage with total/used/available metrics
|
||||
- **Disk**: Root filesystem usage and available space
|
||||
- **Network**: Real-time RX/TX bandwidth statistics
|
||||
|
||||
### Quick Actions
|
||||
- Restart RPCD service
|
||||
- Restart uHTTPd web server
|
||||
- Clear system cache
|
||||
- Create configuration backup
|
||||
- Restart network services
|
||||
- Restart firewall
|
||||
|
||||
### Module Management
|
||||
Auto-detection and status monitoring for all SecuBox modules:
|
||||
|
||||
**Security & Monitoring**
|
||||
- **CrowdSec** - Collaborative threat intelligence
|
||||
- **Netdata** - Real-time system monitoring
|
||||
- **Netifyd** - Deep packet inspection and traffic analysis
|
||||
- **WireGuard** - Modern VPN
|
||||
- **Network Modes** - Simplified network configuration
|
||||
- **Client Guardian** - Access control and captive portal
|
||||
- **System Hub** - System control center
|
||||
- **CDN Cache** - Bandwidth optimization proxy
|
||||
- **Traffic Shaper** - QoS, priorities, and quotas
|
||||
- **Netifyd** - Deep packet inspection
|
||||
- **Client Guardian** - Network access control and captive portal
|
||||
- **Auth Guardian** - Advanced authentication system
|
||||
|
||||
**Network Management**
|
||||
- **WireGuard** - Modern VPN with QR codes
|
||||
- **Network Modes** - Network topology configuration
|
||||
- **Bandwidth Manager** - QoS and bandwidth quotas
|
||||
- **Media Flow** - Media traffic detection and optimization
|
||||
- **Traffic Shaper** - Advanced traffic shaping
|
||||
|
||||
**System & Performance**
|
||||
- **System Hub** - Unified control center
|
||||
- **CDN Cache** - Local caching proxy
|
||||
- **Virtual Host Manager** - Virtual host configuration
|
||||
|
||||
## RPCD API Methods
|
||||
|
||||
The hub provides a comprehensive RPC API via ubus:
|
||||
|
||||
- `status` - Get hub status and basic system info
|
||||
- `modules` - List all SecuBox modules with status
|
||||
- `modules_by_category` - Filter modules by category
|
||||
- `module_info` - Get detailed info for a specific module
|
||||
- `get_system_health` - Detailed system health metrics
|
||||
- `get_alerts` - Aggregated alerts from all modules
|
||||
- `get_dashboard_data` - All dashboard data in one call
|
||||
- `quick_action` - Execute quick actions
|
||||
- `start_module` / `stop_module` / `restart_module` - Module control
|
||||
- `health` - System health checks
|
||||
- `diagnostics` - Generate diagnostics bundle
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
opkg update
|
||||
opkg install luci-app-secubox
|
||||
/etc/init.d/rpcd restart
|
||||
/etc/init.d/uhttpd restart
|
||||
```
|
||||
|
||||
## Building
|
||||
@ -27,6 +80,33 @@ git clone https://github.com/youruser/luci-app-secubox.git package/luci-app-secu
|
||||
make package/luci-app-secubox/compile V=s
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit `/etc/config/secubox` to customize module definitions and settings.
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
luci-app-secubox/
|
||||
├── Makefile
|
||||
├── README.md
|
||||
├── htdocs/luci-static/resources/
|
||||
│ ├── view/secubox/
|
||||
│ │ ├── dashboard.js # Main dashboard view
|
||||
│ │ ├── modules.js # Modules management view
|
||||
│ │ └── settings.js # Settings view
|
||||
│ └── secubox/
|
||||
│ ├── api.js # RPC API client
|
||||
│ └── secubox.css # Dashboard styles
|
||||
└── root/
|
||||
├── etc/config/secubox # UCI configuration
|
||||
└── usr/
|
||||
├── libexec/rpcd/secubox # RPCD backend
|
||||
└── share/
|
||||
├── luci/menu.d/luci-app-secubox.json
|
||||
└── rpcd/acl.d/luci-app-secubox.json
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT License - CyberMind Security
|
||||
Apache-2.0 - Copyright (C) 2025 CyberMind.fr
|
||||
|
||||
@ -64,6 +64,31 @@ var callDiagnostics = rpc.declare({
|
||||
expect: { }
|
||||
});
|
||||
|
||||
var callSystemHealth = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'get_system_health',
|
||||
expect: { }
|
||||
});
|
||||
|
||||
var callAlerts = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'get_alerts',
|
||||
expect: { alerts: [] }
|
||||
});
|
||||
|
||||
var callQuickAction = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'quick_action',
|
||||
params: ['action'],
|
||||
expect: { }
|
||||
});
|
||||
|
||||
var callDashboardData = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'get_dashboard_data',
|
||||
expect: { }
|
||||
});
|
||||
|
||||
function formatUptime(seconds) {
|
||||
if (!seconds) return '0s';
|
||||
var d = Math.floor(seconds / 86400);
|
||||
@ -74,6 +99,14 @@ function formatUptime(seconds) {
|
||||
return m + 'm';
|
||||
}
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (!bytes) return '0 B';
|
||||
var k = 1024;
|
||||
var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
var i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
return baseclass.extend({
|
||||
getStatus: callStatus,
|
||||
getModules: callModules,
|
||||
@ -84,5 +117,10 @@ return baseclass.extend({
|
||||
restartModule: callRestartModule,
|
||||
getHealth: callHealth,
|
||||
getDiagnostics: callDiagnostics,
|
||||
formatUptime: formatUptime
|
||||
getSystemHealth: callSystemHealth,
|
||||
getAlerts: callAlerts,
|
||||
quickAction: callQuickAction,
|
||||
getDashboardData: callDashboardData,
|
||||
formatUptime: formatUptime,
|
||||
formatBytes: formatBytes
|
||||
});
|
||||
|
||||
@ -30,3 +30,262 @@
|
||||
.sb-color-client-guardian { --module-color: #ef4444; }
|
||||
.sb-color-system-hub { --module-color: #6366f1; }
|
||||
.sb-color-cdn-cache { --module-color: #06b6d4; }
|
||||
|
||||
/* System Health Section */
|
||||
.secubox-health-section {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background: var(--sb-bg-card);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-health-section h3 {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--sb-text);
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.secubox-health-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.secubox-gauge {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.secubox-gauge-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--sb-text);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.secubox-gauge-chart {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.secubox-gauge-details {
|
||||
font-size: 12px;
|
||||
color: var(--sb-text-muted);
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Quick Actions Section */
|
||||
.secubox-quick-actions {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background: var(--sb-bg-card);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-quick-actions h3 {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--sb-text);
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.secubox-actions-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.secubox-quick-actions .cbi-button-action {
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Alerts Section */
|
||||
.secubox-alerts-section {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background: var(--sb-bg-card);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-alerts-section h3 {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--sb-text);
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.secubox-alerts-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.secubox-alert {
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.secubox-alert-warning {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
border-left-color: var(--sb-warning);
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
.secubox-alert-error {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-left-color: var(--sb-danger);
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
.secubox-alert-info {
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
border-left-color: var(--sb-primary);
|
||||
color: #93c5fd;
|
||||
}
|
||||
|
||||
/* Modules Section */
|
||||
.secubox-modules-section {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.secubox-modules-section h3 {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--sb-text);
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.secubox-modules-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.secubox-module-card {
|
||||
background: var(--sb-bg-card);
|
||||
border: 1px solid var(--sb-border);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.secubox-module-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
border-color: var(--sb-primary);
|
||||
}
|
||||
|
||||
.secubox-module-card[data-status="running"] {
|
||||
border-left: 4px solid var(--sb-success);
|
||||
}
|
||||
|
||||
.secubox-module-card[data-status="stopped"] {
|
||||
border-left: 4px solid var(--sb-danger);
|
||||
}
|
||||
|
||||
.secubox-module-card[data-status="not-installed"] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.secubox-module-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.secubox-module-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.secubox-module-status {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.secubox-module-body {
|
||||
flex: 1;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.secubox-module-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--sb-text);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.secubox-module-description {
|
||||
font-size: 13px;
|
||||
color: var(--sb-text-muted);
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.secubox-module-category {
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
background: rgba(59, 130, 246, 0.2);
|
||||
color: var(--sb-primary);
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.secubox-module-footer {
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-module-footer .cbi-button-link {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.secubox-not-installed {
|
||||
display: block;
|
||||
text-align: center;
|
||||
color: var(--sb-text-muted);
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.secubox-health-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.secubox-actions-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.secubox-modules-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,38 +1,216 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require rpc';
|
||||
'require ui';
|
||||
'require secubox/api as API';
|
||||
'require dom';
|
||||
|
||||
var callStatus = rpc.declare({object:'luci.secubox',method:'status',expect:{}});
|
||||
var callModules = rpc.declare({object:'luci.secubox',method:'modules',expect:{modules:[]}});
|
||||
// Load CSS
|
||||
document.head.appendChild(E('link', {
|
||||
'rel': 'stylesheet',
|
||||
'type': 'text/css',
|
||||
'href': L.resource('secubox/secubox.css')
|
||||
}));
|
||||
|
||||
return view.extend({
|
||||
load: function() { return Promise.all([callStatus(), callModules()]); },
|
||||
render: function(data) {
|
||||
var status = data[0] || {}, modules = data[1].modules || [];
|
||||
var cats = {security:[], monitoring:[], network:[], system:[]};
|
||||
modules.forEach(function(m) { if(cats[m.category]) cats[m.category].push(m); });
|
||||
|
||||
return E('div', {class:'cbi-map'}, [
|
||||
E('h2', {}, '🛡️ SecuBox Dashboard'),
|
||||
E('div', {style:'display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin:20px 0'}, [
|
||||
E('div', {style:'background:#1e293b;padding:16px;border-radius:8px;text-align:center'}, [
|
||||
E('div', {style:'font-size:24px;font-weight:bold;color:#22d3ee'}, status.modules_total || 0),
|
||||
E('div', {style:'color:#94a3b8'}, 'Total Modules')
|
||||
]),
|
||||
E('div', {style:'background:#1e293b;padding:16px;border-radius:8px;text-align:center'}, [
|
||||
E('div', {style:'font-size:24px;font-weight:bold;color:#3b82f6'}, status.modules_installed || 0),
|
||||
E('div', {style:'color:#94a3b8'}, 'Installed')
|
||||
]),
|
||||
E('div', {style:'background:#1e293b;padding:16px;border-radius:8px;text-align:center'}, [
|
||||
E('div', {style:'font-size:24px;font-weight:bold;color:#22c55e'}, status.modules_running || 0),
|
||||
E('div', {style:'color:#94a3b8'}, 'Running')
|
||||
]),
|
||||
E('div', {style:'background:#1e293b;padding:16px;border-radius:8px;text-align:center'}, [
|
||||
E('div', {style:'font-size:24px;font-weight:bold;color:#f59e0b'}, (status.memory_percent || 0) + '%'),
|
||||
E('div', {style:'color:#94a3b8'}, 'Memory')
|
||||
])
|
||||
]),
|
||||
E('p', {}, 'Hostname: ' + (status.hostname || 'unknown') + ' | Load: ' + (status.load || '0'))
|
||||
]);
|
||||
}
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
API.getDashboardData(),
|
||||
API.getSystemHealth(),
|
||||
API.getAlerts()
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var dashboard = data[0] || {};
|
||||
var health = data[1] || {};
|
||||
var alertsData = data[2] || {};
|
||||
|
||||
var status = dashboard.status || {};
|
||||
var modules = dashboard.modules || [];
|
||||
var counts = dashboard.counts || {};
|
||||
var alerts = alertsData.alerts || [];
|
||||
|
||||
var container = E('div', { 'class': 'cbi-map' });
|
||||
|
||||
// Header
|
||||
container.appendChild(E('h2', {}, 'SecuBox Central Hub'));
|
||||
container.appendChild(E('p', {},
|
||||
'Hostname: ' + (status.hostname || 'Unknown') + ' | ' +
|
||||
'Uptime: ' + API.formatUptime(status.uptime) + ' | ' +
|
||||
'Load: ' + (status.load || '0.00')
|
||||
));
|
||||
|
||||
// System Health Section
|
||||
container.appendChild(this.renderSystemHealth(health));
|
||||
|
||||
// Quick Actions Section
|
||||
container.appendChild(this.renderQuickActions());
|
||||
|
||||
// Alerts Section
|
||||
if (alerts.length > 0) {
|
||||
container.appendChild(this.renderAlerts(alerts));
|
||||
}
|
||||
|
||||
// Modules Grid
|
||||
container.appendChild(this.renderModulesGrid(modules));
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
renderSystemHealth: function(health) {
|
||||
var cpu = health.cpu || {};
|
||||
var memory = health.memory || {};
|
||||
var disk = health.disk || {};
|
||||
var network = health.network || {};
|
||||
|
||||
var section = E('div', { 'class': 'secubox-health-section' }, [
|
||||
E('h3', {}, 'System Health'),
|
||||
E('div', { 'class': 'secubox-health-grid' }, [
|
||||
this.renderGauge('CPU', cpu.percent || 0, '%', cpu.load_1min),
|
||||
this.renderGauge('Memory', memory.percent || 0, '%',
|
||||
API.formatBytes(memory.used_kb * 1024) + ' / ' + API.formatBytes(memory.total_kb * 1024)),
|
||||
this.renderGauge('Disk', disk.percent || 0, '%',
|
||||
API.formatBytes(disk.used_kb * 1024) + ' / ' + API.formatBytes(disk.total_kb * 1024)),
|
||||
this.renderGauge('Network', 0, '',
|
||||
'RX: ' + API.formatBytes(network.rx_bytes) + ' | TX: ' + API.formatBytes(network.tx_bytes))
|
||||
])
|
||||
]);
|
||||
|
||||
return section;
|
||||
},
|
||||
|
||||
renderGauge: function(label, percent, unit, details) {
|
||||
var color = percent < 70 ? '#22c55e' : percent < 85 ? '#f59e0b' : '#ef4444';
|
||||
|
||||
return E('div', { 'class': 'secubox-gauge' }, [
|
||||
E('div', { 'class': 'secubox-gauge-label' }, label),
|
||||
E('div', { 'class': 'secubox-gauge-chart' }, [
|
||||
E('svg', { 'width': '120', 'height': '120', 'viewBox': '0 0 120 120' }, [
|
||||
E('circle', {
|
||||
'cx': '60', 'cy': '60', 'r': '54',
|
||||
'fill': 'none', 'stroke': '#1e293b', 'stroke-width': '12'
|
||||
}),
|
||||
E('circle', {
|
||||
'cx': '60', 'cy': '60', 'r': '54',
|
||||
'fill': 'none', 'stroke': color, 'stroke-width': '12',
|
||||
'stroke-dasharray': (339.292 * percent / 100) + ' 339.292',
|
||||
'stroke-linecap': 'round',
|
||||
'transform': 'rotate(-90 60 60)'
|
||||
}),
|
||||
E('text', {
|
||||
'x': '60', 'y': '65', 'text-anchor': 'middle',
|
||||
'font-size': '24', 'font-weight': 'bold', 'fill': color
|
||||
}, percent + unit)
|
||||
])
|
||||
]),
|
||||
E('div', { 'class': 'secubox-gauge-details' }, details || '')
|
||||
]);
|
||||
},
|
||||
|
||||
renderQuickActions: function() {
|
||||
var self = this;
|
||||
var actions = [
|
||||
{ name: 'restart_rpcd', label: 'Restart RPCD', icon: '🔄' },
|
||||
{ name: 'restart_uhttpd', label: 'Restart uHTTPd', icon: '🌐' },
|
||||
{ name: 'clear_cache', label: 'Clear Cache', icon: '🧹' },
|
||||
{ name: 'backup_config', label: 'Backup Config', icon: '💾' },
|
||||
{ name: 'restart_network', label: 'Restart Network', icon: '📡' },
|
||||
{ name: 'restart_firewall', label: 'Restart Firewall', icon: '🛡️' }
|
||||
];
|
||||
|
||||
var buttons = actions.map(function(action) {
|
||||
return E('button', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'click': function() {
|
||||
self.executeQuickAction(action.name, action.label);
|
||||
}
|
||||
}, action.icon + ' ' + action.label);
|
||||
});
|
||||
|
||||
return E('div', { 'class': 'secubox-quick-actions' }, [
|
||||
E('h3', {}, 'Quick Actions'),
|
||||
E('div', { 'class': 'secubox-actions-grid' }, buttons)
|
||||
]);
|
||||
},
|
||||
|
||||
executeQuickAction: function(action, label) {
|
||||
ui.showModal(_('Quick Action'), [
|
||||
E('p', { 'class': 'spinning' }, _('Executing: ') + label + '...')
|
||||
]);
|
||||
|
||||
API.quickAction(action).then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success) {
|
||||
ui.addNotification(null, E('p', result.message || 'Action completed'), 'info');
|
||||
} else {
|
||||
ui.addNotification(null, E('p', result.message || 'Action failed'), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
renderAlerts: function(alerts) {
|
||||
var alertItems = alerts.map(function(alert) {
|
||||
var severityClass = 'secubox-alert-' + (alert.severity || 'info');
|
||||
return E('div', { 'class': 'secubox-alert ' + severityClass }, [
|
||||
E('strong', {}, alert.module + ': '),
|
||||
E('span', {}, alert.message)
|
||||
]);
|
||||
});
|
||||
|
||||
return E('div', { 'class': 'secubox-alerts-section' }, [
|
||||
E('h3', {}, 'Recent Alerts (' + alerts.length + ')'),
|
||||
E('div', { 'class': 'secubox-alerts-list' }, alertItems)
|
||||
]);
|
||||
},
|
||||
|
||||
renderModulesGrid: function(modules) {
|
||||
var moduleCards = modules.map(function(module) {
|
||||
var statusClass = module.installed ? (module.running ? 'running' : 'stopped') : 'not-installed';
|
||||
var statusIcon = module.installed ? (module.running ? '✓' : '✗') : '○';
|
||||
var statusColor = module.installed ? (module.running ? '#22c55e' : '#ef4444') : '#64748b';
|
||||
|
||||
return E('div', {
|
||||
'class': 'secubox-module-card',
|
||||
'data-status': statusClass
|
||||
}, [
|
||||
E('div', { 'class': 'secubox-module-header' }, [
|
||||
E('div', {
|
||||
'class': 'secubox-module-icon',
|
||||
'style': 'background-color: ' + (module.color || '#64748b')
|
||||
}, module.icon || '📦'),
|
||||
E('div', {
|
||||
'class': 'secubox-module-status',
|
||||
'style': 'color: ' + statusColor
|
||||
}, statusIcon)
|
||||
]),
|
||||
E('div', { 'class': 'secubox-module-body' }, [
|
||||
E('div', { 'class': 'secubox-module-name' }, module.name || module.id),
|
||||
E('div', { 'class': 'secubox-module-description' }, module.description || ''),
|
||||
E('div', { 'class': 'secubox-module-category' }, module.category || 'other')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-module-footer' }, [
|
||||
module.installed ? E('a', {
|
||||
'href': '#',
|
||||
'class': 'cbi-button cbi-button-link',
|
||||
'click': function(ev) {
|
||||
ev.preventDefault();
|
||||
window.location.hash = '#admin/secubox/' + module.id;
|
||||
}
|
||||
}, 'Open Dashboard') : E('span', { 'class': 'secubox-not-installed' }, 'Not Installed')
|
||||
])
|
||||
]);
|
||||
});
|
||||
|
||||
return E('div', { 'class': 'secubox-modules-section' }, [
|
||||
E('h3', {}, 'Installed Modules'),
|
||||
E('div', { 'class': 'secubox-modules-grid' }, moduleCards)
|
||||
]);
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
|
||||
@ -95,3 +95,58 @@ config module 'cdn_cache'
|
||||
option config 'cdn-cache'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
|
||||
config module 'bandwidth_manager'
|
||||
option name 'Bandwidth Manager'
|
||||
option description 'QoS and bandwidth quotas'
|
||||
option category 'network'
|
||||
option icon 'activity'
|
||||
option color '#3b82f6'
|
||||
option package 'luci-app-bandwidth-manager'
|
||||
option config 'bandwidth_manager'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
|
||||
config module 'auth_guardian'
|
||||
option name 'Auth Guardian'
|
||||
option description 'Advanced authentication system'
|
||||
option category 'security'
|
||||
option icon 'key'
|
||||
option color '#f59e0b'
|
||||
option package 'luci-app-auth-guardian'
|
||||
option config 'auth_guardian'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
|
||||
config module 'media_flow'
|
||||
option name 'Media Flow'
|
||||
option description 'Media traffic detection and optimization'
|
||||
option category 'network'
|
||||
option icon 'play-circle'
|
||||
option color '#ec4899'
|
||||
option package 'luci-app-media-flow'
|
||||
option config 'media_flow'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
|
||||
config module 'vhost_manager'
|
||||
option name 'Virtual Host Manager'
|
||||
option description 'Virtual host configuration'
|
||||
option category 'system'
|
||||
option icon 'server'
|
||||
option color '#8b5cf6'
|
||||
option package 'luci-app-vhost-manager'
|
||||
option config 'vhost_manager'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
|
||||
config module 'traffic_shaper'
|
||||
option name 'Traffic Shaper'
|
||||
option description 'Advanced traffic shaping'
|
||||
option category 'network'
|
||||
option icon 'trending-up'
|
||||
option color '#10b981'
|
||||
option package 'luci-app-traffic-shaper'
|
||||
option config 'traffic_shaper'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
|
||||
@ -7,8 +7,23 @@
|
||||
. /lib/functions.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
# Module registry
|
||||
MODULES="crowdsec netdata netifyd wireguard network_modes client_guardian system_hub cdn_cache"
|
||||
# Module registry - auto-detected from /usr/libexec/rpcd/
|
||||
detect_modules() {
|
||||
local modules=""
|
||||
local scripts="crowdsec-dashboard netdata-dashboard netifyd-dashboard wireguard-dashboard network-modes client-guardian system-hub bandwidth-manager auth-guardian media-flow vhost-manager cdn-cache traffic-shaper"
|
||||
|
||||
for script in $scripts; do
|
||||
if [ -x "/usr/libexec/rpcd/$script" ]; then
|
||||
# Convert script name to module ID (remove -dashboard suffix)
|
||||
local module_id=$(echo "$script" | sed 's/-dashboard$//')
|
||||
modules="$modules $module_id"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "$modules"
|
||||
}
|
||||
|
||||
MODULES=$(detect_modules)
|
||||
|
||||
# Check if a module is installed
|
||||
check_module_installed() {
|
||||
@ -338,7 +353,7 @@ get_health() {
|
||||
# Generate diagnostics bundle
|
||||
get_diagnostics() {
|
||||
json_init
|
||||
|
||||
|
||||
# System info
|
||||
json_add_object "system"
|
||||
json_add_string "hostname" "$(uci -q get system.@system[0].hostname)"
|
||||
@ -347,13 +362,13 @@ get_diagnostics() {
|
||||
json_add_string "kernel" "$(uname -r)"
|
||||
json_add_int "uptime" "$(cat /proc/uptime | cut -d. -f1)"
|
||||
json_close_object
|
||||
|
||||
|
||||
# Modules status
|
||||
json_add_array "modules"
|
||||
for module in $MODULES; do
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "id" "$module"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
@ -361,13 +376,13 @@ get_diagnostics() {
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
|
||||
# Network interfaces
|
||||
json_add_array "interfaces"
|
||||
for iface in $(ls /sys/class/net/); do
|
||||
local mac=$(cat /sys/class/net/$iface/address 2>/dev/null)
|
||||
local state=$(cat /sys/class/net/$iface/operstate 2>/dev/null)
|
||||
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "name" "$iface"
|
||||
json_add_string "mac" "$mac"
|
||||
@ -375,9 +390,287 @@ get_diagnostics() {
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
|
||||
json_add_int "generated" "$(date +%s)"
|
||||
|
||||
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Get system health metrics
|
||||
get_system_health() {
|
||||
json_init
|
||||
|
||||
# CPU usage (based on load average)
|
||||
local load=$(cat /proc/loadavg | cut -d' ' -f1)
|
||||
local cpu_cores=$(grep -c processor /proc/cpuinfo)
|
||||
local cpu_pct=$(awk "BEGIN {printf \"%.0f\", ($load / $cpu_cores) * 100}")
|
||||
|
||||
# Memory
|
||||
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
local mem_avail=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
|
||||
local mem_used=$((mem_total - mem_avail))
|
||||
local mem_pct=$((mem_used * 100 / mem_total))
|
||||
|
||||
# Disk usage (root filesystem)
|
||||
local disk_info=$(df / | tail -1)
|
||||
local disk_total=$(echo "$disk_info" | awk '{print $2}')
|
||||
local disk_used=$(echo "$disk_info" | awk '{print $3}')
|
||||
local disk_pct=$(echo "$disk_info" | awk '{print $5}' | tr -d '%')
|
||||
|
||||
# Network stats (sum all interfaces)
|
||||
local net_rx=0
|
||||
local net_tx=0
|
||||
for iface in $(ls /sys/class/net/ | grep -v lo); do
|
||||
if [ -f "/sys/class/net/$iface/statistics/rx_bytes" ]; then
|
||||
local rx=$(cat /sys/class/net/$iface/statistics/rx_bytes 2>/dev/null || echo 0)
|
||||
local tx=$(cat /sys/class/net/$iface/statistics/tx_bytes 2>/dev/null || echo 0)
|
||||
net_rx=$((net_rx + rx))
|
||||
net_tx=$((net_tx + tx))
|
||||
fi
|
||||
done
|
||||
|
||||
# Uptime
|
||||
local uptime=$(cat /proc/uptime | cut -d. -f1)
|
||||
|
||||
# Load averages
|
||||
local load_1min=$(cat /proc/loadavg | cut -d' ' -f1)
|
||||
local load_5min=$(cat /proc/loadavg | cut -d' ' -f2)
|
||||
local load_15min=$(cat /proc/loadavg | cut -d' ' -f3)
|
||||
|
||||
json_add_object "cpu"
|
||||
json_add_int "percent" "$cpu_pct"
|
||||
json_add_int "cores" "$cpu_cores"
|
||||
json_add_string "load_1min" "$load_1min"
|
||||
json_add_string "load_5min" "$load_5min"
|
||||
json_add_string "load_15min" "$load_15min"
|
||||
json_close_object
|
||||
|
||||
json_add_object "memory"
|
||||
json_add_int "percent" "$mem_pct"
|
||||
json_add_int "total_kb" "$mem_total"
|
||||
json_add_int "used_kb" "$mem_used"
|
||||
json_add_int "available_kb" "$mem_avail"
|
||||
json_close_object
|
||||
|
||||
json_add_object "disk"
|
||||
json_add_int "percent" "$disk_pct"
|
||||
json_add_int "total_kb" "$disk_total"
|
||||
json_add_int "used_kb" "$disk_used"
|
||||
json_close_object
|
||||
|
||||
json_add_object "network"
|
||||
json_add_int "rx_bytes" "$net_rx"
|
||||
json_add_int "tx_bytes" "$net_tx"
|
||||
json_close_object
|
||||
|
||||
json_add_int "uptime" "$uptime"
|
||||
json_add_int "timestamp" "$(date +%s)"
|
||||
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Get aggregated alerts from all modules
|
||||
get_alerts() {
|
||||
json_init
|
||||
json_add_array "alerts"
|
||||
|
||||
# Check each installed module for alerts via ubus
|
||||
for module in $MODULES; do
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
|
||||
if [ "$is_installed" = "1" ]; then
|
||||
# Try to call module's status method to get alerts
|
||||
local module_script=$(echo "$module" | sed 's/_/-/g')
|
||||
if [ -x "/usr/libexec/rpcd/${module_script}" ] || [ -x "/usr/libexec/rpcd/${module_script}-dashboard" ]; then
|
||||
# Call via ubus if available
|
||||
local alerts=$(ubus call "luci.${module_script//-/_}" status 2>/dev/null | jsonfilter -e '@.alerts[@]' 2>/dev/null)
|
||||
|
||||
if [ -n "$alerts" ]; then
|
||||
# Module has alerts, add them
|
||||
json_add_object ""
|
||||
json_add_string "module" "$module"
|
||||
json_add_string "message" "$alerts"
|
||||
json_add_string "severity" "warning"
|
||||
json_add_int "timestamp" "$(date +%s)"
|
||||
json_close_object
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if module service is not running
|
||||
local is_running=$(check_module_running "$module")
|
||||
if [ "$is_running" != "1" ]; then
|
||||
config_load secubox
|
||||
local name
|
||||
config_get name "$module" name "$module"
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "module" "$module"
|
||||
json_add_string "message" "$name service is not running"
|
||||
json_add_string "severity" "warning"
|
||||
json_add_int "timestamp" "$(date +%s)"
|
||||
json_close_object
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
json_close_array
|
||||
json_add_int "count" "$(ubus call luci.secubox get_alerts 2>/dev/null | jsonfilter -e '@.alerts[*]' | wc -l || echo 0)"
|
||||
json_add_int "timestamp" "$(date +%s)"
|
||||
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Execute quick actions
|
||||
quick_action() {
|
||||
local action="$1"
|
||||
|
||||
json_init
|
||||
|
||||
case "$action" in
|
||||
restart_rpcd)
|
||||
/etc/init.d/rpcd restart >/dev/null 2>&1
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "RPCD service restarted"
|
||||
;;
|
||||
restart_uhttpd)
|
||||
/etc/init.d/uhttpd restart >/dev/null 2>&1
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "uHTTPd service restarted"
|
||||
;;
|
||||
clear_cache)
|
||||
sync
|
||||
echo 3 > /proc/sys/vm/drop_caches 2>/dev/null
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "System cache cleared"
|
||||
;;
|
||||
backup_config)
|
||||
local backup_file="/tmp/backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
sysupgrade -b "$backup_file" >/dev/null 2>&1
|
||||
if [ -f "$backup_file" ]; then
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Configuration backup created"
|
||||
json_add_string "file" "$backup_file"
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "message" "Backup failed"
|
||||
fi
|
||||
;;
|
||||
restart_network)
|
||||
/etc/init.d/network restart >/dev/null 2>&1
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Network services restarted"
|
||||
;;
|
||||
restart_firewall)
|
||||
/etc/init.d/firewall restart >/dev/null 2>&1
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Firewall restarted"
|
||||
;;
|
||||
*)
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "message" "Unknown action: $action"
|
||||
;;
|
||||
esac
|
||||
|
||||
json_add_int "timestamp" "$(date +%s)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Get all dashboard data in one call
|
||||
get_dashboard_data() {
|
||||
json_init
|
||||
|
||||
# Get status info
|
||||
local uptime=$(cat /proc/uptime | cut -d. -f1)
|
||||
local load=$(cat /proc/loadavg | cut -d' ' -f1-3)
|
||||
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
local mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
|
||||
local mem_used=$((mem_total - mem_free))
|
||||
local mem_pct=$((mem_used * 100 / mem_total))
|
||||
|
||||
json_add_object "status"
|
||||
json_add_string "version" "1.0.0"
|
||||
json_add_string "hostname" "$(uci -q get system.@system[0].hostname || echo 'SecuBox')"
|
||||
json_add_int "uptime" "$uptime"
|
||||
json_add_string "load" "$load"
|
||||
json_add_int "memory_total" "$mem_total"
|
||||
json_add_int "memory_used" "$mem_used"
|
||||
json_add_int "memory_percent" "$mem_pct"
|
||||
json_close_object
|
||||
|
||||
# Get modules list
|
||||
json_add_array "modules"
|
||||
config_load secubox
|
||||
for module in $MODULES; do
|
||||
local name desc category icon color
|
||||
config_get name "$module" name "$module"
|
||||
config_get desc "$module" description ""
|
||||
config_get category "$module" category "other"
|
||||
config_get icon "$module" icon "box"
|
||||
config_get color "$module" color "#64748b"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "id" "$module"
|
||||
json_add_string "name" "$name"
|
||||
json_add_string "description" "$desc"
|
||||
json_add_string "category" "$category"
|
||||
json_add_string "icon" "$icon"
|
||||
json_add_string "color" "$color"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
# Count installed and running modules
|
||||
local total=0 installed=0 running=0
|
||||
for module in $MODULES; do
|
||||
total=$((total + 1))
|
||||
[ "$(check_module_installed "$module")" = "1" ] && installed=$((installed + 1))
|
||||
[ "$(check_module_running "$module")" = "1" ] && running=$((running + 1))
|
||||
done
|
||||
|
||||
json_add_object "counts"
|
||||
json_add_int "total" "$total"
|
||||
json_add_int "installed" "$installed"
|
||||
json_add_int "running" "$running"
|
||||
json_close_object
|
||||
|
||||
# Get system health
|
||||
local cpu_cores=$(grep -c processor /proc/cpuinfo)
|
||||
local load_val=$(cat /proc/loadavg | cut -d' ' -f1)
|
||||
local cpu_pct=$(awk "BEGIN {printf \"%.0f\", ($load_val / $cpu_cores) * 100}")
|
||||
local disk_pct=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
|
||||
|
||||
json_add_object "health"
|
||||
json_add_int "cpu_percent" "$cpu_pct"
|
||||
json_add_int "memory_percent" "$mem_pct"
|
||||
json_add_int "disk_percent" "$disk_pct"
|
||||
json_close_object
|
||||
|
||||
# Get recent alerts (simplified)
|
||||
json_add_array "alerts"
|
||||
for module in $MODULES; do
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
|
||||
if [ "$is_installed" = "1" ] && [ "$is_running" != "1" ]; then
|
||||
config_load secubox
|
||||
local name
|
||||
config_get name "$module" name "$module"
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "module" "$module"
|
||||
json_add_string "message" "$name is not running"
|
||||
json_add_string "severity" "warning"
|
||||
json_close_object
|
||||
fi
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_int "timestamp" "$(date +%s)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
@ -408,6 +701,15 @@ case "$1" in
|
||||
json_close_object
|
||||
json_add_object "diagnostics"
|
||||
json_close_object
|
||||
json_add_object "get_system_health"
|
||||
json_close_object
|
||||
json_add_object "get_alerts"
|
||||
json_close_object
|
||||
json_add_object "quick_action"
|
||||
json_add_string "action" "string"
|
||||
json_close_object
|
||||
json_add_object "get_dashboard_data"
|
||||
json_close_object
|
||||
json_dump
|
||||
;;
|
||||
call)
|
||||
@ -454,6 +756,21 @@ case "$1" in
|
||||
diagnostics)
|
||||
get_diagnostics
|
||||
;;
|
||||
get_system_health)
|
||||
get_system_health
|
||||
;;
|
||||
get_alerts)
|
||||
get_alerts
|
||||
;;
|
||||
quick_action)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var action action ""
|
||||
quick_action "$action"
|
||||
;;
|
||||
get_dashboard_data)
|
||||
get_dashboard_data
|
||||
;;
|
||||
*)
|
||||
echo '{"error":"Unknown method"}'
|
||||
;;
|
||||
|
||||
@ -1,7 +1,30 @@
|
||||
{
|
||||
"luci-app-secubox": {
|
||||
"description": "SecuBox Dashboard",
|
||||
"read": {"ubus": {"luci.secubox": ["status", "modules"]}},
|
||||
"write": {}
|
||||
"read": {
|
||||
"ubus": {
|
||||
"luci.secubox": [
|
||||
"status",
|
||||
"modules",
|
||||
"modules_by_category",
|
||||
"module_info",
|
||||
"health",
|
||||
"diagnostics",
|
||||
"get_system_health",
|
||||
"get_alerts",
|
||||
"get_dashboard_data"
|
||||
]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.secubox": [
|
||||
"start_module",
|
||||
"stop_module",
|
||||
"restart_module",
|
||||
"quick_action"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user