From c2e9ee36658a8549251df7fb37467baa55341a5f Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 18 Jul 2023 03:19:01 +0330 Subject: update - shadowsocks Co-Authored-By: Alireza Ahmadi --- web/assets/js/model/xray.js | 78 ++++++++++++++++++++++++++--- web/html/common/qrcode_modal.html | 2 +- web/html/xui/form/protocol/shadowsocks.html | 4 +- web/html/xui/inbound_info_modal.html | 15 +++++- web/html/xui/inbound_modal.html | 23 ++++----- web/html/xui/inbounds.html | 15 ++++-- 6 files changed, 112 insertions(+), 25 deletions(-) (limited to 'web') diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index 64931758..fe46e85f 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -16,8 +16,12 @@ const VmessMethods = { }; const SSMethods = { - BLAKE3_AES_128_GCM: '2022-blake3-aes-128-gcm', - BLAKE3_AES_256_GCM: '2022-blake3-aes-256-gcm', + CHACHA20_POLY1305: 'chacha20-poly1305', + AES_256_GCM: 'aes-256-gcm', + AES_128_GCM: 'aes-128-gcm', + 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 XTLS_FLOW_CONTROL = { @@ -511,7 +515,8 @@ class TlsStreamSettings extends XrayCommonClass { } if (!ObjectUtil.isEmpty(json.settings)) { - settings = new TlsStreamSettings.Settings(json.settings.allowInsecure , json.settings.fingerprint, json.settings.serverName, json.settings.domains); } + settings = new TlsStreamSettings.Settings(json.settings.allowInsecure , json.settings.fingerprint, json.settings.serverName, json.settings.domains); + } return new TlsStreamSettings( json.serverName, json.minVersion, @@ -980,7 +985,6 @@ class Inbound extends XrayCommonClass { } } - //for Reality get reality() { return this.stream.security === 'reality'; } @@ -1034,6 +1038,9 @@ class Inbound extends XrayCommonClass { return ""; } } + get isSSMultiUser() { + return [SSMethods.BLAKE3_AES_128_GCM,SSMethods.BLAKE3_AES_256_GCM].includes(this.method); + } get serverName() { if (this.stream.isTls || this.stream.isXtls || this.stream.isReality) { @@ -1103,7 +1110,7 @@ class Inbound extends XrayCommonClass { return this.settings.trojans[index].expiryTime < new Date().getTime(); return false case Protocols.SHADOWSOCKS: - if(this.settings.shadowsockses[index].expiryTime > 0) + if(this.settings.shadowsockses.length > 0 && this.settings.shadowsockses[index].expiryTime > 0) return this.settings.shadowsockses[index].expiryTime < new Date().getTime(); return false default: @@ -1184,6 +1191,7 @@ class Inbound extends XrayCommonClass { case Protocols.VMESS: case Protocols.VLESS: case Protocols.TROJAN: + case Protocols.SHADOWSOCKS: return true; default: return false; @@ -1410,8 +1418,66 @@ class Inbound extends XrayCommonClass { genSSLink(address='', remark='', clientIndex = 0) { let settings = this.settings; const port = this.port; + const type = this.stream.network; + 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; + params.set("headerType", kcp.type); + params.set("seed", kcp.seed); + break; + case "ws": + const ws = this.stream.ws; + params.set("path", ws.path); + const index = ws.headers.findIndex(header => header.name.toLowerCase() === 'host'); + if (index >= 0) { + const host = ws.headers[index].value; + params.set("host", host); + } + break; + case "http": + const http = this.stream.http; + params.set("path", http.path); + params.set("host", http.host); + break; + case "quic": + const quic = this.stream.quic; + params.set("quicSecurity", quic.security); + params.set("key", quic.key); + params.set("headerType", quic.type); + break; + case "grpc": + const grpc = this.stream.grpc; + params.set("serviceName", grpc.serviceName); + if(grpc.multiMode){ + params.set("mode", "multi"); + } + break; + } - return 'ss://' + safeBase64(settings.method + ':' + settings.password + ':' +settings.shadowsockses[clientIndex].password) + '@' + address + ':' + this.port + '#' + encodeURIComponent(remark); + let clientPassword = this.isSSMultiUser ? ':' + settings.shadowsockses[clientIndex].password : ''; + + let link = `ss://${safeBase64(settings.method + ':' + settings.password + clientPassword)}@${address}:${this.port}`; + const url = new URL(link); + for (const [key, value] of params) { + url.searchParams.set(key, value) + } + url.hash = encodeURIComponent(remark); + return url.toString(); } genTrojanLink(address = '', remark = '', clientIndex = 0) { diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index 8edfa2de..12dd2060 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/common/qrcode_modal.html @@ -37,7 +37,7 @@ this.inbound = dbInbound.toInbound(); settings = JSON.parse(this.inbound.settings); this.client = settings.clients[clientIndex]; - remark = this.dbInbound.remark + "-" + this.client.email; + remark = this.dbInbound.remark + ( this.client ? "-" + this.client.email : ''); address = this.dbInbound.address; this.subId = ''; this.qrcodes = []; diff --git a/web/html/xui/form/protocol/shadowsocks.html b/web/html/xui/form/protocol/shadowsocks.html index 7af96373..8e16b143 100644 --- a/web/html/xui/form/protocol/shadowsocks.html +++ b/web/html/xui/form/protocol/shadowsocks.html @@ -1,5 +1,6 @@ {{define "form/shadowsocks"}} + - + [[ method ]] diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/inbound_info_modal.html index 00cb5ce6..fae058ad 100644 --- a/web/html/xui/inbound_info_modal.html +++ b/web/html/xui/inbound_info_modal.html @@ -179,6 +179,19 @@ [[ inbound.settings.network ]] + @@ -251,7 +264,7 @@ this.clientSettings = this.settings.clients ? Object.values(this.settings.clients)[index] : null; this.isExpired = this.inbound.isExpiry(index); this.clientStats = this.settings.clients ? this.dbInbound.clientStats.find(row => row.email === this.clientSettings.email) : []; - remark = this.dbInbound.remark + "-" + this.clientSettings.email; + remark = this.dbInbound.remark + ( this.clientSettings ? "-" + this.clientSettings.email : ''); address = this.dbInbound.address; this.links = []; if (this.inbound.tls && !ObjectUtil.isArrEmpty(this.inbound.stream.tls.settings.domains)) { diff --git a/web/html/xui/inbound_modal.html b/web/html/xui/inbound_modal.html index 60244be4..65988b14 100644 --- a/web/html/xui/inbound_modal.html +++ b/web/html/xui/inbound_modal.html @@ -54,23 +54,11 @@ }, }; - const protocols = { - VMESS: Protocols.VMESS, - VLESS: Protocols.VLESS, - TROJAN: Protocols.TROJAN, - SHADOWSOCKS: Protocols.SHADOWSOCKS, - DOKODEMO: Protocols.DOKODEMO, - SOCKS: Protocols.SOCKS, - HTTP: Protocols.HTTP, - }; - new Vue({ delimiters: ['[[', ']]'], el: '#inbound-modal', data: { inModal: inModal, - Protocols: protocols, - SSMethods: SSMethods, delayedStart: false, get inbound() { return inModal.inbound; @@ -117,6 +105,17 @@ }); } }, + SSMethodChange() { + if (this.inModal.inbound.isSSMultiUser) { + if (this.inModal.inbound.settings.shadowsockses.length ==0){ + this.inModal.inbound.settings.shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()]; + } + } else { + if (this.inModal.inbound.settings.shadowsockses.length > 0){ + this.inModal.inbound.settings.shadowsockses = []; + } + } + }, setDefaultCertData(index) { inModal.inbound.stream.tls.certs[index].certFile = app.defaultCert; inModal.inbound.stream.tls.certs[index].keyFile = app.defaultKey; diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html index 193c080b..39c64aff 100644 --- a/web/html/xui/inbounds.html +++ b/web/html/xui/inbounds.html @@ -131,7 +131,11 @@ {{ i18n "edit" }} -
{{ i18n "pages.inbounds.targetAddress" }}