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
+
+
+ {{ i18n "pages.inbounds.Realitydec" }}
+
+
+
+
+
+
+
+
+ XTLS
+
+
+ {{ i18n "pages.inbounds.XTLSdec" }}
+
+
+
+
@@ -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
@@ -239,7 +240,7 @@
}, {
title: '{{ i18n "pages.inbounds.protocol" }}',
align: 'left',
- width: 70,
+ width: 80,
scopedSlots: { customRender: 'protocol' },
}, {
title: '{{ i18n "clients" }}',
diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml
index 6ef0cc97..6b6e296f 100644
--- a/web/translation/translate.en_US.toml
+++ b/web/translation/translate.en_US.toml
@@ -152,6 +152,8 @@
"IPLimitlogDesc" = "IPs history Log (before enabling inbound after it has been disabled by IP limit, you should clear the log)"
"IPLimitlogclear" = "Clear The Log"
"setDefaultCert" = "Set cert from panel"
+"XTLSdec" = "Xray core needs to be 1.7.5 and below"
+"Realitydec" = "Xray core needs to be 1.8.0 and above"
[pages.client]
"add" = "Add client"
diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml
index 41616755..c7ecb331 100644
--- a/web/translation/translate.fa_IR.toml
+++ b/web/translation/translate.fa_IR.toml
@@ -150,6 +150,8 @@
"IPLimitlogDesc" = "گزارش سابقه ای پی (قبل از فعال کردن ورودی پس از غیرفعال شدن توسط محدودیت ای پی، باید گزارش را پاک کنید)"
"IPLimitlogclear" = "پاک کردن گزارش ها"
"setDefaultCert" = "استفاده از گواهی پنل"
+"XTLSdec" = "هسته Xray باید 1.7.5 و کمتر باشد"
+"Realitydec" = "هسته Xray باید 1.8.0 و بالاتر باشد"
[pages.client]
"add" = "کاربر جدید"
diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml
index ee68bfc8..1d8d28b9 100644
--- a/web/translation/translate.zh_Hans.toml
+++ b/web/translation/translate.zh_Hans.toml
@@ -150,6 +150,8 @@
"IPLimitlogDesc" = "IP 历史日志 (通过IP限制禁用inbound之前,需要清空日志)"
"IPLimitlogclear" = "清除日志"
"setDefaultCert" = "从面板设置证书"
+"XTLSdec" = "Xray核心需要1.7.5及以下版本"
+"Realitydec" = "Xray核心需要1.8.0及以上版本"
[pages.client]
"add" = "添加客户端"