瀏覽代碼

new - vmess security (inbound client side - outbound)

mhsanaei 3 月之前
父節點
當前提交
93d52bc86c

+ 2 - 1
README.md

@@ -250,6 +250,7 @@ Our platform offers compatibility with a diverse range of architectures and devi
 - Spanish
 - Indonesian 
 - Ukrainian
+- Turkish
 
 
 ## Features
@@ -258,7 +259,7 @@ Our platform offers compatibility with a diverse range of architectures and devi
 - Search within all inbounds and clients
 - Dark/Light theme
 - Supports multi-user and multi-protocol
-- Supports protocols, including VMess, VLESS, Trojan, Shadowsocks, Dokodemo-door, Socks, HTTP, wireguard
+- Supports protocols, including VMESS, VLESS, Trojan, Shadowsocks, Dokodemo-door, Socks, HTTP, wireguard
 - Supports XTLS native Protocols, including RPRX-Direct, Vision, REALITY
 - Traffic statistics, traffic limit, expiration time limit
 - Customizable Xray configuration templates

+ 2 - 1
database/model/model.go

@@ -10,7 +10,7 @@ import (
 type Protocol string
 
 const (
-	VMess       Protocol = "vmess"
+	VMESS       Protocol = "vmess"
 	VLESS       Protocol = "vless"
 	DOKODEMO    Protocol = "dokodemo-door"
 	HTTP        Protocol = "http"
@@ -86,6 +86,7 @@ type Setting struct {
 
 type Client struct {
 	ID         string `json:"id"`
+	Security   string `json:"security"`
 	Password   string `json:"password"`
 	Flow       string `json:"flow"`
 	Email      string `json:"email"`

+ 3 - 3
go.mod

@@ -85,16 +85,16 @@ require (
 	go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
 	golang.org/x/arch v0.9.0 // indirect
 	golang.org/x/crypto v0.26.0 // indirect
-	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
+	golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
 	golang.org/x/mod v0.20.0 // indirect
 	golang.org/x/net v0.28.0 // indirect
 	golang.org/x/sync v0.8.0 // indirect
-	golang.org/x/sys v0.23.0 // indirect
+	golang.org/x/sys v0.24.0 // indirect
 	golang.org/x/time v0.6.0 // indirect
 	golang.org/x/tools v0.24.0 // indirect
 	golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20240805194559-2c9e96a0b5d4 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a // indirect
 	google.golang.org/protobuf v1.34.2 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect

+ 6 - 6
go.sum

@@ -299,8 +299,8 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
 golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -339,8 +339,8 @@ golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
-golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
@@ -371,8 +371,8 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
 google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
 google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240805194559-2c9e96a0b5d4 h1:OsSGQeIIsyOEOimVxLEIL4rwGcnrjOydQaiA2bOnZUM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240805194559-2c9e96a0b5d4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a h1:EKiZZXueP9/T68B8Nl0GAx9cjbQnCId0yP3qPMgaaHs=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
 google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=

+ 4 - 0
sub/subJsonService.go

@@ -282,6 +282,9 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_ut
 
 	usersData[0].ID = client.ID
 	usersData[0].Level = 8
+	if inbound.Protocol == model.VMESS {
+		usersData[0].Security = client.Security
+	}
 	if inbound.Protocol == model.VLESS {
 		usersData[0].Flow = client.Flow
 		usersData[0].Encryption = "none"
@@ -371,6 +374,7 @@ type UserVnext struct {
 	Encryption string `json:"encryption,omitempty"`
 	Flow       string `json:"flow,omitempty"`
 	ID         string `json:"id"`
+	Security   string `json:"security,omitempty"`
 	Level      int    `json:"level"`
 }
 

+ 2 - 1
sub/subService.go

@@ -168,7 +168,7 @@ func (s *SubService) getLink(inbound *model.Inbound, email string) string {
 }
 
 func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
-	if inbound.Protocol != model.VMess {
+	if inbound.Protocol != model.VMESS {
 		return ""
 	}
 	obj := map[string]interface{}{
@@ -281,6 +281,7 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
 		}
 	}
 	obj["id"] = clients[clientIndex].ID
+	obj["scy"] = clients[clientIndex].Security
 
 	externalProxies, _ := stream["externalProxy"].([]interface{})
 

+ 14 - 3
web/assets/js/model/outbound.js

@@ -69,6 +69,14 @@ const WireguardDomainStrategy = [
     "ForceIPv6v4"
 ];
 
+const USERS_SECURITY = {
+    AES_128_GCM: "aes-128-gcm",
+    CHACHA20_POLY1305: "chacha20-poly1305",
+    AUTO: "auto",
+    NONE: "none",
+    ZERO: "zero",
+};
+
 Object.freeze(Protocols);
 Object.freeze(SSMethods);
 Object.freeze(TLS_FLOW_CONTROL);
@@ -76,6 +84,7 @@ Object.freeze(UTLS_FINGERPRINT);
 Object.freeze(ALPN_OPTION);
 Object.freeze(OutboundDomainStrategies);
 Object.freeze(WireguardDomainStrategy);
+Object.freeze(USERS_SECURITY);
 
 
 class CommonClass {
@@ -721,7 +730,7 @@ class Outbound extends CommonClass {
 
         const port = json.port * 1;
 
-        return new Outbound(json.ps, Protocols.VMess, new Outbound.VmessSettings(json.add, port, json.id), stream);
+        return new Outbound(json.ps, Protocols.VMess, new Outbound.VmessSettings(json.add, port, json.id, json.scy), stream);
     }
 
     static fromParamLink(link) {
@@ -923,11 +932,12 @@ Outbound.DNSSettings = class extends CommonClass {
     }
 };
 Outbound.VmessSettings = class extends CommonClass {
-    constructor(address, port, id) {
+    constructor(address, port, id, security) {
         super();
         this.address = address;
         this.port = port;
         this.id = id;
+        this.security = security;
     }
 
     static fromJson(json = {}) {
@@ -936,6 +946,7 @@ Outbound.VmessSettings = class extends CommonClass {
             json.vnext[0].address,
             json.vnext[0].port,
             json.vnext[0].users[0].id,
+            json.vnext[0].users[0].security,
         );
     }
 
@@ -944,7 +955,7 @@ Outbound.VmessSettings = class extends CommonClass {
             vnext: [{
                 address: this.address,
                 port: this.port,
-                users: [{ id: this.id }],
+                users: [{ id: this.id, security: this.security }],
             }],
         };
     }

+ 55 - 18
web/assets/js/model/xray.js

@@ -110,6 +110,14 @@ const TCP_CONGESTION_OPTION = {
     RENO: "reno",
 };
 
+const USERS_SECURITY = {
+    AES_128_GCM: "aes-128-gcm",
+    CHACHA20_POLY1305: "chacha20-poly1305",
+    AUTO: "auto",
+    NONE: "none",
+    ZERO: "zero",
+};
+
 Object.freeze(Protocols);
 Object.freeze(SSMethods);
 Object.freeze(XTLS_FLOW_CONTROL);
@@ -122,6 +130,7 @@ Object.freeze(SNIFFING_OPTION);
 Object.freeze(USAGE_OPTION);
 Object.freeze(DOMAIN_STRATEGY_OPTION);
 Object.freeze(TCP_CONGESTION_OPTION);
+Object.freeze(USERS_SECURITY);
 
 class XrayCommonClass {
 
@@ -1446,20 +1455,21 @@ class Inbound extends XrayCommonClass {
         this.sniffing = new Sniffing();
     }
 
-    genVmessLink(address = '', port = this.port, forceTls, remark = '', clientId) {
+    genVmessLink(address = '', port = this.port, forceTls, remark = '', clientId, security) {
         if (this.protocol !== Protocols.VMESS) {
             return '';
         }
-        const security = forceTls == 'same' ? this.stream.security : forceTls;
+        const tls = forceTls == 'same' ? this.stream.security : forceTls;
         let obj = {
             v: '2',
             ps: remark,
             add: address,
             port: port,
             id: clientId,
+            scy: security,
             net: this.stream.network,
             type: 'none',
-            tls: security,
+            tls: tls,
         };
         const network = this.stream.network;
         if (network === 'tcp') {
@@ -1870,7 +1880,7 @@ class Inbound extends XrayCommonClass {
     genLink(address = '', port = this.port, forceTls = 'same', remark = '', client) {
         switch (this.protocol) {
             case Protocols.VMESS:
-                return this.genVmessLink(address, port, forceTls, remark, client.id);
+                return this.genVmessLink(address, port, forceTls, remark, client.id, client.security);
             case Protocols.VLESS:
                 return this.genVLESSLink(address, port, forceTls, remark, client.id, client.flow);
             case Protocols.SHADOWSOCKS:
@@ -2007,24 +2017,24 @@ Inbound.Settings = class extends XrayCommonClass {
 
 Inbound.VmessSettings = class extends Inbound.Settings {
     constructor(protocol,
-        vmesses = [new Inbound.VmessSettings.Vmess()]) {
+        vmesses = [new Inbound.VmessSettings.VMESS()]) {
         super(protocol);
         this.vmesses = vmesses;
     }
 
     indexOfVmessById(id) {
-        return this.vmesses.findIndex(vmess => vmess.id === id);
+        return this.vmesses.findIndex(VMESS => VMESS.id === id);
     }
 
-    addVmess(vmess) {
-        if (this.indexOfVmessById(vmess.id) >= 0) {
+    addVmess(VMESS) {
+        if (this.indexOfVmessById(VMESS.id) >= 0) {
             return false;
         }
-        this.vmesses.push(vmess);
+        this.vmesses.push(VMESS);
     }
 
-    delVmess(vmess) {
-        const i = this.indexOfVmessById(vmess.id);
+    delVmess(VMESS) {
+        const i = this.indexOfVmessById(VMESS.id);
         if (i >= 0) {
             this.vmesses.splice(i, 1);
         }
@@ -2033,7 +2043,7 @@ Inbound.VmessSettings = class extends Inbound.Settings {
     static fromJson(json = {}) {
         return new Inbound.VmessSettings(
             Protocols.VMESS,
-            json.clients.map(client => Inbound.VmessSettings.Vmess.fromJson(client)),
+            json.clients.map(client => Inbound.VmessSettings.VMESS.fromJson(client)),
         );
     }
 
@@ -2043,10 +2053,23 @@ Inbound.VmessSettings = class extends Inbound.Settings {
         };
     }
 };
-Inbound.VmessSettings.Vmess = class extends XrayCommonClass {
-    constructor(id = RandomUtil.randomUUID(), email = RandomUtil.randomLowerAndNum(8), limitIp = 0, totalGB = 0, expiryTime = 0, enable = true, tgId = '', subId = RandomUtil.randomLowerAndNum(16), reset = 0) {
+
+Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
+    constructor(
+        id = RandomUtil.randomUUID(),
+        security = USERS_SECURITY.AUTO,
+        email = RandomUtil.randomLowerAndNum(8),
+        limitIp = 0,
+        totalGB = 0,
+        expiryTime = 0,
+        enable = true,
+        tgId = '',
+        subId = RandomUtil.randomLowerAndNum(16),
+        reset = 0
+    ) {
         super();
         this.id = id;
+        this.security = security;
         this.email = email;
         this.limitIp = limitIp;
         this.totalGB = totalGB;
@@ -2058,8 +2081,9 @@ Inbound.VmessSettings.Vmess = class extends XrayCommonClass {
     }
 
     static fromJson(json = {}) {
-        return new Inbound.VmessSettings.Vmess(
+        return new Inbound.VmessSettings.VMESS(
             json.id,
+            json.security,
             json.email,
             json.limitIp,
             json.totalGB,
@@ -2098,10 +2122,12 @@ Inbound.VmessSettings.Vmess = class extends XrayCommonClass {
 };
 
 Inbound.VLESSSettings = class extends Inbound.Settings {
-    constructor(protocol,
+    constructor(
+        protocol,
         vlesses = [new Inbound.VLESSSettings.VLESS()],
         decryption = 'none',
-        fallbacks = []) {
+        fallbacks = []
+    ) {
         super(protocol);
         this.vlesses = vlesses;
         this.decryption = decryption;
@@ -2135,7 +2161,18 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
 };
 
 Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
-    constructor(id = RandomUtil.randomUUID(), flow = '', email = RandomUtil.randomLowerAndNum(8), limitIp = 0, totalGB = 0, expiryTime = 0, enable = true, tgId = '', subId = RandomUtil.randomLowerAndNum(16), reset = 0) {
+    constructor(
+        id = RandomUtil.randomUUID(),
+        flow = '',
+        email = RandomUtil.randomLowerAndNum(8),
+        limitIp = 0,
+        totalGB = 0,
+        expiryTime = 0,
+        enable = true,
+        tgId = '',
+        subId = RandomUtil.randomLowerAndNum(16),
+        reset = 0
+    ) {
         super();
         this.id = id;
         this.flow = flow;

+ 9 - 1
web/html/xui/client_bulk_modal.html

@@ -28,6 +28,11 @@
         <a-form-item label='{{ i18n "pages.client.clientCount" }}' v-if="clientsBulkModal.emailMethod < 2">
             <a-input-number v-model="clientsBulkModal.quantity" :min="1" :max="100"></a-input-number>
         </a-form-item>
+        <a-form-item v-if="inbound.protocol === Protocols.VMESS" label='Security'>
+            <a-select v-model="clientsBulkModal.security" :dropdown-class-name="themeSwitcher.currentTheme">
+                <a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option>
+            </a-select>
+        </a-form-item>
         <a-form-item label='Flow' v-if="clientsBulkModal.inbound.canEnableTlsFlow()">
             <a-select v-model="clientsBulkModal.flow" :dropdown-class-name="themeSwitcher.currentTheme">
                 <a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
@@ -146,6 +151,7 @@
         emailPostfix: "",
         subId: "",
         tgId: '',
+        security: "auto",
         flow: "",
         delayedStart: false,
         reset: 0,
@@ -168,6 +174,7 @@
                 newClient.email += useNum ? prefix + i.toString() + postfix : prefix + postfix;
                 if (clientsBulkModal.subId.length > 0) newClient.subId = clientsBulkModal.subId;
                 newClient.tgId = clientsBulkModal.tgId;
+                newClient.security = clientsBulkModal.security;
                 newClient.limitIp = clientsBulkModal.limitIp;
                 newClient._totalGB = clientsBulkModal.totalGB;
                 newClient._expiryTime = clientsBulkModal.expiryTime;
@@ -203,6 +210,7 @@
             this.emailPostfix = "";
             this.subId = "";
             this.tgId = '';
+            this.security = "auto";
             this.flow = "";
             this.dbInbound = new DBInbound(dbInbound);
             this.inbound = dbInbound.toInbound();
@@ -211,7 +219,7 @@
         },
         newClient(protocol) {
             switch (protocol) {
-                case Protocols.VMESS: return new Inbound.VmessSettings.Vmess();
+                case Protocols.VMESS: return new Inbound.VmessSettings.VMESS();
                 case Protocols.VLESS: return new Inbound.VLESSSettings.VLESS();
                 case Protocols.TROJAN: return new Inbound.TrojanSettings.Trojan();
                 case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings.Shadowsocks(clientsBulkModal.inbound.settings.shadowsockses[0].method);

+ 1 - 1
web/html/xui/client_modal.html

@@ -61,7 +61,7 @@
         },
         addClient(protocol, clients) {
             switch (protocol) {
-                case Protocols.VMESS: return clients.push(new Inbound.VmessSettings.Vmess());
+                case Protocols.VMESS: return clients.push(new Inbound.VmessSettings.VMESS());
                 case Protocols.VLESS: return clients.push(new Inbound.VLESSSettings.VLESS());
                 case Protocols.TROJAN: return clients.push(new Inbound.TrojanSettings.Trojan());
                 case Protocols.SHADOWSOCKS: return clients.push(new Inbound.ShadowsocksSettings.Shadowsocks(clients[0].method));

+ 5 - 0
web/html/xui/form/client.html

@@ -39,6 +39,11 @@
         </template>
         <a-input v-model.trim="client.id"></a-input>
     </a-form-item>
+    <a-form-item v-if="inbound.protocol === Protocols.VMESS" label='Security'>
+        <a-select v-model="client.security" :dropdown-class-name="themeSwitcher.currentTheme">
+            <a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option>
+        </a-select>
+    </a-form-item>
     <a-form-item v-if="client.email && app.subSettings.enable">
         <template slot="label">
             <a-tooltip>

+ 5 - 0
web/html/xui/form/outbound.html

@@ -160,6 +160,11 @@
         <a-form-item label='ID'>
           <a-input v-model.trim="outbound.settings.id"></a-input>
         </a-form-item>
+        <a-form-item label='Security'>
+          <a-select v-model="outbound.settings.security" :dropdown-class-name="themeSwitcher.currentTheme">
+            <a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option>
+          </a-select>
+        </a-form-item>
 
         <!-- vless settings -->
         <template v-if="outbound.canEnableTlsFlow()">

+ 2 - 0
web/html/xui/form/protocol/vmess.html

@@ -10,10 +10,12 @@
             <tr class="client-table-header">
                 <th>{{ i18n "pages.inbounds.email" }}</th>
                 <th>ID</th>
+                <th>Security</th>
             </tr>
             <tr v-for="(client, index) in inbound.settings.vmesses" :class="index % 2 == 1 ? 'client-table-odd-row' : ''">
                 <td>[[ client.email ]]</td>
                 <td>[[ client.id ]]</td>
+                <td>[[ client.security ]]</td>
             </tr>
         </table>
     </a-collapse-panel>

+ 3 - 1
web/html/xui/settings.html

@@ -523,7 +523,9 @@
         if (msg.success) {
           this.loading(true);
           await PromiseUtil.sleep(5000);
-          let { webCertFile, webKeyFile, webDomain: host, webPort: port, webBasePath: base } = this.allSetting;
+          var { webCertFile, webKeyFile, webDomain: host, webPort: port, webBasePath: base } = this.allSetting;
+          if (host == this.oldAllSetting.webDomain) host = null;
+          if (port == this.oldAllSetting.webPort) port = null;
           const isTLS = webCertFile !== "" || webKeyFile !== "";
           const url = buildURL({ host, port, isTLS, base, path: "panel/settings" });
           window.location.replace(url);

+ 3 - 0
web/service/inbound.go

@@ -490,6 +490,7 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) (bool, error) {
 				err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
 					"email":    client.Email,
 					"id":       client.ID,
+					"security": client.Security,
 					"flow":     client.Flow,
 					"password": client.Password,
 					"cipher":   cipher,
@@ -711,6 +712,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
 			err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
 				"email":    clients[0].Email,
 				"id":       clients[0].ID,
+				"security": clients[0].Security,
 				"flow":     clients[0].Flow,
 				"password": clients[0].Password,
 				"cipher":   cipher,
@@ -1559,6 +1561,7 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, e
 				err1 := s.xrayApi.AddUser(string(inbound.Protocol), inbound.Tag, map[string]interface{}{
 					"email":    client.Email,
 					"id":       client.ID,
+					"security": client.Security,
 					"flow":     client.Flow,
 					"password": client.Password,
 					"cipher":   cipher,