From 2982d809ab4f5301a27b811509e7fb92f427673f Mon Sep 17 00:00:00 2001 From: mhsanaei Date: Wed, 13 Nov 2024 19:57:55 +0330 Subject: [PATCH 1/7] update - CF SSL Certificate --- x-ui.sh | 107 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/x-ui.sh b/x-ui.sh index 19f20aea..b99d801d 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -1116,76 +1116,113 @@ ssl_cert_issue() { } ssl_cert_issue_CF() { - echo -E "" - LOGD "******Instructions for use******" - LOGI "This Acme script requires the following data:" - LOGI "1.Cloudflare Registered e-mail" - LOGI "2.Cloudflare Global API Key" - LOGI "3.The domain name that has been resolved dns to the current server by Cloudflare" - LOGI "4.The script applies for a certificate. The default installation path is /root/cert " - confirm "Confirmed?[y/n]" "y" + local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') + local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') + LOGI "****** Instructions for Use ******" + LOGI "Follow the steps below to complete the process:" + LOGI "1. Cloudflare Registered E-mail." + LOGI "2. Cloudflare Global API Key." + LOGI "3. The Domain Name." + LOGI "4. Once the certificate is issued, you will be prompted to set the certificate for the panel (optional)." + LOGI "5. The script also supports automatic renewal of the SSL certificate after installation." + + confirm "Do you confirm the information and wish to proceed? [y/n]" "y" + if [ $? -eq 0 ]; then - # check for acme.sh first + # Check for acme.sh first if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then - echo "acme.sh could not be found. we will install it" + echo "acme.sh could not be found. We will install it." install_acme if [ $? -ne 0 ]; then - LOGE "install acme failed, please check logs" + LOGE "Install acme failed, please check logs." exit 1 fi fi + CF_Domain="" - CF_GlobalKey="" - CF_AccountEmail="" - certPath=/root/cert + certPath="/root/cert-CF" if [ ! -d "$certPath" ]; then - mkdir $certPath + mkdir -p $certPath else rm -rf $certPath - mkdir $certPath + mkdir -p $certPath fi + LOGD "Please set a domain name:" - read -p "Input your domain here:" CF_Domain - LOGD "Your domain name is set to:${CF_Domain}" + read -p "Input your domain here: " CF_Domain + LOGD "Your domain name is set to: ${CF_Domain}" + + # Set up Cloudflare API details + CF_GlobalKey="" + CF_AccountEmail="" LOGD "Please set the API key:" - read -p "Input your key here:" CF_GlobalKey - LOGD "Your API key is:${CF_GlobalKey}" + read -p "Input your key here: " CF_GlobalKey + LOGD "Your API key is: ${CF_GlobalKey}" + LOGD "Please set up registered email:" - read -p "Input your email here:" CF_AccountEmail - LOGD "Your registered email address is:${CF_AccountEmail}" + read -p "Input your email here: " CF_AccountEmail + LOGD "Your registered email address is: ${CF_AccountEmail}" + + # Set the default CA to Let's Encrypt ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt if [ $? -ne 0 ]; then - LOGE "Default CA, Lets'Encrypt fail, script exiting..." + LOGE "Default CA, Let'sEncrypt fail, script exiting..." exit 1 fi + export CF_Key="${CF_GlobalKey}" - export CF_Email=${CF_AccountEmail} + export CF_Email="${CF_AccountEmail}" + + # Issue the certificate using Cloudflare DNS ~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log if [ $? -ne 0 ]; then LOGE "Certificate issuance failed, script exiting..." exit 1 else - LOGI "Certificate issued Successfully, Installing..." + LOGI "Certificate issued successfully, Installing..." fi - ~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} --ca-file /root/cert/ca.cer \ - --cert-file /root/cert/${CF_Domain}.cer --key-file /root/cert/${CF_Domain}.key \ - --fullchain-file /root/cert/fullchain.cer + + # Install the certificate + ~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} \ + --cert-file ${certPath}/${CF_Domain}/fullchain.pem \ + --key-file ${certPath}/${CF_Domain}/privkey.pem + if [ $? -ne 0 ]; then LOGE "Certificate installation failed, script exiting..." exit 1 else - LOGI "Certificate installed Successfully,Turning on automatic updates..." + LOGI "Certificate installed successfully, Turning on automatic updates..." fi + + # Enable auto-update ~/.acme.sh/acme.sh --upgrade --auto-upgrade if [ $? -ne 0 ]; then - LOGE "Auto update setup Failed, script exiting..." - ls -lah cert - chmod 755 $certPath + LOGE "Auto update setup failed, script exiting..." exit 1 else - LOGI "The certificate is installed and auto-renewal is turned on, Specific information is as follows" - ls -lah cert - chmod 755 $certPath + LOGI "The certificate is installed and auto-renewal is turned on. Specific information is as follows:" + ls -lah ${certPath}/${CF_Domain} + chmod 755 ${certPath}/${CF_Domain} + fi + + # Prompt user to set panel paths after successful certificate installation + read -p "Would you like to set this certificate for the panel? (y/n): " setPanel + if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then + local webCertFile="${certPath}/${CF_Domain}/fullchain.pem" + local webKeyFile="${certPath}/${CF_Domain}/privkey.pem" + + if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then + /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" + LOGI "Panel paths set for domain: $CF_Domain" + LOGI " - Certificate File: $webCertFile" + LOGI " - Private Key File: $webKeyFile" + echo -e "${green}Access URL: https://${CF_Domain}:${existing_port}${existing_webBasePath}${plain}" + restart + else + LOGE "Error: Certificate or private key file not found for domain: $CF_Domain." + fi + else + LOGI "Skipping panel path setting." fi else show_menu From ccda652e69f5d613acca6346dda3c15fcb7ba36b Mon Sep 17 00:00:00 2001 From: mhsanaei Date: Thu, 14 Nov 2024 13:09:51 +0330 Subject: [PATCH 2/7] SplitHTTP - Mode --- sub/subService.go | 4 ++++ web/assets/js/model/inbound.js | 19 ++++++++++++++++-- web/assets/js/model/outbound.js | 20 ++++++++++++++++--- web/html/xui/form/outbound.html | 5 +++++ .../xui/form/stream/stream_splithttp.html | 6 ++++++ web/html/xui/inbound_info_modal.html | 8 ++++++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/sub/subService.go b/sub/subService.go index 2838e932..1659b98b 100644 --- a/sub/subService.go +++ b/sub/subService.go @@ -238,6 +238,7 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string { headers, _ := splithttp["headers"].(map[string]interface{}) obj["host"] = searchHost(headers) } + obj["mode"] = splithttp["mode"].(string) } security, _ := stream["security"].(string) obj["tls"] = security @@ -389,6 +390,7 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { headers, _ := splithttp["headers"].(map[string]interface{}) params["host"] = searchHost(headers) } + params["mode"] = splithttp["mode"].(string) } security, _ := stream["security"].(string) if security == "tls" { @@ -586,6 +588,7 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string headers, _ := splithttp["headers"].(map[string]interface{}) params["host"] = searchHost(headers) } + params["mode"] = splithttp["mode"].(string) } security, _ := stream["security"].(string) if security == "tls" { @@ -783,6 +786,7 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st headers, _ := splithttp["headers"].(map[string]interface{}) params["host"] = searchHost(headers) } + params["mode"] = splithttp["mode"].(string) } security, _ := stream["security"].(string) diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js index 41121b66..0e403fce 100644 --- a/web/assets/js/model/inbound.js +++ b/web/assets/js/model/inbound.js @@ -113,6 +113,12 @@ const USERS_SECURITY = { ZERO: "zero", }; +const MODE_OPTION = { + AUTO: "auto", + PACKET_UP: "packet-up", + STREAM_UP: "stream-up", +}; + Object.freeze(Protocols); Object.freeze(SSMethods); Object.freeze(TLS_FLOW_CONTROL); @@ -125,6 +131,7 @@ Object.freeze(USAGE_OPTION); Object.freeze(DOMAIN_STRATEGY_OPTION); Object.freeze(TCP_CONGESTION_OPTION); Object.freeze(USERS_SECURITY); +Object.freeze(MODE_OPTION); class XrayCommonClass { @@ -528,7 +535,8 @@ class SplitHTTPStreamSettings extends XrayCommonClass { maxConnections: 0, cMaxReuseTimes: "64-128", cMaxLifetimeMs: 0 - } + }, + mode = MODE_OPTION.AUTO, ) { super(); this.path = path; @@ -540,6 +548,7 @@ class SplitHTTPStreamSettings extends XrayCommonClass { this.noSSEHeader = noSSEHeader; this.xPaddingBytes = xPaddingBytes; this.xmux = xmux; + this.mode = mode; } addHeader(name, value) { @@ -561,6 +570,7 @@ class SplitHTTPStreamSettings extends XrayCommonClass { json.noSSEHeader, json.xPaddingBytes, json.xmux, + json.mode, ); } @@ -579,7 +589,8 @@ class SplitHTTPStreamSettings extends XrayCommonClass { maxConnections: this.xmux.maxConnections, cMaxReuseTimes: this.xmux.cMaxReuseTimes, cMaxLifetimeMs: this.xmux.cMaxLifetimeMs - } + }, + mode: this.mode, }; } } @@ -1329,6 +1340,7 @@ class Inbound extends XrayCommonClass { const splithttp = this.stream.splithttp; obj.path = splithttp.path; obj.host = splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host'); + obj.mode = splithttp.mode; } if (security === 'tls') { @@ -1401,6 +1413,7 @@ class Inbound extends XrayCommonClass { const splithttp = this.stream.splithttp; params.set("path", splithttp.path); params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host')); + params.set("mode", splithttp.mode); break; } @@ -1504,6 +1517,7 @@ class Inbound extends XrayCommonClass { const splithttp = this.stream.splithttp; params.set("path", splithttp.path); params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host')); + params.set("mode", splithttp.mode); break; } @@ -1586,6 +1600,7 @@ class Inbound extends XrayCommonClass { const splithttp = this.stream.splithttp; params.set("path", splithttp.path); params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host')); + params.set("mode", splithttp.mode); break; } diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index 78078dd6..35be85d8 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -77,6 +77,12 @@ const USERS_SECURITY = { ZERO: "zero", }; +const MODE_OPTION = { + AUTO: "auto", + PACKET_UP: "packet-up", + STREAM_UP: "stream-up", +}; + Object.freeze(Protocols); Object.freeze(SSMethods); Object.freeze(TLS_FLOW_CONTROL); @@ -85,6 +91,7 @@ Object.freeze(ALPN_OPTION); Object.freeze(OutboundDomainStrategies); Object.freeze(WireguardDomainStrategy); Object.freeze(USERS_SECURITY); +Object.freeze(MODE_OPTION); class CommonClass { @@ -320,16 +327,22 @@ class HttpUpgradeStreamSettings extends CommonClass { } class SplitHTTPStreamSettings extends CommonClass { - constructor(path = '/', host = '') { + constructor( + path = '/', + host = '', + mode = '', + ) { super(); this.path = path; this.host = host; + this.mode = mode; } static fromJson(json = {}) { return new SplitHTTPStreamSettings( json.path, json.host, + json.mode, ); } @@ -337,6 +350,7 @@ class SplitHTTPStreamSettings extends CommonClass { return { path: this.path, host: this.host, + mode: this.mode, }; } } @@ -710,7 +724,7 @@ class Outbound extends CommonClass { } else if (network === 'httpupgrade') { stream.httpupgrade = new HttpUpgradeStreamSettings(json.path, json.host); } else if (network === 'splithttp') { - stream.splithttp = new SplitHTTPStreamSettings(json.path, json.host); + stream.splithttp = new SplitHTTPStreamSettings(json.path, json.host, json.mode); } if (json.tls && json.tls == 'tls') { @@ -754,7 +768,7 @@ class Outbound extends CommonClass { } else if (type === 'httpupgrade') { stream.httpupgrade = new HttpUpgradeStreamSettings(path, host); } else if (type === 'splithttp') { - stream.splithttp = new SplitHTTPStreamSettings(path, host); + stream.splithttp = new SplitHTTPStreamSettings(path, host, mode); } if (security == 'tls') { diff --git a/web/html/xui/form/outbound.html b/web/html/xui/form/outbound.html index 2f5d8207..fde2f27c 100644 --- a/web/html/xui/form/outbound.html +++ b/web/html/xui/form/outbound.html @@ -380,6 +380,11 @@ + + + [[ key ]] + + diff --git a/web/html/xui/form/stream/stream_splithttp.html b/web/html/xui/form/stream/stream_splithttp.html index 957720e9..12cd3cac 100644 --- a/web/html/xui/form/stream/stream_splithttp.html +++ b/web/html/xui/form/stream/stream_splithttp.html @@ -22,6 +22,12 @@ + + + [[ key ]] + + diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/inbound_info_modal.html index 36f165c6..0e0a18fc 100644 --- a/web/html/xui/inbound_info_modal.html +++ b/web/html/xui/inbound_info_modal.html @@ -58,6 +58,14 @@ +