3x-ui/web/assets/js/model/inbound.js

2623 lines
79 KiB
JavaScript
Raw Normal View History

2023-02-09 19:18:06 +00:00
const Protocols = {
VMESS: 'vmess',
VLESS: 'vless',
TROJAN: 'trojan',
SHADOWSOCKS: 'shadowsocks',
TUNNEL: 'tunnel',
MIXED: 'mixed',
2023-02-09 19:18:06 +00:00
HTTP: 'http',
WIREGUARD: 'wireguard',
TUN: 'tun',
2023-02-09 19:18:06 +00:00
};
const SSMethods = {
AES_256_GCM: 'aes-256-gcm',
CHACHA20_POLY1305: 'chacha20-poly1305',
CHACHA20_IETF_POLY1305: 'chacha20-ietf-poly1305',
XCHACHA20_IETF_POLY1305: 'xchacha20-ietf-poly1305',
BLAKE3_AES_128_GCM: '2022-blake3-aes-128-gcm',
BLAKE3_AES_256_GCM: '2022-blake3-aes-256-gcm',
BLAKE3_CHACHA20_POLY1305: '2022-blake3-chacha20-poly1305',
2023-02-09 19:18:06 +00:00
};
const TLS_FLOW_CONTROL = {
VISION: "xtls-rprx-vision",
VISION_UDP443: "xtls-rprx-vision-udp443",
2023-02-09 19:18:06 +00:00
};
const TLS_VERSION_OPTION = {
TLS10: "1.0",
TLS11: "1.1",
TLS12: "1.2",
TLS13: "1.3",
2023-03-16 22:01:14 +00:00
};
2023-02-09 19:18:06 +00:00
const TLS_CIPHER_OPTION = {
AES_128_GCM: "TLS_AES_128_GCM_SHA256",
AES_256_GCM: "TLS_AES_256_GCM_SHA384",
CHACHA20_POLY1305: "TLS_CHACHA20_POLY1305_SHA256",
ECDHE_ECDSA_AES_128_CBC: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
ECDHE_ECDSA_AES_256_CBC: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
ECDHE_RSA_AES_128_CBC: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
ECDHE_RSA_AES_256_CBC: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
ECDHE_ECDSA_AES_128_GCM: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
ECDHE_ECDSA_AES_256_GCM: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
ECDHE_RSA_AES_128_GCM: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
ECDHE_RSA_AES_256_GCM: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
ECDHE_ECDSA_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
ECDHE_RSA_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
};
const UTLS_FINGERPRINT = {
UTLS_CHROME: "chrome",
UTLS_FIREFOX: "firefox",
UTLS_SAFARI: "safari",
UTLS_IOS: "ios",
UTLS_android: "android",
UTLS_EDGE: "edge",
UTLS_360: "360",
UTLS_QQ: "qq",
UTLS_RANDOM: "random",
UTLS_RANDOMIZED: "randomized",
2025-03-03 09:20:52 +00:00
UTLS_RONDOMIZEDNOALPN: "randomizednoalpn",
2024-12-17 22:12:40 +00:00
UTLS_UNSAFE: "unsafe",
2023-02-09 19:18:06 +00:00
};
2023-03-16 22:01:14 +00:00
const ALPN_OPTION = {
H3: "h3",
H2: "h2",
HTTP1: "http/1.1",
};
const SNIFFING_OPTION = {
HTTP: "http",
TLS: "tls",
QUIC: "quic",
FAKEDNS: "fakedns"
2023-03-16 22:01:14 +00:00
};
const USAGE_OPTION = {
ENCIPHERMENT: "encipherment",
VERIFY: "verify",
ISSUE: "issue",
};
2024-05-24 07:57:14 +00:00
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",
};
2024-05-24 07:57:14 +00:00
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",
};
2024-11-14 09:39:51 +00:00
const MODE_OPTION = {
AUTO: "auto",
PACKET_UP: "packet-up",
STREAM_UP: "stream-up",
2024-12-03 20:57:44 +00:00
STREAM_ONE: "stream-one",
2024-11-14 09:39:51 +00:00
};
2023-02-09 19:18:06 +00:00
Object.freeze(Protocols);
Object.freeze(SSMethods);
Object.freeze(TLS_FLOW_CONTROL);
Object.freeze(TLS_VERSION_OPTION);
Object.freeze(TLS_CIPHER_OPTION);
Object.freeze(UTLS_FINGERPRINT);
2023-03-16 22:01:14 +00:00
Object.freeze(ALPN_OPTION);
Object.freeze(SNIFFING_OPTION);
Object.freeze(USAGE_OPTION);
2024-05-24 07:57:14 +00:00
Object.freeze(DOMAIN_STRATEGY_OPTION);
Object.freeze(TCP_CONGESTION_OPTION);
Object.freeze(USERS_SECURITY);
2024-11-14 09:39:51 +00:00
Object.freeze(MODE_OPTION);
2023-02-09 19:18:06 +00:00
class XrayCommonClass {
static toJsonArray(arr) {
return arr.map(obj => obj.toJson());
}
static fromJson() {
return new XrayCommonClass();
}
toJson() {
return this;
}
toString(format = true) {
2023-02-09 19:18:06 +00:00
return format ? JSON.stringify(this.toJson(), null, 2) : JSON.stringify(this.toJson());
}
static toHeaders(v2Headers) {
let newHeaders = [];
if (v2Headers) {
Object.keys(v2Headers).forEach(key => {
let values = v2Headers[key];
if (typeof (values) === 'string') {
2023-02-09 19:18:06 +00:00
newHeaders.push({ name: key, value: values });
} else {
for (let i = 0; i < values.length; ++i) {
newHeaders.push({ name: key, value: values[i] });
}
}
});
}
return newHeaders;
}
static toV2Headers(headers, arr = true) {
2023-02-09 19:18:06 +00:00
let v2Headers = {};
for (let i = 0; i < headers.length; ++i) {
let name = headers[i].name;
let value = headers[i].value;
if (ObjectUtil.isEmpty(name) || ObjectUtil.isEmpty(value)) {
continue;
}
if (!(name in v2Headers)) {
v2Headers[name] = arr ? [value] : value;
} else {
if (arr) {
v2Headers[name].push(value);
} else {
v2Headers[name] = value;
}
}
}
return v2Headers;
}
}
class TcpStreamSettings extends XrayCommonClass {
constructor(
acceptProxyProtocol = false,
type = 'none',
request = new TcpStreamSettings.TcpRequest(),
response = new TcpStreamSettings.TcpResponse(),
) {
2023-02-09 19:18:06 +00:00
super();
this.acceptProxyProtocol = acceptProxyProtocol;
2023-02-09 19:18:06 +00:00
this.type = type;
this.request = request;
this.response = response;
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
let header = json.header;
if (!header) {
header = {};
}
2023-04-10 11:03:50 +00:00
return new TcpStreamSettings(json.acceptProxyProtocol,
2023-02-09 19:18:06 +00:00
header.type,
TcpStreamSettings.TcpRequest.fromJson(header.request),
TcpStreamSettings.TcpResponse.fromJson(header.response),
);
}
toJson() {
return {
acceptProxyProtocol: this.acceptProxyProtocol,
2023-02-09 19:18:06 +00:00
header: {
type: this.type,
request: this.type === 'http' ? this.request.toJson() : undefined,
response: this.type === 'http' ? this.response.toJson() : undefined,
},
};
}
}
TcpStreamSettings.TcpRequest = class extends XrayCommonClass {
constructor(
version = '1.1',
method = 'GET',
path = ['/'],
headers = [],
2023-02-09 19:18:06 +00:00
) {
super();
this.version = version;
this.method = method;
this.path = path.length === 0 ? ['/'] : path;
this.headers = headers;
}
addPath(path) {
this.path.push(path);
}
removePath(index) {
this.path.splice(index, 1);
}
addHeader(name, value) {
this.headers.push({ name: name, value: value });
}
removeHeader(index) {
this.headers.splice(index, 1);
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new TcpStreamSettings.TcpRequest(
json.version,
json.method,
json.path,
XrayCommonClass.toHeaders(json.headers),
);
}
toJson() {
return {
version: this.version,
2023-02-09 19:18:06 +00:00
method: this.method,
path: ObjectUtil.clone(this.path),
headers: XrayCommonClass.toV2Headers(this.headers),
};
}
};
TcpStreamSettings.TcpResponse = class extends XrayCommonClass {
constructor(
version = '1.1',
status = '200',
reason = 'OK',
headers = [],
2023-02-09 19:18:06 +00:00
) {
super();
this.version = version;
this.status = status;
this.reason = reason;
this.headers = headers;
}
addHeader(name, value) {
this.headers.push({ name: name, value: value });
}
removeHeader(index) {
this.headers.splice(index, 1);
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new TcpStreamSettings.TcpResponse(
json.version,
json.status,
json.reason,
XrayCommonClass.toHeaders(json.headers),
);
}
toJson() {
return {
version: this.version,
status: this.status,
reason: this.reason,
headers: XrayCommonClass.toV2Headers(this.headers),
};
}
};
class KcpStreamSettings extends XrayCommonClass {
constructor(
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
mtu = 1250,
tti = 50,
uplinkCapacity = 5,
downlinkCapacity = 20,
congestion = false,
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
readBufferSize = 2,
writeBufferSize = 2,
type = 'none',
seed = RandomUtil.randomSeq(10),
) {
2023-02-09 19:18:06 +00:00
super();
this.mtu = mtu;
this.tti = tti;
this.upCap = uplinkCapacity;
this.downCap = downlinkCapacity;
this.congestion = congestion;
this.readBuffer = readBufferSize;
this.writeBuffer = writeBufferSize;
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
this.type = type;
this.seed = seed;
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new KcpStreamSettings(
json.mtu,
json.tti,
json.uplinkCapacity,
json.downlinkCapacity,
json.congestion,
json.readBufferSize,
json.writeBufferSize,
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
ObjectUtil.isEmpty(json.header) ? 'none' : json.header.type,
json.seed,
2023-02-09 19:18:06 +00:00
);
}
toJson() {
return {
mtu: this.mtu,
tti: this.tti,
uplinkCapacity: this.upCap,
downlinkCapacity: this.downCap,
congestion: this.congestion,
readBufferSize: this.readBuffer,
writeBufferSize: this.writeBuffer,
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
header: {
type: this.type,
},
seed: this.seed,
2023-02-09 19:18:06 +00:00
};
}
}
class WsStreamSettings extends XrayCommonClass {
constructor(
acceptProxyProtocol = false,
path = '/',
host = '',
2024-12-03 21:07:58 +00:00
headers = [],
heartbeatPeriod = 0,
) {
2023-02-09 19:18:06 +00:00
super();
this.acceptProxyProtocol = acceptProxyProtocol;
this.path = path;
2024-04-01 12:32:02 +00:00
this.host = host;
2023-02-09 19:18:06 +00:00
this.headers = headers;
2024-12-03 21:07:58 +00:00
this.heartbeatPeriod = heartbeatPeriod;
2023-02-09 19:18:06 +00:00
}
addHeader(name, value) {
this.headers.push({ name: name, value: value });
}
removeHeader(index) {
this.headers.splice(index, 1);
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new WsStreamSettings(
json.acceptProxyProtocol,
json.path,
2024-04-01 12:32:02 +00:00
json.host,
2023-02-09 19:18:06 +00:00
XrayCommonClass.toHeaders(json.headers),
2024-12-03 21:07:58 +00:00
json.heartbeatPeriod,
2023-02-09 19:18:06 +00:00
);
}
toJson() {
return {
acceptProxyProtocol: this.acceptProxyProtocol,
path: this.path,
2024-04-01 12:32:02 +00:00
host: this.host,
2023-02-09 19:18:06 +00:00
headers: XrayCommonClass.toV2Headers(this.headers, false),
2024-12-03 21:07:58 +00:00
heartbeatPeriod: this.heartbeatPeriod,
2023-02-09 19:18:06 +00:00
};
}
}
class GrpcStreamSettings extends XrayCommonClass {
2023-04-27 20:45:06 +00:00
constructor(
serviceName = "",
authority = "",
multiMode = false,
) {
2023-02-09 19:18:06 +00:00
super();
this.serviceName = serviceName;
2024-03-11 09:30:00 +00:00
this.authority = authority;
this.multiMode = multiMode;
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
2023-04-27 20:45:06 +00:00
return new GrpcStreamSettings(
json.serviceName,
2024-03-11 09:30:00 +00:00
json.authority,
json.multiMode
);
2023-02-09 19:18:06 +00:00
}
toJson() {
return {
serviceName: this.serviceName,
2024-03-11 09:30:00 +00:00
authority: this.authority,
multiMode: this.multiMode,
2023-02-09 19:18:06 +00:00
}
}
}
2024-04-02 20:11:06 +00:00
class HTTPUpgradeStreamSettings extends XrayCommonClass {
constructor(
acceptProxyProtocol = false,
path = '/',
host = '',
headers = []
) {
2024-03-11 07:36:33 +00:00
super();
this.acceptProxyProtocol = acceptProxyProtocol;
this.path = path;
this.host = host;
2024-04-02 20:11:06 +00:00
this.headers = headers;
}
addHeader(name, value) {
this.headers.push({ name: name, value: value });
}
removeHeader(index) {
this.headers.splice(index, 1);
2024-03-11 07:36:33 +00:00
}
static fromJson(json = {}) {
2024-04-02 20:11:06 +00:00
return new HTTPUpgradeStreamSettings(
2024-03-11 07:36:33 +00:00
json.acceptProxyProtocol,
json.path,
json.host,
2024-04-02 20:11:06 +00:00
XrayCommonClass.toHeaders(json.headers),
2024-03-11 07:36:33 +00:00
);
}
toJson() {
return {
acceptProxyProtocol: this.acceptProxyProtocol,
path: this.path,
host: this.host,
2024-04-02 20:11:06 +00:00
headers: XrayCommonClass.toV2Headers(this.headers, false),
2024-03-11 07:36:33 +00:00
};
}
}
2024-12-03 21:24:34 +00:00
class xHTTPStreamSettings extends XrayCommonClass {
2024-07-29 11:13:37 +00:00
constructor(
path = '/',
host = '',
headers = [],
2024-12-16 09:46:05 +00:00
scMaxBufferedPosts = 30,
2024-12-05 19:15:19 +00:00
scMaxEachPostBytes = "1000000",
2025-01-26 10:07:35 +00:00
scStreamUpServerSecs = "20-80",
2024-07-29 11:13:37 +00:00
noSSEHeader = false,
2024-08-18 22:13:07 +00:00
xPaddingBytes = "100-1000",
2024-11-14 09:39:51 +00:00
mode = MODE_OPTION.AUTO,
2024-07-29 11:13:37 +00:00
) {
super();
this.path = path;
this.host = host;
this.headers = headers;
2024-12-16 09:46:05 +00:00
this.scMaxBufferedPosts = scMaxBufferedPosts;
2024-07-29 11:05:05 +00:00
this.scMaxEachPostBytes = scMaxEachPostBytes;
2025-01-21 21:43:13 +00:00
this.scStreamUpServerSecs = scStreamUpServerSecs;
2024-07-29 11:13:37 +00:00
this.noSSEHeader = noSSEHeader;
2024-08-18 22:13:07 +00:00
this.xPaddingBytes = xPaddingBytes;
2024-11-14 09:39:51 +00:00
this.mode = mode;
}
addHeader(name, value) {
this.headers.push({ name: name, value: value });
}
removeHeader(index) {
this.headers.splice(index, 1);
}
2024-07-29 11:13:37 +00:00
static fromJson(json = {}) {
2024-12-03 21:24:34 +00:00
return new xHTTPStreamSettings(
json.path,
json.host,
XrayCommonClass.toHeaders(json.headers),
2024-12-16 09:46:05 +00:00
json.scMaxBufferedPosts,
2024-07-29 11:05:05 +00:00
json.scMaxEachPostBytes,
2025-01-21 21:43:13 +00:00
json.scStreamUpServerSecs,
2024-07-29 11:13:37 +00:00
json.noSSEHeader,
2024-08-18 22:13:07 +00:00
json.xPaddingBytes,
2024-11-14 09:39:51 +00:00
json.mode,
);
}
toJson() {
return {
path: this.path,
host: this.host,
headers: XrayCommonClass.toV2Headers(this.headers, false),
2024-12-16 09:46:05 +00:00
scMaxBufferedPosts: this.scMaxBufferedPosts,
2024-07-29 11:05:05 +00:00
scMaxEachPostBytes: this.scMaxEachPostBytes,
2025-01-21 21:43:13 +00:00
scStreamUpServerSecs: this.scStreamUpServerSecs,
2024-07-29 11:13:37 +00:00
noSSEHeader: this.noSSEHeader,
2024-08-18 22:13:07 +00:00
xPaddingBytes: this.xPaddingBytes,
2024-11-14 09:39:51 +00:00
mode: this.mode,
};
}
}
2023-02-09 19:18:06 +00:00
class TlsStreamSettings extends XrayCommonClass {
constructor(
serverName = '',
minVersion = TLS_VERSION_OPTION.TLS12,
maxVersion = TLS_VERSION_OPTION.TLS13,
cipherSuites = '',
rejectUnknownSni = false,
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
verifyPeerCertInNames = ['dns.google', 'cloudflare-dns.com'],
disableSystemRoot = false,
enableSessionResumption = false,
certificates = [new TlsStreamSettings.Cert()],
2025-08-03 23:30:01 +00:00
alpn = [ALPN_OPTION.H2, ALPN_OPTION.HTTP1],
echServerKeys = '',
echForceQuery = 'none',
settings = new TlsStreamSettings.Settings()
) {
2023-02-09 19:18:06 +00:00
super();
2023-12-10 17:13:48 +00:00
this.sni = serverName;
2023-02-09 19:18:06 +00:00
this.minVersion = minVersion;
this.maxVersion = maxVersion;
this.cipherSuites = cipherSuites;
this.rejectUnknownSni = rejectUnknownSni;
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
this.verifyPeerCertInNames = Array.isArray(verifyPeerCertInNames) ? verifyPeerCertInNames.join(",") : verifyPeerCertInNames;
2024-05-22 15:38:25 +00:00
this.disableSystemRoot = disableSystemRoot;
2024-05-24 08:17:20 +00:00
this.enableSessionResumption = enableSessionResumption;
2023-02-09 19:18:06 +00:00
this.certs = certificates;
this.alpn = alpn;
this.echServerKeys = echServerKeys;
this.echForceQuery = echForceQuery;
this.settings = settings;
2023-02-09 19:18:06 +00:00
}
addCert() {
this.certs.push(new TlsStreamSettings.Cert());
2023-02-09 19:18:06 +00:00
}
removeCert(index) {
this.certs.splice(index, 1);
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
let certs;
let settings;
2023-02-09 19:18:06 +00:00
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.echConfigList);
}
2023-02-09 19:18:06 +00:00
return new TlsStreamSettings(
json.serverName,
json.minVersion,
json.maxVersion,
json.cipherSuites,
json.rejectUnknownSni,
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
json.verifyPeerCertInNames,
2024-05-22 15:38:25 +00:00
json.disableSystemRoot,
2024-05-24 08:17:20 +00:00
json.enableSessionResumption,
2023-02-09 19:18:06 +00:00
certs,
json.alpn,
json.echServerKeys,
json.echForceQuery,
settings,
2023-02-09 19:18:06 +00:00
);
}
toJson() {
return {
2023-12-10 17:13:48 +00:00
serverName: this.sni,
2023-02-09 19:18:06 +00:00
minVersion: this.minVersion,
maxVersion: this.maxVersion,
cipherSuites: this.cipherSuites,
rejectUnknownSni: this.rejectUnknownSni,
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
verifyPeerCertInNames: this.verifyPeerCertInNames.split(","),
2024-05-22 15:38:25 +00:00
disableSystemRoot: this.disableSystemRoot,
2024-05-24 08:17:20 +00:00
enableSessionResumption: this.enableSessionResumption,
2023-02-09 19:18:06 +00:00
certificates: TlsStreamSettings.toJsonArray(this.certs),
2023-03-16 22:01:14 +00:00
alpn: this.alpn,
echServerKeys: this.echServerKeys,
echForceQuery: this.echForceQuery,
settings: this.settings,
2023-02-09 19:18:06 +00:00
};
}
}
TlsStreamSettings.Cert = class extends XrayCommonClass {
2024-08-03 22:07:33 +00:00
constructor(
useFile = true,
certificateFile = '',
keyFile = '',
certificate = '',
key = '',
oneTimeLoading = false,
usage = USAGE_OPTION.ENCIPHERMENT,
buildChain = false,
) {
2023-02-09 19:18:06 +00:00
super();
this.useFile = useFile;
this.certFile = certificateFile;
this.keyFile = keyFile;
this.cert = Array.isArray(certificate) ? certificate.join('\n') : certificate;
this.key = Array.isArray(key) ? key.join('\n') : key;
this.oneTimeLoading = oneTimeLoading;
this.usage = usage;
2024-08-03 22:07:33 +00:00
this.buildChain = buildChain
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
if ('certificateFile' in json && 'keyFile' in json) {
return new TlsStreamSettings.Cert(
true,
json.certificateFile,
json.keyFile, '', '',
json.oneTimeLoading,
json.usage,
2024-08-03 22:07:33 +00:00
json.buildChain,
2023-02-09 19:18:06 +00:00
);
} else {
return new TlsStreamSettings.Cert(
false, '', '',
json.certificate.join('\n'),
json.key.join('\n'),
json.oneTimeLoading,
json.usage,
2024-08-03 22:07:33 +00:00
json.buildChain,
2023-02-09 19:18:06 +00:00
);
}
}
toJson() {
if (this.useFile) {
return {
certificateFile: this.certFile,
keyFile: this.keyFile,
oneTimeLoading: this.oneTimeLoading,
usage: this.usage,
2024-08-03 22:07:33 +00:00
buildChain: this.buildChain,
2023-02-09 19:18:06 +00:00
};
} else {
return {
certificate: this.cert.split('\n'),
key: this.key.split('\n'),
oneTimeLoading: this.oneTimeLoading,
usage: this.usage,
2024-08-03 22:07:33 +00:00
buildChain: this.buildChain,
2023-02-09 19:18:06 +00:00
};
}
}
};
2023-03-16 22:01:14 +00:00
TlsStreamSettings.Settings = class extends XrayCommonClass {
constructor(
allowInsecure = false,
fingerprint = UTLS_FINGERPRINT.UTLS_CHROME,
echConfigList = '',
) {
super();
this.allowInsecure = allowInsecure;
this.fingerprint = fingerprint;
this.echConfigList = echConfigList;
}
static fromJson(json = {}) {
return new TlsStreamSettings.Settings(
json.allowInsecure,
json.fingerprint,
json.echConfigList,
);
}
toJson() {
return {
allowInsecure: this.allowInsecure,
fingerprint: this.fingerprint,
echConfigList: this.echConfigList
};
}
2023-03-16 22:01:14 +00:00
};
2024-05-22 15:38:25 +00:00
2023-03-16 22:01:14 +00:00
2023-04-10 16:28:52 +00:00
class RealityStreamSettings extends XrayCommonClass {
2023-04-11 19:00:24 +00:00
constructor(
show = false,
xver = 0,
target = '',
serverNames = '',
privateKey = '',
2025-07-28 11:45:47 +00:00
minClientVer = '',
maxClientVer = '',
2023-04-11 19:00:24 +00:00
maxTimediff = 0,
shortIds = RandomUtil.randomShortIds(),
2025-07-24 23:22:01 +00:00
mldsa65Seed = '',
settings = new RealityStreamSettings.Settings()
) {
2023-04-10 16:28:52 +00:00
super();
// If target/serverNames are not provided, use random values
if (!target && !serverNames) {
const randomTarget = typeof getRandomRealityTarget !== 'undefined'
? getRandomRealityTarget()
: { target: 'www.apple.com:443', sni: 'www.apple.com,apple.com' };
target = randomTarget.target;
serverNames = randomTarget.sni;
}
2023-04-10 16:28:52 +00:00
this.show = show;
this.xver = xver;
2025-09-09 12:35:21 +00:00
this.target = target;
this.serverNames = Array.isArray(serverNames) ? serverNames.join(",") : serverNames;
2023-04-10 16:28:52 +00:00
this.privateKey = privateKey;
2025-07-28 11:45:47 +00:00
this.minClientVer = minClientVer;
this.maxClientVer = maxClientVer;
2023-04-10 16:28:52 +00:00
this.maxTimediff = maxTimediff;
2024-10-17 08:36:05 +00:00
this.shortIds = Array.isArray(shortIds) ? shortIds.join(",") : shortIds;
2025-07-24 23:22:01 +00:00
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,
2025-07-24 23:22:01 +00:00
json.settings.spiderX,
json.settings.mldsa65Verify,
2024-10-17 08:36:05 +00:00
);
}
2023-04-10 16:28:52 +00:00
return new RealityStreamSettings(
json.show,
json.xver,
2025-09-09 12:35:21 +00:00
json.target,
2023-04-10 16:28:52 +00:00
json.serverNames,
json.privateKey,
2025-07-28 11:45:47 +00:00
json.minClientVer,
json.maxClientVer,
2023-04-10 16:28:52 +00:00
json.maxTimediff,
json.shortIds,
2025-07-24 23:22:01 +00:00
json.mldsa65Seed,
2025-01-01 21:49:29 +00:00
settings,
2023-04-10 16:28:52 +00:00
);
}
toJson() {
2023-04-10 16:28:52 +00:00
return {
show: this.show,
xver: this.xver,
2025-09-09 12:35:21 +00:00
target: this.target,
serverNames: this.serverNames.split(","),
2023-04-10 16:28:52 +00:00
privateKey: this.privateKey,
2025-07-28 11:45:47 +00:00
minClientVer: this.minClientVer,
maxClientVer: this.maxClientVer,
2023-04-10 16:28:52 +00:00
maxTimediff: this.maxTimediff,
shortIds: this.shortIds.split(","),
2025-07-24 23:22:01 +00:00
mldsa65Seed: this.mldsa65Seed,
settings: this.settings,
};
2023-04-10 16:28:52 +00:00
}
}
RealityStreamSettings.Settings = class extends XrayCommonClass {
constructor(
publicKey = '',
fingerprint = UTLS_FINGERPRINT.UTLS_CHROME,
serverName = '',
2025-07-24 23:22:01 +00:00
spiderX = '/',
mldsa65Verify = ''
) {
super();
this.publicKey = publicKey;
this.fingerprint = fingerprint;
this.serverName = serverName;
this.spiderX = spiderX;
2025-07-24 23:22:01 +00:00
this.mldsa65Verify = mldsa65Verify;
}
static fromJson(json = {}) {
return new RealityStreamSettings.Settings(
json.publicKey,
json.fingerprint,
json.serverName,
json.spiderX,
2025-07-24 23:22:01 +00:00
json.mldsa65Verify
);
}
toJson() {
return {
publicKey: this.publicKey,
fingerprint: this.fingerprint,
serverName: this.serverName,
spiderX: this.spiderX,
2025-07-24 23:22:01 +00:00
mldsa65Verify: this.mldsa65Verify
};
}
};
2023-04-10 16:28:52 +00:00
class SockoptStreamSettings extends XrayCommonClass {
2024-05-24 07:57:14 +00:00
constructor(
acceptProxyProtocol = false,
tcpFastOpen = false,
mark = 0,
tproxy = "off",
2024-05-24 07:57:14 +00:00
tcpMptcp = false,
2025-01-01 17:42:50 +00:00
penetrate = false,
2024-05-24 07:57:14 +00:00
domainStrategy = DOMAIN_STRATEGY_OPTION.USE_IP,
tcpMaxSeg = 1440,
dialerProxy = "",
tcpKeepAliveInterval = 0,
2024-05-24 07:57:14 +00:00
tcpKeepAliveIdle = 300,
tcpUserTimeout = 10000,
tcpcongestion = TCP_CONGESTION_OPTION.BBR,
V6Only = false,
tcpWindowClamp = 600,
interfaceName = "",
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
trustedXForwardedFor = [],
2024-05-24 07:57:14 +00:00
) {
super();
this.acceptProxyProtocol = acceptProxyProtocol;
this.tcpFastOpen = tcpFastOpen;
this.mark = mark;
this.tproxy = tproxy;
this.tcpMptcp = tcpMptcp;
2025-01-01 17:42:50 +00:00
this.penetrate = penetrate;
2024-05-24 07:57:14 +00:00
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;
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
this.trustedXForwardedFor = trustedXForwardedFor;
}
static fromJson(json = {}) {
2023-08-29 18:44:59 +00:00
if (Object.keys(json).length === 0) return undefined;
return new SockoptStreamSettings(
json.acceptProxyProtocol,
json.tcpFastOpen,
json.mark,
json.tproxy,
json.tcpMptcp,
2025-01-01 17:42:50 +00:00
json.penetrate,
2024-05-24 07:57:14 +00:00
json.domainStrategy,
json.tcpMaxSeg,
json.dialerProxy,
json.tcpKeepAliveInterval,
json.tcpKeepAliveIdle,
json.tcpUserTimeout,
json.tcpcongestion,
json.V6Only,
json.tcpWindowClamp,
json.interface,
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
json.trustedXForwardedFor || [],
);
}
2023-08-29 18:44:59 +00:00
toJson() {
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
const result = {
acceptProxyProtocol: this.acceptProxyProtocol,
tcpFastOpen: this.tcpFastOpen,
mark: this.mark,
tproxy: this.tproxy,
tcpMptcp: this.tcpMptcp,
2025-01-01 17:42:50 +00:00
penetrate: this.penetrate,
2024-05-24 07:57:14 +00:00
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,
};
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
if (this.trustedXForwardedFor && this.trustedXForwardedFor.length > 0) {
result.trustedXForwardedFor = this.trustedXForwardedFor;
}
return result;
}
}
2023-02-09 19:18:06 +00:00
class StreamSettings extends XrayCommonClass {
constructor(network = 'tcp',
security = 'none',
externalProxy = [],
tlsSettings = new TlsStreamSettings(),
2023-04-11 19:00:24 +00:00
realitySettings = new RealityStreamSettings(),
tcpSettings = new TcpStreamSettings(),
kcpSettings = new KcpStreamSettings(),
wsSettings = new WsStreamSettings(),
grpcSettings = new GrpcStreamSettings(),
httpupgradeSettings = new HTTPUpgradeStreamSettings(),
2024-12-03 21:24:34 +00:00
xhttpSettings = new xHTTPStreamSettings(),
sockopt = undefined,
) {
2023-02-09 19:18:06 +00:00
super();
this.network = network;
this.security = security;
this.externalProxy = externalProxy;
2023-02-09 19:18:06 +00:00
this.tls = tlsSettings;
2023-04-10 16:28:52 +00:00
this.reality = realitySettings;
2023-02-09 19:18:06 +00:00
this.tcp = tcpSettings;
this.kcp = kcpSettings;
this.ws = wsSettings;
this.grpc = grpcSettings;
2024-03-11 07:36:33 +00:00
this.httpupgrade = httpupgradeSettings;
2024-12-03 21:24:34 +00:00
this.xhttp = xhttpSettings;
this.sockopt = sockopt;
2023-02-09 19:18:06 +00:00
}
get isTls() {
return this.security === "tls";
2023-02-09 19:18:06 +00:00
}
set isTls(isTls) {
if (isTls) {
this.security = 'tls';
} else {
this.security = 'none';
}
}
2023-04-10 16:28:52 +00:00
//for Reality
get isReality() {
return this.security === "reality";
}
set isReality(isReality) {
if (isReality) {
this.security = 'reality';
2023-02-09 19:18:06 +00:00
} else {
this.security = 'none';
2023-04-10 16:28:52 +00:00
}
}
get sockoptSwitch() {
return this.sockopt != undefined;
}
set sockoptSwitch(value) {
this.sockopt = value ? new SockoptStreamSettings() : undefined;
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new StreamSettings(
json.network,
json.security,
json.externalProxy,
TlsStreamSettings.fromJson(json.tlsSettings),
RealityStreamSettings.fromJson(json.realitySettings),
2023-02-09 19:18:06 +00:00
TcpStreamSettings.fromJson(json.tcpSettings),
KcpStreamSettings.fromJson(json.kcpSettings),
WsStreamSettings.fromJson(json.wsSettings),
GrpcStreamSettings.fromJson(json.grpcSettings),
2024-04-02 20:11:06 +00:00
HTTPUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
2024-12-03 21:24:34 +00:00
xHTTPStreamSettings.fromJson(json.xhttpSettings),
SockoptStreamSettings.fromJson(json.sockopt),
2023-02-09 19:18:06 +00:00
);
}
toJson() {
const network = this.network;
return {
network: network,
security: this.security,
externalProxy: this.externalProxy,
2023-02-09 19:18:06 +00:00
tlsSettings: this.isTls ? this.tls.toJson() : undefined,
2023-04-10 16:28:52 +00:00
realitySettings: this.isReality ? this.reality.toJson() : undefined,
tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
2023-02-09 19:18:06 +00:00
kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined,
wsSettings: network === 'ws' ? this.ws.toJson() : undefined,
grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
2024-03-11 07:36:33 +00:00
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
2024-12-03 21:24:34 +00:00
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
2023-02-09 19:18:06 +00:00
};
}
}
class Sniffing extends XrayCommonClass {
constructor(
2024-10-09 10:31:11 +00:00
enabled = false,
destOverride = ['http', 'tls', 'quic', 'fakedns'],
metadataOnly = false,
routeOnly = false) {
2023-02-09 19:18:06 +00:00
super();
this.enabled = enabled;
this.destOverride = destOverride;
this.metadataOnly = metadataOnly;
this.routeOnly = routeOnly;
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
let destOverride = ObjectUtil.clone(json.destOverride);
if (!ObjectUtil.isEmpty(destOverride) && !ObjectUtil.isArrEmpty(destOverride)) {
if (ObjectUtil.isEmpty(destOverride[0])) {
destOverride = ['http', 'tls', 'quic', 'fakedns'];
2023-02-09 19:18:06 +00:00
}
}
return new Sniffing(
!!json.enabled,
destOverride,
json.metadataOnly,
json.routeOnly,
2023-02-09 19:18:06 +00:00
);
}
}
class Inbound extends XrayCommonClass {
constructor(
port = RandomUtil.randomInteger(10000, 60000),
listen = '',
protocol = Protocols.VLESS,
settings = null,
streamSettings = new StreamSettings(),
tag = '',
sniffing = new Sniffing(),
clientStats = '',
) {
2023-02-09 19:18:06 +00:00
super();
this.port = port;
this.listen = listen;
this._protocol = protocol;
this.settings = ObjectUtil.isEmpty(settings) ? Inbound.Settings.getSettings(protocol) : settings;
this.stream = streamSettings;
this.tag = tag;
this.sniffing = sniffing;
this.clientStats = clientStats;
}
getClientStats() {
return this.clientStats;
}
get clients() {
switch (this.protocol) {
case Protocols.VMESS: return this.settings.vmesses;
case Protocols.VLESS: return this.settings.vlesses;
case Protocols.TROJAN: return this.settings.trojans;
case Protocols.SHADOWSOCKS: return this.isSSMultiUser ? this.settings.shadowsockses : null;
default: return null;
}
}
2023-02-09 19:18:06 +00:00
get protocol() {
return this._protocol;
}
2023-02-09 19:18:06 +00:00
set protocol(protocol) {
this._protocol = protocol;
this.settings = Inbound.Settings.getSettings(protocol);
if (protocol === Protocols.TROJAN) {
2023-05-07 11:06:43 +00:00
this.tls = false;
2023-02-09 19:18:06 +00:00
}
}
2023-02-09 19:18:06 +00:00
get network() {
return this.stream.network;
}
set network(network) {
this.stream.network = network;
}
get isTcp() {
return this.network === "tcp";
}
get isWs() {
return this.network === "ws";
}
get isKcp() {
return this.network === "kcp";
}
get isGrpc() {
return this.network === "grpc";
}
2024-03-11 07:36:33 +00:00
get isHttpupgrade() {
return this.network === "httpupgrade";
}
2024-12-03 21:24:34 +00:00
get isXHTTP() {
return this.network === "xhttp";
}
2023-02-09 19:18:06 +00:00
// Shadowsocks
get method() {
switch (this.protocol) {
case Protocols.SHADOWSOCKS:
return this.settings.method;
default:
return "";
}
}
get isSSMultiUser() {
return this.method != SSMethods.BLAKE3_CHACHA20_POLY1305;
}
get isSS2022() {
return this.method.substring(0, 4) === "2022";
}
2023-02-09 19:18:06 +00:00
get serverName() {
2023-12-10 17:13:48 +00:00
if (this.stream.isTls) return this.stream.tls.sni;
2023-12-08 18:44:52 +00:00
if (this.stream.isReality) return this.stream.reality.serverNames;
2023-02-09 19:18:06 +00:00
return "";
}
getHeader(obj, name) {
for (const header of obj.headers) {
if (header.name.toLowerCase() === name.toLowerCase()) {
return header.value;
}
}
return "";
}
2023-02-09 19:18:06 +00:00
get host() {
if (this.isTcp) {
return this.getHeader(this.stream.tcp.request, 'host');
2023-02-09 19:18:06 +00:00
} else if (this.isWs) {
return this.stream.ws.host?.length > 0 ? this.stream.ws.host : this.getHeader(this.stream.ws, 'host');
2024-03-11 07:36:33 +00:00
} else if (this.isHttpupgrade) {
return this.stream.httpupgrade.host?.length > 0 ? this.stream.httpupgrade.host : this.getHeader(this.stream.httpupgrade, 'host');
2024-12-03 21:24:34 +00:00
} else if (this.isXHTTP) {
return this.stream.xhttp.host?.length > 0 ? this.stream.xhttp.host : this.getHeader(this.stream.xhttp, 'host');
2023-02-09 19:18:06 +00:00
}
return null;
}
get path() {
if (this.isTcp) {
return this.stream.tcp.request.path[0];
} else if (this.isWs) {
return this.stream.ws.path;
2024-03-11 07:36:33 +00:00
} else if (this.isHttpupgrade) {
return this.stream.httpupgrade.path;
2024-12-03 21:24:34 +00:00
} else if (this.isXHTTP) {
return this.stream.xhttp.path;
2023-02-09 19:18:06 +00:00
}
return null;
}
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
get kcpType() {
return this.stream.kcp.type;
}
get kcpSeed() {
return this.stream.kcp.seed;
}
2023-02-09 19:18:06 +00:00
get serviceName() {
return this.stream.grpc.serviceName;
}
isExpiry(index) {
let exp = this.clients[index].expiryTime;
return exp > 0 ? exp < new Date().getTime() : false;
2023-02-09 19:18:06 +00:00
}
canEnableTls() {
if (![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol)) return false;
2024-12-03 21:24:34 +00:00
return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.network);
2023-02-09 19:18:06 +00:00
}
2023-03-16 22:01:14 +00:00
//this is used for xtls-rprx-vision
2023-02-09 19:18:06 +00:00
canEnableTlsFlow() {
2023-04-10 16:28:52 +00:00
if (((this.stream.security === 'tls') || (this.stream.security === 'reality')) && (this.network === "tcp")) {
2023-12-08 15:46:44 +00:00
return this.protocol === Protocols.VLESS;
2023-02-09 19:18:06 +00:00
}
return false;
}
2026-01-03 04:56:35 +00:00
// Vision seed applies only when vision flow is selected
canEnableVisionSeed() {
if (!this.canEnableTlsFlow()) return false;
const clients = this.settings?.vlesses;
if (!Array.isArray(clients)) return false;
return clients.some(c => c?.flow === TLS_FLOW_CONTROL.VISION || c?.flow === TLS_FLOW_CONTROL.VISION_UDP443);
}
canEnableReality() {
if (![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false;
2024-12-03 21:24:34 +00:00
return ["tcp", "http", "grpc", "xhttp"].includes(this.network);
}
2023-02-09 19:18:06 +00:00
canEnableStream() {
2023-12-08 15:46:44 +00:00
return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol);
2023-02-09 19:18:06 +00:00
}
reset() {
this.port = RandomUtil.randomInteger(10000, 60000);
2023-02-09 19:18:06 +00:00
this.listen = '';
this.protocol = Protocols.VMESS;
this.settings = Inbound.Settings.getSettings(Protocols.VMESS);
this.stream = new StreamSettings();
this.tag = '';
this.sniffing = new Sniffing();
}
genVmessLink(address = '', port = this.port, forceTls, remark = '', clientId, security) {
2023-02-09 19:18:06 +00:00
if (this.protocol !== Protocols.VMESS) {
return '';
}
const tls = forceTls == 'same' ? this.stream.security : forceTls;
2023-04-27 20:45:06 +00:00
let obj = {
v: '2',
ps: remark,
add: address,
port: port,
id: clientId,
scy: security,
2023-04-27 20:45:06 +00:00
net: this.stream.network,
tls: tls,
2023-04-27 20:45:06 +00:00
};
const network = this.stream.network;
2023-02-09 19:18:06 +00:00
if (network === 'tcp') {
const tcp = this.stream.tcp;
2023-04-27 20:45:06 +00:00
obj.type = tcp.type;
if (tcp.type === 'http') {
const request = tcp.request;
2023-04-27 20:45:06 +00:00
obj.path = request.path.join(',');
const host = this.getHeader(request, 'host');
if (host) obj.host = host;
2023-02-09 19:18:06 +00:00
}
} else if (network === 'kcp') {
const kcp = this.stream.kcp;
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
obj.type = kcp.type;
obj.path = kcp.seed;
2023-02-09 19:18:06 +00:00
} else if (network === 'ws') {
const ws = this.stream.ws;
2023-04-27 20:45:06 +00:00
obj.path = ws.path;
obj.host = ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host');
2023-02-09 19:18:06 +00:00
} else if (network === 'grpc') {
2023-04-27 20:45:06 +00:00
obj.path = this.stream.grpc.serviceName;
2024-03-11 09:30:00 +00:00
obj.authority = this.stream.grpc.authority;
if (this.stream.grpc.multiMode) {
2023-04-27 20:45:06 +00:00
obj.type = 'multi'
}
2024-03-11 07:36:33 +00:00
} else if (network === 'httpupgrade') {
const httpupgrade = this.stream.httpupgrade;
2024-03-11 07:36:33 +00:00
obj.path = httpupgrade.path;
obj.host = httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host');
2024-12-03 21:24:34 +00:00
} 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');
2025-07-04 11:18:23 +00:00
obj.type = xhttp.mode;
2023-02-09 19:18:06 +00:00
}
2024-12-27 16:51:32 +00:00
if (tls === 'tls') {
if (!ObjectUtil.isEmpty(this.stream.tls.sni)) {
2023-12-10 17:13:48 +00:00
obj.sni = this.stream.tls.sni;
2023-04-27 20:45:06 +00:00
}
if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerprint)) {
2023-04-27 20:45:06 +00:00
obj.fp = this.stream.tls.settings.fingerprint;
}
if (this.stream.tls.alpn.length > 0) {
2023-04-27 20:45:06 +00:00
obj.alpn = this.stream.tls.alpn.join(',');
}
if (this.stream.tls.settings.allowInsecure) {
2023-04-27 20:45:06 +00:00
obj.allowInsecure = this.stream.tls.settings.allowInsecure;
2023-02-09 19:18:06 +00:00
}
}
return 'vmess://' + Base64.encode(JSON.stringify(obj, null, 2));
2023-02-09 19:18:06 +00:00
}
genVLESSLink(address = '', port = this.port, forceTls, remark = '', clientId, flow) {
const uuid = clientId;
2023-02-09 19:18:06 +00:00
const type = this.stream.network;
const security = forceTls == 'same' ? this.stream.security : forceTls;
2023-02-09 19:18:06 +00:00
const params = new Map();
params.set("type", this.stream.network);
2025-09-07 20:35:38 +00:00
params.set("encryption", this.settings.encryption);
2023-02-09 19:18:06 +00:00
switch (type) {
case "tcp":
const tcp = this.stream.tcp;
if (tcp.type === 'http') {
const request = tcp.request;
params.set("path", request.path.join(','));
const index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
if (index >= 0) {
const host = request.headers[index].value;
2023-02-09 19:18:06 +00:00
params.set("host", host);
}
params.set("headerType", 'http');
}
break;
case "kcp":
const kcp = this.stream.kcp;
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
params.set("headerType", kcp.type);
params.set("seed", kcp.seed);
2023-02-09 19:18:06 +00:00
break;
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'));
2023-02-09 19:18:06 +00:00
break;
case "grpc":
const grpc = this.stream.grpc;
params.set("serviceName", grpc.serviceName);
2024-03-11 09:30:00 +00:00
params.set("authority", grpc.authority);
if (grpc.multiMode) {
2023-04-27 20:45:06 +00:00
params.set("mode", "multi");
}
2023-02-09 19:18:06 +00:00
break;
2024-03-11 07:36:33 +00:00
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'));
break;
2024-12-03 21:24:34 +00:00
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);
2024-03-11 07:36:33 +00:00
break;
2023-02-09 19:18:06 +00:00
}
if (security === 'tls') {
2023-03-23 10:38:16 +00:00
params.set("security", "tls");
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) {
params.set("allowInsecure", "1");
}
if (!ObjectUtil.isEmpty(this.stream.tls.sni)) {
2023-12-10 17:13:48 +00:00
params.set("sni", this.stream.tls.sni);
}
if (this.stream.tls.settings.echConfigList?.length > 0) {
params.set("ech", this.stream.tls.settings.echConfigList);
}
if (type == "tcp" && !ObjectUtil.isEmpty(flow)) {
params.set("flow", flow);
}
2023-03-18 16:53:29 +00:00
}
2023-02-09 19:18:06 +00:00
}
else if (security === 'reality') {
2023-04-10 16:28:52 +00:00
params.set("security", "reality");
params.set("pbk", this.stream.reality.settings.publicKey);
params.set("fp", this.stream.reality.settings.fingerprint);
2023-04-10 16:28:52 +00:00
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
2023-04-10 16:28:52 +00:00
}
if (this.stream.reality.shortIds.length > 0) {
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
}
if (!ObjectUtil.isEmpty(this.stream.reality.settings.spiderX)) {
params.set("spx", this.stream.reality.settings.spiderX);
}
2025-08-03 23:30:01 +00:00
if (!ObjectUtil.isEmpty(this.stream.reality.settings.mldsa65Verify)) {
params.set("pqv", this.stream.reality.settings.mldsa65Verify);
}
if (type == 'tcp' && !ObjectUtil.isEmpty(flow)) {
params.set("flow", flow);
}
2023-04-10 16:28:52 +00:00
}
else {
params.set("security", "none");
}
2023-02-09 19:18:06 +00:00
const link = `vless://${uuid}@${address}:${port}`;
const url = new URL(link);
for (const [key, value] of params) {
url.searchParams.set(key, value)
}
url.hash = encodeURIComponent(remark);
return url.toString();
}
2024-04-02 20:11:06 +00:00
genSSLink(address = '', port = this.port, forceTls, remark = '', clientPassword) {
2023-02-09 19:18:06 +00:00
let settings = this.settings;
const type = this.stream.network;
const security = forceTls == 'same' ? this.stream.security : forceTls;
const params = new Map();
params.set("type", this.stream.network);
switch (type) {
case "tcp":
const tcp = this.stream.tcp;
if (tcp.type === 'http') {
const request = tcp.request;
params.set("path", request.path.join(','));
const index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
if (index >= 0) {
const host = request.headers[index].value;
params.set("host", host);
}
params.set("headerType", 'http');
}
break;
case "kcp":
const kcp = this.stream.kcp;
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
params.set("headerType", kcp.type);
params.set("seed", kcp.seed);
break;
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'));
break;
case "grpc":
const grpc = this.stream.grpc;
params.set("serviceName", grpc.serviceName);
2024-03-11 09:30:00 +00:00
params.set("authority", grpc.authority);
2024-04-02 20:11:06 +00:00
if (grpc.multiMode) {
params.set("mode", "multi");
}
break;
2024-03-11 07:36:33 +00:00
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'));
break;
2024-12-03 21:24:34 +00:00
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);
2024-03-11 07:36:33 +00:00
break;
}
if (security === 'tls') {
params.set("security", "tls");
2024-04-02 20:11:06 +00:00
if (this.stream.isTls) {
params.set("fp", this.stream.tls.settings.fingerprint);
params.set("alpn", this.stream.tls.alpn);
2024-04-02 20:11:06 +00:00
if (this.stream.tls.settings.allowInsecure) {
params.set("allowInsecure", "1");
}
if (this.stream.tls.settings.echConfigList?.length > 0) {
params.set("ech", this.stream.tls.settings.echConfigList);
}
2024-04-02 20:11:06 +00:00
if (!ObjectUtil.isEmpty(this.stream.tls.sni)) {
2023-12-10 17:13:48 +00:00
params.set("sni", this.stream.tls.sni);
}
}
}
let password = new Array();
if (this.isSS2022) password.push(settings.password);
if (this.isSSMultiUser) password.push(clientPassword);
let link = `ss://${Base64.encode(`${settings.method}:${password.join(':')}`, true)}@${address}:${port}`;
const url = new URL(link);
for (const [key, value] of params) {
url.searchParams.set(key, value)
}
url.hash = encodeURIComponent(remark);
return url.toString();
2023-02-09 19:18:06 +00:00
}
genTrojanLink(address = '', port = this.port, forceTls, remark = '', clientPassword) {
const security = forceTls == 'same' ? this.stream.security : forceTls;
2023-02-09 19:18:06 +00:00
const type = this.stream.network;
const params = new Map();
params.set("type", this.stream.network);
2023-02-09 19:18:06 +00:00
switch (type) {
case "tcp":
const tcp = this.stream.tcp;
if (tcp.type === 'http') {
const request = tcp.request;
params.set("path", request.path.join(','));
const index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
if (index >= 0) {
const host = request.headers[index].value;
2023-02-09 19:18:06 +00:00
params.set("host", host);
}
params.set("headerType", 'http');
}
break;
case "kcp":
const kcp = this.stream.kcp;
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
params.set("headerType", kcp.type);
params.set("seed", kcp.seed);
2023-02-09 19:18:06 +00:00
break;
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'));
2023-02-09 19:18:06 +00:00
break;
case "grpc":
const grpc = this.stream.grpc;
params.set("serviceName", grpc.serviceName);
2024-03-11 09:30:00 +00:00
params.set("authority", grpc.authority);
if (grpc.multiMode) {
2023-04-27 20:45:06 +00:00
params.set("mode", "multi");
}
2023-02-09 19:18:06 +00:00
break;
2024-03-11 07:36:33 +00:00
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'));
break;
2024-12-03 21:24:34 +00:00
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);
2024-03-11 07:36:33 +00:00
break;
2023-02-09 19:18:06 +00:00
}
if (security === 'tls') {
2023-03-23 10:38:16 +00:00
params.set("security", "tls");
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) {
params.set("allowInsecure", "1");
}
if (this.stream.tls.settings.echConfigList?.length > 0) {
params.set("ech", this.stream.tls.settings.echConfigList);
}
if (!ObjectUtil.isEmpty(this.stream.tls.sni)) {
2023-12-10 17:13:48 +00:00
params.set("sni", this.stream.tls.sni);
}
2023-03-19 09:09:14 +00:00
}
2023-02-09 19:18:06 +00:00
}
else if (security === 'reality') {
2023-04-11 19:00:24 +00:00
params.set("security", "reality");
params.set("pbk", this.stream.reality.settings.publicKey);
params.set("fp", this.stream.reality.settings.fingerprint);
2023-04-11 19:00:24 +00:00
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
2023-04-11 19:00:24 +00:00
}
if (this.stream.reality.shortIds.length > 0) {
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
}
if (!ObjectUtil.isEmpty(this.stream.reality.settings.spiderX)) {
params.set("spx", this.stream.reality.settings.spiderX);
}
2025-08-03 23:30:01 +00:00
if (!ObjectUtil.isEmpty(this.stream.reality.settings.mldsa65Verify)) {
params.set("pqv", this.stream.reality.settings.mldsa65Verify);
}
2023-04-11 19:00:24 +00:00
}
else {
params.set("security", "none");
}
const link = `trojan://${clientPassword}@${address}:${port}`;
2023-02-09 19:18:06 +00:00
const url = new URL(link);
for (const [key, value] of params) {
url.searchParams.set(key, value)
}
url.hash = encodeURIComponent(remark);
return url.toString();
}
getWireguardLink(address, port, remark, peerId) {
let txt = `[Interface]\n`
txt += `PrivateKey = ${this.settings.peers[peerId].privateKey}\n`
txt += `Address = ${this.settings.peers[peerId].allowedIPs[0]}\n`
txt += `DNS = 1.1.1.1, 1.0.0.1\n`
if (this.settings.mtu) {
txt += `MTU = ${this.settings.mtu}\n`
}
txt += `\n# ${remark}\n`
txt += `[Peer]\n`
txt += `PublicKey = ${this.settings.pubKey}\n`
txt += `AllowedIPs = 0.0.0.0/0, ::/0\n`
txt += `Endpoint = ${address}:${port}`
if (this.settings.peers[peerId].psk) {
txt += `\nPresharedKey = ${this.settings.peers[peerId].psk}`
}
if (this.settings.peers[peerId].keepAlive) {
txt += `\nPersistentKeepalive = ${this.settings.peers[peerId].keepAlive}\n`
}
return txt;
}
genLink(address = '', port = this.port, forceTls = 'same', remark = '', client) {
2023-02-09 19:18:06 +00:00
switch (this.protocol) {
case Protocols.VMESS:
return this.genVmessLink(address, port, forceTls, remark, client.id, client.security);
2023-02-12 13:50:09 +00:00
case Protocols.VLESS:
return this.genVLESSLink(address, port, forceTls, remark, client.id, client.flow);
case Protocols.SHADOWSOCKS:
return this.genSSLink(address, port, forceTls, remark, this.isSSMultiUser ? client.password : '');
2023-02-12 13:50:09 +00:00
case Protocols.TROJAN:
return this.genTrojanLink(address, port, forceTls, remark, client.password);
2023-02-09 19:18:06 +00:00
default: return '';
}
}
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;
2023-12-08 19:31:17 +00:00
let port = this.port;
const separationChar = remarkModel.charAt(0);
const orderChars = remarkModel.slice(1);
let orders = {
'i': remark,
'e': email,
2023-12-08 19:31:17 +00:00
'o': '',
};
if (ObjectUtil.isArrEmpty(this.stream.externalProxy)) {
2023-12-08 19:31:17 +00:00
let r = orderChars.split('').map(char => orders[char]).filter(x => x.length > 0).join(separationChar);
result.push({
remark: r,
link: this.genLink(addr, port, 'same', r, client)
});
} else {
this.stream.externalProxy.forEach((ep) => {
2023-12-08 19:31:17 +00:00
orders['o'] = ep.remark;
let r = orderChars.split('').map(char => orders[char]).filter(x => x.length > 0).join(separationChar);
result.push({
remark: r,
link: this.genLink(ep.dest, ep.port, ep.forceTls, r, client)
2023-02-28 21:12:08 +00:00
});
});
}
return result;
}
2023-12-08 19:31:17 +00:00
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 => {
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) {
let links = [];
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');
}
return '';
2023-02-28 21:12:08 +00:00
}
}
2023-02-09 19:18:06 +00:00
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound(
json.port,
json.listen,
json.protocol,
Inbound.Settings.fromJson(json.protocol, json.settings),
StreamSettings.fromJson(json.streamSettings),
json.tag,
Sniffing.fromJson(json.sniffing),
json.clientStats
)
}
toJson() {
let streamSettings;
2025-08-09 14:07:33 +00:00
if (this.canEnableStream() || this.stream?.sockopt) {
2023-02-09 19:18:06 +00:00
streamSettings = this.stream.toJson();
}
return {
port: this.port,
listen: this.listen,
protocol: this.protocol,
settings: this.settings instanceof XrayCommonClass ? this.settings.toJson() : this.settings,
streamSettings: streamSettings,
tag: this.tag,
sniffing: this.sniffing.toJson(),
clientStats: this.clientStats
};
}
}
Inbound.Settings = class extends XrayCommonClass {
constructor(protocol) {
super();
this.protocol = protocol;
}
static getSettings(protocol) {
switch (protocol) {
case Protocols.VMESS: return new Inbound.VmessSettings(protocol);
case Protocols.VLESS: return new Inbound.VLESSSettings(protocol);
case Protocols.TROJAN: return new Inbound.TrojanSettings(protocol);
case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings(protocol);
case Protocols.TUNNEL: return new Inbound.TunnelSettings(protocol);
case Protocols.MIXED: return new Inbound.MixedSettings(protocol);
case Protocols.HTTP: return new Inbound.HttpSettings(protocol);
case Protocols.WIREGUARD: return new Inbound.WireguardSettings(protocol);
case Protocols.TUN: return new Inbound.TunSettings(protocol);
2023-02-09 19:18:06 +00:00
default: return null;
}
}
static fromJson(protocol, json) {
switch (protocol) {
case Protocols.VMESS: return Inbound.VmessSettings.fromJson(json);
case Protocols.VLESS: return Inbound.VLESSSettings.fromJson(json);
case Protocols.TROJAN: return Inbound.TrojanSettings.fromJson(json);
case Protocols.SHADOWSOCKS: return Inbound.ShadowsocksSettings.fromJson(json);
case Protocols.TUNNEL: return Inbound.TunnelSettings.fromJson(json);
case Protocols.MIXED: return Inbound.MixedSettings.fromJson(json);
2023-02-09 19:18:06 +00:00
case Protocols.HTTP: return Inbound.HttpSettings.fromJson(json);
case Protocols.WIREGUARD: return Inbound.WireguardSettings.fromJson(json);
case Protocols.TUN: return Inbound.TunSettings.fromJson(json);
2023-02-09 19:18:06 +00:00
default: return null;
}
}
toJson() {
return {};
}
};
Inbound.VmessSettings = class extends Inbound.Settings {
constructor(protocol,
vmesses = [new Inbound.VmessSettings.VMESS()]) {
2023-02-09 19:18:06 +00:00
super(protocol);
this.vmesses = vmesses;
}
indexOfVmessById(id) {
return this.vmesses.findIndex(VMESS => VMESS.id === id);
2023-02-09 19:18:06 +00:00
}
addVmess(VMESS) {
if (this.indexOfVmessById(VMESS.id) >= 0) {
2023-02-09 19:18:06 +00:00
return false;
}
this.vmesses.push(VMESS);
2023-02-09 19:18:06 +00:00
}
delVmess(VMESS) {
const i = this.indexOfVmessById(VMESS.id);
2023-02-09 19:18:06 +00:00
if (i >= 0) {
this.vmesses.splice(i, 1);
}
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound.VmessSettings(
Protocols.VMESS,
json.clients.map(client => Inbound.VmessSettings.VMESS.fromJson(client)),
2023-02-09 19:18:06 +00:00
);
}
toJson() {
return {
clients: Inbound.VmessSettings.toJsonArray(this.vmesses),
};
}
};
Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
constructor(
id = RandomUtil.randomUUID(),
security = USERS_SECURITY.AUTO,
email = RandomUtil.randomLowerAndNum(8),
limitIp = 0,
totalGB = 0,
expiryTime = 0,
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0,
created_at = undefined,
updated_at = undefined
) {
2023-02-09 19:18:06 +00:00
super();
this.id = id;
this.security = security;
2023-02-09 19:18:06 +00:00
this.email = email;
2023-02-28 19:54:29 +00:00
this.limitIp = limitIp;
2023-02-09 19:18:06 +00:00
this.totalGB = totalGB;
this.expiryTime = expiryTime;
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
2023-12-04 18:20:16 +00:00
this.reset = reset;
this.created_at = created_at;
this.updated_at = updated_at;
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
return new Inbound.VmessSettings.VMESS(
2023-02-09 19:18:06 +00:00
json.id,
json.security,
2023-02-09 19:18:06 +00:00
json.email,
2023-02-28 19:54:29 +00:00
json.limitIp,
2023-02-09 19:18:06 +00:00
json.totalGB,
json.expiryTime,
json.enable,
json.tgId,
json.subId,
json.comment,
2023-12-04 18:20:16 +00:00
json.reset,
json.created_at,
json.updated_at,
2023-02-09 19:18:06 +00:00
);
}
get _expiryTime() {
if (this.expiryTime === 0 || this.expiryTime === "") {
return null;
}
if (this.expiryTime < 0) {
return this.expiryTime / -86400000;
}
2023-02-09 19:18:06 +00:00
return moment(this.expiryTime);
}
set _expiryTime(t) {
if (t == null || t === "") {
this.expiryTime = 0;
} else {
this.expiryTime = t.valueOf();
}
}
get _totalGB() {
return NumberFormatter.toFixed(this.totalGB / SizeFormatter.ONE_GB, 2);
2023-02-09 19:18:06 +00:00
}
set _totalGB(gb) {
this.totalGB = NumberFormatter.toFixed(gb * SizeFormatter.ONE_GB, 0);
2023-02-09 19:18:06 +00:00
}
};
Inbound.VLESSSettings = class extends Inbound.Settings {
constructor(
protocol,
vlesses = [new Inbound.VLESSSettings.VLESS()],
2025-09-07 20:35:38 +00:00
decryption = "none",
2025-09-08 08:08:55 +00:00
encryption = "none",
2025-09-07 20:35:38 +00:00
fallbacks = [],
2025-09-08 08:08:55 +00:00
selectedAuth = undefined,
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
testseed = [900, 500, 900, 256],
) {
2023-02-09 19:18:06 +00:00
super(protocol);
this.vlesses = vlesses;
this.decryption = decryption;
2025-09-07 20:35:38 +00:00
this.encryption = encryption;
2023-02-09 19:18:06 +00:00
this.fallbacks = fallbacks;
2025-09-08 08:08:55 +00:00
this.selectedAuth = selectedAuth;
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
this.testseed = testseed;
2023-02-09 19:18:06 +00:00
}
addFallback() {
this.fallbacks.push(new Inbound.VLESSSettings.Fallback());
}
delFallback(index) {
this.fallbacks.splice(index, 1);
}
static fromJson(json = {}) {
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
// Ensure testseed is always initialized as an array
let testseed = [900, 500, 900, 256];
if (json.testseed && Array.isArray(json.testseed) && json.testseed.length >= 4) {
testseed = json.testseed;
}
2026-01-03 04:56:35 +00:00
2025-09-07 20:35:38 +00:00
const obj = new Inbound.VLESSSettings(
2023-02-09 19:18:06 +00:00
Protocols.VLESS,
2025-09-07 20:35:38 +00:00
(json.clients || []).map(client => Inbound.VLESSSettings.VLESS.fromJson(client)),
json.decryption,
json.encryption,
2025-09-08 08:08:55 +00:00
Inbound.VLESSSettings.Fallback.fromJson(json.fallbacks || []),
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
json.selectedAuth,
testseed
2025-09-07 20:35:38 +00:00
);
return obj;
2023-02-09 19:18:06 +00:00
}
2025-09-07 20:35:38 +00:00
2023-02-09 19:18:06 +00:00
toJson() {
2025-09-07 20:35:38 +00:00
const json = {
2023-02-09 19:18:06 +00:00
clients: Inbound.VLESSSettings.toJsonArray(this.vlesses),
};
2025-09-07 20:35:38 +00:00
if (this.decryption) {
json.decryption = this.decryption;
}
if (this.encryption) {
json.encryption = this.encryption;
}
if (this.fallbacks && this.fallbacks.length > 0) {
json.fallbacks = Inbound.VLESSSettings.toJsonArray(this.fallbacks);
}
if (this.selectedAuth) {
json.selectedAuth = this.selectedAuth;
}
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
if (this.testseed && this.testseed.length >= 4) {
feat: Add WebSocket support for real-time updates and enhance VLESS settings (#3605) * feat: add support for trusted X-Forwarded-For and testseed parameters in VLESS settings * chore: update Xray Core version to 25.12.8 in release workflow * chore: update Xray Core version to 25.12.8 in Docker initialization script * chore: bump version to 2.8.6 and add watcher for security changes in inbound modal * refactor: remove default and random seed buttons from outbound form * refactor: update VLESS form to rename 'Test Seed' to 'Vision Seed' and change button functionality for seed generation * refactor: enhance TLS settings form layout with improved button styling and spacing * feat: integrate WebSocket support for real-time updates on inbounds and Xray service status * chore: downgrade version to 2.8.5 * refactor: translate comments to English * fix: ensure testseed is initialized correctly for VLESS protocol and improve client handling in inbound modal * refactor: simplify VLESS divider condition by removing unnecessary flow checks * fix: add fallback date formatting for cases when IntlUtil is not available * refactor: simplify WebSocket message handling by removing batching and ensuring individual message delivery * refactor: disable WebSocket notifications in inbound and index HTML files * refactor: enhance VLESS testseed initialization and button functionality in inbound modal * fix: * refactor: ensure proper WebSocket URL construction by normalizing basePath * fix: * fix: * fix: * refactor: update testseed methods for improved reactivity and binding in VLESS form * logger info to debug --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-03 04:26:00 +00:00
json.testseed = this.testseed;
}
2025-09-07 20:35:38 +00:00
return json;
2023-02-09 19:18:06 +00:00
}
2025-09-07 20:35:38 +00:00
2023-02-09 19:18:06 +00:00
};
2023-02-09 19:18:06 +00:00
Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
constructor(
id = RandomUtil.randomUUID(),
flow = '',
email = RandomUtil.randomLowerAndNum(8),
limitIp = 0,
totalGB = 0,
expiryTime = 0,
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0,
created_at = undefined,
updated_at = undefined
) {
2023-02-09 19:18:06 +00:00
super();
this.id = id;
this.flow = flow;
this.email = email;
2023-02-28 19:54:29 +00:00
this.limitIp = limitIp;
2023-02-09 19:18:06 +00:00
this.totalGB = totalGB;
this.expiryTime = expiryTime;
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
2023-12-04 18:20:16 +00:00
this.reset = reset;
this.created_at = created_at;
this.updated_at = updated_at;
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound.VLESSSettings.VLESS(
json.id,
json.flow,
json.email,
2023-02-28 19:54:29 +00:00
json.limitIp,
2023-02-09 19:18:06 +00:00
json.totalGB,
json.expiryTime,
json.enable,
json.tgId,
json.subId,
json.comment,
2023-12-04 18:20:16 +00:00
json.reset,
json.created_at,
json.updated_at,
2023-02-09 19:18:06 +00:00
);
}
2023-02-09 19:18:06 +00:00
get _expiryTime() {
if (this.expiryTime === 0 || this.expiryTime === "") {
return null;
}
if (this.expiryTime < 0) {
return this.expiryTime / -86400000;
}
2023-02-09 19:18:06 +00:00
return moment(this.expiryTime);
}
set _expiryTime(t) {
if (t == null || t === "") {
this.expiryTime = 0;
} else {
this.expiryTime = t.valueOf();
}
}
get _totalGB() {
return NumberFormatter.toFixed(this.totalGB / SizeFormatter.ONE_GB, 2);
2023-02-09 19:18:06 +00:00
}
set _totalGB(gb) {
this.totalGB = NumberFormatter.toFixed(gb * SizeFormatter.ONE_GB, 0);
2023-02-09 19:18:06 +00:00
}
};
Inbound.VLESSSettings.Fallback = class extends XrayCommonClass {
constructor(name = "", alpn = '', path = '', dest = '', xver = 0) {
2023-02-09 19:18:06 +00:00
super();
this.name = name;
this.alpn = alpn;
this.path = path;
this.dest = dest;
this.xver = xver;
}
toJson() {
let xver = this.xver;
if (!Number.isInteger(xver)) {
xver = 0;
}
return {
name: this.name,
alpn: this.alpn,
path: this.path,
dest: this.dest,
xver: xver,
}
}
static fromJson(json = []) {
2023-02-09 19:18:06 +00:00
const fallbacks = [];
for (let fallback of json) {
fallbacks.push(new Inbound.VLESSSettings.Fallback(
fallback.name,
fallback.alpn,
fallback.path,
fallback.dest,
fallback.xver,
))
}
return fallbacks;
}
};
Inbound.TrojanSettings = class extends Inbound.Settings {
constructor(protocol,
trojans = [new Inbound.TrojanSettings.Trojan()],
fallbacks = [],) {
2023-02-09 19:18:06 +00:00
super(protocol);
this.trojans = trojans;
this.fallbacks = fallbacks;
}
2023-12-10 14:34:56 +00:00
addFallback() {
2023-02-09 19:18:06 +00:00
this.fallbacks.push(new Inbound.TrojanSettings.Fallback());
}
2023-12-10 14:34:56 +00:00
delFallback(index) {
2023-02-09 19:18:06 +00:00
this.fallbacks.splice(index, 1);
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound.TrojanSettings(
Protocols.TROJAN,
json.clients.map(client => Inbound.TrojanSettings.Trojan.fromJson(client)),
2023-12-10 17:13:48 +00:00
Inbound.TrojanSettings.Fallback.fromJson(json.fallbacks),);
}
2023-02-09 19:18:06 +00:00
toJson() {
return {
clients: Inbound.TrojanSettings.toJsonArray(this.trojans),
2023-12-10 14:34:56 +00:00
fallbacks: Inbound.TrojanSettings.toJsonArray(this.fallbacks)
2023-02-09 19:18:06 +00:00
};
}
};
2024-08-11 10:41:21 +00:00
2023-02-09 19:18:06 +00:00
Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
2024-08-11 10:41:21 +00:00
constructor(
password = RandomUtil.randomSeq(10),
email = RandomUtil.randomLowerAndNum(8),
limitIp = 0,
totalGB = 0,
expiryTime = 0,
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0,
created_at = undefined,
updated_at = undefined
2024-08-11 10:41:21 +00:00
) {
2023-02-09 19:18:06 +00:00
super();
this.password = password;
this.email = email;
2023-02-28 19:54:29 +00:00
this.limitIp = limitIp;
2023-02-09 19:18:06 +00:00
this.totalGB = totalGB;
this.expiryTime = expiryTime;
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
2023-12-04 18:20:16 +00:00
this.reset = reset;
this.created_at = created_at;
this.updated_at = updated_at;
2023-02-09 19:18:06 +00:00
}
toJson() {
return {
password: this.password,
email: this.email,
2023-02-28 19:54:29 +00:00
limitIp: this.limitIp,
2023-02-09 19:18:06 +00:00
totalGB: this.totalGB,
expiryTime: this.expiryTime,
enable: this.enable,
tgId: this.tgId,
subId: this.subId,
comment: this.comment,
2023-12-04 18:20:16 +00:00
reset: this.reset,
created_at: this.created_at,
updated_at: this.updated_at,
2023-02-09 19:18:06 +00:00
};
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound.TrojanSettings.Trojan(
json.password,
json.email,
2023-02-28 19:54:29 +00:00
json.limitIp,
2023-02-09 19:18:06 +00:00
json.totalGB,
json.expiryTime,
json.enable,
json.tgId,
json.subId,
json.comment,
2023-12-04 18:20:16 +00:00
json.reset,
json.created_at,
json.updated_at,
2023-02-09 19:18:06 +00:00
);
}
get _expiryTime() {
if (this.expiryTime === 0 || this.expiryTime === "") {
return null;
}
if (this.expiryTime < 0) {
return this.expiryTime / -86400000;
}
2023-02-09 19:18:06 +00:00
return moment(this.expiryTime);
}
set _expiryTime(t) {
if (t == null || t === "") {
this.expiryTime = 0;
} else {
this.expiryTime = t.valueOf();
}
}
get _totalGB() {
return NumberFormatter.toFixed(this.totalGB / SizeFormatter.ONE_GB, 2);
2023-02-09 19:18:06 +00:00
}
set _totalGB(gb) {
this.totalGB = NumberFormatter.toFixed(gb * SizeFormatter.ONE_GB, 0);
2023-02-09 19:18:06 +00:00
}
};
Inbound.TrojanSettings.Fallback = class extends XrayCommonClass {
constructor(name = "", alpn = '', path = '', dest = '', xver = 0) {
2023-02-09 19:18:06 +00:00
super();
this.name = name;
this.alpn = alpn;
this.path = path;
this.dest = dest;
this.xver = xver;
}
toJson() {
let xver = this.xver;
if (!Number.isInteger(xver)) {
xver = 0;
}
return {
name: this.name,
alpn: this.alpn,
path: this.path,
dest: this.dest,
xver: xver,
}
}
static fromJson(json = []) {
2023-02-09 19:18:06 +00:00
const fallbacks = [];
for (let fallback of json) {
fallbacks.push(new Inbound.TrojanSettings.Fallback(
fallback.name,
fallback.alpn,
fallback.path,
fallback.dest,
fallback.xver,
))
}
return fallbacks;
}
};
Inbound.ShadowsocksSettings = class extends Inbound.Settings {
constructor(protocol,
method = SSMethods.BLAKE3_AES_256_GCM,
password = RandomUtil.randomShadowsocksPassword(),
network = 'tcp,udp',
2024-11-12 10:31:42 +00:00
shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()],
ivCheck = false,
2023-02-09 19:18:06 +00:00
) {
super(protocol);
this.method = method;
this.password = password;
this.network = network;
this.shadowsockses = shadowsockses;
2024-11-12 10:31:42 +00:00
this.ivCheck = ivCheck;
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound.ShadowsocksSettings(
Protocols.SHADOWSOCKS,
json.method,
json.password,
json.network,
json.clients.map(client => Inbound.ShadowsocksSettings.Shadowsocks.fromJson(client)),
2024-11-12 10:31:42 +00:00
json.ivCheck,
2023-02-09 19:18:06 +00:00
);
}
toJson() {
return {
method: this.method,
password: this.password,
network: this.network,
2024-11-12 10:31:42 +00:00
clients: Inbound.ShadowsocksSettings.toJsonArray(this.shadowsockses),
ivCheck: this.ivCheck,
2023-02-09 19:18:06 +00:00
};
}
};
Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
2024-08-11 10:41:21 +00:00
constructor(
method = '',
password = RandomUtil.randomShadowsocksPassword(),
2024-08-11 10:41:21 +00:00
email = RandomUtil.randomLowerAndNum(8),
limitIp = 0,
totalGB = 0,
expiryTime = 0,
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0,
created_at = undefined,
updated_at = undefined
2024-08-11 10:41:21 +00:00
) {
super();
this.method = method;
this.password = password;
this.email = email;
this.limitIp = limitIp;
this.totalGB = totalGB;
this.expiryTime = expiryTime;
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
2023-12-04 18:20:16 +00:00
this.reset = reset;
this.created_at = created_at;
this.updated_at = updated_at;
}
toJson() {
return {
method: this.method,
password: this.password,
email: this.email,
limitIp: this.limitIp,
totalGB: this.totalGB,
expiryTime: this.expiryTime,
enable: this.enable,
tgId: this.tgId,
subId: this.subId,
comment: this.comment,
2023-12-04 18:20:16 +00:00
reset: this.reset,
created_at: this.created_at,
updated_at: this.updated_at,
};
}
static fromJson(json = {}) {
return new Inbound.ShadowsocksSettings.Shadowsocks(
json.method,
json.password,
json.email,
json.limitIp,
json.totalGB,
json.expiryTime,
json.enable,
json.tgId,
json.subId,
json.comment,
2023-12-04 18:20:16 +00:00
json.reset,
json.created_at,
json.updated_at,
);
}
get _expiryTime() {
if (this.expiryTime === 0 || this.expiryTime === "") {
return null;
}
if (this.expiryTime < 0) {
return this.expiryTime / -86400000;
}
return moment(this.expiryTime);
}
set _expiryTime(t) {
if (t == null || t === "") {
this.expiryTime = 0;
} else {
this.expiryTime = t.valueOf();
}
}
get _totalGB() {
return NumberFormatter.toFixed(this.totalGB / SizeFormatter.ONE_GB, 2);
}
set _totalGB(gb) {
this.totalGB = NumberFormatter.toFixed(gb * SizeFormatter.ONE_GB, 0);
}
};
Inbound.TunnelSettings = class extends Inbound.Settings {
2024-08-11 10:41:21 +00:00
constructor(
protocol,
address,
port,
2025-08-04 14:45:09 +00:00
portMap = [],
2024-08-11 10:41:21 +00:00
network = 'tcp,udp',
2024-09-24 10:00:37 +00:00
followRedirect = false
2024-08-11 10:41:21 +00:00
) {
2023-02-09 19:18:06 +00:00
super(protocol);
this.address = address;
this.port = port;
2025-08-04 14:45:09 +00:00
this.portMap = portMap;
2023-02-09 19:18:06 +00:00
this.network = network;
this.followRedirect = followRedirect;
2023-02-09 19:18:06 +00:00
}
static fromJson(json = {}) {
return new Inbound.TunnelSettings(
Protocols.TUNNEL,
2023-02-09 19:18:06 +00:00
json.address,
json.port,
2025-08-04 14:45:09 +00:00
XrayCommonClass.toHeaders(json.portMap),
2023-02-09 19:18:06 +00:00
json.network,
json.followRedirect,
2023-02-09 19:18:06 +00:00
);
}
toJson() {
return {
address: this.address,
port: this.port,
portMap: XrayCommonClass.toV2Headers(this.portMap, false),
2023-02-09 19:18:06 +00:00
network: this.network,
followRedirect: this.followRedirect,
2023-02-09 19:18:06 +00:00
};
}
};
Inbound.MixedSettings = class extends Inbound.Settings {
constructor(protocol, auth = 'password', accounts = [new Inbound.MixedSettings.SocksAccount()], udp = false, ip = '127.0.0.1') {
2023-02-09 19:18:06 +00:00
super(protocol);
this.auth = auth;
this.accounts = accounts;
this.udp = udp;
this.ip = ip;
}
addAccount(account) {
this.accounts.push(account);
}
delAccount(index) {
this.accounts.splice(index, 1);
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
let accounts;
if (json.auth === 'password') {
accounts = json.accounts.map(
account => Inbound.MixedSettings.SocksAccount.fromJson(account)
2023-02-09 19:18:06 +00:00
)
}
return new Inbound.MixedSettings(
Protocols.MIXED,
2023-02-09 19:18:06 +00:00
json.auth,
accounts,
json.udp,
json.ip,
);
}
toJson() {
return {
auth: this.auth,
accounts: this.auth === 'password' ? this.accounts.map(account => account.toJson()) : undefined,
udp: this.udp,
ip: this.ip,
};
}
};
Inbound.MixedSettings.SocksAccount = class extends XrayCommonClass {
constructor(user = RandomUtil.randomSeq(10), pass = RandomUtil.randomSeq(10)) {
2023-02-09 19:18:06 +00:00
super();
this.user = user;
this.pass = pass;
}
static fromJson(json = {}) {
return new Inbound.MixedSettings.SocksAccount(json.user, json.pass);
2023-02-09 19:18:06 +00:00
}
};
Inbound.HttpSettings = class extends Inbound.Settings {
2024-09-17 08:43:12 +00:00
constructor(
2024-10-17 08:36:05 +00:00
protocol,
2024-09-17 08:43:12 +00:00
accounts = [new Inbound.HttpSettings.HttpAccount()],
allowTransparent = false,
) {
2023-02-09 19:18:06 +00:00
super(protocol);
this.accounts = accounts;
2024-09-17 08:43:12 +00:00
this.allowTransparent = allowTransparent;
2023-02-09 19:18:06 +00:00
}
addAccount(account) {
this.accounts.push(account);
}
delAccount(index) {
this.accounts.splice(index, 1);
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound.HttpSettings(
Protocols.HTTP,
json.accounts.map(account => Inbound.HttpSettings.HttpAccount.fromJson(account)),
2024-09-17 08:43:12 +00:00
json.allowTransparent,
2023-02-09 19:18:06 +00:00
);
}
toJson() {
return {
accounts: Inbound.HttpSettings.toJsonArray(this.accounts),
2024-09-17 08:43:12 +00:00
allowTransparent: this.allowTransparent,
2023-02-09 19:18:06 +00:00
};
}
};
Inbound.HttpSettings.HttpAccount = class extends XrayCommonClass {
constructor(user = RandomUtil.randomSeq(10), pass = RandomUtil.randomSeq(10)) {
2023-02-09 19:18:06 +00:00
super();
this.user = user;
this.pass = pass;
}
static fromJson(json = {}) {
2023-02-09 19:18:06 +00:00
return new Inbound.HttpSettings.HttpAccount(json.user, json.pass);
}
};
Inbound.WireguardSettings = class extends XrayCommonClass {
2024-10-16 10:06:47 +00:00
constructor(
protocol,
# Pull Request: Connection Reporting System & Improvements for Restricted Networks ## Description This PR introduces a comprehensive **Connection Reporting System** designed to improve the reliability and monitoring of connections, specifically tailored for environments with restricted internet access (e.g., active censorship, GFW). ### Key Changes 1. **New Reporting API (`/report`)**: * Added `ReportController` and `ReportService` to handle incoming connection reports. * Endpoint receives data such as `Latency`, `Success` status, `Protocol`, and Client Interface details. * Data is persisted to the database via the new `ConnectionReport` model. 2. **Subscription Link Updates**: * Modified `subService` to append a `reportUrl` parameter to generated subscription links (VLESS, VMess, etc.). * This allows compatible clients to automatically discover the reporting endpoint and send feedback. 3. **Database Integration**: * Added `ConnectionReport` schema to `database/model` and registered it in `database/db.go` for auto-migration. ## Why is this helpful for Restricted Internet Locations? In regions with heavy internet censorship, connection stability is volatile. * **Dynamic Reporting Endpoint**: The `reportUrl` parameter embedded in the subscription link explicitly tells the client *where* to send connection data. * **Bypassing Blocking**: By decoupling the reporting URL from the node address, clients can ensure diagnostic data reaches the panel even if specific node IPs are being interfered with (assuming the panel itself is reachable). * **Real-time Network Intelligence**: This mechanism enables the panel to aggregate "ground truth" data from clients inside the restricted network (e.g., latency, accessibility of specific protocols), allowing admins to react faster to blocking events. * **Protocol Performance Tracking**: Allows comparison of different protocols (Reality vs. VLESS+TLS vs. Trojan) based on real-world latency and success rates from actual users. * **Rapid Troubleshooting**: Administrators can see connection quality trends and rotate IPs/domains proactively when success rates drop, minimizing downtime for users. ## Technical Details * **API Endpoint**: `POST /report` * **Payload Format**: JSON containing `SystemInfo` (Interface), `ConnectionQuality` (Latency, Success), and `ProtocolInfo`. * **Security**: Reports are tied to valid client request contexts (implementation detail: ensure endpoint is rate-limited or authenticated if necessary, though currently designed for open reporting from valid sub links). ## How to Test 1. Update the panel. 2. Generate a subscription link. 3. Observe the `reportUrl` parameter in the link. 4. Simulate a client POST to the report URL and verify the entry in the `ConnectionReports` table.
2026-02-04 10:00:00 +00:00
mtu = 1250,
2024-10-16 10:06:47 +00:00
secretKey = Wireguard.generateKeypair().privateKey,
peers = [new Inbound.WireguardSettings.Peer()],
2024-10-20 10:01:55 +00:00
noKernelTun = false
2024-10-16 10:06:47 +00:00
) {
super(protocol);
this.mtu = mtu;
this.secretKey = secretKey;
this.pubKey = secretKey.length > 0 ? Wireguard.generateKeypair(secretKey).publicKey : '';
this.peers = peers;
2024-10-20 10:01:55 +00:00
this.noKernelTun = noKernelTun;
}
addPeer() {
this.peers.push(new Inbound.WireguardSettings.Peer(null, null, '', ['10.0.0.' + (this.peers.length + 2)]));
}
delPeer(index) {
this.peers.splice(index, 1);
}
static fromJson(json = {}) {
return new Inbound.WireguardSettings(
Protocols.WIREGUARD,
json.mtu,
json.secretKey,
json.peers.map(peer => Inbound.WireguardSettings.Peer.fromJson(peer)),
2024-10-20 10:01:55 +00:00
json.noKernelTun,
);
}
toJson() {
return {
mtu: this.mtu ?? undefined,
secretKey: this.secretKey,
peers: Inbound.WireguardSettings.Peer.toJsonArray(this.peers),
2024-10-20 10:01:55 +00:00
noKernelTun: this.noKernelTun,
};
}
};
Inbound.WireguardSettings.Peer = class extends XrayCommonClass {
constructor(privateKey, publicKey, psk = '', allowedIPs = ['10.0.0.2/32'], keepAlive = 0) {
super();
this.privateKey = privateKey
this.publicKey = publicKey;
if (!this.publicKey) {
[this.publicKey, this.privateKey] = Object.values(Wireguard.generateKeypair())
}
this.psk = psk;
allowedIPs.forEach((a, index) => {
if (a.length > 0 && !a.includes('/')) allowedIPs[index] += '/32';
})
this.allowedIPs = allowedIPs;
this.keepAlive = keepAlive;
}
static fromJson(json = {}) {
return new Inbound.WireguardSettings.Peer(
json.privateKey,
json.publicKey,
json.preSharedKey,
json.allowedIPs,
json.keepAlive
);
}
toJson() {
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,
allowedIPs: this.allowedIPs,
keepAlive: this.keepAlive ?? undefined,
};
}
};
Inbound.TunSettings = class extends Inbound.Settings {
constructor(
protocol,
name = 'xray0',
mtu = 1500,
userLevel = 0
) {
super(protocol);
this.name = name;
this.mtu = mtu;
this.userLevel = userLevel;
}
static fromJson(json = {}) {
return new Inbound.TunSettings(
Protocols.TUN,
json.name ?? 'xray0',
json.mtu ?? json.MTU ?? 1500,
json.userLevel ?? 0
);
}
toJson() {
return {
name: this.name || 'xray0',
mtu: this.mtu || 1500,
userLevel: this.userLevel || 0,
};
}
};