diff --git a/retoors/helpers/env_manager.py b/retoors/helpers/env_manager.py index 012e0cc..d860dcf 100644 --- a/retoors/helpers/env_manager.py +++ b/retoors/helpers/env_manager.py @@ -1,9 +1,12 @@ 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. + 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 @@ -47,6 +50,62 @@ SMTP_SENDER_EMAIL=no-reply@retoors.com 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: - ensure_env_file_exists(Path(__file__).parent.parent.parent / ".env") + 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}") diff --git a/retoors/main.py b/retoors/main.py index 3f4c9ce..91e0683 100644 --- a/retoors/main.py +++ b/retoors/main.py @@ -6,12 +6,13 @@ from aiohttp_session import setup as setup_session from aiohttp_session.cookie_storage import EncryptedCookieStorage import os import aiojobs # Import aiojobs +import dotenv # Import dotenv from .routes import setup_routes from .services.user_service import UserService from .services.config_service import ConfigService from .middlewares import user_middleware, error_middleware -from .helpers.env_manager import ensure_env_file_exists +from .helpers.env_manager import ensure_env_file_exists, get_or_create_session_secret_key # Import new function async def setup_services(app: web.Application): @@ -30,7 +31,9 @@ async def setup_services(app: web.Application): def create_app(): # Ensure .env file exists before loading any configurations project_root = Path(__file__).parent.parent - ensure_env_file_exists(project_root / ".env") + env_file_path = project_root / ".env" # Define env_file_path + ensure_env_file_exists(env_file_path) + dotenv.load_dotenv(dotenv_path=env_file_path) # Load environment variables after ensuring .env exists app = web.Application() @@ -39,8 +42,8 @@ def create_app(): app.middlewares.append(error_middleware) # Setup session - secret_key = os.urandom(32) - setup_session(app, EncryptedCookieStorage(secret_key)) + secret_key = get_or_create_session_secret_key(env_file_path) # Use the new helper function + setup_session(app, EncryptedCookieStorage(secret_key.decode("utf-8"))) app.middlewares.append(user_middleware) @@ -68,4 +71,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/retoors/routes.py b/retoors/routes.py index 3186922..378df3c 100644 --- a/retoors/routes.py +++ b/retoors/routes.py @@ -10,6 +10,8 @@ def setup_routes(app): app.router.add_view("/reset_password/{token}", ResetPasswordView, name="reset_password") app.router.add_view("/", SiteView, name="index") app.router.add_view("/solutions", SiteView, name="solutions") + app.router.add_view("/pricing", SiteView, name="pricing") + app.router.add_view("/security", SiteView, name="security") app.router.add_view("/support", SiteView, name="support") app.router.add_view("/use_cases", SiteView, name="use_cases") app.router.add_view("/dashboard", SiteView, name="dashboard") diff --git a/retoors/templates/components/footer.html b/retoors/templates/components/footer.html index 75a2b72..9b89e54 100644 --- a/retoors/templates/components/footer.html +++ b/retoors/templates/components/footer.html @@ -1,3 +1,3 @@ -