update 2023-03-17 23:37:01

This commit is contained in:
github-actions[bot] 2023-03-17 23:37:01 +08:00
parent 4b29bcffc4
commit bf0101179b
8 changed files with 930 additions and 711 deletions

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-homeproxy
PKG_VERSION:=usertesting-0337
PKG_VERSION:=usertesting-0311
LUCI_TITLE:=The modern ImmortalWrt proxy platform for ARM64/AMD64
LUCI_PKGARCH:=all

View File

@ -293,6 +293,7 @@ return view.extend({
var 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];
m = new form.Map('homeproxy', _('Edit nodes'));
@ -334,7 +335,7 @@ return view.extend({
var packet_encoding = uci.get(data[0], 'subscription', 'packet_encoding');
var imported_node = 0;
input_links.forEach((l) => {
var config = parseShareLink(l, data[1]);
var config = parseShareLink(l, features);
if (config) {
if (config.tls === '1' && allow_insecure === '1')
config.tls_insecure = '1'
@ -428,15 +429,15 @@ return view.extend({
so = ss.option(form.ListValue, 'type', _('Type'));
so.value('direct', _('Direct'));
so.value('http', _('HTTP'));
if (data[1].with_quic)
if (features.with_quic)
so.value('hysteria', _('Hysteria'));
so.value('shadowsocks', _('Shadowsocks'));
if (data[1].with_shadowsocksr)
if (features.with_shadowsocksr)
so.value('shadowsocksr', _('ShadowsocksR'));
so.value('shadowtls', _('ShadowTLS'));
so.value('socks', _('Socks'));
so.value('trojan', _('Trojan'));
if (data[1].with_wireguard)
if (features.with_wireguard)
so.value('wireguard', _('WireGuard'));
so.value('vless', _('VLESS'));
so.value('vmess', _('VMess'));
@ -751,14 +752,40 @@ return view.extend({
desc.innerHTML = _('No additional encryption support: It\'s basically duplicate encryption.');
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;
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 period of time after which a health check will be performed using a ping frame if no frames have been received on the connection.<br/>' +
'Please note that a ping response is considered a received frame, so if there is no other traffic on the connection, the health check will be executed every interval.');
this.map.findElement('id', 'cbid.homeproxy.%s.http_ping_timeout'.format(section_id)).nextElementSibling.innerHTML =
_('Specifies the timeout duration after sending a PING frame, within which a response must be received.<br/>' +
'If a response to the PING frame is not received within the specified timeout duration, the connection will be closed.');
} else if (value === 'grpc' && features.with_grpc) {
this.map.findElement('id', 'cbid.homeproxy.%s.http_idle_timeout'.format(section_id)).nextElementSibling.innerHTML =
_('If the transport doesn\'t see any activity after a duration of this time, it pings the client to check if the connection is still active.');
this.map.findElement('id', 'cbid.homeproxy.%s.http_ping_timeout'.format(section_id)).nextElementSibling.innerHTML =
_('The timeout that after performing a keepalive check, the client will wait for activity. If no activity is detected, the connection will be closed.');
}
}
so.modalonly = true;
/* gRPC config */
/* gRPC config start */
so = ss.option(form.Value, 'grpc_servicename', _('gRPC service name'));
so.depends('transport', 'grpc');
so.modalonly = true;
if (features.with_grpc) {
so = ss.option(form.Flag, 'grpc_permit_without_stream', _('gRPC permit without stream'),
_('If enabled, the client transport sends keepalive pings even with no active connections.'));
so.default = so.disabled;
so.depends('transport', 'grpc');
so.modalonly = true;
}
/* gRPC config end */
/* HTTP config start */
so = ss.option(form.DynamicList, 'http_host', _('Host'));
so.datatype = 'hostname';
@ -774,6 +801,22 @@ return view.extend({
so.value('put', _('PUT'));
so.depends('transport', 'http');
so.modalonly = true;
so = ss.option(form.Value, 'http_idle_timeout', _('Idle timeout'),
_('Specifies the period of time after which a health check will be performed using a ping frame if no frames have been received on the connection.<br/>' +
'Please note that a ping response is considered a received frame, so if there is no other traffic on the connection, the health check will be executed every interval.'));
so.datatype = 'uinteger';
so.depends('transport', 'grpc');
so.depends({'transport': 'http', 'tls': '1'});
so.modalonly = true;
so = ss.option(form.Value, 'http_ping_timeout', _('Ping timeout'),
_('Specifies the timeout duration after sending a PING frame, within which a response must be received.<br/>' +
'If a response to the PING frame is not received within the specified timeout duration, the connection will be closed.'));
so.datatype = 'uinteger';
so.depends('transport', 'grpc');
so.depends({'transport': 'http', 'tls': '1'});
so.modalonly = true;
/* HTTP config end */
/* WebSocket config start */
@ -960,7 +1003,7 @@ return view.extend({
so.onclick = L.bind(hp.uploadCertificate, this, _('certificate'), 'client_ca');
so.modalonly = true;
if (data[1].with_ech) {
if (features.with_ech) {
so = ss.option(form.Flag, 'tls_ech', _('Enable ECH'),
_('ECH (Encrypted Client Hello) is a TLS extension that allows a client to encrypt the first part of its ClientHello message.'));
so.depends('tls', '1');
@ -982,7 +1025,7 @@ return view.extend({
so.modalonly = true;
}
if (data[1].with_utls) {
if (features.with_utls) {
so = ss.option(form.ListValue, 'tls_utls', _('uTLS fingerprint'),
_('uTLS is a fork of "crypto/tls", which provides ClientHello fingerprinting resistance.'));
so.value('', _('Disable'));
@ -997,6 +1040,15 @@ return view.extend({
so.value('randomized', _('Randomized'));
so.value('safari', _('Safari'));
so.depends('tls', '1');
so.validate = function(section_id, value) {
if (section_id) {
let tls_reality = this.map.lookupOption('tls_reality', section_id)[0].formvalue(section_id);
if (tls_reality && !value)
return _('Expecting: %s').format(_('non-empty value'));
}
return true;
}
so.modalonly = true;
so = ss.option(form.Flag, 'tls_reality', _('REALITY'));

View File

@ -21,6 +21,7 @@ return view.extend({
render: function(data) {
var m, s, o;
var features = data[1];
m = new form.Map('homeproxy', _('Edit servers'));
@ -54,7 +55,7 @@ return view.extend({
o = s.option(form.ListValue, 'type', _('Type'));
o.value('http', _('HTTP'));
if (data[1].with_quic) {
if (features.with_quic) {
o.value('hysteria', _('Hysteria'));
o.value('naive', _('NaïveProxy'));
}
@ -231,17 +232,27 @@ return view.extend({
desc.innerHTML = _('No additional encryption support: It\'s basically duplicate encryption.');
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;
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 until idle clients should be closed with a GOAWAY frame. PING frames are not considered as activity.');
else if (value === 'grpc' && features.with_grpc)
this.map.findElement('id', 'cbid.homeproxy.%s.http_idle_timeout'.format(section_id)).nextElementSibling.innerHTML =
_('If the transport doesn\'t see any activity after a duration of this time, it pings the client to check if the connection is still active.');
}
o.depends('type', 'trojan');
o.depends('type', 'vless');
o.depends('type', 'vmess');
o.modalonly = true;
/* gRPC config */
/* gRPC config start */
o = s.option(form.Value, 'grpc_servicename', _('gRPC service name'));
o.depends('transport', 'grpc');
o.modalonly = true;
/* gRPC config end */
/* HTTP config start */
o = s.option(form.DynamicList, 'http_host', _('Host'));
o.datatype = 'hostname';
@ -255,6 +266,21 @@ return view.extend({
o = s.option(form.Value, 'http_method', _('Method'));
o.depends('transport', 'http');
o.modalonly = true;
o = s.option(form.Value, 'http_idle_timeout', _('Idle timeout'),
_('Specifies the time until idle clients should be closed with a GOAWAY frame. PING frames are not considered as activity.'));
o.datatype = 'uinteger';
o.depends('transport', 'grpc');
o.depends({'transport': 'http', 'tls': '1'});
o.modalonly = true;
if (features.with_grpc) {
o = s.option(form.Value, 'http_ping_timeout', _('Ping timeout'),
_('The timeout that after performing a keepalive check, the client will wait for activity. If no activity is detected, the connection will be closed.'));
o.datatype = 'uinteger';
o.depends('transport', 'grpc');
o.modalonly = true;
}
/* HTTP config end */
/* WebSocket config start */
@ -330,7 +356,7 @@ return view.extend({
o.optional = true;
o.modalonly = true;
if (data[1].with_acme) {
if (features.with_acme) {
o = s.option(form.Flag, 'tls_acme', _('Enable ACME'),
_('Use ACME TLS certificate issuer.'));
o.default = o.disabled;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,11 @@
import { readfile, writefile } from 'fs';
import { cursor } from 'uci';
import { executeCommand, isEmpty, strToInt, removeBlankAttrs, validateHostname, validation } from 'homeproxy';
import { HP_DIR, RUN_DIR } from 'homeproxy';
import {
executeCommand, isEmpty, strToInt,
removeBlankAttrs, validateHostname, validation,
HP_DIR, RUN_DIR
} from 'homeproxy';
/* UCI config start */
const uci = cursor();
@ -215,7 +218,10 @@ function generate_outbound(node) {
method: node.http_method,
max_early_data: strToInt(node.websocket_early_data),
early_data_header_name: node.websocket_early_data_header,
service_name: node.grpc_servicename
service_name: node.grpc_servicename,
idle_timeout: node.http_idle_timeout ? (node.http_idle_timeout + 's') : null,
ping_timeout: node.http_ping_timeout ? (node.http_ping_timeout + 's') : null,
permit_without_stream: (node.grpc_permit_without_stream === '1') || null
} : null,
udp_over_tcp: (node.udp_over_tcp === '1') || null,
tcp_fast_open: (node.tcp_fast_open === '1') || null,
@ -325,7 +331,7 @@ if (!isEmpty(main_node)) {
if (dns_server !== wan_dns) {
push(config.dns.servers, {
tag: 'main-dns',
address: 'tcp://' + ((validation('ip6addr', dns_server) === 0) ? `[${dns_server}]` : dns_server),
address: 'tcp://' + (validation('ip6addr', dns_server) ? `[${dns_server}]` : dns_server),
strategy: (ipv6_support !== '1') ? 'ipv4_only' : null,
detour: 'main-out'
});
@ -524,7 +530,9 @@ if (server_enabled === '1')
method: cfg.http_method,
max_early_data: strToInt(cfg.websocket_early_data),
early_data_header_name: cfg.websocket_early_data_header,
service_name: cfg.grpc_servicename
service_name: cfg.grpc_servicename,
idle_timeout: cfg.http_idle_timeout ? (cfg.http_idle_timeout + 's') : null,
ping_timeout: cfg.http_ping_timeout ? (cfg.http_ping_timeout + 's') : null
} : null
});
});

View File

@ -114,7 +114,7 @@ export function validation(datatype, data) {
return null;
const ret = system(`/sbin/validate_data ${shellQuote(datatype)} ${shellQuote(data)} 2>/dev/null`);
return ret;
return (ret === 0);
};
/* String helper end */
@ -174,9 +174,9 @@ export function parseURL(url) {
return '';
});
if (validation('ip4addr', val) === 0 ||
validation('ip6addr', replace(val, /\[|\]/g, '')) === 0 ||
validation('hostname', val) === 0)
if (validation('ip4addr', val) ||
validation('ip6addr', replace(val, /\[|\]/g, '')) ||
validation('hostname', val))
objurl.hostname = val;
return '';

View File

@ -360,11 +360,11 @@ function parse_uri(uri) {
if (config.address)
config.address = replace(config.address, /\[|\]/g, '');
if (validation('host', config.address) !== 0 || validation('port', config.port) !== 0) {
if (!validation('host', config.address) || !validation('port', config.port)) {
log(sprintf('Skipping invalid %s node: %s.', config.type, config.label || 'NULL'));
return null;
} else if (!config.label)
config.label = (validation('ip6addr', config.address) === 0 ?
config.label = (validation('ip6addr', config.address) ?
`[${config.address}]` : config.address) + ':' + config.port;
}