diff --git a/install.sh b/install.sh index 919024f09..ee0bc2584 100644 --- a/install.sh +++ b/install.sh @@ -1368,6 +1368,13 @@ setup_fail2ban() { return 0 fi + # Scripts older than v3.4.0 have no setup-fail2ban and exit 0 from the + # usage banner, which would read as success here. + if ! grep -q '"setup-fail2ban")' /usr/bin/x-ui; then + echo -e "${yellow}This x-ui.sh predates 'x-ui setup-fail2ban'; skipping Fail2ban auto-setup.${plain}" + return 0 + fi + echo -e "${green}Setting up Fail2ban for the IP Limit feature...${plain}" if /usr/bin/x-ui setup-fail2ban; then echo -e "${green}Fail2ban setup complete.${plain}" @@ -1426,6 +1433,23 @@ resolve_latest_tag() { curl -Ls --retry 5 --retry-delay 3 --connect-timeout 15 --max-time 60 "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' } +# Older tags predate some of these files (x-ui.rc arrived in v2.8.4). Serving +# main's copy against an old binary is the mismatch this pinning exists to +# prevent, so probe before anything is stopped or removed and refuse the tag. +require_repo_files() { + local ref="$1" name status + shift + [[ "${ref}" == "main" ]] && return 0 + for name in "$@"; do + status=$(curl -sIL --retry 3 --connect-timeout 15 -o /dev/null -w '%{http_code}' "https://raw.githubusercontent.com/MHSanaei/3x-ui/${ref}/${name}") + if [[ "${status}" != "200" ]]; then + echo -e "${red}${name} is not available for ${ref} (HTTP ${status})${plain}" + echo -e "${red}Install a release that ships it, or 'dev' for the rolling build. Your existing installation has not been touched.${plain}" + exit 1 + fi + done +} + install_x-ui() { cd ${xui_folder%/x-ui}/ @@ -1478,9 +1502,20 @@ install_x-ui() { exit 1 fi fi + # x-ui.sh, x-ui.rc and the unit files must come from the same release as + # the binary; only the rolling dev build tracks main. + local script_ref="${tag_version}" + if [[ "${tag_version}" == "dev-latest" ]]; then + script_ref="main" + fi + # The unit files are only fetched when the release tarball lacks them, so + # they are checked at that point instead of here. + local required_files=("x-ui.sh") + [[ $release == "alpine" ]] && required_files+=("x-ui.rc") + require_repo_files "${script_ref}" "${required_files[@]}" local xui_script_temp="/usr/bin/x-ui-temp.$$" rm -f "${xui_script_temp}" - curl -fLRo "${xui_script_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh + curl -fLRo "${xui_script_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.sh" if [[ $? -ne 0 ]]; then rm -f "${xui_script_temp}" echo -e "${red}Failed to download x-ui.sh${plain}" @@ -1631,7 +1666,7 @@ install_x-ui() { if [[ $release == "alpine" ]]; then xui_rc_temp="/etc/init.d/x-ui.tmp.$$" rm -f "${xui_rc_temp}" - curl -fLRo "${xui_rc_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc + curl -fLRo "${xui_rc_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.rc" if [[ $? -ne 0 ]]; then rm -f "${xui_rc_temp}" echo -e "${red}Failed to download x-ui.rc${plain}" @@ -1696,18 +1731,18 @@ install_x-ui() { echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}" case "${release}" in ubuntu | debian | armbian) - service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian" + service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.debian" ;; arch | manjaro | parch) - service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch" + service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.arch" ;; *) - service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel" + service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.rhel" ;; esac if ! _install_xui_service_unit "$service_unit_url" "true"; then - echo -e "${red}Failed to install x-ui.service from GitHub${plain}" + echo -e "${red}Failed to install x-ui.service from GitHub (${script_ref}) -- the release tarball did not ship one either${plain}" exit 1 fi service_installed=true diff --git a/update.sh b/update.sh index e3945b0a8..e972d84b7 100755 --- a/update.sh +++ b/update.sh @@ -924,6 +924,13 @@ setup_fail2ban() { return 0 fi + # Scripts older than v3.4.0 have no setup-fail2ban and exit 0 from the + # usage banner, which would read as success here. + if ! grep -q '"setup-fail2ban")' /usr/bin/x-ui; then + echo -e "${yellow}This x-ui.sh predates 'x-ui setup-fail2ban'; skipping Fail2ban auto-setup.${plain}" + return 0 + fi + echo -e "${green}Setting up Fail2ban for the IP Limit feature...${plain}" if /usr/bin/x-ui setup-fail2ban; then echo -e "${green}Fail2ban setup complete.${plain}" @@ -967,6 +974,21 @@ _install_xui_service_unit() { return 0 } +# Older tags predate some of these files (x-ui.rc arrived in v2.8.4). Serving +# main's copy against an old binary is the mismatch this pinning exists to +# prevent, so probe before the old install is removed and refuse the tag. +require_repo_files() { + local ref="$1" name status + shift + [[ "${ref}" == "main" ]] && return 0 + for name in "$@"; do + status=$(${curl_bin} -sIL --retry 3 --connect-timeout 15 -o /dev/null -w '%{http_code}' "https://raw.githubusercontent.com/MHSanaei/3x-ui/${ref}/${name}") + if [[ "${status}" != "200" ]]; then + _fail "ERROR: ${name} is not available for ${ref} (HTTP ${status}). Update to a release that ships it, or to 'dev-latest'. The current installation is untouched." + fi + done +} + update_x-ui() { cd ${xui_folder%/x-ui}/ @@ -993,6 +1015,17 @@ update_x-ui() { fi fi echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..." + # x-ui.sh, x-ui.rc and the unit files must come from the same release as + # the binary; only the rolling dev build tracks main. + script_ref="${tag_version}" + if [[ "${tag_version}" == "dev-latest" ]]; then + script_ref="main" + fi + # The unit files are only fetched when the release tarball lacks them, so + # they are checked at that point instead of here. + local required_files=("x-ui.sh") + [[ $release == "alpine" ]] && required_files+=("x-ui.rc") + require_repo_files "${script_ref}" "${required_files[@]}" ${curl_bin} -fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2> /dev/null if [[ $? -ne 0 ]]; then _fail "ERROR: Failed to download x-ui, please be sure that your server can access GitHub" @@ -1086,7 +1119,7 @@ update_x-ui() { echo -e "${green}Downloading and installing x-ui.sh script...${plain}" local xui_script_temp="/usr/bin/x-ui-temp.$$" rm -f "${xui_script_temp}" - ${curl_bin} -fLRo "${xui_script_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh > /dev/null 2>&1 + ${curl_bin} -fLRo "${xui_script_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.sh" > /dev/null 2>&1 if [[ $? -ne 0 ]]; then rm -f "${xui_script_temp}" _fail "ERROR: Failed to download x-ui.sh script, please be sure that your server can access GitHub" @@ -1117,7 +1150,7 @@ update_x-ui() { echo -e "${green}Downloading and installing startup unit x-ui.rc...${plain}" xui_rc_temp="/etc/init.d/x-ui.tmp.$$" rm -f "${xui_rc_temp}" - ${curl_bin} -fLRo "${xui_rc_temp}" https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc > /dev/null 2>&1 + ${curl_bin} -fLRo "${xui_rc_temp}" "https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.rc" > /dev/null 2>&1 if [[ $? -ne 0 ]]; then rm -f "${xui_rc_temp}" _fail "ERROR: Failed to download startup unit x-ui.rc, please be sure that your server can access GitHub" @@ -1176,18 +1209,18 @@ update_x-ui() { echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}" case "${release}" in ubuntu | debian | armbian) - service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian" + service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.debian" ;; arch | manjaro | parch) - service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch" + service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.arch" ;; *) - service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel" + service_unit_url="https://raw.githubusercontent.com/MHSanaei/3x-ui/${script_ref}/x-ui.service.rhel" ;; esac if ! _install_xui_service_unit "$service_unit_url" "true"; then - echo -e "${red}Failed to install x-ui.service from GitHub${plain}" + echo -e "${red}Failed to install x-ui.service from GitHub (${script_ref}) -- the release tarball did not ship one either${plain}" exit 1 fi fi diff --git a/x-ui.sh b/x-ui.sh index 9dcf27c0a..e9d74a9a5 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -208,6 +208,19 @@ replace_xui_script() { return 0 } +# The menu must match the installed panel, so update it from that release's +# tag; fall back to main only when no script is published for the version. +installed_script_url() { + local ver + ver=$("${xui_folder}/x-ui" -v 2> /dev/null | tr -d '[:space:]') + if [[ "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && curl -fsIL -o /dev/null "https://raw.githubusercontent.com/MHSanaei/3x-ui/v${ver}/x-ui.sh"; then + echo "https://raw.githubusercontent.com/MHSanaei/3x-ui/v${ver}/x-ui.sh" + else + echo -e "${yellow}No x-ui.sh published for the installed version (${ver:-unknown}), using main${plain}" >&2 + echo "https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh" + fi +} + update_menu() { echo -e "${yellow}Updating Menu${plain}" confirm "This function will update the menu to the latest changes." "y" @@ -219,7 +232,7 @@ update_menu() { return 0 fi - if replace_xui_script "https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh" "false"; then + if replace_xui_script "$(installed_script_url)" "false"; then chmod +x ${xui_folder}/x-ui.sh echo -e "${green}Update successful. The panel has automatically restarted.${plain}" exit 0 @@ -836,7 +849,7 @@ enable_bbr() { } update_shell() { - if replace_xui_script "https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh" "true"; then + if replace_xui_script "$(installed_script_url)" "true"; then LOGI "Upgrade script succeeded, Please rerun the script" before_show_menu else