Resolved fernet issue.

This commit is contained in:
retoor 2025-11-08 19:59:28 +01:00
parent 83ac1eb001
commit 56b9aaa021
6 changed files with 85 additions and 19 deletions

View File

@ -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}")

View File

@ -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()
main()

View File

@ -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")

View File

@ -1,3 +1,3 @@
<footer>
<footer aria-label="Site information and copyright">
<p>&copy; 2025 Retoors. All rights reserved.</p>
</footer>

View File

@ -1,20 +1,20 @@
<header>
<nav>
<a href="/" class="logo">
<nav aria-label="Main navigation">
<a href="/" class="logo" aria-label="Retoor's Cloud Solutions home">
<img src="/static/images/retoors-logo.svg" alt="Retoor's Cloud Solutions" />
<span>Retoor's Cloud Solutions</span>
</a>
<ul>
<li><a href="/solutions">Solutions</a></li>
<li><a href="/pricing">Pricing</a></li>
<li><a href="/security">Security</a></li>
<li><a href="/support">Support</a></li>
<li><a href="/solutions" aria-label="Our Solutions">Solutions</a></li>
<li><a href="/pricing" aria-label="Pricing Plans">Pricing</a></li>
<li><a href="/security" aria-label="Security Information">Security</a></li>
<li><a href="/support" aria-label="Support Page">Support</a></li>
{% if request['user'] %}
<li><a href="/dashboard">Dashboard</a></li>
<li><a href="/logout" class="btn-nav">Logout</a></li>
<li><a href="/dashboard" aria-label="User Dashboard">Dashboard</a></li>
<li><a href="/logout" class="btn-nav" aria-label="Logout">Logout</a></li>
{% else %}
<li><a href="/login" class="btn-outline-nav">Sign In</a></li>
<li><a href="/register" class="btn-primary-nav">Start Your Free Trial</a></li>
<li><a href="/login" class="btn-outline-nav" aria-label="Sign In to your account">Sign In</a></li>
<li><a href="/register" class="btn-primary-nav" aria-label="Start your free trial">Start Your Free Trial</a></li>
{% endif %}
</ul>
</nav>

View File

@ -5,10 +5,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Retoors Storage{% endblock %}</title>
<link rel="stylesheet" href="/static/css/base.css">
<link rel="stylesheet" href="/static/css/components/footer.css">
<link rel="stylesheet" href="/static/css/components/content_pages.css"> {# Added for content page styling #}
{% block head %}{% endblock %}
</head>
<body>
{% include 'components/navigation.html' %}
<div class="container">
{% block content %}{% endblock %}
</div>