Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMHSanaei <ho3ein.sanaei@gmail.com>2026-04-20 17:05:27 +0300
committerMHSanaei <ho3ein.sanaei@gmail.com>2026-04-20 17:05:27 +0300
commitae5ad505d04fa347eb96a0d2bfb54ff541c3b709 (patch)
tree54a8088e98e15868238be54b063bb051ab84fcb0
parentc188056f64be268dda8f7c16e23f7ef9c90d014f (diff)
add hysteria inbound
Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
-rw-r--r--database/model/model.go8
-rw-r--r--sub/subJsonService.go45
-rw-r--r--sub/subService.go68
-rw-r--r--web/assets/js/model/dbinbound.js4
-rw-r--r--web/assets/js/model/inbound.js551
-rw-r--r--web/assets/js/model/outbound.js4
-rw-r--r--web/html/component/aClientTable.html4
-rw-r--r--web/html/form/client.html112
-rw-r--r--web/html/form/inbound.html8
-rw-r--r--web/html/form/protocol/hysteria.html32
-rw-r--r--web/html/form/stream/stream_hysteria.html75
-rw-r--r--web/html/form/stream/stream_settings.html8
-rw-r--r--web/html/form/tls_settings.html21
-rw-r--r--web/html/inbounds.html483
-rw-r--r--web/html/modals/client_bulk_modal.html104
-rw-r--r--web/html/modals/client_modal.html16
-rw-r--r--web/service/inbound.go22
-rw-r--r--web/service/xray.go4
-rw-r--r--xray/api.go5
19 files changed, 1072 insertions, 502 deletions
diff --git a/database/model/model.go b/database/model/model.go
index 63f4a1b4..5fa934c0 100644
--- a/database/model/model.go
+++ b/database/model/model.go
@@ -21,6 +21,7 @@ const (
Shadowsocks Protocol = "shadowsocks"
Mixed Protocol = "mixed"
WireGuard Protocol = "wireguard"
+ Hysteria Protocol = "hysteria"
)
// User represents a user account in the 3x-ui panel.
@@ -118,10 +119,11 @@ type CustomGeoResource struct {
// Client represents a client configuration for Xray inbounds with traffic limits and settings.
type Client struct {
- ID string `json:"id"` // Unique client identifier
+ ID string `json:"id,omitempty"` // Unique client identifier
Security string `json:"security"` // Security method (e.g., "auto", "aes-128-gcm")
- Password string `json:"password"` // Client password
- Flow string `json:"flow"` // Flow control (XTLS)
+ Password string `json:"password,omitempty"` // Client password
+ Flow string `json:"flow,omitempty"` // Flow control (XTLS)
+ Auth string `json:"auth,omitempty"` // Auth password (Hysteria)
Email string `json:"email"` // Client email identifier
LimitIP int `json:"limitIp"` // IP limit for this client
TotalGB int64 `json:"totalGB" form:"totalGB"` // Total traffic limit in GB
diff --git a/sub/subJsonService.go b/sub/subJsonService.go
index 05552fe8..7ce93e22 100644
--- a/sub/subJsonService.go
+++ b/sub/subJsonService.go
@@ -194,6 +194,8 @@ func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client,
newOutbounds = append(newOutbounds, s.genVless(inbound, streamSettings, client))
case "trojan", "shadowsocks":
newOutbounds = append(newOutbounds, s.genServer(inbound, streamSettings, client))
+ case "hysteria":
+ newOutbounds = append(newOutbounds, s.genHy(inbound, newStream, client))
}
newOutbounds = append(newOutbounds, s.defaultOutbounds...)
@@ -389,6 +391,49 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_u
return result
}
+func (s *SubJsonService) genHy(inbound *model.Inbound, newStream map[string]any, client model.Client) json_util.RawMessage {
+ outbound := Outbound{}
+
+ outbound.Protocol = string(inbound.Protocol)
+ outbound.Tag = "proxy"
+
+ if s.mux != "" {
+ outbound.Mux = json_util.RawMessage(s.mux)
+ }
+
+ var settings, stream map[string]any
+ json.Unmarshal([]byte(inbound.Settings), &settings)
+ version, _ := settings["version"].(float64)
+ outbound.Settings = map[string]any{
+ "version": int(version),
+ "address": inbound.Listen,
+ "port": inbound.Port,
+ }
+
+ json.Unmarshal([]byte(inbound.StreamSettings), &stream)
+ hyStream := stream["hysteriaSettings"].(map[string]any)
+ outHyStream := map[string]any{
+ "version": int(version),
+ "auth": client.Auth,
+ }
+ if udpIdleTimeout, ok := hyStream["udpIdleTimeout"].(float64); ok {
+ outHyStream["udpIdleTimeout"] = int(udpIdleTimeout)
+ }
+ newStream["hysteriaSettings"] = outHyStream
+
+ if finalmask, ok := hyStream["finalmask"].(map[string]any); ok {
+ newStream["finalmask"] = finalmask
+ }
+
+ newStream["network"] = "hysteria"
+ newStream["security"] = "tls"
+
+ outbound.StreamSettings, _ = json.MarshalIndent(newStream, "", " ")
+
+ result, _ := json.MarshalIndent(outbound, "", " ")
+ return result
+}
+
type Outbound struct {
Protocol string `json:"protocol"`
Tag string `json:"tag"`
diff --git a/sub/subService.go b/sub/subService.go
index b6422dd4..a4d38485 100644
--- a/sub/subService.go
+++ b/sub/subService.go
@@ -120,7 +120,7 @@ func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error)
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
WHERE
- protocol in ('vmess','vless','trojan','shadowsocks')
+ protocol in ('vmess','vless','trojan','shadowsocks','hysteria')
AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ?
)`, subId, true).Find(&inbounds).Error
if err != nil {
@@ -171,6 +171,8 @@ func (s *SubService) getLink(inbound *model.Inbound, email string) string {
return s.genTrojanLink(inbound, email)
case "shadowsocks":
return s.genShadowsocksLink(inbound, email)
+ case "hysteria":
+ return s.genHysteriaLink(inbound, email)
}
return ""
}
@@ -885,6 +887,70 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
return url.String()
}
+func (s *SubService) genHysteriaLink(inbound *model.Inbound, email string) string {
+ address := s.address
+ if inbound.Protocol != model.Hysteria {
+ return ""
+ }
+ var stream map[string]interface{}
+ json.Unmarshal([]byte(inbound.StreamSettings), &stream)
+ clients, _ := s.inboundService.GetClients(inbound)
+ clientIndex := -1
+ for i, client := range clients {
+ if client.Email == email {
+ clientIndex = i
+ break
+ }
+ }
+ auth := clients[clientIndex].Auth
+ port := inbound.Port
+ params := make(map[string]string)
+
+ params["security"] = "tls"
+ tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
+ alpns, _ := tlsSetting["alpn"].([]interface{})
+ var alpn []string
+ for _, a := range alpns {
+ alpn = append(alpn, a.(string))
+ }
+ if len(alpn) > 0 {
+ params["alpn"] = strings.Join(alpn, ",")
+ }
+ if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
+ params["sni"], _ = sniValue.(string)
+ }
+
+ tlsSettings, _ := searchKey(tlsSetting, "settings")
+ if tlsSetting != nil {
+ if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
+ params["fp"], _ = fpValue.(string)
+ }
+ if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
+ if insecure.(bool) {
+ params["insecure"] = "1"
+ }
+ }
+ }
+
+ var settings map[string]interface{}
+ json.Unmarshal([]byte(inbound.Settings), &settings)
+ version, _ := settings["version"].(float64)
+ protocol := "hysteria2"
+ if int(version) == 1 {
+ protocol = "hysteria"
+ }
+
+ link := fmt.Sprintf("%s://%s@%s:%d", protocol, auth, address, port)
+ url, _ := url.Parse(link)
+ q := url.Query()
+ for k, v := range params {
+ q.Add(k, v)
+ }
+ url.RawQuery = q.Encode()
+ url.Fragment = s.genRemark(inbound, email, "")
+ return url.String()
+}
+
func (s *SubService) genRemark(inbound *model.Inbound, email string, extra string) string {
separationChar := string(s.remarkModel[0])
orderChars := s.remarkModel[1:]
diff --git a/web/assets/js/model/dbinbound.js b/web/assets/js/model/dbinbound.js
index c347a7eb..e1802635 100644
--- a/web/assets/js/model/dbinbound.js
+++ b/web/assets/js/model/dbinbound.js
@@ -125,7 +125,7 @@ class DBInbound {
sniffing: sniffing,
clientStats: this.clientStats,
};
-
+
this._cachedInbound = Inbound.fromJson(config);
return this._cachedInbound;
}
@@ -147,6 +147,7 @@ class DBInbound {
case Protocols.VMESS:
case Protocols.VLESS:
case Protocols.TROJAN:
+ case Protocols.HYSTERIA:
return true;
case Protocols.SHADOWSOCKS:
return this.toInbound().isSSMultiUser;
@@ -161,6 +162,7 @@ class DBInbound {
case Protocols.VLESS:
case Protocols.TROJAN:
case Protocols.SHADOWSOCKS:
+ case Protocols.HYSTERIA:
return true;
default:
return false;
diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js
index b6059cf7..f74b2736 100644
--- a/web/assets/js/model/inbound.js
+++ b/web/assets/js/model/inbound.js
@@ -8,6 +8,7 @@ const Protocols = {
HTTP: 'http',
WIREGUARD: 'wireguard',
TUN: 'tun',
+ HYSTERIA: 'hysteria',
};
const SSMethods = {
@@ -589,6 +590,106 @@ class xHTTPStreamSettings extends XrayCommonClass {
}
}
+class HysteriaStreamSettings extends XrayCommonClass {
+ constructor(
+ protocol,
+ version = 2,
+ auth = '',
+ udpIdleTimeout = 60,
+ masquerade,
+ ) {
+ super(protocol);
+ this.version = version;
+ this.auth = auth;
+ this.udpIdleTimeout = udpIdleTimeout;
+ this.masquerade = masquerade;
+ }
+
+ static fromJson(json = {}) {
+ return new HysteriaStreamSettings(
+ json.protocol,
+ json.version ?? 2,
+ json.auth ?? '',
+ json.udpIdleTimeout ?? 60,
+ json.masquerade ? HysteriaMasquerade.fromJson(json.masquerade) : undefined,
+ );
+ }
+
+ toJson() {
+ return {
+ protocol: this.protocol,
+ version: this.version,
+ auth: this.auth,
+ udpIdleTimeout: this.udpIdleTimeout,
+ masquerade: this.masqueradeSwitch ? this.masquerade.toJson() : undefined,
+ };
+ }
+
+ get masqueradeSwitch() {
+ return this.masquerade != undefined;
+ }
+
+ set masqueradeSwitch(value) {
+ this.masquerade = value ? new HysteriaMasquerade() : undefined;
+ }
+};
+
+class HysteriaMasquerade extends XrayCommonClass {
+ constructor(
+ type = 'proxy',
+ dir = '',
+ url = '',
+ rewriteHost = false,
+ insecure = false,
+ content = '',
+ headers = [],
+ statusCode = 0,
+ ) {
+ super();
+ this.type = type;
+ this.dir = dir;
+ this.url = url;
+ this.rewriteHost = rewriteHost;
+ this.insecure = insecure;
+ this.content = content;
+ this.headers = headers;
+ this.statusCode = statusCode;
+ }
+
+ addHeader(name, value) {
+ this.headers.push({ name: name, value: value });
+ }
+
+ removeHeader(index) {
+ this.headers.splice(index, 1);
+ }
+
+ static fromJson(json = {}) {
+ return new HysteriaMasquerade(
+ json.type,
+ json.dir,
+ json.url,
+ json.rewriteHost,
+ json.insecure,
+ json.content,
+ XrayCommonClass.toHeaders(json.headers),
+ json.statusCode,
+ );
+ }
+
+ toJson() {
+ return {
+ type: this.type,
+ dir: this.dir,
+ url: this.url,
+ rewriteHost: this.rewriteHost,
+ insecure: this.insecure,
+ content: this.content,
+ headers: XrayCommonClass.toV2Headers(this.headers, false),
+ statusCode: this.statusCode,
+ };
+ }
+};
class TlsStreamSettings extends XrayCommonClass {
constructor(
serverName = '',
@@ -987,6 +1088,12 @@ class UdpMask extends XrayCommonClass {
case 'header-wechat':
case 'header-wireguard':
return {};
+ case 'header-custom':
+ return { client: [], server: [] };
+ case 'noise':
+ return { reset: 0, noise: [] };
+ case 'sudoku':
+ return { ascii: '', customTable: '', customTables: [], paddingMin: 0, paddingMax: 0 };
default:
return settings;
}
@@ -1021,7 +1128,6 @@ class FinalMaskStreamSettings extends XrayCommonClass {
return {
udp: this.udp.map(udp => udp.toJson())
};
-
}
}
@@ -1037,6 +1143,7 @@ class StreamSettings extends XrayCommonClass {
grpcSettings = new GrpcStreamSettings(),
httpupgradeSettings = new HTTPUpgradeStreamSettings(),
xhttpSettings = new xHTTPStreamSettings(),
+ hysteriaSettings = new HysteriaStreamSettings(),
finalmask = new FinalMaskStreamSettings(),
sockopt = undefined,
) {
@@ -1052,6 +1159,7 @@ class StreamSettings extends XrayCommonClass {
this.grpc = grpcSettings;
this.httpupgrade = httpupgradeSettings;
this.xhttp = xhttpSettings;
+ this.hysteria = hysteriaSettings;
this.finalmask = finalmask;
this.sockopt = sockopt;
}
@@ -1116,6 +1224,7 @@ class StreamSettings extends XrayCommonClass {
GrpcStreamSettings.fromJson(json.grpcSettings),
HTTPUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
xHTTPStreamSettings.fromJson(json.xhttpSettings),
+ HysteriaStreamSettings.fromJson(json.hysteriaSettings),
FinalMaskStreamSettings.fromJson(json.finalmask),
SockoptStreamSettings.fromJson(json.sockopt),
);
@@ -1135,6 +1244,7 @@ class StreamSettings extends XrayCommonClass {
grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
+ hysteriaSettings: network === 'hysteria' ? this.hysteria.toJson() : undefined,
finalmask: this.hasFinalMask ? this.finalmask.toJson() : undefined,
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
};
@@ -1201,6 +1311,7 @@ class Inbound extends XrayCommonClass {
case Protocols.VLESS: return this.settings.vlesses;
case Protocols.TROJAN: return this.settings.trojans;
case Protocols.SHADOWSOCKS: return this.isSSMultiUser ? this.settings.shadowsockses : null;
+ case Protocols.HYSTERIA: return this.settings.hysterias;
default: return null;
}
}
@@ -1212,9 +1323,14 @@ class Inbound extends XrayCommonClass {
set protocol(protocol) {
this._protocol = protocol;
this.settings = Inbound.Settings.getSettings(protocol);
+ this.stream = new StreamSettings();
if (protocol === Protocols.TROJAN) {
this.tls = false;
}
+ if (protocol === Protocols.HYSTERIA) {
+ this.stream.network = 'hysteria';
+ this.stream.security = 'tls';
+ }
}
get network() {
@@ -1316,6 +1432,7 @@ class Inbound extends XrayCommonClass {
}
canEnableTls() {
+ if (this.protocol === Protocols.HYSTERIA) return true;
if (![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol)) return false;
return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.network);
}
@@ -1342,7 +1459,7 @@ class Inbound extends XrayCommonClass {
}
canEnableStream() {
- return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol);
+ return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS, Protocols.HYSTERIA].includes(this.protocol);
}
reset() {
@@ -1689,6 +1806,26 @@ class Inbound extends XrayCommonClass {
return url.toString();
}
+ genHysteriaLink(address = '', port = this.port, remark = '', clientAuth) {
+ const protocol = this.settings.version == 2 ? "hysteria2" : "hysteria";
+ const link = `${protocol}://${clientAuth}@${address}:${port}`;
+
+ const params = new Map();
+ params.set("security", "tls");
+ if (this.stream.tls.settings.fingerprint?.length > 0) params.set("fp", this.stream.tls.settings.fingerprint);
+ if (this.stream.tls.alpn?.length > 0) params.set("alpn", this.stream.tls.alpn);
+ if (this.stream.tls.settings.allowInsecure) params.set("insecure", "1");
+ if (this.stream.tls.settings.echConfigList?.length > 0) params.set("ech", this.stream.tls.settings.echConfigList.join(','));
+ if (this.stream.tls.sni?.length > 0) params.set("sni", this.stream.tls.sni);
+
+ 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`
@@ -1721,6 +1858,8 @@ class Inbound extends XrayCommonClass {
return this.genSSLink(address, port, forceTls, remark, this.isSSMultiUser ? client.password : '');
case Protocols.TROJAN:
return this.genTrojanLink(address, port, forceTls, remark, client.password);
+ case Protocols.HYSTERIA:
+ return this.genHysteriaLink(address, port, remark, client.auth.length > 0 ? client.auth : this.stream.hysteria.auth);
default: return '';
}
}
@@ -1827,6 +1966,7 @@ Inbound.Settings = class extends XrayCommonClass {
case Protocols.HTTP: return new Inbound.HttpSettings(protocol);
case Protocols.WIREGUARD: return new Inbound.WireguardSettings(protocol);
case Protocols.TUN: return new Inbound.TunSettings(protocol);
+ case Protocols.HYSTERIA: return new Inbound.HysteriaSettings(protocol);
default: return null;
}
}
@@ -1842,6 +1982,7 @@ Inbound.Settings = class extends XrayCommonClass {
case Protocols.HTTP: return Inbound.HttpSettings.fromJson(json);
case Protocols.WIREGUARD: return Inbound.WireguardSettings.fromJson(json);
case Protocols.TUN: return Inbound.TunSettings.fromJson(json);
+ case Protocols.HYSTERIA: return Inbound.HysteriaSettings.fromJson(json);
default: return null;
}
}
@@ -1851,49 +1992,9 @@ Inbound.Settings = class extends XrayCommonClass {
}
};
-Inbound.VmessSettings = class extends Inbound.Settings {
- constructor(protocol,
- vmesses = [new Inbound.VmessSettings.VMESS()]) {
- super(protocol);
- this.vmesses = vmesses;
- }
-
- indexOfVmessById(id) {
- return this.vmesses.findIndex(VMESS => VMESS.id === id);
- }
-
- addVmess(VMESS) {
- if (this.indexOfVmessById(VMESS.id) >= 0) {
- return false;
- }
- this.vmesses.push(VMESS);
- }
-
- delVmess(VMESS) {
- const i = this.indexOfVmessById(VMESS.id);
- if (i >= 0) {
- this.vmesses.splice(i, 1);
- }
- }
-
- static fromJson(json = {}) {
- return new Inbound.VmessSettings(
- Protocols.VMESS,
- json.clients.map(client => Inbound.VmessSettings.VMESS.fromJson(client)),
- );
- }
-
- toJson() {
- return {
- clients: Inbound.VmessSettings.toJsonArray(this.vmesses),
- };
- }
-};
-
-Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
+/** Shared user-quota fields and UI helpers for multi-user protocol clients. */
+Inbound.ClientBase = class extends XrayCommonClass {
constructor(
- id = RandomUtil.randomUUID(),
- security = USERS_SECURITY.AUTO,
email = RandomUtil.randomLowerAndNum(8),
limitIp = 0,
totalGB = 0,
@@ -1904,11 +2005,9 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
comment = '',
reset = 0,
created_at = undefined,
- updated_at = undefined
+ updated_at = undefined,
) {
super();
- this.id = id;
- this.security = security;
this.email = email;
this.limitIp = limitIp;
this.totalGB = totalGB;
@@ -1922,10 +2021,8 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
this.updated_at = updated_at;
}
- static fromJson(json = {}) {
- return new Inbound.VmessSettings.VMESS(
- json.id,
- json.security,
+ static commonArgsFromJson(json = {}) {
+ return [
json.email,
json.limitIp,
json.totalGB,
@@ -1937,10 +2034,27 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
json.reset,
json.created_at,
json.updated_at,
- );
+ ];
}
+
+ _clientBaseToJson() {
+ return {
+ email: this.email,
+ limitIp: this.limitIp,
+ totalGB: this.totalGB,
+ expiryTime: this.expiryTime,
+ enable: this.enable,
+ tgId: this.tgId,
+ subId: this.subId,
+ comment: this.comment,
+ reset: this.reset,
+ created_at: this.created_at,
+ updated_at: this.updated_at,
+ };
+ }
+
get _expiryTime() {
- if (this.expiryTime === 0 || this.expiryTime === "") {
+ if (this.expiryTime === 0 || this.expiryTime === '') {
return null;
}
if (this.expiryTime < 0) {
@@ -1950,12 +2064,13 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
}
set _expiryTime(t) {
- if (t == null || t === "") {
+ if (t == null || t === '') {
this.expiryTime = 0;
} else {
this.expiryTime = t.valueOf();
}
}
+
get _totalGB() {
return NumberFormatter.toFixed(this.totalGB / SizeFormatter.ONE_GB, 2);
}
@@ -1963,7 +2078,73 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
set _totalGB(gb) {
this.totalGB = NumberFormatter.toFixed(gb * SizeFormatter.ONE_GB, 0);
}
+};
+Inbound.VmessSettings = class extends Inbound.Settings {
+ constructor(protocol,
+ vmesses = [new Inbound.VmessSettings.VMESS()]) {
+ super(protocol);
+ this.vmesses = vmesses;
+ }
+
+ indexOfVmessById(id) {
+ return this.vmesses.findIndex(VMESS => VMESS.id === id);
+ }
+
+ addVmess(VMESS) {
+ if (this.indexOfVmessById(VMESS.id) >= 0) {
+ return false;
+ }
+ this.vmesses.push(VMESS);
+ }
+
+ delVmess(VMESS) {
+ const i = this.indexOfVmessById(VMESS.id);
+ if (i >= 0) {
+ this.vmesses.splice(i, 1);
+ }
+ }
+
+ static fromJson(json = {}) {
+ return new Inbound.VmessSettings(
+ Protocols.VMESS,
+ (json.clients || []).map(client => Inbound.VmessSettings.VMESS.fromJson(client)),
+ );
+ }
+
+ toJson() {
+ return {
+ clients: Inbound.VmessSettings.toJsonArray(this.vmesses),
+ };
+ }
+};
+
+Inbound.VmessSettings.VMESS = class extends Inbound.ClientBase {
+ constructor(
+ id = RandomUtil.randomUUID(),
+ security = USERS_SECURITY.AUTO,
+ email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at,
+ ) {
+ super(email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at);
+ this.id = id;
+ this.security = security;
+ }
+
+ static fromJson(json = {}) {
+ return new Inbound.VmessSettings.VMESS(
+ json.id,
+ json.security,
+ ...Inbound.ClientBase.commonArgsFromJson(json),
+ );
+ }
+
+ toJson() {
+ return {
+ id: this.id,
+ security: this.security,
+ ...this._clientBaseToJson(),
+ };
+ }
};
Inbound.VLESSSettings = class extends Inbound.Settings {
@@ -2041,85 +2222,36 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
return json;
}
-
-
};
-Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
+Inbound.VLESSSettings.VLESS = class extends Inbound.ClientBase {
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
+ email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at,
) {
- super();
+ super(email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at);
this.id = id;
this.flow = flow;
- this.email = email;
- this.limitIp = limitIp;
- this.totalGB = totalGB;
- this.expiryTime = expiryTime;
- this.enable = enable;
- this.tgId = tgId;
- this.subId = subId;
- this.comment = comment;
- this.reset = reset;
- this.created_at = created_at;
- this.updated_at = updated_at;
}
static fromJson(json = {}) {
return new Inbound.VLESSSettings.VLESS(
json.id,
json.flow,
- json.email,
- json.limitIp,
- json.totalGB,
- json.expiryTime,
- json.enable,
- json.tgId,
- json.subId,
- json.comment,
- json.reset,
- json.created_at,
- json.updated_at,
+ ...Inbound.ClientBase.commonArgsFromJson(json),
);
}
- 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);
+ toJson() {
+ return {
+ id: this.id,
+ flow: this.flow,
+ ...this._clientBaseToJson(),
+ };
}
};
+
Inbound.VLESSSettings.Fallback = class extends XrayCommonClass {
constructor(name = "", alpn = '', path = '', dest = '', xver = 0) {
super();
@@ -2179,7 +2311,7 @@ Inbound.TrojanSettings = class extends Inbound.Settings {
static fromJson(json = {}) {
return new Inbound.TrojanSettings(
Protocols.TROJAN,
- json.clients.map(client => Inbound.TrojanSettings.Trojan.fromJson(client)),
+ (json.clients || []).map(client => Inbound.TrojanSettings.Trojan.fromJson(client)),
Inbound.TrojanSettings.Fallback.fromJson(json.fallbacks),);
}
@@ -2191,95 +2323,28 @@ Inbound.TrojanSettings = class extends Inbound.Settings {
}
};
-Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
+Inbound.TrojanSettings.Trojan = class extends Inbound.ClientBase {
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
+ email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at,
) {
- super();
+ super(email, limitIp, totalGB, expiryTime, enable, tgId, subId, comment, reset, created_at, updated_at);
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;
- this.reset = reset;
- this.created_at = created_at;
- this.updated_at = updated_at;
}
toJson() {
return {
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,
- reset: this.reset,
- created_at: this.created_at,
- updated_at: this.updated_at,
+ ...this._clientBaseToJson(),
};
}
static fromJson(json = {}) {
return new Inbound.TrojanSettings.Trojan(
json.password,
- json.email,
- json.limitIp,
- json.totalGB,
- json.expiryTime,
- json.enable,
- json.tgId,
- json.subId,
- json.comment,
- json.reset,
- json.created_at,
- json.updated_at,
+ ...Inbound.ClientBase.commonArgsFromJson(json),
);
}
-
- 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.TrojanSettings.Fallback = class extends XrayCommonClass {
@@ -2343,7 +2408,7 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
json.method,
json.password,
json.network,
- json.clients.map(client => Inbound.ShadowsocksSettings.Shadowsocks.fromJson(client)),
+ (json.clients || []).map(client => Inbound.ShadowsocksSettings.Shadowsocks.fromJson(client)),
json.ivCheck,
);
}
@@ -2359,53 +2424,22 @@ Inbound.Shadowsoc