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