mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-06 03:14:12 +08:00
⛅ Sync 2026-09-29 21:45:00
This commit is contained in:
1 parent
a4d6e3e4b9
commit
da77daf88e
191 files changed
+8077
-6247
No files matched your search
+211
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2022-2025 ImmortalWrt.org
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
'require baseclass';
|
||||
'require form';
|
||||
'require uci';
|
||||
|
||||
'require homeproxy-pro as hp';
|
||||
'require tools.firewall as fwtool';
|
||||
'require tools.widgets as widgets';
|
||||
|
||||
/* Access Control tab. Five sub-tabs (interface control, LAN IP policy,
|
||||
* WAN IP policy, proxy domain list, direct domain list). Each domain-list
|
||||
* sub-tab reads/writes the proxy_list / direct_list files through an
|
||||
* ubus RPC; the load callback is the only path that touches that RPC. */
|
||||
function render(ctx) {
|
||||
const { s, hosts, stubValidator } = ctx;
|
||||
let o, ss, so;
|
||||
|
||||
s.tab('control', _('Access Control'));
|
||||
|
||||
o = s.taboption('control', form.SectionValue, '_control', form.NamedSection, 'control', 'homeproxy-pro');
|
||||
ss = o.subsection;
|
||||
|
||||
/* Interface control start */
|
||||
ss.tab('interface', _('Interface Control'));
|
||||
|
||||
so = ss.taboption('interface', widgets.DeviceSelect, 'listen_interfaces', _('Listen interfaces'),
|
||||
_('Only process traffic from specific interfaces. Leave empty for all.'));
|
||||
so.multiple = true;
|
||||
so.noaliases = true;
|
||||
|
||||
so = ss.taboption('interface', widgets.DeviceSelect, 'bind_interface', _('Bind interface'),
|
||||
_('Bind outbound traffic to specific interface. Leave empty to auto detect.'));
|
||||
so.multiple = false;
|
||||
so.noaliases = true;
|
||||
/* Interface control end */
|
||||
|
||||
/* LAN IP policy start */
|
||||
ss.tab('lan_ip_policy', _('LAN IP Policy'));
|
||||
|
||||
so = ss.taboption('lan_ip_policy', form.ListValue, 'lan_proxy_mode', _('Proxy filter mode'));
|
||||
so.value('disabled', _('Disable'));
|
||||
so.value('listed_only', _('Proxy listed only'));
|
||||
so.value('except_listed', _('Proxy all except listed'));
|
||||
so.default = 'disabled';
|
||||
so.rmempty = false;
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_direct_ipv4_ips', _('Direct IPv4 IP-s'), null, 'ipv4', hosts, true);
|
||||
so.depends('lan_proxy_mode', 'except_listed');
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_direct_ipv6_ips', _('Direct IPv6 IP-s'), null, 'ipv6', hosts, true);
|
||||
so.depends({'lan_proxy_mode': 'except_listed', 'homeproxy-pro.config.ipv6_support': '1'});
|
||||
|
||||
so = fwtool.addMACOption(ss, 'lan_ip_policy', 'lan_direct_mac_addrs', _('Direct MAC-s'), null, hosts);
|
||||
so.depends('lan_proxy_mode', 'except_listed');
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_proxy_ipv4_ips', _('Proxy IPv4 IP-s'), null, 'ipv4', hosts, true);
|
||||
so.depends('lan_proxy_mode', 'listed_only');
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_proxy_ipv6_ips', _('Proxy IPv6 IP-s'), null, 'ipv6', hosts, true);
|
||||
so.depends({'lan_proxy_mode': 'listed_only', 'homeproxy-pro.config.ipv6_support': '1'});
|
||||
|
||||
so = fwtool.addMACOption(ss, 'lan_ip_policy', 'lan_proxy_mac_addrs', _('Proxy MAC-s'), null, hosts);
|
||||
so.depends('lan_proxy_mode', 'listed_only');
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_gaming_mode_ipv4_ips', _('Gaming mode IPv4 IP-s'), null, 'ipv4', hosts, true);
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_gaming_mode_ipv6_ips', _('Gaming mode IPv6 IP-s'), null, 'ipv6', hosts, true);
|
||||
so.depends('homeproxy-pro.config.ipv6_support', '1');
|
||||
|
||||
so = fwtool.addMACOption(ss, 'lan_ip_policy', 'lan_gaming_mode_mac_addrs', _('Gaming mode MAC-s'), null, hosts);
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_global_proxy_ipv4_ips', _('Global proxy IPv4 IP-s'), null, 'ipv4', hosts, true);
|
||||
so.depends({'homeproxy-pro.config.routing_mode': 'custom', '!reverse': true});
|
||||
|
||||
so = fwtool.addIPOption(ss, 'lan_ip_policy', 'lan_global_proxy_ipv6_ips', _('Global proxy IPv6 IP-s'), null, 'ipv6', hosts, true);
|
||||
so.depends({'homeproxy-pro.config.routing_mode': /^((?!custom).)+$/, 'homeproxy-pro.config.ipv6_support': '1'});
|
||||
|
||||
so = fwtool.addMACOption(ss, 'lan_ip_policy', 'lan_global_proxy_mac_addrs', _('Global proxy MAC-s'), null, hosts);
|
||||
so.depends({'homeproxy-pro.config.routing_mode': 'custom', '!reverse': true});
|
||||
/* LAN IP policy end */
|
||||
|
||||
/* WAN IP policy start */
|
||||
ss.tab('wan_ip_policy', _('WAN IP Policy'));
|
||||
|
||||
so = ss.taboption('wan_ip_policy', form.DynamicList, 'wan_proxy_ipv4_ips', _('Proxy IPv4 IP-s'));
|
||||
so.datatype = 'or(ip4addr, cidr4)';
|
||||
|
||||
so = ss.taboption('wan_ip_policy', form.DynamicList, 'wan_proxy_ipv6_ips', _('Proxy IPv6 IP-s'));
|
||||
so.datatype = 'or(ip6addr, cidr6)';
|
||||
so.depends('homeproxy-pro.config.ipv6_support', '1');
|
||||
|
||||
so = ss.taboption('wan_ip_policy', form.DynamicList, 'wan_direct_ipv4_ips', _('Direct IPv4 IP-s'));
|
||||
so.datatype = 'or(ip4addr, cidr4)';
|
||||
|
||||
so = ss.taboption('wan_ip_policy', form.DynamicList, 'wan_direct_ipv6_ips', _('Direct IPv6 IP-s'));
|
||||
so.datatype = 'or(ip6addr, cidr6)';
|
||||
so.depends('homeproxy-pro.config.ipv6_support', '1');
|
||||
/* WAN IP policy end */
|
||||
|
||||
/* Proxy domain list start */
|
||||
ss.tab('proxy_domain_list', _('Proxy Domain List'));
|
||||
|
||||
so = ss.taboption('proxy_domain_list', form.TextValue, '_proxy_domain_list');
|
||||
so.rows = 10;
|
||||
so.monospace = true;
|
||||
so.datatype = 'hostname';
|
||||
so.description = _('One domain per line. No spaces, no comments, no wildcards; the backend rejects invalid characters and tells you which line.');
|
||||
so.depends({'homeproxy-pro.config.routing_mode': 'custom', '!reverse': true});
|
||||
so.load = function(/* ... */) {
|
||||
return hp.rpcCall('acllist_read', ['proxy_list'],
|
||||
{ params: ['type'], expect: { '': {} } }).then((res) => {
|
||||
/* acllist_read returns { content: null, error: '...' }
|
||||
* when the backend rejected the request (bad type, file
|
||||
* unreadable, ...). Surface the error instead of silently
|
||||
* resolving to "" which makes the field look unchanged. */
|
||||
if (res && res.error)
|
||||
ui.addNotification(null, E('p', _('Failed to read domain list: %s.').format(res.error)));
|
||||
return res ? res.content : '';
|
||||
}, {});
|
||||
}
|
||||
so.write = function(_section_id, value) {
|
||||
return hp.rpcCall('acllist_write', ['proxy_list', value], { params: ['type', 'content'], expect: { '': {} } }).then((ret) => {
|
||||
/* Without this, a backend error like "UCI commit failed"
|
||||
* is silently dropped and the user sees the old value
|
||||
* reappear after refresh with no explanation. */
|
||||
if (ret && ret.result === false)
|
||||
throw (ret.error || 'unknown error');
|
||||
return true;
|
||||
});
|
||||
}
|
||||
so.remove = function(/* ... */) {
|
||||
/* routing_mode is an option of the page's 'config' NamedSection, not
|
||||
* of this nested 'control' one: `this.section.formvalue(...)` walks
|
||||
* the children of `this.section`, never found it and returned null,
|
||||
* so the test below was always true and a reset wiped the file even
|
||||
* in custom mode, where the list is in use. Read the saved UCI value
|
||||
* the backend will act on. */
|
||||
let routing_mode = uci.get('homeproxy-pro', 'config', 'routing_mode');
|
||||
if (routing_mode !== 'custom')
|
||||
return hp.rpcCall('acllist_write', ['proxy_list', ''], { params: ['type', 'content'], expect: { '': {} } }).then((ret) => {
|
||||
if (ret && ret.result === false)
|
||||
throw (ret.error || 'unknown error');
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
so.validate = function(section_id, value) {
|
||||
if (section_id && value)
|
||||
for (let i of value.split('\n'))
|
||||
if (i && !stubValidator.apply('hostname', i))
|
||||
return _('Expecting: %s').format(_('valid hostname'));
|
||||
|
||||
return true;
|
||||
}
|
||||
/* Proxy domain list end */
|
||||
|
||||
/* Direct domain list start */
|
||||
ss.tab('direct_domain_list', _('Direct Domain List'));
|
||||
|
||||
so = ss.taboption('direct_domain_list', form.TextValue, '_direct_domain_list');
|
||||
so.rows = 10;
|
||||
so.monospace = true;
|
||||
so.datatype = 'hostname';
|
||||
so.description = _('One domain per line. No spaces, no comments, no wildcards; the backend rejects invalid characters and tells you which line.');
|
||||
so.depends({'homeproxy-pro.config.routing_mode': 'custom', '!reverse': true});
|
||||
so.load = function(/* ... */) {
|
||||
return hp.rpcCall('acllist_read', ['direct_list'],
|
||||
{ params: ['type'], expect: { '': {} } }).then((res) => {
|
||||
if (res && res.error)
|
||||
ui.addNotification(null, E('p', _('Failed to read domain list: %s.').format(res.error)));
|
||||
return res ? res.content : '';
|
||||
}, {});
|
||||
}
|
||||
so.write = function(_section_id, value) {
|
||||
return hp.rpcCall('acllist_write', ['direct_list', value], { params: ['type', 'content'], expect: { '': {} } }).then((ret) => {
|
||||
if (ret && ret.result === false)
|
||||
throw (ret.error || 'unknown error');
|
||||
return true;
|
||||
});
|
||||
}
|
||||
so.remove = function(/* ... */) {
|
||||
/* Same `this.section` mistake as the proxy list above. */
|
||||
let routing_mode = uci.get('homeproxy-pro', 'config', 'routing_mode');
|
||||
if (routing_mode !== 'custom')
|
||||
return hp.rpcCall('acllist_write', ['direct_list', ''], { params: ['type', 'content'], expect: { '': {} } }).then((ret) => {
|
||||
if (ret && ret.result === false)
|
||||
throw (ret.error || 'unknown error');
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
so.validate = function(section_id, value) {
|
||||
if (section_id && value)
|
||||
for (let i of value.split('\n'))
|
||||
if (i && !stubValidator.apply('hostname', i))
|
||||
return _('Expecting: %s').format(_('valid hostname'));
|
||||
|
||||
return true;
|
||||
}
|
||||
/* Direct domain list end */
|
||||
/* ACL settings end */
|
||||
}
|
||||
|
||||
return baseclass.extend({ render });
|
||||
Reference in new issue
Block a user