From abb79bd97889e6e75fcd5a3a23e737c993906ffb Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Mon, 10 Apr 2023 19:58:52 +0330 Subject: [PATCH] Reality --- web/assets/js/model/xray.js | 136 ++++++++++++++++++++++++- web/assets/js/util/utils.js | 53 ++++++++++ web/html/xui/form/tls_settings.html | 54 +++++++++- web/html/xui/inbounds.html | 3 +- web/translation/translate.en_US.toml | 2 + web/translation/translate.fa_IR.toml | 2 + web/translation/translate.zh_Hans.toml | 2 + 7 files changed, 244 insertions(+), 8 deletions(-) diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index a7b43e3f..c757f47f 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -91,6 +91,9 @@ const UTLS_FINGERPRINT = { UTLS_RANDOMIZED: "randomized", }; +const bytesToHex = e => Array.from(e).map(e => e.toString(16).padStart(2, 0)).join(''); +const hexToBytes = e => new Uint8Array(e.match(/[0-9a-f]{2}/gi).map(e => parseInt(e, 16))); + const ALPN_OPTION = { H3: "h3", H2: "h2", @@ -596,10 +599,62 @@ TlsStreamSettings.Settings = class extends XrayCommonClass { } }; +class RealityStreamSettings extends XrayCommonClass { + constructor(show = false,xver = 0, fingerprint = UTLS_FINGERPRINT.UTLS_FIREFOX, dest = 'github.io:443', serverNames = 'github.io,www.github.io,', privateKey = RandomUtil.randomX25519PrivateKey(), publicKey = '', minClient = '', + maxClient = '', maxTimediff = 0, shortIds = RandomUtil.randowShortId()) { + super(); + this.show = show; + this.xver = xver; + this.fingerprint = fingerprint; + this.dest = dest; + this.serverNames = serverNames instanceof Array ? serverNames.join(",") : serverNames; + this.privateKey = privateKey; + this.publicKey = RandomUtil.randomX25519PublicKey(this.privateKey); + this.minClient = minClient; + this.maxClient = maxClient; + this.maxTimediff = maxTimediff; + this.shortIds = shortIds instanceof Array ? shortIds.join(",") : shortIds; + + } + + static fromJson(json = {}) { + return new RealityStreamSettings( + json.show, + json.xver, + json.fingerprint, + json.dest, + json.serverNames, + json.privateKey, + json.publicKey, + json.minClient, + json.maxClient, + json.maxTimediff, + json.shortIds + ); + + } + toJson() { + return { + show: this.show, + xver: this.xver, + fingerprint: this.fingerprint, + dest: this.dest, + serverNames: this.serverNames.split(/,|,|\s+/), + privateKey: this.privateKey, + publicKey: this.publicKey, + minClient: this.minClient, + maxClient: this.maxClient, + maxTimediff: this.maxTimediff, + shortIds: this.shortIds.split(/,|,|\s+/) + }; + } +} + class StreamSettings extends XrayCommonClass { constructor(network='tcp', security='none', tlsSettings=new TlsStreamSettings(), + realitySettings = new RealityStreamSettings(), tcpSettings=new TcpStreamSettings(), kcpSettings=new KcpStreamSettings(), wsSettings=new WsStreamSettings(), @@ -611,6 +666,7 @@ class StreamSettings extends XrayCommonClass { this.network = network; this.security = security; this.tls = tlsSettings; + this.reality = realitySettings; this.tcp = tcpSettings; this.kcp = kcpSettings; this.ws = wsSettings; @@ -643,17 +699,34 @@ class StreamSettings extends XrayCommonClass { } } - static fromJson(json={}) { - let tls; - if (json.security === "xtls") { - tls = TlsStreamSettings.fromJson(json.XTLSSettings); + //for Reality + get isReality() { + return this.security === "reality"; + } + + set isReality(isReality) { + if (isReality) { + this.security = "reality"; } else { + this.security = "none"; + } + } + + static fromJson(json = {}) { + let tls, reality; + if (json.security === "xtls") { + tls = TlsStreamSettings.fromJson(json.xtlsSettings); + } else if (json.security === "tls") { tls = TlsStreamSettings.fromJson(json.tlsSettings); } + if (json.security === "reality") { + reality = RealityStreamSettings.fromJson(json.realitySettings) + } return new StreamSettings( json.network, json.security, tls, + reality, TcpStreamSettings.fromJson(json.tcpSettings), KcpStreamSettings.fromJson(json.kcpSettings), WsStreamSettings.fromJson(json.wsSettings), @@ -671,6 +744,7 @@ class StreamSettings extends XrayCommonClass { tlsSettings: this.isTls ? this.tls.toJson() : undefined, XTLSSettings: this.isXTLS ? this.tls.toJson() : undefined, tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined, + realitySettings: this.isReality ? this.reality.toJson() : undefined, kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined, wsSettings: network === 'ws' ? this.ws.toJson() : undefined, httpSettings: network === 'http' ? this.http.toJson() : undefined, @@ -743,6 +817,8 @@ class Inbound extends XrayCommonClass { set tls(isTls) { if (isTls) { + this.xtls = false; + this.reality = false; this.stream.security = 'tls'; } else { this.stream.security = 'none'; @@ -755,12 +831,32 @@ class Inbound extends XrayCommonClass { set XTLS(isXTLS) { if (isXTLS) { + this.xtls = false; + this.reality = false; this.stream.security = 'xtls'; } else { this.stream.security = 'none'; } } + //for Reality + get reality() { + if (this.stream.security === "reality") { + return this.network === "tcp" || this.network === "grpc" || this.network === "http"; + } + return false; + } + + set reality(isReality) { + if (isReality) { + this.tls = false; + this.xtls = false; + this.stream.security = "reality"; + } else { + this.stream.security = "none"; + } + } + get network() { return this.stream.network; } @@ -957,9 +1053,19 @@ class Inbound extends XrayCommonClass { } } + canEnableReality() { + switch (this.protocol) { + case Protocols.VLESS: + break; + default: + return false; + } + return this.network === "tcp" || this.network === "grpc" || this.network === "http"; + } + //this is used for xtls-rprx-vision canEnableTlsFlow() { - if ((this.stream.security === 'tls') && (this.network === "tcp")) { + if (((this.stream.security === 'tls') || (this.stream.security === 'reality')) && (this.network === "tcp")) { switch (this.protocol) { case Protocols.VLESS: return true; @@ -1169,6 +1275,26 @@ class Inbound extends XrayCommonClass { params.set("flow", this.settings.vlesses[clientIndex].flow); } + if (this.reality) { + params.set("security", "reality"); + if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) { + params.set("sni", this.stream.reality.serverNames.split(/,|,|\s+/)[0]); + } + if (this.stream.reality.publicKey != "") { + //params.set("pbk", Ed25519.getPublicKey(this.stream.reality.privateKey)); + params.set("pbk", this.stream.reality.publicKey); + } + if (this.stream.network === 'tcp') { + params.set("flow", this.settings.vlesses[clientIndex].flow); + } + if (this.stream.reality.shortIds != "") { + params.set("sid", this.stream.reality.shortIds); + } + if (this.stream.reality.fingerprint != "") { + params.set("fp", this.stream.reality.fingerprint); + } + } + const link = `vless://${uuid}@${address}:${port}`; const url = new URL(link); for (const [key, value] of params) { diff --git a/web/assets/js/util/utils.js b/web/assets/js/util/utils.js index ec6df22a..405985da 100644 --- a/web/assets/js/util/utils.js +++ b/web/assets/js/util/utils.js @@ -89,6 +89,31 @@ const seq = [ 'U', 'V', 'W', 'X', 'Y', 'Z' ]; +const shortIdSeq = [ + 'a', 'b', 'c', 'd', 'e', 'f', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', +]; + +const x25519Map = new Map( + [ + ['EH2FWe-Ij_FFAa2u9__-aiErLvVIneP601GOCdlyPWw', "goY3OtfaA4UYbiz7Hn0NysI5QJrK0VT_Chg6RLgUPQU"], + ['cKI_6DoMSP1IepeWWXrG3G9nkehl94KYBhagU50g2U0', "VigpKFbSLnHLzBWobZaS1IBmw--giJ51w92y723ajnU"], + ['qM2SNyK3NyHB6deWpEP3ITyCGKQFRTna_mlKP0w1QH0', "HYyIGuyNFslmcnNT7mrDdmuXwn4cm7smE_FZbYguKHQ"], + ['qCWg5GMEDFd3n1nxDswlIpOHoPUXMLuMOIiLUVzubkI', "rJFC3dUjJxMnVZiUGzmf_LFsJUwFWY-CU5RQgFOHCWM"], + ['4NOBxDrEsOhNI3Y3EnVIy_TN-uyBoAjQw6QM0YsOi0s', "CbcY9qc4YuMDJDyyL0OITlU824TBg1O84ClPy27e2RM"], + ['eBvFb0M4HpSOwWjtXV8zliiEs_hg56zX4a2LpuuqpEI', "CjulQ2qVIky7ImIfysgQhNX7s_drGLheCGSkVHcLZhc"], + ['yEpOzQV04NNcycWVeWtRNTzv5TS-ynTuKRacZCH-6U8', "O9RSr5gSdok2K_tobQnf_scyKVqnCx6C4Jrl7_rCZEQ"], + ['CNt6TAUVCwqM6xIBHyni0K3Zqbn2htKQLvLb6XDgh0s', "d9cGLVBrDFS02L2OvkqyqwFZ1Ux3AHs28ehl4Rwiyl0"], + ['EInKw-6Wr0rAHXlxxDuZU5mByIzcD3Z-_iWPzXlUL1k', "LlYD2nNVAvyjNvjZGZh4R8PkMIwkc6EycPTvR2LE0nQ"], + ['GKIKo7rcXVyle-EUHtGIDtYnDsI6osQmOUl3DTJRAGc', "VcqHivYGGoBkcxOI6cSSjQmneltstkb2OhvO53dyhEM"], + ['-FVDzv68IC17fJVlNDlhrrgX44WeBfbhwjWpCQVXGHE', "PGG2EYOvsFt2lAQTD7lqHeRxz2KxvllEDKcUrtizPBU"], + ['0H3OJEYEu6XW7woqy7cKh2vzg6YHkbF_xSDTHKyrsn4', "mzevpYbS8kXengBY5p7tt56QE4tS3lwlwRemmkcQeyc"], + ['8F8XywN6ci44ES6em2Z0fYYxyptB9uaXY9Hc1WSSPE4', "qCZUdWQZ2H33vWXnOkG8NpxBeq3qn5QWXlfCOWBNkkc"], + ['IN0dqfkC10dj-ifRHrg2PmmOrzYs697ajGMwcLbu-1g', "2UW_EO3r7uczPGUUlpJBnMDpDmWUHE2yDzCmXS4sckE"], + ['uIcmks5rAhvBe4dRaJOdeSqgxLGGMZhsGk4J4PEKL2s', "F9WJV_74IZp0Ide4hWjiJXk9FRtBUBkUr3mzU-q1lzk"], + ] +); + class RandomUtil { static randomIntRange(min, max) { @@ -107,6 +132,14 @@ class RandomUtil { return str; } + static randomShortIdSeq(count) { + let str = ''; + for (let i = 0; i < count; ++i) { + str += shortIdSeq[this.randomInt(16)]; + } + return str; + } + static randomLowerAndNum(count) { let str = ''; for (let i = 0; i < count; ++i) { @@ -137,6 +170,26 @@ class RandomUtil { }); } + static randowShortId() { + let str = ''; + str += this.randomShortIdSeq(8) + return str; + } + + static randomX25519PrivateKey() { + let num = x25519Map.size; + let index = this.randomInt(num); + let cntr = 0; + for (let key of x25519Map.keys()) { + if (cntr++ === index) { + return key; + } + } + } + + static randomX25519PublicKey(key) { + return x25519Map.get(key) + } static randomText() { var chars = 'abcdefghijklmnopqrstuvwxyz1234567890'; var string = ''; diff --git a/web/html/xui/form/tls_settings.html b/web/html/xui/form/tls_settings.html index c083aa20..f954b76b 100644 --- a/web/html/xui/form/tls_settings.html +++ b/web/html/xui/form/tls_settings.html @@ -1,11 +1,32 @@ {{define "form/tlsSettings"}} - + - + + + Reality + + + + + + + + + + XTLS + + + + + @@ -72,4 +93,33 @@ + + + + + + + + + + + [[ key ]] + + + + + + + + + + + + + + + + + + {{end}} \ No newline at end of file diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html index 0ea018af..b962efcb 100644 --- a/web/html/xui/inbounds.html +++ b/web/html/xui/inbounds.html @@ -134,6 +134,7 @@ [[ dbInbound.toInbound().stream.network ]] TLS XTLS + Reality