luci-app-homeproxy: sync upstream

last commit: e8649347b5
This commit is contained in:
gitea-action 2024-12-31 21:30:19 +08:00
parent b93f2ac709
commit 1061f7eb38
4 changed files with 903 additions and 705 deletions

View File

@ -378,22 +378,23 @@ return view.extend({
so = ss.option(form.ListValue, 'node', _('Node'), so = ss.option(form.ListValue, 'node', _('Node'),
_('Outbound node')); _('Outbound node'));
so.value('urltest', _('URLTest'));
for (var i in proxy_nodes) for (var i in proxy_nodes)
so.value(i, proxy_nodes[i]); so.value(i, proxy_nodes[i]);
so.validate = L.bind(hp.validateUniqueValue, this, data[0], 'routing_node', 'node');
so.editable = true; so.editable = true;
so = ss.option(form.ListValue, 'domain_strategy', _('Domain strategy'), so = ss.option(form.ListValue, 'domain_strategy', _('Domain strategy'),
_('If set, the server domain name will be resolved to IP before connecting.<br/>')); _('If set, the server domain name will be resolved to IP before connecting.<br/>'));
for (var i in hp.dns_strategy) for (var i in hp.dns_strategy)
so.value(i, hp.dns_strategy[i]); so.value(i, hp.dns_strategy[i]);
so.depends({'node': 'urltest', '!reverse': true});
so.modalonly = true; so.modalonly = true;
so = ss.option(widgets.DeviceSelect, 'bind_interface', _('Bind interface'), so = ss.option(widgets.DeviceSelect, 'bind_interface', _('Bind interface'),
_('The network interface to bind to.')); _('The network interface to bind to.'));
so.multiple = false; so.multiple = false;
so.noaliases = true; so.noaliases = true;
so.depends('outbound', ''); so.depends({'outbound': '', 'node': /^((?!urltest$).)+$/});
so.modalonly = true; so.modalonly = true;
so = ss.option(form.ListValue, 'outbound', _('Outbound'), so = ss.option(form.ListValue, 'outbound', _('Outbound'),
@ -416,9 +417,12 @@ return view.extend({
var conflict = false; var conflict = false;
uci.sections(data[0], 'routing_node', (res) => { uci.sections(data[0], 'routing_node', (res) => {
if (res['.name'] !== section_id) if (res['.name'] !== section_id) {
if (res.outbound === section_id && res['.name'] == value) if (res.outbound === section_id && res['.name'] == value)
conflict = true; conflict = true;
else if (res?.urltest_nodes?.includes(node) && res['.name'] == value)
conflict = true;
}
}); });
if (conflict) if (conflict)
return _('Recursive outbound detected!'); return _('Recursive outbound detected!');
@ -426,6 +430,66 @@ return view.extend({
return true; return true;
} }
so.depends({'node': 'urltest', '!reverse': true});
so = ss.option(hp.CBIStaticList, 'urltest_nodes', _('URLTest nodes'),
_('List of nodes to test.'));
for (var i in proxy_nodes)
so.value(i, proxy_nodes[i]);
so.depends('node', 'urltest');
so.modalonly = true;
so = ss.option(form.Value, 'urltest_url', _('Test URL'),
_('The URL to test. <code>https://www.gstatic.com/generate_204</code> will be used if empty.'));
so.validate = function(section_id, value) {
if (section_id && value) {
try {
var url = new URL(value);
if (!url.hostname)
return _('Expecting: %s').format(_('valid URL'));
}
catch(e) {
return _('Expecting: %s').format(_('valid URL'));
}
}
return true;
}
so.depends('node', 'urltest');
so.modalonly = true;
so = ss.option(form.Value, 'urltest_interval', _('Test interval'),
_('The test interval in seconds. <code>180</code> will be used if empty.'));
so.datatype = 'uinteger';
so.validate = function(section_id, value) {
if (section_id && value) {
var idle_timeout = this.map.lookupOption('urltest_idle_timeout', section_id)[0].formvalue(section_id) || '1800';
if (parseInt(value) > parseInt(idle_timeout))
return _('Test interval must be less or equal than idle timeout.');
}
return true;
}
so.depends('node', 'urltest');
so.modalonly = true;
so = ss.option(form.Value, 'urltest_tolerance', _('Test tolerance'),
_('The test tolerance in milliseconds. <code>50</code> will be used if empty.'));
so.datatype = 'uinteger';
so.depends('node', 'urltest');
so.modalonly = true;
so = ss.option(form.Value, 'urltest_idle_timeout', _('Idle timeout'),
_('The idle timeout in seconds. <code>1800</code> will be used if empty.'));
so.datatype = 'uinteger';
so.depends('node', 'urltest');
so.modalonly = true;
so = ss.option(form.Flag, 'urltest_interrupt_exist_connections', _('Interrupt existing connections'),
_('Interrupt existing connections when the selected outbound has changed.'));
so.default = so.disabled;
so.depends('node', 'urltest');
so.modalonly = true;
/* Routing nodes end */ /* Routing nodes end */
/* Routing rules start */ /* Routing rules start */
@ -580,13 +644,12 @@ return view.extend({
_('Match user name.')); _('Match user name.'));
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_other', form.MultiValue, 'rule_set', _('Rule set'), so = ss.taboption('field_other', hp.CBIStaticList, 'rule_set', _('Rule set'),
_('Match rule set.')); _('Match rule set.'));
so.load = function(section_id) { so.load = function(section_id) {
delete this.keylist; delete this.keylist;
delete this.vallist; delete this.vallist;
this.value('', _('-- Please choose --'));
uci.sections(data[0], 'ruleset', (res) => { uci.sections(data[0], 'ruleset', (res) => {
if (res.enabled === '1') if (res.enabled === '1')
this.value(res['.name'], res.label); this.value(res['.name'], res.label);
@ -920,13 +983,12 @@ return view.extend({
_('Match user name.')); _('Match user name.'));
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_other', form.MultiValue, 'rule_set', _('Rule set'), so = ss.taboption('field_other', hp.CBIStaticList, 'rule_set', _('Rule set'),
_('Match rule set.')); _('Match rule set.'));
so.load = function(section_id) { so.load = function(section_id) {
delete this.keylist; delete this.keylist;
delete this.vallist; delete this.vallist;
this.value('', _('-- Please choose --'));
uci.sections(data[0], 'ruleset', (res) => { uci.sections(data[0], 'ruleset', (res) => {
if (res.enabled === '1') if (res.enabled === '1')
this.value(res['.name'], res.label); this.value(res['.name'], res.label);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -300,6 +300,8 @@ function get_outbound(cfg) {
const node = uci.get(uciconfig, cfg, 'node'); const node = uci.get(uciconfig, cfg, 'node');
if (isEmpty(node)) if (isEmpty(node))
die(sprintf("%s's node is missing, please check your configuration.", cfg)); die(sprintf("%s's node is missing, please check your configuration.", cfg));
else if (node === 'urltest')
return 'cfg-' + cfg + '-out';
else else
return 'cfg-' + node + '-out'; return 'cfg-' + node + '-out';
} }
@ -571,17 +573,39 @@ if (!isEmpty(main_node)) {
push(config.outbounds, generate_outbound(main_udp_node_cfg)); push(config.outbounds, generate_outbound(main_udp_node_cfg));
config.outbounds[length(config.outbounds)-1].tag = 'main-udp-out'; config.outbounds[length(config.outbounds)-1].tag = 'main-udp-out';
} }
} else if (!isEmpty(default_outbound)) } else if (!isEmpty(default_outbound)) {
let urltest_nodes = [],
routing_nodes = [];
uci.foreach(uciconfig, uciroutingnode, (cfg) => { uci.foreach(uciconfig, uciroutingnode, (cfg) => {
if (cfg.enabled !== '1') if (cfg.enabled !== '1')
return; return;
const outbound = uci.get_all(uciconfig, cfg.node) || {}; if (cfg.node === 'urltest') {
push(config.outbounds, generate_outbound(outbound)); push(config.outbounds, {
config.outbounds[length(config.outbounds)-1].domain_strategy = cfg.domain_strategy; type: 'urltest',
config.outbounds[length(config.outbounds)-1].bind_interface = cfg.bind_interface; tag: 'cfg-' + cfg['.name'] + '-out',
config.outbounds[length(config.outbounds)-1].detour = get_outbound(cfg.outbound); outbounds: map(cfg.urltest_nodes, (k) => `cfg-${k}-out`),
url: cfg.urltest_url,
interval: cfg.urltest_interval ? (cfg.urltest_interval + 's') : null,
tolerance: strToInt(cfg.urltest_tolerance),
idle_timeout: cfg.urltest_idle_timeout ? (cfg.urltest_idle_timeout + 's') : null,
interrupt_exist_connections: (cfg.urltest_interrupt_exist_connections === '1')
});
urltest_nodes = [...urltest_nodes, ...filter(cfg.urltest_nodes, ((l) => !~index(urltest_nodes, l)))];
} else {
const outbound = uci.get_all(uciconfig, cfg.node) || {};
push(config.outbounds, generate_outbound(outbound));
config.outbounds[length(config.outbounds)-1].domain_strategy = cfg.domain_strategy;
config.outbounds[length(config.outbounds)-1].bind_interface = cfg.bind_interface;
config.outbounds[length(config.outbounds)-1].detour = get_outbound(cfg.outbound);
push(routing_nodes, cfg.node);
}
}); });
for (let i in filter(urltest_nodes, ((l) => !~index(routing_nodes, l))))
push(config.outbounds, generate_outbound(uci.get_all(uciconfig, i)));
}
/* Outbound end */ /* Outbound end */
/* Routing rules start */ /* Routing rules start */
@ -593,7 +617,6 @@ config.route = {
outbound: 'dns-out' outbound: 'dns-out'
} }
], ],
rule_set: [],
auto_detect_interface: isEmpty(default_interface) ? true : null, auto_detect_interface: isEmpty(default_interface) ? true : null,
default_interface: default_interface default_interface: default_interface
}; };
@ -654,6 +677,7 @@ if (!isEmpty(main_node)) {
/* Rule set */ /* Rule set */
if (routing_mode === 'custom') { if (routing_mode === 'custom') {
config.route.rule_set = [];
uci.foreach(uciconfig, uciruleset, (cfg) => { uci.foreach(uciconfig, uciruleset, (cfg) => {
if (cfg.enabled !== '1') if (cfg.enabled !== '1')
return null; return null;