so-far updates

This commit is contained in:
Alireza Ahmadi
2025-07-30 16:09:15 +02:00
parent ee03836eeb
commit e954ccd957
26 changed files with 806 additions and 403 deletions

4
.github/FUNDING.yml vendored
View File

@@ -1,6 +1,6 @@
# These are supported funding model platforms # 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 patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi 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 issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username 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'] custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -7,7 +7,7 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View File

@@ -18,7 +18,7 @@ jobs:
- armv5 - armv5
- 386 - 386
- s390x - s390x
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -84,7 +84,7 @@ jobs:
cd x-ui/bin cd x-ui/bin
# Download dependencies # 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 if [ "${{ matrix.platform }}" == "amd64" ]; then
wget -q ${Xray_URL}Xray-linux-64.zip wget -q ${Xray_URL}Xray-linux-64.zip
unzip Xray-linux-64.zip unzip Xray-linux-64.zip

View File

@@ -23,7 +23,7 @@ case $1 in
esac esac
mkdir -p build/bin mkdir -p build/bin
cd 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" unzip "Xray-linux-${ARCH}.zip"
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat LICENSE README.md rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat LICENSE README.md
mv xray "xray-linux-${FNAME}" mv xray "xray-linux-${FNAME}"

View File

@@ -1,4 +1,4 @@
FROM golang:1.23-alpine AS builder FROM golang:1.24-alpine AS builder
WORKDIR /app WORKDIR /app
ARG TARGETARCH ARG TARGETARCH
RUN apk --no-cache --update add build-base gcc wget unzip RUN apk --no-cache --update add build-base gcc wget unzip

View File

@@ -188,7 +188,7 @@ docker build -t x-ui .
## Recommended OS ## Recommended OS
- Ubuntu 20.04+ - Ubuntu 22.04+
- Debian 11+ - Debian 11+
- CentOS 8+ - CentOS 8+
- OpenEuler 22.03+ - OpenEuler 22.03+

View File

@@ -60,8 +60,8 @@ elif [[ "${release}" == "centos" ]]; then
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1 echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "ubuntu" ]]; then elif [[ "${release}" == "ubuntu" ]]; then
if [[ ${os_version} -lt 2004 ]]; then if [[ ${os_version} -lt 2204 ]]; then
echo -e "${red} Please use Ubuntu 20 or higher version!${plain}\n" && exit 1 echo -e "${red} Please use Ubuntu 22 or higher version!${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "fedora" ]]; then elif [[ "${release}" == "fedora" ]]; then
if [[ ${os_version} -lt 36 ]]; 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 echo -e "${red} Please use Amazon Linux 2023!${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "debian" ]]; then elif [[ "${release}" == "debian" ]]; then
if [[ ${os_version} -lt 11 ]]; then if [[ ${os_version} -lt 12 ]]; then
echo -e "${red} Please use Debian 11 or higher ${plain}\n" && exit 1 echo -e "${red} Please use Debian 12 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "almalinux" ]]; then elif [[ "${release}" == "almalinux" ]]; then
if [[ ${os_version} -lt 80 ]]; then if [[ ${os_version} -lt 95 ]]; then
echo -e "${red} Please use AlmaLinux 8.0 or higher ${plain}\n" && exit 1 echo -e "${red} Please use AlmaLinux 9.5 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "rocky" ]]; then elif [[ "${release}" == "rocky" ]]; then
if [[ ${os_version} -lt 8 ]]; then if [[ ${os_version} -lt 95 ]]; then
echo -e "${red} Please use Rocky Linux 8 or higher ${plain}\n" && exit 1 echo -e "${red} Please use Rocky Linux 9.5 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "ol" ]]; then elif [[ "${release}" == "ol" ]]; then
if [[ ${os_version} -lt 8 ]]; then if [[ ${os_version} -lt 8 ]]; then
@@ -90,8 +90,8 @@ elif [[ "${release}" == "ol" ]]; then
else else
echo -e "${red}Your operating system is not supported by this script.${plain}\n" 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 "Please ensure you are using one of the following supported operating systems:"
echo "- Ubuntu 20.04+" echo "- Ubuntu 22.04+"
echo "- Debian 11+" echo "- Debian 12+"
echo "- CentOS 8+" echo "- CentOS 8+"
echo "- OpenEuler 22.03+" echo "- OpenEuler 22.03+"
echo "- Fedora 36+" echo "- Fedora 36+"
@@ -99,8 +99,8 @@ else
echo "- Parch Linux" echo "- Parch Linux"
echo "- Manjaro" echo "- Manjaro"
echo "- Armbian" echo "- Armbian"
echo "- AlmaLinux 8.0+" echo "- AlmaLinux 9.5+"
echo "- Rocky Linux 8+" echo "- Rocky Linux 9.5+"
echo "- Oracle Linux 8+" echo "- Oracle Linux 8+"
echo "- OpenSUSE Tumbleweed" echo "- OpenSUSE Tumbleweed"
echo "- Amazon Linux 2023" echo "- Amazon Linux 2023"

View File

@@ -263,6 +263,7 @@ func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]in
rltyData["show"] = false rltyData["show"] = false
rltyData["publicKey"] = rltyClientSettings["publicKey"] rltyData["publicKey"] = rltyClientSettings["publicKey"]
rltyData["fingerprint"] = rltyClientSettings["fingerprint"] rltyData["fingerprint"] = rltyClientSettings["fingerprint"]
rltyData["mldsa65Verify"] = rltyClientSettings["mldsa65Verify"]
// Set random data // Set random data
rltyData["spiderX"] = "/" + random.Seq(15) rltyData["spiderX"] = "/" + random.Seq(15)

File diff suppressed because it is too large Load Diff

View File

@@ -39,6 +39,7 @@ const UTLS_FINGERPRINT = {
UTLS_QQ: "qq", UTLS_QQ: "qq",
UTLS_RANDOM: "random", UTLS_RANDOM: "random",
UTLS_RANDOMIZED: "randomized", UTLS_RANDOMIZED: "randomized",
UTLS_RONDOMIZEDNOALPN: "randomizednoalpn",
UTLS_UNSAFE: "unsafe", UTLS_UNSAFE: "unsafe",
}; };
@@ -70,19 +71,41 @@ const WireguardDomainStrategy = [
"ForceIPv6v4" "ForceIPv6v4"
]; ];
const USERS_SECURITY = {
AES_128_GCM: "aes-128-gcm",
CHACHA20_POLY1305: "chacha20-poly1305",
AUTO: "auto",
NONE: "none",
ZERO: "zero",
};
const MODE_OPTION = { const MODE_OPTION = {
AUTO: "auto", AUTO: "auto",
PACKET_UP: "packet-up", PACKET_UP: "packet-up",
STREAM_UP: "stream-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(Protocols);
Object.freeze(SSMethods); Object.freeze(SSMethods);
Object.freeze(TLS_FLOW_CONTROL); Object.freeze(TLS_FLOW_CONTROL);
Object.freeze(UTLS_FINGERPRINT);
Object.freeze(ALPN_OPTION); Object.freeze(ALPN_OPTION);
Object.freeze(OutboundDomainStrategies); Object.freeze(OutboundDomainStrategies);
Object.freeze(WireguardDomainStrategy); Object.freeze(WireguardDomainStrategy);
Object.freeze(USERS_SECURITY);
Object.freeze(MODE_OPTION); Object.freeze(MODE_OPTION);
Object.freeze(Address_Port_Strategy);
class CommonClass { class CommonClass {
@@ -98,30 +121,30 @@ class CommonClass {
return this; return this;
} }
toString(format=true) { toString(format = true) {
return format ? JSON.stringify(this.toJson(), null, 2) : JSON.stringify(this.toJson()); return format ? JSON.stringify(this.toJson(), null, 2) : JSON.stringify(this.toJson());
} }
} }
class TcpStreamSettings extends CommonClass { class TcpStreamSettings extends CommonClass {
constructor(type='none', host, path) { constructor(type = 'none', host, path) {
super(); super();
this.type = type; this.type = type;
this.host = host; this.host = host;
this.path = path; this.path = path;
} }
static fromJson(json={}) { static fromJson(json = {}) {
let header = json.header; let header = json.header;
if (!header) return new TcpStreamSettings(); if (!header) return new TcpStreamSettings();
if(header.type == 'http' && header.request){ if (header.type == 'http' && header.request) {
return new TcpStreamSettings( return new TcpStreamSettings(
header.type, header.type,
header.request.headers.Host.join(','), header.request.headers.Host.join(','),
header.request.path.join(','), header.request.path.join(','),
); );
} }
return new TcpStreamSettings(header.type,'',''); return new TcpStreamSettings(header.type, '', '');
} }
toJson() { toJson() {
@@ -140,15 +163,17 @@ class TcpStreamSettings extends CommonClass {
} }
class KcpStreamSettings extends CommonClass { class KcpStreamSettings extends CommonClass {
constructor(mtu=1350, tti=20, constructor(
uplinkCapacity=5, mtu = 1350,
downlinkCapacity=20, tti = 50,
congestion=false, uplinkCapacity = 5,
readBufferSize=2, downlinkCapacity = 20,
writeBufferSize=2, congestion = false,
type='none', readBufferSize = 2,
seed='', writeBufferSize = 2,
) { type = 'none',
seed = '',
) {
super(); super();
this.mtu = mtu; this.mtu = mtu;
this.tti = tti; this.tti = tti;
@@ -161,7 +186,7 @@ class KcpStreamSettings extends CommonClass {
this.seed = seed; this.seed = seed;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new KcpStreamSettings( return new KcpStreamSettings(
json.mtu, json.mtu,
json.tti, json.tti,
@@ -193,16 +218,23 @@ class KcpStreamSettings extends CommonClass {
} }
class WsStreamSettings extends CommonClass { class WsStreamSettings extends CommonClass {
constructor(path='/', host='') { constructor(
path = '/',
host = '',
heartbeatPeriod = 0,
) {
super(); super();
this.path = path; this.path = path;
this.host = host; this.host = host;
this.heartbeatPeriod = heartbeatPeriod;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new WsStreamSettings( return new WsStreamSettings(
json.path, json.path,
json.host, json.host,
json.heartbeatPeriod,
); );
} }
@@ -210,19 +242,24 @@ class WsStreamSettings extends CommonClass {
return { return {
path: this.path, path: this.path,
host: this.host, host: this.host,
heartbeatPeriod: this.heartbeatPeriod
}; };
} }
} }
class GrpcStreamSettings extends CommonClass { class GrpcStreamSettings extends CommonClass {
constructor(serviceName="", authority="", multiMode=false) { constructor(
serviceName = "",
authority = "",
multiMode = false
) {
super(); super();
this.serviceName = serviceName; this.serviceName = serviceName;
this.authority = authority; this.authority = authority;
this.multiMode = multiMode; this.multiMode = multiMode;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new GrpcStreamSettings(json.serviceName, json.authority, json.multiMode); return new GrpcStreamSettings(json.serviceName, json.authority, json.multiMode);
} }
@@ -230,19 +267,19 @@ class GrpcStreamSettings extends CommonClass {
return { return {
serviceName: this.serviceName, serviceName: this.serviceName,
authority: this.authority, authority: this.authority,
multiMode: this.multiMode, multiMode: this.multiMode
} }
} }
} }
class HttpUpgradeStreamSettings extends CommonClass { class HttpUpgradeStreamSettings extends CommonClass {
constructor(path='/', host='') { constructor(path = '/', host = '') {
super(); super();
this.path = path; this.path = path;
this.host = host; this.host = host;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new HttpUpgradeStreamSettings( return new HttpUpgradeStreamSettings(
json.path, json.path,
json.host, json.host,
@@ -313,10 +350,12 @@ class xHTTPStreamSettings extends CommonClass {
} }
class TlsStreamSettings extends CommonClass { class TlsStreamSettings extends CommonClass {
constructor(serverName='', constructor(
alpn=[], serverName = '',
fingerprint = '', alpn = [],
allowInsecure = false) { fingerprint = '',
allowInsecure = false
) {
super(); super();
this.serverName = serverName; this.serverName = serverName;
this.alpn = alpn; this.alpn = alpn;
@@ -324,7 +363,7 @@ class TlsStreamSettings extends CommonClass {
this.allowInsecure = allowInsecure; this.allowInsecure = allowInsecure;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new TlsStreamSettings( return new TlsStreamSettings(
json.serverName, json.serverName,
json.alpn, json.alpn,
@@ -344,7 +383,13 @@ class TlsStreamSettings extends CommonClass {
} }
class RealityStreamSettings extends CommonClass { class RealityStreamSettings extends CommonClass {
constructor(publicKey = '', fingerprint = '', serverName = '', shortId = '', spiderX = '/') { constructor(
publicKey = '',
fingerprint = '',
serverName = '',
shortId = '',
spiderX = '/'
) {
super(); super();
this.publicKey = publicKey; this.publicKey = publicKey;
this.fingerprint = fingerprint; this.fingerprint = fingerprint;
@@ -371,14 +416,22 @@ class RealityStreamSettings extends CommonClass {
}; };
} }
}; };
class SockoptStreamSettings 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(); super();
this.dialerProxy = dialerProxy; this.dialerProxy = dialerProxy;
this.tcpFastOpen = tcpFastOpen; this.tcpFastOpen = tcpFastOpen;
this.tcpKeepAliveInterval = tcpKeepAliveInterval; this.tcpKeepAliveInterval = tcpKeepAliveInterval;
this.tcpMptcp = tcpMptcp;
this.penetrate = penetrate; this.penetrate = penetrate;
this.addressPortStrategy = addressPortStrategy;
} }
static fromJson(json = {}) { static fromJson(json = {}) {
@@ -387,7 +440,9 @@ class SockoptStreamSettings extends CommonClass {
json.dialerProxy, json.dialerProxy,
json.tcpFastOpen, json.tcpFastOpen,
json.tcpKeepAliveInterval, json.tcpKeepAliveInterval,
json.tcpMptcp,
json.penetrate, json.penetrate,
json.addressPortStrategy
); );
} }
@@ -396,24 +451,27 @@ class SockoptStreamSettings extends CommonClass {
dialerProxy: this.dialerProxy, dialerProxy: this.dialerProxy,
tcpFastOpen: this.tcpFastOpen, tcpFastOpen: this.tcpFastOpen,
tcpKeepAliveInterval: this.tcpKeepAliveInterval, tcpKeepAliveInterval: this.tcpKeepAliveInterval,
tcpMptcp: this.tcpMptcp,
penetrate: this.penetrate, penetrate: this.penetrate,
addressPortStrategy: this.addressPortStrategy
}; };
} }
} }
class StreamSettings extends CommonClass { class StreamSettings extends CommonClass {
constructor(network='tcp', constructor(
security='none', network = 'tcp',
tlsSettings=new TlsStreamSettings(), security = 'none',
realitySettings = new RealityStreamSettings(), tlsSettings = new TlsStreamSettings(),
tcpSettings=new TcpStreamSettings(), realitySettings = new RealityStreamSettings(),
kcpSettings=new KcpStreamSettings(), tcpSettings = new TcpStreamSettings(),
wsSettings=new WsStreamSettings(), kcpSettings = new KcpStreamSettings(),
grpcSettings=new GrpcStreamSettings(), wsSettings = new WsStreamSettings(),
httpupgradeSettings=new HttpUpgradeStreamSettings(), grpcSettings = new GrpcStreamSettings(),
xhttpSettings=new xHTTPStreamSettings(), httpupgradeSettings = new HttpUpgradeStreamSettings(),
sockopt = undefined, xhttpSettings = new xHTTPStreamSettings(),
) { sockopt = undefined,
) {
super(); super();
this.network = network; this.network = network;
this.security = security; this.security = security;
@@ -427,7 +485,7 @@ class StreamSettings extends CommonClass {
this.xhttp = xhttpSettings; this.xhttp = xhttpSettings;
this.sockopt = sockopt; this.sockopt = sockopt;
} }
get isTls() { get isTls() {
return this.security === 'tls'; return this.security === 'tls';
} }
@@ -444,7 +502,7 @@ class StreamSettings extends CommonClass {
this.sockopt = value ? new SockoptStreamSettings() : undefined; this.sockopt = value ? new SockoptStreamSettings() : undefined;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new StreamSettings( return new StreamSettings(
json.network, json.network,
json.security, json.security,
@@ -509,9 +567,9 @@ class Mux extends CommonClass {
class Outbound extends CommonClass { class Outbound extends CommonClass {
constructor( constructor(
tag='', tag = '',
protocol=Protocols.VMess, protocol = Protocols.VLESS,
settings=null, settings = null,
streamSettings = new StreamSettings(), streamSettings = new StreamSettings(),
sendThrough, sendThrough,
mux = new Mux(), mux = new Mux(),
@@ -558,11 +616,27 @@ class Outbound extends CommonClass {
} }
canEnableMux() { 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; this.mux.enabled = false;
return 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() { hasVnext() {
@@ -589,7 +663,7 @@ class Outbound extends CommonClass {
return [Protocols.Socks, Protocols.HTTP].includes(this.protocol); return [Protocols.Socks, Protocols.HTTP].includes(this.protocol);
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new Outbound( return new Outbound(
json.tag, json.tag,
json.protocol, json.protocol,
@@ -620,8 +694,8 @@ class Outbound extends CommonClass {
static fromLink(link) { static fromLink(link) {
data = link.split('://'); data = link.split('://');
if(data.length !=2) return null; if (data.length != 2) return null;
switch(data[0].toLowerCase()){ switch (data[0].toLowerCase()) {
case Protocols.VMess: case Protocols.VMess:
return this.fromVmessLink(JSON.parse(Base64.decode(data[1]))); return this.fromVmessLink(JSON.parse(Base64.decode(data[1])));
case Protocols.VLESS: 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 stream = new StreamSettings(json.net, json.tls);
let network = json.net; let network = json.net;
@@ -647,16 +721,16 @@ class Outbound extends CommonClass {
stream.type = json.type; stream.type = json.type;
stream.seed = json.path; stream.seed = json.path;
} else if (network === 'ws') { } else if (network === 'ws') {
stream.ws = new WsStreamSettings(json.path,json.host); stream.ws = new WsStreamSettings(json.path, json.host);
} else if (network === 'grpc') { } else if (network === 'grpc') {
stream.grpc = new GrpcStreamSettings(json.path, json.authority, json.type == 'multi'); stream.grpc = new GrpcStreamSettings(json.path, json.authority, json.type == 'multi');
} else if (network === 'httpupgrade') { } else if (network === 'httpupgrade') {
stream.httpupgrade = new HttpUpgradeStreamSettings(json.path,json.host); stream.httpupgrade = new HttpUpgradeStreamSettings(json.path, json.host);
} else if (network === 'xhttp') { } 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( stream.tls = new TlsStreamSettings(
json.sni, json.sni,
json.alpn ? json.alpn.split(',') : [], json.alpn ? json.alpn.split(',') : [],
@@ -666,10 +740,10 @@ class Outbound extends CommonClass {
const port = json.port * 1; 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); const url = new URL(link);
let type = url.searchParams.get('type') ?? 'tcp'; let type = url.searchParams.get('type') ?? 'tcp';
let security = url.searchParams.get('security') ?? 'none'; let security = url.searchParams.get('security') ?? 'none';
@@ -687,32 +761,32 @@ class Outbound extends CommonClass {
stream.kcp.type = headerType ?? 'none'; stream.kcp.type = headerType ?? 'none';
stream.kcp.seed = path; stream.kcp.seed = path;
} else if (type === 'ws') { } else if (type === 'ws') {
stream.ws = new WsStreamSettings(path,host); stream.ws = new WsStreamSettings(path, host);
} else if (type === 'grpc') { } else if (type === 'grpc') {
stream.grpc = new GrpcStreamSettings( stream.grpc = new GrpcStreamSettings(
url.searchParams.get('serviceName') ?? '', url.searchParams.get('serviceName') ?? '',
url.searchParams.get('authority') ?? '', url.searchParams.get('authority') ?? '',
url.searchParams.get('mode') == 'multi'); url.searchParams.get('mode') == 'multi');
} else if (type === 'httpupgrade') { } else if (type === 'httpupgrade') {
stream.httpupgrade = new HttpUpgradeStreamSettings(path,host); stream.httpupgrade = new HttpUpgradeStreamSettings(path, host);
} else if (type === 'xhttp') { } else if (type === 'xhttp') {
stream.xhttp = new xHTTPStreamSettings(path,host,mode); stream.xhttp = new xHTTPStreamSettings(path, host, mode);
} }
if(security == 'tls'){ if (security == 'tls') {
let fp=url.searchParams.get('fp') ?? 'none'; let fp = url.searchParams.get('fp') ?? 'none';
let alpn=url.searchParams.get('alpn'); let alpn = url.searchParams.get('alpn');
let allowInsecure=url.searchParams.get('allowInsecure'); let allowInsecure = url.searchParams.get('allowInsecure');
let sni=url.searchParams.get('sni') ?? ''; let sni = url.searchParams.get('sni') ?? '';
stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, allowInsecure == 1); stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, allowInsecure == 1);
} }
if(security == 'reality'){ if (security == 'reality') {
let pbk=url.searchParams.get('pbk'); let pbk = url.searchParams.get('pbk');
let fp=url.searchParams.get('fp'); let fp = url.searchParams.get('fp');
let sni=url.searchParams.get('sni') ?? ''; let sni = url.searchParams.get('sni') ?? '';
let sid=url.searchParams.get('sid') ?? ''; let sid = url.searchParams.get('sid') ?? '';
let spx=url.searchParams.get('spx') ?? ''; let spx = url.searchParams.get('spx') ?? '';
stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx); stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx);
} }
@@ -720,14 +794,14 @@ class Outbound extends CommonClass {
const match = link.match(regex); const match = link.match(regex);
if (!match) return null; if (!match) return null;
let [, protocol, userData, address, port, ] = match; let [, protocol, userData, address, port,] = match;
port *= 1; port *= 1;
if(protocol == 'ss') { if (protocol == 'ss') {
protocol = 'shadowsocks'; protocol = 'shadowsocks';
userData = atob(userData).split(':'); userData = atob(userData).split(':');
} }
var settings; var settings;
switch(protocol){ switch (protocol) {
case Protocols.VLESS: case Protocols.VLESS:
settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? ''); settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? '');
break; break;
@@ -735,7 +809,7 @@ class Outbound extends CommonClass {
settings = new Outbound.TrojanSettings(address, port, userData); settings = new Outbound.TrojanSettings(address, port, userData);
break; break;
case Protocols.Shadowsocks: 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); settings = new Outbound.ShadowsocksSettings(address, port, userData.join(":"), method, true);
break; break;
default: default:
@@ -832,14 +906,18 @@ Outbound.FreedomSettings = class extends CommonClass {
}; };
Outbound.FreedomSettings.Fragment = class extends CommonClass { Outbound.FreedomSettings.Fragment = class extends CommonClass {
constructor(packets='1-3',length='',interval=''){ constructor(
packets = '1-3',
length = '',
interval = ''
) {
super(); super();
this.packets = packets; this.packets = packets;
this.length = length; this.length = length;
this.interval = interval; this.interval = interval;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new Outbound.FreedomSettings.Fragment( return new Outbound.FreedomSettings.Fragment(
json.packets, json.packets,
json.length, json.length,
@@ -883,7 +961,7 @@ Outbound.BlackholeSettings = class extends CommonClass {
this.type = type; this.type = type;
} }
static fromJson(json={}) { static fromJson(json = {}) {
return new Outbound.BlackholeSettings( return new Outbound.BlackholeSettings(
json.response ? json.response.type : undefined, json.response ? json.response.type : undefined,
); );
@@ -891,14 +969,14 @@ Outbound.BlackholeSettings = class extends CommonClass {
toJson() { toJson() {
return { return {
response: ObjectUtil.isEmpty(this.type) ? undefined : {type: this.type}, response: ObjectUtil.isEmpty(this.type) ? undefined : { type: this.type },
}; };
} }
}; };
Outbound.DNSSettings = class extends CommonClass { Outbound.DNSSettings = class extends CommonClass {
constructor( constructor(
network = 'udp', network = 'udp',
address = '1.1.1.1', address = '',
port = 53, port = 53,
nonIPQuery = 'drop', nonIPQuery = 'drop',
blockTypes = [] blockTypes = []
@@ -922,19 +1000,21 @@ Outbound.DNSSettings = class extends CommonClass {
} }
}; };
Outbound.VmessSettings = class extends CommonClass { Outbound.VmessSettings = class extends CommonClass {
constructor(address, port, id) { constructor(address, port, id, security) {
super(); super();
this.address = address; this.address = address;
this.port = port; this.port = port;
this.id = id; this.id = id;
this.security = security;
} }
static fromJson(json={}) { static fromJson(json = {}) {
if(ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VmessSettings(); if (ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VmessSettings();
return new Outbound.VmessSettings( return new Outbound.VmessSettings(
json.vnext[0].address, json.vnext[0].address,
json.vnext[0].port, json.vnext[0].port,
json.vnext[0].users[0].id, json.vnext[0].users[0].id,
json.vnext[0].users[0].security,
); );
} }
@@ -943,13 +1023,13 @@ Outbound.VmessSettings = class extends CommonClass {
vnext: [{ vnext: [{
address: this.address, address: this.address,
port: this.port, port: this.port,
users: [{id: this.id}], users: [{ id: this.id, security: this.security }],
}], }],
}; };
} }
}; };
Outbound.VLESSSettings = class extends CommonClass { Outbound.VLESSSettings = class extends CommonClass {
constructor(address, port, id, flow, encryption='none') { constructor(address, port, id, flow, encryption = 'none') {
super(); super();
this.address = address; this.address = address;
this.port = port; this.port = port;
@@ -958,8 +1038,8 @@ Outbound.VLESSSettings = class extends CommonClass {
this.encryption = encryption this.encryption = encryption
} }
static fromJson(json={}) { static fromJson(json = {}) {
if(ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VLESSSettings(); if (ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VLESSSettings();
return new Outbound.VLESSSettings( return new Outbound.VLESSSettings(
json.vnext[0].address, json.vnext[0].address,
json.vnext[0].port, json.vnext[0].port,
@@ -974,7 +1054,7 @@ Outbound.VLESSSettings = class extends CommonClass {
vnext: [{ vnext: [{
address: this.address, address: this.address,
port: this.port, 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; this.password = password;
} }
static fromJson(json={}) { static fromJson(json = {}) {
if(ObjectUtil.isArrEmpty(json.servers)) return new Outbound.TrojanSettings(); if (ObjectUtil.isArrEmpty(json.servers)) return new Outbound.TrojanSettings();
return new Outbound.TrojanSettings( return new Outbound.TrojanSettings(
json.servers[0].address, json.servers[0].address,
json.servers[0].port, json.servers[0].port,
@@ -1007,24 +1087,26 @@ Outbound.TrojanSettings = class extends CommonClass {
} }
}; };
Outbound.ShadowsocksSettings = class extends CommonClass { Outbound.ShadowsocksSettings = class extends CommonClass {
constructor(address, port, password, method, uot) { constructor(address, port, password, method, uot, UoTVersion) {
super(); super();
this.address = address; this.address = address;
this.port = port; this.port = port;
this.password = password; this.password = password;
this.method = method; this.method = method;
this.uot = uot; this.uot = uot;
this.UoTVersion = UoTVersion;
} }
static fromJson(json={}) { static fromJson(json = {}) {
let servers = json.servers; let servers = json.servers;
if(ObjectUtil.isArrEmpty(servers)) servers=[{}]; if (ObjectUtil.isArrEmpty(servers)) servers = [{}];
return new Outbound.ShadowsocksSettings( return new Outbound.ShadowsocksSettings(
servers[0].address, servers[0].address,
servers[0].port, servers[0].port,
servers[0].password, servers[0].password,
servers[0].method, servers[0].method,
servers[0].uot, servers[0].uot,
servers[0].UoTVersion,
); );
} }
@@ -1036,10 +1118,12 @@ Outbound.ShadowsocksSettings = class extends CommonClass {
password: this.password, password: this.password,
method: this.method, method: this.method,
uot: this.uot, uot: this.uot,
UoTVersion: this.UoTVersion,
}], }],
}; };
} }
}; };
Outbound.SocksSettings = class extends CommonClass { Outbound.SocksSettings = class extends CommonClass {
constructor(address, port, user, pass) { constructor(address, port, user, pass) {
super(); super();
@@ -1049,9 +1133,9 @@ Outbound.SocksSettings = class extends CommonClass {
this.pass = pass; this.pass = pass;
} }
static fromJson(json={}) { static fromJson(json = {}) {
let servers = json.servers; let servers = json.servers;
if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}]; if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }];
return new Outbound.SocksSettings( return new Outbound.SocksSettings(
servers[0].address, servers[0].address,
servers[0].port, servers[0].port,
@@ -1065,7 +1149,7 @@ Outbound.SocksSettings = class extends CommonClass {
servers: [{ servers: [{
address: this.address, address: this.address,
port: this.port, 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; this.pass = pass;
} }
static fromJson(json={}) { static fromJson(json = {}) {
let servers = json.servers; let servers = json.servers;
if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}]; if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }];
return new Outbound.HttpSettings( return new Outbound.HttpSettings(
servers[0].address, servers[0].address,
servers[0].port, servers[0].port,
@@ -1095,16 +1179,23 @@ Outbound.HttpSettings = class extends CommonClass {
servers: [{ servers: [{
address: this.address, address: this.address,
port: this.port, 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 { Outbound.WireguardSettings = class extends CommonClass {
constructor( constructor(
mtu=1420, secretKey='', mtu = 1420,
address='', workers=2, domainStrategy='', reserved='', secretKey = '',
peers=[new Outbound.WireguardSettings.Peer()], kernelMode=false) { address = [''],
workers = 2,
domainStrategy = '',
reserved = '',
peers = [new Outbound.WireguardSettings.Peer()],
kernelMode = false,
) {
super(); super();
this.mtu = mtu; this.mtu = mtu;
this.secretKey = secretKey; this.secretKey = secretKey;
@@ -1125,7 +1216,7 @@ Outbound.WireguardSettings = class extends CommonClass {
this.peers.splice(index, 1); this.peers.splice(index, 1);
} }
static fromJson(json={}){ static fromJson(json = {}) {
return new Outbound.WireguardSettings( return new Outbound.WireguardSettings(
json.mtu, json.mtu,
json.secretKey, json.secretKey,
@@ -1140,10 +1231,10 @@ Outbound.WireguardSettings = class extends CommonClass {
toJson() { toJson() {
return { return {
mtu: this.mtu?? undefined, mtu: this.mtu ?? undefined,
secretKey: this.secretKey, secretKey: this.secretKey,
address: this.address ? this.address.split(",") : [], address: this.address ? this.address.split(",") : [],
workers: this.workers?? undefined, workers: this.workers ?? undefined,
domainStrategy: WireguardDomainStrategy.includes(this.domainStrategy) ? this.domainStrategy : undefined, domainStrategy: WireguardDomainStrategy.includes(this.domainStrategy) ? this.domainStrategy : undefined,
reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined, reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined,
peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers), peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers),
@@ -1151,8 +1242,15 @@ Outbound.WireguardSettings = class extends CommonClass {
}; };
} }
}; };
Outbound.WireguardSettings.Peer = 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(); super();
this.publicKey = publicKey; this.publicKey = publicKey;
this.psk = psk; this.psk = psk;
@@ -1161,7 +1259,7 @@ Outbound.WireguardSettings.Peer = class extends CommonClass {
this.keepAlive = keepAlive; this.keepAlive = keepAlive;
} }
static fromJson(json={}){ static fromJson(json = {}) {
return new Outbound.WireguardSettings.Peer( return new Outbound.WireguardSettings.Peer(
json.publicKey, json.publicKey,
json.preSharedKey, json.preSharedKey,
@@ -1174,10 +1272,10 @@ Outbound.WireguardSettings.Peer = class extends CommonClass {
toJson() { toJson() {
return { return {
publicKey: this.publicKey, 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, allowedIPs: this.allowedIPs ? this.allowedIPs : undefined,
endpoint: this.endpoint, endpoint: this.endpoint,
keepAlive: this.keepAlive?? undefined, keepAlive: this.keepAlive ?? undefined,
}; };
} }
}; };

View File

@@ -49,6 +49,7 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
g.GET("/getDb", a.getDb) g.GET("/getDb", a.getDb)
g.POST("/importDB", a.importDB) g.POST("/importDB", a.importDB)
g.POST("/getNewX25519Cert", a.getNewX25519Cert) g.POST("/getNewX25519Cert", a.getNewX25519Cert)
g.POST("/getNewmldsa65", a.getNewmldsa65)
} }
func (a *ServerController) refreshStatus() { func (a *ServerController) refreshStatus() {
@@ -186,3 +187,12 @@ func (a *ServerController) getNewX25519Cert(c *gin.Context) {
} }
jsonObj(c, cert, nil) 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)
}

View File

@@ -2,7 +2,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="renderer" content="webkit"> <meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="robots" content="noindex,nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ .base_path }}assets/ant-design-vue@1.7.8/antd.min.css"> <link rel="stylesheet" href="{{ .base_path }}assets/ant-design-vue@1.7.8/antd.min.css">
<link rel="stylesheet" href="{{ .base_path }}assets/element-ui@2.15.0/theme-chalk/display.css"> <link rel="stylesheet" href="{{ .base_path }}assets/element-ui@2.15.0/theme-chalk/display.css">

View File

@@ -66,7 +66,7 @@
</a-divider> </a-divider>
<a-form-item label='Type'> <a-form-item label='Type'>
<a-select v-model="noise.type" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select v-model="noise.type" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="s in ['rand','base64','str']" :value="s">[[ s ]]</a-select-option> <a-select-option v-for="s in ['rand','base64','str','hex']" :value="s">[[ s ]]</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label='Packet'> <a-form-item label='Packet'>
@@ -460,12 +460,20 @@
<a-select-option v-for="tag in ['', ...outModal.tags]" :value="tag">[[ tag ]]</a-select-option> <a-select-option v-for="tag in ['', ...outModal.tags]" :value="tag">[[ tag ]]</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label="TCP Fast Open"> <a-form-item label='Address Port Strategy'>
<a-switch v-model="outbound.stream.sockopt.tcpFastOpen"></a-switch> <a-select v-model="outbound.stream.sockopt.addressPortStrategy" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in Address_Port_Strategy" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item> </a-form-item>
<a-form-item label="Keep Alive Interval"> <a-form-item label="Keep Alive Interval">
<a-input-number v-model.number="outbound.stream.sockopt.tcpKeepAliveInterval" :min="0"></a-input-number> <a-input-number v-model.number="outbound.stream.sockopt.tcpKeepAliveInterval" :min="0"></a-input-number>
</a-form-item> </a-form-item>
<a-form-item label="TCP Fast Open">
<a-switch v-model="outbound.stream.sockopt.tcpFastOpen"></a-switch>
</a-form-item>
<a-form-item label="Multipath TCP">
<a-switch v-model.trim="outbound.stream.sockopt.tcpMptcp"></a-switch>
</a-form-item>
<a-form-item label="Penetrate"> <a-form-item label="Penetrate">
<a-switch v-model="outbound.stream.sockopt.penetrate"></a-switch> <a-switch v-model="outbound.stream.sockopt.penetrate"></a-switch>
</a-form-item> </a-form-item>

View File

@@ -42,5 +42,14 @@
<a-form-item label=" "> <a-form-item label=" ">
<a-button type="primary" icon="import" @click="getNewX25519Cert">Get New Cert</a-button> <a-button type="primary" icon="import" @click="getNewX25519Cert">Get New Cert</a-button>
</a-form-item> </a-form-item>
<a-form-item label="mldsa65 Seed">
<a-input v-model="inbound.stream.reality.mldsa65Seed"></a-input>
</a-form-item>
<a-form-item label="mldsa65 Verify">
<a-textarea v-model="inbound.stream.reality.settings.mldsa65Verify"></a-textarea>
</a-form-item>
<a-form-item label=" ">
<a-button type="primary" icon="import" @click="getNewmldsa65">Get New Seed</a-button>
</a-form-item>
</template> </template>
{{end}} {{end}}

View File

@@ -33,6 +33,9 @@
<a-form-item label="Max Upload Size (Byte)" v-if="inbound.stream.xhttp.mode === 'packet-up'"> <a-form-item label="Max Upload Size (Byte)" v-if="inbound.stream.xhttp.mode === 'packet-up'">
<a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input> <a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="Stream-Up Server" v-if="inbound.stream.xhttp.mode === 'stream-up'">
<a-input v-model.trim="inbound.stream.xhttp.scStreamUpServerSecs"></a-input>
</a-form-item>
<a-form-item label="Padding Bytes"> <a-form-item label="Padding Bytes">
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input> <a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
</a-form-item> </a-form-item>

View File

@@ -132,6 +132,16 @@
inModal.inbound.stream.reality.privateKey = msg.obj.privateKey; inModal.inbound.stream.reality.privateKey = msg.obj.privateKey;
inModal.inbound.stream.reality.settings.publicKey = msg.obj.publicKey; 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;
},
}, },
}); });

View File

@@ -328,7 +328,7 @@
:dropdown-class-name="themeSwitcher.currentTheme" :dropdown-class-name="themeSwitcher.currentTheme"
@change="(value) => updateNoiseType(index, value)"> @change="(value) => updateNoiseType(index, value)">
<a-select-option :value="p" :label="p" <a-select-option :value="p" :label="p"
v-for="p in ['rand', 'base64', 'str']" :key="p"> v-for="p in ['rand', 'base64', 'str', 'hex']" :key="p">
[[ p ]] </a-select-option> [[ p ]] </a-select-option>
</a-select> </a-select>
</a-col> </a-col>

View File

@@ -174,10 +174,10 @@ new Vue({
}, },
async register(){ async register(){
warpModal.loading(true); warpModal.loading(true);
keys = Wireguard.generateKeypair(); const keys = Wireguard.generateKeypair();
const msg = await HttpUtil.post('/xui/xray/warp/reg',keys); const msg = await HttpUtil.post('/xui/xray/warp/reg',keys);
if (msg.success) { if (msg.success) {
resp = JSON.parse(msg.obj); const resp = JSON.parse(msg.obj);
warpModal.warpData = resp.data; warpModal.warpData = resp.data;
warpModal.warpConfig = resp.config; warpModal.warpConfig = resp.config;
this.collectConfig(); this.collectConfig();

View File

@@ -1258,8 +1258,7 @@
} }
newTemplateSettings.routing.balancers.push(tmpBalancer); newTemplateSettings.routing.balancers.push(tmpBalancer);
this.templateSettings = newTemplateSettings; this.templateSettings = newTemplateSettings;
if (balancer.strategy == 'leastPing' || balancer.strategy == 'leastLoad') this.updateObservatorySelectors();
this.updateObservatorySelectors();
balancerModal.close(); balancerModal.close();
this.changeObsCode(); this.changeObsCode();
}, },
@@ -1307,8 +1306,7 @@
}); });
} }
this.templateSettings = newTemplateSettings; this.templateSettings = newTemplateSettings;
if (balancer.strategy == 'leastPing' || balancer.strategy == 'leastLoad') this.updateObservatorySelectors();
this.updateObservatorySelectors();
balancerModal.close(); balancerModal.close();
this.changeObsCode(); this.changeObsCode();
}, },
@@ -1318,7 +1316,11 @@
updateObservatorySelectors(){ updateObservatorySelectors(){
newTemplateSettings = this.templateSettings; newTemplateSettings = this.templateSettings;
const leastPings = this.balancersData.filter((b) => b.strategy == 'leastPing'); 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 (leastPings.length>0){
if (!newTemplateSettings.observatory) if (!newTemplateSettings.observatory)
newTemplateSettings.observatory = this.defaultObservatory; newTemplateSettings.observatory = this.defaultObservatory;

View File

@@ -79,5 +79,6 @@
} }
] ]
}, },
"stats": {} "stats": {},
"metrics": {}
} }

View File

@@ -564,3 +564,29 @@ func (s *ServerService) GetNewX25519Cert() (interface{}, error) {
return keyPair, nil 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
}

View File

@@ -56,8 +56,7 @@ func (s *WarpService) GetWarpConfig() (string, error) {
return "", err return "", err
} }
defer resp.Body.Close() defer resp.Body.Close()
buffer := bytes.NewBuffer(make([]byte, 8192)) buffer := &bytes.Buffer{}
buffer.Reset()
_, err = buffer.ReadFrom(resp.Body) _, err = buffer.ReadFrom(resp.Body)
if err != nil { if err != nil {
return "", err return "", err
@@ -87,8 +86,7 @@ func (s *WarpService) RegWarp(secretKey string, publicKey string) (string, error
return "", err return "", err
} }
defer resp.Body.Close() defer resp.Body.Close()
buffer := bytes.NewBuffer(make([]byte, 8192)) buffer := &bytes.Buffer{}
buffer.Reset()
_, err = buffer.ReadFrom(resp.Body) _, err = buffer.ReadFrom(resp.Body)
if err != nil { if err != nil {
return "", err return "", err
@@ -144,8 +142,7 @@ func (s *WarpService) SetWarpLicense(license string) (string, error) {
return "", err return "", err
} }
defer resp.Body.Close() defer resp.Body.Close()
buffer := bytes.NewBuffer(make([]byte, 8192)) buffer := &bytes.Buffer{}
buffer.Reset()
_, err = buffer.ReadFrom(resp.Body) _, err = buffer.ReadFrom(resp.Body)
if err != nil { if err != nil {
return "", err return "", err

24
x-ui.sh
View File

@@ -56,8 +56,8 @@ elif [[ "${release}" == "centos" ]]; then
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1 echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "ubuntu" ]]; then elif [[ "${release}" == "ubuntu" ]]; then
if [[ ${os_version} -lt 2004 ]]; then if [[ ${os_version} -lt 2204 ]]; then
echo -e "${red} Please use Ubuntu 20 or higher version!${plain}\n" && exit 1 echo -e "${red} Please use Ubuntu 22 or higher version!${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "fedora" ]]; then elif [[ "${release}" == "fedora" ]]; then
if [[ ${os_version} -lt 36 ]]; 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 echo -e "${red} Please use Amazon Linux 2023!${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "debian" ]]; then elif [[ "${release}" == "debian" ]]; then
if [[ ${os_version} -lt 11 ]]; then if [[ ${os_version} -lt 12 ]]; then
echo -e "${red} Please use Debian 11 or higher ${plain}\n" && exit 1 echo -e "${red} Please use Debian 12 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "almalinux" ]]; then elif [[ "${release}" == "almalinux" ]]; then
if [[ ${os_version} -lt 80 ]]; then if [[ ${os_version} -lt 95 ]]; then
echo -e "${red} Please use AlmaLinux 8.0 or higher ${plain}\n" && exit 1 echo -e "${red} Please use AlmaLinux 9.5 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "rocky" ]]; then elif [[ "${release}" == "rocky" ]]; then
if [[ ${os_version} -lt 8 ]]; then if [[ ${os_version} -lt 95 ]]; then
echo -e "${red} Please use Rocky Linux 8 or higher ${plain}\n" && exit 1 echo -e "${red} Please use Rocky Linux 9.5 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "ol" ]]; then elif [[ "${release}" == "ol" ]]; then
if [[ ${os_version} -lt 8 ]]; then if [[ ${os_version} -lt 8 ]]; then
@@ -86,8 +86,8 @@ elif [[ "${release}" == "ol" ]]; then
else else
echo -e "${red}Your operating system is not supported by this script.${plain}\n" 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 "Please ensure you are using one of the following supported operating systems:"
echo "- Ubuntu 20.04+" echo "- Ubuntu 22.04+"
echo "- Debian 11+" echo "- Debian 12+"
echo "- CentOS 8+" echo "- CentOS 8+"
echo "- OpenEuler 22.03+" echo "- OpenEuler 22.03+"
echo "- Fedora 36+" echo "- Fedora 36+"
@@ -95,8 +95,8 @@ else
echo "- Parch Linux" echo "- Parch Linux"
echo "- Manjaro" echo "- Manjaro"
echo "- Armbian" echo "- Armbian"
echo "- AlmaLinux 8.0+" echo "- AlmaLinux 9.5+"
echo "- Rocky Linux 8+" echo "- Rocky Linux 9.5+"
echo "- Oracle Linux 8+" echo "- Oracle Linux 8+"
echo "- OpenSUSE Tumbleweed" echo "- OpenSUSE Tumbleweed"
echo "- Amazon Linux 2023" echo "- Amazon Linux 2023"

View File

@@ -20,6 +20,7 @@ type Config struct {
FakeDNS json_util.RawMessage `json:"fakedns"` FakeDNS json_util.RawMessage `json:"fakedns"`
Observatory json_util.RawMessage `json:"observatory"` Observatory json_util.RawMessage `json:"observatory"`
BurstObservatory json_util.RawMessage `json:"burstObservatory"` BurstObservatory json_util.RawMessage `json:"burstObservatory"`
Metrics json_util.RawMessage `json:"metrics"`
} }
func (c *Config) Equals(other *Config) bool { 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) { if !bytes.Equal(c.FakeDNS, other.FakeDNS) {
return false return false
} }
if !bytes.Equal(c.Metrics, other.Metrics) {
return false
}
return true return true
} }

View File

@@ -25,7 +25,7 @@ func (lw *LogWriter) Write(m []byte) (n int, err error) {
if crashRegex.MatchString(message) { if crashRegex.MatchString(message) {
logger.Debug("Core crash detected:\n", message) logger.Debug("Core crash detected:\n", message)
lw.lastLine = message lw.lastLine = message
err1 := writeCrachReport(m) err1 := writeCrashReport(m)
if err1 != nil { if err1 != nil {
logger.Error("Unable to write crash report:", err1) logger.Error("Unable to write crash report:", err1)
} }

View File

@@ -192,7 +192,7 @@ func (p *process) Stop() error {
return p.cmd.Process.Signal(syscall.SIGTERM) 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" crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log"
return os.WriteFile(crashReportPath, m, os.ModePerm) return os.WriteFile(crashReportPath, m, os.ModePerm)
} }