diff --git a/luci-app-homeproxy/htdocs/luci-static/resources/homeproxy.js b/luci-app-homeproxy/htdocs/luci-static/resources/homeproxy.js index 020ea3e01..be47bd5ef 100644 --- a/luci-app-homeproxy/htdocs/luci-static/resources/homeproxy.js +++ b/luci-app-homeproxy/htdocs/luci-static/resources/homeproxy.js @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: GPL-2.0-only * - * Copyright (C) 2022-2023 ImmortalWrt.org + * Copyright (C) 2022-2025 ImmortalWrt.org */ 'use strict'; @@ -73,7 +73,7 @@ return baseclass.extend({ } }), - calcStringMD5: function(e) { + calcStringMD5(e) { /* Thanks to https://stackoverflow.com/a/41602636 */ function h(a, b) { var c, d, e, f, g; @@ -154,7 +154,7 @@ return baseclass.extend({ return (p(a) + p(b) + p(c) + p(d)).toLowerCase(); }, - decodeBase64Str: function(str) { + decodeBase64Str(str) { if (!str) return null; @@ -169,7 +169,7 @@ return baseclass.extend({ ).join('')); }, - getBuiltinFeatures: function() { + getBuiltinFeatures() { const callGetSingBoxFeatures = rpc.declare({ object: 'luci.homeproxy', method: 'singbox_get_features', @@ -179,7 +179,7 @@ return baseclass.extend({ return L.resolveDefault(callGetSingBoxFeatures(), {}); }, - generateRand: function(type, length) { + generateRand(type, length) { var byteArr; if (['base64', 'hex'].includes(type)) byteArr = crypto.getRandomValues(new Uint8Array(length)); @@ -201,7 +201,7 @@ return baseclass.extend({ }; }, - loadDefaultLabel: function(uciconfig, ucisection) { + loadDefaultLabel(uciconfig, ucisection) { var label = uci.get(uciconfig, ucisection, 'label'); if (label) { return label; @@ -211,12 +211,12 @@ return baseclass.extend({ } }, - loadModalTitle: function(title, addtitle, uciconfig, ucisection) { + loadModalTitle(title, addtitle, uciconfig, ucisection) { var label = uci.get(uciconfig, ucisection, 'label'); return label ? title + ' » ' + label : addtitle; }, - renderSectionAdd: function(section, extra_class) { + renderSectionAdd(section, extra_class) { var el = form.GridSection.prototype.renderSectionAdd.apply(section, [ extra_class ]), nameEl = el.querySelector('.cbi-section-create-name'); ui.addValidator(nameEl, 'uciname', true, (v) => { @@ -238,7 +238,7 @@ return baseclass.extend({ return el; }, - uploadCertificate: function(option, type, filename, ev) { + uploadCertificate(_option, type, filename, ev) { const callWriteCertificate = rpc.declare({ object: 'luci.homeproxy', method: 'certificate_write', @@ -247,7 +247,7 @@ return baseclass.extend({ }); return ui.uploadFile('/tmp/homeproxy_certificate.tmp', ev.target) - .then(L.bind((btn, res) => { + .then(L.bind((_btn, res) => { return L.resolveDefault(callWriteCertificate(filename), {}).then((ret) => { if (ret.result === true) ui.addNotification(null, E('p', _('Your %s was successfully uploaded. Size: %sB.').format(type, res.size))); @@ -258,7 +258,7 @@ return baseclass.extend({ .catch((e) => { ui.addNotification(null, E('p', e.message)) }); }, - validateBase64Key: function(length, section_id, value) { + validateBase64Key(length, section_id, value) { /* Thanks to luci-proto-wireguard */ if (section_id && value) if (value.length !== length || !value.match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/) || value[length-1] !== '=') @@ -267,7 +267,7 @@ return baseclass.extend({ return true; }, - validateCertificatePath: function(section_id, value) { + validateCertificatePath(section_id, value) { if (section_id && value) if (!value.match(/^(\/etc\/homeproxy\/certs\/|\/etc\/acme\/|\/etc\/ssl\/).+$/)) return _('Expecting: %s').format(_('/etc/homeproxy/certs/..., /etc/acme/..., /etc/ssl/...')); @@ -275,7 +275,7 @@ return baseclass.extend({ return true; }, - validateUniqueValue: function(uciconfig, ucisection, ucioption, section_id, value) { + validateUniqueValue(uciconfig, ucisection, ucioption, section_id, value) { if (section_id) { if (!value) return _('Expecting: %s').format(_('non-empty value')); @@ -295,7 +295,7 @@ return baseclass.extend({ return true; }, - validateUUID: function(section_id, value) { + validateUUID(section_id, value) { if (section_id) { if (!value) return _('Expecting: %s').format(_('non-empty value')); diff --git a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js index 16e6b996f..8b5474a4c 100644 --- a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js +++ b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/client.js @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: GPL-2.0-only * - * Copyright (C) 2022-2023 ImmortalWrt.org + * Copyright (C) 2022-2025 ImmortalWrt.org */ 'use strict'; @@ -40,7 +40,7 @@ const callWriteDomainList = rpc.declare({ function getServiceStatus() { return L.resolveDefault(callServiceList('homeproxy'), {}).then((res) => { - var isRunning = false; + let isRunning = false; try { isRunning = res['homeproxy']['instances']['sing-box-c']['running']; } catch (e) { } @@ -49,8 +49,8 @@ function getServiceStatus() { } function renderStatus(isRunning, version) { - var spanTemp = '%s (sing-box v%s) %s'; - var renderHTML; + let spanTemp = '%s (sing-box v%s) %s'; + let renderHTML; if (isRunning) renderHTML = spanTemp.format('green', _('HomeProxy'), version, _('RUNNING')); else @@ -78,21 +78,21 @@ function validatePortRange(section_id, value) { return true; } -var stubValidator = { +let stubValidator = { factory: validation, - apply: function(type, value, args) { + apply(type, value, args) { if (value != null) this.value = value; return validation.types[type].apply(this, args); }, - assert: function(condition) { + assert(condition) { return !!condition; } }; return view.extend({ - load: function() { + load() { return Promise.all([ uci.load('homeproxy'), hp.getBuiltinFeatures(), @@ -100,16 +100,16 @@ return view.extend({ ]); }, - render: function(data) { + render(data) { let m, s, o, ss, so; - var features = data[1], + let features = data[1], hosts = data[2]?.hosts; /* Cache all configured proxy nodes, they will be called multiple times */ - var proxy_nodes = {}; + let proxy_nodes = {}; uci.sections(data[0], 'node', (res) => { - var nodeaddr = ((res.type === 'direct') ? res.override_address : res.address) || '', + let nodeaddr = ((res.type === 'direct') ? res.override_address : res.address) || '', nodeport = ((res.type === 'direct') ? res.override_port : res.port) || ''; proxy_nodes[res['.name']] = @@ -124,7 +124,7 @@ return view.extend({ s.render = function () { poll.add(function () { return L.resolveDefault(getServiceStatus()).then((res) => { - var view = document.getElementById('service_status'); + let view = document.getElementById('service_status'); view.innerHTML = renderStatus(res, features.version); }); }); @@ -140,7 +140,7 @@ return view.extend({ o = s.taboption('routing', form.ListValue, 'main_node', _('Main node')); o.value('nil', _('Disable')); - for (var i in proxy_nodes) + for (let i in proxy_nodes) o.value(i, proxy_nodes[i]); o.default = 'nil'; o.depends({'routing_mode': 'custom', '!reverse': true}); @@ -149,7 +149,7 @@ return view.extend({ o = s.taboption('routing', form.ListValue, 'main_udp_node', _('Main UDP node')); o.value('nil', _('Disable')); o.value('same', _('Same as main node')); - for (var i in proxy_nodes) + for (let i in proxy_nodes) o.value(i, proxy_nodes[i]); o.default = 'nil'; o.depends({'routing_mode': /^((?!custom).)+$/, 'proxy_mode': /^((?!redirect$).)+$/}); @@ -173,9 +173,9 @@ return view.extend({ if (!value) return _('Expecting: %s').format(_('non-empty value')); - var ipv6_support = this.map.lookupOption('ipv6_support', section_id)[0].formvalue(section_id); + let ipv6_support = this.map.lookupOption('ipv6_support', section_id)[0].formvalue(section_id); try { - var url = new URL(value); + let url = new URL(value); if (stubValidator.apply('hostname', url.hostname)) return true; else if (stubValidator.apply('ip4addr', url.hostname)) @@ -209,7 +209,7 @@ return view.extend({ return _('Expecting: %s').format(_('non-empty value')); try { - var url = new URL(value); + let url = new URL(value); if (stubValidator.apply('hostname', url.hostname)) return true; else if (stubValidator.apply('ip4addr', url.hostname)) @@ -247,8 +247,8 @@ return view.extend({ o.validate = function(section_id, value) { if (section_id && value && value !== 'common') { - var ports = []; - for (var i of value.split(',')) { + let ports = []; + for (let i of value.split(',')) { if (!stubValidator.apply('port', i) && !stubValidator.apply('portrange', i)) return _('Expecting: %s').format(_('valid port value')); if (ports.includes(i)) @@ -301,7 +301,7 @@ return view.extend({ so.depends('homeproxy.config.proxy_mode', 'tun'); so.rmempty = false; so.onchange = function(ev, section_id, value) { - var desc = ev.target.nextElementSibling; + let desc = ev.target.nextElementSibling; if (value === 'mixed') desc.innerHTML = _('Mixed system TCP stack and gVisor UDP stack.') else if (value === 'gvisor') @@ -333,7 +333,7 @@ return view.extend({ so = ss.option(form.ListValue, 'domain_strategy', _('Domain strategy'), _('If set, the requested domain name will be resolved to IP before routing.')); - for (var i in hp.dns_strategy) + for (let i in hp.dns_strategy) so.value(i, hp.dns_strategy[i]) so = ss.option(form.Flag, 'sniff_override', _('Override destination'), @@ -387,14 +387,14 @@ return view.extend({ so = ss.option(form.ListValue, 'node', _('Node'), _('Outbound node')); so.value('urltest', _('URLTest')); - for (var i in proxy_nodes) + for (let i in proxy_nodes) so.value(i, proxy_nodes[i]); so.validate = L.bind(hp.validateUniqueValue, this, data[0], 'routing_node', 'node'); so.editable = true; so = ss.option(form.ListValue, 'domain_strategy', _('Domain strategy'), _('If set, the server domain name will be resolved to IP before connecting.
')); - for (var i in hp.dns_strategy) + for (let i in hp.dns_strategy) so.value(i, hp.dns_strategy[i]); so.depends({'node': 'urltest', '!reverse': true}); so.modalonly = true; @@ -422,9 +422,9 @@ return view.extend({ } so.validate = function(section_id, value) { if (section_id && value) { - var node = this.map.lookupOption('node', section_id)[0].formvalue(section_id); + let node = this.map.lookupOption('node', section_id)[0].formvalue(section_id); - var conflict = false; + let conflict = false; uci.sections(data[0], 'routing_node', (res) => { if (res['.name'] !== section_id) { if (res.outbound === section_id && res['.name'] == value) @@ -444,7 +444,7 @@ return view.extend({ so = ss.option(hp.CBIStaticList, 'urltest_nodes', _('URLTest nodes'), _('List of nodes to test.')); - for (var i in proxy_nodes) + for (let i in proxy_nodes) so.value(i, proxy_nodes[i]); so.depends('node', 'urltest'); so.modalonly = true; @@ -454,7 +454,7 @@ return view.extend({ so.validate = function(section_id, value) { if (section_id && value) { try { - var url = new URL(value); + let url = new URL(value); if (!url.hostname) return _('Expecting: %s').format(_('valid URL')); } @@ -473,7 +473,7 @@ return view.extend({ 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'; + let 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.'); } @@ -706,7 +706,7 @@ return view.extend({ ss = o.subsection; so = ss.option(form.ListValue, 'default_strategy', _('Default DNS strategy'), _('The DNS strategy for resolving the domain name in the address.')); - for (var i in hp.dns_strategy) + for (let i in hp.dns_strategy) so.value(i, hp.dns_strategy[i]); so = ss.option(form.ListValue, 'default_server', _('Default DNS server')); @@ -788,7 +788,7 @@ return view.extend({ return _('Expecting: %s').format(_('non-empty value')); try { - var url = new URL(value); + let url = new URL(value); if (stubValidator.apply('hostname', url.hostname)) return true; else if (stubValidator.apply('ip4addr', url.hostname)) @@ -824,7 +824,7 @@ return view.extend({ } so.validate = function(section_id, value) { if (section_id && value) { - var conflict = false; + let conflict = false; uci.sections(data[0], 'dns_server', (res) => { if (res['.name'] !== section_id) if (res.address_resolver === section_id && res['.name'] == value) @@ -840,13 +840,13 @@ return view.extend({ so = ss.option(form.ListValue, 'address_strategy', _('Address strategy'), _('The domain strategy for resolving the domain name in the address.')); - for (var i in hp.dns_strategy) + for (let i in hp.dns_strategy) so.value(i, hp.dns_strategy[i]); so.modalonly = true; so = ss.option(form.ListValue, 'resolve_strategy', _('Resolve strategy'), _('Default domain strategy for resolving the domain names.')); - for (var i in hp.dns_strategy) + for (let i in hp.dns_strategy) so.value(i, hp.dns_strategy[i]); so.editable = true; @@ -1150,7 +1150,7 @@ return view.extend({ return _('Expecting: %s').format(_('non-empty value')); try { - var url = new URL(value); + let url = new URL(value); if (!url.hostname) return _('Expecting: %s').format(_('valid URL')); } @@ -1278,20 +1278,24 @@ return view.extend({ so.monospace = true; so.datatype = 'hostname'; so.depends({'homeproxy.config.routing_mode': 'custom', '!reverse': true}); - so.load = function(section_id) { + so.load = function(/* ... */) { return L.resolveDefault(callReadDomainList('proxy_list')).then((res) => { return res.content; }, {}); } - so.write = function(section_id, value) { + so.write = function(_section_id, value) { return callWriteDomainList('proxy_list', value); } - so.remove = function(section_id, value) { - return callWriteDomainList('proxy_list', ''); + so.remove = function(/* ... */) { + let routing_mode = this.map.lookupOption('routing_mode', 'config')[0].formvalue('config'); + + if (routing_mode !== 'custom') + return callWriteDomainList('proxy_list', ''); + return true; } so.validate = function(section_id, value) { if (section_id && value) - for (var i of value.split('\n')) + for (let i of value.split('\n')) if (i && !stubValidator.apply('hostname', i)) return _('Expecting: %s').format(_('valid hostname')); @@ -1307,20 +1311,24 @@ return view.extend({ so.monospace = true; so.datatype = 'hostname'; so.depends({'homeproxy.config.routing_mode': 'custom', '!reverse': true}); - so.load = function(section_id) { + so.load = function(/* ... */) { return L.resolveDefault(callReadDomainList('direct_list')).then((res) => { return res.content; }, {}); } - so.write = function(section_id, value) { + so.write = function(_section_id, value) { return callWriteDomainList('direct_list', value); } - so.remove = function(section_id, value) { - return callWriteDomainList('direct_list', ''); + so.remove = function(/* ... */) { + let routing_mode = this.map.lookupOption('routing_mode', 'config')[0].formvalue('config'); + + if (routing_mode !== 'custom') + return callWriteDomainList('direct_list', ''); + return true; } so.validate = function(section_id, value) { if (section_id && value) - for (var i of value.split('\n')) + for (let i of value.split('\n')) if (i && !stubValidator.apply('hostname', i)) return _('Expecting: %s').format(_('valid hostname')); diff --git a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js index 31ce172ec..b108137bd 100644 --- a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js +++ b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/node.js @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: GPL-2.0-only * - * Copyright (C) 2022-2024 ImmortalWrt.org + * Copyright (C) 2022-2025 ImmortalWrt.org */ 'use strict'; @@ -14,20 +14,20 @@ 'require homeproxy as hp'; 'require tools.widgets as widgets'; -function allowInsecureConfirm(ev, section_id, value) { +function allowInsecureConfirm(ev, _section_id, value) { if (value === '1' && !confirm(_('Are you sure to allow insecure?'))) ev.target.firstElementChild.checked = null; } function parseShareLink(uri, features) { - var config; + let config, url, params; uri = uri.split('://'); if (uri[0] && uri[1]) { switch (uri[0]) { case 'http': case 'https': - var url = new URL('http://' + uri[1]); + url = new URL('http://' + uri[1]); config = { label: url.hash ? decodeURIComponent(url.hash.slice(1)) : null, @@ -42,8 +42,8 @@ function parseShareLink(uri, features) { break; case 'hysteria': /* https://github.com/HyNetwork/hysteria/wiki/URI-Scheme */ - var url = new URL('http://' + uri[1]); - var params = url.searchParams; + url = new URL('http://' + uri[1]); + params = url.searchParams; /* WeChat-Video / FakeTCP are unsupported by sing-box currently */ if (!features.with_quic || (params.get('protocol') && params.get('protocol') !== 'udp')) @@ -70,8 +70,8 @@ function parseShareLink(uri, features) { case 'hysteria2': case 'hy2': /* https://v2.hysteria.network/docs/developers/URI-Scheme/ */ - var url = new URL('http://' + uri[1]); - var params = url.searchParams; + url = new URL('http://' + uri[1]); + params = url.searchParams; if (!features.with_quic) return null; @@ -97,7 +97,7 @@ function parseShareLink(uri, features) { case 'socks4a': case 'socsk5': case 'socks5h': - var url = new URL('http://' + uri[1]); + url = new URL('http://' + uri[1]); config = { label: url.hash ? decodeURIComponent(url.hash.slice(1)) : null, @@ -114,7 +114,7 @@ function parseShareLink(uri, features) { try { /* "Lovely" Shadowrocket format */ try { - var suri = uri[1].split('#'), slabel = ''; + let suri = uri[1].split('#'), slabel = ''; if (suri.length <= 2) { if (suri.length === 2) slabel = '#' + suri[1]; @@ -123,9 +123,9 @@ function parseShareLink(uri, features) { } catch(e) { } /* SIP002 format https://shadowsocks.org/guide/sip002.html */ - var url = new URL('http://' + uri[1]); + url = new URL('http://' + uri[1]); - var userinfo; + let userinfo; if (url.username && url.password) /* User info encoded with URIComponent */ userinfo = [url.username, decodeURIComponent(url.password)]; @@ -136,9 +136,9 @@ function parseShareLink(uri, features) { if (!hp.shadowsocks_encrypt_methods.includes(userinfo[0])) return null; - var plugin, plugin_opts; + let plugin, plugin_opts; if (url.search && url.searchParams.get('plugin')) { - var plugin_info = url.searchParams.get('plugin').split(';'); + let plugin_info = url.searchParams.get('plugin').split(';'); plugin = plugin_info[0]; plugin_opts = plugin_info.slice(1) ? plugin_info.slice(1).join(';') : null; } @@ -173,8 +173,8 @@ function parseShareLink(uri, features) { break; case 'trojan': /* https://p4gefau1t.github.io/trojan-go/developer/url/ */ - var url = new URL('http://' + uri[1]); - var params = url.searchParams; + url = new URL('http://' + uri[1]); + params = url.searchParams; /* Check if password exists */ if (!url.username) @@ -208,8 +208,8 @@ function parseShareLink(uri, features) { break; case 'tuic': /* https://github.com/daeuniverse/dae/discussions/182 */ - var url = new URL('http://' + uri[1]); - var params = url.searchParams; + url = new URL('http://' + uri[1]); + params = url.searchParams; /* Check if uuid exists */ if (!url.username) @@ -232,8 +232,8 @@ function parseShareLink(uri, features) { break; case 'vless': /* https://github.com/XTLS/Xray-core/discussions/716 */ - var url = new URL('http://' + uri[1]); - var params = url.searchParams; + url = new URL('http://' + uri[1]); + params = url.searchParams; /* Unsupported protocol */ if (params.get('type') === 'kcp') @@ -356,7 +356,7 @@ function parseShareLink(uri, features) { } function renderNodeSettings(section, data, features, main_node, routing_mode) { - var s = section, o; + let s = section, o; s.rowcolors = true; s.sortable = true; s.nodescriptions = true; @@ -439,12 +439,12 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { o.depends({'type': 'socks', 'socks_version': '5'}); o.validate = function(section_id, value) { if (section_id) { - var type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); - var required_type = [ 'shadowsocks', 'shadowtls', 'trojan' ]; + let type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); + let required_type = [ 'shadowsocks', 'shadowtls', 'trojan' ]; if (required_type.includes(type)) { if (type === 'shadowsocks') { - var encmode = this.map.lookupOption('shadowsocks_encrypt_method', section_id)[0].formvalue(section_id); + let encmode = this.map.lookupOption('shadowsocks_encrypt_method', section_id)[0].formvalue(section_id); if (encmode === 'none') return true; } @@ -546,7 +546,7 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { /* Shadowsocks config start */ o = s.option(form.ListValue, 'shadowsocks_encrypt_method', _('Encrypt method')); - for (var i of hp.shadowsocks_encrypt_methods) + for (let i of hp.shadowsocks_encrypt_methods) o.value(i); /* Stream ciphers */ o.value('aes-128-ctr'); @@ -720,7 +720,7 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { o.depends('type', 'vless'); o.depends('type', 'vmess'); o.onchange = function(ev, section_id, value) { - var desc = this.map.findElement('id', 'cbid.homeproxy.%s.transport'.format(section_id)).nextElementSibling; + let desc = this.map.findElement('id', 'cbid.homeproxy.%s.transport'.format(section_id)).nextElementSibling; if (value === 'http') desc.innerHTML = _('TLS is not enforced. If TLS is not configured, plain HTTP 1.1 is used.'); else if (value === 'quic') @@ -728,7 +728,7 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { else desc.innerHTML = _('No TCP transport, plain HTTP is merged into the HTTP transport.'); - var tls = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; + let tls = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; if ((value === 'http' && tls.checked) || (value === 'grpc' && !features.with_grpc)) { this.map.findElement('id', 'cbid.homeproxy.%s.http_idle_timeout'.format(section_id)).nextElementSibling.innerHTML = _('Specifies the period of time (in seconds) after which a health check will be performed using a ping frame if no frames have been received on the connection.
' + @@ -951,10 +951,10 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { o.depends('type', 'tuic'); o.depends('type', 'vless'); o.depends('type', 'vmess'); - o.validate = function(section_id, value) { + o.validate = function(section_id, _value) { if (section_id) { - var type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); - var tls = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; + let type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); + let tls = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; if (['hysteria', 'hysteria2', 'shadowtls', 'tuic'].includes(type)) { tls.checked = true; @@ -990,7 +990,7 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { o = s.option(form.ListValue, 'tls_min_version', _('Minimum TLS version'), _('The minimum TLS version that is acceptable.')); o.value('', _('default')); - for (var i of hp.tls_versions) + for (let i of hp.tls_versions) o.value(i); o.depends('tls', '1'); o.modalonly = true; @@ -998,14 +998,14 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { o = s.option(form.ListValue, 'tls_max_version', _('Maximum TLS version'), _('The maximum TLS version that is acceptable.')); o.value('', _('default')); - for (var i of hp.tls_versions) + for (let i of hp.tls_versions) o.value(i); o.depends('tls', '1'); o.modalonly = true; o = s.option(hp.CBIStaticList, 'tls_cipher_suites', _('Cipher suites'), _('The elliptic curves that will be used in an ECDHE handshake, in preference order. If empty, the default will be used.')); - for (var i of hp.tls_cipher_suites) + for (let i of hp.tls_cipher_suites) o.value(i); o.depends('tls', '1'); o.optional = true; @@ -1144,22 +1144,22 @@ function renderNodeSettings(section, data, features, main_node, routing_mode) { } return view.extend({ - load: function() { + load() { return Promise.all([ uci.load('homeproxy'), hp.getBuiltinFeatures() ]); }, - render: function(data) { + render(data) { let m, s, o, ss, so; - var main_node = uci.get(data[0], 'config', 'main_node'); - var routing_mode = uci.get(data[0], 'config', 'routing_mode'); - var features = data[1]; + let main_node = uci.get(data[0], 'config', 'main_node'); + let routing_mode = uci.get(data[0], 'config', 'routing_mode'); + let features = data[1]; /* Cache subscription information, it will be called multiple times */ - var subinfo = []; - for (var suburl of (uci.get(data[0], 'subscription', 'subscription_url') || [])) { + let subinfo = []; + for (let suburl of (uci.get(data[0], 'subscription', 'subscription_url') || [])) { const url = new URL(suburl); const urlhash = hp.calcStringMD5(suburl.replace(/#.*$/, '')); const title = url.hash ? decodeURIComponent(url.hash.slice(1)) : url.hostname; @@ -1177,7 +1177,7 @@ return view.extend({ ss = renderNodeSettings(o.subsection, data, features, main_node, routing_mode); ss.addremove = true; ss.filter = function(section_id) { - for (var info of subinfo) + for (let info of subinfo) if (info.hash === uci.get(data[0], section_id, 'grouphash')) return false; @@ -1186,7 +1186,7 @@ return view.extend({ /* Import subscription links start */ /* Thanks to luci-app-shadowsocks-libev */ ss.handleLinkImport = function() { - var textarea = new ui.Textarea(); + let textarea = new ui.Textarea(); ui.showModal(_('Import share links'), [ E('p', _('Support Hysteria, Shadowsocks, Trojan, v2rayN (VMess), and XTLS (VLESS) online configuration delivery standard.')), textarea.render(), @@ -1199,25 +1199,25 @@ return view.extend({ E('button', { class: 'btn cbi-button-action', click: ui.createHandlerFn(this, function() { - var input_links = textarea.getValue().trim().split('\n'); + let input_links = textarea.getValue().trim().split('\n'); if (input_links && input_links[0]) { /* Remove duplicate lines */ input_links = input_links.reduce((pre, cur) => (!pre.includes(cur) && pre.push(cur), pre), []); - var allow_insecure = uci.get(data[0], 'subscription', 'allow_insecure'); - var packet_encoding = uci.get(data[0], 'subscription', 'packet_encoding'); - var imported_node = 0; + let allow_insecure = uci.get(data[0], 'subscription', 'allow_insecure'); + let packet_encoding = uci.get(data[0], 'subscription', 'packet_encoding'); + let imported_node = 0; input_links.forEach((l) => { - var config = parseShareLink(l, features); + let config = parseShareLink(l, features); if (config) { if (config.tls === '1' && allow_insecure === '1') config.tls_insecure = '1' if (['vless', 'vmess'].includes(config.type)) config.packet_encoding = packet_encoding - var nameHash = hp.calcStringMD5(config.label); - var sid = uci.add(data[0], 'node', nameHash); + let nameHash = hp.calcStringMD5(config.label); + let sid = uci.add(data[0], 'node', nameHash); Object.keys(config).forEach((k) => { uci.set(data[0], sid, k, config[k]); }); @@ -1245,12 +1245,12 @@ return view.extend({ ]) } ss.renderSectionAdd = function(/* ... */) { - var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments), + let el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments), nameEl = el.querySelector('.cbi-section-create-name'); ui.addValidator(nameEl, 'uciname', true, (v) => { - var button = el.querySelector('.cbi-section-create > .cbi-button-add'); - var uciconfig = this.uciconfig || this.map.config; + let button = el.querySelector('.cbi-section-create > .cbi-button-add'); + let uciconfig = this.uciconfig || this.map.config; if (!v) { button.disabled = true; @@ -1296,7 +1296,7 @@ return view.extend({ o.rmempty = false; o = s.taboption('subscription', form.ListValue, 'auto_update_time', _('Update time')); - for (var i = 0; i < 24; i++) + for (let i = 0; i < 24; i++) o.value(i, i + ':00'); o.default = '2'; o.depends('auto_update', '1'); @@ -1311,7 +1311,7 @@ return view.extend({ o.validate = function(section_id, value) { if (section_id && value) { try { - var url = new URL(value); + let url = new URL(value); if (!url.hostname) return _('Expecting: %s').format(_('valid URL')); } @@ -1364,7 +1364,7 @@ return view.extend({ o = s.taboption('subscription', form.Button, '_update_subscriptions', _('Update nodes from subscriptions')); o.inputstyle = 'apply'; o.inputtitle = function(section_id) { - var sublist = uci.get(data[0], section_id, 'subscription_url') || []; + let sublist = uci.get(data[0], section_id, 'subscription_url') || []; if (sublist.length > 0) { return _('Update %s subscriptions').format(sublist.length); } else { @@ -1384,7 +1384,7 @@ return view.extend({ o = s.taboption('subscription', form.Button, '_remove_subscriptions', _('Remove all nodes from subscriptions')); o.inputstyle = 'reset'; o.inputtitle = function() { - var subnodes = []; + let subnodes = []; uci.sections(data[0], 'node', (res) => { if (res.grouphash) subnodes = subnodes.concat(res['.name']) @@ -1398,13 +1398,13 @@ return view.extend({ } } o.onclick = function() { - var subnodes = []; + let subnodes = []; uci.sections(data[0], 'node', (res) => { if (res.grouphash) subnodes = subnodes.concat(res['.name']) }); - for (var i in subnodes) + for (let i in subnodes) uci.remove(data[0], subnodes[i]); if (subnodes.includes(uci.get(data[0], 'config', 'main_node'))) diff --git a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js index c93960f83..cf8c6d83d 100644 --- a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js +++ b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/server.js @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: GPL-2.0-only * - * Copyright (C) 2022-2023 ImmortalWrt.org + * Copyright (C) 2022-2025 ImmortalWrt.org */ 'use strict'; @@ -23,7 +23,7 @@ const callServiceList = rpc.declare({ function getServiceStatus() { return L.resolveDefault(callServiceList('homeproxy'), {}).then((res) => { - var isRunning = false; + let isRunning = false; try { isRunning = res['homeproxy']['instances']['sing-box-s']['running']; } catch (e) { } @@ -32,8 +32,8 @@ function getServiceStatus() { } function renderStatus(isRunning, version) { - var spanTemp = '%s (sing-box v%s) %s'; - var renderHTML; + let spanTemp = '%s (sing-box v%s) %s'; + let renderHTML; if (isRunning) renderHTML = spanTemp.format('green', _('HomeProxy Server'), version, _('RUNNING')); else @@ -43,10 +43,10 @@ function renderStatus(isRunning, version) { } function handleGenKey(option) { - var section_id = this.section.section; - var type = this.section.getOption('type').formvalue(section_id); - var widget = this.map.findElement('id', 'widget.cbid.homeproxy.%s.%s'.format(section_id, option)); - var password, required_method; + let section_id = this.section.section; + let type = this.section.getOption('type').formvalue(section_id); + let widget = this.map.findElement('id', 'widget.cbid.homeproxy.%s.%s'.format(section_id, option)); + let password, required_method; if (option === 'uuid') required_method = 'uuid'; @@ -83,16 +83,16 @@ function handleGenKey(option) { } return view.extend({ - load: function() { + load() { return Promise.all([ uci.load('homeproxy'), hp.getBuiltinFeatures() ]); }, - render: function(data) { + render(data) { let m, s, o; - var features = data[1]; + let features = data[1]; m = new form.Map('homeproxy', _('HomeProxy Server'), _('The modern OpenWrt proxy platform for ARM64/AMD64.')); @@ -101,7 +101,7 @@ return view.extend({ s.render = function () { poll.add(function () { return L.resolveDefault(getServiceStatus()).then((res) => { - var view = document.getElementById('service_status'); + let view = document.getElementById('service_status'); view.innerHTML = renderStatus(res, features.version); }); }); @@ -183,7 +183,7 @@ return view.extend({ o.depends('type', 'trojan'); o.depends('type', 'tuic'); o.renderWidget = function() { - var node = form.Value.prototype.renderWidget.apply(this, arguments); + let node = form.Value.prototype.renderWidget.apply(this, arguments); (node.querySelector('.control-group') || node).appendChild(E('button', { 'class': 'cbi-button cbi-button-apply', @@ -195,12 +195,12 @@ return view.extend({ } o.validate = function(section_id, value) { if (section_id) { - var type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); - var required_type = [ 'http', 'mixed', 'naive', 'socks', 'shadowsocks' ]; + let type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); + let required_type = [ 'http', 'mixed', 'naive', 'socks', 'shadowsocks' ]; if (required_type.includes(type)) { if (type === 'shadowsocks') { - var encmode = this.map.lookupOption('shadowsocks_encrypt_method', section_id)[0].formvalue(section_id); + let encmode = this.map.lookupOption('shadowsocks_encrypt_method', section_id)[0].formvalue(section_id); if (encmode === 'none') return true; else if (encmode === '2022-blake3-aes-128-gcm') @@ -266,7 +266,7 @@ return view.extend({ o.depends('type', 'hysteria'); o.depends({'type': 'hysteria2', 'hysteria_obfs_type': /[\s\S]/}); o.renderWidget = function() { - var node = form.Value.prototype.renderWidget.apply(this, arguments); + let node = form.Value.prototype.renderWidget.apply(this, arguments); (node.querySelector('.control-group') || node).appendChild(E('button', { 'class': 'cbi-button cbi-button-apply', @@ -319,7 +319,7 @@ return view.extend({ /* Shadowsocks config */ o = s.option(form.ListValue, 'shadowsocks_encrypt_method', _('Encrypt method')); - for (var i of hp.shadowsocks_encrypt_methods) + for (let i of hp.shadowsocks_encrypt_methods) o.value(i); o.default = 'aes-128-gcm'; o.depends('type', 'shadowsocks'); @@ -331,7 +331,7 @@ return view.extend({ o.depends('type', 'vless'); o.depends('type', 'vmess'); o.renderWidget = function() { - var node = form.Value.prototype.renderWidget.apply(this, arguments); + let node = form.Value.prototype.renderWidget.apply(this, arguments); (node.querySelector('.control-group') || node).appendChild(E('button', { 'class': 'cbi-button cbi-button-apply', @@ -402,7 +402,7 @@ return view.extend({ o.depends('type', 'vless'); o.depends('type', 'vmess'); o.onchange = function(ev, section_id, value) { - var desc = this.map.findElement('id', 'cbid.homeproxy.%s.transport'.format(section_id)).nextElementSibling; + let desc = this.map.findElement('id', 'cbid.homeproxy.%s.transport'.format(section_id)).nextElementSibling; if (value === 'http') desc.innerHTML = _('TLS is not enforced. If TLS is not configured, plain HTTP 1.1 is used.'); else if (value === 'quic') @@ -410,7 +410,7 @@ return view.extend({ else desc.innerHTML = _('No TCP transport, plain HTTP is merged into the HTTP transport.'); - var tls_element = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; + let tls_element = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; if ((value === 'http' && tls_element.checked) || (value === 'grpc' && !features.with_grpc)) this.map.findElement('id', 'cbid.homeproxy.%s.http_idle_timeout'.format(section_id)).nextElementSibling.innerHTML = _('Specifies the time (in seconds) until idle clients should be closed with a GOAWAY frame. PING frames are not considered as activity.'); @@ -539,8 +539,8 @@ return view.extend({ o.rmempty = false; o.validate = function(section_id, value) { if (section_id) { - var type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); - var tls = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; + let type = this.map.lookupOption('type', section_id)[0].formvalue(section_id); + let tls = this.map.findElement('id', 'cbid.homeproxy.%s.tls'.format(section_id)).firstElementChild; if (['hysteria', 'hysteria2', 'tuic'].includes(type)) { tls.checked = true; @@ -567,7 +567,7 @@ return view.extend({ o = s.option(form.ListValue, 'tls_min_version', _('Minimum TLS version'), _('The minimum TLS version that is acceptable.')); o.value('', _('default')); - for (var i of hp.tls_versions) + for (let i of hp.tls_versions) o.value(i); o.depends('tls', '1'); o.modalonly = true; @@ -575,14 +575,14 @@ return view.extend({ o = s.option(form.ListValue, 'tls_max_version', _('Maximum TLS version'), _('The maximum TLS version that is acceptable.')); o.value('', _('default')); - for (var i of hp.tls_versions) + for (let i of hp.tls_versions) o.value(i); o.depends('tls', '1'); o.modalonly = true; o = s.option(hp.CBIStaticList, 'tls_cipher_suites', _('Cipher suites'), _('The elliptic curves that will be used in an ECDHE handshake, in preference order. If empty, the default will be used.')); - for (var i of hp.tls_cipher_suites) + for (let i of hp.tls_cipher_suites) o.value(i); o.depends('tls', '1'); o.optional = true; @@ -808,7 +808,7 @@ return view.extend({ o = s.option(form.ListValue, 'domain_strategy', _('Domain strategy'), _('If set, the requested domain name will be resolved to IP before routing.')); - for (var i in hp.dns_strategy) + for (let i in hp.dns_strategy) o.value(i, hp.dns_strategy[i]) o.modalonly = true; diff --git a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/status.js b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/status.js index 139d6d5e4..2d2bc49d7 100644 --- a/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/status.js +++ b/luci-app-homeproxy/htdocs/luci-static/resources/view/homeproxy/status.js @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: GPL-2.0-only * - * Copyright (C) 2022-2023 ImmortalWrt.org + * Copyright (C) 2022-2025 ImmortalWrt.org */ 'use strict'; @@ -15,7 +15,7 @@ 'require view'; /* Thanks to luci-app-aria2 */ -var css = ' \ +const css = ' \ #log_textarea { \ padding: 10px; \ text-align: left; \ @@ -29,7 +29,7 @@ var css = ' \ background-color: #33ccff; \ }'; -var hp_dir = '/var/run/homeproxy'; +const hp_dir = '/var/run/homeproxy'; function getConnStat(self, site) { const callConnStat = rpc.declare({ @@ -44,7 +44,7 @@ function getConnStat(self, site) { 'class': 'btn cbi-button cbi-button-action', 'click': ui.createHandlerFn(this, function() { return L.resolveDefault(callConnStat(site), {}).then((ret) => { - var ele = self.default.firstElementChild.nextElementSibling; + let ele = self.default.firstElementChild.nextElementSibling; if (ret.result) { ele.style.setProperty('color', 'green'); ele.innerHTML = _('passed'); @@ -76,7 +76,7 @@ function getResVersion(self, type) { }); return L.resolveDefault(callResVersion(type), {}).then((res) => { - var spanTemp = E('div', { 'style': 'cbi-value-field' }, [ + let spanTemp = E('div', { 'style': 'cbi-value-field' }, [ E('button', { 'class': 'btn cbi-button cbi-button-action', 'click': ui.createHandlerFn(this, function() { @@ -121,7 +121,7 @@ function getRuntimeLog(name, filename) { expect: { '': {} } }); - var log_textarea = E('div', { 'id': 'log_textarea' }, + let log_textarea = E('div', { 'id': 'log_textarea' }, E('img', { 'src': L.resource('icons/loading.gif'), 'alt': _('Loading'), @@ -129,7 +129,7 @@ function getRuntimeLog(name, filename) { }, _('Collecting data...')) ); - var log; + let log; poll.add(L.bind(function() { return fs.read_direct(String.format('%s/%s.log', hp_dir, filename), 'text') .then(function(res) { @@ -176,15 +176,8 @@ function getRuntimeLog(name, filename) { } return view.extend({ - load: function() { - return Promise.all([ - uci.load('homeproxy') - ]); - }, - - render: function(data) { - var m, s, o; - var routing_mode = uci.get(data[0], 'config', 'routing_mode') || 'bypass_mainland_china'; + render() { + let m, s, o; m = new form.Map('homeproxy'); diff --git a/luci-app-homeproxy/po/templates/homeproxy.pot b/luci-app-homeproxy/po/templates/homeproxy.pot index 0a6379fe5..4358f3e53 100644 --- a/luci-app-homeproxy/po/templates/homeproxy.pot +++ b/luci-app-homeproxy/po/templates/homeproxy.pot @@ -209,7 +209,7 @@ msgstr "" msgid "BBR" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:194 +#: htdocs/luci-static/resources/view/homeproxy/status.js:187 msgid "BaiDu" msgstr "" @@ -309,15 +309,15 @@ msgstr "" msgid "China DNS server" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:204 +#: htdocs/luci-static/resources/view/homeproxy/status.js:197 msgid "China IPv4 list version" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:208 +#: htdocs/luci-static/resources/view/homeproxy/status.js:201 msgid "China IPv6 list version" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:212 +#: htdocs/luci-static/resources/view/homeproxy/status.js:205 msgid "China list version" msgstr "" @@ -373,7 +373,7 @@ msgstr "" msgid "Congestion control algorithm" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:191 +#: htdocs/luci-static/resources/view/homeproxy/status.js:184 msgid "Connection check" msgstr "" @@ -467,7 +467,7 @@ msgstr "" msgid "Direct" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/client.js:1303 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1307 msgid "Direct Domain List" msgstr "" @@ -737,8 +737,8 @@ msgstr "" #: htdocs/luci-static/resources/view/homeproxy/client.js:1150 #: htdocs/luci-static/resources/view/homeproxy/client.js:1155 #: htdocs/luci-static/resources/view/homeproxy/client.js:1158 -#: htdocs/luci-static/resources/view/homeproxy/client.js:1296 -#: htdocs/luci-static/resources/view/homeproxy/client.js:1325 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1300 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1333 #: htdocs/luci-static/resources/view/homeproxy/node.js:452 #: htdocs/luci-static/resources/view/homeproxy/node.js:1087 #: htdocs/luci-static/resources/view/homeproxy/node.js:1260 @@ -791,7 +791,7 @@ msgstr "" msgid "GET" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:216 +#: htdocs/luci-static/resources/view/homeproxy/status.js:209 msgid "GFW list version" msgstr "" @@ -849,7 +849,7 @@ msgstr "" msgid "Global settings" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:197 +#: htdocs/luci-static/resources/view/homeproxy/status.js:190 msgid "Google" msgstr "" @@ -897,7 +897,7 @@ msgstr "" #: htdocs/luci-static/resources/view/homeproxy/client.js:55 #: htdocs/luci-static/resources/view/homeproxy/client.js:57 #: htdocs/luci-static/resources/view/homeproxy/client.js:120 -#: htdocs/luci-static/resources/view/homeproxy/status.js:224 +#: htdocs/luci-static/resources/view/homeproxy/status.js:217 #: root/usr/share/luci/menu.d/luci-app-homeproxy.json:3 msgid "HomeProxy" msgstr "" @@ -1787,7 +1787,7 @@ msgstr "" msgid "Resolve strategy" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:201 +#: htdocs/luci-static/resources/view/homeproxy/status.js:194 msgid "Resources management" msgstr "" @@ -2653,11 +2653,11 @@ msgstr "" msgid "quic-go / uquic chrome" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:227 +#: htdocs/luci-static/resources/view/homeproxy/status.js:220 msgid "sing-box client" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/status.js:230 +#: htdocs/luci-static/resources/view/homeproxy/status.js:223 msgid "sing-box server" msgstr "" @@ -2722,8 +2722,8 @@ msgstr "" msgid "valid base64 key with %d characters" msgstr "" -#: htdocs/luci-static/resources/view/homeproxy/client.js:1296 -#: htdocs/luci-static/resources/view/homeproxy/client.js:1325 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1300 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1333 msgid "valid hostname" msgstr "" diff --git a/luci-app-homeproxy/po/zh_Hans/homeproxy.po b/luci-app-homeproxy/po/zh_Hans/homeproxy.po index 59fc05e9a..fa34d586b 100644 --- a/luci-app-homeproxy/po/zh_Hans/homeproxy.po +++ b/luci-app-homeproxy/po/zh_Hans/homeproxy.po @@ -218,7 +218,7 @@ msgstr "自动更新订阅和地理数据。" msgid "BBR" msgstr "BBR" -#: htdocs/luci-static/resources/view/homeproxy/status.js:194 +#: htdocs/luci-static/resources/view/homeproxy/status.js:187 msgid "BaiDu" msgstr "百度" @@ -318,15 +318,15 @@ msgstr "检查更新" msgid "China DNS server" msgstr "国内 DNS 服务器" -#: htdocs/luci-static/resources/view/homeproxy/status.js:204 +#: htdocs/luci-static/resources/view/homeproxy/status.js:197 msgid "China IPv4 list version" msgstr "国内 IPv4 库版本" -#: htdocs/luci-static/resources/view/homeproxy/status.js:208 +#: htdocs/luci-static/resources/view/homeproxy/status.js:201 msgid "China IPv6 list version" msgstr "国内 IPv6 库版本" -#: htdocs/luci-static/resources/view/homeproxy/status.js:212 +#: htdocs/luci-static/resources/view/homeproxy/status.js:205 msgid "China list version" msgstr "国内域名列表版本" @@ -382,7 +382,7 @@ msgstr "仅常用端口(绕过 P2P 流量)" msgid "Congestion control algorithm" msgstr "拥塞控制算法" -#: htdocs/luci-static/resources/view/homeproxy/status.js:191 +#: htdocs/luci-static/resources/view/homeproxy/status.js:184 msgid "Connection check" msgstr "连接检查" @@ -476,7 +476,7 @@ msgstr "默认服务器名称" msgid "Direct" msgstr "直连" -#: htdocs/luci-static/resources/view/homeproxy/client.js:1303 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1307 msgid "Direct Domain List" msgstr "直连域名列表" @@ -758,8 +758,8 @@ msgstr "加密方式" #: htdocs/luci-static/resources/view/homeproxy/client.js:1150 #: htdocs/luci-static/resources/view/homeproxy/client.js:1155 #: htdocs/luci-static/resources/view/homeproxy/client.js:1158 -#: htdocs/luci-static/resources/view/homeproxy/client.js:1296 -#: htdocs/luci-static/resources/view/homeproxy/client.js:1325 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1300 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1333 #: htdocs/luci-static/resources/view/homeproxy/node.js:452 #: htdocs/luci-static/resources/view/homeproxy/node.js:1087 #: htdocs/luci-static/resources/view/homeproxy/node.js:1260 @@ -812,7 +812,7 @@ msgstr "格式" msgid "GET" msgstr "GET" -#: htdocs/luci-static/resources/view/homeproxy/status.js:216 +#: htdocs/luci-static/resources/view/homeproxy/status.js:209 msgid "GFW list version" msgstr "GFW 域名列表版本" @@ -870,7 +870,7 @@ msgstr "全局代理 MAC 地址" msgid "Global settings" msgstr "全局设置" -#: htdocs/luci-static/resources/view/homeproxy/status.js:197 +#: htdocs/luci-static/resources/view/homeproxy/status.js:190 msgid "Google" msgstr "谷歌" @@ -918,7 +918,7 @@ msgstr "心跳间隔" #: htdocs/luci-static/resources/view/homeproxy/client.js:55 #: htdocs/luci-static/resources/view/homeproxy/client.js:57 #: htdocs/luci-static/resources/view/homeproxy/client.js:120 -#: htdocs/luci-static/resources/view/homeproxy/status.js:224 +#: htdocs/luci-static/resources/view/homeproxy/status.js:217 #: root/usr/share/luci/menu.d/luci-app-homeproxy.json:3 msgid "HomeProxy" msgstr "HomeProxy" @@ -1814,7 +1814,7 @@ msgstr "保留字段字节" msgid "Resolve strategy" msgstr "解析策略" -#: htdocs/luci-static/resources/view/homeproxy/status.js:201 +#: htdocs/luci-static/resources/view/homeproxy/status.js:194 msgid "Resources management" msgstr "资源管理" @@ -2720,11 +2720,11 @@ msgstr "私钥" msgid "quic-go / uquic chrome" msgstr "quic-go / uquic chrome" -#: htdocs/luci-static/resources/view/homeproxy/status.js:227 +#: htdocs/luci-static/resources/view/homeproxy/status.js:220 msgid "sing-box client" msgstr "sing-box 客户端" -#: htdocs/luci-static/resources/view/homeproxy/status.js:230 +#: htdocs/luci-static/resources/view/homeproxy/status.js:223 msgid "sing-box server" msgstr "sing-box 服务端" @@ -2790,8 +2790,8 @@ msgstr "有效网址" msgid "valid base64 key with %d characters" msgstr "包含 %d 个字符的有效 base64 密钥" -#: htdocs/luci-static/resources/view/homeproxy/client.js:1296 -#: htdocs/luci-static/resources/view/homeproxy/client.js:1325 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1300 +#: htdocs/luci-static/resources/view/homeproxy/client.js:1333 msgid "valid hostname" msgstr "有效主机名" diff --git a/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc b/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc index 74e880897..162a5779c 100755 --- a/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc +++ b/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc @@ -13,8 +13,8 @@ import { connect } from 'ubus'; import { cursor } from 'uci'; import { - executeCommand, isEmpty, strToBool, strToInt, - removeBlankAttrs, validateHostname, validation, + isEmpty, strToBool, strToInt, + removeBlankAttrs, validation, HP_DIR, RUN_DIR } from 'homeproxy'; @@ -373,20 +373,15 @@ config.dns = { if (!isEmpty(main_node)) { /* Main DNS */ - let default_final_dns = 'default-dns'; - if (dns_server !== wan_dns) { - push(config.dns.servers, { - tag: 'main-dns', - address: !match(dns_server, /:\/\//) ? 'tcp://' + (validation('ip6addr', dns_server) ? `[${dns_server}]` : dns_server) : dns_server, - strategy: (ipv6_support !== '1') ? 'ipv4_only' : null, - address_resolver: 'default-dns', - address_strategy: (ipv6_support !== '1') ? 'ipv4_only' : null, - detour: 'main-out' - }); - - default_final_dns = 'main-dns'; - } - config.dns.final = default_final_dns; + push(config.dns.servers, { + tag: 'main-dns', + address: !match(dns_server, /:\/\//) ? 'tcp://' + (validation('ip6addr', dns_server) ? `[${dns_server}]` : dns_server) : dns_server, + strategy: (ipv6_support !== '1') ? 'ipv4_only' : null, + address_resolver: 'default-dns', + address_strategy: (ipv6_support !== '1') ? 'ipv4_only' : null, + detour: 'main-out' + }); + config.dns.final = 'main-dns'; /* Avoid DNS loop */ push(config.dns.rules, { @@ -394,16 +389,16 @@ if (!isEmpty(main_node)) { server: 'default-dns' }); - if (direct_domain_list) + if (length(direct_domain_list)) push(config.dns.rules, { - domain_keyword: direct_domain_list, - server: 'default-dns' + rule_set: 'direct-domain', + server: (routing_mode === 'bypass_mainland_china' ) ? 'china-dns' : 'default-dns' }); /* Filter out SVCB/HTTPS queries for "exquisite" Apple devices */ - if (routing_mode === 'gfwlist' || proxy_domain_list) + if (routing_mode === 'gfwlist' || length(proxy_domain_list)) push(config.dns.rules, { - domain_keyword: (routing_mode !== 'gfwlist') ? proxy_domain_list : null, + rule_set: (routing_mode !== 'gfwlist') ? 'proxy-domain' : null, query_type: [64, 65], server: 'block-dns' }); @@ -415,10 +410,10 @@ if (!isEmpty(main_node)) { detour: 'direct-out' }); - if (proxy_domain_list) + if (length(proxy_domain_list)) push(config.dns.rules, { - domain_keyword: proxy_domain_list, - server: default_final_dns + rule_set: 'proxy-domain', + server: 'main-dns' }); push(config.dns.rules, { @@ -440,6 +435,7 @@ if (!isEmpty(main_node)) { server: 'china-dns' }); } + } else if (!isEmpty(default_outbound)) { /* DNS servers */ uci.foreach(uciconfig, ucidnsserver, (cfg) => { @@ -590,11 +586,13 @@ config.outbounds = [ if (!isEmpty(main_node)) { const main_node_cfg = uci.get_all(uciconfig, main_node) || {}; push(config.outbounds, generate_outbound(main_node_cfg)); + config.outbounds[length(config.outbounds)-1].domain_strategy = (ipv6_support !== '1') ? 'prefer_ipv4' : null; config.outbounds[length(config.outbounds)-1].tag = 'main-out'; if (dedicated_udp_node) { const main_udp_node_cfg = uci.get_all(uciconfig, main_udp_node) || {}; push(config.outbounds, generate_outbound(main_udp_node_cfg)); + config.outbounds[length(config.outbounds)-1].domain_strategy = (ipv6_support !== '1') ? 'prefer_ipv4' : null; config.outbounds[length(config.outbounds)-1].tag = 'main-udp-out'; } } else if (!isEmpty(default_outbound)) { @@ -651,7 +649,7 @@ if (!isEmpty(main_node)) { /* Direct list */ if (length(direct_domain_list)) push(config.route.rules, { - domain_keyword: direct_domain_list, + rule_set: 'direct-domain', outbound: 'direct-out' }); @@ -665,6 +663,30 @@ if (!isEmpty(main_node)) { config.route.final = 'main-out'; /* Rule set */ + /* Direct list */ + if (length(direct_domain_list)) + push(config.route.rule_set, { + type: 'inline', + tag: 'direct-domain', + rules: [ + { + domain_keyword: direct_domain_list, + } + ] + }); + + /* Proxy list */ + if (length(proxy_domain_list)) + push(config.route.rule_set, { + type: 'inline', + tag: 'proxy-domain', + rules: [ + { + domain_keyword: proxy_domain_list, + } + ] + }); + if (routing_mode === 'bypass_mainland_china') { push(config.route.rule_set, { type: 'remote', @@ -688,6 +710,9 @@ if (!isEmpty(main_node)) { download_detour: 'main-out' }); } + + if (isEmpty(config.route.rule_set)) + config.route.rule_set = null; } else if (!isEmpty(default_outbound)) { uci.foreach(uciconfig, uciroutingrule, (cfg) => { if (cfg.enabled !== '1') diff --git a/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_server.uc b/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_server.uc index bd4fdcd33..0432bb26d 100755 --- a/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_server.uc +++ b/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_server.uc @@ -7,13 +7,12 @@ 'use strict'; -import { readfile, writefile } from 'fs'; +import { writefile } from 'fs'; import { cursor } from 'uci'; import { - executeCommand, isEmpty, strToBool, strToInt, - removeBlankAttrs, validateHostname, validation, - HP_DIR, RUN_DIR + isEmpty, strToBool, strToInt, + removeBlankAttrs, HP_DIR, RUN_DIR } from 'homeproxy'; /* UCI config start */ diff --git a/luci-app-homeproxy/root/etc/homeproxy/scripts/homeproxy.uc b/luci-app-homeproxy/root/etc/homeproxy/scripts/homeproxy.uc index 5623ab0dd..3f7cb2bc3 100644 --- a/luci-app-homeproxy/root/etc/homeproxy/scripts/homeproxy.uc +++ b/luci-app-homeproxy/root/etc/homeproxy/scripts/homeproxy.uc @@ -5,7 +5,7 @@ */ import { mkstemp } from 'fs'; -import { urldecode, urldecode_params } from 'luci.http'; +import { urldecode_params } from 'luci.http'; /* Global variables start */ export const HP_DIR = '/etc/homeproxy'; diff --git a/luci-app-homeproxy/root/etc/homeproxy/scripts/update_subscriptions.uc b/luci-app-homeproxy/root/etc/homeproxy/scripts/update_subscriptions.uc index 0dfbf1fac..b10dc5edd 100755 --- a/luci-app-homeproxy/root/etc/homeproxy/scripts/update_subscriptions.uc +++ b/luci-app-homeproxy/root/etc/homeproxy/scripts/update_subscriptions.uc @@ -11,11 +11,11 @@ import { open } from 'fs'; import { connect } from 'ubus'; import { cursor } from 'uci'; -import { urldecode, urlencode, urldecode_params } from 'luci.http'; +import { urldecode, urlencode } from 'luci.http'; import { init_action } from 'luci.sys'; import { - calcStringMD5, wGET, executeCommand, decodeBase64Str, + calcStringMD5, wGET, decodeBase64Str, getTime, isEmpty, parseURL, validation, HP_DIR, RUN_DIR } from 'homeproxy'; diff --git a/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy b/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy index 10a96896e..6605a96b4 100644 --- a/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy +++ b/luci-app-homeproxy/root/usr/share/rpcd/ucode/luci.homeproxy @@ -7,7 +7,7 @@ 'use strict'; -import { access, error, lstat, mkstemp, popen, readfile, writefile } from 'fs'; +import { access, error, lstat, popen, readfile, writefile } from 'fs'; /* Kanged from ucode/luci */ function shellquote(s) {