rbash_verify_upgrade() { local new_rbashrc="$1" local sig_file="$2" local key_file="$3" local gnupg_home key_fpr rc command -v gpg >/dev/null 2>&1 || { echo "gpg is required for rbash upgrade verification" return 1 } [ -n "${RBASH_SIGNING_FPR:-}" ] || { echo "RBASH_SIGNING_FPR is not set" echo "Refusing to upgrade without a pinned signing key fingerprint" return 1 } [ -f "$new_rbashrc" ] || { echo "missing rbashrc: $new_rbashrc" return 1 } [ -f "$sig_file" ] || { echo "missing signature: $sig_file" return 1 } [ -f "$key_file" ] || { echo "missing public key: $key_file" return 1 } gnupg_home="$(mktemp -d)" chmod 700 "$gnupg_home" GNUPGHOME="$gnupg_home" gpg --quiet --batch --import "$key_file" >/dev/null 2>&1 || { rc=$? rm -rf "$gnupg_home" echo "failed to import rbash signing key" return "$rc" } key_fpr="$( GNUPGHOME="$gnupg_home" gpg --with-colons --fingerprint 2>/dev/null | awk -F: '$1 == "fpr" { print $10; exit }' )" if [ "$key_fpr" != "$RBASH_SIGNING_FPR" ]; then rm -rf "$gnupg_home" echo "rbash signing key fingerprint mismatch" echo "expected: $RBASH_SIGNING_FPR" echo "got: ${key_fpr:-}" return 1 fi GNUPGHOME="$gnupg_home" gpg \ --quiet \ --batch \ --verify "$sig_file" "$new_rbashrc" >/dev/null 2>&1 rc=$? rm -rf "$gnupg_home" if [ "$rc" -ne 0 ]; then echo "rbash signature verification failed" return "$rc" fi return 0 } rbash-upgrade() { local target backup backup_suffix local tmp_dir tmp_rbashrc tmp_sig tmp_key local base_url rbashrc_url sig_url key_url local rc target="${__RBASH_SCRIPT:-$HOME/.bashrc}" base_url="$(rbash_url "dist")" rbashrc_url="$base_url/rbashrc" sig_url="$base_url/rbashrc.asc" key_url="$base_url/rbash-signing-key.asc" command -v gpg >/dev/null 2>&1 || { echo "gpg is required" return 1 } tmp_dir="$(mktemp -d)" tmp_rbashrc="$tmp_dir/rbashrc" tmp_sig="$tmp_dir/rbashrc.asc" tmp_key="$tmp_dir/rbash-signing-key.asc" __rbash_upgrade_cleanup() { rm -rf "$tmp_dir" } trap __rbash_upgrade_cleanup RETURN echo "Downloading rbashrc..." rbash_download "$rbashrc_url" > "$tmp_rbashrc" || return 1 echo "Downloading rbashrc signature..." rbash_download "$sig_url" > "$tmp_sig" || return 1 echo "Downloading rbash signing public key..." rbash_download "$key_url" > "$tmp_key" || return 1 echo "Verifying rbashrc signature..." rbash_verify_upgrade "$tmp_rbashrc" "$tmp_sig" "$tmp_key" || { echo "rbash upgrade aborted" return 1 } backup_suffix="$(date +%Y%m%d%H%M%S)" backup="$target.bak.$backup_suffix" echo "Updating $target" echo "Backup: $backup" if [ -f "$target" ]; then cp "$target" "$backup" || { echo "failed to create backup: $backup" return 1 } fi cp "$tmp_rbashrc" "$target" || { rc=$? echo "failed to install new rbashrc" if [ -f "$backup" ]; then echo "restoring backup" cp "$backup" "$target" || true fi return "$rc" } chmod 600 "$target" 2>/dev/null || true echo "rbash upgrade complete" }