mirror of
https://github.com/th30d4y/OpenLearnX.git
synced 2026-05-26 19:26:33 +00:00
Improve code quality - add custom exception, documentation, and refactor auth.py
Co-authored-by: Stalin-143 <161853795+Stalin-143@users.noreply.github.com>
This commit is contained in:
+33
-4
@@ -110,17 +110,46 @@ def check_docker_availability():
|
|||||||
|
|
||||||
# ✅ ENHANCED: Flask app configuration with your .env variables
|
# ✅ ENHANCED: Flask app configuration with your .env variables
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
class MissingSecretError(ValueError):
|
||||||
|
"""Raised when a required secret is not set in environment variables."""
|
||||||
|
pass
|
||||||
|
|
||||||
def get_required_secret(env_var: str, description: str) -> str:
|
def get_required_secret(env_var: str, description: str) -> str:
|
||||||
"""Get required secret from environment, raise error if not set"""
|
"""
|
||||||
|
Get required secret from environment.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
env_var: Name of the environment variable
|
||||||
|
description: Human-readable description of the secret
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The secret value from the environment
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
MissingSecretError: If the environment variable is not set
|
||||||
|
"""
|
||||||
value = os.getenv(env_var)
|
value = os.getenv(env_var)
|
||||||
if not value:
|
if not value:
|
||||||
raise ValueError(f"{description} ({env_var}) must be set in environment variables for security. Do not use default values for secrets.")
|
raise MissingSecretError(f"{description} ({env_var}) must be set in environment variables for security. Do not use default values for secrets.")
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_dev_fallback_secret(name: str) -> str:
|
def get_dev_fallback_secret(name: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a persistent random secret for development use only.
|
Generate a persistent random secret for development use only.
|
||||||
Stores the secret in a file to persist across restarts.
|
|
||||||
|
Stores the secret in a file in the system temp directory to persist across restarts.
|
||||||
|
Files are created with restrictive permissions (0600) to limit access.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Unique identifier for this secret (used in filename)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A 64-character hex string (32 bytes of randomness)
|
||||||
|
|
||||||
|
Security Note:
|
||||||
|
These secrets are stored in temp files and should only be used for development.
|
||||||
|
In production, always set proper secrets via environment variables.
|
||||||
"""
|
"""
|
||||||
import tempfile
|
import tempfile
|
||||||
import stat
|
import stat
|
||||||
@@ -147,7 +176,7 @@ try:
|
|||||||
_secret_key = get_required_secret('SECRET_KEY', 'Flask secret key')
|
_secret_key = get_required_secret('SECRET_KEY', 'Flask secret key')
|
||||||
_jwt_secret_key = get_required_secret('JWT_SECRET_KEY', 'JWT secret key')
|
_jwt_secret_key = get_required_secret('JWT_SECRET_KEY', 'JWT secret key')
|
||||||
_admin_token = get_required_secret('ADMIN_TOKEN', 'Admin authentication token')
|
_admin_token = get_required_secret('ADMIN_TOKEN', 'Admin authentication token')
|
||||||
except ValueError as e:
|
except MissingSecretError as e:
|
||||||
print(f"⚠️ SECURITY WARNING: {e}")
|
print(f"⚠️ SECURITY WARNING: {e}")
|
||||||
print("⚠️ Using persistent development secrets. Set proper secrets in production!")
|
print("⚠️ Using persistent development secrets. Set proper secrets in production!")
|
||||||
_secret_key = os.getenv('SECRET_KEY') or get_dev_fallback_secret('secret_key')
|
_secret_key = os.getenv('SECRET_KEY') or get_dev_fallback_secret('secret_key')
|
||||||
|
|||||||
@@ -22,7 +22,13 @@ if not JWT_SECRET:
|
|||||||
import warnings
|
import warnings
|
||||||
import tempfile
|
import tempfile
|
||||||
import stat
|
import stat
|
||||||
|
import secrets as secrets_module
|
||||||
warnings.warn("JWT_SECRET environment variable not set. Using persistent dev secret.", UserWarning)
|
warnings.warn("JWT_SECRET environment variable not set. Using persistent dev secret.", UserWarning)
|
||||||
|
|
||||||
|
def _generate_and_store_secret():
|
||||||
|
"""Generate a random secret and store it with restrictive permissions."""
|
||||||
|
return secrets_module.token_hex(32)
|
||||||
|
|
||||||
# Use persistent file-based secret for development to avoid invalidating tokens on restart
|
# Use persistent file-based secret for development to avoid invalidating tokens on restart
|
||||||
_secret_file = os.path.join(tempfile.gettempdir(), '.openlearnx_dev_jwt_secret_auth')
|
_secret_file = os.path.join(tempfile.gettempdir(), '.openlearnx_dev_jwt_secret_auth')
|
||||||
try:
|
try:
|
||||||
@@ -30,15 +36,13 @@ if not JWT_SECRET:
|
|||||||
with open(_secret_file, 'r') as f:
|
with open(_secret_file, 'r') as f:
|
||||||
JWT_SECRET = f.read().strip()
|
JWT_SECRET = f.read().strip()
|
||||||
if not JWT_SECRET:
|
if not JWT_SECRET:
|
||||||
import secrets as _secrets
|
JWT_SECRET = _generate_and_store_secret()
|
||||||
JWT_SECRET = _secrets.token_hex(32)
|
|
||||||
with open(_secret_file, 'w') as f:
|
with open(_secret_file, 'w') as f:
|
||||||
f.write(JWT_SECRET)
|
f.write(JWT_SECRET)
|
||||||
# Set restrictive permissions (owner read/write only)
|
# Set restrictive permissions (owner read/write only)
|
||||||
os.chmod(_secret_file, stat.S_IRUSR | stat.S_IWUSR)
|
os.chmod(_secret_file, stat.S_IRUSR | stat.S_IWUSR)
|
||||||
except Exception:
|
except Exception:
|
||||||
import secrets as _secrets
|
JWT_SECRET = _generate_and_store_secret()
|
||||||
JWT_SECRET = _secrets.token_hex(32)
|
|
||||||
|
|
||||||
@bp.route('/nonce', methods=['POST', 'OPTIONS'])
|
@bp.route('/nonce', methods=['POST', 'OPTIONS'])
|
||||||
def get_nonce():
|
def get_nonce():
|
||||||
|
|||||||
Reference in New Issue
Block a user