🌴 Sync 2026-07-14 04:31:14

This commit is contained in:
github-actions[bot] committed 2026-07-14 04:31:14 +08:00
1 parent e652a38f70
commit fd29dc0037
47 files changed
+926 -789

No files matched your search

@@ -164,7 +164,7 @@ const inbound_type = [
['anytls', _('AnyTLS') + ' - ' + _('TCP')],
['tuic', _('TUIC') + ' - ' + _('UDP')],
['hysteria2', _('Hysteria2') + ' - ' + _('UDP')],
['hysteria2-realm', _('Hysteria2 Realm') + ' - ' + _('TCP/UDP')],
['hysteria2-realm', _('Hysteria2 Realm Server') + ' - ' + _('TCP/UDP')],
['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')],
['tunnel', _('Tunnel') + ' - ' + _('TCP/UDP')]
];
@@ -198,12 +198,12 @@ const outbound_type = [
['vless', _('VLESS') + ' - ' + _('TCP')],
['trojan', _('Trojan') + ' - ' + _('TCP')],
['anytls', _('AnyTLS') + ' - ' + _('TCP')],
['tuic', _('TUIC') + ' - ' + _('UDP')],
//['hysteria', _('Hysteria') + ' - ' + _('UDP')],
['hysteria2', _('Hysteria2') + ' - ' + _('UDP')],
['tuic', _('TUIC') + ' - ' + _('UDP')],
['masque', _('Masque') + ' - ' + _('UDP')], // https://blog.cloudflare.com/post-quantum-warp/
['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')],
['wireguard', _('WireGuard') + ' - ' + _('UDP')],
['masque', _('Masque') + ' - ' + _('UDP')], // https://blog.cloudflare.com/post-quantum-warp/
['ssh', _('SSH') + ' - ' + _('TCP')]
];
@@ -171,86 +171,6 @@ function renderListeners(s, uciconfig, isClient) {
o.depends({type: /^(tuic)$/, uuid: /.+/});
o.modalonly = true;
/* Hysteria2 fields */
o = s.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'),
_('In Mbps.'));
o.datatype = 'uinteger';
o.depends('type', 'hysteria2');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'),
_('In Mbps.'));
o.datatype = 'uinteger';
o.depends('type', 'hysteria2');
o.modalonly = true;
o = s.taboption('field_general', form.Flag, 'hysteria_ignore_client_bandwidth', _('Ignore client bandwidth'),
_('Tell the client to use the BBR flow control algorithm instead of Hysteria CC.'));
o.default = o.disabled;
o.depends({type: 'hysteria2', hysteria_up_mbps: '', hysteria_down_mbps: ''});
o.modalonly = true;
o = s.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type'));
o.value('', _('Disable'));
o.value('salamander', _('Salamander'));
o.value('gecko', _('Gecko'));
o.depends('type', 'hysteria2');
o.modalonly = true;
o = s.taboption('field_general', hm.GenValue, 'hysteria_obfs_password', _('Obfuscate password'),
_('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.'));
o.password = true;
o.rmempty = false;
o.depends('type', 'hysteria');
o.depends({type: 'hysteria2', hysteria_obfs_type: /.+/});
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size'));
o.placeholder = '512'
o.depends('hysteria_obfs_type', 'gecko');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size'));
o.placeholder = '1200'
o.depends('hysteria_obfs_type', 'gecko');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_masquerade', _('Masquerade'),
_('HTTP3 server behavior when authentication fails.<br/>A 404 page will be returned if empty.'));
o.placeholder = 'file:///var/www or http://127.0.0.1:8080'
o.depends('type', 'hysteria2');
o.modalonly = true;
/* Hysteria2 Realmserver fields */
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_token', _('Pre-shared key'));
o.placeholder = 'public';
o.rmempty = false;
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms', _('Max realms'));
o.datatype = 'uinteger';
o.placeholder = '65536';
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms_per_ip', _('Max realms per client IP'));
o.datatype = 'uinteger';
o.placeholder = '4';
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_trusted_proxy_header', _('Trusted proxy header'),
_('Header to read real client IP from (e.g. X-Forwarded-For)'));
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_realm_name_pattern', _('Realm name pattern'));
o.default = '^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$';
o.rmempty = false;
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
/* Shadowsocks fields */
o = s.taboption('field_general', form.ListValue, 'shadowsocks_chipher', _('Chipher'));
o.default = hm.shadowsocks_cipher_methods[1][0];
@@ -470,31 +390,26 @@ function renderListeners(s, uciconfig, isClient) {
o.depends('type', 'snell');
o.modalonly = true;
/* Tuic fields */
o = s.taboption('field_general', hm.GenValue, 'uuid', _('UUID'));
/* VMess / VLESS fields */
o = s.taboption('field_general', hm.GenValue, 'vmess_uuid', _('UUID'));
o.rmempty = false;
o.validate = hm.validateUUID;
o.depends('type', 'tuic');
o.depends({type: /^(vmess|vless)$/});
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'tuic_max_udp_relay_packet_size', _('Max UDP relay packet size'));
o = s.taboption('field_general', form.ListValue, 'vless_flow', _('Flow'));
o.default = hm.vless_flow[0][0];
hm.vless_flow.forEach((res) => {
o.value.apply(o, res);
})
o.depends('type', 'vless');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID'),
_('Legacy protocol support (VMess MD5 Authentication) is provided for compatibility purposes only, use of alterId > 1 is not recommended.'));
o.datatype = 'uinteger';
o.default = '1500';
o.depends('type', 'tuic');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'tuic_max_idle_time', _('Idle timeout'),
_('In seconds.'));
o.default = '15000';
o.validate = hm.validateTimeDuration;
o.depends('type', 'tuic');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'tuic_authentication_timeout', _('Auth timeout'),
_('In seconds.'));
o.default = '1000';
o.validate = hm.validateTimeDuration;
o.depends('type', 'tuic');
o.placeholder = '0';
o.depends('type', 'vmess');
o.modalonly = true;
/* Trojan fields */
@@ -525,26 +440,111 @@ function renderListeners(s, uciconfig, isClient) {
o.depends('type', 'anytls');
o.modalonly = true;
/* VMess / VLESS fields */
o = s.taboption('field_general', hm.GenValue, 'vmess_uuid', _('UUID'));
/* Tuic fields */
o = s.taboption('field_general', hm.GenValue, 'uuid', _('UUID'));
o.rmempty = false;
o.validate = hm.validateUUID;
o.depends({type: /^(vmess|vless)$/});
o.depends('type', 'tuic');
o.modalonly = true;
o = s.taboption('field_general', form.ListValue, 'vless_flow', _('Flow'));
o.default = hm.vless_flow[0][0];
hm.vless_flow.forEach((res) => {
o.value.apply(o, res);
})
o.depends('type', 'vless');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID'),
_('Legacy protocol support (VMess MD5 Authentication) is provided for compatibility purposes only, use of alterId > 1 is not recommended.'));
o = s.taboption('field_general', form.Value, 'tuic_max_udp_relay_packet_size', _('Max UDP relay packet size'));
o.datatype = 'uinteger';
o.placeholder = '0';
o.depends('type', 'vmess');
o.default = '1500';
o.depends('type', 'tuic');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'tuic_max_idle_time', _('Idle timeout'),
_('In seconds.'));
o.default = '15000';
o.validate = hm.validateTimeDuration;
o.depends('type', 'tuic');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'tuic_authentication_timeout', _('Auth timeout'),
_('In seconds.'));
o.default = '1000';
o.validate = hm.validateTimeDuration;
o.depends('type', 'tuic');
o.modalonly = true;
/* Hysteria2 fields */
o = s.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'),
_('In Mbps.'));
o.datatype = 'uinteger';
o.depends('type', 'hysteria2');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'),
_('In Mbps.'));
o.datatype = 'uinteger';
o.depends('type', 'hysteria2');
o.modalonly = true;
o = s.taboption('field_general', form.Flag, 'hysteria_ignore_client_bandwidth', _('Ignore client bandwidth'),
_('Tell the client to use the BBR flow control algorithm instead of Hysteria CC.'));
o.default = o.disabled;
o.depends({type: 'hysteria2', hysteria_up_mbps: '', hysteria_down_mbps: ''});
o.modalonly = true;
o = s.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type'));
o.value('', _('Disable'));
o.value('salamander', _('Salamander'));
o.value('gecko', _('Gecko'));
o.depends('type', 'hysteria2');
o.modalonly = true;
o = s.taboption('field_general', hm.GenValue, 'hysteria_obfs_password', _('Obfuscate password'),
_('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.'));
o.password = true;
o.rmempty = false;
o.depends('type', 'hysteria');
o.depends({type: 'hysteria2', hysteria_obfs_type: /.+/});
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size'));
o.placeholder = '512'
o.depends('hysteria_obfs_type', 'gecko');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size'));
o.placeholder = '1200'
o.depends('hysteria_obfs_type', 'gecko');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria_masquerade', _('Masquerade'),
_('HTTP3 server behavior when authentication fails.<br/>A 404 page will be returned if empty.'));
o.placeholder = 'file:///var/www or http://127.0.0.1:8080'
o.depends('type', 'hysteria2');
o.modalonly = true;
/* Hysteria2 Realmserver fields */
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_token', _('Pre-shared key'));
o.placeholder = 'public';
o.rmempty = false;
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms', _('Max realms'));
o.datatype = 'uinteger';
o.placeholder = '65536';
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms_per_ip', _('Max realms per client IP'));
o.datatype = 'uinteger';
o.placeholder = '4';
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_trusted_proxy_header', _('Trusted proxy header'),
_('Header to read real client IP from (e.g. X-Forwarded-For)'));
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_realm_name_pattern', _('Realm name pattern'));
o.default = '^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$';
o.rmempty = false;
o.depends('type', 'hysteria2-realm');
o.modalonly = true;
/* TrustTunnel fields */
@@ -622,6 +622,7 @@ function renderListeners(s, uciconfig, isClient) {
if (isClient) {
o = s.taboption('field_general', form.Value, 'routing_mark', _('Routing mark (Fwmark)'));
o.datatype = 'uinteger';
o.modalonly = false;
o.editable = true;
o = s.taboption('field_general', hm.ListValue, 'rule', _('Sub rule'),
@@ -633,6 +634,7 @@ function renderListeners(s, uciconfig, isClient) {
...hm.loadLabelValues(this.config, 'subrule-group')
], section_id);
}
o.modalonly = false;
o.editable = true;
o = s.taboption('field_general', hm.ListValue, 'proxy', _('Proxy group'),
@@ -647,6 +649,7 @@ function renderListeners(s, uciconfig, isClient) {
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
}
o.modalonly = false;
o.editable = true;
}
@@ -947,8 +950,8 @@ function renderListeners(s, uciconfig, isClient) {
let def_alpn;
switch (type) {
case 'hysteria2':
case 'tuic':
case 'hysteria2':
def_alpn = ['h3'];
break;
case 'hysteria2-realm':
@@ -1032,7 +1035,7 @@ function renderListeners(s, uciconfig, isClient) {
hm.tls_client_auth_types.forEach((res) => {
o.value.apply(o, res);
})
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/});
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/});
o.modalonly = true;
o = s.taboption('field_tls', form.Value, 'tls_client_auth_cert_path', _('Client Auth Certificate path') + _(' (mTLS)'),
@@ -1041,7 +1044,7 @@ function renderListeners(s, uciconfig, isClient) {
o.validate = function(/* ... */) {
return hm.validateMTLSClientAuth.call(this, 'tls_client_auth_type', ...arguments);
}
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/});
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/});
o.modalonly = true;
o = s.taboption('field_tls', form.Button, '_upload_client_auth_cert', _('Upload certificate') + _(' (mTLS)'),
@@ -1090,13 +1093,13 @@ function renderListeners(s, uciconfig, isClient) {
return node;
}
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/});
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/});
o.modalonly = true;
o = s.taboption('field_tls', hm.CopyValue, 'tls_ech_config', _('ECH config'),
_('This ECH parameter needs to be added to the HTTPS record of the domain.'));
o.placeholder = 'AEn+DQBFKwAgACABWIHUGj4u+PIggYXcR5JF0gYk3dCRioBW8uJq9H4mKAAIAAEAAQABAANAEnB1YmxpYy50bHMtZWNoLmRldgAA';
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/});
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/});
o.modalonly = true;
// uTLS fields
@@ -1235,7 +1238,7 @@ function renderListeners(s, uciconfig, isClient) {
/* Multiplex fields */
o = s.taboption('field_general', form.Flag, 'smux_enabled', _('Multiplex'));
o.default = o.disabled;
o.depends({type: /^(shadowsocks|vmess|vless|trojan|tuic|hysteria2|sudoku)$/});
o.depends({type: /^(shadowsocks|sudoku|vmess|vless|trojan|tuic|hysteria2)$/});
o.modalonly = true;
o = s.taboption('field_multiplex', form.Flag, 'smux_padding', _('Enable padding'));
@@ -130,7 +130,7 @@ const parseProviderYaml = hm.parseYaml.extend({
override_prefix: this.jq(cfg, "override.additional-prefix"),
override_suffix: this.jq(cfg, "override.additional-suffix"),
override_replace: (this.jq(cfg, "override.proxy-name") || []).map((obj) => JSON.stringify(obj)), // array.string: array.object
// Configuration Items
// Other configuration items
override_tfo: this.bool2str(this.jq(cfg, "override.tfo")), // bool
override_mptcp: this.bool2str(this.jq(cfg, "override.mptcp")), // bool
override_udp: this.bool2str(this.jq(cfg, "override.udp")), // bool
@@ -306,7 +306,7 @@ return view.extend({
so = ss.taboption('field_general', form.Value, 'password', _('Password'));
so.password = true;
so.validate = hm.validateAuthPassword;
so.depends({type: /^(http|socks5|mieru|trojan|anytls|hysteria2|tuic|trusttunnel|ssh)$/});
so.depends({type: /^(http|socks5|mieru|trojan|anytls|tuic|hysteria2|trusttunnel|ssh)$/});
so.modalonly = true;
so = ss.taboption('field_general', hm.TextValue, 'headers', _('HTTP header'));
@@ -315,75 +315,6 @@ return view.extend({
so.depends('type', 'http');
so.modalonly = true;
/* Hysteria / Hysteria2 fields */
so = ss.taboption('field_general', form.DynamicList, 'hysteria_ports', _('Ports pool'));
so.datatype = 'or(port, portrange)';
so.depends({type: /^(hysteria|hysteria2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'hysteria_hop_interval', _('Port hop interval'),
_('In seconds. <code>%s</code> will be used if empty.').format('30'));
so.placeholder = '15 OR 15-30';
so.depends('type', 'hysteria2');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'),
_('In Mbps.'));
so.datatype = 'uinteger';
so.depends({type: /^(hysteria|hysteria2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'),
_('In Mbps.'));
so.datatype = 'uinteger';
so.depends({type: /^(hysteria|hysteria2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type'));
so.value('', _('Disable'));
so.value('salamander', _('Salamander'));
so.value('gecko', _('Gecko'));
so.depends('type', 'hysteria2');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'hysteria_obfs_password', _('Obfuscate password'),
_('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.'));
so.password = true;
so.rmempty = false;
so.depends('type', 'hysteria');
so.depends({type: 'hysteria2', hysteria_obfs_type: /.+/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size'));
so.placeholder = '512'
so.depends('hysteria_obfs_type', 'gecko');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size'));
so.placeholder = '1200'
so.depends('hysteria_obfs_type', 'gecko');
so.modalonly = true;
/* SSH fields */
so = ss.taboption('field_general', form.TextValue, 'ssh_priv_key', _('Priv-key'));
so.depends('type', 'ssh');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'ssh_priv_key_passphrase', _('Priv-key passphrase'));
so.password = true;
so.depends({type: 'ssh', ssh_priv_key: /.+/});
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key_algorithms', _('Host-key algorithms'));
so.placeholder = 'rsa';
so.depends('type', 'ssh');
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key', _('Host-key'));
so.placeholder = 'ssh-rsa AAAAB3NzaC1yc2EAA...';
so.depends({type: 'ssh', ssh_host_key_algorithms: /.+/});
so.modalonly = true;
/* Shadowsocks fields */
so = ss.taboption('field_general', form.ListValue, 'shadowsocks_chipher', _('Chipher'));
so.default = hm.shadowsocks_cipher_methods[1][0];
@@ -574,6 +505,100 @@ return view.extend({
so.depends({type: 'snell', snell_version: /^(4|5)$/});
so.modalonly = true;
/* VMess / VLESS fields */
so = ss.taboption('field_general', form.Value, 'vmess_uuid', _('UUID'));
so.rmempty = false;
so.validate = hm.validateUUID;
so.depends({type: /^(vmess|vless)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'vless_flow', _('Flow'));
so.default = hm.vless_flow[0][0];
hm.vless_flow.forEach((res) => {
so.value.apply(so, res);
})
so.depends('type', 'vless');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID'));
so.datatype = 'uinteger';
so.default = '0';
so.depends('type', 'vmess');
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'vmess_chipher', _('Chipher'));
so.default = 'auto';
so.value('auto', _('auto'));
so.value('none', _('none'));
so.value('zero', _('zero'));
so.value('aes-128-gcm', _('aes-128-gcm'));
so.value('chacha20-poly1305', _('chacha20-poly1305'));
so.depends('type', 'vmess');
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'vmess_global_padding', _('Global padding'),
_('Protocol parameter. Will waste traffic randomly if enabled (enabled by default in v2ray and cannot be disabled).'));
so.default = so.enabled;
so.depends('type', 'vmess');
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'vmess_authenticated_length', _('Authenticated length'),
_('Protocol parameter. Enable length block encryption.'));
so.default = so.disabled;
so.depends('type', 'vmess');
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'vmess_packet_encoding', _('Packet encoding'));
so.value('', _('none'));
so.value('packetaddr', _('packet addr (v2ray-core v5+)'));
so.value('xudp', _('Xudp (Xray-core)'));
so.depends({type: /^(vmess|vless)$/});
so.modalonly = true;
/* Trojan fields */
so = ss.taboption('field_general', form.Flag, 'trojan_ss_enabled', _('Shadowsocks encrypt'));
so.default = so.disabled;
so.depends('type', 'trojan');
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'trojan_ss_chipher', _('Shadowsocks chipher'));
so.default = hm.trojan_cipher_methods[0][0];
hm.trojan_cipher_methods.forEach((res) => {
so.value.apply(so, res);
})
so.depends({type: 'trojan', trojan_ss_enabled: '1'});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'trojan_ss_password', _('Shadowsocks password'));
so.password = true;
so.validate = function(section_id, value) {
const encmode = this.section.getOption('trojan_ss_chipher').formvalue(section_id);
return hm.validateShadowsocksPassword.call(this, encmode, section_id, value);
}
so.depends({type: 'trojan', trojan_ss_enabled: '1'});
so.modalonly = true;
/* AnyTLS fields */
so = ss.taboption('field_general', form.Value, 'anytls_idle_session_check_interval', _('Idle session check interval'),
_('In seconds.'));
so.placeholder = '30';
so.validate = hm.validateTimeDuration;
so.depends('type', 'anytls');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'anytls_idle_session_timeout', _('Idle session timeout'),
_('In seconds.'));
so.placeholder = '30';
so.validate = hm.validateTimeDuration;
so.depends('type', 'anytls');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'anytls_min_idle_session', _('Min of idle sessions to keep'));
so.datatype = 'uinteger';
so.placeholder = '0';
so.depends('type', 'anytls');
so.modalonly = true;
/* TUIC fields */
so = ss.taboption('field_general', form.Value, 'uuid', _('UUID'));
so.rmempty = false;
@@ -644,165 +669,53 @@ return view.extend({
so.depends('type', 'tuic');
so.modalonly = true;
/* Trojan fields */
so = ss.taboption('field_general', form.Flag, 'trojan_ss_enabled', _('Shadowsocks encrypt'));
so.default = so.disabled;
so.depends('type', 'trojan');
/* Hysteria / Hysteria2 fields */
so = ss.taboption('field_general', form.DynamicList, 'hysteria_ports', _('Ports pool'));
so.datatype = 'or(port, portrange)';
so.depends({type: /^(hysteria|hysteria2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'trojan_ss_chipher', _('Shadowsocks chipher'));
so.default = hm.trojan_cipher_methods[0][0];
hm.trojan_cipher_methods.forEach((res) => {
so.value.apply(so, res);
})
so.depends({type: 'trojan', trojan_ss_enabled: '1'});
so = ss.taboption('field_general', form.Value, 'hysteria_hop_interval', _('Port hop interval'),
_('In seconds. <code>%s</code> will be used if empty.').format('30'));
so.placeholder = '15 OR 15-30';
so.depends('type', 'hysteria2');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'trojan_ss_password', _('Shadowsocks password'));
so.password = true;
so.validate = function(section_id, value) {
const encmode = this.section.getOption('trojan_ss_chipher').formvalue(section_id);
return hm.validateShadowsocksPassword.call(this, encmode, section_id, value);
}
so.depends({type: 'trojan', trojan_ss_enabled: '1'});
so.modalonly = true;
/* AnyTLS fields */
so = ss.taboption('field_general', form.Value, 'anytls_idle_session_check_interval', _('Idle session check interval'),
_('In seconds.'));
so.placeholder = '30';
so.validate = hm.validateTimeDuration;
so.depends('type', 'anytls');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'anytls_idle_session_timeout', _('Idle session timeout'),
_('In seconds.'));
so.placeholder = '30';
so.validate = hm.validateTimeDuration;
so.depends('type', 'anytls');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'anytls_min_idle_session', _('Min of idle sessions to keep'));
so = ss.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'),
_('In Mbps.'));
so.datatype = 'uinteger';
so.placeholder = '0';
so.depends('type', 'anytls');
so.depends({type: /^(hysteria|hysteria2)$/});
so.modalonly = true;
/* VMess / VLESS fields */
so = ss.taboption('field_general', form.Value, 'vmess_uuid', _('UUID'));
so.rmempty = false;
so.validate = hm.validateUUID;
so.depends({type: /^(vmess|vless)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'vless_flow', _('Flow'));
so.default = hm.vless_flow[0][0];
hm.vless_flow.forEach((res) => {
so.value.apply(so, res);
})
so.depends('type', 'vless');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID'));
so = ss.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'),
_('In Mbps.'));
so.datatype = 'uinteger';
so.default = '0';
so.depends('type', 'vmess');
so.depends({type: /^(hysteria|hysteria2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'vmess_chipher', _('Chipher'));
so.default = 'auto';
so.value('auto', _('auto'));
so.value('none', _('none'));
so.value('zero', _('zero'));
so.value('aes-128-gcm', _('aes-128-gcm'));
so.value('chacha20-poly1305', _('chacha20-poly1305'));
so.depends('type', 'vmess');
so = ss.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type'));
so.value('', _('Disable'));
so.value('salamander', _('Salamander'));
so.value('gecko', _('Gecko'));
so.depends('type', 'hysteria2');
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'vmess_global_padding', _('Global padding'),
_('Protocol parameter. Will waste traffic randomly if enabled (enabled by default in v2ray and cannot be disabled).'));
so.default = so.enabled;
so.depends('type', 'vmess');
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'vmess_authenticated_length', _('Authenticated length'),
_('Protocol parameter. Enable length block encryption.'));
so.default = so.disabled;
so.depends('type', 'vmess');
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'vmess_packet_encoding', _('Packet encoding'));
so.value('', _('none'));
so.value('packetaddr', _('packet addr (v2ray-core v5+)'));
so.value('xudp', _('Xudp (Xray-core)'));
so.depends({type: /^(vmess|vless)$/});
so.modalonly = true;
/* Masque fields */
so = ss.taboption('field_general', form.Value, 'masque_private_key', _('Private key'),
_('Base64 encoded ECDSA private key on the NIST P-256 curve.'));
so = ss.taboption('field_general', form.Value, 'hysteria_obfs_password', _('Obfuscate password'),
_('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.'));
so.password = true;
so.validate = L.bind(hm.validateBase64Key, so, 164);
so.rmempty = false;
so.depends('type', 'masque');
so.depends('type', 'hysteria');
so.depends({type: 'hysteria2', hysteria_obfs_type: /.+/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_endpoint_public_key', _('Endpoint pubkic key'),
_('Base64 encoded ECDSA public key on the NIST P-256 curve.'));
so.validate = L.bind(hm.validateBase64Key, so, 124);
so.rmempty = false;
so.depends('type', 'masque');
so = ss.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size'));
so.placeholder = '512'
so.depends('hysteria_obfs_type', 'gecko');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_ip', _('Local address'),
_('The %s address used by local machine in the Cloudflare WARP network.').format('IPv4'));
so.datatype = 'ip4addr(1)';
so.placeholder = '172.16.0.2';
so.rmempty = false;
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_ipv6', _('Local IPv6 address'),
_('The %s address used by local machine in the Cloudflare WARP network.').format('IPv6'));
so.datatype = 'ip6addr(1)';
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_mtu', _('MTU'));
so.datatype = 'range(0,9000)';
so.placeholder = '1280';
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'masque_network', _('Network'));
so.default = '';
so.value('', _('h3'));
so.value('h3-l4proxy', _('h3-l4proxy'));
so.value('h2', _('h2'));
so.validate = function(section_id, value) {
const udp = this.section.getUIElement(section_id, 'udp').node.querySelector('input');
// Force disabled
if (value === 'h3-l4proxy') {
udp.checked = false;
udp.disabled = true;
} else
udp.removeAttribute('disabled');
return true;
}
so.depends('type', 'masque');
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'masque_remote_dns_resolve', _('Remote DNS resolve'),
_('Force DNS remote resolution.'));
so.default = so.disabled;
so.depends('type', 'masque');
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'masque_dns', _('DNS server'));
so.datatype = 'or(host, hostport)';
so.depends('masque_remote_dns_resolve', '1');
so = ss.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size'));
so.placeholder = '1200'
so.depends('hysteria_obfs_type', 'gecko');
so.modalonly = true;
/* TrustTunnel fields */
@@ -888,6 +801,93 @@ return view.extend({
so.depends('wireguard_remote_dns_resolve', '1');
so.modalonly = true;
/* Masque fields */
so = ss.taboption('field_general', form.Value, 'masque_private_key', _('Private key'),
_('Base64 encoded ECDSA private key on the NIST P-256 curve.'));
so.password = true;
so.validate = L.bind(hm.validateBase64Key, so, 164);
so.rmempty = false;
so.depends('type', 'masque');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_endpoint_public_key', _('Endpoint pubkic key'),
_('Base64 encoded ECDSA public key on the NIST P-256 curve.'));
so.validate = L.bind(hm.validateBase64Key, so, 124);
so.rmempty = false;
so.depends('type', 'masque');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_ip', _('Local address'),
_('The %s address used by local machine in the Cloudflare WARP network.').format('IPv4'));
so.datatype = 'ip4addr(1)';
so.placeholder = '172.16.0.2';
so.rmempty = false;
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_ipv6', _('Local IPv6 address'),
_('The %s address used by local machine in the Cloudflare WARP network.').format('IPv6'));
so.datatype = 'ip6addr(1)';
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_mtu', _('MTU'));
so.datatype = 'range(0,9000)';
so.placeholder = '1280';
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'masque_network', _('Network'));
so.default = '';
so.value('', _('h3'));
so.value('h3-l4proxy', _('h3-l4proxy'));
so.value('h2', _('h2'));
so.validate = function(section_id, value) {
const udp = this.section.getUIElement(section_id, 'udp').node.querySelector('input');
// Force disabled
if (value === 'h3-l4proxy') {
udp.checked = false;
udp.disabled = true;
} else
udp.removeAttribute('disabled');
return true;
}
so.depends('type', 'masque');
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'masque_remote_dns_resolve', _('Remote DNS resolve'),
_('Force DNS remote resolution.'));
so.default = so.disabled;
so.depends('type', 'masque');
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'masque_dns', _('DNS server'));
so.datatype = 'or(host, hostport)';
so.depends('masque_remote_dns_resolve', '1');
so.modalonly = true;
/* SSH fields */
so = ss.taboption('field_general', form.TextValue, 'ssh_priv_key', _('Priv-key'));
so.depends('type', 'ssh');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'ssh_priv_key_passphrase', _('Priv-key passphrase'));
so.password = true;
so.depends({type: 'ssh', ssh_priv_key: /.+/});
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key_algorithms', _('Host-key algorithms'));
so.placeholder = 'rsa';
so.depends('type', 'ssh');
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key', _('Host-key'));
so.placeholder = 'ssh-rsa AAAAB3NzaC1yc2EAA...';
so.depends({type: 'ssh', ssh_host_key_algorithms: /.+/});
so.modalonly = true;
/* Plugin fields */
so = ss.taboption('field_general', form.ListValue, 'plugin', _('Plugin'));
so.value('', _('none'));
@@ -975,12 +975,12 @@ return view.extend({
_('The default value is <code>%s</code>, indicating that only the outer connection timeout is used.').format('0'));
so.datatype = 'uinteger';
so.placeholder = '30';
so.depends({type: /^(masque|openvpn)$/});
so.depends({type: /^(openvpn|masque)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'udp', _('UDP'));
so.default = so.disabled;
so.depends({type: /^(rematch|direct|socks5|ss|mieru|vmess|vless|trojan|anytls|trusttunnel|masque|wireguard)$/});
so.depends({type: /^(rematch|direct|socks5|ss|mieru|vmess|vless|trojan|anytls|trusttunnel|wireguard|masque)$/});
so.depends({type: 'snell', snell_version: /^(3|4|5)$/});
so.modalonly = true;
@@ -1115,7 +1115,7 @@ return view.extend({
return true;
}
so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel|masque)$/});
so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel|masque)$/});
so.modalonly = true;
so = ss.taboption('field_tls', form.Flag, 'tls_disable_sni', _('Disable SNI'),
@@ -1146,9 +1146,9 @@ return view.extend({
case 'snell':
def_alpn = ['h2', 'http/1.1']; // when plugin === 'shadow-tls'
break;
case 'tuic':
case 'hysteria':
case 'hysteria2':
case 'tuic':
def_alpn = ['h3'];
break;
case 'vmess':
@@ -1171,7 +1171,7 @@ return view.extend({
return true;
}
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel)$/});
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel)$/});
so.depends({type: /^(ss|snell)$/, plugin: 'shadow-tls'});
so.modalonly = true;
@@ -1193,7 +1193,7 @@ return view.extend({
'<br/>' +
_('This is <strong>DANGEROUS</strong>, your traffic is almost like <strong>PLAIN TEXT</strong>! Use at your own risk!'));
so.default = so.disabled;
so.depends({tls: '1', type: /^(http|socks5|vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel)$/});
so.depends({tls: '1', type: /^(http|socks5|vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel)$/});
so.modalonly = true;
so = ss.taboption('field_tls', form.Value, 'tls_cert_path', _('Certificate path') + _(' (mTLS)'),
@@ -1226,7 +1226,7 @@ return view.extend({
so = ss.taboption('field_tls', form.Flag, 'tls_ech', _('Enable ECH'));
so.default = so.disabled;
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|hysteria|hysteria2|tuic)$/});
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|tuic|hysteria|hysteria2)$/});
so.depends({type: 'ss', plugin: /^(v2ray-plugin|gost-plugin)$/});
so.modalonly = true;
@@ -1899,7 +1899,7 @@ return view.extend({
so = ss.taboption('field_override', form.DummyValue, '_config_items', null);
so.load = function() {
return '<a target="_blank" href="%s" rel="noreferrer noopener">%s</a>'
.format('https://wiki.metacubex.one/config/proxy-providers/#_2', _('Configuration Items'));
.format('https://wiki.metacubex.one/config/proxy-providers/#override_1', _('Other configuration items'));
}
so.rawhtml = true;
so.depends({type: 'inline', '!reverse': true});