blob: bc0918b21463886d0be6c894f7ed24916035a228 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#!/usr/bin/env bash
2# Script to perform verified file downloads.
3# Exit codes:
4# 0 - File downloaded successfully and verified
5# 1 - Failed to download requested file
6# 2 - Failed to download sha256sums file
7# 3 - Failed to download sha256sums.gpg file
8# 4 - GnuPG is available but fails to verify the signature (missing pubkey, file integrity error, ...)
9# 5 - The checksums do not match
10# 6 - Unable to copy the requested file to its final destination
11# 254 - The script got interrupted by a signal
12# 255 - A suitable download or checksum utility is missing
13
14[ -n "$1" ] || {
15 echo "$0 - Download and verify build artifacts"
16 echo "Usage: $0 <url>" >&2
17 exit 1
18}
19
20finish() {
21 [ -e "/tmp/verify.$$" ] && {
22 echo "Cleaning up."
23 rm -r "/tmp/verify.$$"
24 }
25 exit "$1"
26}
27
28trap "finish 254" INT TERM
29
30destdir="$(pwd)"
31image_url="$1"
32image_file="${image_url##*/}"
33sha256_url="${image_url%/*}/sha256sums"
34gpgsig_url="${image_url%/*}/sha256sums.asc"
35keyserver_url="hkp://keyserver.ubuntu.com"
36
37# Find a suitable download utility
38if which curl >/dev/null; then
39 download() { curl --progress-bar -o "$1" "$2"; }
40elif which wget >/dev/null; then
41 download() { wget -O "$1" "$2"; }
42elif which fetch >/dev/null; then
43 download() { fetch -o "$1" "$2"; }
44else
45 echo "No suitable download utility found, cannot download files!" >&2
46 finish 255
47fi
48
49# Find a suitable checksum utility
50if which sha256sum >/dev/null; then
51 checksum() { sha256sum -c --ignore-missing "sha256sums"; }
52elif which shasum >/dev/null; then
53 checksum() {
54 local sum
55 sum="$(shasum -a 256 "$image_file")";
56 grep -xF "${sum%% *} *$image_file" "sha256sums";
57 }
58else
59 echo "No SHA256 checksum executable installed, cannot verify checksums!" >&2
60 finish 255
61fi
62
63# Check for gpg availability
64if which gpg >/dev/null; then
65 runpgp() { gpg "$@"; }
66else
67 runpgp() {
68 echo "WARNING: No GnuPG installed, cannot verify digital signature!" >&2
69 return 0
70 }
71fi
72
73tmpdir="$(mktemp -d)"
74cd "$tmpdir" || {
75 echo "Failed to create temporary directory!" >&2
76 finish 255
77}
78
79echo ""
80echo "1) Downloading artifact file"
81echo "========================="
82download "$image_file" "$image_url" || {
83 echo "Failed to download image file!" >&2
84 finish 1
85}
86
87echo ""
88echo "2) Downloading checksum file"
89echo "============================"
90download "sha256sums" "$sha256_url" || {
91 echo "Failed to download checksum file!" >&2
92 finish 2
93}
94
95echo ""
96echo "3) Downloading the GPG signature"
97echo "================================"
98download "sha256sums.gpg" "$gpgsig_url" || {
99 echo "Failed to download GPG signature!" >&2
100 finish 3
101}
102
103echo ""
104echo "4) Verifying GPG signature"
105echo "=========================="
106missing_key=$(runpgp --status-fd 1 --with-fingerprint --verify \
107 "sha256sums.gpg" "sha256sums" 2>/dev/null | sed -ne 's!^.* NO_PUBKEY !!p')
108
109if [ -n "$missing_key" ]; then
110 echo "The signature was signed by a public key with the id $missing_key" >&2
111 echo "which is not present on this system." >&2
112 echo "" >&2
113
114 echo "Provide a public keyserver url below or press enter to accept the" >&2
115 echo "default suggestion. Hit Ctrl-C to abort the operation." >&2
116 echo "" >&2
117
118 while true; do
119 printf 'Keyserver to use? [%s] > ' "$keyserver_url"
120 read -r url; case "${url:-$keyserver_url}" in
121 hkp://*)
122 gpg --keyserver "${url:-$keyserver_url}" --recv-keys "$missing_key" || {
123 echo "Failed to download public key." >&2
124 finish 7
125 }
126 break
127 ;;
128 *)
129 echo "Expecting a key server url in the form 'hkp://hostname'." >&2
130 ;;
131 esac
132 done
133fi
134
135runpgp --with-fingerprint --verify "sha256sums.gpg" "sha256sums" || {
136 echo "Failed to verify checksum file with GPG signature!" >&2
137 finish 4
138}
139
140echo ""
141echo "5) Verifying SHA256 checksum"
142echo "============================"
143checksum || {
144 echo "Checksums do not match!" >&2
145 finish 5
146}
147
148cp "$image_file" "$destdir/$image_file" || {
149 echo "Failed to write '$destdir/$image_file'" >&2
150 finish 6
151}
152
153echo ""
154echo "Verification done!"
155echo "=================="
156echo "Downloaded artifact placed in '$destdir/$image_file'."
157echo ""
158
159finish 0