From b06151739f689d2da67d94cfb29b30e04f848ddd Mon Sep 17 00:00:00 2001 From: denshooter Date: Mon, 15 Sep 2025 23:42:52 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Add=20Bitwarden=20.env=20sync=20?= =?UTF-8?q?script=20for=20environment=20variable=20management?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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. --- sync-env.sh | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100755 sync-env.sh diff --git a/sync-env.sh b/sync-env.sh new file mode 100755 index 0000000..686adb2 --- /dev/null +++ b/sync-env.sh @@ -0,0 +1,233 @@ +#!/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 \ No newline at end of file