diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 761e5331..b6c0d06e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: alireza0 # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username @@ -10,5 +10,5 @@ liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry polar: # Replace with a single Polar username -buy_me_a_coffee: alireza7 +buy_me_a_coffee: # removed custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ffad183a..f2c332e3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -7,7 +7,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c3f0932e..adc7de2b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - armv5 - 386 - s390x - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -84,7 +84,7 @@ jobs: cd x-ui/bin # Download dependencies - Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v25.1.1/" + Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v25.7.26/" if [ "${{ matrix.platform }}" == "amd64" ]; then wget -q ${Xray_URL}Xray-linux-64.zip unzip Xray-linux-64.zip diff --git a/DockerInitFiles.sh b/DockerInitFiles.sh index 1a9a6693..ca522254 100755 --- a/DockerInitFiles.sh +++ b/DockerInitFiles.sh @@ -23,7 +23,7 @@ case $1 in esac mkdir -p build/bin cd build/bin -wget -q "https://github.com/XTLS/Xray-core/releases/download/v25.1.1/Xray-linux-${ARCH}.zip" +wget -q "https://github.com/XTLS/Xray-core/releases/download/v25.7.26/Xray-linux-${ARCH}.zip" unzip "Xray-linux-${ARCH}.zip" rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat LICENSE README.md mv xray "xray-linux-${FNAME}" diff --git a/Dockerfile b/Dockerfile index a89f8d2f..cb6dd132 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23-alpine AS builder +FROM golang:1.24-alpine AS builder WORKDIR /app ARG TARGETARCH RUN apk --no-cache --update add build-base gcc wget unzip diff --git a/README.md b/README.md index 8a6f65f7..34eb5a03 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ docker build -t x-ui . ## Recommended OS -- Ubuntu 20.04+ +- Ubuntu 22.04+ - Debian 11+ - CentOS 8+ - OpenEuler 22.03+ diff --git a/install.sh b/install.sh index ef9d3293..98f9f5bb 100755 --- a/install.sh +++ b/install.sh @@ -60,8 +60,8 @@ elif [[ "${release}" == "centos" ]]; then echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "ubuntu" ]]; then - if [[ ${os_version} -lt 2004 ]]; then - echo -e "${red} Please use Ubuntu 20 or higher version!${plain}\n" && exit 1 + if [[ ${os_version} -lt 2204 ]]; then + echo -e "${red} Please use Ubuntu 22 or higher version!${plain}\n" && exit 1 fi elif [[ "${release}" == "fedora" ]]; then if [[ ${os_version} -lt 36 ]]; then @@ -72,16 +72,16 @@ elif [[ "${release}" == "amzn" ]]; then echo -e "${red} Please use Amazon Linux 2023!${plain}\n" && exit 1 fi elif [[ "${release}" == "debian" ]]; then - if [[ ${os_version} -lt 11 ]]; then - echo -e "${red} Please use Debian 11 or higher ${plain}\n" && exit 1 + if [[ ${os_version} -lt 12 ]]; then + echo -e "${red} Please use Debian 12 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "almalinux" ]]; then - if [[ ${os_version} -lt 80 ]]; then - echo -e "${red} Please use AlmaLinux 8.0 or higher ${plain}\n" && exit 1 + if [[ ${os_version} -lt 95 ]]; then + echo -e "${red} Please use AlmaLinux 9.5 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "rocky" ]]; then - if [[ ${os_version} -lt 8 ]]; then - echo -e "${red} Please use Rocky Linux 8 or higher ${plain}\n" && exit 1 + if [[ ${os_version} -lt 95 ]]; then + echo -e "${red} Please use Rocky Linux 9.5 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "ol" ]]; then if [[ ${os_version} -lt 8 ]]; then @@ -90,8 +90,8 @@ elif [[ "${release}" == "ol" ]]; then else echo -e "${red}Your operating system is not supported by this script.${plain}\n" echo "Please ensure you are using one of the following supported operating systems:" - echo "- Ubuntu 20.04+" - echo "- Debian 11+" + echo "- Ubuntu 22.04+" + echo "- Debian 12+" echo "- CentOS 8+" echo "- OpenEuler 22.03+" echo "- Fedora 36+" @@ -99,8 +99,8 @@ else echo "- Parch Linux" echo "- Manjaro" echo "- Armbian" - echo "- AlmaLinux 8.0+" - echo "- Rocky Linux 8+" + echo "- AlmaLinux 9.5+" + echo "- Rocky Linux 9.5+" echo "- Oracle Linux 8+" echo "- OpenSUSE Tumbleweed" echo "- Amazon Linux 2023" diff --git a/sub/subJsonService.go b/sub/subJsonService.go index 27749fe4..055a924f 100644 --- a/sub/subJsonService.go +++ b/sub/subJsonService.go @@ -263,6 +263,7 @@ func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]in rltyData["show"] = false rltyData["publicKey"] = rltyClientSettings["publicKey"] rltyData["fingerprint"] = rltyClientSettings["fingerprint"] + rltyData["mldsa65Verify"] = rltyClientSettings["mldsa65Verify"] // Set random data rltyData["spiderX"] = "/" + random.Seq(15) diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js index 4f1bab77..a60bfb0c 100644 --- a/web/assets/js/model/inbound.js +++ b/web/assets/js/model/inbound.js @@ -34,10 +34,6 @@ const TLS_VERSION_OPTION = { }; const TLS_CIPHER_OPTION = { - RSA_AES_128_CBC: "TLS_RSA_WITH_AES_128_CBC_SHA", - RSA_AES_256_CBC: "TLS_RSA_WITH_AES_256_CBC_SHA", - RSA_AES_128_GCM: "TLS_RSA_WITH_AES_128_GCM_SHA256", - RSA_AES_256_GCM: "TLS_RSA_WITH_AES_256_GCM_SHA384", AES_128_GCM: "TLS_AES_128_GCM_SHA256", AES_256_GCM: "TLS_AES_256_GCM_SHA384", CHACHA20_POLY1305: "TLS_CHACHA20_POLY1305_SHA256", @@ -64,6 +60,7 @@ const UTLS_FINGERPRINT = { UTLS_QQ: "qq", UTLS_RANDOM: "random", UTLS_RANDOMIZED: "randomized", + UTLS_RONDOMIZEDNOALPN: "randomizednoalpn", UTLS_UNSAFE: "unsafe", }; @@ -74,16 +71,51 @@ const ALPN_OPTION = { }; const SNIFFING_OPTION = { - HTTP: "http", - TLS: "tls", - QUIC: "quic", + HTTP: "http", + TLS: "tls", + QUIC: "quic", FAKEDNS: "fakedns" }; +const USAGE_OPTION = { + ENCIPHERMENT: "encipherment", + VERIFY: "verify", + ISSUE: "issue", +}; + +const DOMAIN_STRATEGY_OPTION = { + AS_IS: "AsIs", + USE_IP: "UseIP", + USE_IPV6V4: "UseIPv6v4", + USE_IPV6: "UseIPv6", + USE_IPV4V6: "UseIPv4v6", + USE_IPV4: "UseIPv4", + FORCE_IP: "ForceIP", + FORCE_IPV6V4: "ForceIPv6v4", + FORCE_IPV6: "ForceIPv6", + FORCE_IPV4V6: "ForceIPv4v6", + FORCE_IPV4: "ForceIPv4", +}; + +const TCP_CONGESTION_OPTION = { + BBR: "bbr", + CUBIC: "cubic", + RENO: "reno", +}; + +const USERS_SECURITY = { + AES_128_GCM: "aes-128-gcm", + CHACHA20_POLY1305: "chacha20-poly1305", + AUTO: "auto", + NONE: "none", + ZERO: "zero", +}; + const MODE_OPTION = { AUTO: "auto", PACKET_UP: "packet-up", STREAM_UP: "stream-up", + STREAM_ONE: "stream-one", }; Object.freeze(Protocols); @@ -94,9 +126,12 @@ Object.freeze(TLS_CIPHER_OPTION); Object.freeze(UTLS_FINGERPRINT); Object.freeze(ALPN_OPTION); Object.freeze(SNIFFING_OPTION); +Object.freeze(USAGE_OPTION); +Object.freeze(DOMAIN_STRATEGY_OPTION); +Object.freeze(TCP_CONGESTION_OPTION); +Object.freeze(USERS_SECURITY); Object.freeze(MODE_OPTION); - class XrayCommonClass { static toJsonArray(arr) { @@ -111,7 +146,7 @@ class XrayCommonClass { return this; } - toString(format=true) { + toString(format = true) { return format ? JSON.stringify(this.toJson(), null, 2) : JSON.stringify(this.toJson()); } @@ -120,7 +155,7 @@ class XrayCommonClass { if (v2Headers) { Object.keys(v2Headers).forEach(key => { let values = v2Headers[key]; - if (typeof(values) === 'string') { + if (typeof (values) === 'string') { newHeaders.push({ name: key, value: values }); } else { for (let i = 0; i < values.length; ++i) { @@ -132,7 +167,7 @@ class XrayCommonClass { return newHeaders; } - static toV2Headers(headers, arr=true) { + static toV2Headers(headers, arr = true) { let v2Headers = {}; for (let i = 0; i < headers.length; ++i) { let name = headers[i].name; @@ -155,11 +190,12 @@ class XrayCommonClass { } class TcpStreamSettings extends XrayCommonClass { - constructor(acceptProxyProtocol=false, - type='none', - request=new TcpStreamSettings.TcpRequest(), - response=new TcpStreamSettings.TcpResponse(), - ) { + constructor( + acceptProxyProtocol = false, + type = 'none', + request = new TcpStreamSettings.TcpRequest(), + response = new TcpStreamSettings.TcpResponse(), + ) { super(); this.acceptProxyProtocol = acceptProxyProtocol; this.type = type; @@ -167,7 +203,7 @@ class TcpStreamSettings extends XrayCommonClass { this.response = response; } - static fromJson(json={}) { + static fromJson(json = {}) { let header = json.header; if (!header) { header = {}; @@ -192,10 +228,11 @@ class TcpStreamSettings extends XrayCommonClass { } TcpStreamSettings.TcpRequest = class extends XrayCommonClass { - constructor(version='1.1', - method='GET', - path=['/'], - headers=[], + constructor( + version = '1.1', + method = 'GET', + path = ['/'], + headers = [], ) { super(); this.version = version; @@ -220,7 +257,7 @@ TcpStreamSettings.TcpRequest = class extends XrayCommonClass { this.headers.splice(index, 1); } - static fromJson(json={}) { + static fromJson(json = {}) { return new TcpStreamSettings.TcpRequest( json.version, json.method, @@ -240,10 +277,11 @@ TcpStreamSettings.TcpRequest = class extends XrayCommonClass { }; TcpStreamSettings.TcpResponse = class extends XrayCommonClass { - constructor(version='1.1', - status='200', - reason='OK', - headers=[], + constructor( + version = '1.1', + status = '200', + reason = 'OK', + headers = [], ) { super(); this.version = version; @@ -260,7 +298,7 @@ TcpStreamSettings.TcpResponse = class extends XrayCommonClass { this.headers.splice(index, 1); } - static fromJson(json={}) { + static fromJson(json = {}) { return new TcpStreamSettings.TcpResponse( json.version, json.status, @@ -280,15 +318,17 @@ TcpStreamSettings.TcpResponse = class extends XrayCommonClass { }; class KcpStreamSettings extends XrayCommonClass { - constructor(mtu=1350, tti=20, - uplinkCapacity=5, - downlinkCapacity=20, - congestion=false, - readBufferSize=2, - writeBufferSize=2, - type='none', - seed=RandomUtil.randomSeq(10), - ) { + constructor( + mtu = 1350, + tti = 50, + uplinkCapacity = 5, + downlinkCapacity = 20, + congestion = false, + readBufferSize = 2, + writeBufferSize = 2, + type = 'none', + seed = RandomUtil.randomSeq(10), + ) { super(); this.mtu = mtu; this.tti = tti; @@ -301,7 +341,7 @@ class KcpStreamSettings extends XrayCommonClass { this.seed = seed; } - static fromJson(json={}) { + static fromJson(json = {}) { return new KcpStreamSettings( json.mtu, json.tti, @@ -333,12 +373,19 @@ class KcpStreamSettings extends XrayCommonClass { } class WsStreamSettings extends XrayCommonClass { - constructor(acceptProxyProtocol=false, path='/', host='', headers=[]) { + constructor( + acceptProxyProtocol = false, + path = '/', + host = '', + headers = [], + heartbeatPeriod = 0, + ) { super(); this.acceptProxyProtocol = acceptProxyProtocol; this.path = path; this.host = host; this.headers = headers; + this.heartbeatPeriod = heartbeatPeriod; } addHeader(name, value) { @@ -349,12 +396,13 @@ class WsStreamSettings extends XrayCommonClass { this.headers.splice(index, 1); } - static fromJson(json={}) { + static fromJson(json = {}) { return new WsStreamSettings( json.acceptProxyProtocol, json.path, json.host, XrayCommonClass.toHeaders(json.headers), + json.heartbeatPeriod, ); } @@ -364,20 +412,29 @@ class WsStreamSettings extends XrayCommonClass { path: this.path, host: this.host, headers: XrayCommonClass.toV2Headers(this.headers, false), + heartbeatPeriod: this.heartbeatPeriod, }; } } class GrpcStreamSettings extends XrayCommonClass { - constructor(serviceName='', authority='', multiMode=false) { + constructor( + serviceName = "", + authority = "", + multiMode = false, + ) { super(); this.serviceName = serviceName; this.authority = authority; this.multiMode = multiMode; } - static fromJson(json={}) { - return new GrpcStreamSettings(json.serviceName, json.authority, json.multiMode); + static fromJson(json = {}) { + return new GrpcStreamSettings( + json.serviceName, + json.authority, + json.multiMode + ); } toJson() { @@ -390,7 +447,12 @@ class GrpcStreamSettings extends XrayCommonClass { } class HttpUpgradeStreamSettings extends XrayCommonClass { - constructor(acceptProxyProtocol=false, path='/', host='', headers=[]) { + constructor( + acceptProxyProtocol = false, + path = '/', + host = '', + headers = [] + ) { super(); this.acceptProxyProtocol = acceptProxyProtocol; this.path = path; @@ -406,7 +468,7 @@ class HttpUpgradeStreamSettings extends XrayCommonClass { this.headers.splice(index, 1); } - static fromJson(json={}) { + static fromJson(json = {}) { return new HttpUpgradeStreamSettings( json.acceptProxyProtocol, json.path, @@ -424,6 +486,7 @@ class HttpUpgradeStreamSettings extends XrayCommonClass { }; } } + class xHTTPStreamSettings extends XrayCommonClass { constructor( path = '/', @@ -431,6 +494,7 @@ class xHTTPStreamSettings extends XrayCommonClass { headers = [], scMaxBufferedPosts = 30, scMaxEachPostBytes = "1000000", + scStreamUpServerSecs = "20-80", noSSEHeader = false, xPaddingBytes = "100-1000", mode = MODE_OPTION.AUTO, @@ -441,6 +505,7 @@ class xHTTPStreamSettings extends XrayCommonClass { this.headers = headers; this.scMaxBufferedPosts = scMaxBufferedPosts; this.scMaxEachPostBytes = scMaxEachPostBytes; + this.scStreamUpServerSecs = scStreamUpServerSecs; this.noSSEHeader = noSSEHeader; this.xPaddingBytes = xPaddingBytes; this.mode = mode; @@ -461,6 +526,7 @@ class xHTTPStreamSettings extends XrayCommonClass { XrayCommonClass.toHeaders(json.headers), json.scMaxBufferedPosts, json.scMaxEachPostBytes, + json.scStreamUpServerSecs, json.noSSEHeader, json.xPaddingBytes, json.mode, @@ -474,6 +540,7 @@ class xHTTPStreamSettings extends XrayCommonClass { headers: XrayCommonClass.toV2Headers(this.headers, false), scMaxBufferedPosts: this.scMaxBufferedPosts, scMaxEachPostBytes: this.scMaxEachPostBytes, + scStreamUpServerSecs: this.scStreamUpServerSecs, noSSEHeader: this.noSSEHeader, xPaddingBytes: this.xPaddingBytes, mode: this.mode, @@ -482,20 +549,28 @@ class xHTTPStreamSettings extends XrayCommonClass { } class TlsStreamSettings extends XrayCommonClass { - constructor(serverName='', - minVersion = TLS_VERSION_OPTION.TLS12, - maxVersion = TLS_VERSION_OPTION.TLS13, - cipherSuites = '', - rejectUnknownSni = false, - certificates=[new TlsStreamSettings.Cert()], - alpn=[ALPN_OPTION.H2,ALPN_OPTION.HTTP1], - settings=new TlsStreamSettings.Settings()) { + constructor( + serverName = '', + minVersion = TLS_VERSION_OPTION.TLS12, + maxVersion = TLS_VERSION_OPTION.TLS13, + cipherSuites = '', + rejectUnknownSni = false, + verifyPeerCertInNames = ['dns.google', 'cloudflare-dns.com'], + disableSystemRoot = false, + enableSessionResumption = false, + certificates = [new TlsStreamSettings.Cert()], + alpn = [ALPN_OPTION.H3, ALPN_OPTION.H2, ALPN_OPTION.HTTP1], + settings = new TlsStreamSettings.Settings() + ) { super(); this.sni = serverName; this.minVersion = minVersion; this.maxVersion = maxVersion; this.cipherSuites = cipherSuites; this.rejectUnknownSni = rejectUnknownSni; + this.verifyPeerCertInNames = Array.isArray(verifyPeerCertInNames) ? verifyPeerCertInNames.join(",") : verifyPeerCertInNames; + this.disableSystemRoot = disableSystemRoot; + this.enableSessionResumption = enableSessionResumption; this.certs = certificates; this.alpn = alpn; this.settings = settings; @@ -509,15 +584,15 @@ class TlsStreamSettings extends XrayCommonClass { this.certs.splice(index, 1); } - static fromJson(json={}) { + 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)) { - settings = new TlsStreamSettings.Settings(json.settings.allowInsecure , json.settings.fingerprint, json.settings.serverName, json.settings.domains); + if (!ObjectUtil.isEmpty(json.settings)) { + settings = new TlsStreamSettings.Settings(json.settings.allowInsecure, json.settings.fingerprint, json.settings.serverName, json.settings.domains); } return new TlsStreamSettings( json.serverName, @@ -525,6 +600,9 @@ class TlsStreamSettings extends XrayCommonClass { json.maxVersion, json.cipherSuites, json.rejectUnknownSni, + json.verifyPeerCertInNames, + json.disableSystemRoot, + json.enableSessionResumption, certs, json.alpn, settings, @@ -538,6 +616,9 @@ class TlsStreamSettings extends XrayCommonClass { maxVersion: this.maxVersion, cipherSuites: this.cipherSuites, rejectUnknownSni: this.rejectUnknownSni, + verifyPeerCertInNames: this.verifyPeerCertInNames.split(","), + disableSystemRoot: this.disableSystemRoot, + enableSessionResumption: this.enableSessionResumption, certificates: TlsStreamSettings.toJsonArray(this.certs), alpn: this.alpn, settings: this.settings, @@ -546,23 +627,39 @@ class TlsStreamSettings extends XrayCommonClass { } TlsStreamSettings.Cert = class extends XrayCommonClass { - constructor(useFile=true, certificateFile='', keyFile='', certificate='', key='', ocspStapling=3600) { + constructor( + useFile = true, + certificateFile = '', + keyFile = '', + certificate = '', + key = '', + ocspStapling = 0, + oneTimeLoading = false, + usage = USAGE_OPTION.ENCIPHERMENT, + buildChain = false, + ) { super(); this.useFile = useFile; this.certFile = certificateFile; this.keyFile = keyFile; - this.cert = certificate instanceof Array ? certificate.join('\n') : certificate; - this.key = key instanceof Array ? key.join('\n') : key; + this.cert = Array.isArray(certificate) ? certificate.join('\n') : certificate; + this.key = Array.isArray(key) ? key.join('\n') : key; this.ocspStapling = ocspStapling; + this.oneTimeLoading = oneTimeLoading; + this.usage = usage; + this.buildChain = buildChain } - static fromJson(json={}) { + static fromJson(json = {}) { if ('certificateFile' in json && 'keyFile' in json) { return new TlsStreamSettings.Cert( true, json.certificateFile, json.keyFile, '', '', json.ocspStapling, + json.oneTimeLoading, + json.usage, + json.buildChain, ); } else { return new TlsStreamSettings.Cert( @@ -570,6 +667,9 @@ TlsStreamSettings.Cert = class extends XrayCommonClass { json.certificate.join('\n'), json.key.join('\n'), json.ocspStapling, + json.oneTimeLoading, + json.usage, + json.buildChain, ); } } @@ -580,12 +680,18 @@ TlsStreamSettings.Cert = class extends XrayCommonClass { certificateFile: this.certFile, keyFile: this.keyFile, ocspStapling: this.ocspStapling, + oneTimeLoading: this.oneTimeLoading, + usage: this.usage, + buildChain: this.buildChain, }; } else { return { certificate: this.cert.split('\n'), key: this.key.split('\n'), ocspStapling: this.ocspStapling, + oneTimeLoading: this.oneTimeLoading, + usage: this.usage, + buildChain: this.buildChain, }; } } @@ -595,7 +701,7 @@ TlsStreamSettings.Settings = class extends XrayCommonClass { constructor( allowInsecure = false, fingerprint = UTLS_FINGERPRINT.UTLS_CHROME, - ) { + ) { super(); this.allowInsecure = allowInsecure; this.fingerprint = fingerprint; @@ -614,13 +720,21 @@ TlsStreamSettings.Settings = class extends XrayCommonClass { } }; + class RealityStreamSettings extends XrayCommonClass { - constructor(show = false, xver = 0, + constructor( + show = false, + xver = 0, dest = 'microsoft.com:443', serverNames = 'microsoft.com,www.microsoft.com', - privateKey = '', minClient = '', maxClient = '', - maxTimediff = 0, shortIds = RandomUtil.randomShortId(), - settings= new RealityStreamSettings.Settings()) { + privateKey = '', + minClient = '', + maxClient = '', + maxTimediff = 0, + shortIds = RandomUtil.randomShortId(), + mldsa65Seed = '', + settings = new RealityStreamSettings.Settings() + ) { super(); this.show = show; this.xver = xver; @@ -631,13 +745,20 @@ class RealityStreamSettings extends XrayCommonClass { this.maxClient = maxClient; this.maxTimediff = maxTimediff; this.shortIds = shortIds instanceof Array ? shortIds.join(",") : shortIds; + this.mldsa65Seed = mldsa65Seed; this.settings = settings; } static fromJson(json = {}) { let settings; - if (!ObjectUtil.isEmpty(json.settings)) { - settings = new RealityStreamSettings.Settings(json.settings.publicKey , json.settings.fingerprint, json.settings.serverName, json.settings.spiderX); + if (!ObjectUtil.isEmpty(json.settings)) { + settings = new RealityStreamSettings.Settings( + json.settings.publicKey, + json.settings.fingerprint, + json.settings.serverName, + json.settings.spiderX, + json.settings.mldsa65Verify, + ); } return new RealityStreamSettings( json.show, @@ -649,10 +770,11 @@ class RealityStreamSettings extends XrayCommonClass { json.maxClient, json.maxTimediff, json.shortIds, - json.settings, + json.mldsa65Seed, + settings, ); - } + toJson() { return { show: this.show, @@ -664,6 +786,7 @@ class RealityStreamSettings extends XrayCommonClass { maxClient: this.maxClient, maxTimediff: this.maxTimediff, shortIds: this.shortIds.split(","), + mldsa65Seed: this.mldsa65Seed, settings: this.settings, }; } @@ -674,13 +797,15 @@ RealityStreamSettings.Settings = class extends XrayCommonClass { publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_CHROME, serverName = '', - spiderX = '/' + spiderX = '/', + mldsa65Verify = '' ) { super(); this.publicKey = publicKey; this.fingerprint = fingerprint; this.serverName = serverName; this.spiderX = spiderX; + this.mldsa65Verify = mldsa65Verify; } static fromJson(json = {}) { return new RealityStreamSettings.Settings( @@ -688,6 +813,7 @@ RealityStreamSettings.Settings = class extends XrayCommonClass { json.fingerprint, json.serverName, json.spiderX, + json.mldsa65Verify ); } toJson() { @@ -696,17 +822,47 @@ RealityStreamSettings.Settings = class extends XrayCommonClass { fingerprint: this.fingerprint, serverName: this.serverName, spiderX: this.spiderX, + mldsa65Verify: this.mldsa65Verify }; } }; class SockoptStreamSettings extends XrayCommonClass { - constructor(acceptProxyProtocol = false, tcpFastOpen = false, mark = 0, tproxy="off") { + constructor( + acceptProxyProtocol = false, + tcpFastOpen = false, + mark = 0, + tproxy = "off", + tcpMptcp = false, + penetrate = false, + domainStrategy = DOMAIN_STRATEGY_OPTION.USE_IP, + tcpMaxSeg = 1440, + dialerProxy = "", + tcpKeepAliveInterval = 0, + tcpKeepAliveIdle = 300, + tcpUserTimeout = 10000, + tcpcongestion = TCP_CONGESTION_OPTION.BBR, + V6Only = false, + tcpWindowClamp = 600, + interfaceName = "", + ) { super(); this.acceptProxyProtocol = acceptProxyProtocol; this.tcpFastOpen = tcpFastOpen; this.mark = mark; this.tproxy = tproxy; + this.tcpMptcp = tcpMptcp; + this.penetrate = penetrate; + this.domainStrategy = domainStrategy; + this.tcpMaxSeg = tcpMaxSeg; + this.dialerProxy = dialerProxy; + this.tcpKeepAliveInterval = tcpKeepAliveInterval; + this.tcpKeepAliveIdle = tcpKeepAliveIdle; + this.tcpUserTimeout = tcpUserTimeout; + this.tcpcongestion = tcpcongestion; + this.V6Only = V6Only; + this.tcpWindowClamp = tcpWindowClamp; + this.interfaceName = interfaceName; } static fromJson(json = {}) { @@ -716,6 +872,18 @@ class SockoptStreamSettings extends XrayCommonClass { json.tcpFastOpen, json.mark, json.tproxy, + json.tcpMptcp, + json.penetrate, + json.domainStrategy, + json.tcpMaxSeg, + json.dialerProxy, + json.tcpKeepAliveInterval, + json.tcpKeepAliveIdle, + json.tcpUserTimeout, + json.tcpcongestion, + json.V6Only, + json.tcpWindowClamp, + json.interface, ); } @@ -725,24 +893,36 @@ class SockoptStreamSettings extends XrayCommonClass { tcpFastOpen: this.tcpFastOpen, mark: this.mark, tproxy: this.tproxy, + tcpMptcp: this.tcpMptcp, + penetrate: this.penetrate, + domainStrategy: this.domainStrategy, + tcpMaxSeg: this.tcpMaxSeg, + dialerProxy: this.dialerProxy, + tcpKeepAliveInterval: this.tcpKeepAliveInterval, + tcpKeepAliveIdle: this.tcpKeepAliveIdle, + tcpUserTimeout: this.tcpUserTimeout, + tcpcongestion: this.tcpcongestion, + V6Only: this.V6Only, + tcpWindowClamp: this.tcpWindowClamp, + interface: this.interfaceName, }; } } class StreamSettings extends XrayCommonClass { - constructor(network='tcp', - security='none', - externalProxy = [], - tlsSettings=new TlsStreamSettings(), - realitySettings = new RealityStreamSettings(), - tcpSettings=new TcpStreamSettings(), - kcpSettings=new KcpStreamSettings(), - wsSettings=new WsStreamSettings(), - grpcSettings=new GrpcStreamSettings(), - httpupgradeSettings=new HttpUpgradeStreamSettings(), - xhttpSettings=new xHTTPStreamSettings(), - sockopt = undefined, - ) { + constructor(network = 'tcp', + security = 'none', + externalProxy = [], + tlsSettings = new TlsStreamSettings(), + realitySettings = new RealityStreamSettings(), + tcpSettings = new TcpStreamSettings(), + kcpSettings = new KcpStreamSettings(), + wsSettings = new WsStreamSettings(), + grpcSettings = new GrpcStreamSettings(), + httpupgradeSettings = new HttpUpgradeStreamSettings(), + xhttpSettings = new xHTTPStreamSettings(), + sockopt = undefined, + ) { super(); this.network = network; this.security = security; @@ -759,7 +939,7 @@ class StreamSettings extends XrayCommonClass { } get isTls() { - return this.security === 'tls'; + return this.security === "tls"; } set isTls(isTls) { @@ -770,6 +950,7 @@ class StreamSettings extends XrayCommonClass { } } + //for Reality get isReality() { return this.security === "reality"; } @@ -790,7 +971,7 @@ class StreamSettings extends XrayCommonClass { this.sockopt = value ? new SockoptStreamSettings() : undefined; } - static fromJson(json={}) { + static fromJson(json = {}) { return new StreamSettings( json.network, json.security, @@ -828,10 +1009,10 @@ class StreamSettings extends XrayCommonClass { class Sniffing extends XrayCommonClass { constructor( - enabled=false, - destOverride=['http', 'tls', 'quic', 'fakedns'], - metadataOnly=false, - routeOnly=false) { + enabled = false, + destOverride = ['http', 'tls', 'quic', 'fakedns'], + metadataOnly = false, + routeOnly = false) { super(); this.enabled = enabled; this.destOverride = destOverride; @@ -839,7 +1020,7 @@ class Sniffing extends XrayCommonClass { this.routeOnly = routeOnly; } - static fromJson(json={}) { + static fromJson(json = {}) { let destOverride = ObjectUtil.clone(json.destOverride); if (!ObjectUtil.isEmpty(destOverride) && !ObjectUtil.isArrEmpty(destOverride)) { if (ObjectUtil.isEmpty(destOverride[0])) { @@ -856,15 +1037,16 @@ class Sniffing extends XrayCommonClass { } class Inbound extends XrayCommonClass { - constructor(port=RandomUtil.randomIntRange(10000, 60000), - listen='', - protocol=Protocols.VLESS, - settings=null, - streamSettings=new StreamSettings(), - tag='', - sniffing=new Sniffing(), - clientStats='', - ) { + constructor( + port = RandomUtil.randomIntRange(10000, 60000), + listen = '', + protocol = Protocols.VLESS, + settings = null, + streamSettings = new StreamSettings(), + tag = '', + sniffing = new Sniffing(), + clientStats = '', + ) { super(); this.port = port; this.listen = listen; @@ -897,7 +1079,7 @@ class Inbound extends XrayCommonClass { this._protocol = protocol; this.settings = Inbound.Settings.getSettings(protocol); if (protocol === Protocols.TROJAN) { - this.stream.isTls = true; + this.tls = false; } } @@ -928,7 +1110,7 @@ class Inbound extends XrayCommonClass { get isHttpupgrade() { return this.network === "httpupgrade"; } - + get isXHTTP() { return this.network === "xhttp"; } @@ -939,7 +1121,7 @@ class Inbound extends XrayCommonClass { case Protocols.SHADOWSOCKS: return this.settings.method; default: - return ''; + return ""; } } get isSSMultiUser() { @@ -968,11 +1150,11 @@ class Inbound extends XrayCommonClass { if (this.isTcp) { return this.getHeader(this.stream.tcp.request, 'host'); } else if (this.isWs) { - return this.stream.ws.host?.length>0 ? this.stream.ws.host : this.getHeader(this.stream.ws, 'host'); + return this.stream.ws.host?.length > 0 ? this.stream.ws.host : this.getHeader(this.stream.ws, 'host'); } else if (this.isHttpupgrade) { - return this.stream.httpupgrade.host?.length>0 ? this.stream.httpupgrade.host : this.getHeader(this.stream.httpupgrade, 'host'); + return this.stream.httpupgrade.host?.length > 0 ? this.stream.httpupgrade.host : this.getHeader(this.stream.httpupgrade, 'host'); } else if (this.isXHTTP) { - return this.stream.xhttp.host?.length>0 ? this.stream.xhttp.host : this.getHeader(this.stream.xhttp, 'host'); + return this.stream.xhttp.host?.length > 0 ? this.stream.xhttp.host : this.getHeader(this.stream.xhttp, 'host'); } return null; } @@ -990,7 +1172,6 @@ class Inbound extends XrayCommonClass { return null; } - get kcpType() { return this.stream.kcp.type; } @@ -1009,20 +1190,20 @@ class Inbound extends XrayCommonClass { } canEnableTls() { - if(![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol)) return false; - return ["tcp", "ws", "http", "grpc", "httpupgrade" , "xhttp"].includes(this.network); + if (![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol)) return false; + return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.network); } //this is used for xtls-rprx-vision canEnableTlsFlow() { - if ((this.stream.security != 'none') && (this.network === "tcp")) { + if (((this.stream.security === 'tls') || (this.stream.security === 'reality')) && (this.network === "tcp")) { return this.protocol === Protocols.VLESS; } return false; } canEnableReality() { - if(![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false; + if (![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false; return ["tcp", "http", "grpc", "xhttp"].includes(this.network); } @@ -1040,20 +1221,20 @@ 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') { @@ -1062,7 +1243,7 @@ class Inbound extends XrayCommonClass { if (tcp.type === 'http') { const request = tcp.request; obj.path = request.path.join(','); - const host = this.getHeader(request,'host'); + const host = this.getHeader(request, 'host'); if (host) obj.host = host; } } else if (network === 'kcp') { @@ -1072,47 +1253,43 @@ class Inbound extends XrayCommonClass { } else if (network === 'ws') { const ws = this.stream.ws; obj.path = ws.path; - obj.host = ws.host?.length>0 ? ws.host : this.getHeader(ws, 'host'); - } else if (network === 'http') { - obj.net = 'h2'; - obj.path = this.stream.http.path; - obj.host = this.stream.http.host.join(','); + obj.host = ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host'); } else if (network === 'grpc') { obj.path = this.stream.grpc.serviceName; obj.authority = this.stream.grpc.authority; - if (this.stream.grpc.multiMode){ + if (this.stream.grpc.multiMode) { obj.type = 'multi' } } else if (network === 'httpupgrade') { const httpupgrade = this.stream.httpupgrade; obj.path = httpupgrade.path; - obj.host = httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host'); + obj.host = httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host'); } else if (network === 'xhttp') { const xhttp = this.stream.xhttp; obj.path = xhttp.path; - obj.host = xhttp.host?.length>0 ? xhttp.host : this.getHeader(xhttp, 'host'); - obj.mode = xhttp.mode; + obj.host = xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host'); + obj.type = xhttp.mode; } - if (security === 'tls') { - if (!ObjectUtil.isEmpty(this.stream.tls.sni)){ + if (tls === 'tls') { + if (!ObjectUtil.isEmpty(this.stream.tls.sni)) { obj.sni = this.stream.tls.sni; } - if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerprint)){ + if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerprint)) { obj.fp = this.stream.tls.settings.fingerprint; } - if (this.stream.tls.alpn.length>0){ + if (this.stream.tls.alpn.length > 0) { obj.alpn = this.stream.tls.alpn.join(','); } - if (this.stream.tls.settings.allowInsecure){ + if (this.stream.tls.settings.allowInsecure) { obj.allowInsecure = this.stream.tls.settings.allowInsecure; } } - - return 'vmess://' + base64(JSON.stringify(obj, null, 2)); + + return 'vmess://' + Base64.encode(JSON.stringify(obj, null, 2)); } - genVLESSLink(address = '', port=this.port, forceTls, remark='', clientId, flow) { + 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; @@ -1140,38 +1317,38 @@ class Inbound extends XrayCommonClass { case "ws": const ws = this.stream.ws; params.set("path", ws.path); - params.set("host", ws.host?.length>0 ? ws.host : this.getHeader(ws, 'host')); + params.set("host", ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host')); break; case "grpc": const grpc = this.stream.grpc; params.set("serviceName", grpc.serviceName); params.set("authority", grpc.authority); - if(grpc.multiMode){ + if (grpc.multiMode) { params.set("mode", "multi"); } break; case "httpupgrade": - const httpupgrade = this.stream.httpupgrade; - params.set("path", httpupgrade.path); - params.set("host", httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); break; case "xhttp": - const xhttp = this.stream.xhttp; - params.set("path", xhttp.path); - params.set("host", xhttp.host?.length>0 ? xhttp.host : this.getHeader(xhttp, 'host')); - params.set("mode", xhttp.mode); + const xhttp = this.stream.xhttp; + params.set("path", xhttp.path); + params.set("host", xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host')); + params.set("mode", xhttp.mode); break; } if (security === 'tls') { params.set("security", "tls"); - if (this.stream.isTls){ - params.set("fp" , this.stream.tls.settings.fingerprint); + 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){ + if (this.stream.tls.settings.allowInsecure) { params.set("allowInsecure", "1"); } - if (!ObjectUtil.isEmpty(this.stream.tls.sni)){ + if (!ObjectUtil.isEmpty(this.stream.tls.sni)) { params.set("sni", this.stream.tls.sni); } if (type == "tcp" && !ObjectUtil.isEmpty(flow)) { @@ -1211,7 +1388,7 @@ class Inbound extends XrayCommonClass { return url.toString(); } - genSSLink(address='', port=this.port, forceTls, remark='', clientPassword) { + genSSLink(address = '', port = this.port, forceTls, remark = '', clientPassword) { let settings = this.settings; const type = this.stream.network; const security = forceTls == 'same' ? this.stream.security : forceTls; @@ -1239,38 +1416,38 @@ class Inbound extends XrayCommonClass { case "ws": const ws = this.stream.ws; params.set("path", ws.path); - params.set("host", ws.host?.length>0 ? ws.host : this.getHeader(ws, 'host')); + params.set("host", ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host')); break; case "grpc": const grpc = this.stream.grpc; params.set("serviceName", grpc.serviceName); params.set("authority", grpc.authority); - if(grpc.multiMode){ + if (grpc.multiMode) { params.set("mode", "multi"); } break; case "httpupgrade": - const httpupgrade = this.stream.httpupgrade; - params.set("path", httpupgrade.path); - params.set("host", httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); break; case "xhttp": - const xhttp = this.stream.xhttp; - params.set("path", xhttp.path); - params.set("host", xhttp.host?.length>0 ? xhttp.host : this.getHeader(xhttp, 'host')); - params.set("mode", xhttp.mode); + const xhttp = this.stream.xhttp; + params.set("path", xhttp.path); + params.set("host", xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host')); + params.set("mode", xhttp.mode); break; } if (security === 'tls') { params.set("security", "tls"); - if (this.stream.isTls){ - params.set("fp" , this.stream.tls.settings.fingerprint); + 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){ + if (this.stream.tls.settings.allowInsecure) { params.set("allowInsecure", "1"); } - if (!ObjectUtil.isEmpty(this.stream.tls.sni)){ + if (!ObjectUtil.isEmpty(this.stream.tls.sni)) { params.set("sni", this.stream.tls.sni); } } @@ -1290,7 +1467,7 @@ class Inbound extends XrayCommonClass { return url.toString(); } - genTrojanLink(address = '', port=this.port, forceTls, remark = '', clientPassword) { + 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(); @@ -1317,38 +1494,38 @@ class Inbound extends XrayCommonClass { case "ws": const ws = this.stream.ws; params.set("path", ws.path); - params.set("host", ws.host?.length>0 ? ws.host : this.getHeader(ws, 'host')); + params.set("host", ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host')); break; case "grpc": const grpc = this.stream.grpc; params.set("serviceName", grpc.serviceName); params.set("authority", grpc.authority); - if(grpc.multiMode){ + if (grpc.multiMode) { params.set("mode", "multi"); } break; case "httpupgrade": - const httpupgrade = this.stream.httpupgrade; - params.set("path", httpupgrade.path); - params.set("host", httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); break; case "xhttp": - const xhttp = this.stream.xhttp; - params.set("path", xhttp.path); - params.set("host", xhttp.host?.length>0 ? xhttp.host : this.getHeader(xhttp, 'host')); - params.set("mode", xhttp.mode); + const xhttp = this.stream.xhttp; + params.set("path", xhttp.path); + params.set("host", xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host')); + params.set("mode", xhttp.mode); break; } if (security === 'tls') { params.set("security", "tls"); - if (this.stream.isTls){ - params.set("fp" , this.stream.tls.settings.fingerprint); + 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){ + if (this.stream.tls.settings.allowInsecure) { params.set("allowInsecure", "1"); } - if (!ObjectUtil.isEmpty(this.stream.tls.sni)){ + if (!ObjectUtil.isEmpty(this.stream.tls.sni)) { params.set("sni", this.stream.tls.sni); } } @@ -1368,6 +1545,7 @@ class Inbound extends XrayCommonClass { params.set("spx", this.stream.reality.settings.spiderX); } } + else { params.set("security", "none"); } @@ -1403,13 +1581,13 @@ class Inbound extends XrayCommonClass { return txt; } - genLink(address='', port=this.port, forceTls='same', remark='', client) { + 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: + case Protocols.SHADOWSOCKS: return this.genSSLink(address, port, forceTls, remark, this.isSSMultiUser ? client.password : ''); case Protocols.TROJAN: return this.genTrojanLink(address, port, forceTls, remark, client.password); @@ -1417,7 +1595,7 @@ class Inbound extends XrayCommonClass { } } - genAllLinks(remark='', remarkModel = '-ieo', client){ + genAllLinks(remark = '', remarkModel = '-ieo', client) { let result = []; let email = client ? client.email : ''; let addr = !ObjectUtil.isEmpty(this.listen) && this.listen !== "0.0.0.0" ? this.listen : location.hostname; @@ -1428,8 +1606,8 @@ class Inbound extends XrayCommonClass { 'i': remark, 'e': email, 'o': '', - }; - if(ObjectUtil.isArrEmpty(this.stream.externalProxy)){ + }; + if (ObjectUtil.isArrEmpty(this.stream.externalProxy)) { let r = orderChars.split('').map(char => orders[char]).filter(x => x.length > 0).join(separationChar); result.push({ remark: r, @@ -1450,20 +1628,20 @@ class Inbound extends XrayCommonClass { genInboundLinks(remark = '', remarkModel = '-ieo') { let addr = !ObjectUtil.isEmpty(this.listen) && this.listen !== "0.0.0.0" ? this.listen : location.hostname; - if(this.clients){ - let links = []; - this.clients.forEach((client) => { - this.genAllLinks(remark,remarkModel,client).forEach(l => { + if (this.clients) { + let links = []; + this.clients.forEach((client) => { + this.genAllLinks(remark, remarkModel, client).forEach(l => { links.push(l.link); }) }); return links.join('\r\n'); } else { - if(this.protocol == Protocols.SHADOWSOCKS && !this.isSSMultiUser) return this.genSSLink(addr, this.port, 'same', remark); - if(this.protocol == Protocols.WIREGUARD) { + if (this.protocol == Protocols.SHADOWSOCKS && !this.isSSMultiUser) return this.genSSLink(addr, this.port, 'same', remark); + if (this.protocol == Protocols.WIREGUARD) { let links = []; - this.settings.peers.forEach((p,index) => { - links.push(this.getWireguardLink(addr,this.port,remark + remarkModel.charAt(0) + (index+1),index)); + this.settings.peers.forEach((p, index) => { + links.push(this.getWireguardLink(addr, this.port, remark + remarkModel.charAt(0) + (index + 1), index)); }); return links.join('\r\n'); } @@ -1471,7 +1649,7 @@ class Inbound extends XrayCommonClass { } } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound( json.port, json.listen, @@ -1579,10 +1757,22 @@ Inbound.VmessSettings = class extends Inbound.Settings { }; } }; + Inbound.VmessSettings.Vmess = class extends XrayCommonClass { - constructor(id=RandomUtil.randomUUID(), email=RandomUtil.randomLowerAndNum(9), totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { + constructor( + id = RandomUtil.randomUUID(), + security = USERS_SECURITY.AUTO, + email = RandomUtil.randomLowerAndNum(8), + totalGB = 0, + expiryTime = 0, + enable = true, + tgId = '', + subId = RandomUtil.randomLowerAndNum(16), + reset = 0 + ) { super(); this.id = id; + this.security = security; this.email = email; this.totalGB = totalGB; this.expiryTime = expiryTime; @@ -1592,9 +1782,10 @@ Inbound.VmessSettings.Vmess = class extends XrayCommonClass { this.reset = reset; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.VmessSettings.Vmess( json.id, + json.security, json.email, json.totalGB, json.expiryTime, @@ -1608,7 +1799,7 @@ Inbound.VmessSettings.Vmess = class extends XrayCommonClass { if (this.expiryTime === 0 || this.expiryTime === '') { return null; } - if (this.expiryTime < 0){ + if (this.expiryTime < 0) { return this.expiryTime / -86400000; } return moment(this.expiryTime); @@ -1632,10 +1823,12 @@ Inbound.VmessSettings.Vmess = class extends XrayCommonClass { }; Inbound.VLESSSettings = class extends Inbound.Settings { - constructor(protocol, - vlesses=[new Inbound.VLESSSettings.VLESS()], - decryption='none', - fallbacks=[],) { + constructor( + protocol, + vlesses = [new Inbound.VLESSSettings.VLESS()], + decryption = 'none', + fallbacks = [] + ) { super(protocol); this.vlesses = vlesses; this.decryption = decryption; @@ -1651,26 +1844,35 @@ Inbound.VLESSSettings = class extends Inbound.Settings { } // decryption should be set to static value - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.VLESSSettings( Protocols.VLESS, json.clients.map(client => Inbound.VLESSSettings.VLESS.fromJson(client)), - 'none', - Inbound.VLESSSettings.Fallback.fromJson(json.fallbacks), - ); + json.decryption || 'none', + Inbound.VLESSSettings.Fallback.fromJson(json.fallbacks),); } toJson() { return { clients: Inbound.VLESSSettings.toJsonArray(this.vlesses), - decryption: 'none', + decryption: this.decryption, fallbacks: Inbound.VLESSSettings.toJsonArray(this.fallbacks), }; } - }; + Inbound.VLESSSettings.VLESS = class extends XrayCommonClass { - constructor(id=RandomUtil.randomUUID(), flow='', email=RandomUtil.randomLowerAndNum(9), totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { + constructor( + id = RandomUtil.randomUUID(), + flow = '', + email = RandomUtil.randomLowerAndNum(8), + totalGB = 0, + expiryTime = 0, + enable = true, + tgId = '', + subId = RandomUtil.randomLowerAndNum(16), + reset = 0 + ) { super(); this.id = id; this.flow = flow; @@ -1683,7 +1885,7 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass { this.reset = reset; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.VLESSSettings.VLESS( json.id, json.flow, @@ -1695,13 +1897,13 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass { json.subId, json.reset, ); - } + } get _expiryTime() { if (this.expiryTime === 0 || this.expiryTime === '') { return null; } - if (this.expiryTime < 0){ + if (this.expiryTime < 0) { return this.expiryTime / -86400000; } return moment(this.expiryTime); @@ -1746,7 +1948,7 @@ Inbound.VLESSSettings.Fallback = class extends XrayCommonClass { } } - static fromJson(json=[]) { + static fromJson(json = []) { const fallbacks = []; for (let fallback of json) { fallbacks.push(new Inbound.VLESSSettings.Fallback( @@ -1763,8 +1965,8 @@ Inbound.VLESSSettings.Fallback = class extends XrayCommonClass { Inbound.TrojanSettings = class extends Inbound.Settings { constructor(protocol, - trojans=[new Inbound.TrojanSettings.Trojan()], - fallbacks=[],) { + trojans = [new Inbound.TrojanSettings.Trojan()], + fallbacks = [],) { super(protocol); this.trojans = trojans; this.fallbacks = fallbacks; @@ -1778,7 +1980,7 @@ Inbound.TrojanSettings = class extends Inbound.Settings { this.fallbacks.splice(index, 1); } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.TrojanSettings( Protocols.TROJAN, json.clients.map(client => Inbound.TrojanSettings.Trojan.fromJson(client)), @@ -1788,12 +1990,22 @@ Inbound.TrojanSettings = class extends Inbound.Settings { toJson() { return { clients: Inbound.TrojanSettings.toJsonArray(this.trojans), - fallbacks: Inbound.TrojanSettings.toJsonArray(this.fallbacks), + fallbacks: Inbound.TrojanSettings.toJsonArray(this.fallbacks) }; } }; + Inbound.TrojanSettings.Trojan = class extends XrayCommonClass { - constructor(password=RandomUtil.randomSeq(10), email=RandomUtil.randomLowerAndNum(9), totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { + constructor( + password = RandomUtil.randomSeq(10), + email = RandomUtil.randomLowerAndNum(8), + totalGB = 0, + expiryTime = 0, + enable = true, + tgId = '', + subId = RandomUtil.randomLowerAndNum(16), + reset = 0 + ) { super(); this.password = password; this.email = email; @@ -1835,7 +2047,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass { if (this.expiryTime === 0 || this.expiryTime === '') { return null; } - if (this.expiryTime < 0){ + if (this.expiryTime < 0) { return this.expiryTime / -86400000; } return moment(this.expiryTime); @@ -1882,7 +2094,7 @@ Inbound.TrojanSettings.Fallback = class extends XrayCommonClass { } } - static fromJson(json=[]) { + static fromJson(json = []) { const fallbacks = []; for (let fallback of json) { fallbacks.push(new Inbound.TrojanSettings.Fallback( @@ -1899,11 +2111,11 @@ Inbound.TrojanSettings.Fallback = class extends XrayCommonClass { Inbound.ShadowsocksSettings = class extends Inbound.Settings { constructor(protocol, - method=SSMethods.BLAKE3_AES_256_GCM, - password=RandomUtil.randomShadowsocksPassword(), - network='tcp,udp', - shadowsockses=[new Inbound.ShadowsocksSettings.Shadowsocks()], - ivCheck = false, + method = SSMethods.BLAKE3_AES_256_GCM, + password = RandomUtil.randomShadowsocksPassword(), + network = 'tcp,udp', + shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()], + ivCheck = false, ) { super(protocol); this.method = method; @@ -1913,7 +2125,7 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings { this.ivCheck = ivCheck; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.ShadowsocksSettings( Protocols.SHADOWSOCKS, json.method, @@ -1936,7 +2148,17 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings { }; Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { - constructor(method='', password=RandomUtil.randomShadowsocksPassword(), email=RandomUtil.randomLowerAndNum(9), totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { + constructor( + method = '', + password = RandomUtil.randomShadowsocksPassword(), + email = RandomUtil.randomLowerAndNum(8), + totalGB = 0, + expiryTime = 0, + enable = true, + tgId = '', + subId = RandomUtil.randomLowerAndNum(16), + reset = 0 + ) { super(); this.method = method; this.password = password; @@ -1981,7 +2203,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { if (this.expiryTime === 0 || this.expiryTime === '') { return null; } - if (this.expiryTime < 0){ + if (this.expiryTime < 0) { return this.expiryTime / -86400000; } return moment(this.expiryTime); @@ -2005,7 +2227,13 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { }; Inbound.DokodemoSettings = class extends Inbound.Settings { - constructor(protocol, address, port, network='tcp,udp', followRedirect=false) { + constructor( + protocol, + address, + port, + network = 'tcp,udp', + followRedirect = false + ) { super(protocol); this.address = address; this.port = port; @@ -2013,13 +2241,13 @@ Inbound.DokodemoSettings = class extends Inbound.Settings { this.followRedirect = followRedirect; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.DokodemoSettings( Protocols.DOKODEMO, json.address, json.port, json.network, - json.followRedirect + json.followRedirect, ); } @@ -2028,13 +2256,13 @@ Inbound.DokodemoSettings = class extends Inbound.Settings { address: this.address, port: this.port, network: this.network, - followRedirect: this.followRedirect + followRedirect: this.followRedirect, }; } }; Inbound.SocksSettings = class extends Inbound.Settings { - constructor(protocol, auth='password', accounts=[new Inbound.SocksSettings.SocksAccount()], udp=false, ip='127.0.0.1') { + constructor(protocol, auth = 'password', accounts = [new Inbound.SocksSettings.SocksAccount()], udp = false, ip = '127.0.0.1') { super(protocol); this.auth = auth; this.accounts = accounts; @@ -2050,7 +2278,7 @@ Inbound.SocksSettings = class extends Inbound.Settings { this.accounts.splice(index, 1); } - static fromJson(json={}) { + static fromJson(json = {}) { let accounts; if (json.auth === 'password') { accounts = json.accounts.map( @@ -2076,20 +2304,20 @@ Inbound.SocksSettings = class extends Inbound.Settings { } }; Inbound.SocksSettings.SocksAccount = class extends XrayCommonClass { - constructor(user=RandomUtil.randomSeq(10), pass=RandomUtil.randomSeq(10)) { + constructor(user = RandomUtil.randomSeq(10), pass = RandomUtil.randomSeq(10)) { super(); this.user = user; this.pass = pass; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.SocksSettings.SocksAccount(json.user, json.pass); } }; Inbound.HttpSettings = class extends Inbound.Settings { constructor( - protocol, + protocol, accounts = [new Inbound.HttpSettings.HttpAccount()], allowTransparent = false, ) { @@ -2123,19 +2351,25 @@ Inbound.HttpSettings = class extends Inbound.Settings { }; Inbound.HttpSettings.HttpAccount = class extends XrayCommonClass { - constructor(user=RandomUtil.randomSeq(10), pass=RandomUtil.randomSeq(10)) { + constructor(user = RandomUtil.randomSeq(10), pass = RandomUtil.randomSeq(10)) { super(); this.user = user; this.pass = pass; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Inbound.HttpSettings.HttpAccount(json.user, json.pass); } }; Inbound.WireguardSettings = class extends XrayCommonClass { - constructor(protocol, mtu=1420, secretKey=Wireguard.generateKeypair().privateKey, peers=[new Inbound.WireguardSettings.Peer()], kernelMode=false) { + constructor( + protocol, + mtu = 1420, + secretKey = Wireguard.generateKeypair().privateKey, + peers = [new Inbound.WireguardSettings.Peer()], + kernelMode = false + ) { super(protocol); this.mtu = mtu; this.secretKey = secretKey; @@ -2188,7 +2422,7 @@ Inbound.WireguardSettings.Peer = class extends XrayCommonClass { this.keepAlive = keepAlive; } - static fromJson(json={}){ + static fromJson(json = {}) { return new Inbound.WireguardSettings.Peer( json.privateKey, json.publicKey, @@ -2199,15 +2433,15 @@ Inbound.WireguardSettings.Peer = class extends XrayCommonClass { } toJson() { - this.allowedIPs.forEach((a,index) => { - if (a.length>0 && !a.includes('/')) this.allowedIPs[index] += '/32'; + this.allowedIPs.forEach((a, index) => { + if (a.length > 0 && !a.includes('/')) this.allowedIPs[index] += '/32'; }); return { privateKey: this.privateKey, publicKey: this.publicKey, - preSharedKey: this.psk.length>0 ? this.psk : undefined, + preSharedKey: this.psk.length > 0 ? this.psk : undefined, allowedIPs: this.allowedIPs, - keepAlive: this.keepAlive?? undefined, + keepAlive: this.keepAlive ?? undefined, }; } -}; \ No newline at end of file +}; diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index 3bf7e944..a69b4405 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -39,6 +39,7 @@ const UTLS_FINGERPRINT = { UTLS_QQ: "qq", UTLS_RANDOM: "random", UTLS_RANDOMIZED: "randomized", + UTLS_RONDOMIZEDNOALPN: "randomizednoalpn", UTLS_UNSAFE: "unsafe", }; @@ -70,19 +71,41 @@ const WireguardDomainStrategy = [ "ForceIPv6v4" ]; +const USERS_SECURITY = { + AES_128_GCM: "aes-128-gcm", + CHACHA20_POLY1305: "chacha20-poly1305", + AUTO: "auto", + NONE: "none", + ZERO: "zero", +}; + const MODE_OPTION = { AUTO: "auto", PACKET_UP: "packet-up", STREAM_UP: "stream-up", + STREAM_ONE: "stream-one", +}; + +const Address_Port_Strategy = { + NONE: "none", + SrvPortOnly: "srvportonly", + SrvAddressOnly: "srvaddressonly", + SrvPortAndAddress: "srvportandaddress", + TxtPortOnly: "txtportonly", + TxtAddressOnly: "txtaddressonly", + TxtPortAndAddress: "txtportandaddress" }; Object.freeze(Protocols); Object.freeze(SSMethods); Object.freeze(TLS_FLOW_CONTROL); +Object.freeze(UTLS_FINGERPRINT); Object.freeze(ALPN_OPTION); Object.freeze(OutboundDomainStrategies); Object.freeze(WireguardDomainStrategy); +Object.freeze(USERS_SECURITY); Object.freeze(MODE_OPTION); +Object.freeze(Address_Port_Strategy); class CommonClass { @@ -98,30 +121,30 @@ class CommonClass { return this; } - toString(format=true) { + toString(format = true) { return format ? JSON.stringify(this.toJson(), null, 2) : JSON.stringify(this.toJson()); } } class TcpStreamSettings extends CommonClass { - constructor(type='none', host, path) { + constructor(type = 'none', host, path) { super(); this.type = type; this.host = host; this.path = path; } - static fromJson(json={}) { + static fromJson(json = {}) { let header = json.header; if (!header) return new TcpStreamSettings(); - if(header.type == 'http' && header.request){ + if (header.type == 'http' && header.request) { return new TcpStreamSettings( header.type, header.request.headers.Host.join(','), header.request.path.join(','), ); } - return new TcpStreamSettings(header.type,'',''); + return new TcpStreamSettings(header.type, '', ''); } toJson() { @@ -140,15 +163,17 @@ class TcpStreamSettings extends CommonClass { } class KcpStreamSettings extends CommonClass { - constructor(mtu=1350, tti=20, - uplinkCapacity=5, - downlinkCapacity=20, - congestion=false, - readBufferSize=2, - writeBufferSize=2, - type='none', - seed='', - ) { + constructor( + mtu = 1350, + tti = 50, + uplinkCapacity = 5, + downlinkCapacity = 20, + congestion = false, + readBufferSize = 2, + writeBufferSize = 2, + type = 'none', + seed = '', + ) { super(); this.mtu = mtu; this.tti = tti; @@ -161,7 +186,7 @@ class KcpStreamSettings extends CommonClass { this.seed = seed; } - static fromJson(json={}) { + static fromJson(json = {}) { return new KcpStreamSettings( json.mtu, json.tti, @@ -193,16 +218,23 @@ class KcpStreamSettings extends CommonClass { } class WsStreamSettings extends CommonClass { - constructor(path='/', host='') { + constructor( + path = '/', + host = '', + heartbeatPeriod = 0, + + ) { super(); this.path = path; this.host = host; + this.heartbeatPeriod = heartbeatPeriod; } - static fromJson(json={}) { + static fromJson(json = {}) { return new WsStreamSettings( json.path, json.host, + json.heartbeatPeriod, ); } @@ -210,19 +242,24 @@ class WsStreamSettings extends CommonClass { return { path: this.path, host: this.host, + heartbeatPeriod: this.heartbeatPeriod }; } } class GrpcStreamSettings extends CommonClass { - constructor(serviceName="", authority="", multiMode=false) { + constructor( + serviceName = "", + authority = "", + multiMode = false + ) { super(); this.serviceName = serviceName; this.authority = authority; this.multiMode = multiMode; } - static fromJson(json={}) { + static fromJson(json = {}) { return new GrpcStreamSettings(json.serviceName, json.authority, json.multiMode); } @@ -230,19 +267,19 @@ class GrpcStreamSettings extends CommonClass { return { serviceName: this.serviceName, authority: this.authority, - multiMode: this.multiMode, + multiMode: this.multiMode } } } class HttpUpgradeStreamSettings extends CommonClass { - constructor(path='/', host='') { + constructor(path = '/', host = '') { super(); this.path = path; this.host = host; } - static fromJson(json={}) { + static fromJson(json = {}) { return new HttpUpgradeStreamSettings( json.path, json.host, @@ -313,10 +350,12 @@ class xHTTPStreamSettings extends CommonClass { } class TlsStreamSettings extends CommonClass { - constructor(serverName='', - alpn=[], - fingerprint = '', - allowInsecure = false) { + constructor( + serverName = '', + alpn = [], + fingerprint = '', + allowInsecure = false + ) { super(); this.serverName = serverName; this.alpn = alpn; @@ -324,7 +363,7 @@ class TlsStreamSettings extends CommonClass { this.allowInsecure = allowInsecure; } - static fromJson(json={}) { + static fromJson(json = {}) { return new TlsStreamSettings( json.serverName, json.alpn, @@ -344,7 +383,13 @@ class TlsStreamSettings extends CommonClass { } class RealityStreamSettings extends CommonClass { - constructor(publicKey = '', fingerprint = '', serverName = '', shortId = '', spiderX = '/') { + constructor( + publicKey = '', + fingerprint = '', + serverName = '', + shortId = '', + spiderX = '/' + ) { super(); this.publicKey = publicKey; this.fingerprint = fingerprint; @@ -371,14 +416,22 @@ class RealityStreamSettings extends CommonClass { }; } }; - class SockoptStreamSettings extends CommonClass { - constructor(dialerProxy = "", tcpFastOpen = false, tcpKeepAliveInterval = 0, penetrate = false) { + constructor( + dialerProxy = "", + tcpFastOpen = false, + tcpKeepAliveInterval = 0, + tcpMptcp = false, + penetrate = false, + addressPortStrategy = Address_Port_Strategy.NONE, + ) { super(); this.dialerProxy = dialerProxy; this.tcpFastOpen = tcpFastOpen; this.tcpKeepAliveInterval = tcpKeepAliveInterval; + this.tcpMptcp = tcpMptcp; this.penetrate = penetrate; + this.addressPortStrategy = addressPortStrategy; } static fromJson(json = {}) { @@ -387,7 +440,9 @@ class SockoptStreamSettings extends CommonClass { json.dialerProxy, json.tcpFastOpen, json.tcpKeepAliveInterval, + json.tcpMptcp, json.penetrate, + json.addressPortStrategy ); } @@ -396,24 +451,27 @@ class SockoptStreamSettings extends CommonClass { dialerProxy: this.dialerProxy, tcpFastOpen: this.tcpFastOpen, tcpKeepAliveInterval: this.tcpKeepAliveInterval, + tcpMptcp: this.tcpMptcp, penetrate: this.penetrate, + addressPortStrategy: this.addressPortStrategy }; } } class StreamSettings extends CommonClass { - constructor(network='tcp', - security='none', - tlsSettings=new TlsStreamSettings(), - realitySettings = new RealityStreamSettings(), - tcpSettings=new TcpStreamSettings(), - kcpSettings=new KcpStreamSettings(), - wsSettings=new WsStreamSettings(), - grpcSettings=new GrpcStreamSettings(), - httpupgradeSettings=new HttpUpgradeStreamSettings(), - xhttpSettings=new xHTTPStreamSettings(), - sockopt = undefined, - ) { + constructor( + network = 'tcp', + security = 'none', + tlsSettings = new TlsStreamSettings(), + realitySettings = new RealityStreamSettings(), + tcpSettings = new TcpStreamSettings(), + kcpSettings = new KcpStreamSettings(), + wsSettings = new WsStreamSettings(), + grpcSettings = new GrpcStreamSettings(), + httpupgradeSettings = new HttpUpgradeStreamSettings(), + xhttpSettings = new xHTTPStreamSettings(), + sockopt = undefined, + ) { super(); this.network = network; this.security = security; @@ -427,7 +485,7 @@ class StreamSettings extends CommonClass { this.xhttp = xhttpSettings; this.sockopt = sockopt; } - + get isTls() { return this.security === 'tls'; } @@ -444,7 +502,7 @@ class StreamSettings extends CommonClass { this.sockopt = value ? new SockoptStreamSettings() : undefined; } - static fromJson(json={}) { + static fromJson(json = {}) { return new StreamSettings( json.network, json.security, @@ -509,9 +567,9 @@ class Mux extends CommonClass { class Outbound extends CommonClass { constructor( - tag='', - protocol=Protocols.VMess, - settings=null, + tag = '', + protocol = Protocols.VLESS, + settings = null, streamSettings = new StreamSettings(), sendThrough, mux = new Mux(), @@ -558,11 +616,27 @@ class Outbound extends CommonClass { } canEnableMux() { - if (this.settings.flow && this.settings.flow != ''){ + // Disable Mux if flow is set + if (this.settings.flow && this.settings.flow !== '') { this.mux.enabled = false; return false; } - return [Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks, Protocols.HTTP, Protocols.Socks].includes(this.protocol); + + // Disable Mux if network is xhttp + if (this.stream.network === 'xhttp') { + this.mux.enabled = false; + return false; + } + + // Allow Mux only for these protocols + return [ + Protocols.VMess, + Protocols.VLESS, + Protocols.Trojan, + Protocols.Shadowsocks, + Protocols.HTTP, + Protocols.Socks + ].includes(this.protocol); } hasVnext() { @@ -589,7 +663,7 @@ class Outbound extends CommonClass { return [Protocols.Socks, Protocols.HTTP].includes(this.protocol); } - static fromJson(json={}) { + static fromJson(json = {}) { return new Outbound( json.tag, json.protocol, @@ -620,8 +694,8 @@ class Outbound extends CommonClass { static fromLink(link) { data = link.split('://'); - if(data.length !=2) return null; - switch(data[0].toLowerCase()){ + if (data.length != 2) return null; + switch (data[0].toLowerCase()) { case Protocols.VMess: return this.fromVmessLink(JSON.parse(Base64.decode(data[1]))); case Protocols.VLESS: @@ -633,7 +707,7 @@ class Outbound extends CommonClass { } } - static fromVmessLink(json={}){ + static fromVmessLink(json = {}) { let stream = new StreamSettings(json.net, json.tls); let network = json.net; @@ -647,16 +721,16 @@ class Outbound extends CommonClass { stream.type = json.type; stream.seed = json.path; } else if (network === 'ws') { - stream.ws = new WsStreamSettings(json.path,json.host); + stream.ws = new WsStreamSettings(json.path, json.host); } else if (network === 'grpc') { stream.grpc = new GrpcStreamSettings(json.path, json.authority, json.type == 'multi'); } else if (network === 'httpupgrade') { - stream.httpupgrade = new HttpUpgradeStreamSettings(json.path,json.host); + stream.httpupgrade = new HttpUpgradeStreamSettings(json.path, json.host); } else if (network === 'xhttp') { - stream.xhttp = new xHTTPStreamSettings(json.path,json.host,json.mode); + stream.xhttp = new xHTTPStreamSettings(json.path, json.host, json.mode); } - if(json.tls && json.tls == 'tls'){ + if (json.tls && json.tls == 'tls') { stream.tls = new TlsStreamSettings( json.sni, json.alpn ? json.alpn.split(',') : [], @@ -666,10 +740,10 @@ 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){ + static fromParamLink(link) { const url = new URL(link); let type = url.searchParams.get('type') ?? 'tcp'; let security = url.searchParams.get('security') ?? 'none'; @@ -687,32 +761,32 @@ class Outbound extends CommonClass { stream.kcp.type = headerType ?? 'none'; stream.kcp.seed = path; } else if (type === 'ws') { - stream.ws = new WsStreamSettings(path,host); + stream.ws = new WsStreamSettings(path, host); } else if (type === 'grpc') { stream.grpc = new GrpcStreamSettings( url.searchParams.get('serviceName') ?? '', url.searchParams.get('authority') ?? '', url.searchParams.get('mode') == 'multi'); } else if (type === 'httpupgrade') { - stream.httpupgrade = new HttpUpgradeStreamSettings(path,host); + stream.httpupgrade = new HttpUpgradeStreamSettings(path, host); } else if (type === 'xhttp') { - stream.xhttp = new xHTTPStreamSettings(path,host,mode); + stream.xhttp = new xHTTPStreamSettings(path, host, mode); } - if(security == 'tls'){ - let fp=url.searchParams.get('fp') ?? 'none'; - let alpn=url.searchParams.get('alpn'); - let allowInsecure=url.searchParams.get('allowInsecure'); - let sni=url.searchParams.get('sni') ?? ''; + if (security == 'tls') { + let fp = url.searchParams.get('fp') ?? 'none'; + let alpn = url.searchParams.get('alpn'); + let allowInsecure = url.searchParams.get('allowInsecure'); + let sni = url.searchParams.get('sni') ?? ''; stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, allowInsecure == 1); } - if(security == 'reality'){ - let pbk=url.searchParams.get('pbk'); - let fp=url.searchParams.get('fp'); - let sni=url.searchParams.get('sni') ?? ''; - let sid=url.searchParams.get('sid') ?? ''; - let spx=url.searchParams.get('spx') ?? ''; + if (security == 'reality') { + let pbk = url.searchParams.get('pbk'); + let fp = url.searchParams.get('fp'); + let sni = url.searchParams.get('sni') ?? ''; + let sid = url.searchParams.get('sid') ?? ''; + let spx = url.searchParams.get('spx') ?? ''; stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx); } @@ -720,14 +794,14 @@ class Outbound extends CommonClass { const match = link.match(regex); if (!match) return null; - let [, protocol, userData, address, port, ] = match; + let [, protocol, userData, address, port,] = match; port *= 1; - if(protocol == 'ss') { + if (protocol == 'ss') { protocol = 'shadowsocks'; userData = atob(userData).split(':'); } var settings; - switch(protocol){ + switch (protocol) { case Protocols.VLESS: settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? ''); break; @@ -735,7 +809,7 @@ class Outbound extends CommonClass { settings = new Outbound.TrojanSettings(address, port, userData); break; case Protocols.Shadowsocks: - let method = userData.splice(0,1)[0]; + let method = userData.splice(0, 1)[0]; settings = new Outbound.ShadowsocksSettings(address, port, userData.join(":"), method, true); break; default: @@ -832,14 +906,18 @@ Outbound.FreedomSettings = class extends CommonClass { }; Outbound.FreedomSettings.Fragment = class extends CommonClass { - constructor(packets='1-3',length='',interval=''){ + constructor( + packets = '1-3', + length = '', + interval = '' + ) { super(); this.packets = packets; this.length = length; this.interval = interval; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Outbound.FreedomSettings.Fragment( json.packets, json.length, @@ -883,7 +961,7 @@ Outbound.BlackholeSettings = class extends CommonClass { this.type = type; } - static fromJson(json={}) { + static fromJson(json = {}) { return new Outbound.BlackholeSettings( json.response ? json.response.type : undefined, ); @@ -891,14 +969,14 @@ Outbound.BlackholeSettings = class extends CommonClass { toJson() { return { - response: ObjectUtil.isEmpty(this.type) ? undefined : {type: this.type}, + response: ObjectUtil.isEmpty(this.type) ? undefined : { type: this.type }, }; } }; Outbound.DNSSettings = class extends CommonClass { constructor( network = 'udp', - address = '1.1.1.1', + address = '', port = 53, nonIPQuery = 'drop', blockTypes = [] @@ -922,19 +1000,21 @@ 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={}) { - if(ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VmessSettings(); + static fromJson(json = {}) { + if (ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VmessSettings(); return new Outbound.VmessSettings( json.vnext[0].address, json.vnext[0].port, json.vnext[0].users[0].id, + json.vnext[0].users[0].security, ); } @@ -943,13 +1023,13 @@ Outbound.VmessSettings = class extends CommonClass { vnext: [{ address: this.address, port: this.port, - users: [{id: this.id}], + users: [{ id: this.id, security: this.security }], }], }; } }; Outbound.VLESSSettings = class extends CommonClass { - constructor(address, port, id, flow, encryption='none') { + constructor(address, port, id, flow, encryption = 'none') { super(); this.address = address; this.port = port; @@ -958,8 +1038,8 @@ Outbound.VLESSSettings = class extends CommonClass { this.encryption = encryption } - static fromJson(json={}) { - if(ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VLESSSettings(); + static fromJson(json = {}) { + if (ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VLESSSettings(); return new Outbound.VLESSSettings( json.vnext[0].address, json.vnext[0].port, @@ -974,7 +1054,7 @@ Outbound.VLESSSettings = class extends CommonClass { vnext: [{ address: this.address, port: this.port, - users: [{id: this.id, flow: this.flow, encryption: 'none',}], + users: [{ id: this.id, flow: this.flow, encryption: 'none', }], }], }; } @@ -987,8 +1067,8 @@ Outbound.TrojanSettings = class extends CommonClass { this.password = password; } - static fromJson(json={}) { - if(ObjectUtil.isArrEmpty(json.servers)) return new Outbound.TrojanSettings(); + static fromJson(json = {}) { + if (ObjectUtil.isArrEmpty(json.servers)) return new Outbound.TrojanSettings(); return new Outbound.TrojanSettings( json.servers[0].address, json.servers[0].port, @@ -1007,24 +1087,26 @@ Outbound.TrojanSettings = class extends CommonClass { } }; Outbound.ShadowsocksSettings = class extends CommonClass { - constructor(address, port, password, method, uot) { + constructor(address, port, password, method, uot, UoTVersion) { super(); this.address = address; this.port = port; this.password = password; this.method = method; this.uot = uot; + this.UoTVersion = UoTVersion; } - static fromJson(json={}) { + static fromJson(json = {}) { let servers = json.servers; - if(ObjectUtil.isArrEmpty(servers)) servers=[{}]; + if (ObjectUtil.isArrEmpty(servers)) servers = [{}]; return new Outbound.ShadowsocksSettings( servers[0].address, servers[0].port, servers[0].password, servers[0].method, servers[0].uot, + servers[0].UoTVersion, ); } @@ -1036,10 +1118,12 @@ Outbound.ShadowsocksSettings = class extends CommonClass { password: this.password, method: this.method, uot: this.uot, + UoTVersion: this.UoTVersion, }], }; } }; + Outbound.SocksSettings = class extends CommonClass { constructor(address, port, user, pass) { super(); @@ -1049,9 +1133,9 @@ Outbound.SocksSettings = class extends CommonClass { this.pass = pass; } - static fromJson(json={}) { + static fromJson(json = {}) { let servers = json.servers; - if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}]; + if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }]; return new Outbound.SocksSettings( servers[0].address, servers[0].port, @@ -1065,7 +1149,7 @@ Outbound.SocksSettings = class extends CommonClass { servers: [{ address: this.address, port: this.port, - users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, pass: this.pass}], + users: ObjectUtil.isEmpty(this.user) ? [] : [{ user: this.user, pass: this.pass }], }], }; } @@ -1079,9 +1163,9 @@ Outbound.HttpSettings = class extends CommonClass { this.pass = pass; } - static fromJson(json={}) { + static fromJson(json = {}) { let servers = json.servers; - if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}]; + if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }]; return new Outbound.HttpSettings( servers[0].address, servers[0].port, @@ -1095,16 +1179,23 @@ Outbound.HttpSettings = class extends CommonClass { servers: [{ address: this.address, port: this.port, - users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, pass: this.pass}], + users: ObjectUtil.isEmpty(this.user) ? [] : [{ user: this.user, pass: this.pass }], }], }; } }; + Outbound.WireguardSettings = class extends CommonClass { constructor( - mtu=1420, secretKey='', - address='', workers=2, domainStrategy='', reserved='', - peers=[new Outbound.WireguardSettings.Peer()], kernelMode=false) { + mtu = 1420, + secretKey = '', + address = [''], + workers = 2, + domainStrategy = '', + reserved = '', + peers = [new Outbound.WireguardSettings.Peer()], + kernelMode = false, + ) { super(); this.mtu = mtu; this.secretKey = secretKey; @@ -1125,7 +1216,7 @@ Outbound.WireguardSettings = class extends CommonClass { this.peers.splice(index, 1); } - static fromJson(json={}){ + static fromJson(json = {}) { return new Outbound.WireguardSettings( json.mtu, json.secretKey, @@ -1140,10 +1231,10 @@ Outbound.WireguardSettings = class extends CommonClass { toJson() { return { - mtu: this.mtu?? undefined, + mtu: this.mtu ?? undefined, secretKey: this.secretKey, address: this.address ? this.address.split(",") : [], - workers: this.workers?? undefined, + workers: this.workers ?? undefined, domainStrategy: WireguardDomainStrategy.includes(this.domainStrategy) ? this.domainStrategy : undefined, reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined, peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers), @@ -1151,8 +1242,15 @@ Outbound.WireguardSettings = class extends CommonClass { }; } }; + Outbound.WireguardSettings.Peer = class extends CommonClass { - constructor(publicKey='', psk='', allowedIPs=['0.0.0.0/0','::/0'], endpoint='', keepAlive=0) { + constructor( + publicKey = '', + psk = '', + allowedIPs = ['0.0.0.0/0', '::/0'], + endpoint = '', + keepAlive = 0 + ) { super(); this.publicKey = publicKey; this.psk = psk; @@ -1161,7 +1259,7 @@ Outbound.WireguardSettings.Peer = class extends CommonClass { this.keepAlive = keepAlive; } - static fromJson(json={}){ + static fromJson(json = {}) { return new Outbound.WireguardSettings.Peer( json.publicKey, json.preSharedKey, @@ -1174,10 +1272,10 @@ Outbound.WireguardSettings.Peer = class extends CommonClass { toJson() { return { publicKey: this.publicKey, - preSharedKey: this.psk.length>0 ? this.psk : undefined, + preSharedKey: this.psk.length > 0 ? this.psk : undefined, allowedIPs: this.allowedIPs ? this.allowedIPs : undefined, endpoint: this.endpoint, - keepAlive: this.keepAlive?? undefined, + keepAlive: this.keepAlive ?? undefined, }; } }; \ No newline at end of file diff --git a/web/controller/server.go b/web/controller/server.go index 28fd4ac0..7b60118a 100644 --- a/web/controller/server.go +++ b/web/controller/server.go @@ -49,6 +49,7 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) { g.GET("/getDb", a.getDb) g.POST("/importDB", a.importDB) g.POST("/getNewX25519Cert", a.getNewX25519Cert) + g.POST("/getNewmldsa65", a.getNewmldsa65) } func (a *ServerController) refreshStatus() { @@ -186,3 +187,12 @@ func (a *ServerController) getNewX25519Cert(c *gin.Context) { } jsonObj(c, cert, nil) } + +func (a *ServerController) getNewmldsa65(c *gin.Context) { + cert, err := a.serverService.GetNewmldsa65() + if err != nil { + jsonMsg(c, "get mldsa65 certificate", err) + return + } + jsonObj(c, cert, nil) +} diff --git a/web/html/common/head.html b/web/html/common/head.html index b2533098..f4ebc410 100644 --- a/web/html/common/head.html +++ b/web/html/common/head.html @@ -2,7 +2,7 @@ - + diff --git a/web/html/xui/form/outbound.html b/web/html/xui/form/outbound.html index 3a906477..536ab697 100644 --- a/web/html/xui/form/outbound.html +++ b/web/html/xui/form/outbound.html @@ -66,7 +66,7 @@ - [[ s ]] + [[ s ]] @@ -460,12 +460,20 @@ [[ tag ]] - - + + + [[ key ]] + + + + + + + diff --git a/web/html/xui/form/reality_settings.html b/web/html/xui/form/reality_settings.html index 08ff25b6..516cd043 100644 --- a/web/html/xui/form/reality_settings.html +++ b/web/html/xui/form/reality_settings.html @@ -42,5 +42,14 @@ Get New Cert + + + + + + + + Get New Seed + {{end}} \ No newline at end of file diff --git a/web/html/xui/form/stream/stream_xhttp.html b/web/html/xui/form/stream/stream_xhttp.html index f985d3c6..1dd0a452 100644 --- a/web/html/xui/form/stream/stream_xhttp.html +++ b/web/html/xui/form/stream/stream_xhttp.html @@ -33,6 +33,9 @@ + + + diff --git a/web/html/xui/inbound_modal.html b/web/html/xui/inbound_modal.html index e1a271cc..1aa85438 100644 --- a/web/html/xui/inbound_modal.html +++ b/web/html/xui/inbound_modal.html @@ -132,6 +132,16 @@ inModal.inbound.stream.reality.privateKey = msg.obj.privateKey; inModal.inbound.stream.reality.settings.publicKey = msg.obj.publicKey; }, + async getNewmldsa65() { + inModal.loading(true); + const msg = await HttpUtil.post('/server/getNewmldsa65'); + inModal.loading(false); + if (!msg.success) { + return; + } + inModal.inbound.stream.reality.mldsa65Seed = msg.obj.seed; + inModal.inbound.stream.reality.settings.mldsa65Verify = msg.obj.verify; + }, }, }); diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html index e296f62e..eb13fdac 100644 --- a/web/html/xui/settings.html +++ b/web/html/xui/settings.html @@ -328,7 +328,7 @@ :dropdown-class-name="themeSwitcher.currentTheme" @change="(value) => updateNoiseType(index, value)"> + v-for="p in ['rand', 'base64', 'str', 'hex']" :key="p"> [[ p ]] diff --git a/web/html/xui/warp_modal.html b/web/html/xui/warp_modal.html index 7db58386..b8c03fd4 100644 --- a/web/html/xui/warp_modal.html +++ b/web/html/xui/warp_modal.html @@ -174,10 +174,10 @@ new Vue({ }, async register(){ warpModal.loading(true); - keys = Wireguard.generateKeypair(); + const keys = Wireguard.generateKeypair(); const msg = await HttpUtil.post('/xui/xray/warp/reg',keys); if (msg.success) { - resp = JSON.parse(msg.obj); + const resp = JSON.parse(msg.obj); warpModal.warpData = resp.data; warpModal.warpConfig = resp.config; this.collectConfig(); diff --git a/web/html/xui/xray.html b/web/html/xui/xray.html index 83247d17..814c6480 100644 --- a/web/html/xui/xray.html +++ b/web/html/xui/xray.html @@ -1258,8 +1258,7 @@ } newTemplateSettings.routing.balancers.push(tmpBalancer); this.templateSettings = newTemplateSettings; - if (balancer.strategy == 'leastPing' || balancer.strategy == 'leastLoad') - this.updateObservatorySelectors(); + this.updateObservatorySelectors(); balancerModal.close(); this.changeObsCode(); }, @@ -1307,8 +1306,7 @@ }); } this.templateSettings = newTemplateSettings; - if (balancer.strategy == 'leastPing' || balancer.strategy == 'leastLoad') - this.updateObservatorySelectors(); + this.updateObservatorySelectors(); balancerModal.close(); this.changeObsCode(); }, @@ -1318,7 +1316,11 @@ updateObservatorySelectors(){ newTemplateSettings = this.templateSettings; const leastPings = this.balancersData.filter((b) => b.strategy == 'leastPing'); - const leastLoads = this.balancersData.filter((b) => b.strategy == 'leastLoad'); + const leastLoads = this.balancersData.filter((b) => + b.strategy === 'leastLoad' || + b.strategy === 'roundRobin' || + b.strategy === 'random' + ); if (leastPings.length>0){ if (!newTemplateSettings.observatory) newTemplateSettings.observatory = this.defaultObservatory; diff --git a/web/service/config.json b/web/service/config.json index cb0e66fc..f45a96c0 100644 --- a/web/service/config.json +++ b/web/service/config.json @@ -79,5 +79,6 @@ } ] }, - "stats": {} + "stats": {}, + "metrics": {} } \ No newline at end of file diff --git a/web/service/server.go b/web/service/server.go index 2d26cd8f..16528b84 100644 --- a/web/service/server.go +++ b/web/service/server.go @@ -564,3 +564,29 @@ func (s *ServerService) GetNewX25519Cert() (interface{}, error) { return keyPair, nil } + +func (s *ServerService) GetNewmldsa65() (any, error) { + // Run the command + cmd := exec.Command(xray.GetBinaryPath(), "mldsa65") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return nil, err + } + + lines := strings.Split(out.String(), "\n") + + SeedLine := strings.Split(lines[0], ":") + VerifyLine := strings.Split(lines[1], ":") + + seed := strings.TrimSpace(SeedLine[1]) + verify := strings.TrimSpace(VerifyLine[1]) + + keyPair := map[string]any{ + "seed": seed, + "verify": verify, + } + + return keyPair, nil +} diff --git a/web/service/warp.go b/web/service/warp.go index de6a50eb..68274a96 100644 --- a/web/service/warp.go +++ b/web/service/warp.go @@ -56,8 +56,7 @@ func (s *WarpService) GetWarpConfig() (string, error) { return "", err } defer resp.Body.Close() - buffer := bytes.NewBuffer(make([]byte, 8192)) - buffer.Reset() + buffer := &bytes.Buffer{} _, err = buffer.ReadFrom(resp.Body) if err != nil { return "", err @@ -87,8 +86,7 @@ func (s *WarpService) RegWarp(secretKey string, publicKey string) (string, error return "", err } defer resp.Body.Close() - buffer := bytes.NewBuffer(make([]byte, 8192)) - buffer.Reset() + buffer := &bytes.Buffer{} _, err = buffer.ReadFrom(resp.Body) if err != nil { return "", err @@ -144,8 +142,7 @@ func (s *WarpService) SetWarpLicense(license string) (string, error) { return "", err } defer resp.Body.Close() - buffer := bytes.NewBuffer(make([]byte, 8192)) - buffer.Reset() + buffer := &bytes.Buffer{} _, err = buffer.ReadFrom(resp.Body) if err != nil { return "", err diff --git a/x-ui.sh b/x-ui.sh index 98f360f7..92c1bbfa 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -56,8 +56,8 @@ elif [[ "${release}" == "centos" ]]; then echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "ubuntu" ]]; then - if [[ ${os_version} -lt 2004 ]]; then - echo -e "${red} Please use Ubuntu 20 or higher version!${plain}\n" && exit 1 + if [[ ${os_version} -lt 2204 ]]; then + echo -e "${red} Please use Ubuntu 22 or higher version!${plain}\n" && exit 1 fi elif [[ "${release}" == "fedora" ]]; then if [[ ${os_version} -lt 36 ]]; then @@ -68,16 +68,16 @@ elif [[ "${release}" == "amzn" ]]; then echo -e "${red} Please use Amazon Linux 2023!${plain}\n" && exit 1 fi elif [[ "${release}" == "debian" ]]; then - if [[ ${os_version} -lt 11 ]]; then - echo -e "${red} Please use Debian 11 or higher ${plain}\n" && exit 1 + if [[ ${os_version} -lt 12 ]]; then + echo -e "${red} Please use Debian 12 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "almalinux" ]]; then - if [[ ${os_version} -lt 80 ]]; then - echo -e "${red} Please use AlmaLinux 8.0 or higher ${plain}\n" && exit 1 + if [[ ${os_version} -lt 95 ]]; then + echo -e "${red} Please use AlmaLinux 9.5 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "rocky" ]]; then - if [[ ${os_version} -lt 8 ]]; then - echo -e "${red} Please use Rocky Linux 8 or higher ${plain}\n" && exit 1 + if [[ ${os_version} -lt 95 ]]; then + echo -e "${red} Please use Rocky Linux 9.5 or higher ${plain}\n" && exit 1 fi elif [[ "${release}" == "ol" ]]; then if [[ ${os_version} -lt 8 ]]; then @@ -86,8 +86,8 @@ elif [[ "${release}" == "ol" ]]; then else echo -e "${red}Your operating system is not supported by this script.${plain}\n" echo "Please ensure you are using one of the following supported operating systems:" - echo "- Ubuntu 20.04+" - echo "- Debian 11+" + echo "- Ubuntu 22.04+" + echo "- Debian 12+" echo "- CentOS 8+" echo "- OpenEuler 22.03+" echo "- Fedora 36+" @@ -95,8 +95,8 @@ else echo "- Parch Linux" echo "- Manjaro" echo "- Armbian" - echo "- AlmaLinux 8.0+" - echo "- Rocky Linux 8+" + echo "- AlmaLinux 9.5+" + echo "- Rocky Linux 9.5+" echo "- Oracle Linux 8+" echo "- OpenSUSE Tumbleweed" echo "- Amazon Linux 2023" diff --git a/xray/config.go b/xray/config.go index 67ff7d95..a246b845 100644 --- a/xray/config.go +++ b/xray/config.go @@ -20,6 +20,7 @@ type Config struct { FakeDNS json_util.RawMessage `json:"fakedns"` Observatory json_util.RawMessage `json:"observatory"` BurstObservatory json_util.RawMessage `json:"burstObservatory"` + Metrics json_util.RawMessage `json:"metrics"` } func (c *Config) Equals(other *Config) bool { @@ -61,5 +62,8 @@ func (c *Config) Equals(other *Config) bool { if !bytes.Equal(c.FakeDNS, other.FakeDNS) { return false } + if !bytes.Equal(c.Metrics, other.Metrics) { + return false + } return true } diff --git a/xray/log_writer.go b/xray/log_writer.go index cc00d541..24d22f2c 100644 --- a/xray/log_writer.go +++ b/xray/log_writer.go @@ -25,7 +25,7 @@ func (lw *LogWriter) Write(m []byte) (n int, err error) { if crashRegex.MatchString(message) { logger.Debug("Core crash detected:\n", message) lw.lastLine = message - err1 := writeCrachReport(m) + err1 := writeCrashReport(m) if err1 != nil { logger.Error("Unable to write crash report:", err1) } diff --git a/xray/process.go b/xray/process.go index fbbd28e1..8dc9dbab 100644 --- a/xray/process.go +++ b/xray/process.go @@ -192,7 +192,7 @@ func (p *process) Stop() error { return p.cmd.Process.Signal(syscall.SIGTERM) } -func writeCrachReport(m []byte) error { +func writeCrashReport(m []byte) error { crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log" return os.WriteFile(crashReportPath, m, os.ModePerm) }