- Introduced `sync-env.sh` to automate the synchronization of environment variables from Bitwarden.
- Implemented authentication with Bitwarden CLI, including session management and error handling.
- Added functionality to fetch environment variables from Bitwarden items and create/update a `.env` file in the specified target directory.
- Included logging for debugging and operational transparency.
✅ This script enhances the management of environment variables by integrating with Bitwarden, ensuring secure and efficient updates.
233 lines
6.6 KiB
Bash
Executable File
233 lines
6.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# === Bitwarden .env Sync (Advanced) ===
|
|
|
|
# Configuration
|
|
TARGET_DIR=""
|
|
SESSION_FILE="$HOME/.bw-session"
|
|
DEBUG=false
|
|
|
|
# Parse arguments
|
|
for arg in "$@"; do
|
|
case $arg in
|
|
--debug)
|
|
DEBUG=true
|
|
;;
|
|
*)
|
|
# If not a flag, treat as target directory
|
|
if [[ -z "$TARGET_DIR" ]] && [[ "$arg" != --* ]]; then
|
|
TARGET_DIR="$arg"
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Set default target directory if not specified
|
|
if [[ -z "$TARGET_DIR" ]]; then
|
|
TARGET_DIR="$(pwd)"
|
|
fi
|
|
|
|
# Logging functions
|
|
log_info() {
|
|
echo "[INFO] $1"
|
|
}
|
|
|
|
log_debug() {
|
|
if [[ "$DEBUG" == "true" ]]; then
|
|
echo "[DEBUG] $1"
|
|
fi
|
|
}
|
|
|
|
log_error() {
|
|
echo "[ERROR] $1" >&2
|
|
}
|
|
|
|
# Check dependencies
|
|
check_dependencies() {
|
|
log_debug "Checking dependencies..."
|
|
|
|
if ! command -v bw &> /dev/null; then
|
|
log_error "Bitwarden CLI (bw) is not installed"
|
|
exit 1
|
|
fi
|
|
log_debug "bw found at: $(which bw)"
|
|
|
|
if ! command -v jq &> /dev/null; then
|
|
log_error "jq is not installed"
|
|
exit 1
|
|
fi
|
|
log_debug "jq found at: $(which jq)"
|
|
}
|
|
|
|
# Authenticate with Bitwarden
|
|
authenticate_bitwarden() {
|
|
log_debug "Starting Bitwarden authentication..."
|
|
|
|
# Check if we have a valid session
|
|
if [[ -f "$SESSION_FILE" ]]; then
|
|
log_debug "Session file found, loading session..."
|
|
export BW_SESSION=$(cat "$SESSION_FILE")
|
|
|
|
# Test if session is valid
|
|
if bw status --session "$BW_SESSION" 2>/dev/null | jq -e '.status == "unlocked"' &>/dev/null; then
|
|
log_debug "Session is valid and vault is unlocked"
|
|
return 0
|
|
else
|
|
log_debug "Session is invalid or vault is locked"
|
|
rm -f "$SESSION_FILE"
|
|
fi
|
|
else
|
|
log_debug "Session file does not exist"
|
|
fi
|
|
|
|
# Check login status
|
|
STATUS=$(bw status | jq -r '.status')
|
|
log_debug "Bitwarden status: $STATUS"
|
|
|
|
case "$STATUS" in
|
|
"unauthenticated")
|
|
log_info "Not logged in to Bitwarden. Please login:"
|
|
bw login
|
|
if [[ $? -ne 0 ]]; then
|
|
log_error "Login failed"
|
|
exit 1
|
|
fi
|
|
# After login, we need to unlock
|
|
STATUS="locked"
|
|
;;
|
|
esac
|
|
|
|
# Handle locked vault
|
|
if [[ "$STATUS" == "locked" ]]; then
|
|
log_info "Vault is locked. Unlocking..."
|
|
|
|
# Unlock and capture the session key
|
|
SESSION_OUTPUT=$(bw unlock --raw)
|
|
if [[ $? -ne 0 ]]; then
|
|
log_error "Failed to unlock vault"
|
|
exit 1
|
|
fi
|
|
|
|
# Save session to file and export
|
|
echo "$SESSION_OUTPUT" > "$SESSION_FILE"
|
|
export BW_SESSION="$SESSION_OUTPUT"
|
|
log_debug "Vault unlocked and session saved"
|
|
|
|
elif [[ "$STATUS" == "unlocked" ]]; then
|
|
# Vault is already unlocked but we don't have the session
|
|
log_info "Vault is already unlocked but session not found. Please unlock again:"
|
|
|
|
SESSION_OUTPUT=$(bw unlock --raw)
|
|
if [[ $? -ne 0 ]]; then
|
|
log_error "Failed to get session"
|
|
exit 1
|
|
fi
|
|
|
|
echo "$SESSION_OUTPUT" > "$SESSION_FILE"
|
|
export BW_SESSION="$SESSION_OUTPUT"
|
|
log_debug "Session retrieved and saved"
|
|
fi
|
|
|
|
# Final verification
|
|
if ! bw status --session "$BW_SESSION" 2>/dev/null | jq -e '.status == "unlocked"' &>/dev/null; then
|
|
log_error "Failed to authenticate with Bitwarden"
|
|
exit 1
|
|
fi
|
|
|
|
log_info "Successfully authenticated with Bitwarden"
|
|
}
|
|
|
|
# Sync environment variables
|
|
sync_env_vars() {
|
|
log_info "Starting .env sync to: $TARGET_DIR"
|
|
|
|
# Ensure BW_SESSION is set
|
|
if [[ -z "$BW_SESSION" ]]; then
|
|
log_error "No Bitwarden session available"
|
|
exit 1
|
|
fi
|
|
|
|
# Sync with Bitwarden to get latest data
|
|
log_info "Syncing with Bitwarden to get latest data..."
|
|
if bw sync --session "$BW_SESSION" &>/dev/null; then
|
|
log_debug "Successfully synced with Bitwarden"
|
|
else
|
|
log_error "Failed to sync with Bitwarden"
|
|
exit 1
|
|
fi
|
|
|
|
# Create .env file path
|
|
ENV_FILE="$TARGET_DIR/.env"
|
|
|
|
# Backup existing .env if it exists
|
|
if [[ -f "$ENV_FILE" ]]; then
|
|
cp "$ENV_FILE" "${ENV_FILE}.backup"
|
|
log_debug "Backed up existing .env to .env.backup"
|
|
fi
|
|
|
|
# Search for items with .env in notes or custom fields
|
|
# Adjust the search query based on how you store your env vars
|
|
log_info "Fetching environment variables from Bitwarden..."
|
|
|
|
# Example: Get a specific item by name (adjust based on your setup)
|
|
# You might want to search by folder, collection, or specific naming convention
|
|
ITEM_NAME="portfolio-env" # Adjust this to your item name
|
|
|
|
ITEM=$(bw get item "$ITEM_NAME" --session "$BW_SESSION" 2>/dev/null)
|
|
|
|
if [[ -z "$ITEM" ]]; then
|
|
log_error "Could not find item '$ITEM_NAME' in Bitwarden"
|
|
log_info "Make sure you have an item named '$ITEM_NAME' with your environment variables"
|
|
exit 1
|
|
fi
|
|
|
|
# Extract notes (assuming env vars are in notes field)
|
|
NOTES=$(echo "$ITEM" | jq -r '.notes // empty')
|
|
|
|
if [[ -z "$NOTES" ]]; then
|
|
# Try custom fields if notes are empty
|
|
log_debug "Notes empty, checking custom fields..."
|
|
|
|
# Extract all custom fields and format as KEY=VALUE
|
|
echo "$ITEM" | jq -r '.fields[]? | select(.type == 0) | "\(.name)=\(.value)"' > "$ENV_FILE"
|
|
|
|
if [[ ! -s "$ENV_FILE" ]]; then
|
|
log_error "No environment variables found in item '$ITEM_NAME'"
|
|
exit 1
|
|
fi
|
|
else
|
|
# Write notes directly to .env file
|
|
echo "$NOTES" > "$ENV_FILE"
|
|
fi
|
|
|
|
# Validate .env file
|
|
if [[ -f "$ENV_FILE" ]] && [[ -s "$ENV_FILE" ]]; then
|
|
log_info "Successfully created .env file at: $ENV_FILE"
|
|
log_debug "Environment variables written:"
|
|
if [[ "$DEBUG" == "true" ]]; then
|
|
# Show keys only, not values for security
|
|
grep -E '^[A-Z_]+=' "$ENV_FILE" | cut -d'=' -f1 | while read -r key; do
|
|
echo " - $key"
|
|
done
|
|
fi
|
|
else
|
|
log_error "Failed to create .env file or file is empty"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
log_info "=== Bitwarden .env Sync (Advanced) ==="
|
|
log_info "Target directory: $TARGET_DIR"
|
|
log_debug "Session file: $SESSION_FILE"
|
|
|
|
check_dependencies
|
|
authenticate_bitwarden
|
|
sync_env_vars
|
|
|
|
log_info "=== Sync completed successfully ==="
|
|
}
|
|
|
|
# Run main function
|
|
main |