from pathlib import Path
import os
from cryptography.fernet import Fernet # Import Fernet
import dotenv # Import dotenv to reload env vars
def ensure_env_file_exists(env_path: Path):
"""
Ensures that a .env file exists at the specified path.
If it doesn't exist, it creates one with default values (excluding SESSION_SECRET_KEY).
"""
if not env_path.exists():
default_env_content = """# .env - Environment variables for Retoor's Cloud Solutions
#
# This file is used to configure various aspects of the application,
# including pricing, email settings, and other sensitive information.
#
# For production, it is recommended to manage these variables through
# your hosting provider's environment variable management system
# rather than committing this file to version control.
# Pricing Configuration
# PRICE_PER_GB: Cost per gigabyte of storage.
PRICE_PER_GB=0.05
# SMTP (Email Sending) Configuration
# Used for sending transactional emails (e.g., welcome, password reset).
# SMTP_HOST: The hostname of your SMTP server.
# SMTP_PORT: The port of your SMTP server (e.g., 587 for TLS, 465 for SSL, 25 for unencrypted).
# SMTP_USERNAME: The username for authenticating with your SMTP server.
# SMTP_PASSWORD: The password for authenticating with your SMTP server.
# SMTP_USE_TLS: Set to True to enable STARTTLS encryption (recommended for most servers).
# SMTP_SENDER_EMAIL: The email address from which system emails will be sent.
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_USE_TLS=False
SMTP_SENDER_EMAIL=no-reply@retoors.com
# IMAP (Email Receiving) Configuration (if applicable for future features)
# IMAP_HOST=
# IMAP_PORT=
# IMAP_USERNAME=
# IMAP_PASSWORD=
# IMAP_USE_SSL=True
"""
with open(env_path, "w") as f:
f.write(default_env_content)
print(f"Created default .env file at {env_path}")
else:
print(f".env file already exists at {env_path}")
def get_or_create_session_secret_key(env_path: Path) -> bytes:
"""
Retrieves the SESSION_SECRET_KEY from environment variables.
If not found or invalid, generates a new one, saves it to .env,
and reloads environment variables.
Returns the valid secret key as bytes.
"""
key_name = 'SESSION_SECRET_KEY'
# Try to get the key from already loaded environment variables
# This assumes dotenv.load_dotenv() has been called in main.py
secret_key_str = os.getenv(key_name)
# Variable to hold the key in bytes format
final_secret_key_bytes = None
if secret_key_str:
try:
# Fernet expects bytes, so encode the string from env var
final_secret_key_bytes = secret_key_str.encode('utf-8')
Fernet(final_secret_key_bytes) # Validate the key
print(f"Using existing valid {key_name} from environment.")
except ValueError:
print(f"Existing {key_name} in .env is invalid. Generating a new one.")
final_secret_key_bytes = None # Invalidate to trigger generation
if final_secret_key_bytes is None:
# Generate a new url-safe base64-encoded key
generated_key_bytes = Fernet.generate_key()
generated_key_str = generated_key_bytes.decode('utf-8')
# Append to .env file
with open(env_path, 'a') as f:
f.write(f'\n{key_name}={generated_key_str}\n')
print(f"Generated and added {key_name} to {env_path}")
# Reload environment variables to make the new key available for subsequent os.getenv calls
# This is important if other parts of the app might call os.getenv(key_name) later
dotenv.load_dotenv(dotenv_path=env_path)
final_secret_key_bytes = generated_key_bytes # Use the newly generated bytes directly
if final_secret_key_bytes is None:
raise RuntimeError(f"Failed to get or create {key_name}")
return final_secret_key_bytes
if __name__ == "__main__":
# Example usage:
project_root = Path(__file__).parent.parent.parent
env_file = project_root / ".env"
ensure_env_file_exists(env_file)
try:
key = get_or_create_session_secret_key(env_file)
print(f"Session key obtained: {key}")
except RuntimeError as e:
print(f"Error: {e}")