penguin/utils

my env utils

bash/core/50_upgrade.bash

raw ยท 3049 bytes

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:-<none>}"
		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"
}