Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorAlireza Ahmadi <alireza7@gmail.com>2023-12-08 20:45:21 +0300
committerAlireza Ahmadi <alireza7@gmail.com>2023-12-08 20:45:21 +0300
commit5fbf8f0d535b131ad6de22a0d1dda0f2167d5ee0 (patch)
treec2da678a5d851fe5349644468427c5ba45e24d3d /web
parentbcc897640e68f7a731d39bee04c8930d7d7196c6 (diff)
Expand multiDomain to externalProxy #1300
Diffstat (limited to 'web')
-rw-r--r--web/assets/js/model/xray.js255
-rw-r--r--web/html/common/qrcode_modal.html26
-rw-r--r--web/html/xui/client_modal.html13
-rw-r--r--web/html/xui/form/inbound.html1
-rw-r--r--web/html/xui/form/stream/external_proxy.html32
-rw-r--r--web/html/xui/form/tls_settings.html30
-rw-r--r--web/html/xui/inbound_info_modal.html25
-rw-r--r--web/html/xui/inbound_modal.html28
-rw-r--r--web/html/xui/inbounds.html46
-rw-r--r--web/service/inbound.go40
-rw-r--r--web/service/xray.go29
-rw-r--r--web/translation/translate.en_US.toml1
-rw-r--r--web/translation/translate.es_ES.toml1
-rw-r--r--web/translation/translate.fa_IR.toml1
-rw-r--r--web/translation/translate.ru_RU.toml1
-rw-r--r--web/translation/translate.vi_VN.toml1
-rw-r--r--web/translation/translate.zh_Hans.toml1
17 files changed, 262 insertions, 269 deletions
diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js
index 0418540a..97110ae9 100644
--- a/web/assets/js/model/xray.js
+++ b/web/assets/js/model/xray.js
@@ -578,27 +578,21 @@ TlsStreamSettings.Cert = class extends XrayCommonClass {
};
TlsStreamSettings.Settings = class extends XrayCommonClass {
- constructor(allowInsecure = false, fingerprint = '', serverName = '', domains = []) {
+ constructor(allowInsecure = false, fingerprint = '') {
super();
this.allowInsecure = allowInsecure;
this.fingerprint = fingerprint;
- this.serverName = serverName;
- this.domains = domains;
}
static fromJson(json = {}) {
return new TlsStreamSettings.Settings(
json.allowInsecure,
json.fingerprint,
- json.serverName,
- json.domains,
);
}
toJson() {
return {
allowInsecure: this.allowInsecure,
fingerprint: this.fingerprint,
- serverName: this.serverName,
- domains: this.domains,
};
}
};
@@ -692,21 +686,18 @@ XtlsStreamSettings.Cert = class extends XrayCommonClass {
};
XtlsStreamSettings.Settings = class extends XrayCommonClass {
- constructor(allowInsecure = false, serverName = '') {
+ constructor(allowInsecure = false) {
super();
this.allowInsecure = allowInsecure;
- this.serverName = serverName;
}
static fromJson(json = {}) {
return new XtlsStreamSettings.Settings(
json.allowInsecure,
- json.servername,
);
}
toJson() {
return {
allowInsecure: this.allowInsecure,
- serverName: this.serverName,
};
}
};
@@ -773,18 +764,16 @@ class RealityStreamSettings extends XrayCommonClass {
}
RealityStreamSettings.Settings = class extends XrayCommonClass {
- constructor(publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_FIREFOX, serverName = '', spiderX= '/') {
+ constructor(publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_FIREFOX, spiderX= '/') {
super();
this.publicKey = publicKey;
this.fingerprint = fingerprint;
- this.serverName = serverName;
this.spiderX = spiderX;
}
static fromJson(json = {}) {
return new RealityStreamSettings.Settings(
json.publicKey,
json.fingerprint,
- json.serverName,
json.spiderX,
);
}
@@ -792,7 +781,6 @@ RealityStreamSettings.Settings = class extends XrayCommonClass {
return {
publicKey: this.publicKey,
fingerprint: this.fingerprint,
- serverName: this.serverName,
spiderX: this.spiderX,
};
}
@@ -829,6 +817,7 @@ class SockoptStreamSettings extends XrayCommonClass {
class StreamSettings extends XrayCommonClass {
constructor(network='tcp',
security='none',
+ externalProxy = [],
tlsSettings=new TlsStreamSettings(),
xtlsSettings=new XtlsStreamSettings(),
realitySettings = new RealityStreamSettings(),
@@ -843,6 +832,7 @@ class StreamSettings extends XrayCommonClass {
super();
this.network = network;
this.security = security;
+ this.externalProxy = externalProxy;
this.tls = tlsSettings;
this.xtls = xtlsSettings;
this.reality = realitySettings;
@@ -901,10 +891,10 @@ class StreamSettings extends XrayCommonClass {
}
static fromJson(json={}) {
-
return new StreamSettings(
json.network,
json.security,
+ json.externalProxy,
TlsStreamSettings.fromJson(json.tlsSettings),
XtlsStreamSettings.fromJson(json.xtlsSettings),
RealityStreamSettings.fromJson(json.realitySettings),
@@ -923,6 +913,7 @@ class StreamSettings extends XrayCommonClass {
return {
network: network,
security: this.security,
+ externalProxy: this.externalProxy,
tlsSettings: this.isTls ? this.tls.toJson() : undefined,
xtlsSettings: this.isXtls ? this.xtls.toJson() : undefined,
realitySettings: this.isReality ? this.reality.toJson() : undefined,
@@ -982,6 +973,16 @@ class Inbound extends XrayCommonClass {
return this.clientStats;
}
+ get clients() {
+ switch (this.protocol) {
+ case Protocols.VMESS: return this.settings.vmesses;
+ case Protocols.VLESS: return this.settings.vlesses;
+ case Protocols.TROJAN: return this.settings.trojans;
+ case Protocols.SHADOWSOCKS: return this.isSSMultiUser ? this.settings.shadowsockses : null;
+ default: return null;
+ }
+ }
+
get protocol() {
return this._protocol;
}
@@ -1132,26 +1133,8 @@ class Inbound extends XrayCommonClass {
}
isExpiry(index) {
- switch (this.protocol) {
- case Protocols.VMESS:
- if(this.settings.vmesses[index].expiryTime > 0)
- return this.settings.vmesses[index].expiryTime < new Date().getTime();
- return false
- case Protocols.VLESS:
- if(this.settings.vlesses[index].expiryTime > 0)
- return this.settings.vlesses[index].expiryTime < new Date().getTime();
- return false
- case Protocols.TROJAN:
- if(this.settings.trojans[index].expiryTime > 0)
- return this.settings.trojans[index].expiryTime < new Date().getTime();
- return false
- case Protocols.SHADOWSOCKS:
- if(this.settings.shadowsockses.length > 0 && this.settings.shadowsockses[index].expiryTime > 0)
- return this.settings.shadowsockses[index].expiryTime < new Date().getTime();
- return false
- default:
- return false;
- }
+ let exp = this.clients[index].expiryTime;
+ return exp > 0 ? exp < new Date().getTime() : false;
}
canEnableTls() {
@@ -1195,19 +1178,20 @@ class Inbound extends XrayCommonClass {
this.sniffing = new Sniffing();
}
- genVmessLink(address='', remark='', clientIndex=0) {
+ genVmessLink(address='', port=this.port, forceTls, remark='', clientId) {
if (this.protocol !== Protocols.VMESS) {
return '';
}
+ const security = forceTls == 'same' ? this.stream.security : forceTls;
let obj = {
v: '2',
ps: remark,
add: address,
- port: this.port,
- id: this.settings.vmesses[clientIndex].id,
+ port: port,
+ id: clientId,
net: this.stream.network,
type: 'none',
- tls: this.stream.security,
+ tls: security,
};
let network = this.stream.network;
if (network === 'tcp') {
@@ -1247,12 +1231,9 @@ class Inbound extends XrayCommonClass {
}
}
- if (this.stream.security === 'tls') {
- if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
- obj.add = this.stream.tls.server;
- }
- if (!ObjectUtil.isEmpty(this.stream.tls.settings.serverName)){
- obj.sni = this.stream.tls.settings.serverName;
+ if (security === 'tls') {
+ if (!ObjectUtil.isEmpty(this.stream.tls.sni)){
+ obj.sni = this.stream.tls.server;
}
if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerprint)){
obj.fp = this.stream.tls.settings.fingerprint;
@@ -1268,11 +1249,10 @@ class Inbound extends XrayCommonClass {
return 'vmess://' + base64(JSON.stringify(obj, null, 2));
}
- genVLESSLink(address = '', remark='', clientIndex=0) {
- const settings = this.settings;
- const uuid = settings.vlesses[clientIndex].id;
- const port = this.port;
+ genVLESSLink(address = '', port=this.port, forceTls, remark='', clientId, flow) {
+ const uuid = clientId;
const type = this.stream.network;
+ const security = forceTls == 'same' ? this.stream.security : forceTls;
const params = new Map();
params.set("type", this.stream.network);
switch (type) {
@@ -1323,58 +1303,51 @@ class Inbound extends XrayCommonClass {
break;
}
- if (this.tls) {
+ if (security === 'tls') {
params.set("security", "tls");
- params.set("fp" , this.stream.tls.settings.fingerprint);
- params.set("alpn", this.stream.tls.alpn);
- if(this.stream.tls.settings.allowInsecure){
- params.set("allowInsecure", "1");
- }
- if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
- address = this.stream.tls.server;
- }
- if (this.stream.tls.settings.serverName !== ''){
- params.set("sni", this.stream.tls.settings.serverName);
- }
- if (type === "tcp" && this.settings.vlesses[clientIndex].flow.length > 0) {
- params.set("flow", this.settings.vlesses[clientIndex].flow);
+ if (this.stream.isTls){
+ params.set("fp" , this.stream.tls.settings.fingerprint);
+ params.set("alpn", this.stream.tls.alpn);
+ if(this.stream.tls.settings.allowInsecure){
+ params.set("allowInsecure", "1");
+ }
+ if (!ObjectUtil.isEmpty(this.stream.tls.server)){
+ params.set("sni", this.stream.tls.server);
+ }
+ if (type == "tcp" && !ObjectUtil.isEmpty(flow)) {
+ params.set("flow", flow);
+ }
}
}
- else if (this.xtls) {
+ else if (security === 'xtls') {
params.set("security", "xtls");
params.set("alpn", this.stream.xtls.alpn);
if(this.stream.xtls.settings.allowInsecure){
params.set("allowInsecure", "1");
}
- if (!ObjectUtil.isEmpty(this.stream.xtls.server)) {
- address = this.stream.xtls.server;
- }
- if (this.stream.xtls.settings.serverName !== ''){
- params.set("sni", this.stream.xtls.settings.serverName);
+ if (!ObjectUtil.isEmpty(this.stream.xtls.server)){
+ params.set("sni", this.stream.xtls.server);
}
params.set("flow", this.settings.vlesses[clientIndex].flow);
}
- else if (this.reality) {
+ else if (security === 'reality') {
params.set("security", "reality");
- params.set("fp", this.stream.reality.settings.fingerprint);
params.set("pbk", this.stream.reality.settings.publicKey);
+ params.set("fp", this.stream.reality.settings.fingerprint);
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
}
- if (this.stream.network === 'tcp' && !ObjectUtil.isEmpty(this.settings.vlesses[clientIndex].flow)) {
- params.set("flow", this.settings.vlesses[clientIndex].flow);
- }
if (this.stream.reality.shortIds.length > 0) {
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
}
- if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
- address = this.stream.reality.settings.serverName;
- }
if (!ObjectUtil.isEmpty(this.stream.reality.settings.spiderX)) {
params.set("spx", this.stream.reality.settings.spiderX);
}
+ if (type == 'tcp' && !ObjectUtil.isEmpty(flow)) {
+ params.set("flow", flow);
+ }
}
else {
@@ -1390,10 +1363,10 @@ class Inbound extends XrayCommonClass {
return url.toString();
}
- genSSLink(address='', remark='', clientIndex = 0) {
+ genSSLink(address='', port=this.port, forceTls, remark='', clientPassword) {
let settings = this.settings;
- const port = this.port;
const type = this.stream.network;
+ const security = forceTls == 'same' ? this.stream.security : forceTls;
const params = new Map();
params.set("type", this.stream.network);
switch (type) {
@@ -1444,11 +1417,26 @@ class Inbound extends XrayCommonClass {
break;
}
+ if (security === 'tls') {
+ params.set("security", "tls");
+ if (this.stream.isTls){
+ params.set("fp" , this.stream.tls.settings.fingerprint);
+ params.set("alpn", this.stream.tls.alpn);
+ if(this.stream.tls.settings.allowInsecure){
+ params.set("allowInsecure", "1");
+ }
+ if (!ObjectUtil.isEmpty(this.stream.tls.server)){
+ params.set("sni", this.stream.tls.server);
+ }
+ }
+ }
+
+
let password = new Array();
if (this.isSS2022) password.push(settings.password);
- if (this.isSSMultiUser) password.push(settings.shadowsockses[clientIndex].password);
+ if (this.isSSMultiUser) password.push(clientPassword);
- let link = `ss://${safeBase64(settings.method + ':' + password.join(':'))}@${address}:${this.port}`;
+ let link = `ss://${safeBase64(settings.method + ':' + password.join(':'))}@${address}:${port}`;
const url = new URL(link);
for (const [key, value] of params) {
url.searchParams.set(key, value)
@@ -1457,9 +1445,8 @@ class Inbound extends XrayCommonClass {
return url.toString();
}
- genTrojanLink(address = '', remark = '', clientIndex = 0) {
- let settings = this.settings;
- const port = this.port;
+ genTrojanLink(address = '', port=this.port, forceTls, remark = '', clientPassword) {
+ const security = forceTls == 'same' ? this.stream.security : forceTls;
const type = this.stream.network;
const params = new Map();
params.set("type", this.stream.network);
@@ -1511,48 +1498,41 @@ class Inbound extends XrayCommonClass {
break;
}
- if (this.tls) {
+ if (security === 'tls') {
params.set("security", "tls");
- params.set("fp" , this.stream.tls.settings.fingerprint);
- params.set("alpn", this.stream.tls.alpn);
- if(this.stream.tls.settings.allowInsecure){
- params.set("allowInsecure", "1");
- }
- if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
- address = this.stream.tls.server;
+ if (this.stream.isTls){
+ params.set("fp" , this.stream.tls.settings.fingerprint);
+ params.set("alpn", this.stream.tls.alpn);
+ if(this.stream.tls.settings.allowInsecure){
+ params.set("allowInsecure", "1");
+ }
+ if (!ObjectUtil.isEmpty(this.stream.tls.server)){
+ params.set("sni", this.stream.tls.server);
+ }
}
- if (this.stream.tls.settings.serverName !== ''){
- params.set("sni", this.stream.tls.settings.serverName);
- }
}
- else if (this.reality) {
+ else if (security === 'reality') {
params.set("security", "reality");
- params.set("fp", this.stream.reality.settings.fingerprint);
params.set("pbk", this.stream.reality.settings.publicKey);
+ params.set("fp", this.stream.reality.settings.fingerprint);
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
}
if (this.stream.reality.shortIds.length > 0) {
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
}
- if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
- address = this.stream.reality.settings.serverName;
- }
if (!ObjectUtil.isEmpty(this.stream.reality.settings.spiderX)) {
params.set("spx", this.stream.reality.settings.spiderX);
}
}
- else if (this.xtls) {
+ else if (security === 'xtls') {
params.set("security", "xtls");
params.set("alpn", this.stream.xtls.alpn);
if(this.stream.xtls.settings.allowInsecure){
params.set("allowInsecure", "1");
}
- if (!ObjectUtil.isEmpty(this.stream.xtls.server)) {
- address = this.stream.xtls.server;
- }
if (this.stream.xtls.settings.serverName !== ''){
params.set("sni", this.stream.xtls.settings.serverName);
}
@@ -1563,7 +1543,7 @@ class Inbound extends XrayCommonClass {
params.set("security", "none");
}
- const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}`;
+ const link = `trojan://${clientPassword}@${address}:${port}`;
const url = new URL(link);
for (const [key, value] of params) {
url.searchParams.set(key, value)
@@ -1572,38 +1552,55 @@ class Inbound extends XrayCommonClass {
return url.toString();
}
- genLink(address='', remark='', clientIndex=0) {
+ genLink(address='', port=this.port, forceTls='same', remark='', client) {
switch (this.protocol) {
- case Protocols.VMESS:
- return this.genVmessLink(address, remark, clientIndex);
+ case Protocols.VMESS:
+ return this.genVmessLink(address, port, forceTls, remark, client.id);
case Protocols.VLESS:
- return this.genVLESSLink(address, remark, clientIndex);
+ return this.genVLESSLink(address, port, forceTls, remark, client.id, client.flow);
case Protocols.SHADOWSOCKS:
- return this.genSSLink(address, remark, clientIndex);
+ return this.genSSLink(address, port, forceTls, remark, this.isSSMultiUser ? client.password : '');
case Protocols.TROJAN:
- return this.genTrojanLink(address, remark, clientIndex);
+ return this.genTrojanLink(address, port, forceTls, remark, client.password);
default: return '';
}
}
- genInboundLinks(address = '', remark = '') {
- let link = '';
- switch (this.protocol) {
- case Protocols.VMESS:
- case Protocols.VLESS:
- case Protocols.TROJAN:
- case Protocols.SHADOWSOCKS:
- JSON.parse(this.settings).clients.forEach((client,index) => {
- if(this.tls && !ObjectUtil.isArrEmpty(this.stream.tls.settings.domains)){
- this.stream.tls.settings.domains.forEach((domain) => {
- link += this.genLink(domain.domain, [remark, client.email, domain.remark].filter(x => x.length > 0).join('-'), index) + '\r\n';
- });
- } else {
- link += this.genLink(address, [remark, client.email].filter(x => x.length > 0).join('-'), index) + '\r\n';
- }
+ genAllLinks(remark='', client){
+ let result = [];
+ let email = client ? client.email : '';
+ let addr = !ObjectUtil.isEmpty(this.listen) && this.listen !== "0.0.0.0" ? this.listen : location.hostname;
+ let port = this.port
+ if(ObjectUtil.isArrEmpty(this.stream.externalProxy)){
+ let r = [remark, email].filter(x => x.length > 0).join('-');
+ result.push({
+ remark: r,
+ link: this.genLink(addr, port, 'same', r, client)
+ });
+ } else {
+ this.stream.externalProxy.forEach((ep) => {
+ let r = [remark, email, ep.remark].filter(x => x.length > 0).join('-')
+ result.push({
+ remark: r,
+ link: this.genLink(ep.dest, ep.port, ep.forceTls, r, client)
});
- return link;
- default: return '';
+ });
+ }
+ return result;
+ }
+
+ genInboundLinks(remark = '') {
+ if(this.clients){
+ let links = [];
+ this.clients.forEach((client) => {
+ genAllLinks(remark,client).forEach(l => {
+ links.push(l.link);
+ })
+ });
+ return links.join('\r\n');
+ } else {
+ if(this.protocol == Protocols.SHADOWSOCKS && !this.isSSMultiUser) return this.genSSLink(this.listen, this.port, remark);
+ return '';
}
}
diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html
index 85ada3d4..0df369ff 100644
--- a/web/html/common/qrcode_modal.html
+++ b/web/html/common/qrcode_modal.html
@@ -22,39 +22,25 @@
const qrModal = {
title: '',
- clientIndex: 0,
- inbound: new Inbound(),
dbInbound: new DBInbound(),
client: null,
qrcodes: [],
clipboard: null,
visible: false,
subId: '',
- show: function (title = '', dbInbound = new DBInbound(), clientIndex = 0) {
+ show: function (title = '', dbInbound, client) {
this.title = title;
- this.clientIndex = clientIndex;
this.dbInbound = dbInbound;
this.inbound = dbInbound.toInbound();
- settings = JSON.parse(this.inbound.settings);
- this.client = settings.clients[clientIndex];
- remark = [this.dbInbound.remark, ( this.client ? this.client.email : '')].filter(Boolean).join('-');
- address = this.dbInbound.address;
+ this.client = client;
this.subId = '';
this.qrcodes = [];
- if (this.inbound.tls && !ObjectUtil.isArrEmpty(this.inbound.stream.tls.settings.domains)) {
- this.inbound.stream.tls.settings.domains.forEach((domain) => {
- remarkText = [remark, domain.remark].filter(Boolean).join('-');
- this.qrcodes.push({
- remark: remarkText,
- link: this.inbound.genLink(domain.domain, remarkText, clientIndex)
- });
- });
- } else {
+ this.inbound.genAllLinks(this.dbInbound.remark, client).forEach(l => {
this.qrcodes.push({
- remark: remark,
- link: this.inbound.genLink(address, remark, clientIndex)
+ remark: l.remark,
+ link: l.link
});
- }
+ });
this.visible = true;
},
close: function () {
diff --git a/web/html/xui/client_modal.html b/web/html/xui/client_modal.html
index 265a2cac..1bc48a6a 100644
--- a/web/html/xui/client_modal.html
+++ b/web/html/xui/client_modal.html
@@ -38,7 +38,7 @@
this.isEdit = isEdit;
this.dbInbound = new DBInbound(dbInbound);
this.inbound = dbInbound.toInbound();
- this.clients = this.getClients(this.inbound.protocol, this.inbound.settings);
+ this.clients = this.inbound.clients;
this.index = index === null ? this.clients.length : index;
this.delayedStart = false;
if (isEdit) {
@@ -51,16 +51,7 @@
}
this.clientStats = this.dbInbound.clientStats.find(row => row.email === this.clients[this.index].email);
this.confirm = confirm;
- },
- getClients(protocol, clientSettings) {
- switch (protocol) {
- case Protocols.VMESS: return clientSettings.vmesses;
- case Protocols.VLESS: return clientSettings.vlesses;
- case Protocols.TROJAN: return clientSettings.trojans;
- case Protocols.SHADOWSOCKS: return clientSettings.shadowsockses;
- default: return null;
- }
- },
+ },
getClientId(protocol, client) {
switch (protocol) {
case Protocols.TROJAN: return client.password;
diff --git a/web/html/xui/form/inbound.html b/web/html/xui/form/inbound.html
index 40a96d1e..b46ce951 100644
--- a/web/html/xui/form/inbound.html
+++ b/web/html/xui/form/inbound.html
@@ -96,6 +96,7 @@
<!-- stream settings -->
<template v-if="inbound.canEnableStream()">
{{template "form/streamSettings"}}
+ {{template "form/externalProxy" }}
</template>
<!-- tls settings -->
diff --git a/web/html/xui/form/stream/external_proxy.html b/web/html/xui/form/stream/external_proxy.html
new file mode 100644
index 00000000..bb80070c
--- /dev/null
+++ b/web/html/xui/form/stream/external_proxy.html
@@ -0,0 +1,32 @@
+{{define "form/externalProxy"}}
+<a-form layout="inline">
+ <a-divider style="margin:0;"></a-divider>
+ <a-form-item label="External Proxy">
+ <a-switch v-model="externalProxy"></a-switch>
+ <a-button v-if="externalProxy" type="primary" style="margin-left: 10px" size="small" @click="inbound.stream.externalProxy.push({forceTls: 'same', dest: '', port: 443, remark: ''})">+</a-button>
+ </a-form-item>
+ <table width="100%" class="ant-table-tbody" v-if="externalProxy" style="margin-bottom:5px">
+ <tr style="line-height: 40px;">
+ <td width="100%">
+ <a-input-group style="margin: 0 5px;" 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">
+ <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%" 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="65531"></a-input-number>
+ </a-tooltip>
+ <a-input style="width: 20%" 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>
+ </td>
+ </tr>
+ </table>
+</a-form>
+{{end}}
diff --git a/web/html/xui/form/tls_settings.html b/web/html/xui/form/tls_settings.html
index eb201862..a77bec40 100644
--- a/web/html/xui/form/tls_settings.html
+++ b/web/html/xui/form/tls_settings.html
@@ -24,26 +24,6 @@
<!-- tls settings -->
<a-form v-if="inbound.tls" layout="inline">
- <a-form-item label='Multi Domain'>
- <a-switch v-model="multiDomain"></a-switch>
- </a-form-item>
- <a-form-item v-if="multiDomain">
- <a-row>
- <span>Domains:</span>
- <a-button v-if="multiDomain" type="primary" size="small" @click="inbound.stream.tls.settings.domains.push({remark: '', domain: ''})" style="margin-left: 10px">+</a-button>
- </a-row>
- <a-input-group v-for="(row, index) in inbound.stream.tls.settings.domains">
- <a-input style="width: 40%" v-model.trim="row.remark" addon-before='{{ i18n "remark" }}'></a-input>
- <a-input style="width: 60%" v-model.trim="row.domain" addon-before='{{ i18n "host" }}'>
- <template slot="addonAfter">
- <a-button type="primary" size="small" style="margin-left: 10px" @click="inbound.stream.tls.settings.domains.splice(index, 1)">-</a-button>
- </template>
- </a-input>
- </a-input-group>
- </a-form-item>
- <a-form-item v-else label='{{ i18n "domainName" }}'>
- <a-input v-model.trim="inbound.stream.tls.server" style="width: 250px"></a-input>
- </a-form-item>
<a-form-item label="CipherSuites">
<a-select v-model="inbound.stream.tls.cipherSuites" style="width: 300px" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="">auto</a-select-option>
@@ -61,7 +41,7 @@
</a-input-group>
</a-form-item>
<a-form-item label="SNI" placeholder="Server Name Indication">
- <a-input v-model.trim="inbound.stream.tls.settings.serverName" style="width: 250px"></a-input>
+ <a-input v-model.trim="inbound.stream.tls.server" style="width: 250px"></a-input>
</a-form-item>
<a-form-item label="uTLS">
<a-select v-model="inbound.stream.tls.settings.fingerprint"
@@ -122,11 +102,8 @@
<!-- xtls settings -->
<a-form v-else-if="inbound.xtls" layout="inline">
- <a-form-item label='{{ i18n "domainName" }}'>
- <a-input v-model.trim="inbound.stream.xtls.server"></a-input>
- </a-form-item>
<a-form-item label="SNI" placeholder="Server Name Indication">
- <a-input v-model.trim="inbound.stream.xtls.settings.serverName" style="width: 250px"></a-input>
+ <a-input v-model.trim="inbound.stream.xtls.server" style="width: 250px"></a-input>
</a-form-item>
<a-form-item label="Alpn">
<a-checkbox-group v-model="inbound.stream.xtls.alpn" style="width:200px">
@@ -180,9 +157,6 @@
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
- <a-form-item label='{{ i18n "domainName" }}'>
- <a-input v-model.trim="inbound.stream.reality.settings.serverName" style="width: 250px"></a-input>
- </a-form-item>
<a-form-item label="Dest">
<a-input v-model.trim="inbound.stream.reality.dest" style="width: 300px"></a-input>
</a-form-item>
diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/inbound_info_modal.html
index 554d10a3..1390bbcd 100644
--- a/web/html/xui/inbound_info_modal.html
+++ b/web/html/xui/inbound_info_modal.html
@@ -265,27 +265,10 @@
this.index = index;
this.inbound = dbInbound.toInbound();
this.dbInbound = new DBInbound(dbInbound);
- this.settings = JSON.parse(this.inbound.settings);
- this.clientSettings = this.settings.clients ? Object.values(this.settings.clients)[index] : null;
- this.isExpired = this.inbound.isExpiry(index);
- this.clientStats = this.settings.clients ? this.dbInbound.clientStats.find(row => row.email === this.clientSettings.email) : [];
- remark = [this.dbInbound.remark, ( this.clientSettings ? this.clientSettings.email : '')].filter(Boolean).join('-');
- address = this.dbInbound.address;
- this.links = [];
- if (this.inbound.tls && !ObjectUtil.isArrEmpty(this.inbound.stream.tls.settings.domains)) {
- this.inbound.stream.tls.settings.domains.forEach((domain) => {
- remarkText = [remark, domain.remark].filter(Boolean).join('-');
- this.links.push({
- remark: remarkText,
- link: this.inbound.genLink(domain.domain, remarkText, index)
- });
- });
- } else {
- this.links.push({
- remark: remark,
- link: this.inbound.genLink(address, remark, index)
- });
- }
+ this.clientSettings = this.inbound.clients ? this.inbound.clients[index] : null;
+ this.isExpired = this.inbound.clients ? this.inbound.isExpiry(index): this.dbInbound.isExpiry;
+ this.clientStats = this.inbound.clients ? this.dbInbound.clientStats.find(row => row.email === this.clientSettings.email) : [];
+ this.links = this.inbound.genAllLinks(this.dbInbound.remark, this.clientSettings);
if (this.clientSettings) {
if (this.clientSettings.subId) {
this.subLink = this.genSubLink(this.clientSettings.subId);
diff --git a/web/html/xui/inbound_modal.html b/web/html/xui/inbound_modal.html
index df42225c..4ef8f2d6 100644
--- a/web/html/xui/inbound_modal.html
+++ b/