feat(ui): Apply KISS theme with C3BOX sidebar to SecuBox views
- InterceptoR: Refactor to use shared KissTheme.wrap() module - Remove duplicate inline CSS (~200 lines) - Use shared theme for sidebar navigation - IoT Guard: Update to KISS dark theme styling - Use KissTheme.wrap() with sidebar - Update stat cards to use KISS classes - Update device chips and anomaly table styling - mitmproxy: Add KISS theme wrapper - Add KissTheme.wrap() for sidebar navigation - Update info card styling to match theme - System Hub: Update to KISS theme - Add KissTheme.wrap() for sidebar navigation - Update quick actions to use kiss-btn class - Inject KISS-compatible extra styles for cards Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
546da471f8
commit
edca533f07
@ -2,6 +2,7 @@
|
||||
'require view';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
'require secubox/kiss-theme';
|
||||
|
||||
var callGetStatus = rpc.declare({
|
||||
object: 'luci.interceptor',
|
||||
@ -24,27 +25,6 @@ var QUICK_LINKS = [
|
||||
{ name: 'CrowdSec', path: 'admin/secubox/security/crowdsec/overview', icon: '🛡️' }
|
||||
];
|
||||
|
||||
var C3_NAV = [
|
||||
{ cat: 'Main', items: [
|
||||
{ icon: '🏠', name: 'Home', path: 'admin/secubox-home' },
|
||||
{ icon: '📊', name: 'System Hub', path: 'admin/secubox/system/system-hub' }
|
||||
]},
|
||||
{ cat: 'Security', items: [
|
||||
{ icon: '🧙', name: 'InterceptoR', path: 'admin/secubox/interceptor/overview', active: true },
|
||||
{ icon: '🛡️', name: 'CrowdSec', path: 'admin/secubox/security/crowdsec/overview' },
|
||||
{ icon: '🔍', name: 'mitmproxy', path: 'admin/secubox/security/mitmproxy/status' },
|
||||
{ icon: '🌐', name: 'DNS Guard', path: 'admin/secubox/security/dnsguard' }
|
||||
]},
|
||||
{ cat: 'Services', items: [
|
||||
{ icon: '📡', name: 'IoT Guard', path: 'admin/secubox/services/iot-guard' },
|
||||
{ icon: '💾', name: 'CDN Cache', path: 'admin/services/cdn-cache' },
|
||||
{ icon: '🔗', name: 'HAProxy', path: 'admin/services/haproxy' }
|
||||
]},
|
||||
{ cat: 'Navigate', items: [
|
||||
{ icon: '🌳', name: 'LuCI Tree', path: 'admin/secubox/luci-tree' }
|
||||
]}
|
||||
];
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return callGetStatus().catch(function() {
|
||||
@ -55,33 +35,25 @@ return view.extend({
|
||||
render: function(data) {
|
||||
var self = this;
|
||||
|
||||
// Inject KISS CSS
|
||||
this.injectCSS();
|
||||
|
||||
if (!data || !data.success) {
|
||||
return E('div', { 'class': 'kiss-root' }, [
|
||||
return KissTheme.wrap([
|
||||
E('div', { 'class': 'kiss-card kiss-panel-red' }, [
|
||||
E('div', { 'class': 'kiss-card-title' }, '⚠️ InterceptoR Status Unavailable'),
|
||||
E('p', { 'style': 'color: var(--kiss-muted);' }, 'Failed to load status. Check if RPCD service is running.')
|
||||
])
|
||||
]);
|
||||
], 'admin/secubox/interceptor/overview');
|
||||
}
|
||||
|
||||
var summary = data.summary || {};
|
||||
var score = summary.health_score || 0;
|
||||
var pillarsActive = summary.pillars_active || 0;
|
||||
|
||||
return E('div', { 'class': 'kiss-root kiss-with-sidebar' }, [
|
||||
// Sidebar
|
||||
this.renderSidebar(),
|
||||
|
||||
// Main content
|
||||
E('div', { 'class': 'kiss-main' }, [
|
||||
// Header
|
||||
E('div', { 'style': 'margin-bottom: 24px;' }, [
|
||||
E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '🧙 InterceptoR'),
|
||||
E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'The Gandalf Proxy — Transparent traffic interception')
|
||||
]),
|
||||
var content = [
|
||||
// Header
|
||||
E('div', { 'style': 'margin-bottom: 24px;' }, [
|
||||
E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '🧙 InterceptoR'),
|
||||
E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'The Gandalf Proxy — Transparent traffic interception')
|
||||
]),
|
||||
|
||||
// Health Score Card
|
||||
E('div', { 'class': 'kiss-card', 'style': 'text-align: center; padding: 30px; margin-bottom: 20px;' }, [
|
||||
@ -98,54 +70,22 @@ return view.extend({
|
||||
})
|
||||
),
|
||||
|
||||
// Quick Links
|
||||
E('div', { 'class': 'kiss-card' }, [
|
||||
E('div', { 'class': 'kiss-card-title' }, '🔗 Quick Links'),
|
||||
E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 10px;' },
|
||||
QUICK_LINKS.map(function(link) {
|
||||
return E('a', {
|
||||
'href': '/cgi-bin/luci/' + link.path,
|
||||
'class': 'kiss-btn',
|
||||
'style': 'text-decoration: none;'
|
||||
}, link.icon + ' ' + link.name);
|
||||
})
|
||||
)
|
||||
])
|
||||
// Quick Links
|
||||
E('div', { 'class': 'kiss-card' }, [
|
||||
E('div', { 'class': 'kiss-card-title' }, '🔗 Quick Links'),
|
||||
E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 10px;' },
|
||||
QUICK_LINKS.map(function(link) {
|
||||
return E('a', {
|
||||
'href': '/cgi-bin/luci/' + link.path,
|
||||
'class': 'kiss-btn',
|
||||
'style': 'text-decoration: none;'
|
||||
}, link.icon + ' ' + link.name);
|
||||
})
|
||||
)
|
||||
])
|
||||
]);
|
||||
},
|
||||
];
|
||||
|
||||
renderSidebar: function() {
|
||||
var navItems = [];
|
||||
|
||||
C3_NAV.forEach(function(cat) {
|
||||
navItems.push(E('div', { 'class': 'kiss-nav-section' }, cat.cat));
|
||||
cat.items.forEach(function(item) {
|
||||
navItems.push(E('a', {
|
||||
'href': '/cgi-bin/luci/' + item.path,
|
||||
'class': 'kiss-nav-item' + (item.active ? ' active' : '')
|
||||
}, [
|
||||
E('span', { 'class': 'kiss-nav-icon' }, item.icon),
|
||||
item.name
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
||||
return E('nav', { 'class': 'kiss-sidebar' }, [
|
||||
// Logo
|
||||
E('div', { 'class': 'kiss-sidebar-logo' }, [
|
||||
E('div', { 'class': 'kiss-logo-text' }, [
|
||||
E('span', { 'style': 'color: var(--kiss-green);' }, 'C'),
|
||||
E('span', { 'style': 'color: var(--kiss-red); font-size: 14px; vertical-align: super;' }, '3'),
|
||||
E('span', { 'style': 'color: var(--kiss-blue);' }, 'B'),
|
||||
E('span', { 'style': 'color: #37474F;' }, 'O'),
|
||||
E('span', { 'style': 'color: var(--kiss-green);' }, 'X')
|
||||
]),
|
||||
E('div', { 'class': 'kiss-logo-sub' }, 'SECUBOX')
|
||||
]),
|
||||
// Nav
|
||||
E('div', { 'class': 'kiss-nav' }, navItems)
|
||||
]);
|
||||
return KissTheme.wrap(content, 'admin/secubox/interceptor/overview');
|
||||
},
|
||||
|
||||
renderPillar: function(pillar, data) {
|
||||
@ -193,135 +133,6 @@ return view.extend({
|
||||
return 'var(--kiss-red)';
|
||||
},
|
||||
|
||||
kissMode: true,
|
||||
|
||||
injectCSS: function() {
|
||||
var self = this;
|
||||
if (document.querySelector('#kiss-interceptor-css')) return;
|
||||
|
||||
var css = `
|
||||
:root {
|
||||
--kiss-bg: #0a0e17; --kiss-bg2: #111827; --kiss-card: #161e2e;
|
||||
--kiss-line: #1e293b; --kiss-text: #e2e8f0; --kiss-muted: #94a3b8;
|
||||
--kiss-green: #00C853; --kiss-red: #FF1744; --kiss-blue: #2979FF;
|
||||
--kiss-cyan: #22d3ee; --kiss-yellow: #fbbf24;
|
||||
}
|
||||
.kiss-root {
|
||||
background: var(--kiss-bg); color: var(--kiss-text);
|
||||
font-family: 'Segoe UI', sans-serif; min-height: 100vh;
|
||||
}
|
||||
.kiss-with-sidebar { display: flex; }
|
||||
.kiss-sidebar {
|
||||
position: fixed; left: 0; top: 0; bottom: 0; width: 200px;
|
||||
background: linear-gradient(180deg, #0d1321 0%, var(--kiss-bg) 100%);
|
||||
border-right: 1px solid var(--kiss-line); z-index: 100;
|
||||
display: flex; flex-direction: column; overflow-y: auto;
|
||||
}
|
||||
.kiss-sidebar-logo {
|
||||
padding: 16px; border-bottom: 1px solid var(--kiss-line); text-align: center;
|
||||
}
|
||||
.kiss-logo-text { font-weight: 900; font-size: 24px; letter-spacing: -1px; }
|
||||
.kiss-logo-sub { font-size: 9px; color: var(--kiss-muted); letter-spacing: 2px; margin-top: 4px; }
|
||||
.kiss-nav { flex: 1; padding: 8px 0; }
|
||||
.kiss-nav-section {
|
||||
padding: 8px 12px 4px; font-size: 9px; letter-spacing: 2px;
|
||||
text-transform: uppercase; color: var(--kiss-muted);
|
||||
}
|
||||
.kiss-nav-item {
|
||||
display: flex; align-items: center; gap: 10px; padding: 8px 16px;
|
||||
text-decoration: none; font-size: 13px; color: var(--kiss-muted);
|
||||
transition: all 0.2s; border-left: 2px solid transparent;
|
||||
}
|
||||
.kiss-nav-item:hover { background: rgba(255,255,255,0.03); color: var(--kiss-text); }
|
||||
.kiss-nav-item.active { color: var(--kiss-green); background: rgba(0,200,83,0.05); border-left-color: var(--kiss-green); }
|
||||
.kiss-nav-icon { font-size: 16px; width: 20px; text-align: center; }
|
||||
.kiss-main { margin-left: 200px; padding: 20px; flex: 1; min-height: 100vh; }
|
||||
.kiss-card {
|
||||
background: var(--kiss-card); border: 1px solid var(--kiss-line);
|
||||
border-radius: 12px; padding: 20px; margin-bottom: 16px;
|
||||
}
|
||||
.kiss-card-title { font-weight: 700; font-size: 16px; margin-bottom: 12px; }
|
||||
.kiss-grid { display: grid; gap: 16px; }
|
||||
.kiss-grid-auto { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
|
||||
.kiss-btn {
|
||||
padding: 10px 16px; border-radius: 8px; font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; border: 1px solid var(--kiss-line); background: var(--kiss-bg2);
|
||||
color: var(--kiss-text); transition: all 0.2s; display: inline-flex; align-items: center; gap: 6px;
|
||||
}
|
||||
.kiss-btn:hover { border-color: rgba(0,200,83,0.3); background: rgba(0,200,83,0.05); }
|
||||
.kiss-panel-red { border-left: 3px solid var(--kiss-red); }
|
||||
#kiss-toggle {
|
||||
position: fixed; top: 10px; right: 10px; z-index: 99999;
|
||||
font-size: 32px; cursor: pointer; opacity: 0.7; transition: all 0.3s;
|
||||
background: rgba(0,0,0,0.5); border-radius: 50%; width: 50px; height: 50px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
#kiss-toggle:hover { opacity: 1; transform: scale(1.1); }
|
||||
@media (max-width: 768px) {
|
||||
.kiss-sidebar { width: 60px; }
|
||||
.kiss-sidebar-logo, .kiss-nav-section { display: none; }
|
||||
.kiss-nav-item { padding: 12px; justify-content: center; }
|
||||
.kiss-nav-item span:last-child { display: none; }
|
||||
.kiss-main { margin-left: 60px; }
|
||||
.kiss-grid-auto { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.kiss-sidebar { display: none; }
|
||||
.kiss-main { margin-left: 0; }
|
||||
.kiss-grid-auto { grid-template-columns: 1fr; }
|
||||
}
|
||||
`;
|
||||
var style = document.createElement('style');
|
||||
style.id = 'kiss-interceptor-css';
|
||||
style.textContent = css;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Add toggle button
|
||||
if (!document.querySelector('#kiss-toggle')) {
|
||||
var toggle = document.createElement('div');
|
||||
toggle.id = 'kiss-toggle';
|
||||
toggle.innerHTML = '👁️';
|
||||
toggle.title = 'Toggle KISS/LuCI mode';
|
||||
toggle.onclick = function() { self.toggleMode(); };
|
||||
document.body.appendChild(toggle);
|
||||
}
|
||||
|
||||
// Hide LuCI chrome
|
||||
this.hideChrome();
|
||||
},
|
||||
|
||||
hideChrome: function() {
|
||||
document.body.style.background = 'var(--kiss-bg)';
|
||||
['#mainmenu', '.main-left', 'header', 'footer', '#topmenu', '#tabmenu'].forEach(function(sel) {
|
||||
var el = document.querySelector(sel);
|
||||
if (el) el.style.display = 'none';
|
||||
});
|
||||
var main = document.querySelector('.main-right') || document.querySelector('#maincontent');
|
||||
if (main) { main.style.marginLeft = '0'; main.style.padding = '0'; main.style.maxWidth = 'none'; }
|
||||
},
|
||||
|
||||
showChrome: function() {
|
||||
document.body.style.background = '';
|
||||
['#mainmenu', '.main-left', 'header', 'footer', '#topmenu', '#tabmenu'].forEach(function(sel) {
|
||||
var el = document.querySelector(sel);
|
||||
if (el) el.style.display = '';
|
||||
});
|
||||
var main = document.querySelector('.main-right') || document.querySelector('#maincontent');
|
||||
if (main) { main.style.marginLeft = ''; main.style.padding = ''; main.style.maxWidth = ''; }
|
||||
},
|
||||
|
||||
toggleMode: function() {
|
||||
this.kissMode = !this.kissMode;
|
||||
var toggle = document.getElementById('kiss-toggle');
|
||||
if (this.kissMode) {
|
||||
toggle.innerHTML = '👁️';
|
||||
this.hideChrome();
|
||||
} else {
|
||||
toggle.innerHTML = '👁️🗨️';
|
||||
this.showChrome();
|
||||
}
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
'require view';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
'require secubox/kiss-theme';
|
||||
|
||||
var callStatus = rpc.declare({
|
||||
object: 'luci.iot-guard',
|
||||
@ -28,27 +29,19 @@ var callScan = rpc.declare({
|
||||
expect: {}
|
||||
});
|
||||
|
||||
// Device class icons (emoji-free)
|
||||
// Device class icons
|
||||
var CLASS_ICONS = {
|
||||
camera: '[CAM]',
|
||||
thermostat: '[TMP]',
|
||||
lighting: '[LGT]',
|
||||
plug: '[PLG]',
|
||||
assistant: '[AST]',
|
||||
media: '[MED]',
|
||||
lock: '[LCK]',
|
||||
sensor: '[SNS]',
|
||||
diy: '[DIY]',
|
||||
mixed: '[MIX]',
|
||||
unknown: '[???]'
|
||||
};
|
||||
|
||||
// Risk colors
|
||||
var RISK_COLORS = {
|
||||
high: '#ff4444',
|
||||
medium: '#ffaa00',
|
||||
low: '#44cc44',
|
||||
unknown: '#888888'
|
||||
camera: '📷',
|
||||
thermostat: '🌡️',
|
||||
lighting: '💡',
|
||||
plug: '🔌',
|
||||
assistant: '🎤',
|
||||
media: '📺',
|
||||
lock: '🔒',
|
||||
sensor: '📡',
|
||||
diy: '🛠️',
|
||||
mixed: '🔗',
|
||||
unknown: '❓'
|
||||
};
|
||||
|
||||
return view.extend({
|
||||
@ -70,43 +63,7 @@ return view.extend({
|
||||
var status = data[0] || {};
|
||||
var devices = (data[1] && data[1].devices) || [];
|
||||
var anomalies = (data[2] && data[2].anomalies) || [];
|
||||
|
||||
var view = E('div', { 'class': 'cbi-map', 'style': 'padding: 20px;' }, [
|
||||
// Header
|
||||
E('h2', { 'style': 'margin-bottom: 5px;' }, 'IoT Guard'),
|
||||
E('div', { 'style': 'color: #666; margin-bottom: 20px;' }, 'Device Isolation & Security Monitoring'),
|
||||
|
||||
// Status Cards Row
|
||||
E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 15px; margin-bottom: 25px;' }, [
|
||||
this.renderStatCard('Devices', status.total_devices || 0, '#4a9eff'),
|
||||
this.renderStatCard('Isolated', status.isolated || 0, '#ffaa00'),
|
||||
this.renderStatCard('Blocked', status.blocked || 0, '#ff4444'),
|
||||
this.renderStatCard('High Risk', status.high_risk || 0, '#ff4444'),
|
||||
this.renderStatCard('Anomalies', status.anomalies || 0, '#ff6600'),
|
||||
this.renderScoreCard('Security Score', status.security_score || 0)
|
||||
]),
|
||||
|
||||
// Action buttons
|
||||
E('div', { 'style': 'margin-bottom: 25px;' }, [
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'click': L.bind(this.handleScan, this)
|
||||
}, 'Scan Network'),
|
||||
E('a', {
|
||||
'href': L.url('admin/secubox/services/iot-guard/devices'),
|
||||
'class': 'cbi-button',
|
||||
'style': 'margin-left: 10px;'
|
||||
}, 'View All Devices')
|
||||
]),
|
||||
|
||||
// Device Grid by Risk
|
||||
E('h3', { 'style': 'margin-top: 25px; margin-bottom: 15px;' }, 'Devices by Risk Level'),
|
||||
this.renderDeviceGrid(devices),
|
||||
|
||||
// Recent Anomalies
|
||||
E('h3', { 'style': 'margin-top: 30px; margin-bottom: 15px;' }, 'Recent Anomalies'),
|
||||
this.renderAnomaliesTable(anomalies)
|
||||
]);
|
||||
var self = this;
|
||||
|
||||
// Poll for updates
|
||||
poll.add(L.bind(function() {
|
||||
@ -115,39 +72,89 @@ return view.extend({
|
||||
}, this));
|
||||
}, this), 10);
|
||||
|
||||
return view;
|
||||
var content = [
|
||||
// Header
|
||||
E('div', { 'style': 'margin-bottom: 24px;' }, [
|
||||
E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '📡 IoT Guard'),
|
||||
E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'Device Isolation & Security Monitoring')
|
||||
]),
|
||||
|
||||
// Stats Grid
|
||||
E('div', { 'class': 'kiss-grid kiss-grid-auto', 'style': 'margin-bottom: 24px;' }, [
|
||||
this.renderStatCard('Devices', status.total_devices || 0, 'var(--kiss-blue)'),
|
||||
this.renderStatCard('Isolated', status.isolated || 0, 'var(--kiss-yellow)'),
|
||||
this.renderStatCard('Blocked', status.blocked || 0, 'var(--kiss-red)'),
|
||||
this.renderStatCard('High Risk', status.high_risk || 0, 'var(--kiss-red)'),
|
||||
this.renderStatCard('Anomalies', status.anomalies || 0, 'var(--kiss-orange)'),
|
||||
this.renderScoreCard('Security Score', status.security_score || 0)
|
||||
]),
|
||||
|
||||
// Action buttons
|
||||
E('div', { 'class': 'kiss-card', 'style': 'display: flex; gap: 12px; flex-wrap: wrap;' }, [
|
||||
E('button', {
|
||||
'class': 'kiss-btn kiss-btn-green',
|
||||
'click': L.bind(this.handleScan, this)
|
||||
}, '🔍 Scan Network'),
|
||||
E('a', {
|
||||
'href': L.url('admin/secubox/services/iot-guard/devices'),
|
||||
'class': 'kiss-btn',
|
||||
'style': 'text-decoration: none;'
|
||||
}, '📋 View All Devices'),
|
||||
E('a', {
|
||||
'href': L.url('admin/secubox/services/iot-guard/settings'),
|
||||
'class': 'kiss-btn',
|
||||
'style': 'text-decoration: none;'
|
||||
}, '⚙️ Settings')
|
||||
]),
|
||||
|
||||
// Device Grid by Risk
|
||||
E('div', { 'class': 'kiss-card' }, [
|
||||
E('div', { 'class': 'kiss-card-title' }, '🎯 Devices by Risk Level'),
|
||||
this.renderDeviceGrid(devices)
|
||||
]),
|
||||
|
||||
// Recent Anomalies
|
||||
E('div', { 'class': 'kiss-card' }, [
|
||||
E('div', { 'class': 'kiss-card-title' }, '⚠️ Recent Anomalies'),
|
||||
this.renderAnomaliesTable(anomalies)
|
||||
])
|
||||
];
|
||||
|
||||
return KissTheme.wrap(content, 'admin/secubox/services/iot-guard');
|
||||
},
|
||||
|
||||
renderStatCard: function(label, value, color) {
|
||||
return E('div', {
|
||||
'style': 'background: linear-gradient(135deg, ' + color + '22, ' + color + '11); ' +
|
||||
'border: 1px solid ' + color + '44; border-radius: 8px; padding: 15px 20px; ' +
|
||||
'min-width: 120px; text-align: center;'
|
||||
}, [
|
||||
return E('div', { 'class': 'kiss-stat', 'style': 'border-left: 3px solid ' + color + ';' }, [
|
||||
E('div', {
|
||||
'style': 'font-size: 28px; font-weight: bold; color: ' + color + ';',
|
||||
'class': 'kiss-stat-value',
|
||||
'style': 'color: ' + color + ';',
|
||||
'data-stat': label.toLowerCase().replace(' ', '-')
|
||||
}, String(value)),
|
||||
E('div', { 'style': 'color: #666; font-size: 12px; margin-top: 5px;' }, label)
|
||||
E('div', { 'class': 'kiss-stat-label' }, label)
|
||||
]);
|
||||
},
|
||||
|
||||
renderScoreCard: function(label, score) {
|
||||
var color = score >= 70 ? '#44cc44' : (score >= 40 ? '#ffaa00' : '#ff4444');
|
||||
return E('div', {
|
||||
'style': 'background: linear-gradient(135deg, ' + color + '22, ' + color + '11); ' +
|
||||
'border: 1px solid ' + color + '44; border-radius: 8px; padding: 15px 20px; ' +
|
||||
'min-width: 140px; text-align: center;'
|
||||
}, [
|
||||
var color = score >= 70 ? 'var(--kiss-green)' : (score >= 40 ? 'var(--kiss-yellow)' : 'var(--kiss-red)');
|
||||
return E('div', { 'class': 'kiss-stat', 'style': 'border-left: 3px solid ' + color + ';' }, [
|
||||
E('div', {
|
||||
'style': 'font-size: 28px; font-weight: bold; color: ' + color + ';',
|
||||
'class': 'kiss-stat-value',
|
||||
'style': 'color: ' + color + ';',
|
||||
'data-stat': 'security-score'
|
||||
}, score + '%'),
|
||||
E('div', { 'style': 'color: #666; font-size: 12px; margin-top: 5px;' }, label)
|
||||
E('div', { 'class': 'kiss-stat-label' }, label)
|
||||
]);
|
||||
},
|
||||
|
||||
renderDeviceGrid: function(devices) {
|
||||
var self = this;
|
||||
var RISK_COLORS = {
|
||||
high: 'var(--kiss-red)',
|
||||
medium: 'var(--kiss-yellow)',
|
||||
low: 'var(--kiss-green)',
|
||||
unknown: 'var(--kiss-muted)'
|
||||
};
|
||||
|
||||
var groups = { high: [], medium: [], low: [], unknown: [] };
|
||||
|
||||
devices.forEach(function(d) {
|
||||
@ -164,76 +171,78 @@ return view.extend({
|
||||
['high', 'medium', 'low'].forEach(function(risk) {
|
||||
if (groups[risk].length === 0) return;
|
||||
|
||||
rows.push(E('div', { 'style': 'margin-bottom: 15px;' }, [
|
||||
rows.push(E('div', { 'style': 'margin-bottom: 16px;' }, [
|
||||
E('div', {
|
||||
'style': 'color: ' + RISK_COLORS[risk] + '; font-weight: bold; margin-bottom: 8px; text-transform: uppercase;'
|
||||
'style': 'color: ' + RISK_COLORS[risk] + '; font-weight: 600; margin-bottom: 10px; font-size: 12px; text-transform: uppercase; letter-spacing: 1px;'
|
||||
}, risk + ' Risk (' + groups[risk].length + ')'),
|
||||
E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 10px;' },
|
||||
groups[risk].slice(0, 12).map(function(d) {
|
||||
return this.renderDeviceChip(d);
|
||||
}, this)
|
||||
return self.renderDeviceChip(d, RISK_COLORS);
|
||||
})
|
||||
)
|
||||
]));
|
||||
}, this);
|
||||
});
|
||||
|
||||
if (rows.length === 0) {
|
||||
return E('div', { 'style': 'color: #888; padding: 20px; text-align: center;' },
|
||||
'No IoT devices detected. Click "Scan Network" to discover devices.');
|
||||
return E('div', { 'style': 'color: var(--kiss-muted); padding: 30px; text-align: center;' }, [
|
||||
E('div', { 'style': 'font-size: 48px; margin-bottom: 12px;' }, '📡'),
|
||||
E('p', {}, 'No IoT devices detected.'),
|
||||
E('p', { 'style': 'font-size: 12px;' }, 'Click "Scan Network" to discover devices.')
|
||||
]);
|
||||
}
|
||||
|
||||
return E('div', {}, rows);
|
||||
},
|
||||
|
||||
renderDeviceChip: function(device) {
|
||||
renderDeviceChip: function(device, RISK_COLORS) {
|
||||
var icon = CLASS_ICONS[device.device_class] || CLASS_ICONS.unknown;
|
||||
var color = RISK_COLORS[device.risk_level] || RISK_COLORS.unknown;
|
||||
|
||||
var statusBadge = '';
|
||||
if (device.isolated) statusBadge = ' [ISO]';
|
||||
else if (device.blocked) statusBadge = ' [BLK]';
|
||||
else if (device.trusted) statusBadge = ' [OK]';
|
||||
if (device.isolated) statusBadge = ' 🔸';
|
||||
else if (device.blocked) statusBadge = ' 🚫';
|
||||
else if (device.trusted) statusBadge = ' ✓';
|
||||
|
||||
var label = device.hostname || device.ip || device.mac.substring(9);
|
||||
|
||||
return E('a', {
|
||||
'href': L.url('admin/secubox/services/iot-guard/devices') + '?mac=' + encodeURIComponent(device.mac),
|
||||
'style': 'background: #1a1a2e; border: 1px solid ' + color + '66; border-radius: 6px; ' +
|
||||
'padding: 8px 12px; color: #eee; text-decoration: none; display: inline-flex; ' +
|
||||
'align-items: center; gap: 8px; font-size: 13px;',
|
||||
'class': 'kiss-btn',
|
||||
'style': 'text-decoration: none; border-color: ' + color + '66;',
|
||||
'title': device.vendor + ' - ' + device.mac
|
||||
}, [
|
||||
E('span', { 'style': 'color: ' + color + '; font-weight: bold;' }, icon),
|
||||
E('span', {}, icon),
|
||||
E('span', {}, label.length > 15 ? label.substring(0, 12) + '...' : label),
|
||||
statusBadge ? E('span', { 'style': 'color: #888; font-size: 11px;' }, statusBadge) : ''
|
||||
statusBadge ? E('span', { 'style': 'font-size: 10px;' }, statusBadge) : ''
|
||||
]);
|
||||
},
|
||||
|
||||
renderAnomaliesTable: function(anomalies) {
|
||||
if (!anomalies || anomalies.length === 0) {
|
||||
return E('div', {
|
||||
'style': 'background: #0a2a0a; border: 1px solid #2a4a2a; border-radius: 8px; ' +
|
||||
'padding: 20px; text-align: center; color: #4a8a4a;'
|
||||
}, 'No recent anomalies detected');
|
||||
return E('div', { 'style': 'text-align: center; padding: 30px; color: var(--kiss-green);' }, [
|
||||
E('div', { 'style': 'font-size: 48px; margin-bottom: 12px;' }, '✅'),
|
||||
E('p', {}, 'No recent anomalies detected')
|
||||
]);
|
||||
}
|
||||
|
||||
var rows = anomalies.map(function(a) {
|
||||
var sevColor = a.severity === 'high' ? '#ff4444' : (a.severity === 'medium' ? '#ffaa00' : '#888');
|
||||
var sevColor = a.severity === 'high' ? 'var(--kiss-red)' : (a.severity === 'medium' ? 'var(--kiss-yellow)' : 'var(--kiss-muted)');
|
||||
return E('tr', {}, [
|
||||
E('td', { 'style': 'padding: 8px; border-bottom: 1px solid #333;' }, a.timestamp ? a.timestamp.substring(11, 16) : '-'),
|
||||
E('td', { 'style': 'padding: 8px; border-bottom: 1px solid #333;' }, a.hostname || a.mac),
|
||||
E('td', { 'style': 'padding: 8px; border-bottom: 1px solid #333;' }, a.type),
|
||||
E('td', { 'style': 'padding: 8px; border-bottom: 1px solid #333; color: ' + sevColor + ';' }, a.severity),
|
||||
E('td', { 'style': 'padding: 8px; border-bottom: 1px solid #333; color: #888;' }, a.description)
|
||||
E('td', { 'class': 'td' }, a.timestamp ? a.timestamp.substring(11, 16) : '-'),
|
||||
E('td', { 'class': 'td' }, a.hostname || a.mac),
|
||||
E('td', { 'class': 'td' }, a.type),
|
||||
E('td', { 'class': 'td', 'style': 'color: ' + sevColor + '; font-weight: 600;' }, a.severity),
|
||||
E('td', { 'class': 'td', 'style': 'color: var(--kiss-muted);' }, a.description)
|
||||
]);
|
||||
});
|
||||
|
||||
return E('table', { 'style': 'width: 100%; border-collapse: collapse;' }, [
|
||||
E('thead', {}, E('tr', { 'style': 'background: #222;' }, [
|
||||
E('th', { 'style': 'padding: 10px; text-align: left;' }, 'Time'),
|
||||
E('th', { 'style': 'padding: 10px; text-align: left;' }, 'Device'),
|
||||
E('th', { 'style': 'padding: 10px; text-align: left;' }, 'Type'),
|
||||
E('th', { 'style': 'padding: 10px; text-align: left;' }, 'Severity'),
|
||||
E('th', { 'style': 'padding: 10px; text-align: left;' }, 'Description')
|
||||
return E('table', { 'class': 'kiss-table' }, [
|
||||
E('thead', {}, E('tr', {}, [
|
||||
E('th', { 'class': 'th' }, 'Time'),
|
||||
E('th', { 'class': 'th' }, 'Device'),
|
||||
E('th', { 'class': 'th' }, 'Type'),
|
||||
E('th', { 'class': 'th' }, 'Severity'),
|
||||
E('th', { 'class': 'th' }, 'Description')
|
||||
])),
|
||||
E('tbody', {}, rows)
|
||||
]);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
'require poll';
|
||||
'require rpc';
|
||||
'require ui';
|
||||
'require secubox/kiss-theme';
|
||||
|
||||
var callStatus = rpc.declare({
|
||||
object: 'luci.mitmproxy',
|
||||
@ -93,8 +94,12 @@ return view.extend({
|
||||
var bans = bansData.bans || [];
|
||||
var self = this;
|
||||
|
||||
var view = E('div', { 'class': 'cbi-map' }, [
|
||||
E('h2', {}, _('mitmproxy - HTTPS Intercepting Proxy')),
|
||||
var content = [
|
||||
// Header
|
||||
E('div', { 'style': 'margin-bottom: 24px;' }, [
|
||||
E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '🔍 mitmproxy'),
|
||||
E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'HTTPS Intercepting Proxy & WAF')
|
||||
]),
|
||||
|
||||
// Service Status Card
|
||||
E('div', { 'class': 'cbi-section' }, [
|
||||
@ -500,27 +505,27 @@ return view.extend({
|
||||
]),
|
||||
|
||||
// Info Card
|
||||
E('div', { 'class': 'cbi-section' }, [
|
||||
E('h3', {}, _('Information')),
|
||||
E('div', { 'class': 'cbi-section-node' }, [
|
||||
E('p', {}, _('mitmproxy is an interactive HTTPS proxy for traffic inspection and modification.')),
|
||||
E('ul', {}, [
|
||||
E('div', { 'class': 'kiss-card' }, [
|
||||
E('div', { 'class': 'kiss-card-title' }, '📖 ' + _('Information')),
|
||||
E('div', {}, [
|
||||
E('p', { 'style': 'color: var(--kiss-muted); margin-bottom: 12px;' }, _('mitmproxy is an interactive HTTPS proxy for traffic inspection and modification.')),
|
||||
E('ul', { 'style': 'color: var(--kiss-muted); margin: 0; padding-left: 20px;' }, [
|
||||
E('li', {}, _('Intercept and inspect HTTP/HTTPS traffic')),
|
||||
E('li', {}, _('Detect SQL injection, XSS, and other attacks')),
|
||||
E('li', {}, _('Log threats to CrowdSec for automatic blocking')),
|
||||
E('li', {}, _('Access the Web UI for detailed traffic analysis'))
|
||||
]),
|
||||
E('p', { 'style': 'margin-top: 12px;' }, [
|
||||
E('strong', {}, _('CA Certificate: ')),
|
||||
E('p', { 'style': 'margin-top: 12px; color: var(--kiss-muted);' }, [
|
||||
E('strong', { 'style': 'color: var(--kiss-text);' }, _('CA Certificate: ')),
|
||||
_('To inspect HTTPS traffic, install the CA certificate from '),
|
||||
E('a', { 'href': 'http://mitm.it', 'target': '_blank' }, 'http://mitm.it'),
|
||||
E('a', { 'href': 'http://mitm.it', 'target': '_blank', 'style': 'color: var(--kiss-cyan);' }, 'http://mitm.it'),
|
||||
_(' on client devices.')
|
||||
])
|
||||
])
|
||||
])
|
||||
]);
|
||||
];
|
||||
|
||||
return view;
|
||||
return KissTheme.wrap(content, 'admin/secubox/security/mitmproxy/status');
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
'require rpc';
|
||||
'require ui';
|
||||
'require poll';
|
||||
'require secubox/kiss-theme';
|
||||
|
||||
var callStatus = rpc.declare({
|
||||
object: 'luci.system-hub',
|
||||
@ -184,20 +185,25 @@ return view.extend({
|
||||
|
||||
renderQuickActions: function() {
|
||||
return E('div', { 'class': 'sh-section' }, [
|
||||
E('h3', {}, 'Quick Actions'),
|
||||
E('h3', {}, '⚡ Quick Actions'),
|
||||
E('div', { 'class': 'sh-actions' }, [
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'class': 'kiss-btn',
|
||||
'click': function() { window.location.href = L.url('admin/system/system'); }
|
||||
}, '\u2699 System Settings'),
|
||||
}, '⚙️ System Settings'),
|
||||
E('button', {
|
||||
'class': 'cbi-button',
|
||||
'class': 'kiss-btn',
|
||||
'click': function() { window.location.href = L.url('admin/system/reboot'); }
|
||||
}, '\uD83D\uDD04 Reboot'),
|
||||
}, '🔄 Reboot'),
|
||||
E('button', {
|
||||
'class': 'cbi-button',
|
||||
'class': 'kiss-btn',
|
||||
'click': function() { window.location.href = L.url('admin/system/flash'); }
|
||||
}, '\uD83D\uDCE6 Backup/Flash')
|
||||
}, '📦 Backup/Flash'),
|
||||
E('a', {
|
||||
'href': L.url('admin/secubox/system/system-hub/health'),
|
||||
'class': 'kiss-btn',
|
||||
'style': 'text-decoration: none;'
|
||||
}, '❤️ Health Check')
|
||||
])
|
||||
]);
|
||||
},
|
||||
@ -303,51 +309,52 @@ return view.extend({
|
||||
});
|
||||
}, 5);
|
||||
|
||||
return E('div', { 'class': 'sh-dashboard' }, [
|
||||
E('style', {}, [
|
||||
'.sh-dashboard { max-width: 1200px; }',
|
||||
'.sh-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin-bottom: 24px; }',
|
||||
'.sh-card { background: #fff; border-radius: 8px; padding: 16px; display: flex; align-items: center; gap: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }',
|
||||
'.sh-card-icon { width: 48px; height: 48px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 20px; color: #fff; flex-shrink: 0; }',
|
||||
'.sh-card-value { font-size: 18px; font-weight: 700; }',
|
||||
'.sh-card-label { font-size: 12px; color: #666; }',
|
||||
'.sh-section { background: #fff; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }',
|
||||
'.sh-section h3 { margin: 0 0 16px 0; font-size: 16px; font-weight: 600; color: #333; }',
|
||||
'.sh-actions { display: flex; gap: 10px; flex-wrap: wrap; }',
|
||||
'.sh-resources { display: flex; flex-direction: column; gap: 16px; }',
|
||||
'.sh-resource { }',
|
||||
'.sh-resource-header { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 13px; }',
|
||||
'.sh-resource-bar { height: 12px; background: #eee; border-radius: 6px; overflow: hidden; }',
|
||||
'.sh-resource-fill { height: 100%; transition: width 0.3s, background 0.3s; border-radius: 6px; }',
|
||||
'.sh-resource-percent { font-size: 12px; color: #666; margin-top: 4px; text-align: right; }',
|
||||
'.sh-status-badge { display: inline-block; padding: 2px 8px; border-radius: 4px; color: #fff; font-size: 11px; font-weight: 600; }',
|
||||
'.table { width: 100%; border-collapse: collapse; }',
|
||||
'.table th, .table td { padding: 10px 12px; text-align: left; border-bottom: 1px solid #eee; }',
|
||||
'.table th { background: #f8f9fa; font-weight: 600; font-size: 12px; text-transform: uppercase; color: #666; }',
|
||||
'.table tbody tr:hover { background: #f8f9fa; }',
|
||||
'@media (prefers-color-scheme: dark) {',
|
||||
' .sh-card { background: #2d2d2d; }',
|
||||
' .sh-card-label { color: #aaa; }',
|
||||
' .sh-card-value { color: #fff; }',
|
||||
' .sh-section { background: #2d2d2d; }',
|
||||
' .sh-section h3 { color: #eee; }',
|
||||
' .sh-resource-header { color: #ccc; }',
|
||||
' .sh-resource-bar { background: #444; }',
|
||||
' .table th { background: #333; color: #aaa; }',
|
||||
' .table td { border-color: #444; color: #ccc; }',
|
||||
' .table tbody tr:hover { background: #333; }',
|
||||
'}'
|
||||
].join('\n')),
|
||||
E('h2', { 'style': 'margin-bottom: 20px' }, '\u2699\uFE0F System Control Center'),
|
||||
E('p', { 'style': 'color: #666; margin-bottom: 24px' },
|
||||
'Unified system monitoring and management dashboard.'),
|
||||
// Additional KISS-compatible styles
|
||||
var extraStyles = `
|
||||
.sh-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
||||
.sh-card { background: var(--kiss-card); border: 1px solid var(--kiss-line); border-radius: 10px; padding: 16px; display: flex; align-items: center; gap: 12px; }
|
||||
.sh-card-icon { width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; color: #fff; flex-shrink: 0; }
|
||||
.sh-card-value { font-size: 18px; font-weight: 700; color: var(--kiss-text); }
|
||||
.sh-card-label { font-size: 11px; color: var(--kiss-muted); }
|
||||
.sh-section { background: var(--kiss-card); border: 1px solid var(--kiss-line); border-radius: 12px; padding: 20px; }
|
||||
.sh-section h3 { margin: 0 0 16px 0; font-size: 16px; font-weight: 700; color: var(--kiss-text); }
|
||||
.sh-actions { display: flex; gap: 10px; flex-wrap: wrap; }
|
||||
.sh-resources { display: flex; flex-direction: column; gap: 16px; }
|
||||
.sh-resource-header { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 13px; color: var(--kiss-muted); }
|
||||
.sh-resource-bar { height: 10px; background: rgba(255,255,255,0.06); border-radius: 5px; overflow: hidden; }
|
||||
.sh-resource-fill { height: 100%; transition: width 0.3s, background 0.3s; border-radius: 5px; }
|
||||
.sh-resource-percent { font-size: 11px; color: var(--kiss-muted); margin-top: 4px; text-align: right; }
|
||||
.sh-status-badge { display: inline-block; padding: 3px 10px; border-radius: 4px; color: #fff; font-size: 10px; font-weight: 600; letter-spacing: 0.5px; }
|
||||
`;
|
||||
// Inject extra styles
|
||||
if (!document.querySelector('#sh-kiss-extra')) {
|
||||
var style = document.createElement('style');
|
||||
style.id = 'sh-kiss-extra';
|
||||
style.textContent = extraStyles;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
var content = [
|
||||
// Header
|
||||
E('div', { 'style': 'margin-bottom: 24px;' }, [
|
||||
E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '📊 System Hub'),
|
||||
E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'Unified system monitoring and management dashboard')
|
||||
]),
|
||||
|
||||
// Status Cards
|
||||
this.renderStatusCards(status, health),
|
||||
E('div', { 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 20px;' }, [
|
||||
|
||||
// Two column grid
|
||||
E('div', { 'class': 'kiss-grid kiss-grid-2', 'style': 'margin-bottom: 20px;' }, [
|
||||
this.renderResourceBars(health, status),
|
||||
this.renderQuickActions()
|
||||
]),
|
||||
|
||||
// Services Table
|
||||
this.renderServicesTable(services)
|
||||
]);
|
||||
];
|
||||
|
||||
return KissTheme.wrap(content, 'admin/secubox/system/system-hub');
|
||||
},
|
||||
|
||||
handleSave: null,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user