mirror of
https://github.com/alireza0/x-ui.git
synced 2026-08-28 04:15:05 +00:00
[feat] tls and fragment options for extProxy
This commit is contained in:
parent
c4b20273dd
commit
d0784f8ccc
6 changed files with 416 additions and 36 deletions
|
|
@ -182,6 +182,7 @@ func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client,
|
|||
inbound.Listen = extPrxy["dest"].(string)
|
||||
inbound.Port = int(extPrxy["port"].(float64))
|
||||
newStream := stream
|
||||
var newOutbounds []json_util.RawMessage
|
||||
switch extPrxy["forceTls"].(string) {
|
||||
case "tls":
|
||||
if newStream["security"] != "tls" {
|
||||
|
|
@ -194,9 +195,37 @@ func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client,
|
|||
delete(newStream, "tlsSettings")
|
||||
}
|
||||
}
|
||||
streamSettings, _ := json.MarshalIndent(newStream, "", " ")
|
||||
if newStream["security"] != "none" {
|
||||
newTlsSettings := newStream["tlsSettings"].(map[string]interface{})
|
||||
if utlsValue, ok := extPrxy["utls"].(string); ok && len(utlsValue) > 0 {
|
||||
newTlsSettings["fingerprint"] = utlsValue
|
||||
}
|
||||
if sniValue, ok := extPrxy["sni"].(string); ok && len(sniValue) > 0 {
|
||||
newTlsSettings["serverName"] = sniValue
|
||||
}
|
||||
if alpnValue, ok := extPrxy["alpn"].([]interface{}); ok && len(alpnValue) > 0 {
|
||||
newTlsSettings["alpn"] = alpnValue
|
||||
}
|
||||
if allowInsecureValue, ok := extPrxy["allowInsecure"].(bool); ok && allowInsecureValue {
|
||||
newTlsSettings["allowInsecure"] = "1"
|
||||
}
|
||||
newStream["tlsSettings"] = newTlsSettings
|
||||
}
|
||||
|
||||
var newOutbounds []json_util.RawMessage
|
||||
if fragmentValue, ok := extPrxy["fragment"].(map[string]interface{}); ok {
|
||||
newTag := "freedom_out_" + extPrxy["remark"].(string) + "_" + random.Seq(10)
|
||||
newOutboundFreedom := map[string]interface{}{
|
||||
"protocol": "freedom",
|
||||
"settings": map[string]interface{}{
|
||||
"fragment": fragmentValue,
|
||||
},
|
||||
"tag": newTag,
|
||||
}
|
||||
newOutboundFreedomJson, _ := json.MarshalIndent(newOutboundFreedom, "", " ")
|
||||
newOutbounds = append(newOutbounds, newOutboundFreedomJson)
|
||||
newStream["sockopt"] = json_util.RawMessage(fmt.Sprintf(`{"dialerProxy": "%s"}`, newTag))
|
||||
}
|
||||
streamSettings, _ := json.MarshalIndent(newStream, "", " ")
|
||||
|
||||
switch inbound.Protocol {
|
||||
case "vmess":
|
||||
|
|
|
|||
|
|
@ -295,6 +295,27 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
|||
if newSecurity != "same" {
|
||||
newObj["tls"] = newSecurity
|
||||
}
|
||||
if utlsValue, ok := ep["utls"].(string); ok && len(utlsValue) > 0 {
|
||||
newObj["fp"] = utlsValue
|
||||
}
|
||||
if sniValue, ok := ep["sni"].(string); ok && len(sniValue) > 0 {
|
||||
newObj["sni"] = sniValue
|
||||
}
|
||||
if alpnValue, ok := ep["alpn"].([]interface{}); ok && len(alpnValue) > 0 {
|
||||
alpn := make([]string, len(alpnValue))
|
||||
for i, a := range alpnValue {
|
||||
alpn[i] = a.(string)
|
||||
}
|
||||
newObj["alpn"] = strings.Join(alpn, ",")
|
||||
}
|
||||
if allowInsecureValue, ok := ep["allowInsecure"].(bool); ok && allowInsecureValue {
|
||||
newObj["allowInsecure"] = "1"
|
||||
}
|
||||
if fragmentValue, ok := ep["fragment"].(map[string]interface{}); ok {
|
||||
newObj["packets"], _ = fragmentValue["packets"].(string)
|
||||
newObj["length"], _ = fragmentValue["length"].(string)
|
||||
newObj["interval"], _ = fragmentValue["interval"].(string)
|
||||
}
|
||||
if index > 0 {
|
||||
links += "\n"
|
||||
}
|
||||
|
|
@ -481,6 +502,27 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
|
|||
newSecurity, _ := ep["forceTls"].(string)
|
||||
dest, _ := ep["dest"].(string)
|
||||
port := int(ep["port"].(float64))
|
||||
if utlsValue, ok := ep["utls"].(string); ok && len(utlsValue) > 0 {
|
||||
params["fp"] = utlsValue
|
||||
}
|
||||
if sniValue, ok := ep["sni"].(string); ok && len(sniValue) > 0 {
|
||||
params["sni"] = sniValue
|
||||
}
|
||||
if alpnValue, ok := ep["alpn"].([]interface{}); ok && len(alpnValue) > 0 {
|
||||
alpn := make([]string, len(alpnValue))
|
||||
for i, a := range alpnValue {
|
||||
alpn[i] = a.(string)
|
||||
}
|
||||
params["alpn"] = strings.Join(alpn, ",")
|
||||
}
|
||||
if allowInsecureValue, ok := ep["allowInsecure"].(bool); ok && allowInsecureValue {
|
||||
params["allowInsecure"] = "1"
|
||||
}
|
||||
if fragmentValue, ok := ep["fragment"].(map[string]interface{}); ok {
|
||||
params["packets"] = fragmentValue["packets"].(string)
|
||||
params["length"] = fragmentValue["length"].(string)
|
||||
params["interval"] = fragmentValue["interval"].(string)
|
||||
}
|
||||
link := fmt.Sprintf("vless://%s@%s:%d", uuid, dest, port)
|
||||
|
||||
if newSecurity != "same" {
|
||||
|
|
@ -682,6 +724,27 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
|||
newSecurity, _ := ep["forceTls"].(string)
|
||||
dest, _ := ep["dest"].(string)
|
||||
port := int(ep["port"].(float64))
|
||||
if utlsValue, ok := ep["utls"].(string); ok && len(utlsValue) > 0 {
|
||||
params["fp"] = utlsValue
|
||||
}
|
||||
if sniValue, ok := ep["sni"].(string); ok && len(sniValue) > 0 {
|
||||
params["sni"] = sniValue
|
||||
}
|
||||
if alpnValue, ok := ep["alpn"].([]interface{}); ok && len(alpnValue) > 0 {
|
||||
alpn := make([]string, len(alpnValue))
|
||||
for i, a := range alpnValue {
|
||||
alpn[i] = a.(string)
|
||||
}
|
||||
params["alpn"] = strings.Join(alpn, ",")
|
||||
}
|
||||
if allowInsecureValue, ok := ep["allowInsecure"].(bool); ok && allowInsecureValue {
|
||||
params["allowInsecure"] = "1"
|
||||
}
|
||||
if fragmentValue, ok := ep["fragment"].(map[string]interface{}); ok {
|
||||
params["packets"] = fragmentValue["packets"].(string)
|
||||
params["length"] = fragmentValue["length"].(string)
|
||||
params["interval"] = fragmentValue["interval"].(string)
|
||||
}
|
||||
link := fmt.Sprintf("trojan://%s@%s:%d", password, dest, port)
|
||||
|
||||
if newSecurity != "same" {
|
||||
|
|
@ -859,6 +922,27 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
|
|||
newSecurity, _ := ep["forceTls"].(string)
|
||||
dest, _ := ep["dest"].(string)
|
||||
port := int(ep["port"].(float64))
|
||||
if utlsValue, ok := ep["utls"].(string); ok && len(utlsValue) > 0 {
|
||||
params["fp"] = utlsValue
|
||||
}
|
||||
if sniValue, ok := ep["sni"].(string); ok && len(sniValue) > 0 {
|
||||
params["sni"] = sniValue
|
||||
}
|
||||
if alpnValue, ok := ep["alpn"].([]interface{}); ok && len(alpnValue) > 0 {
|
||||
alpn := make([]string, len(alpnValue))
|
||||
for i, a := range alpnValue {
|
||||
alpn[i] = a.(string)
|
||||
}
|
||||
params["alpn"] = strings.Join(alpn, ",")
|
||||
}
|
||||
if allowInsecureValue, ok := ep["allowInsecure"].(bool); ok && allowInsecureValue {
|
||||
params["allowInsecure"] = "1"
|
||||
}
|
||||
if fragmentValue, ok := ep["fragment"].(map[string]interface{}); ok {
|
||||
params["packets"] = fragmentValue["packets"].(string)
|
||||
params["length"] = fragmentValue["length"].(string)
|
||||
params["interval"] = fragmentValue["interval"].(string)
|
||||
}
|
||||
link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), dest, port)
|
||||
|
||||
if newSecurity != "same" {
|
||||
|
|
@ -956,6 +1040,57 @@ func (s *SubService) genHysteriaLink(inbound *model.Inbound, email string) strin
|
|||
protocol = "hysteria"
|
||||
}
|
||||
|
||||
externalProxies, _ := stream["externalProxy"].([]interface{})
|
||||
|
||||
if len(externalProxies) > 0 {
|
||||
links := ""
|
||||
for index, externalProxy := range externalProxies {
|
||||
ep, _ := externalProxy.(map[string]interface{})
|
||||
newSecurity, _ := ep["forceTls"].(string)
|
||||
dest, _ := ep["dest"].(string)
|
||||
port := int(ep["port"].(float64))
|
||||
if utlsValue, ok := ep["utls"].(string); ok && len(utlsValue) > 0 {
|
||||
params["fp"] = utlsValue
|
||||
}
|
||||
if sniValue, ok := ep["sni"].(string); ok && len(sniValue) > 0 {
|
||||
params["sni"] = sniValue
|
||||
}
|
||||
if alpnValue, ok := ep["alpn"].([]interface{}); ok && len(alpnValue) > 0 {
|
||||
alpn := make([]string, len(alpnValue))
|
||||
for i, a := range alpnValue {
|
||||
alpn[i] = a.(string)
|
||||
}
|
||||
params["alpn"] = strings.Join(alpn, ",")
|
||||
}
|
||||
if allowInsecureValue, ok := ep["allowInsecure"].(bool); ok && allowInsecureValue {
|
||||
params["allowInsecure"] = "1"
|
||||
}
|
||||
if fragmentValue, ok := ep["fragment"].(map[string]interface{}); ok {
|
||||
params["packets"] = fragmentValue["packets"].(string)
|
||||
params["length"] = fragmentValue["length"].(string)
|
||||
params["interval"] = fragmentValue["interval"].(string)
|
||||
}
|
||||
link := fmt.Sprintf("%s://%s@%s:%d", protocol, auth, dest, port)
|
||||
if newSecurity != "same" {
|
||||
params["security"] = newSecurity
|
||||
} else {
|
||||
params["security"] = "tls"
|
||||
}
|
||||
url, _ := url.Parse(link)
|
||||
q := url.Query()
|
||||
for k, v := range params {
|
||||
q.Add(k, v)
|
||||
}
|
||||
url.RawQuery = q.Encode()
|
||||
url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
|
||||
if index > 0 {
|
||||
links += "\n"
|
||||
}
|
||||
links += url.String()
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
link := fmt.Sprintf("%s://%s@%s:%d", protocol, auth, address, port)
|
||||
url, _ := url.Parse(link)
|
||||
q := url.Query()
|
||||
|
|
|
|||
|
|
@ -250,6 +250,10 @@ style attribute {
|
|||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.ant-select-selection--multiple {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.drawer-handle {
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -1417,6 +1417,66 @@ class FinalMaskStreamSettings extends XrayCommonClass {
|
|||
}
|
||||
}
|
||||
|
||||
class ExternalProxy extends XrayCommonClass {
|
||||
constructor(
|
||||
forceTls = 'same',
|
||||
dest = '',
|
||||
port = 443,
|
||||
remark = '',
|
||||
fragment = undefined,
|
||||
utls = '',
|
||||
sni = '',
|
||||
alpn = [],
|
||||
allowInsecure = false,
|
||||
) {
|
||||
super();
|
||||
this.forceTls = forceTls;
|
||||
this.dest = dest;
|
||||
this.port = port;
|
||||
this.remark = remark;
|
||||
this.fragment = fragment;
|
||||
this.utls = utls;
|
||||
this.sni = sni;
|
||||
this.alpn = alpn;
|
||||
this.allowInsecure = allowInsecure;
|
||||
}
|
||||
|
||||
get hasFragment() {
|
||||
return this.fragment !== undefined;
|
||||
}
|
||||
|
||||
set hasFragment(value) {
|
||||
this.fragment = value ? {packets: 'tlshello', length: '100-200', interval: '10-20'} : undefined;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
return new ExternalProxy(
|
||||
json.forceTls,
|
||||
json.dest,
|
||||
json.port,
|
||||
json.remark,
|
||||
json.fragment,
|
||||
json.utls,
|
||||
json.sni,
|
||||
json.alpn,
|
||||
json.allowInsecure,
|
||||
);
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
forceTls: this.forceTls,
|
||||
dest: this.dest,
|
||||
port: this.port,
|
||||
remark: this.remark,
|
||||
fragment: this.hasFragment ? this.fragment : undefined,
|
||||
utls: this.utls,
|
||||
sni: this.sni,
|
||||
alpn: this.alpn,
|
||||
allowInsecure: this.allowInsecure,
|
||||
};
|
||||
}
|
||||
}
|
||||
class StreamSettings extends XrayCommonClass {
|
||||
constructor(network = 'tcp',
|
||||
security = 'none',
|
||||
|
|
@ -1513,7 +1573,7 @@ class StreamSettings extends XrayCommonClass {
|
|||
return new StreamSettings(
|
||||
json.network,
|
||||
json.security,
|
||||
json.externalProxy,
|
||||
json.externalProxy ? json.externalProxy.map(ep => ExternalProxy.fromJson(ep)) : [],
|
||||
TlsStreamSettings.fromJson(json.tlsSettings),
|
||||
RealityStreamSettings.fromJson(json.realitySettings),
|
||||
TcpStreamSettings.fromJson(json.tcpSettings),
|
||||
|
|
@ -1533,7 +1593,7 @@ class StreamSettings extends XrayCommonClass {
|
|||
return {
|
||||
network: network,
|
||||
security: this.security,
|
||||
externalProxy: this.externalProxy,
|
||||
externalProxy: this.externalProxy.map(ep => ep.toJson()),
|
||||
tlsSettings: this.isTls ? this.tls.toJson() : undefined,
|
||||
realitySettings: this.isReality ? this.reality.toJson() : undefined,
|
||||
tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
|
||||
|
|
@ -1796,11 +1856,11 @@ class Inbound extends XrayCommonClass {
|
|||
this.sniffing = new Sniffing();
|
||||
}
|
||||
|
||||
genVmessLink(address = '', port = this.port, forceTls, remark = '', clientId, security) {
|
||||
genVmessLink(address = '', port = this.port, extProxy, remark = '', clientId, security) {
|
||||
if (this.protocol !== Protocols.VMESS) {
|
||||
return '';
|
||||
}
|
||||
const tls = forceTls == 'same' ? this.stream.security : forceTls;
|
||||
const tls = extProxy.forceTls == 'same' ? this.stream.security : extProxy.forceTls;
|
||||
let obj = {
|
||||
v: '2',
|
||||
ps: remark,
|
||||
|
|
@ -1861,13 +1921,33 @@ class Inbound extends XrayCommonClass {
|
|||
}
|
||||
}
|
||||
|
||||
if (extProxy) {
|
||||
if (!ObjectUtil.isEmpty(extProxy.sni)) {
|
||||
obj.sni = extProxy.sni;
|
||||
}
|
||||
if (!ObjectUtil.isEmpty(extProxy.utls)) {
|
||||
obj.fp = extProxy.utls;
|
||||
}
|
||||
if (!ObjectUtil.isArrEmpty(extProxy.alpn)) {
|
||||
obj.alpn = extProxy.alpn.join(',');
|
||||
}
|
||||
if (extProxy.allowInsecure === 'true') {
|
||||
obj.allowInsecure = true;
|
||||
}
|
||||
if (extProxy.fragment) {
|
||||
obj.packets = extProxy.fragment.packets;
|
||||
obj.length = extProxy.fragment.length;
|
||||
obj.interval = extProxy.fragment.interval;
|
||||
}
|
||||
}
|
||||
|
||||
return 'vmess://' + Base64.encode(JSON.stringify(obj, null, 2));
|
||||
}
|
||||
|
||||
genVLESSLink(address = '', port = this.port, forceTls, remark = '', clientId, flow) {
|
||||
genVLESSLink(address = '', port = this.port, extProxy, remark = '', clientId, flow) {
|
||||
const uuid = clientId;
|
||||
const type = this.stream.network;
|
||||
const security = forceTls == 'same' ? this.stream.security : forceTls;
|
||||
const security = extProxy.forceTls == 'same' ? this.stream.security : extProxy.forceTls;
|
||||
const params = new Map();
|
||||
params.set("type", this.stream.network);
|
||||
params.set("encryption", this.settings.encryption);
|
||||
|
|
@ -1961,6 +2041,26 @@ class Inbound extends XrayCommonClass {
|
|||
params.set("security", "none");
|
||||
}
|
||||
|
||||
if (extProxy) {
|
||||
if (extProxy.sni?.length > 0) {
|
||||
params.set("sni", extProxy.sni);
|
||||
}
|
||||
if (extProxy.alpn?.length > 0) {
|
||||
params.set("alpn", extProxy.alpn.join(','));
|
||||
}
|
||||
if (extProxy.allowInsecure === 'true') {
|
||||
params.set("allowInsecure", "1");
|
||||
}
|
||||
if (extProxy.utls?.length > 0) {
|
||||
params.set("fp", extProxy.utls);
|
||||
}
|
||||
if (extProxy.fragment) {
|
||||
params.set("packets", extProxy.fragment.packets);
|
||||
params.set("length", extProxy.fragment.length);
|
||||
params.set("interval", extProxy.fragment.interval);
|
||||
}
|
||||
}
|
||||
|
||||
const link = `vless://${uuid}@${address}:${port}`;
|
||||
const url = new URL(link);
|
||||
for (const [key, value] of params) {
|
||||
|
|
@ -1970,10 +2070,10 @@ class Inbound extends XrayCommonClass {
|
|||
return url.toString();
|
||||
}
|
||||
|
||||
genSSLink(address = '', port = this.port, forceTls, remark = '', clientPassword) {
|
||||
genSSLink(address = '', port = this.port, extProxy, remark = '', clientPassword) {
|
||||
let settings = this.settings;
|
||||
const type = this.stream.network;
|
||||
const security = forceTls == 'same' ? this.stream.security : forceTls;
|
||||
const security = extProxy.forceTls == 'same' ? this.stream.security : extProxy.forceTls;
|
||||
const params = new Map();
|
||||
params.set("type", this.stream.network);
|
||||
switch (type) {
|
||||
|
|
@ -2038,6 +2138,26 @@ class Inbound extends XrayCommonClass {
|
|||
}
|
||||
}
|
||||
|
||||
if (extProxy) {
|
||||
if (extProxy.sni?.length > 0) {
|
||||
params.set("sni", extProxy.sni);
|
||||
}
|
||||
if (extProxy.alpn?.length > 0) {
|
||||
params.set("alpn", extProxy.alpn.join(','));
|
||||
}
|
||||
if (extProxy.allowInsecure === 'true') {
|
||||
params.set("allowInsecure", "1");
|
||||
}
|
||||
if (extProxy.utls?.length > 0) {
|
||||
params.set("fp", extProxy.utls);
|
||||
}
|
||||
if (extProxy.fragment) {
|
||||
params.set("packets", extProxy.fragment.packets);
|
||||
params.set("length", extProxy.fragment.length);
|
||||
params.set("interval", extProxy.fragment.interval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let password = new Array();
|
||||
if (this.isSS2022) password.push(settings.password);
|
||||
|
|
@ -2052,8 +2172,8 @@ class Inbound extends XrayCommonClass {
|
|||
return url.toString();
|
||||
}
|
||||
|
||||
genTrojanLink(address = '', port = this.port, forceTls, remark = '', clientPassword) {
|
||||
const security = forceTls == 'same' ? this.stream.security : forceTls;
|
||||
genTrojanLink(address = '', port = this.port, extProxy, remark = '', clientPassword) {
|
||||
const security = extProxy.forceTls == 'same' ? this.stream.security : extProxy.forceTls;
|
||||
const type = this.stream.network;
|
||||
const params = new Map();
|
||||
params.set("type", this.stream.network);
|
||||
|
|
@ -2141,6 +2261,25 @@ class Inbound extends XrayCommonClass {
|
|||
params.set("security", "none");
|
||||
}
|
||||
|
||||
if (extProxy) {
|
||||
if (extProxy.sni?.length > 0) {
|
||||
params.set("sni", extProxy.sni);
|
||||
}
|
||||
if (extProxy.alpn?.length > 0) {
|
||||
params.set("alpn", extProxy.alpn.join(','));
|
||||
}
|
||||
if (extProxy.allowInsecure === 'true') {
|
||||
params.set("allowInsecure", "1");
|
||||
}
|
||||
if (extProxy.utls?.length > 0) {
|
||||
params.set("fp", extProxy.utls);
|
||||
}
|
||||
if (extProxy.fragment) {
|
||||
params.set("packets", extProxy.fragment.packets);
|
||||
params.set("length", extProxy.fragment.length);
|
||||
params.set("interval", extProxy.fragment.interval);
|
||||
}
|
||||
}
|
||||
const link = `trojan://${clientPassword}@${address}:${port}`;
|
||||
const url = new URL(link);
|
||||
for (const [key, value] of params) {
|
||||
|
|
@ -2150,7 +2289,7 @@ class Inbound extends XrayCommonClass {
|
|||
return url.toString();
|
||||
}
|
||||
|
||||
genHysteriaLink(address = '', port = this.port, remark = '', clientAuth) {
|
||||
genHysteriaLink(address = '', port = this.port, extProxy, remark = '', clientAuth) {
|
||||
const protocol = this.settings.version == 2 ? "hysteria2" : "hysteria";
|
||||
const link = `${protocol}://${clientAuth}@${address}:${port}`;
|
||||
|
||||
|
|
@ -2162,6 +2301,25 @@ class Inbound extends XrayCommonClass {
|
|||
if (this.stream.tls.settings.echConfigList?.length > 0) params.set("ech", this.stream.tls.settings.echConfigList.join(','));
|
||||
if (this.stream.tls.sni?.length > 0) params.set("sni", this.stream.tls.sni);
|
||||
|
||||
if (extProxy) {
|
||||
if (extProxy.sni?.length > 0) {
|
||||
params.set("sni", extProxy.sni);
|
||||
}
|
||||
if (extProxy.alpn?.length > 0) {
|
||||
params.set("alpn", extProxy.alpn.join(','));
|
||||
}
|
||||
if (extProxy.allowInsecure === 'true') {
|
||||
params.set("insecure", "1");
|
||||
}
|
||||
if (extProxy.utls?.length > 0) {
|
||||
params.set("fp", extProxy.utls);
|
||||
}
|
||||
if (extProxy.fragment) {
|
||||
params.set("packets", extProxy.fragment.packets);
|
||||
params.set("length", extProxy.fragment.length);
|
||||
params.set("interval", extProxy.fragment.interval);
|
||||
}
|
||||
}
|
||||
const url = new URL(link);
|
||||
for (const [key, value] of params) {
|
||||
url.searchParams.set(key, value);
|
||||
|
|
@ -2192,18 +2350,19 @@ class Inbound extends XrayCommonClass {
|
|||
return txt;
|
||||
}
|
||||
|
||||
genLink(address = '', port = this.port, forceTls = 'same', remark = '', client) {
|
||||
genLink(address = '', port = this.port, extProxy = new ExternalProxy('same'), remark = '', client) {
|
||||
console.log(extProxy);
|
||||
switch (this.protocol) {
|
||||
case Protocols.VMESS:
|
||||
return this.genVmessLink(address, port, forceTls, remark, client.id, client.security);
|
||||
return this.genVmessLink(address, port, extProxy, remark, client.id, client.security);
|
||||
case Protocols.VLESS:
|
||||
return this.genVLESSLink(address, port, forceTls, remark, client.id, client.flow);
|
||||
return this.genVLESSLink(address, port, extProxy, remark, client.id, client.flow);
|
||||
case Protocols.SHADOWSOCKS:
|
||||
return this.genSSLink(address, port, forceTls, remark, this.isSSMultiUser ? client.password : '');
|
||||
return this.genSSLink(address, port, extProxy, remark, this.isSSMultiUser ? client.password : '');
|
||||
case Protocols.TROJAN:
|
||||
return this.genTrojanLink(address, port, forceTls, remark, client.password);
|
||||
return this.genTrojanLink(address, port, extProxy, remark, client.password);
|
||||
case Protocols.HYSTERIA:
|
||||
return this.genHysteriaLink(address, port, remark, client.auth.length > 0 ? client.auth : this.stream.hysteria.auth);
|
||||
return this.genHysteriaLink(address, port, remark, extProxy, client.auth.length > 0 ? client.auth : this.stream.hysteria.auth);
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
|
|
@ -2224,7 +2383,7 @@ class Inbound extends XrayCommonClass {
|
|||
let r = orderChars.split('').map(char => orders[char]).filter(x => x.length > 0).join(separationChar);
|
||||
result.push({
|
||||
remark: r,
|
||||
link: this.genLink(addr, port, 'same', r, client)
|
||||
link: this.genLink(addr, port, new ExternalProxy('same'), r, client)
|
||||
});
|
||||
} else {
|
||||
this.stream.externalProxy.forEach((ep) => {
|
||||
|
|
@ -2232,7 +2391,7 @@ class Inbound extends XrayCommonClass {
|
|||
let r = orderChars.split('').map(char => orders[char]).filter(x => x.length > 0).join(separationChar);
|
||||
result.push({
|
||||
remark: r,
|
||||
link: this.genLink(ep.dest, ep.port, ep.forceTls, r, client)
|
||||
link: this.genLink(ep.dest, ep.port, ep, r, client)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,77 @@
|
|||
{{define "form/externalProxy"}}
|
||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item label='{{ i18n "pages.inbounds.stream.common.externalProxy" }}'>
|
||||
<a-button type="primary" style="margin-left: 10px" size="small" @click="inbound.stream.externalProxy.push({forceTls: 'same', dest: '', port: 443, remark: ''})">+</a-button>
|
||||
<a-button type="primary" style="margin-left: 10px" size="small"
|
||||
@click="inbound.stream.externalProxy.push(new ExternalProxy('same', location.hostname, inbound.port))">+</a-button>
|
||||
</a-form-item>
|
||||
<a-input-group style="margin: 5px 0;" compact v-for="(row, index) in inbound.stream.externalProxy">
|
||||
<template>
|
||||
<a-tooltip title="Force TLS">
|
||||
<a-select v-model="row.forceTls" style="width:20%; margin: 0px" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<template style="margin: 5px 0;" compact v-for="(row, index) in inbound.stream.externalProxy">
|
||||
<a-divider :style="{ margin: '0' }">[[ index + 1 ]]
|
||||
<a-icon type="delete"
|
||||
@click="() => inbound.stream.externalProxy.splice(index, 1)"
|
||||
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }">
|
||||
</a-icon>
|
||||
</a-divider>
|
||||
<a-input-group compact style="margin-bottom: 10px;">
|
||||
<a-tooltip title="{{ i18n "security" }}">
|
||||
<a-select v-model="row.forceTls" style="width:20%; margin: 0px" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value="same">{{ i18n "pages.inbounds.same" }}</a-select-option>
|
||||
<a-select-option value="none">{{ i18n "none" }}</a-select-option>
|
||||
<a-select-option value="tls">TLS</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input style="width: 35%; border-radius: 0;" v-model.trim="row.dest" placeholder='{{ i18n "host" }}'></a-input>
|
||||
<a-tooltip title='{{ i18n "pages.inbounds.port" }}'>
|
||||
<a-input-number style="width: 15%;" v-model.number="row.port" min="1" max="65535"></a-input-number>
|
||||
</a-tooltip>
|
||||
<a-input style="width: 20%; border-radius: 0;" v-model.trim="row.remark" placeholder='{{ i18n "remark" }}'></a-input>
|
||||
<a-button style="width: 10%; margin: 0px" @click="inbound.stream.externalProxy.splice(index, 1)">-</a-button>
|
||||
</a-input-group>
|
||||
<a-tooltip title="{{ i18n "host" }}">
|
||||
<a-input v-model.trim="row.dest" style="width: 35%; border-radius: 0;" placeholder='{{ i18n "host" }}'></a-input>
|
||||
</a-tooltip>
|
||||
<a-tooltip title="{{ i18n "pages.inbounds.port" }}">
|
||||
<a-input-number v-model.number="row.port" style="width: 15%;" min="1" max="65535"></a-input-number>
|
||||
</a-tooltip>
|
||||
<a-tooltip title="{{ i18n "pages.inbounds.remark" }}">
|
||||
<a-input v-model.trim="row.remark" style="width: 30%;" placeholder='{{ i18n "pages.inbounds.remark" }}'></a-input>
|
||||
</a-tooltip>
|
||||
</a-input-group>
|
||||
<a-input-group compact v-if="row.forceTls === 'tls' || (row.forceTls === 'same' && inbound.stream.isTls)" style="margin-bottom: 10px;">
|
||||
<a-tooltip title='{{ i18n "pages.inbounds.stream.tls.uTLS" }}'>
|
||||
<a-select v-model="row.utls"
|
||||
style="width: 20%;"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value=''>None</a-select-option>
|
||||
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
<a-tooltip title='{{ i18n "pages.inbounds.stream.tls.sniDesc" }}'>
|
||||
<a-input v-model.trim="row.sni" style="width: 35%; border-radius: 0;" placeholder='{{ i18n "pages.inbounds.stream.tls.sni" }}'></a-input>
|
||||
</a-tooltip>
|
||||
<a-tooltip title='{{ i18n "pages.inbounds.stream.tls.alpn" }}'>
|
||||
<a-select mode="multiple" :dropdown-class-name="themeSwitcher.currentTheme"
|
||||
v-model="row.alpn" style="width: 30%;">
|
||||
<a-select-option v-for="alpn in ALPN_OPTION" :value="alpn">[[ alpn ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
<a-tooltip title='{{ i18n "pages.inbounds.stream.tls.allowInsecure" }}'>
|
||||
<a-select v-model="row.allowInsecure" style="width: 15%;"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value=''>False</a-select-option>
|
||||
<a-select-option value='true'>True</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-input-group>
|
||||
<a-input-group compact style="margin-bottom: 10px;">
|
||||
<a-tooltip title="{{ i18n "pages.xray.outbound.freedom.fragment" }}">
|
||||
<a-checkbox v-model="row.hasFragment" style="width: 10%; height: 32px;">{{ i18n "pages.xray.outbound.freedom.fragment" }}</a-checkbox>
|
||||
</a-tooltip>
|
||||
<!-- Fragment -->
|
||||
<template v-if="row.fragment !== undefined">
|
||||
<a-tooltip title='{{ i18n "pages.xray.outbound.freedom.packets" }}'>
|
||||
<a-input v-model.trim="row.fragment.packets" placeholder="tlshello" style="width: 30%; border-radius: 1rem 0 0 1rem;" />
|
||||
</a-tooltip>
|
||||
<a-tooltip title='{{ i18n "pages.xray.outbound.freedom.length" }}'>
|
||||
<a-input v-model.trim="row.fragment.length" placeholder="100-200" style="width: 30%; border-radius: 0;" />
|
||||
</a-tooltip>
|
||||
<a-tooltip title='{{ i18n "pages.inbounds.stream.finalmask.delay" }}'>
|
||||
<a-input v-model.trim="row.fragment.interval" placeholder="10-20" style="width: 30%; border-radius: 0 1rem 1rem 0;" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input-group>
|
||||
</template>
|
||||
</a-form>
|
||||
{{end}}
|
||||
|
|
@ -398,8 +398,8 @@
|
|||
[pages.xray.outbound.freedom]
|
||||
"strategy" = "استراتژی"
|
||||
"redirect" = "تغییر مسیر"
|
||||
"fragment" = "Fragment"
|
||||
"packets" = "Packets"
|
||||
"fragment" = "فرگمنت"
|
||||
"packets" = "بستهها"
|
||||
"length" = "طول"
|
||||
"interval" = "بازه"
|
||||
"noises" = "نویزها"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue