diff --git a/README.md b/README.md index b6a1fb41..93263122 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)** | Features | Enable? | | ------------- |:-------------:| | Multi-lang | :heavy_check_mark: | +| Dark/Light Theme | :heavy_check_mark: | | Search in deep | :heavy_check_mark: | | Inbound Multi User | :heavy_check_mark: | | Multi User Traffic & Expiration time | :heavy_check_mark: | @@ -24,6 +25,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)** - System Status Monitoring - Search within all inbounds and clients +- Support Dark/Light theme UI - Support multi-user multi-protocol, web page visualization operation - Supported protocols: vmess, vless, trojan, shadowsocks, dokodemo-door, socks, http - Support for configuring more transport configurations @@ -36,6 +38,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)** # Screenshot from Inbouds page ![inbounds](./media/inbounds.png) +![Dark inbounds](./media/inbounds-dark.png) # Install & Upgrade @@ -65,8 +68,6 @@ systemctl restart x-ui ## Install using docker -> This docker tutorial and docker image are provided by [alireza0](https://github.com/alireza0) - 1. install docker ```shell @@ -77,7 +78,9 @@ curl -fsSL https://get.docker.com | sh ```shell mkdir x-ui && cd x-ui -docker run -itd --network=host \ +docker run -itd \ + -p 54321:54321 -p 443:443 -p 80:80 \ + -e XRAY_VMESS_AEAD_FORCED=false \ -v $PWD/db/:/etc/x-ui/ \ -v $PWD/cert/:/root/cert/ \ --name x-ui --restart=unless-stopped \ @@ -113,8 +116,8 @@ certbot certonly --standalone --register-unsafely-without-email --non-interactiv X-UI supports daily traffic notification, panel login reminder and other functions through the Tg robot. To use the Tg robot, you need to apply for the specific application tutorial. You can refer to the [blog](https://coderfan.net/how-to-use-telegram-bot-to-alarm-you-when-someone-login-into-your-vps.html) Set the robot-related parameters in the panel background, including: -- Tg Robot Token -- Tg Robot ChatId +- Tg robot Token +- Tg robot ChatId - Tg robot cycle runtime, in crontab syntax - Tg robot Expiration threshold - Tg robot Traffic threshold @@ -135,8 +138,9 @@ Reference syntax: - CPU threshold notification - Threshold for Expiration time and Traffic to report in advance - Support client report if client's telegram username is added to the end of `email` like 'test123@telegram_username' +- Support telegram traffic report searched with UID (VMESS/VLESS) or Password (TROJAN) - anonymously - Menu based bot -- Search client by email +- Search client by email ( only admin ) - Check all inbounds - Check server status - Check Exhausted users diff --git a/config/version b/config/version index 60a2d3e9..44bb5d1f 100644 --- a/config/version +++ b/config/version @@ -1 +1 @@ -0.4.0 \ No newline at end of file +0.4.1 \ No newline at end of file diff --git a/media/inbounds-dark.png b/media/inbounds-dark.png new file mode 100644 index 00000000..dc49e8e5 Binary files /dev/null and b/media/inbounds-dark.png differ diff --git a/media/inbounds.png b/media/inbounds.png index 63c89d1f..381033cb 100644 Binary files a/media/inbounds.png and b/media/inbounds.png differ diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index 02ffa34a..9359a789 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -92,6 +92,12 @@ const UTLS_FINGERPRINT = { UTLS_RANDOMIZED: "randomized", }; +const ALPN_OPTION = { + H2: "h2", + HTTP1: "http/1.1", + BOTH: "h2,http/1.1", +}; + Object.freeze(Protocols); Object.freeze(VmessMethods); Object.freeze(SSMethods); @@ -101,6 +107,7 @@ Object.freeze(XTLS_FLOW_CONTROL); Object.freeze(TLS_FLOW_CONTROL); Object.freeze(TLS_VERSION_OPTION); Object.freeze(TLS_CIPHER_OPTION); +Object.freeze(ALPN_OPTION); class XrayCommonClass { @@ -471,7 +478,8 @@ class TlsStreamSettings extends XrayCommonClass { maxVersion = TLS_VERSION_OPTION.TLS13, cipherSuites = '', certificates=[new TlsStreamSettings.Cert()], - alpn=["h2", "http/1.1"]) { + alpn=[''], + settings=[new TlsStreamSettings.Settings()]) { super(); this.server = serverName; this.minVersion = minVersion; @@ -479,6 +487,7 @@ class TlsStreamSettings extends XrayCommonClass { this.cipherSuites = cipherSuites; this.certs = certificates; this.alpn = alpn; + this.settings = settings; } addCert(cert) { @@ -491,17 +500,23 @@ class TlsStreamSettings extends XrayCommonClass { static fromJson(json={}) { let certs; + let settings; if (!ObjectUtil.isEmpty(json.certificates)) { certs = json.certificates.map(cert => TlsStreamSettings.Cert.fromJson(cert)); } + if (!ObjectUtil.isEmpty(json.settings)) { + let values = json.settings[0]; + settings = [new TlsStreamSettings.Settings(values.allowInsecure , values.fingerprint, values.serverName)]; + } return new TlsStreamSettings( json.serverName, json.minVersion, json.maxVersion, json.cipherSuites, certs, - json.alpn + json.alpn, + settings, ); } @@ -512,7 +527,8 @@ class TlsStreamSettings extends XrayCommonClass { maxVersion: this.maxVersion, cipherSuites: this.cipherSuites, certificates: TlsStreamSettings.toJsonArray(this.certs), - alpn: this.alpn + alpn: this.alpn, + settings: TlsStreamSettings.toJsonArray(this.settings), }; } } @@ -558,6 +574,29 @@ TlsStreamSettings.Cert = class extends XrayCommonClass { } }; +TlsStreamSettings.Settings = class extends XrayCommonClass { + constructor(insecure = false, fingerprint = '', serverName = '') { + super(); + this.inSecure = insecure; + this.fingerprint = fingerprint; + this.serverName = serverName; + } + static fromJson(json = {}) { + return new TlsStreamSettings.Settings( + json.allowInsecure, + json.fingerprint, + json.servername, + ); + } + toJson() { + return { + allowInsecure: this.inSecure, + fingerprint: this.fingerprint, + serverName: this.serverName, + }; + } +}; + class StreamSettings extends XrayCommonClass { constructor(network='tcp', security='none', @@ -920,7 +959,7 @@ class Inbound extends XrayCommonClass { } } - //this is used for xtls-rprx-vison + //this is used for xtls-rprx-vision canEnableTlsFlow() { if ((this.stream.security === 'tls') && (this.network === "tcp")) { switch (this.protocol) { @@ -1053,6 +1092,7 @@ class Inbound extends XrayCommonClass { const type = this.stream.network; const params = new Map(); params.set("type", this.stream.network); + params.set("security", this.stream.security); if (this.xtls) { params.set("security", "xtls"); address = this.stream.tls.server; @@ -1107,13 +1147,29 @@ class Inbound extends XrayCommonClass { if (this.stream.security === 'tls') { if (!ObjectUtil.isEmpty(this.stream.tls.server)) { address = this.stream.tls.server; - params.set("sni", address); - } - params.set("flow", this.settings.vlesses[clientIndex].flow); + params.set("fp" , this.stream.tls.settings[0]['fingerprint']); + params.set("alpn", this.stream.tls.alpn[0]); + if (this.stream.tls.settings[0]['serverName'] !== ''){ + params.set("sni", this.stream.tls.settings[0]['serverName']); + } + else{ + params.set("sni", address); + } + if (type === "tcp" && this.settings.vlesses[clientIndex].flow.length > 0) { + params.set("flow", this.settings.vlesses[clientIndex].flow); + } + } } if (this.xtls) { - params.set("flow", this.settings.vlesses[clientIndex].flow); + if (this.stream.security === 'xtls') { + if (!ObjectUtil.isEmpty(this.stream.tls.server)) { + address = this.stream.tls.server; + if (type === "tcp") { + params.set("flow", this.settings.vlesses[clientIndex].flow); + } + } + } } const link = `vless://${uuid}@${address}:${port}`; @@ -1144,12 +1200,6 @@ class Inbound extends XrayCommonClass { const port = this.port; const type = this.stream.network; const params = new Map(); - params.set("type", this.stream.network); - if (this.xtls) { - params.set("security", "xtls"); - } else { - params.set("security", this.stream.security); - } switch (type) { case "tcp": const tcp = this.stream.tcp; @@ -1198,13 +1248,26 @@ class Inbound extends XrayCommonClass { if (this.stream.security === 'tls') { if (!ObjectUtil.isEmpty(this.stream.tls.server)) { address = this.stream.tls.server; - params.set("sni", address); - } - params.set("flow", this.settings.trojans[clientIndex].flow); + params.set("fp" , this.stream.tls.settings[0]['fingerprint']); + params.set("alpn", this.stream.tls.alpn[0]); + if (this.stream.tls.settings[0]['serverName'] !== ''){ + params.set("sni", this.stream.tls.settings[0]['serverName']); + } + else{ + params.set("sni", address); + } + } } - if (this.xtls) { - params.set("flow", this.settings.trojans[clientIndex].flow); + + if (this.stream.security === 'xtls') { + if (!ObjectUtil.isEmpty(this.stream.tls.server)) { + address = this.stream.tls.server; + if (type === "tcp" && this.settings.trojans[clientIndex].flow.length > 0) { + params.set("flow", this.settings.trojans[clientIndex].flow); + } + } } + const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`; const url = new URL(link); for (const [key, value] of params) { diff --git a/web/html/xui/form/tls_settings.html b/web/html/xui/form/tls_settings.html index 4c06b66b..1ff7a73c 100644 --- a/web/html/xui/form/tls_settings.html +++ b/web/html/xui/form/tls_settings.html @@ -12,6 +12,15 @@ + + + + + + auto + [[ key ]] + + [[ key ]] @@ -22,17 +31,20 @@ [[ key ]] - - - auto - [[ key ]] + + + None + [[ key ]] - - + + + auto + [[ key ]] + @@ -42,18 +54,18 @@