secubox-openwrt/luci-app-network-modes/htdocs/luci-static/resources/view/network-modes/router.js

360 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
'require view';
'require dom';
'require ui';
'require network-modes.api as api';
return view.extend({
title: _('Router Mode'),
load: function() {
return api.getRouterConfig();
},
render: function(data) {
var config = data || {};
var wanConfig = config.wan || {};
var lanConfig = config.lan || {};
var fwConfig = config.firewall || {};
var proxyConfig = config.proxy || {};
var frontendConfig = config.https_frontend || {};
var vhosts = config.virtual_hosts || [];
var view = E('div', { 'class': 'network-modes-dashboard' }, [
// Header
E('div', { 'class': 'nm-header' }, [
E('div', { 'class': 'nm-logo' }, [
E('div', { 'class': 'nm-logo-icon' }, '🌐'),
E('div', { 'class': 'nm-logo-text' }, ['Router ', E('span', {}, 'Mode')])
])
]),
// Description
E('div', { 'class': 'nm-alert nm-alert-info' }, [
E('span', { 'class': 'nm-alert-icon' }, '🌐'),
E('div', {}, [
E('div', { 'class': 'nm-alert-title' }, 'Full Router with Advanced Features'),
E('div', { 'class': 'nm-alert-text' },
'Complete router functionality with WAN management, NAT, firewall, ' +
'web proxy, and HTTPS reverse proxy for multiple domains.')
])
]),
// WAN Configuration
E('div', { 'class': 'nm-card' }, [
E('div', { 'class': 'nm-card-header' }, [
E('div', { 'class': 'nm-card-title' }, [
E('span', { 'class': 'nm-card-title-icon' }, '🌍'),
'WAN Configuration'
])
]),
E('div', { 'class': 'nm-card-body' }, [
E('div', { 'class': 'nm-form-group' }, [
E('label', { 'class': 'nm-form-label' }, 'WAN Interface'),
E('input', {
'class': 'nm-input',
'type': 'text',
'value': wanConfig.interface || 'eth1',
'id': 'wan-interface'
})
]),
E('div', { 'class': 'nm-form-group' }, [
E('label', { 'class': 'nm-form-label' }, 'WAN Protocol'),
E('select', { 'class': 'nm-select', 'id': 'wan-protocol' },
(config.available_wan_protocols || ['dhcp', 'static', 'pppoe']).map(function(proto) {
return E('option', {
'value': proto,
'selected': proto === wanConfig.protocol
}, proto.toUpperCase());
})
)
]),
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' }, 'NAT / Masquerade'),
E('div', { 'class': 'nm-toggle-desc' }, 'Network Address Translation for LAN')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (wanConfig.nat_enabled !== false ? ' active' : ''),
'id': 'toggle-nat'
})
])
])
]),
// Firewall
E('div', { 'class': 'nm-card' }, [
E('div', { 'class': 'nm-card-header' }, [
E('div', { 'class': 'nm-card-title' }, [
E('span', { 'class': 'nm-card-title-icon' }, '🛡️'),
'Firewall'
]),
E('div', { 'class': 'nm-card-badge' }, fwConfig.enabled ? 'Enabled' : 'Disabled')
]),
E('div', { 'class': 'nm-card-body' }, [
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' }, 'Enable Firewall'),
E('div', { 'class': 'nm-toggle-desc' }, 'Protect network with firewall rules')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (fwConfig.enabled !== false ? ' active' : ''),
'id': 'toggle-firewall'
})
]),
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' }, 'SYN Flood Protection'),
E('div', { 'class': 'nm-toggle-desc' }, 'Prevent SYN flood DoS attacks')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (fwConfig.syn_flood ? ' active' : ''),
'id': 'toggle-synflood'
})
]),
E('div', { 'class': 'nm-wifi-grid', 'style': 'margin-top: 16px' }, [
E('div', { 'class': 'nm-wifi-setting' }, [
E('div', { 'class': 'nm-wifi-setting-label' }, 'WAN Input'),
E('div', { 'class': 'nm-wifi-setting-value', 'style': 'font-size: 14px' }, fwConfig.input || 'REJECT')
]),
E('div', { 'class': 'nm-wifi-setting' }, [
E('div', { 'class': 'nm-wifi-setting-label' }, 'WAN Output'),
E('div', { 'class': 'nm-wifi-setting-value', 'style': 'font-size: 14px' }, fwConfig.output || 'ACCEPT')
]),
E('div', { 'class': 'nm-wifi-setting' }, [
E('div', { 'class': 'nm-wifi-setting-label' }, 'WAN Forward'),
E('div', { 'class': 'nm-wifi-setting-value', 'style': 'font-size: 14px' }, fwConfig.forward || 'REJECT')
])
])
])
]),
// Proxy Configuration
E('div', { 'class': 'nm-card' }, [
E('div', { 'class': 'nm-card-header' }, [
E('div', { 'class': 'nm-card-title' }, [
E('span', { 'class': 'nm-card-title-icon' }, '🦑'),
'Web Proxy'
]),
E('div', { 'class': 'nm-card-badge' }, proxyConfig.enabled ? 'Active' : 'Disabled')
]),
E('div', { 'class': 'nm-card-body' }, [
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' }, 'Enable Proxy'),
E('div', { 'class': 'nm-toggle-desc' }, 'HTTP/HTTPS caching proxy')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (proxyConfig.enabled ? ' active' : ''),
'id': 'toggle-proxy'
})
]),
E('div', { 'class': 'nm-form-group', 'style': 'margin-top: 16px' }, [
E('label', { 'class': 'nm-form-label' }, 'Proxy Type'),
E('select', { 'class': 'nm-select', 'id': 'proxy-type' }, [
E('option', { 'value': 'squid', 'selected': proxyConfig.type === 'squid' }, 'Squid'),
E('option', { 'value': 'tinyproxy', 'selected': proxyConfig.type === 'tinyproxy' }, 'TinyProxy'),
E('option', { 'value': 'privoxy', 'selected': proxyConfig.type === 'privoxy' }, 'Privoxy')
])
]),
E('div', { 'class': 'nm-form-group' }, [
E('label', { 'class': 'nm-form-label' }, 'Proxy Port'),
E('input', {
'class': 'nm-input',
'type': 'number',
'value': proxyConfig.port || 3128,
'id': 'proxy-port'
})
]),
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' }, 'Transparent Proxy'),
E('div', { 'class': 'nm-toggle-desc' }, 'Intercept traffic without client config')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (proxyConfig.transparent ? ' active' : ''),
'id': 'toggle-transparent'
})
]),
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' }, 'DNS over HTTPS'),
E('div', { 'class': 'nm-toggle-desc' }, 'Encrypt DNS queries')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (proxyConfig.dns_over_https ? ' active' : ''),
'id': 'toggle-doh'
})
])
])
]),
// HTTPS Frontend / Reverse Proxy
E('div', { 'class': 'nm-card' }, [
E('div', { 'class': 'nm-card-header' }, [
E('div', { 'class': 'nm-card-title' }, [
E('span', { 'class': 'nm-card-title-icon' }, '🔐'),
'HTTPS Reverse Proxy'
]),
E('div', { 'class': 'nm-card-badge' }, vhosts.length + ' virtual hosts')
]),
E('div', { 'class': 'nm-card-body' }, [
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' }, 'Enable HTTPS Frontend'),
E('div', { 'class': 'nm-toggle-desc' }, 'Reverse proxy for multiple domains')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (frontendConfig.enabled ? ' active' : ''),
'id': 'toggle-frontend'
})
]),
E('div', { 'class': 'nm-form-group', 'style': 'margin-top: 16px' }, [
E('label', { 'class': 'nm-form-label' }, 'Frontend Type'),
E('select', { 'class': 'nm-select', 'id': 'frontend-type' }, [
E('option', { 'value': 'nginx', 'selected': frontendConfig.type === 'nginx' }, 'Nginx'),
E('option', { 'value': 'haproxy', 'selected': frontendConfig.type === 'haproxy' }, 'HAProxy'),
E('option', { 'value': 'caddy', 'selected': frontendConfig.type === 'caddy' }, 'Caddy')
])
]),
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' }, 'Let\'s Encrypt'),
E('div', { 'class': 'nm-toggle-desc' }, 'Automatic SSL certificates')
])
]),
E('div', {
'class': 'nm-toggle-switch' + (frontendConfig.letsencrypt ? ' active' : ''),
'id': 'toggle-letsencrypt'
})
]),
// Virtual Hosts Table
vhosts.length > 0 ?
E('div', { 'style': 'margin-top: 20px' }, [
E('h4', { 'style': 'margin: 0 0 12px 0; font-size: 14px' }, 'Virtual Hosts'),
E('table', { 'class': 'nm-vhost-table' }, [
E('thead', {}, [
E('tr', {}, [
E('th', {}, 'Domain'),
E('th', {}, 'Backend'),
E('th', {}, 'Port'),
E('th', {}, 'SSL'),
E('th', {}, 'Actions')
])
]),
E('tbody', {},
vhosts.map(function(vhost) {
return E('tr', {}, [
E('td', { 'class': 'domain' }, vhost.domain),
E('td', { 'class': 'mono' }, vhost.backend),
E('td', { 'class': 'mono' }, vhost.port || 80),
E('td', {}, [
E('span', { 'class': 'nm-ssl-badge ' + (vhost.ssl ? 'enabled' : 'disabled') },
vhost.ssl ? '🔒 HTTPS' : '⚠️ HTTP')
]),
E('td', {}, [
E('button', { 'class': 'nm-btn', 'style': 'padding: 4px 8px; font-size: 12px' }, '🗑️')
])
]);
})
)
])
]) :
E('p', { 'style': 'color: var(--nm-text-muted); font-size: 13px; margin-top: 16px' },
'No virtual hosts configured. Add domains below.'),
// Add Virtual Host
E('div', { 'style': 'margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--nm-border)' }, [
E('h4', { 'style': 'margin: 0 0 12px 0; font-size: 14px' }, 'Add Virtual Host'),
E('div', { 'style': 'display: grid; grid-template-columns: 2fr 2fr 1fr auto; gap: 12px; align-items: end' }, [
E('div', { 'class': 'nm-form-group', 'style': 'margin: 0' }, [
E('label', { 'class': 'nm-form-label' }, 'Domain'),
E('input', { 'class': 'nm-input', 'type': 'text', 'placeholder': 'example.com', 'id': 'new-domain' })
]),
E('div', { 'class': 'nm-form-group', 'style': 'margin: 0' }, [
E('label', { 'class': 'nm-form-label' }, 'Backend'),
E('input', { 'class': 'nm-input', 'type': 'text', 'placeholder': '127.0.0.1:8080', 'id': 'new-backend' })
]),
E('div', { 'class': 'nm-form-group', 'style': 'margin: 0' }, [
E('label', { 'class': 'nm-form-label' }, 'SSL'),
E('select', { 'class': 'nm-select', 'id': 'new-ssl' }, [
E('option', { 'value': '1' }, 'Yes'),
E('option', { 'value': '0' }, 'No')
])
]),
E('button', { 'class': 'nm-btn nm-btn-primary', 'style': 'height: 46px' }, ' Add')
])
])
])
]),
// Actions
E('div', { 'class': 'nm-btn-group' }, [
E('button', { 'class': 'nm-btn nm-btn-primary' }, [
E('span', {}, '💾'),
'Save Settings'
]),
E('button', { 'class': 'nm-btn' }, [
E('span', {}, '🔄'),
'Apply & Restart'
]),
E('button', { 'class': 'nm-btn' }, [
E('span', {}, '📝'),
'Generate Config'
])
])
]);
// Toggle handlers
view.querySelectorAll('.nm-toggle-switch').forEach(function(toggle) {
toggle.addEventListener('click', function() {
this.classList.toggle('active');
});
});
// Include CSS
var cssLink = E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/dashboard.css') });
document.head.appendChild(cssLink);
return view;
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});