From 0e5965dd6c8fc9ec59bd62f2153e97bd89ff5b66 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Tue, 10 Feb 2026 16:54:31 +0100 Subject: [PATCH] fix(client-guardian): Restore original menu path --- .../view/client-guardian/overview.js | 392 +++++------------- .../view/client-guardian/settings.js | 189 +-------- .../luci/menu.d/luci-app-client-guardian.json | 62 +-- 3 files changed, 138 insertions(+), 505 deletions(-) diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js index d7a9b220..9c99304c 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js @@ -2,16 +2,8 @@ 'require view'; 'require dom'; 'require poll'; -'require uci'; -'require ui'; 'require rpc'; -'require client-guardian/nav as CgNav'; -'require secubox-portal/header as SbHeader'; - -var callGetStatus = rpc.declare({ - object: 'luci.client-guardian', - method: 'status' -}); +'require ui'; var callGetClients = rpc.declare({ object: 'luci.client-guardian', @@ -19,12 +11,6 @@ var callGetClients = rpc.declare({ expect: { clients: [] } }); -var callGetZones = rpc.declare({ - object: 'luci.client-guardian', - method: 'zones', - expect: { zones: [] } -}); - var callApproveClient = rpc.declare({ object: 'luci.client-guardian', method: 'approve_client', @@ -37,297 +23,149 @@ var callBanClient = rpc.declare({ params: ['mac', 'reason'] }); -function formatBytes(bytes) { - if (!bytes || bytes === 0) return '0 B'; - var units = ['B', 'KB', 'MB', 'GB', 'TB']; - var i = Math.floor(Math.log(bytes) / Math.log(1024)); - i = Math.min(i, units.length - 1); - return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + units[i]; -} - -function getDeviceIcon(hostname, mac) { - hostname = (hostname || '').toLowerCase(); - mac = (mac || '').toLowerCase(); - if (hostname.match(/android|iphone|ipad|mobile|phone|samsung|xiaomi|huawei/)) return '📱'; - if (hostname.match(/pc|laptop|desktop|macbook|imac|windows|linux|ubuntu/)) return '💻'; - if (hostname.match(/camera|bulb|switch|sensor|thermostat|doorbell|lock/)) return '📷'; - if (hostname.match(/tv|roku|chromecast|firestick|appletv|media/)) return '📺'; - if (hostname.match(/playstation|xbox|nintendo|switch|steam/)) return '🎮'; - if (hostname.match(/router|switch|ap|access[-_]?point|bridge/)) return '🌐'; - if (hostname.match(/printer|print|hp-|canon-|epson-/)) return '🖨️'; - return '🔌'; -} +var callUnbanClient = rpc.declare({ + object: 'luci.client-guardian', + method: 'unban_client', + params: ['mac'] +}); return view.extend({ load: function() { - return Promise.all([ - callGetStatus(), - callGetClients(), - callGetZones(), - uci.load('client-guardian') - ]); + return callGetClients(); }, render: function(data) { - var status = data[0]; - var clients = Array.isArray(data[1]) ? data[1] : (data[1].clients || []); - var zones = Array.isArray(data[2]) ? data[2] : (data[2].zones || []); + var clients = Array.isArray(data) ? data : (data.clients || []); + var online = clients.filter(function(c) { return c.online; }).length; + var approved = clients.filter(function(c) { return c.status === 'approved'; }).length; + var banned = clients.filter(function(c) { return c.status === 'banned'; }).length; - var onlineClients = clients.filter(function(c) { return c.online; }); - var approvedClients = clients.filter(function(c) { return c.status === 'approved'; }); - var quarantineClients = clients.filter(function(c) { return c.status === 'unknown' || c.zone === 'quarantine'; }); - var bannedClients = clients.filter(function(c) { return c.status === 'banned'; }); + var view = E('div', { 'class': 'cbi-map' }, [ + E('h2', {}, 'Client Guardian'), + E('div', { 'class': 'cbi-map-descr' }, 'Network client management'), - // Main wrapper with SecuBox header - var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); - wrapper.appendChild(SbHeader.render()); - - var view = E('div', { 'class': 'client-guardian-dashboard' }, [ - E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), - E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/common.css') }), - E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }), - CgNav.renderTabs('overview'), - - // Chip Header - this.renderChipHeader(onlineClients.length, approvedClients.length, quarantineClients.length, - bannedClients.length, clients.filter(function(c) { return c.has_threats; }).length, zones.length), - - // Recent Clients Card - E('div', { 'class': 'cg-card' }, [ - E('div', { 'class': 'cg-card-header' }, [ - E('div', { 'class': 'cg-card-title' }, [ - E('span', { 'class': 'cg-card-title-icon' }, '⚡'), - 'Clients Récents' - ]), - E('span', { 'class': 'cg-card-badge' }, 'Temps réel') + // Stats + E('div', { 'style': 'display:flex;gap:20px;margin:20px 0;' }, [ + E('div', { 'style': 'padding:15px;background:#22c55e22;border-radius:8px;' }, [ + E('strong', { 'style': 'font-size:24px;color:#22c55e;' }, String(online)), + E('div', {}, 'Online') ]), - E('div', { 'class': 'cg-card-body' }, [ - E('div', { 'class': 'cg-client-list' }, - onlineClients.slice(0, 5).map(L.bind(this.renderClientItem, this, false)) - ) + E('div', { 'style': 'padding:15px;background:#3b82f622;border-radius:8px;' }, [ + E('strong', { 'style': 'font-size:24px;color:#3b82f6;' }, String(approved)), + E('div', {}, 'Approved') + ]), + E('div', { 'style': 'padding:15px;background:#ef444422;border-radius:8px;' }, [ + E('strong', { 'style': 'font-size:24px;color:#ef4444;' }, String(banned)), + E('div', {}, 'Banned') ]) ]), - // Pending Approval Card - quarantineClients.length > 0 ? E('div', { 'class': 'cg-card' }, [ - E('div', { 'class': 'cg-card-header' }, [ - E('div', { 'class': 'cg-card-title' }, [ - E('span', { 'class': 'cg-card-title-icon' }, '⏳'), - 'En Attente d\'Approbation' - ]), - E('span', { 'class': 'cg-card-badge' }, quarantineClients.length + ' clients') - ]), - E('div', { 'class': 'cg-card-body' }, [ - E('div', { 'class': 'cg-client-list' }, - quarantineClients.map(L.bind(this.renderClientItem, this, true)) - ) - ]) - ]) : E('div') - ]); - - // Setup auto-refresh polling based on UCI settings - var autoRefresh = uci.get('client-guardian', 'config', 'auto_refresh'); - var refreshInterval = parseInt(uci.get('client-guardian', 'config', 'refresh_interval') || '10'); - - if (autoRefresh === '1') { - poll.add(L.bind(function() { - return this.handleRefresh(); - }, this), refreshInterval); - } - - wrapper.appendChild(view); - return wrapper; - }, - - renderHeaderChip: function(stat) { - return E('div', { 'class': 'sh-header-chip' + (stat.tone ? ' ' + stat.tone : '') }, [ - E('span', { 'class': 'sh-chip-icon' }, stat.icon || '•'), - E('div', { 'class': 'sh-chip-text' }, [ - E('span', { 'class': 'sh-chip-label' }, stat.label), - E('strong', {}, String(stat.value)) - ]) - ]); - }, - - renderChipHeader: function(online, approved, quarantine, banned, threats, zones) { - var stats = [ - { icon: '📱', label: _('Online'), value: online, tone: online > 0 ? 'success' : '' }, - { icon: '✅', label: _('Approved'), value: approved }, - { icon: '⏳', label: _('Quarantine'), value: quarantine, tone: quarantine > 0 ? 'warn' : '' }, - { icon: '🚫', label: _('Banned'), value: banned, tone: banned > 0 ? 'error' : '' }, - { icon: '⚠️', label: _('Threats'), value: threats, tone: threats > 0 ? 'error' : '' }, - { icon: '🌐', label: _('Zones'), value: zones } - ]; - - return E('div', { 'class': 'sh-page-header sh-page-header-lite' }, [ - E('div', {}, [ - E('h2', { 'class': 'sh-page-title' }, [ - E('span', { 'class': 'sh-page-title-icon' }, '🛡️'), - _('Client Guardian') - ]), - E('p', { 'class': 'sh-page-subtitle' }, - _('Device protection · Access control · Threat monitoring')) - ]), - E('div', { 'class': 'sh-header-meta' }, stats.map(L.bind(this.renderHeaderChip, this))) - ]); - }, - - renderStatCard: function(icon, value, label) { - return E('div', { 'class': 'cg-stat-card' }, [ - E('div', { 'class': 'cg-stat-icon' }, icon), - E('div', { 'class': 'cg-stat-value' }, String(value)), - E('div', { 'class': 'cg-stat-label' }, label) - ]); - }, - - renderClientItem: function(showActions, client) { - var statusClass = client.online ? 'online' : 'offline'; - if (client.status === 'unknown' || client.zone === 'quarantine') - statusClass += ' quarantine'; - if (client.status === 'banned') - statusClass += ' banned'; - - var deviceIcon = getDeviceIcon(client.hostname || client.name, client.mac); - var zoneClass = (client.zone || 'unknown').replace('lan_', ''); - - var item = E('div', { 'class': 'cg-client-item ' + statusClass }, [ - E('div', { 'class': 'cg-client-avatar' }, deviceIcon), - E('div', { 'class': 'cg-client-info' }, [ - E('div', { 'class': 'cg-client-name' }, [ - client.online ? E('span', { 'class': 'online-indicator' }) : E('span'), - client.name || client.hostname || 'Unknown', - client.has_threats ? E('span', { - 'class': 'cg-threat-badge', - 'title': (client.threat_count || 0) + ' menace(s) active(s), score de risque: ' + (client.risk_score || 0), - 'style': 'margin-left: 8px; color: #ef4444; font-size: 16px; cursor: help;' - }, '⚠️') : E('span') - ]), - E('div', { 'class': 'cg-client-meta' }, [ - E('span', {}, client.mac), - E('span', {}, client.ip || 'N/A'), - client.has_threats ? E('span', { - 'style': 'color: #ef4444; font-weight: 500; margin-left: 8px;' - }, 'Risque: ' + (client.risk_score || 0) + '%') : E('span') - ]) - ]), - E('span', { 'class': 'cg-client-zone ' + zoneClass }, client.zone || 'unknown'), - E('div', { 'class': 'cg-client-traffic' }, [ - E('div', { 'class': 'cg-client-traffic-value' }, '↓ ' + formatBytes(client.rx_bytes || 0)), - E('div', { 'class': 'cg-client-traffic-label' }, '↑ ' + formatBytes(client.tx_bytes || 0)) + // Client Table + E('div', { 'class': 'cbi-section' }, [ + E('table', { 'class': 'table', 'id': 'client-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, 'Status'), + E('th', { 'class': 'th' }, 'Name'), + E('th', { 'class': 'th' }, 'MAC'), + E('th', { 'class': 'th' }, 'IP'), + E('th', { 'class': 'th' }, 'Actions') + ]) + ].concat(clients.map(L.bind(this.renderClientRow, this)))) ]) ]); - if (showActions) { - var actions = E('div', { 'class': 'cg-client-actions' }); + poll.add(L.bind(this.refresh, this), 10); + return view; + }, - if (client.status === 'unknown') { - var approveBtn = E('div', { - 'class': 'cg-client-action approve', - 'title': 'Approuver', - 'data-mac': client.mac - }, '✅'); - approveBtn.addEventListener('click', L.bind(this.handleApprove, this)); - actions.appendChild(approveBtn); - } - - if (client.status !== 'banned') { - var banBtn = E('div', { - 'class': 'cg-client-action ban', - 'title': 'Bannir', - 'data-mac': client.mac - }, '🚫'); - banBtn.addEventListener('click', L.bind(this.handleBan, this)); - actions.appendChild(banBtn); - } - - item.appendChild(actions); + renderClientRow: function(client) { + var statusIcon = client.online ? '🟢' : '⚪'; + var statusStyle = ''; + if (client.status === 'banned') { + statusIcon = '🔴'; + statusStyle = 'background:#fee2e2;'; } - return item; + return E('tr', { 'class': 'tr', 'style': statusStyle, 'data-mac': client.mac }, [ + E('td', { 'class': 'td' }, statusIcon), + E('td', { 'class': 'td' }, client.name || client.hostname || '-'), + E('td', { 'class': 'td', 'style': 'font-family:monospace;' }, client.mac), + E('td', { 'class': 'td' }, client.ip || '-'), + E('td', { 'class': 'td' }, this.renderActions(client)) + ]); + }, + + renderActions: function(client) { + var actions = E('div', { 'style': 'display:flex;gap:8px;' }); + + if (client.status !== 'approved') { + var approveBtn = E('button', { + 'class': 'cbi-button cbi-button-positive', + 'style': 'padding:4px 12px;', + 'data-mac': client.mac + }, '✓ Approve'); + approveBtn.addEventListener('click', L.bind(this.handleApprove, this)); + actions.appendChild(approveBtn); + } + + if (client.status === 'banned') { + var unbanBtn = E('button', { + 'class': 'cbi-button cbi-button-action', + 'style': 'padding:4px 12px;', + 'data-mac': client.mac + }, 'Unban'); + unbanBtn.addEventListener('click', L.bind(this.handleUnban, this)); + actions.appendChild(unbanBtn); + } else { + var banBtn = E('button', { + 'class': 'cbi-button cbi-button-negative', + 'style': 'padding:4px 12px;', + 'data-mac': client.mac + }, 'Ban'); + banBtn.addEventListener('click', L.bind(this.handleBan, this)); + actions.appendChild(banBtn); + } + + return actions; }, handleApprove: function(ev) { var mac = ev.currentTarget.dataset.mac; - var self = this; - - ui.showModal(_('Approuver le Client'), [ - E('p', {}, _('Choisissez une zone pour ce client:')), - E('select', { 'id': 'approve-zone', 'class': 'cg-select' }, [ - E('option', { 'value': 'lan_private' }, 'LAN Privé'), - E('option', { 'value': 'iot' }, 'IoT'), - E('option', { 'value': 'kids' }, 'Enfants'), - E('option', { 'value': 'guest' }, 'Invités') - ]), - E('div', { 'class': 'right' }, [ - E('button', { - 'class': 'cg-btn', - 'click': ui.hideModal - }, _('Annuler')), - E('button', { - 'class': 'cg-btn cg-btn-success', - 'click': L.bind(function() { - var zone = document.getElementById('approve-zone').value; - callApproveClient(mac, '', zone, '').then(L.bind(function() { - ui.hideModal(); - ui.addNotification(null, E('p', _('Client approved successfully')), 'success'); - this.handleRefresh(); - }, this)); - }, this) - }, _('Approuver')) - ]) - ]); + callApproveClient(mac, '', 'lan_private', '').then(L.bind(function() { + ui.addNotification(null, E('p', 'Client approved'), 'info'); + this.refresh(); + }, this)); }, handleBan: function(ev) { var mac = ev.currentTarget.dataset.mac; - - ui.showModal(_('Bannir le Client'), [ - E('p', {}, _('Voulez-vous vraiment bannir ce client?')), - E('p', {}, E('strong', {}, mac)), - E('div', { 'class': 'right' }, [ - E('button', { - 'class': 'cg-btn', - 'click': ui.hideModal - }, _('Annuler')), - E('button', { - 'class': 'cg-btn cg-btn-danger', - 'click': L.bind(function() { - callBanClient(mac, 'Manual ban').then(L.bind(function() { - ui.hideModal(); - ui.addNotification(null, E('p', _('Client banned successfully')), 'info'); - this.handleRefresh(); - }, this)); - }, this) - }, _('Bannir')) - ]) - ]); + if (confirm('Ban this client?\n' + mac)) { + callBanClient(mac, 'Manual ban').then(L.bind(function() { + ui.addNotification(null, E('p', 'Client banned'), 'info'); + this.refresh(); + }, this)); + } }, - handleRefresh: function() { - return Promise.all([ - callGetStatus(), - callGetClients(), - callGetZones() - ]).then(L.bind(function(data) { - var container = document.querySelector('.client-guardian-dashboard'); - if (container) { - var statusBadge = document.querySelector('.cg-status-badge'); - if (statusBadge) { - statusBadge.classList.add('loading'); - } - var newView = this.render(data); - dom.content(container.parentNode, newView); - if (statusBadge) { - statusBadge.classList.remove('loading'); - } + handleUnban: function(ev) { + var mac = ev.currentTarget.dataset.mac; + callUnbanClient(mac).then(L.bind(function() { + ui.addNotification(null, E('p', 'Client unbanned'), 'info'); + this.refresh(); + }, this)); + }, + + refresh: function() { + return callGetClients().then(L.bind(function(data) { + var clients = Array.isArray(data) ? data : (data.clients || []); + var table = document.getElementById('client-table'); + if (table) { + while (table.rows.length > 1) table.deleteRow(1); + clients.forEach(L.bind(function(client) { + table.appendChild(this.renderClientRow(client)); + }, this)); } - }, this)).catch(function(err) { - console.error('Failed to refresh Client Guardian dashboard:', err); - }); - }, - - handleLeave: function() { - poll.stop(); + }, this)); }, handleSaveApply: null, diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js index 135077b5..ce2bb8ff 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js @@ -1,189 +1,40 @@ 'use strict'; 'require view'; 'require form'; -'require ui'; 'require uci'; -'require client-guardian/api as API'; -'require client-guardian/nav as CgNav'; -'require secubox-portal/header as SbHeader'; return view.extend({ load: function() { - return Promise.all([ - API.getPolicy(), - API.getStatus(), - L.resolveDefault(uci.load('client-guardian'), {}) - ]); + return uci.load('client-guardian'); }, - render: function(data) { - var policy = data[0] || {}; - var status = data[1] || {}; - + render: function() { var m, s, o; - m = new form.Map('client-guardian', _('Client Guardian Settings'), - _('Configure default network access policy and client management.')); + m = new form.Map('client-guardian', 'Client Guardian Settings', + 'Basic network client management.'); - // General Settings - s = m.section(form.NamedSection, 'config', 'client-guardian', _('General Settings')); + s = m.section(form.NamedSection, 'config', 'client-guardian', 'General'); + s.anonymous = true; - o = s.option(form.Flag, 'enabled', _('Enable Client Guardian')); - o.default = '0'; - o.rmempty = false; - o.description = _('Enable or disable the Client Guardian access control system. WARNING: Enabling with restrictive policies may block network access!'); + o = s.option(form.Flag, 'enabled', 'Enable'); + o.default = '1'; - o = s.option(form.ListValue, 'default_policy', _('Default Policy')); - o.value('open', _('Open - Allow all clients (Recommended)')); - o.value('quarantine', _('Quarantine - Require approval (Restrictive)')); - o.value('whitelist', _('Whitelist Only - Block unknown clients (Very Restrictive)')); + o = s.option(form.ListValue, 'default_policy', 'Default Policy'); + o.value('open', 'Open - Auto-approve new clients'); + o.value('closed', 'Closed - Require approval'); o.default = 'open'; - o.rmempty = false; - o.description = _('Default behavior for new/unknown clients. WARNING: Quarantine and Whitelist modes will block new devices from accessing the network!'); - o = s.option(form.Flag, 'auto_approve', _('Auto-Approve Known Devices')); - o.default = '0'; - o.depends('default_policy', 'whitelist'); - o.description = _('Automatically approve devices that have connected before'); - - o = s.option(form.Value, 'session_timeout', _('Session Timeout')); - o.datatype = 'uinteger'; - o.default = '86400'; - o.placeholder = '86400'; - o.description = _('Maximum session duration in seconds (default: 86400 = 24 hours)'); - - // Advanced Settings - s = m.section(form.NamedSection, 'config', 'client-guardian', _('Advanced Settings')); - - o = s.option(form.Flag, 'mac_filtering', _('Enable MAC Filtering')); + o = s.option(form.Flag, 'auto_approve', 'Auto-approve known devices'); o.default = '1'; - o.description = _('Use MAC addresses for client identification and blocking'); - o = s.option(form.Flag, 'log_connections', _('Log Connection Events')); - o.default = '1'; - o.description = _('Log client connections and authentication events'); + o = s.option(form.ListValue, 'log_level', 'Log Level'); + o.value('error', 'Error'); + o.value('warn', 'Warning'); + o.value('info', 'Info'); + o.value('debug', 'Debug'); + o.default = 'info'; - o = s.option(form.Value, 'log_retention', _('Log Retention (days)')); - o.datatype = 'uinteger'; - o.default = '30'; - o.depends('log_connections', '1'); - o.description = _('Number of days to keep connection logs'); - - o = s.option(form.Flag, 'block_tor', _('Block Tor Exit Nodes')); - o.default = '0'; - o.description = _('Automatically block known Tor exit nodes'); - - o = s.option(form.Flag, 'block_vpn', _('Block VPN Detection')); - o.default = '0'; - o.description = _('Attempt to detect and block VPN connections'); - - // Dashboard Reactiveness - s = m.section(form.NamedSection, 'config', 'client-guardian', _('Dashboard Reactiveness')); - - o = s.option(form.Flag, 'auto_refresh', _('Enable Auto-Refresh'), - _('Automatically refresh dashboard every few seconds')); - o.default = o.enabled; - o.rmempty = false; - - o = s.option(form.ListValue, 'refresh_interval', _('Refresh Interval'), - _('How often to poll for updates')); - o.value('5', _('Every 5 seconds')); - o.value('10', _('Every 10 seconds (recommended)')); - o.value('30', _('Every 30 seconds')); - o.value('60', _('Every 60 seconds')); - o.default = '10'; - o.depends('auto_refresh', '1'); - - // Threat Intelligence Integration - s = m.section(form.NamedSection, 'threat_policy', 'threat_policy', _('Threat Intelligence Integration')); - - o = s.option(form.Flag, 'enabled', _('Enable Threat Intelligence'), - _('Correlate clients with Security Threats Dashboard data')); - o.default = o.enabled; - o.rmempty = false; - - o = s.option(form.Value, 'auto_ban_threshold', _('Auto-Ban Threshold'), - _('Automatically ban clients with threat score above this value (0-100)')); - o.datatype = 'range(1,100)'; - o.placeholder = '80'; - o.default = '80'; - o.depends('enabled', '1'); - - o = s.option(form.Value, 'auto_quarantine_threshold', _('Auto-Quarantine Threshold'), - _('Automatically quarantine clients with threat score above this value (0-100)')); - o.datatype = 'range(1,100)'; - o.placeholder = '60'; - o.default = '60'; - o.depends('enabled', '1'); - - o = s.option(form.Value, 'threat_check_interval', _('Threat Check Interval'), - _('How often to check for threats (seconds)')); - o.datatype = 'uinteger'; - o.placeholder = '60'; - o.default = '60'; - o.depends('enabled', '1'); - - return m.render().then(function(rendered) { - // Policy display names - var policyNames = { - 'open': _('Open'), - 'quarantine': _('Quarantine'), - 'whitelist': _('Whitelist Only') - }; - var currentPolicy = policy.default_policy || 'quarantine'; - var policyDisplay = policyNames[currentPolicy] || currentPolicy; - - // Add policy info box at the top - var infoBox = E('div', { - 'class': 'cbi-section', - 'style': 'background: var(--cg-bg-secondary, #151b23); border-left: 4px solid var(--cg-accent, #6366f1); padding: 1em; margin-bottom: 1em; border-radius: 8px;' - }, [ - E('h3', { 'style': 'margin-top: 0; color: var(--cg-text-primary, #e6edf3);' }, [ - _('Current Policy: '), - E('span', { 'style': 'color: var(--cg-accent, #6366f1); font-weight: 600;' }, policyDisplay) - ]), - E('div', { 'style': 'margin-top: 0.5em; color: var(--cg-text-secondary, #8b949e);' }, [ - E('strong', {}, _('Session Timeout: ')), - E('span', {}, (policy.session_timeout || 86400) + ' ' + _('seconds')) - ]), - E('div', { 'style': 'margin-top: 1em; padding: 0.75em; background: var(--cg-bg-tertiary, #1e2632); border-radius: 4px;' }, [ - E('strong', { 'style': 'color: var(--cg-text-primary, #e6edf3);' }, _('Policy Descriptions:')), - E('ul', { 'style': 'margin: 0.5em 0; color: var(--cg-text-secondary, #8b949e);' }, [ - E('li', {}, [ - E('strong', { 'style': 'color: #22c55e;' }, _('Open: ')), - _('All clients can access the network without authentication. Not recommended for public networks.') - ]), - E('li', {}, [ - E('strong', { 'style': 'color: #f59e0b;' }, _('Quarantine: ')), - _('New clients are placed in quarantine and require manual approval. Recommended for secure networks.') - ]), - E('li', {}, [ - E('strong', { 'style': 'color: #ef4444;' }, _('Whitelist Only: ')), - _('Only explicitly approved clients can access the network. Highest security.') - ]) - ]) - ]) - ]); - - rendered.insertBefore(infoBox, rendered.firstChild); - - // Main wrapper with SecuBox header - var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); - wrapper.appendChild(SbHeader.render()); - - var view = E('div', { 'class': 'client-guardian-dashboard' }, [ - E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), - E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }), - CgNav.renderTabs('settings'), - rendered - ]); - - wrapper.appendChild(view); - return wrapper; - }); - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null + return m.render(); + } }); diff --git a/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json b/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json index bb6fd482..0432059c 100644 --- a/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json +++ b/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json @@ -9,73 +9,17 @@ "acl": ["luci-app-client-guardian"] } }, - "admin/secubox/security/guardian/overview": { - "title": "Overview", + "admin/secubox/security/guardian/clients": { + "title": "Clients", "order": 10, "action": { "type": "view", "path": "client-guardian/overview" } }, - "admin/secubox/security/guardian/wizard": { - "title": "Setup Wizard", - "order": 15, - "action": { - "type": "view", - "path": "client-guardian/wizard" - } - }, - "admin/secubox/security/guardian/clients": { - "title": "Clients", - "order": 20, - "action": { - "type": "view", - "path": "client-guardian/clients" - } - }, - "admin/secubox/security/guardian/zones": { - "title": "Network Zones", - "order": 25, - "action": { - "type": "view", - "path": "client-guardian/zones" - } - }, - "admin/secubox/security/guardian/autozoning": { - "title": "Auto-Zoning Rules", - "order": 30, - "action": { - "type": "view", - "path": "client-guardian/autozoning" - } - }, - "admin/secubox/security/guardian/logs": { - "title": "Event Logs", - "order": 40, - "action": { - "type": "view", - "path": "client-guardian/logs" - } - }, - "admin/secubox/security/guardian/alerts": { - "title": "Alerts & Notifications", - "order": 50, - "action": { - "type": "view", - "path": "client-guardian/alerts" - } - }, - "admin/secubox/security/guardian/parental": { - "title": "Parental Controls", - "order": 60, - "action": { - "type": "view", - "path": "client-guardian/parental" - } - }, "admin/secubox/security/guardian/settings": { "title": "Settings", - "order": 90, + "order": 20, "action": { "type": "view", "path": "client-guardian/settings"