Major Enhancements: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Network Modes Module: - Added 3 new network modes: * Double NAT mode (doublenat.js) - Cascaded router configuration * Multi-WAN mode (multiwan.js) - Load balancing and failover * VPN Relay mode (vpnrelay.js) - VPN gateway configuration - Enhanced existing modes: * Access Point improvements * Travel mode refinements * Router mode enhancements * Relay mode updates * Sniffer mode optimizations - Updated wizard with new mode options - Enhanced API with new mode support - Improved dashboard CSS styling - Updated helpers for new modes - Extended RPCD backend functionality - Updated menu structure for new modes - Enhanced UCI configuration System Hub Module: - Added dedicated logs.css stylesheet - Enhanced logs.js view with better styling - Improved overview.css responsive design - Enhanced services.css for better UX - Updated overview.js with theme integration - Improved services.js layout SecuBox Dashboard: - Enhanced dashboard.css with theme variables - Improved dashboard.js responsiveness - Better integration with global theme Files Changed: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Network Modes (17 files): Modified: api.js, dashboard.css, helpers.js, menu, config, RPCD backend Modified Views: accesspoint, overview, relay, router, sniffer, travel, wizard New Views: doublenat, multiwan, vpnrelay System Hub (6 files): New: logs.css Modified: overview.css, services.css, logs.js, overview.js, services.js SecuBox (2 files): Modified: dashboard.css, dashboard.js Total: 25 files changed (21 modified, 4 new) Technical Improvements: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - Global theme CSS variable usage - Responsive design enhancements - Improved error handling - Better mode validation - Enhanced user feedback - Optimized CSS performance - Improved accessibility Network Mode Capabilities: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. Router Mode - Standard routing 2. Access Point Mode - WiFi AP with bridge 3. Relay Mode - WiFi repeater/extender 4. Travel Mode - Portable router configuration 5. Sniffer Mode - Network monitoring 6. Double NAT Mode - Cascaded NAT for network isolation (NEW) 7. Multi-WAN Mode - Multiple uplinks with load balancing (NEW) 8. VPN Relay Mode - VPN gateway and tunnel endpoint (NEW) Breaking Changes: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ None - All changes are backward compatible 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
192 lines
6.2 KiB
JavaScript
192 lines
6.2 KiB
JavaScript
'use strict';
|
|
'require view';
|
|
'require ui';
|
|
'require network-modes.api as api';
|
|
'require network-modes.helpers as helpers';
|
|
'require secubox-theme/theme as Theme';
|
|
|
|
Theme.init({ theme: 'dark', language: 'en' });
|
|
|
|
return view.extend({
|
|
title: _('Double NAT Mode'),
|
|
|
|
load: function() {
|
|
return api.getDoubleNatConfig();
|
|
},
|
|
|
|
render: function(data) {
|
|
var cfg = data || {};
|
|
var wan = cfg.wan || {};
|
|
var lan = cfg.lan || {};
|
|
|
|
var container = E('div', { 'class': 'network-modes-dashboard doublenat-mode' }, [
|
|
E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/dashboard.css') }),
|
|
helpers.createHero({
|
|
icon: '🔁',
|
|
title: _('Double NAT'),
|
|
subtitle: _('Operate behind an ISP router with a second isolated LAN, guest network, and hardened perimeter.'),
|
|
actions: [
|
|
E('button', {
|
|
'class': 'nm-btn nm-btn-primary',
|
|
'data-action': 'doublenat-save',
|
|
'type': 'button'
|
|
}, '💾 ' + _('Save Settings')),
|
|
E('button', {
|
|
'class': 'nm-btn',
|
|
'type': 'button',
|
|
'click': ui.createHandlerFn(helpers, helpers.showGeneratedConfig, 'doublenat')
|
|
}, '📝 ' + _('Preview Config'))
|
|
]
|
|
}),
|
|
this.renderWanSection(wan),
|
|
this.renderLanSection(lan, cfg),
|
|
this.renderSecuritySection(cfg)
|
|
]);
|
|
|
|
container.querySelectorAll('.nm-toggle-switch').forEach(function(toggle) {
|
|
toggle.addEventListener('click', function() {
|
|
this.classList.toggle('active');
|
|
});
|
|
});
|
|
|
|
this.bindActions(container);
|
|
return container;
|
|
},
|
|
|
|
renderWanSection: function(wan) {
|
|
return helpers.createSection({
|
|
icon: '🌐',
|
|
title: _('Upstream (ISP box)'),
|
|
body: [
|
|
E('div', { 'class': 'nm-form-grid' }, [
|
|
E('div', { 'class': 'nm-form-group' }, [
|
|
E('label', { 'class': 'nm-form-label' }, _('WAN Interface')),
|
|
E('input', {
|
|
'class': 'nm-input',
|
|
'id': 'dn-wan-interface',
|
|
'value': wan.interface || 'eth1'
|
|
})
|
|
]),
|
|
E('div', { 'class': 'nm-form-group' }, [
|
|
E('label', { 'class': 'nm-form-label' }, _('Protocol')),
|
|
E('select', { 'class': 'nm-select', 'id': 'dn-wan-proto' }, [
|
|
E('option', { 'value': 'dhcp', 'selected': (wan.protocol || 'dhcp') === 'dhcp' }, _('DHCP Client')),
|
|
E('option', { 'value': 'static', 'selected': wan.protocol === 'static' }, _('Static IP')),
|
|
E('option', { 'value': 'pppoe', 'selected': wan.protocol === 'pppoe' }, _('PPPoE'))
|
|
])
|
|
])
|
|
]),
|
|
E('p', { 'class': 'nm-text-muted' }, _('Keep WAN as DHCP client to obtain an address from the ISP box. Use DMZ on the ISP router to point to SecuBox for best results.'))
|
|
]
|
|
});
|
|
},
|
|
|
|
renderLanSection: function(lan, cfg) {
|
|
return helpers.createSection({
|
|
icon: '🏠',
|
|
title: _('LAN & Guest Segments'),
|
|
body: [
|
|
E('div', { 'class': 'nm-form-grid' }, [
|
|
E('div', { 'class': 'nm-form-group' }, [
|
|
E('label', { 'class': 'nm-form-label' }, _('LAN Interface')),
|
|
E('input', {
|
|
'class': 'nm-input',
|
|
'id': 'dn-lan-interface',
|
|
'value': lan.interface || 'br-lan'
|
|
})
|
|
]),
|
|
E('div', { 'class': 'nm-form-group' }, [
|
|
E('label', { 'class': 'nm-form-label' }, _('LAN IP')),
|
|
E('input', {
|
|
'class': 'nm-input',
|
|
'id': 'dn-lan-ip',
|
|
'value': lan.ipaddr || '10.10.0.1'
|
|
})
|
|
]),
|
|
E('div', { 'class': 'nm-form-group' }, [
|
|
E('label', { 'class': 'nm-form-label' }, _('LAN Netmask')),
|
|
E('input', {
|
|
'class': 'nm-input',
|
|
'id': 'dn-lan-netmask',
|
|
'value': lan.netmask || '255.255.255.0'
|
|
})
|
|
]),
|
|
E('div', { 'class': 'nm-form-group' }, [
|
|
E('label', { 'class': 'nm-form-label' }, _('Guest bridge name')),
|
|
E('input', {
|
|
'class': 'nm-input',
|
|
'id': 'dn-guest-bridge',
|
|
'value': cfg.guest_network || 'br-guest'
|
|
})
|
|
])
|
|
])
|
|
]
|
|
});
|
|
},
|
|
|
|
renderSecuritySection: function(cfg) {
|
|
return helpers.createSection({
|
|
icon: '🛡️',
|
|
title: _('Security Hardening'),
|
|
body: [
|
|
E('div', { 'class': 'nm-toggle-list' }, [
|
|
this.renderToggle(_('Disable UPnP on downstream LAN'), 'Prevents auto-forwarding from LAN devices', 'dn-upnp', cfg.upnp_enabled && cfg.upnp_enabled !== '0'),
|
|
this.renderToggle(_('Isolate guest bridge'), 'Block traffic between guest and LAN networks', 'dn-isolate-guest', cfg.isolate_guest === 1 || cfg.isolate_guest === '1')
|
|
]),
|
|
E('div', { 'class': 'nm-form-group', 'style': 'margin-top: 16px;' }, [
|
|
E('label', { 'class': 'nm-form-label' }, _('DMZ Host on ISP router')),
|
|
E('input', {
|
|
'class': 'nm-input',
|
|
'id': 'dn-dmz-host',
|
|
'value': cfg.dmz_host || '',
|
|
'placeholder': _('192.168.1.254 (optional)')
|
|
}),
|
|
E('p', { 'class': 'nm-text-muted' }, _('Configure the ISP router DMZ to forward everything to this LAN IP.'))
|
|
])
|
|
]
|
|
});
|
|
},
|
|
|
|
renderToggle: function(label, desc, id, active) {
|
|
return E('div', { 'class': 'nm-toggle' }, [
|
|
E('div', { 'class': 'nm-toggle-info' }, [
|
|
E('span', { 'class': 'nm-toggle-icon' }, '⚙️'),
|
|
E('div', {}, [
|
|
E('div', { 'class': 'nm-toggle-label' }, label),
|
|
E('div', { 'class': 'nm-toggle-desc' }, desc)
|
|
])
|
|
]),
|
|
E('div', {
|
|
'class': 'nm-toggle-switch' + (active ? ' active' : ''),
|
|
'id': id
|
|
})
|
|
]);
|
|
},
|
|
|
|
bindActions: function(container) {
|
|
var saveBtn = container.querySelector('[data-action="doublenat-save"]');
|
|
if (saveBtn)
|
|
saveBtn.addEventListener('click', ui.createHandlerFn(this, 'saveDoubleNatSettings', container));
|
|
},
|
|
|
|
saveDoubleNatSettings: function(container) {
|
|
var payload = {
|
|
wan_interface: (container.querySelector('#dn-wan-interface') || {}).value,
|
|
wan_protocol: (container.querySelector('#dn-wan-proto') || {}).value,
|
|
lan_interface: (container.querySelector('#dn-lan-interface') || {}).value,
|
|
lan_ip: (container.querySelector('#dn-lan-ip') || {}).value,
|
|
lan_netmask: (container.querySelector('#dn-lan-netmask') || {}).value,
|
|
guest_network: (container.querySelector('#dn-guest-bridge') || {}).value,
|
|
isolate_guest: helpers.isToggleActive(container.querySelector('#dn-isolate-guest')) ? 1 : 0,
|
|
upnp_enabled: helpers.isToggleActive(container.querySelector('#dn-upnp')) ? 1 : 0,
|
|
dmz_host: (container.querySelector('#dn-dmz-host') || {}).value
|
|
};
|
|
|
|
return helpers.persistSettings('doublenat', payload);
|
|
},
|
|
|
|
handleSaveApply: null,
|
|
handleSave: null,
|
|
handleReset: null
|
|
});
|