- lib/distro.sh: add DISTRO_CODENAME from VERSION_CODENAME; remove unused REPO_ADD_RPM variable; export DISTRO_CODENAME - stages/01-repos.sh: replace repeated '. /etc/os-release' subshell calls with $DISTRO_CODENAME in Docker and Tailscale repo lines - stages/00-envcheck.sh: combine four mkdir -p calls into one - stages/02-packages.sh: remove identical if/else branches in fd symlink block; both branches were the same command - stages/03-toolchains.sh: set NVM_DIR once before the if/else instead of twice; remove dead commented-out duplicate curl line - stages/04-shell.sh: capture $(date +%Y%m%d) into _bak_date once per backup and reuse in cp and warn to avoid redundant forks - stages/06-scripts.sh: split 'export VAR=$(cmd)' into assignment + export to correctly propagate errors under set -euo pipefail - stages/07-uv-projects.sh: remove unused has_package_json field (always false, never read); fix stage completion message 06 -> 07 - stages/08-systemd.sh: remove mempi-sync.timer (deploy, enable, header comment); deploy mempi-sync.service only - stages/09-desktop.sh: remove duplicate mkdir -p in COSMIC section; remove unused repo_url parameter from install_nerd_font() - stages/12-other-apps.sh: replace manual distro branch for Nextcloud with pkg_install_mapped - config/scripts/bw-load-ssh.sh: split 'export BW_SESSION=$(cat ...)' into assignment + export - config/systemd/mempi-sync.timer: delete file
101 lines
3.1 KiB
Bash
Executable File
101 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ===========================================================================
|
|
# bw-load-ssh.sh — Load SSH keys from Bitwarden into ssh-agent
|
|
# Reads SSH key items from Bitwarden vault and loads private keys into
|
|
# the running ssh-agent.
|
|
#
|
|
# Dependencies: bw (Bitwarden CLI), jq, ssh-agent running
|
|
# Usage:
|
|
# 1. First, authenticate: bw login
|
|
# 2. Unlock and save session: bw unlock --raw > ~/.config/Bitwarden\ CLI/.session
|
|
# 3. Run: ./bw-load-ssh.sh
|
|
# Or run automatically via bw-ssh-keys.service (systemd user service).
|
|
# ===========================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
CONFIG_DIR="${HOME}/.config/Bitwarden CLI"
|
|
SESSION_FILE="${CONFIG_DIR}/.session"
|
|
|
|
# Check session file exists
|
|
if [ ! -f "$SESSION_FILE" ]; then
|
|
echo "ERROR: Session file not found at $SESSION_FILE"
|
|
echo "Run: bw unlock --raw > '$SESSION_FILE' && chmod 600 '$SESSION_FILE'"
|
|
exit 1
|
|
fi
|
|
|
|
# Check ssh-agent is running (retry in case graphical session hasn't fully started)
|
|
# ssh-add -l exits 2 if agent not running, 1 if no identities (which is fine)
|
|
_ssh_retries=5
|
|
_ssh_waited=0
|
|
while [ $_ssh_waited -lt $_ssh_retries ]; do
|
|
_ssh_exit=0
|
|
ssh-add -l >/dev/null 2>&1 || _ssh_exit=$?
|
|
if [ $_ssh_exit -eq 2 ]; then
|
|
sleep 2
|
|
_ssh_waited=$((_ssh_waited + 1))
|
|
else
|
|
break
|
|
fi
|
|
done
|
|
if [ $_ssh_exit -eq 2 ]; then
|
|
echo "ERROR: ssh-agent is not running after ${_ssh_retries} attempts."
|
|
echo "Start it with: eval \$(ssh-agent)"
|
|
exit 1
|
|
fi
|
|
|
|
# Read session key
|
|
BW_SESSION=$(cat "$SESSION_FILE")
|
|
export BW_SESSION
|
|
|
|
# Verify session is still valid
|
|
if ! bw status 2>/dev/null | jq -e '.status == "unlocked"' >/dev/null 2>&1; then
|
|
echo "ERROR: Session is no longer valid (vault is locked or logged out)."
|
|
echo "Regenerate with: bw unlock --raw > '$SESSION_FILE' && chmod 600 '$SESSION_FILE'"
|
|
exit 1
|
|
fi
|
|
|
|
# Find all SSH key items
|
|
echo "Fetching SSH keys from vault..."
|
|
ITEMS=$(bw list items 2>/dev/null | jq -c '.[] | select(.type == 5)')
|
|
|
|
if [ -z "$ITEMS" ]; then
|
|
echo "No SSH keys found in vault."
|
|
exit 0
|
|
fi
|
|
|
|
LOADED=0
|
|
SKIPPED=0
|
|
|
|
# Use process substitution instead of pipe to avoid subshell and set -e issues
|
|
while IFS= read -r item; do
|
|
NAME=$(echo "$item" | jq -r '.name')
|
|
PUBLIC_KEY=$(echo "$item" | jq -r '.sshKey.publicKey // ""')
|
|
PRIVATE_KEY=$(echo "$item" | jq -r '.sshKey.privateKey // ""')
|
|
|
|
if [ -z "$PRIVATE_KEY" ]; then
|
|
echo " SKIP '$NAME' — no private key found"
|
|
continue
|
|
fi
|
|
|
|
# Extract comment from public key for checking if already loaded
|
|
COMMENT=$(echo "$PUBLIC_KEY" | awk '{print $3}' | tr -d '\n')
|
|
|
|
# Check if already loaded in ssh-agent
|
|
if [ -n "$COMMENT" ] && ssh-add -l 2>/dev/null | grep -q "$COMMENT"; then
|
|
echo " OK '$NAME' — already loaded"
|
|
SKIPPED=$((SKIPPED + 1))
|
|
continue
|
|
fi
|
|
|
|
# Load into ssh-agent
|
|
if echo "$PRIVATE_KEY" | ssh-add - 2>/dev/null; then
|
|
echo " LOAD '$NAME'"
|
|
LOADED=$((LOADED + 1))
|
|
else
|
|
echo " FAIL '$NAME'"
|
|
fi
|
|
done <<< "$ITEMS"
|
|
|
|
echo "Done. Loaded: $LOADED, Skipped (already loaded): $SKIPPED"
|