|
97 | 97 |
|
98 | 98 | # Check if sha256sum or shasum is available (for checksum verification) |
99 | 99 | HAS_CHECKSUM_TOOL=false |
100 | | -CHECKSUM_CMD="" |
| 100 | +CHECKSUM_CMD=() |
101 | 101 | if command -v sha256sum &> /dev/null; then |
102 | 102 | HAS_CHECKSUM_TOOL=true |
103 | | - CHECKSUM_CMD="sha256sum" |
| 103 | + CHECKSUM_CMD=(sha256sum) |
104 | 104 | elif command -v shasum &> /dev/null; then |
105 | 105 | HAS_CHECKSUM_TOOL=true |
106 | | - CHECKSUM_CMD="shasum -a 256" |
| 106 | + CHECKSUM_CMD=(shasum -a 256) |
107 | 107 | fi |
108 | 108 |
|
109 | 109 | if [ "$SKIP_CHECKSUM" = false ] && [ "$HAS_CHECKSUM_TOOL" = false ]; then |
110 | | - print_warning "Neither sha256sum nor shasum is available. Checksum verification will be skipped." |
111 | | - print_warning "To suppress this warning, use --skip-checksum flag." |
112 | | - SKIP_CHECKSUM=true |
| 110 | + print_error "Neither sha256sum nor shasum is available. Cannot verify binary integrity." |
| 111 | + print_info "Install sha256sum or shasum and retry." |
| 112 | + exit 1 |
113 | 113 | fi |
114 | 114 |
|
115 | 115 | # Determine OS and architecture |
|
527 | 527 | # Download and verify checksums if not skipped |
528 | 528 | if [ "$SKIP_CHECKSUM" = false ]; then |
529 | 529 | print_info "Downloading checksums file..." |
530 | | - CHECKSUMS_DOWNLOADED=false |
531 | | - |
532 | | - for attempt in $(seq 1 $MAX_RETRIES); do |
533 | | - if curl -L -f --connect-timeout 15 --max-time 60 -o "$CHECKSUMS_PATH" "$CHECKSUMS_URL" 2>/dev/null; then |
534 | | - CHECKSUMS_DOWNLOADED=true |
535 | | - print_success "Checksums file downloaded successfully" |
536 | | - break |
537 | | - else |
538 | | - if [ "$attempt" -eq "$MAX_RETRIES" ]; then |
539 | | - print_warning "Failed to download checksums file after $MAX_RETRIES attempts" |
540 | | - print_warning "Checksum verification will be skipped for this version." |
541 | | - print_info "This may occur for older releases that don't include checksums." |
542 | | - break |
543 | | - else |
| 530 | + download_checksums_with_retry() { |
| 531 | + local url="$1" |
| 532 | + for attempt in $(seq 1 $MAX_RETRIES); do |
| 533 | + if curl -L -f --connect-timeout 15 --max-time 60 -o "$CHECKSUMS_PATH" "$url" 2>/dev/null; then |
| 534 | + print_success "Checksums file downloaded successfully" |
| 535 | + return 0 |
| 536 | + fi |
| 537 | + if [ "$attempt" -lt "$MAX_RETRIES" ]; then |
544 | 538 | print_warning "Checksum download attempt $attempt failed. Retrying in 2s..." |
545 | 539 | sleep 2 |
546 | 540 | fi |
547 | | - fi |
548 | | - done |
549 | | - |
550 | | - # Verify checksum if we downloaded it successfully |
551 | | - if [ "$CHECKSUMS_DOWNLOADED" = true ]; then |
552 | | - print_info "Verifying binary checksum..." |
553 | | - |
554 | | - # Determine the expected filename in the checksums file |
555 | | - EXPECTED_FILENAME="$PLATFORM" |
556 | | - if [ "$OS_NAME" = "windows" ]; then |
557 | | - EXPECTED_FILENAME="${PLATFORM}.exe" |
558 | | - fi |
559 | | - |
560 | | - # Extract the expected checksum from the checksums file (exact filename match on field 2) |
561 | | - EXPECTED_CHECKSUM=$(awk -v f="$EXPECTED_FILENAME" '$2 == f {print $1}' "$CHECKSUMS_PATH") |
562 | | - |
563 | | - if [ -z "$EXPECTED_CHECKSUM" ]; then |
564 | | - print_warning "Checksum for $EXPECTED_FILENAME not found in checksums file" |
565 | | - print_warning "Checksum verification will be skipped." |
566 | | - else |
567 | | - # Compute the actual checksum of the downloaded binary |
568 | | - ACTUAL_CHECKSUM=$($CHECKSUM_CMD "$STAGED_BINARY_PATH" | awk '{print $1}') |
569 | | - |
570 | | - if [ "$ACTUAL_CHECKSUM" = "$EXPECTED_CHECKSUM" ]; then |
571 | | - print_success "Checksum verification passed!" |
572 | | - print_info "Expected: $EXPECTED_CHECKSUM" |
573 | | - print_info "Actual: $ACTUAL_CHECKSUM" |
| 541 | + done |
| 542 | + return 1 |
| 543 | + } |
| 544 | + |
| 545 | + if ! download_checksums_with_retry "$CHECKSUMS_URL"; then |
| 546 | + if [ -n "$FALLBACK_CHECKSUMS_URL" ] && [ "$CHECKSUMS_URL" != "$FALLBACK_CHECKSUMS_URL" ]; then |
| 547 | + print_warning "Failed to download checksums from latest redirect URL. Retrying with resolved tag URL ($LATEST_TAG)." |
| 548 | + CHECKSUMS_URL="$FALLBACK_CHECKSUMS_URL" |
| 549 | + if download_checksums_with_retry "$CHECKSUMS_URL"; then |
| 550 | + CHECKSUMS_DOWNLOADED=true |
574 | 551 | else |
575 | | - print_error "Checksum verification failed!" |
576 | | - print_error "Expected: $EXPECTED_CHECKSUM" |
577 | | - print_error "Actual: $ACTUAL_CHECKSUM" |
578 | | - print_error "The downloaded binary may be corrupted or tampered with." |
579 | | - print_info "To skip checksum verification, use: ./install-gh-aw.sh $VERSION --skip-checksum" |
580 | | - exit 1 |
| 552 | + CHECKSUMS_DOWNLOADED=false |
581 | 553 | fi |
| 554 | + else |
| 555 | + CHECKSUMS_DOWNLOADED=false |
| 556 | + fi |
| 557 | + if [ "$CHECKSUMS_DOWNLOADED" = false ]; then |
| 558 | + print_error "Failed to download checksums file after $MAX_RETRIES attempts" |
| 559 | + print_error "Cannot verify binary integrity. Installation aborted." |
| 560 | + print_info "Check that $CHECKSUMS_URL is available and retry." |
| 561 | + print_info "For older releases without checksums.txt, prefer a release with checksums or explicitly use --skip-checksum (disables integrity verification; corrupted or tampered binaries may be executed)." |
| 562 | + exit 1 |
582 | 563 | fi |
583 | | - |
584 | | - # Clean up checksums file |
585 | | - rm -f "$CHECKSUMS_PATH" |
586 | 564 | fi |
| 565 | + |
| 566 | + print_info "Verifying binary checksum..." |
| 567 | + |
| 568 | + EXPECTED_FILENAME="$PLATFORM" |
| 569 | + if [ "$OS_NAME" = "windows" ]; then |
| 570 | + EXPECTED_FILENAME="${PLATFORM}.exe" |
| 571 | + fi |
| 572 | + |
| 573 | + # Require exactly one well-formed SHA256 entry for the exact release asset. |
| 574 | + if ! EXPECTED_CHECKSUM=$(awk -v f="$EXPECTED_FILENAME" ' |
| 575 | + $2 == f { |
| 576 | + count++ |
| 577 | + if (NF != 2 || length($1) != 64 || $1 !~ /^[0-9a-fA-F]+$/) { |
| 578 | + invalid = 1 |
| 579 | + } |
| 580 | + checksum = tolower($1) |
| 581 | + } |
| 582 | + END { |
| 583 | + if (count != 1 || invalid) { |
| 584 | + exit 1 |
| 585 | + } |
| 586 | + print checksum |
| 587 | + } |
| 588 | + ' "$CHECKSUMS_PATH"); then |
| 589 | + print_error "Missing or malformed checksum for $EXPECTED_FILENAME in checksums file." |
| 590 | + print_error "Cannot verify binary integrity. Installation aborted." |
| 591 | + print_info "Use a release with exactly one valid SHA256 checksum for $EXPECTED_FILENAME." |
| 592 | + exit 1 |
| 593 | + fi |
| 594 | + |
| 595 | + if ! CHECKSUM_OUTPUT=$("${CHECKSUM_CMD[@]}" "$STAGED_BINARY_PATH"); then |
| 596 | + print_error "Failed to compute binary checksum. Installation aborted." |
| 597 | + exit 1 |
| 598 | + fi |
| 599 | + ACTUAL_CHECKSUM=$(printf '%s\n' "$CHECKSUM_OUTPUT" | awk '{print tolower($1)}') |
| 600 | + |
| 601 | + if [[ "$ACTUAL_CHECKSUM" =~ ^[0-9a-f]{64}$ ]] && [ "$ACTUAL_CHECKSUM" = "$EXPECTED_CHECKSUM" ]; then |
| 602 | + print_success "Checksum verification passed!" |
| 603 | + print_info "Expected: $EXPECTED_CHECKSUM" |
| 604 | + print_info "Actual: $ACTUAL_CHECKSUM" |
| 605 | + else |
| 606 | + print_error "Checksum verification failed!" |
| 607 | + print_error "Expected: $EXPECTED_CHECKSUM" |
| 608 | + print_error "Actual: $ACTUAL_CHECKSUM" |
| 609 | + print_error "The downloaded binary may be corrupted or tampered with. Installation aborted." |
| 610 | + exit 1 |
| 611 | + fi |
| 612 | + |
| 613 | + rm -f "$CHECKSUMS_PATH" |
587 | 614 | else |
588 | 615 | print_warning "Checksum verification skipped (--skip-checksum flag used)" |
589 | 616 | fi |
|
0 commit comments