From 729d8549e2b536a10c402a88e0d4cfde9e4baf3f Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Mon, 4 Dec 2023 19:17:38 +0100 Subject: new frontend and mobile view #1286 --- web/assets/js/model/models.js | 13 ++++++++++++ web/assets/js/util/common.js | 48 +++++++++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 11 deletions(-) (limited to 'web/assets/js') diff --git a/web/assets/js/model/models.js b/web/assets/js/model/models.js index 122145fb..dd602c46 100644 --- a/web/assets/js/model/models.js +++ b/web/assets/js/model/models.js @@ -141,6 +141,19 @@ class DBInbound { return Inbound.fromJson(config); } + isMultiUser() { + switch (this.protocol) { + case Protocols.VMESS: + case Protocols.VLESS: + case Protocols.TROJAN: + return true; + case Protocols.SHADOWSOCKS: + return this.toInbound().isSSMultiUser; + default: + return false; + } + } + hasLink() { switch (this.protocol) { case Protocols.VMESS: diff --git a/web/assets/js/util/common.js b/web/assets/js/util/common.js index 8e30bce7..b2f15fb2 100644 --- a/web/assets/js/util/common.js +++ b/web/assets/js/util/common.js @@ -52,13 +52,15 @@ function safeBase64(str) { function formatSecond(second) { if (second < 60) { - return second.toFixed(0) + ' s'; + return second.toFixed(0) + 's'; } else if (second < 3600) { - return (second / 60).toFixed(0) + ' m'; + return (second / 60).toFixed(0) + 'm'; } else if (second < 3600 * 24) { - return (second / 3600).toFixed(0) + ' h'; + return (second / 3600).toFixed(0) + 'h'; } else { - return (second / 3600 / 24).toFixed(0) + ' d'; + day = Math.floor(second / 3600 / 24); + remain = ((second/3600) - (day*24)).toFixed(0); + return day + 'd' + (remain > 0 ? ' ' + remain + 'h' : ''); } } @@ -72,7 +74,7 @@ function addZero(num) { function toFixed(num, n) { n = Math.pow(10, n); - return Math.round(num * n) / n; + return Math.floor(num * n) / n; } function debounce(fn, delay) { @@ -115,15 +117,39 @@ function setCookie(cname, cvalue, exdays) { function usageColor(data, threshold, total) { switch (true) { case data === null: - return 'blue'; - case total <= 0: - return 'blue'; + return "green"; + case total < 0: + return "blue"; + case total == 0: + return "purple"; case data < total - threshold: - return 'cyan'; + return "blue"; case data < total: - return 'orange'; + return "orange"; default: - return 'red'; + return "red"; + } +} + +function userExpiryColor(threshold, client, isDark = false) { + if (!client.enable) { + return isDark ? '#2c3950' : '#bcbcbc'; + } + now = new Date().getTime(), + expiry = client.expiryTime; + switch (true) { + case expiry === null: + return "#389e0d"; + case expiry < 0: + return "#0e49b5"; + case expiry == 0: + return "#7a316f"; + case now < expiry - threshold: + return "#0e49b5"; + case now < expiry: + return "#ffa031"; + default: + return "#e04141"; } } -- cgit v1.2.3 From a8b7063647c055988f3768a35af59ca391928b9b Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Mon, 4 Dec 2023 19:20:16 +0100 Subject: auto renew feature #1286 --- web/assets/js/model/xray.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'web/assets/js') diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index f7e13be2..d183b882 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -1783,7 +1783,7 @@ Inbound.VmessSettings = class extends Inbound.Settings { } }; Inbound.VmessSettings.Vmess = class extends XrayCommonClass { - constructor(id=RandomUtil.randomUUID(), email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16)) { + constructor(id=RandomUtil.randomUUID(), email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { super(); this.id = id; this.email = email; @@ -1793,6 +1793,7 @@ Inbound.VmessSettings.Vmess = class extends XrayCommonClass { this.enable = enable; this.tgId = tgId; this.subId = subId; + this.reset = reset; } static fromJson(json={}) { @@ -1805,6 +1806,7 @@ Inbound.VmessSettings.Vmess = class extends XrayCommonClass { json.enable, json.tgId, json.subId, + json.reset, ); } get _expiryTime() { @@ -1873,7 +1875,7 @@ Inbound.VLESSSettings = class extends Inbound.Settings { }; 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)) { + constructor(id=RandomUtil.randomUUID(), flow='', email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { super(); this.id = id; this.flow = flow; @@ -1884,6 +1886,7 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass { this.enable = enable; this.tgId = tgId; this.subId = subId; + this.reset = reset; } static fromJson(json={}) { @@ -1897,6 +1900,7 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass { json.enable, json.tgId, json.subId, + json.reset, ); } @@ -1996,7 +2000,7 @@ Inbound.TrojanSettings = class extends Inbound.Settings { } }; Inbound.TrojanSettings.Trojan = class extends XrayCommonClass { - constructor(password=RandomUtil.randomSeq(10), flow='', email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16)) { + constructor(password=RandomUtil.randomSeq(10), flow='', email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { super(); this.password = password; this.flow = flow; @@ -2007,6 +2011,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass { this.enable = enable; this.tgId = tgId; this.subId = subId; + this.reset = reset; } toJson() { @@ -2020,6 +2025,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass { enable: this.enable, tgId: this.tgId, subId: this.subId, + reset: this.reset, }; } @@ -2034,6 +2040,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass { json.enable, json.tgId, json.subId, + json.reset, ); } @@ -2138,7 +2145,7 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings { }; Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { - constructor(method='', password=RandomUtil.randomShadowsocksPassword(), email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16)) { + constructor(method='', password=RandomUtil.randomShadowsocksPassword(), email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16), reset=0) { super(); this.method = method; this.password = password; @@ -2149,6 +2156,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { this.enable = enable; this.tgId = tgId; this.subId = subId; + this.reset = reset; } toJson() { @@ -2162,6 +2170,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { enable: this.enable, tgId: this.tgId, subId: this.subId, + reset: this.reset, }; } @@ -2176,6 +2185,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { json.enable, json.tgId, json.subId, + json.reset, ); } -- cgit v1.2.3 From 375814da273cd2548c30fc56a86dd74ef5f009c9 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Mon, 4 Dec 2023 23:51:14 +0330 Subject: [bug] fix status colors in pages Co-Authored-By: Alireza Ahmadi --- web/assets/js/util/common.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'web/assets/js') diff --git a/web/assets/js/util/common.js b/web/assets/js/util/common.js index b2f15fb2..38a2c37e 100644 --- a/web/assets/js/util/common.js +++ b/web/assets/js/util/common.js @@ -131,6 +131,19 @@ function usageColor(data, threshold, total) { } } +function clientUsageColor(clientStats, trafficDiff) { + switch (true) { + case !clientStats || clientStats.total == 0: + return "#7a316f"; + case clientStats.up + clientStats.down < clientStats.total - trafficDiff: + return "#0e49b5"; + case clientStats.up + clientStats.down < clientStats.total: + return "#FFA031"; + default: + return "#E04141"; + } +} + function userExpiryColor(threshold, client, isDark = false) { if (!client.enable) { return isDark ? '#2c3950' : '#bcbcbc'; -- cgit v1.2.3 From d8c509b41056b9ca41725fac0bfa7515ce1f795b Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 5 Dec 2023 00:19:01 +0330 Subject: small typo Co-Authored-By: Alireza Ahmadi --- web/assets/js/util/common.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'web/assets/js') diff --git a/web/assets/js/util/common.js b/web/assets/js/util/common.js index 38a2c37e..82bc9a0c 100644 --- a/web/assets/js/util/common.js +++ b/web/assets/js/util/common.js @@ -138,9 +138,9 @@ function clientUsageColor(clientStats, trafficDiff) { case clientStats.up + clientStats.down < clientStats.total - trafficDiff: return "#0e49b5"; case clientStats.up + clientStats.down < clientStats.total: - return "#FFA031"; + return "#ffa031"; default: - return "#E04141"; + return "#e04141"; } } -- cgit v1.2.3 From c419eadf15630518606ab434387079172070d340 Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Tue, 5 Dec 2023 18:13:36 +0100 Subject: xray setting enhancements #1286 --- web/assets/js/model/dbinbound.js | 144 +++++++ web/assets/js/model/models.js | 224 ---------- web/assets/js/model/outbound.js | 900 +++++++++++++++++++++++++++++++++++++++ web/assets/js/model/setting.js | 45 ++ web/assets/js/util/utils.js | 18 + 5 files changed, 1107 insertions(+), 224 deletions(-) create mode 100644 web/assets/js/model/dbinbound.js delete mode 100644 web/assets/js/model/models.js create mode 100644 web/assets/js/model/outbound.js create mode 100644 web/assets/js/model/setting.js (limited to 'web/assets/js') diff --git a/web/assets/js/model/dbinbound.js b/web/assets/js/model/dbinbound.js new file mode 100644 index 00000000..7f4f0812 --- /dev/null +++ b/web/assets/js/model/dbinbound.js @@ -0,0 +1,144 @@ +class DBInbound { + + constructor(data) { + this.id = 0; + this.userId = 0; + this.up = 0; + this.down = 0; + this.total = 0; + this.remark = ""; + this.enable = true; + this.expiryTime = 0; + + this.listen = ""; + this.port = 0; + this.protocol = ""; + this.settings = ""; + this.streamSettings = ""; + this.tag = ""; + this.sniffing = ""; + this.clientStats = "" + if (data == null) { + return; + } + ObjectUtil.cloneProps(this, data); + } + + get totalGB() { + return toFixed(this.total / ONE_GB, 2); + } + + set totalGB(gb) { + this.total = toFixed(gb * ONE_GB, 0); + } + + get isVMess() { + return this.protocol === Protocols.VMESS; + } + + get isVLess() { + return this.protocol === Protocols.VLESS; + } + + get isTrojan() { + return this.protocol === Protocols.TROJAN; + } + + get isSS() { + return this.protocol === Protocols.SHADOWSOCKS; + } + + get isSocks() { + return this.protocol === Protocols.SOCKS; + } + + get isHTTP() { + return this.protocol === Protocols.HTTP; + } + + get address() { + let address = location.hostname; + if (!ObjectUtil.isEmpty(this.listen) && this.listen !== "0.0.0.0") { + address = this.listen; + } + return address; + } + + get _expiryTime() { + if (this.expiryTime === 0) { + return null; + } + return moment(this.expiryTime); + } + + set _expiryTime(t) { + if (t == null) { + this.expiryTime = 0; + } else { + this.expiryTime = t.valueOf(); + } + } + + get isExpiry() { + return this.expiryTime < new Date().getTime(); + } + + toInbound() { + let settings = {}; + if (!ObjectUtil.isEmpty(this.settings)) { + settings = JSON.parse(this.settings); + } + + let streamSettings = {}; + if (!ObjectUtil.isEmpty(this.streamSettings)) { + streamSettings = JSON.parse(this.streamSettings); + } + + let sniffing = {}; + if (!ObjectUtil.isEmpty(this.sniffing)) { + sniffing = JSON.parse(this.sniffing); + } + + const config = { + port: this.port, + listen: this.listen, + protocol: this.protocol, + settings: settings, + streamSettings: streamSettings, + tag: this.tag, + sniffing: sniffing, + clientStats: this.clientStats, + }; + return Inbound.fromJson(config); + } + + isMultiUser() { + switch (this.protocol) { + case Protocols.VMESS: + case Protocols.VLESS: + case Protocols.TROJAN: + return true; + case Protocols.SHADOWSOCKS: + return this.toInbound().isSSMultiUser; + default: + return false; + } + } + + hasLink() { + switch (this.protocol) { + case Protocols.VMESS: + case Protocols.VLESS: + case Protocols.TROJAN: + case Protocols.SHADOWSOCKS: + return true; + default: + return false; + } + } + + get genInboundLinks() { + const inbound = this.toInbound(); + return inbound.genInboundLinks(this.remark); + } +} \ No newline at end of file diff --git a/web/assets/js/model/models.js b/web/assets/js/model/models.js deleted file mode 100644 index dd602c46..00000000 --- a/web/assets/js/model/models.js +++ /dev/null @@ -1,224 +0,0 @@ -class User { - - constructor() { - this.username = ""; - this.password = ""; - this.LoginSecret = ""; - } -} - -class Msg { - - constructor(success, msg, obj) { - this.success = false; - this.msg = ""; - this.obj = null; - - if (success != null) { - this.success = success; - } - if (msg != null) { - this.msg = msg; - } - if (obj != null) { - this.obj = obj; - } - } -} - -class DBInbound { - - constructor(data) { - this.id = 0; - this.userId = 0; - this.up = 0; - this.down = 0; - this.total = 0; - this.remark = ""; - this.enable = true; - this.expiryTime = 0; - this.limitIp = 0; - - this.listen = ""; - this.port = 0; - this.protocol = ""; - this.settings = ""; - this.streamSettings = ""; - this.tag = ""; - this.sniffing = ""; - this.clientStats = "" - if (data == null) { - return; - } - ObjectUtil.cloneProps(this, data); - } - - get totalGB() { - return toFixed(this.total / ONE_GB, 2); - } - - set totalGB(gb) { - this.total = toFixed(gb * ONE_GB, 0); - } - - get isVMess() { - return this.protocol === Protocols.VMESS; - } - - get isVLess() { - return this.protocol === Protocols.VLESS; - } - - get isTrojan() { - return this.protocol === Protocols.TROJAN; - } - - get isSS() { - return this.protocol === Protocols.SHADOWSOCKS; - } - - get isSocks() { - return this.protocol === Protocols.SOCKS; - } - - get isHTTP() { - return this.protocol === Protocols.HTTP; - } - - get address() { - let address = location.hostname; - if (!ObjectUtil.isEmpty(this.listen) && this.listen !== "0.0.0.0") { - address = this.listen; - } - return address; - } - - get _expiryTime() { - if (this.expiryTime === 0) { - return null; - } - return moment(this.expiryTime); - } - - set _expiryTime(t) { - if (t == null) { - this.expiryTime = 0; - } else { - this.expiryTime = t.valueOf(); - } - } - - get isExpiry() { - return this.expiryTime < new Date().getTime(); - } - - toInbound() { - let settings = {}; - if (!ObjectUtil.isEmpty(this.settings)) { - settings = JSON.parse(this.settings); - } - - let streamSettings = {}; - if (!ObjectUtil.isEmpty(this.streamSettings)) { - streamSettings = JSON.parse(this.streamSettings); - } - - let sniffing = {}; - if (!ObjectUtil.isEmpty(this.sniffing)) { - sniffing = JSON.parse(this.sniffing); - } - - const config = { - port: this.port, - listen: this.listen, - protocol: this.protocol, - settings: settings, - streamSettings: streamSettings, - tag: this.tag, - sniffing: sniffing, - clientStats: this.clientStats, - }; - return Inbound.fromJson(config); - } - - isMultiUser() { - switch (this.protocol) { - case Protocols.VMESS: - case Protocols.VLESS: - case Protocols.TROJAN: - return true; - case Protocols.SHADOWSOCKS: - return this.toInbound().isSSMultiUser; - default: - return false; - } - } - - hasLink() { - switch (this.protocol) { - case Protocols.VMESS: - case Protocols.VLESS: - case Protocols.TROJAN: - case Protocols.SHADOWSOCKS: - return true; - default: - return false; - } - } - - genLink(address=this.address, remark=this.remark, clientIndex=0) { - const inbound = this.toInbound(); - return inbound.genLink(address, remark, clientIndex); - } - - get genInboundLinks() { - const inbound = this.toInbound(); - return inbound.genInboundLinks(this.address, this.remark); - } -} - -class AllSetting { - - constructor(data) { - this.webListen = ""; - this.webDomain = ""; - this.webPort = 2053; - this.webCertFile = ""; - this.webKeyFile = ""; - this.webBasePath = "/"; - this.sessionMaxAge = ""; - this.expireDiff = ""; - this.trafficDiff = ""; - this.tgBotEnable = false; - this.tgBotToken = ""; - this.tgBotChatId = ""; - this.tgRunTime = "@daily"; - this.tgBotBackup = false; - this.tgBotLoginNotify = true; - this.tgCpu = ""; - this.tgLang = "en-US"; - this.xrayTemplateConfig = ""; - this.secretEnable = false; - this.subEnable = false; - this.subListen = ""; - this.subPort = "2096"; - this.subPath = "/sub/"; - this.subDomain = ""; - this.subCertFile = ""; - this.subKeyFile = ""; - this.subUpdates = 0; - this.subEncrypt = true; - this.subShowInfo = true; - - this.timeLocation = "Asia/Tehran"; - - if (data == null) { - return - } - ObjectUtil.cloneProps(this, data); - } - - equals(other) { - return ObjectUtil.equals(this, other); - } -} \ No newline at end of file diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js new file mode 100644 index 00000000..75d3b878 --- /dev/null +++ b/web/assets/js/model/outbound.js @@ -0,0 +1,900 @@ +const Protocols = { + Freedom: "freedom", + Blackhole: "blackhole", + DNS: "dns", + VMess: "vmess", + VLESS: "vless", + Trojan: "trojan", + Shadowsocks: "shadowsocks", + Socks: "socks", + HTTP: "http", +}; + +const SSMethods = { + AES_256_GCM: 'aes-256-gcm', + AES_128_GCM: 'aes-128-gcm', + CHACHA20_POLY1305: 'chacha20-poly1305', + CHACHA20_IETF_POLY1305: 'chacha20-ietf-poly1305', + XCHACHA20_POLY1305: 'xchacha20-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', +}; + +const TLS_FLOW_CONTROL = { + VISION: "xtls-rprx-vision", + VISION_UDP443: "xtls-rprx-vision-udp443", +}; + +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", +}; + +const ALPN_OPTION = { + H3: "h3", + H2: "h2", + HTTP1: "http/1.1", +}; + +const outboundDomainStrategies = [ + "AsIs", + "UseIP", + "UseIPv4", + "UseIPv6" +] + +Object.freeze(Protocols); +Object.freeze(SSMethods); +Object.freeze(TLS_FLOW_CONTROL); +Object.freeze(ALPN_OPTION); +Object.freeze(outboundDomainStrategies); + +class CommonClass { + + static toJsonArray(arr) { + return arr.map(obj => obj.toJson()); + } + + static fromJson() { + return new CommonClass(); + } + + toJson() { + return this; + } + + toString(format=true) { + return format ? JSON.stringify(this.toJson(), null, 2) : JSON.stringify(this.toJson()); + } +} + +class TcpStreamSettings extends CommonClass { + constructor(type='none', host, path) { + super(); + this.type = type; + this.host = host; + this.path = path; + } + + static fromJson(json={}) { + let header = json.header; + if (!header) return new TcpStreamSettings(); + if(header.type == 'http' && header.request){ + return new TcpStreamSettings( + header.type, + header.request.headers.Host.join(','), + header.request.path.join(','), + ); + } + return new TcpStreamSettings(header.type,'',''); + } + + toJson() { + return { + header: { + type: this.type, + request: this.type === 'http' ? { + headers: { + Host: ObjectUtil.isEmpty(this.host) ? [] : this.host.split(',') + }, + path: ObjectUtil.isEmpty(this.path) ? ["/"] : this.path.split(',') + } : undefined, + } + }; + } +} + +class KcpStreamSettings extends CommonClass { + constructor(mtu=1350, tti=20, + uplinkCapacity=5, + downlinkCapacity=20, + congestion=false, + readBufferSize=2, + writeBufferSize=2, + type='none', + seed='', + ) { + super(); + this.mtu = mtu; + this.tti = tti; + this.upCap = uplinkCapacity; + this.downCap = downlinkCapacity; + this.congestion = congestion; + this.readBuffer = readBufferSize; + this.writeBuffer = writeBufferSize; + this.type = type; + this.seed = seed; + } + + static fromJson(json={}) { + return new KcpStreamSettings( + json.mtu, + json.tti, + json.uplinkCapacity, + json.downlinkCapacity, + json.congestion, + json.readBufferSize, + json.writeBufferSize, + ObjectUtil.isEmpty(json.header) ? 'none' : json.header.type, + json.seed, + ); + } + + toJson() { + return { + mtu: this.mtu, + tti: this.tti, + uplinkCapacity: this.upCap, + downlinkCapacity: this.downCap, + congestion: this.congestion, + readBufferSize: this.readBuffer, + writeBufferSize: this.writeBuffer, + header: { + type: this.type, + }, + seed: this.seed, + }; + } +} + +class WsStreamSettings extends CommonClass { + constructor(path='/', host='') { + super(); + this.path = path; + this.host = host; + } + + static fromJson(json={}) { + return new WsStreamSettings( + json.path, + json.headers && !ObjectUtil.isEmpty(json.headers.Host) ? json.headers.Host : '', + ); + } + + toJson() { + return { + path: this.path, + headers: ObjectUtil.isEmpty(this.host) ? undefined : {Host: this.host}, + }; + } +} + +class HttpStreamSettings extends CommonClass { + constructor(path='/', host='') { + super(); + this.path = path; + this.host = host; + } + + static fromJson(json={}) { + return new HttpStreamSettings( + json.path, + json.host ? json.host.join(',') : '', + ); + } + + toJson() { + return { + path: this.path, + host: ObjectUtil.isEmpty(this.host) ? [''] : this.host.split(','), + } + } +} + +class QuicStreamSettings extends CommonClass { + constructor(security='none', + key='', type='none') { + super(); + this.security = security; + this.key = key; + this.type = type; + } + + static fromJson(json={}) { + return new QuicStreamSettings( + json.security, + json.key, + json.header ? json.header.type : 'none', + ); + } + + toJson() { + return { + security: this.security, + key: this.key, + header: { + type: this.type, + } + } + } +} + +class GrpcStreamSettings extends CommonClass { + constructor(serviceName="", multiMode=false) { + super(); + this.serviceName = serviceName; + this.multiMode = multiMode; + } + + static fromJson(json={}) { + return new GrpcStreamSettings(json.serviceName, json.multiMode); + } + + toJson() { + return { + serviceName: this.serviceName, + multiMode: this.multiMode, + } + } +} + +class TlsStreamSettings extends CommonClass { + constructor(serverName='', + alpn=[], + fingerprint = '', + allowInsecure = false) { + super(); + this.serverName = serverName; + this.alpn = alpn; + this.fingerprint = fingerprint; + this.allowInsecure = allowInsecure; + } + + static fromJson(json={}) { + return new TlsStreamSettings( + json.serverName, + json.alpn, + json.fingerprint, + json.allowInsecure, + ); + } + + toJson() { + return { + serverName: this.serverName, + alpn: this.alpn, + fingerprint: this.fingerprint, + allowInsecure: this.allowInsecure, + }; + } +} + +class RealityStreamSettings extends CommonClass { + constructor(publicKey = '', fingerprint = '', serverName = '', shortId = '', spiderX = '/') { + super(); + this.publicKey = publicKey; + this.fingerprint = fingerprint; + this.serverName = serverName; + this.shortId = shortId + this.spiderX = spiderX; + } + static fromJson(json = {}) { + return new RealityStreamSettings( + json.publicKey, + json.fingerprint, + json.serverName, + json.shortId, + json.spiderX, + ); + } + toJson() { + return { + publicKey: this.publicKey, + fingerprint: this.fingerprint, + serverName: this.serverName, + shortId: this.shortId, + spiderX: this.spiderX, + }; + } +}; + +class StreamSettings extends CommonClass { + constructor(network='tcp', + security='none', + tlsSettings=new TlsStreamSettings(), + realitySettings = new RealityStreamSettings(), + tcpSettings=new TcpStreamSettings(), + kcpSettings=new KcpStreamSettings(), + wsSettings=new WsStreamSettings(), + httpSettings=new HttpStreamSettings(), + quicSettings=new QuicStreamSettings(), + grpcSettings=new GrpcStreamSettings(), + ) { + super(); + this.network = network; + this.security = security; + this.tls = tlsSettings; + this.reality = realitySettings; + this.tcp = tcpSettings; + this.kcp = kcpSettings; + this.ws = wsSettings; + this.http = httpSettings; + this.quic = quicSettings; + this.grpc = grpcSettings; + } + + get isTls() { + return this.security === 'tls'; + } + + get isReality() { + return this.security === "reality"; + } + + static fromJson(json={}) { + return new StreamSettings( + json.network, + json.security, + TlsStreamSettings.fromJson(json.tlsSettings), + RealityStreamSettings.fromJson(json.realitySettings), + TcpStreamSettings.fromJson(json.tcpSettings), + KcpStreamSettings.fromJson(json.kcpSettings), + WsStreamSettings.fromJson(json.wsSettings), + HttpStreamSettings.fromJson(json.httpSettings), + QuicStreamSettings.fromJson(json.quicSettings), + GrpcStreamSettings.fromJson(json.grpcSettings), + ); + } + + toJson() { + const network = this.network; + return { + network: network, + security: this.security, + tlsSettings: this.security == 'tls' ? this.tls.toJson() : undefined, + realitySettings: this.security == 'reality' ? this.reality.toJson() : undefined, + tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined, + kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined, + wsSettings: network === 'ws' ? this.ws.toJson() : undefined, + httpSettings: network === 'http' ? this.http.toJson() : undefined, + quicSettings: network === 'quic' ? this.quic.toJson() : undefined, + grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined, + }; + } +} + +class Outbound extends CommonClass { + constructor( + tag='', + protocol=Protocols.VMess, + settings=null, + streamSettings = new StreamSettings(), + ) { + super(); + this.tag = tag; + this._protocol = protocol; + this.settings = settings == null ? Outbound.Settings.getSettings(protocol) : settings; + this.stream = streamSettings; + } + + get protocol() { + return this._protocol; + } + + set protocol(protocol) { + this._protocol = protocol; + this.settings = Outbound.Settings.getSettings(protocol); + this.stream = new StreamSettings(); + } + + canEnableTls() { + if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan].includes(this.protocol)) return false; + return ["tcp", "ws", "http", "quic", "grpc"].includes(this.stream.network); + } + + //this is used for xtls-rprx-vision + canEnableTlsFlow() { + if ((this.stream.security != 'none') && (this.stream.network === "tcp")) { + return this.protocol === Protocols.VLESS; + } + return false; + } + + canEnableReality() { + if (![Protocols.VLESS, Protocols.Trojan].includes(this.protocol)) return false; + return ["tcp", "http", "grpc"].includes(this.stream.network); + } + + canEnableStream() { + return [Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(this.protocol); + } + + hasVnext() { + return [Protocols.VMess, Protocols.VLESS].includes(this.protocol); + } + + hasServers() { + return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Socks, Protocols.HTTP].includes(this.protocol); + } + + hasAddressPort() { + return [ + Protocols.DNS, + Protocols.VMess, + Protocols.VLESS, + Protocols.Trojan, + Protocols.Shadowsocks, + Protocols.Socks, + Protocols.HTTP + ].includes(this.protocol); + } + + hasUsername() { + return [Protocols.Socks, Protocols.HTTP].includes(this.protocol); + } + + static fromJson(json={}) { + return new Outbound( + json.tag, + json.protocol, + Outbound.Settings.fromJson(json.protocol, json.settings), + StreamSettings.fromJson(json.streamSettings), + ) + } + + toJson() { + return { + tag: this.tag == '' ? undefined : this.tag, + protocol: this.protocol, + settings: this.settings instanceof CommonClass ? this.settings.toJson() : this.settings, + streamSettings: this.canEnableStream() ? this.stream.toJson() : undefined, + }; + } + + static fromLink(link) { + data = link.split('://'); + if(data.length !=2) return null; + switch(data[0].toLowerCase()){ + case Protocols.VMess: + return this.fromVmessLink(JSON.parse(atob(data[1]))); + case Protocols.VLESS: + case Protocols.Trojan: + case 'ss': + return this.fromParamLink(link); + default: + return null; + } + } + + static fromVmessLink(json={}){ + let stream = new StreamSettings(json.net, json.tls); + + let network = json.net; + if (network === 'tcp') { + stream.tcp = new TcpStreamSettings( + json.type, + json.host ? json.host.split(','): [], + json.path ? json.path.split(','): []); + } else if (network === 'kcp') { + stream.kcp = new KcpStreamSettings(); + stream.type = json.type; + stream.seed = json.path; + } else if (network === 'ws') { + stream.ws = new WsStreamSettings(json.path,json.host); + } else if (network === 'http' || network == 'h2') { + stream.network = 'http' + stream.http = new HttpStreamSettings( + json.path, + json.host ? json.host.split(',') : []); + } else if (network === 'quic') { + stream.quic = new QuicStreamSettings( + json.host ? json.host : 'none', + json.path, + json.type ? json.type : 'none'); + } else if (network === 'grpc') { + stream.grpc = new GrpcStreamSettings(json.path, json.type == 'multi'); + } + + if(json.tls && json.tls == 'tls'){ + stream.tls = new TlsStreamSettings( + json.sni, + json.alpn ? json.alpn.split(',') : [], + json.fp, + json.allowInsecure); + } + + + return new Outbound(json.ps, Protocols.VMess, new Outbound.VmessSettings(json.add, json.port, json.id), stream); + } + + static fromParamLink(link){ + const url = new URL(link); + let type = url.searchParams.get('type'); + let security = url.searchParams.get('security') ?? 'none'; + let stream = new StreamSettings(type, security); + + let headerType = url.searchParams.get('headerType'); + let host = url.searchParams.get('host'); + let path = url.searchParams.get('path'); + + if (type === 'tcp') { + stream.tcp = new TcpStreamSettings(headerType ?? 'none', host, path); + } else if (type === 'kcp') { + stream.kcp = new KcpStreamSettings(); + stream.kcp.type = headerType ?? 'none'; + stream.kcp.seed = path; + } else if (type === 'ws') { + stream.ws = new WsStreamSettings(path,host); + } else if (type === 'http' || type == 'h2') { + stream.http = new HttpStreamSettings(path,host); + } else if (type === 'quic') { + stream.quic = new QuicStreamSettings( + url.searchParams.get('quicSecurity') ?? 'none', + url.searchParams.get('key') ?? '', + headerType ?? 'none'); + } else if (type === 'grpc') { + stream.grpc = new GrpcStreamSettings(url.searchParams.get('serviceName') ?? '', url.searchParams.get('mode') == 'multi'); + } + + if(security == 'tls'){ + let fp=url.searchParams.get('fp') ?? 'none'; + let alpn=url.searchParams.get('alpn'); + let allowInsecure=url.searchParams.get('allowInsecure'); + let sni=url.searchParams.get('sni') ?? ''; + stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, allowInsecure == 1); + } + + if(security == 'reality'){ + let pbk=url.searchParams.get('pbk'); + let fp=url.searchParams.get('fp'); + let sni=url.searchParams.get('sni') ?? ''; + let sid=url.searchParams.get('sid') ?? ''; + let spx=url.searchParams.get('spx') ?? ''; + stream.tls = new RealityStreamSettings(pbk, fp, sni, sid, spx); + } + + let data = link.split('?'); + if(data.length != 2) return null; + + const regex = /([^@]+):\/\/([^@]+)@([^:]+):(\d+)\?(.*)$/; + const match = link.match(regex); + + if (!match) return null; + let [, protocol, userData, address, port, ] = match; + port *= 1; + if(protocol == 'ss') { + protocol = 'shadowsocks'; + userData = atob(userData).split(':'); + } + var settings; + switch(protocol){ + case Protocols.VLESS: + settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? ''); + break; + case Protocols.Trojan: + settings = new Outbound.TrojanSettings(address, port, userData); + break; + case Protocols.Shadowsocks: + let method = userData.splice(0,1)[0]; + settings = new Outbound.ShadowsocksSettings(address, port, userData.join(":"), method, true); + break; + default: + return null; + } + let remark = decodeURIComponent(url.hash); + // Remove '#' from url.hash + remark = remark.length > 0 ? remark.substring(1) : 'out-' + protocol + '-' + port; + return new Outbound(remark, protocol, settings, stream); + } +} + +Outbound.Settings = class extends CommonClass { + constructor(protocol) { + super(); + this.protocol = protocol; + } + + static getSettings(protocol) { + switch (protocol) { + case Protocols.Freedom: return new Outbound.FreedomSettings(); + case Protocols.Blackhole: return new Outbound.BlackholeSettings(); + case Protocols.DNS: return new Outbound.DNSSettings(); + case Protocols.VMess: return new Outbound.VmessSettings(); + case Protocols.VLESS: return new Outbound.VLESSSettings(); + case Protocols.Trojan: return new Outbound.TrojanSettings(); + case Protocols.Shadowsocks: return new Outbound.ShadowsocksSettings(); + case Protocols.Socks: return new Outbound.SocksSettings(); + case Protocols.HTTP: return new Outbound.HttpSettings(); + default: return null; + } + } + + static fromJson(protocol, json) { + switch (protocol) { + case Protocols.Freedom: return Outbound.FreedomSettings.fromJson(json); + case Protocols.Blackhole: return Outbound.BlackholeSettings.fromJson(json); + case Protocols.DNS: return Outbound.DNSSettings.fromJson(json); + case Protocols.VMess: return Outbound.VmessSettings.fromJson(json); + case Protocols.VLESS: return Outbound.VLESSSettings.fromJson(json); + case Protocols.Trojan: return Outbound.TrojanSettings.fromJson(json); + case Protocols.Shadowsocks: return Outbound.ShadowsocksSettings.fromJson(json); + case Protocols.Socks: return Outbound.SocksSettings.fromJson(json); + case Protocols.HTTP: return Outbound.HttpSettings.fromJson(json); + default: return null; + } + } + + toJson() { + return {}; + } +}; +Outbound.FreedomSettings = class extends CommonClass { + constructor(domainStrategy='', fragment={}) { + super(); + this.domainStrategy = domainStrategy; + this.fragment = fragment; + } + + static fromJson(json={}) { + return new Outbound.FreedomSettings( + json.domainStrategy, + json.fragment ? Outbound.FreedomSettings.Fragment.fromJson(json.fragment) : undefined, + ); + } + + toJson() { + return { + domainStrategy: ObjectUtil.isEmpty(this.domainStrategy) ? undefined : this.domainStrategy, + fragment: Object.keys(this.fragment).length === 0 ? undefined : this.fragment, + }; + } +}; +Outbound.FreedomSettings.Fragment = class extends CommonClass { + constructor(packets='1-3',length='',interval=''){ + super(); + this.packets = packets; + this.length = length; + this.interval = interval; + } + + static fromJson(json={}) { + return new Outbound.FreedomSettings.Fragment( + json.packets, + json.length, + json.interval, + ); + } +}; +Outbound.BlackholeSettings = class extends CommonClass { + constructor(type) { + super(); + this.type; + } + + static fromJson(json={}) { + return new Outbound.BlackholeSettings( + json.response ? json.response.type : undefined, + ); + } + + toJson() { + return { + response: ObjectUtil.isEmpty(this.type) ? undefined : {type: this.type}, + }; + } +}; +Outbound.DNSSettings = class extends CommonClass { + constructor(network='udp', address='1.1.1.1', port=53) { + super(); + this.network = network; + this.address = address; + this.port = port; + } + + static fromJson(json={}){ + return new Outbound.DNSSettings( + json.network, + json.address, + json.port, + ); + } +}; +Outbound.VmessSettings = class extends CommonClass { + constructor(address, port, id) { + super(); + this.address = address; + this.port = port; + this.id = id; + } + + static fromJson(json={}) { + if(ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VmessSettings(); + return new Outbound.VmessSettings( + json.vnext[0].address, + json.vnext[0].port, + json.vnext[0].users[0].id, + ); + } + + toJson() { + return { + vnext: [{ + address: this.address, + port: this.port, + users: [{id: this.id}], + }], + }; + } +}; +Outbound.VLESSSettings = class extends CommonClass { + constructor(address, port, id, flow, encryption='none') { + super(); + this.address = address; + this.port = port; + this.id = id; + this.flow = flow; + this.encryption = encryption + } + + static fromJson(json={}) { + if(ObjectUtil.isArrEmpty(json.vnext)) return new Outbound.VLESSSettings(); + return new Outbound.VLESSSettings( + json.vnext[0].address, + json.vnext[0].port, + json.vnext[0].users[0].id, + json.vnext[0].users[0].flow, + json.vnext[0].users[0].encryption, + ); + } + + toJson() { + return { + vnext: [{ + address: this.address, + port: this.port, + users: [{id: this.id, flow: this.flow, encryption: 'none',}], + }], + }; + } +}; +Outbound.TrojanSettings = class extends CommonClass { + constructor(address, port, password) { + super(); + this.address = address; + this.port = port; + this.password = password; + } + + static fromJson(json={}) { + if(ObjectUtil.isArrEmpty(json.servers)) return new Outbound.TrojanSettings(); + return new Outbound.TrojanSettings( + json.servers[0].address, + json.servers[0].port, + json.servers[0].password, + ); + } + + toJson() { + return { + servers: [{ + address: this.address, + port: this.port, + password: this.password, + }], + }; + } +}; +Outbound.ShadowsocksSettings = class extends CommonClass { + constructor(address, port, password, method, uot) { + super(); + this.address = address; + this.port = port; + this.password = password; + this.method = method; + this.uot = uot; + } + + static fromJson(json={}) { + let servers = json.servers; + if(ObjectUtil.isArrEmpty(servers)) servers=[{}]; + return new Outbound.ShadowsocksSettings( + servers[0].address, + servers[0].port, + servers[0].password, + servers[0].method, + servers[0].uot, + ); + } + + toJson() { + return { + servers: [{ + address: this.address, + port: this.port, + password: this.password, + method: this.method, + uot: this.uot, + }], + }; + } +}; +Outbound.SocksSettings = class extends CommonClass { + constructor(address, port, user, password) { + super(); + this.address = address; + this.port = port; + this.user = user; + this.password = password; + } + + static fromJson(json={}) { + servers = json.servers; + if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}]; + return new Outbound.SocksSettings( + servers[0].address, + servers[0].port, + ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user, + ObjectUtil.isArrEmpty(servers[0].password) ? '' : servers[0].users[0].password, + ); + } + + toJson() { + return { + servers: [{ + address: this.address, + port: this.port, + users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, password: this.password}], + }], + }; + } +}; +Outbound.HttpSettings = class extends CommonClass { + constructor(address, port, user, password) { + super(); + this.address = address; + this.port = port; + this.user = user; + this.password = password; + } + + static fromJson(json={}) { + servers = json.servers; + if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}]; + return new Outbound.HttpSettings( + servers[0].address, + servers[0].port, + ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user, + ObjectUtil.isArrEmpty(servers[0].password) ? '' : servers[0].users[0].password, + ); + } + + toJson() { + return { + servers: [{ + address: this.address, + port: this.port, + users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, password: this.password}], + }], + }; + } +}; \ No newline at end of file diff --git a/web/assets/js/model/setting.js b/web/assets/js/model/setting.js new file mode 100644 index 00000000..06f66f81 --- /dev/null +++ b/web/assets/js/model/setting.js @@ -0,0 +1,45 @@ +class AllSetting { + + constructor(data) { + this.webListen = ""; + this.webDomain = ""; + this.webPort = 54321; + this.webCertFile = ""; + this.webKeyFile = ""; + this.webBasePath = "/"; + this.sessionMaxAge = ""; + this.pageSize = 0; + this.expireDiff = ""; + this.trafficDiff = ""; + this.tgBotEnable = false; + this.tgBotToken = ""; + this.tgBotChatId = ""; + this.tgRunTime = "@daily"; + this.tgBotBackup = false; + this.tgBotLoginNotify = false; + this.tgCpu = ""; + this.tgLang = ""; + this.subEnable = false; + this.subListen = ""; + this.subPort = "2096"; + this.subPath = "/sub/"; + this.subDomain = ""; + this.subCertFile = ""; + this.subKeyFile = ""; + this.subUpdates = 0; + this.subEncrypt = true; + this.subShowInfo = false; + this.subURI = ''; + + this.timeLocation = "Asia/Tehran"; + + if (data == null) { + return + } + ObjectUtil.cloneProps(this, data); + } + + equals(other) { + return ObjectUtil.equals(this, other); + } +} \ No newline at end of file diff --git a/web/assets/js/util/utils.js b/web/assets/js/util/utils.js index 781e13a8..9d6cb0d1 100644 --- a/web/assets/js/util/utils.js +++ b/web/assets/js/util/utils.js @@ -1,3 +1,21 @@ +class Msg { + constructor(success, msg, obj) { + this.success = false; + this.msg = ""; + this.obj = null; + + if (success != null) { + this.success = success; + } + if (msg != null) { + this.msg = msg; + } + if (obj != null) { + this.obj = obj; + } + } +} + class HttpUtil { static _handleMsg(msg) { if (!(msg instanceof Msg)) { -- cgit v1.2.3 From f7e439b9307357ebb53cc909d164cb4dab23dfc8 Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Tue, 5 Dec 2023 22:57:45 +0100 Subject: fix deep search null error --- web/assets/js/util/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/assets/js') diff --git a/web/assets/js/util/utils.js b/web/assets/js/util/utils.js index 9d6cb0d1..8bab58ec 100644 --- a/web/assets/js/util/utils.js +++ b/web/assets/js/util/utils.js @@ -176,7 +176,7 @@ class ObjectUtil { } } } else { - return obj.toString().toLowerCase().indexOf(key.toLowerCase()) >= 0; + return this.isEmpty(obj) ? false : obj.toString().toLowerCase().indexOf(key.toLowerCase()) >= 0; } return false; } -- cgit v1.2.3 From 549f230221d7139270efefd76ac81f37e1a747f9 Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Fri, 8 Dec 2023 16:46:44 +0100 Subject: optimize security in front codes #1300 --- web/assets/js/model/xray.js | 89 +++++---------------------------------------- 1 file changed, 10 insertions(+), 79 deletions(-) (limited to 'web/assets/js') diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index d183b882..0418540a 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -8,13 +8,6 @@ const Protocols = { HTTP: 'http', }; -const VmessMethods = { - AES_128_GCM: 'aes-128-gcm', - CHACHA20_POLY1305: 'chacha20-poly1305', - AUTO: 'auto', - NONE: 'none', -}; - const SSMethods = { AES_256_GCM: 'aes-256-gcm', AES_128_GCM: 'aes-128-gcm', @@ -91,7 +84,6 @@ const SNIFFING_OPTION = { }; Object.freeze(Protocols); -Object.freeze(VmessMethods); Object.freeze(SSMethods); Object.freeze(XTLS_FLOW_CONTROL); Object.freeze(TLS_FLOW_CONTROL); @@ -422,7 +414,7 @@ class HttpStreamSettings extends XrayCommonClass { } class QuicStreamSettings extends XrayCommonClass { - constructor(security=VmessMethods.NONE, + constructor(security='none', key=RandomUtil.randomSeq(10), type='none') { super(); this.security = security; @@ -1163,95 +1155,34 @@ class Inbound extends XrayCommonClass { } canEnableTls() { - switch (this.protocol) { - case Protocols.VMESS: - case Protocols.VLESS: - case Protocols.TROJAN: - break; - default: - return false; - } - - switch (this.network) { - case "tcp": - case "ws": - case "http": - case "quic": - case "grpc": - return true; - default: - return false; - } + if(![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false; + return ["tcp", "ws", "http", "quic", "grpc"].includes(this.network); } canEnableReality() { - switch (this.protocol) { - case Protocols.VLESS: - case Protocols.TROJAN: - break; - default: - return false; - } - switch (this.network) { - case "tcp": - case "http": - case "grpc": - return true; - default: - return false; - } + if(![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false; + return ["tcp", "http", "grpc"].includes(this.network); } //this is used for xtls-rprx-vision canEnableTlsFlow() { if (((this.stream.security === 'tls') || (this.stream.security === 'reality')) && (this.network === "tcp")) { - switch (this.protocol) { - case Protocols.VLESS: - return true; - default: - return false; - } + return this.protocol === Protocols.VLESS; } return false; } - canSetTls() { - return this.canEnableTls(); - } - canEnableXtls() { - switch (this.protocol) { - case Protocols.VLESS: - case Protocols.TROJAN: - break; - default: - return false; - } + if(![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false; return this.network === "tcp"; } canEnableStream() { - switch (this.protocol) { - case Protocols.VMESS: - case Protocols.VLESS: - case Protocols.TROJAN: - case Protocols.SHADOWSOCKS: - return true; - default: - return false; - } + return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol); } canSniffing() { - switch (this.protocol) { - case Protocols.VMESS: - case Protocols.VLESS: - case Protocols.TROJAN: - case Protocols.SHADOWSOCKS: - return true; - default: - return false; - } + return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol); } reset() { @@ -1691,7 +1622,7 @@ class Inbound extends XrayCommonClass { toJson() { let streamSettings; - if (this.canEnableStream() || this.protocol === Protocols.TROJAN) { + if (this.canEnableStream()) { streamSettings = this.stream.toJson(); } return { -- cgit v1.2.3 From 5fbf8f0d535b131ad6de22a0d1dda0f2167d5ee0 Mon Sep 17 00:00:00 2001 From: Alireza Ahmadi Date: Fri, 8 Dec 2023 18:45:21 +0100 Subject: Expand multiDomain to externalProxy #1300 --- web/assets/js/model/xray.js | 255 ++++++++++++++++++++++---------------------- 1 file changed, 126 insertions(+), 129 deletions(-) (limited to 'web/assets/js') diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index 0418540a..97110ae9 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -578,27 +578,21 @@ TlsStreamSettings.Cert = class extends XrayCommonClass { }; TlsStreamSettings.Settings = class extends XrayCommonClass { - constructor(allowInsecure = false, fingerprint = '', serverName = '', domains = []) { + constructor(allowInsecure = false, fingerprint = '') { super(); this.allowInsecure = allowInsecure; this.fingerprint = fingerprint; - this.serverName = serverName; - this.domains = domains; } static fromJson(json = {}) { return new TlsStreamSettings.Settings( json.allowInsecure, json.fingerprint, - json.serverName, - json.domains, ); } toJson() { return { allowInsecure: this.allowInsecure, fingerprint: this.fingerprint, - serverName: this.serverName, - domains: this.domains, }; } }; @@ -692,21 +686,18 @@ XtlsStreamSettings.Cert = class extends XrayCommonClass { }; XtlsStreamSettings.Settings = class extends XrayCommonClass { - constructor(allowInsecure = false, serverName = '') { + constructor(allowInsecure = false) { super(); this.allowInsecure = allowInsecure; - this.serverName = serverName; } static fromJson(json = {}) { return new XtlsStreamSettings.Settings( json.allowInsecure, - json.servername, ); } toJson() { return { allowInsecure: this.allowInsecure, - serverName: this.serverName, }; } }; @@ -773,18 +764,16 @@ class RealityStreamSettings extends XrayCommonClass { } RealityStreamSettings.Settings = class extends XrayCommonClass { - constructor(publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_FIREFOX, serverName = '', spiderX= '/') { + constructor(publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_FIREFOX, spiderX= '/') { super(); this.publicKey = publicKey; this.fingerprint = fingerprint; - this.serverName = serverName; this.spiderX = spiderX; } static fromJson(json = {}) { return new RealityStreamSettings.Settings( json.publicKey, json.fingerprint, - json.serverName, json.spiderX, ); } @@ -792,7 +781,6 @@ RealityStreamSettings.Settings = class extends XrayCommonClass { return { publicKey: this.publicKey, fingerprint: this.fingerprint, - serverName: this.serverName, spiderX: this.spiderX, }; } @@ -829,6 +817,7 @@ class SockoptStreamSettings extends XrayCommonClass { class StreamSettings extends XrayCommonClass { constructor(network='tcp', security='none', + externalProxy = [], tlsSettings=new TlsStreamSettings(), xtlsSettings=new XtlsStreamSettings(), realitySettings = new RealityStreamSettings(), @@ -843,6 +832,7 @@ class StreamSettings extends XrayCommonClass { super(); this.network = network; this.security = security; + this.externalProxy = externalProxy; this.tls = tlsSettings; this.xtls = xtlsSettings; this.reality = realitySettings; @@ -901,10 +891,10 @@ class StreamSettings extends XrayCommonClass { } static fromJson(json={}) { - return new StreamSettings( json.network, json.security, + json.externalProxy, TlsStreamSettings.fromJson(json.tlsSettings), XtlsStreamSettings.fromJson(json.xtlsSettings), RealityStreamSettings.fromJson(json.realitySettings), @@ -923,6 +913,7 @@ class StreamSettings extends XrayCommonClass { return { network: network, security: this.security, + externalProxy: this.externalProxy, tlsSettings: this.isTls ? this.tls.toJson() : undefined, xtlsSettings: this.isXtls ? this.xtls.toJson() : undefined, realitySettings: this.isReality ? this.reality.toJson() : undefined, @@ -982,6 +973,16 @@ class Inbound extends XrayCommonClass { 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; + } + } + get protocol() { return this._protocol; } @@ -1132,26 +1133,8 @@ class Inbound extends XrayCommonClass { } isExpiry(index) { - switch (this.protocol) { - case Protocols.VMESS: - if(this.settings.vmesses[index].expiryTime > 0) - return this.settings.vmesses[index].expiryTime < new Date().getTime(); - return false - case Protocols.VLESS: - if(this.settings.vlesses[index].expiryTime > 0) - return this.settings.vlesses[index].expiryTime < new Date().getTime(); - return false - case Protocols.TROJAN: - if(this.settings.trojans[index].expiryTime > 0) - return this.settings.trojans[index].expiryTime < new Date().getTime(); - return false - case Protocols.SHADOWSOCKS: - if(this.settings.shadowsockses.length > 0 && this.settings.shadowsockses[index].expiryTime > 0) - return this.settings.shadowsockses[index].expiryTime < new Date().getTime(); - return false - default: - return false; - } + let exp = this.clients[index].expiryTime; + return exp > 0 ? exp < new Date().getTime() : false; } canEnableTls() { @@ -1195,19 +1178,20 @@ class Inbound extends XrayCommonClass { this.sniffing = new Sniffing(); } - genVmessLink(address='', remark='', clientIndex=0) { + genVmessLink(address='', port=this.port, forceTls, remark='', clientId) { if (this.protocol !== Protocols.VMESS) { return ''; } + const security = forceTls == 'same' ? this.stream.security : forceTls; let obj = { v: '2', ps: remark, add: address, - port: this.port, - id: this.settings.vmesses[clientIndex].id, + port: port, + id: clientId, net: this.stream.network, type: 'none', - tls: this.stream.security, + tls: security, }; let network = this.stream.network; if (network === 'tcp') { @@ -1247,12 +1231,9 @@ class Inbound extends XrayCommonClass { } } - if (this.stream.security === 'tls') { - if (!ObjectUtil.isEmpty(this.stream.tls.server)) { - obj.add = this.stream.tls.server; - } - if (!ObjectUtil.isEmpty(this.stream.tls.settings.serverName)){ - obj.sni = this.stream.tls.settings.serverName; + if (security === 'tls') { + if (!ObjectUtil.isEmpty(this.stream.tls.sni)){ + obj.sni = this.stream.tls.server; } if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerpr