(url, dest, expectedChecksum string)
| 219 | } |
| 220 | |
| 221 | func downloadAndVerifyFile(url, dest, expectedChecksum string) error { |
| 222 | // Download to memory first to verify before writing to disk |
| 223 | resp, err := http.Get(url) |
| 224 | if err != nil { |
| 225 | return err |
| 226 | } |
| 227 | defer resp.Body.Close() |
| 228 | |
| 229 | if resp.StatusCode != http.StatusOK { |
| 230 | return fmt.Errorf("download returned status %d", resp.StatusCode) |
| 231 | } |
| 232 | |
| 233 | // Read the entire response body into memory and calculate checksum |
| 234 | body, err := io.ReadAll(resp.Body) |
| 235 | if err != nil { |
| 236 | return fmt.Errorf("error reading response: %v", err) |
| 237 | } |
| 238 | |
| 239 | // Verify checksum before proceeding |
| 240 | hasher := sha256.New() |
| 241 | hasher.Write(body) |
| 242 | actualChecksum := hex.EncodeToString(hasher.Sum(nil)) |
| 243 | if actualChecksum != expectedChecksum { |
| 244 | return fmt.Errorf("checksum verification failed (expected: %s, got: %s)", expectedChecksum, actualChecksum) |
| 245 | } |
| 246 | |
| 247 | // Create gzip reader from verified data |
| 248 | gzipReader, err := gzip.NewReader(bytes.NewReader(body)) |
| 249 | if err != nil { |
| 250 | return fmt.Errorf("error creating gzip reader: %v", err) |
| 251 | } |
| 252 | defer gzipReader.Close() |
| 253 | |
| 254 | // Create tar reader |
| 255 | tarReader := tar.NewReader(gzipReader) |
| 256 | |
| 257 | // Read the first (and should be only) file from the archive |
| 258 | _, err = tarReader.Next() |
| 259 | if err != nil { |
| 260 | return fmt.Errorf("error reading tar: %v", err) |
| 261 | } |
| 262 | |
| 263 | // Create output file |
| 264 | out, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) |
| 265 | if err != nil { |
| 266 | return err |
| 267 | } |
| 268 | defer out.Close() |
| 269 | |
| 270 | // Write the decompressed data to the file |
| 271 | if _, err := io.Copy(out, tarReader); err != nil { |
| 272 | return fmt.Errorf("error extracting file: %v", err) |
| 273 | } |
| 274 | |
| 275 | return nil |
| 276 | } |
| 277 | |
| 278 | func isNewer(latest, current string) bool { |
no test coverage detected