#!/usr/bin/env bash set -euo pipefail # scripts/generate_env.sh # Interactive generator for .env from .env.example # Usage: ./scripts/generate_env.sh [--yes] [--production] BASE_DIR="$(cd "$(dirname "$0")/.." && pwd)" EXAMPLE="$BASE_DIR/.env.example" TARGET="$BASE_DIR/.env" confirm=false production=false # Parse arguments for arg in "$@"; do case $arg in --yes) confirm=true ;; --production) production=true ;; *) echo "Usage: $0 [--yes] [--production]" echo " --yes Non-interactive mode, use defaults or environment variables" echo " --production Setup for production environment" exit 1 ;; esac done if [[ ! -f "$EXAMPLE" ]]; then echo "Error: .env.example not found at $EXAMPLE" exit 1 fi echo "🔧 Generating $TARGET from $EXAMPLE" if [[ -f "$TARGET" && "$confirm" = false ]]; then read -p "$TARGET exists. Overwrite? (y/N): " ans case "$ans" in [Yy]*) ;; *) echo "Aborted"; exit 0;; esac fi # Function to generate secure passwords generate_password() { openssl rand -base64 32 | tr -d "=+/" | cut -c1-25 } # Function to generate Django secret key generate_secret_key() { python3 -c " from django.core.management.utils import get_random_secret_key print(get_random_secret_key()) " 2>/dev/null || openssl rand -base64 50 | tr -d "=+/" } # Function to safely update env variable update_env_var() { local key="$1" local value="$2" local file="$3" # Remove existing line and add new one grep -v "^${key}=" "$file" > "${file}.tmp" 2>/dev/null || true echo "${key}=${value}" >> "${file}.tmp" mv "${file}.tmp" "$file" } # Copy example first cp "$EXAMPLE" "$TARGET" # Production mode adjustments if [[ "$production" = true ]]; then echo "🚀 Setting up for production environment..." # Generate secure values SECRET_KEY=$(generate_secret_key) DB_PASSWORD=$(generate_password) # Set production values update_env_var "DJANGO_SECRET_KEY" "$SECRET_KEY" "$TARGET" update_env_var "DJANGO_DEBUG" "False" "$TARGET" update_env_var "DATABASE_PASSWORD" "$DB_PASSWORD" "$TARGET" update_env_var "POSTGRES_PASSWORD" "$DB_PASSWORD" "$TARGET" update_env_var "DJANGO_SECURE_SSL_REDIRECT" "True" "$TARGET" update_env_var "DJANGO_SECURE_HSTS_SECONDS" "31536000" "$TARGET" update_env_var "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS" "True" "$TARGET" update_env_var "DJANGO_SECURE_HSTS_PRELOAD" "True" "$TARGET" # Prompt for domain if [[ "$confirm" = false ]]; then read -p "Enter your domain (e.g., example.com): " domain read -p "Enter your email for SSL certificate: " email if [[ -n "$domain" ]]; then update_env_var "DOMAIN" "$domain" "$TARGET" update_env_var "DJANGO_ALLOWED_HOSTS" "${domain},localhost,127.0.0.1" "$TARGET" update_env_var "DJANGO_CSRF_TRUSTED_ORIGINS" "https://${domain}" "$TARGET" update_env_var "CORS_ALLOWED_ORIGINS" "https://${domain}" "$TARGET" update_env_var "NEXT_PUBLIC_API_URL" "https://${domain}" "$TARGET" fi if [[ -n "$email" ]]; then update_env_var "EMAIL" "$email" "$TARGET" fi fi echo "✅ Production configuration generated with secure passwords" echo "📝 Database password: $DB_PASSWORD" echo "⚠️ Save this password securely!" fi # For each variable in example, prompt the user to keep or change while IFS= read -r line; do if [[ "$line" =~ ^# ]] || [[ -z "$line" ]]; then continue fi key=$(echo "$line" | cut -d= -f1) val=$(echo "$line" | cut -d= -f2-) # Trim key=$(echo "$key" | xargs) val=$(echo "$val" | xargs) current=$(grep -E "^$key=" "$TARGET" || true) current_val="" if [[ -n "$current" ]]; then current_val=$(echo "$current" | cut -d= -f2-) fi if [[ "$confirm" = true ]]; then # non-interactive: keep example defaults or environment overrides env_val="" if [[ -n "${!key:-}" ]]; then env_val="${!key}" fi if [[ -n "$env_val" ]]; then update_env_var "$key" "$env_val" "$TARGET" fi continue fi # Skip if production mode already set the value if [[ "$production" = true ]]; then case "$key" in DJANGO_SECRET_KEY|DATABASE_PASSWORD|POSTGRES_PASSWORD|DJANGO_DEBUG|DJANGO_SECURE_*|DOMAIN|EMAIL) continue ;; esac fi # Interactive mode: prompt user for each variable if read -t 1 -n 0 2>/dev/null; then # Special prompts for certain variables case "$key" in DJANGO_SECRET_KEY) if [[ -z "$current_val" ]]; then read -p "$key (press Enter to generate): " new_val || true if [[ -z "$new_val" ]]; then new_val=$(generate_secret_key) fi else read -p "$key [HIDDEN]: " new_val || true fi ;; DATABASE_PASSWORD|POSTGRES_PASSWORD) if [[ -z "$current_val" ]]; then read -p "$key (press Enter to generate): " new_val || true if [[ -z "$new_val" ]]; then new_val=$(generate_password) fi else read -p "$key [HIDDEN]: " new_val || true fi ;; *) read -p "$key [$current_val]: " new_val || true ;; esac else # no stdin available, skip prompting new_val="" fi if [[ -n "$new_val" ]]; then update_env_var "$key" "$new_val" "$TARGET" fi done < <(grep -E '^[A-Z0-9_]+=.*' "$EXAMPLE") echo "✅ Written $TARGET" if [[ "$production" = false ]]; then echo "" echo "💡 Tips:" echo " - Run with --production for production setup with secure defaults" echo " - Run with --yes to auto-fill from environment variables" echo " - Check the generated .env file and adjust values as needed" fi