diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a4c654ea..48b5e5cb7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -183,13 +183,17 @@ jobs: cd ../.. - name: Package - run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui + run: | + tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui + sha256sum x-ui-linux-${{ matrix.platform }}.tar.gz > x-ui-linux-${{ matrix.platform }}.tar.gz.sha256 - name: Upload files to Artifacts uses: actions/upload-artifact@v7 with: name: x-ui-linux-${{ matrix.platform }} - path: ./x-ui-linux-${{ matrix.platform }}.tar.gz + path: | + ./x-ui-linux-${{ matrix.platform }}.tar.gz + ./x-ui-linux-${{ matrix.platform }}.tar.gz.sha256 - name: Upload files to GH release uses: svenstaro/upload-release-action@v2 @@ -197,8 +201,8 @@ jobs: with: repo_token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ github.ref_name }} - file: x-ui-linux-${{ matrix.platform }}.tar.gz - asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz + file: x-ui-linux-${{ matrix.platform }}.tar.gz* + file_glob: true overwrite: true prerelease: true @@ -316,12 +320,16 @@ jobs: shell: pwsh run: | Compress-Archive -Path .\x-ui -DestinationPath "x-ui-windows-amd64.zip" + $hash = (Get-FileHash x-ui-windows-amd64.zip -Algorithm SHA256).Hash.ToLower() + [IO.File]::WriteAllText("$PWD\x-ui-windows-amd64.zip.sha256", "$hash x-ui-windows-amd64.zip`n") - name: Upload files to Artifacts uses: actions/upload-artifact@v7 with: name: x-ui-windows-amd64 - path: ./x-ui-windows-amd64.zip + path: | + ./x-ui-windows-amd64.zip + ./x-ui-windows-amd64.zip.sha256 - name: Upload files to GH release uses: svenstaro/upload-release-action@v2 @@ -329,8 +337,8 @@ jobs: with: repo_token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ github.ref_name }} - file: x-ui-windows-amd64.zip - asset_name: x-ui-windows-amd64.zip + file: x-ui-windows-amd64.zip* + file_glob: true overwrite: true prerelease: true @@ -398,4 +406,4 @@ jobs: --target "${COMMIT}" --title "Dev build ${short}" --notes "${notes}" fi - retry gh release upload dev-latest dev-artifacts/*.tar.gz dev-artifacts/*.zip --clobber + retry gh release upload dev-latest dev-artifacts/*.tar.gz dev-artifacts/*.zip dev-artifacts/*.sha256 --clobber diff --git a/install.sh b/install.sh index ee0bc2584..a3c341f6a 100644 --- a/install.sh +++ b/install.sh @@ -1433,6 +1433,34 @@ 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/' } +# Releases publish .sha256 next to each archive. A mismatch or a failed +# sidecar download aborts the install; only a 404 (releases predating the +# sidecar) is tolerated with a warning. +verify_release_checksum() { + local url="$1" file="$2" sums="$2.sha256" code expected actual + rm -f "${sums}" + code=$(curl -sL --retry 3 --retry-delay 3 --connect-timeout 15 --max-time 60 -o "${sums}" -w '%{http_code}' "${url}.sha256") + if [[ "${code}" == "404" ]]; then + rm -f "${sums}" + echo -e "${yellow}No checksum published for this release, skipping verification${plain}" + return 0 + fi + if [[ "${code}" != "200" ]]; then + rm -f "${sums}" "${file}" + echo -e "${red}Failed to download the checksum for $(basename "${file}") (HTTP ${code})${plain}" + exit 1 + fi + expected=$(awk 'NR == 1 {print $1}' "${sums}") + actual=$(sha256sum "${file}" | awk '{print $1}') + rm -f "${sums}" + if [[ ! "${expected}" =~ ^[0-9a-f]{64}$ || "${expected}" != "${actual}" ]]; then + rm -f "${file}" + echo -e "${red}Checksum mismatch for $(basename "${file}"): expected ${expected:-}, got ${actual}${plain}" + exit 1 + fi + echo -e "${green}Checksum verified: ${actual}${plain}" +} + # 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. @@ -1471,6 +1499,7 @@ install_x-ui() { echo -e "${red}Downloaded x-ui release archive is empty${plain}" exit 1 fi + verify_release_checksum "https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz" "${xui_folder}-linux-$(arch).tar.gz" else tag_version=$1 # The rolling dev channel ships under a fixed, non-semver tag that is @@ -1501,6 +1530,7 @@ install_x-ui() { echo -e "${red}Downloaded x-ui release archive is empty${plain}" exit 1 fi + verify_release_checksum "${url}" "${xui_folder}-linux-$(arch).tar.gz" 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. diff --git a/update.sh b/update.sh index e972d84b7..a64a96317 100755 --- a/update.sh +++ b/update.sh @@ -1034,6 +1034,28 @@ update_x-ui() { rm ${xui_folder}-linux-$(arch).tar.gz -f > /dev/null 2>&1 _fail "ERROR: Downloaded x-ui release archive is empty, please be sure that your server can access GitHub" fi + # Releases publish .sha256 next to each archive. A mismatch or a + # failed sidecar download aborts the update; only a 404 (releases + # predating the sidecar) is tolerated with a warning. + archive="${xui_folder}-linux-$(arch).tar.gz" + rm -f "${archive}.sha256" + sidecar_code=$(${curl_bin} -sL --retry 3 --retry-delay 3 --connect-timeout 15 --max-time 60 -o "${archive}.sha256" -w '%{http_code}' "https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz.sha256" 2> /dev/null) + if [[ "${sidecar_code}" == "200" ]]; then + expected_sha256=$(awk 'NR == 1 {print $1}' "${archive}.sha256") + actual_sha256=$(sha256sum "${archive}" | awk '{print $1}') + rm -f "${archive}.sha256" + if [[ ! "${expected_sha256}" =~ ^[0-9a-f]{64}$ || "${expected_sha256}" != "${actual_sha256}" ]]; then + rm -f "${archive}" + _fail "ERROR: Checksum mismatch for $(basename "${archive}"): expected ${expected_sha256:-}, got ${actual_sha256}" + fi + echo -e "${green}Checksum verified: ${actual_sha256}${plain}" + elif [[ "${sidecar_code}" == "404" ]]; then + rm -f "${archive}.sha256" + echo -e "${yellow}No checksum published for this release, skipping verification${plain}" + else + rm -f "${archive}.sha256" "${archive}" + _fail "ERROR: Failed to download the checksum for x-ui-linux-$(arch).tar.gz (HTTP ${sidecar_code})" + fi if [[ -e ${xui_folder}/ ]]; then echo -e "${green}Stopping x-ui...${plain}"