155 lines
5.9 KiB
Python
155 lines
5.9 KiB
Python
"""
|
|
Unified configuration that reads secrets from environment variables.
|
|
Non-secret configuration (like CORS origins) can have defaults per environment.
|
|
"""
|
|
import os
|
|
|
|
|
|
class ApplicationConfig:
|
|
"""
|
|
Application configuration loaded from environment variables.
|
|
All secrets MUST be provided via environment variables.
|
|
"""
|
|
|
|
# Current environment mode
|
|
CURRENT_SETTINGS = os.environ.get('MODE', 'DEVELOPMENT')
|
|
|
|
# ===========================================
|
|
# DATABASE CONFIGURATION (Required)
|
|
# ===========================================
|
|
POSTGRES_USERNAME = os.environ.get('POSTGRES_USERNAME')
|
|
POSTGRES_PW = os.environ.get('POSTGRES_PASSWORD')
|
|
POSTGRES_SERVER = os.environ.get('POSTGRES_SERVER')
|
|
POSTGRES_PORT = os.environ.get('POSTGRES_PORT', '5432')
|
|
POSTGRES_DBNAME00 = os.environ.get('POSTGRES_DBNAME')
|
|
|
|
# ===========================================
|
|
# JWT CONFIGURATION (Required)
|
|
# ===========================================
|
|
JWT_SECRET_KEY = os.environ.get('JWT_SECRET_KEY')
|
|
JWT_ALGORITHM = os.environ.get('JWT_ALGORITHM', 'HS256')
|
|
# Token expiry in minutes (default: 30 min for prod, can override for dev)
|
|
JWT_ACCESS_TOKEN_EXPIRE_MINUTES = int(os.environ.get('JWT_ACCESS_TOKEN_EXPIRE_MINUTES', '30'))
|
|
|
|
# ===========================================
|
|
# AUTHORIZE.NET CONFIGURATION (Required for payments)
|
|
# ===========================================
|
|
AUTH_NET_API_LOGIN_ID = os.environ.get('AUTH_NET_API_LOGIN_ID')
|
|
AUTH_NET_TRANSACTION_KEY = os.environ.get('AUTH_NET_TRANSACTION_KEY')
|
|
|
|
# ===========================================
|
|
# SMTP CONFIGURATION (Required for password reset)
|
|
# ===========================================
|
|
SMTP_SERVER = os.environ.get('SMTP_SERVER', 'smtp.gmail.com')
|
|
SMTP_PORT = int(os.environ.get('SMTP_PORT', '587'))
|
|
SMTP_USERNAME = os.environ.get('SMTP_USERNAME')
|
|
SMTP_PASSWORD = os.environ.get('SMTP_PASSWORD')
|
|
SMTP_FROM_EMAIL = os.environ.get('SMTP_FROM_EMAIL')
|
|
|
|
# ===========================================
|
|
# FRONTEND URL (Required for password reset links)
|
|
# ===========================================
|
|
FRONTEND_URL = os.environ.get('FRONTEND_URL', 'http://localhost:3000')
|
|
|
|
# ===========================================
|
|
# CORS ORIGINS - Environment specific defaults
|
|
# ===========================================
|
|
_origins_env = os.environ.get('CORS_ORIGINS', '')
|
|
|
|
if _origins_env:
|
|
# Use comma-separated list from environment
|
|
origins = [origin.strip() for origin in _origins_env.split(',') if origin.strip()]
|
|
else:
|
|
# Default origins based on MODE
|
|
_mode = os.environ.get('MODE', 'DEVELOPMENT')
|
|
if _mode == 'PRODUCTION':
|
|
origins = [
|
|
"https://oil.edwineames.com",
|
|
"https://apiauto.edwineames.com",
|
|
"https://portal.auburnoil.com",
|
|
]
|
|
elif _mode == 'LOCAL':
|
|
origins = [
|
|
"http://192.168.1.204:9000",
|
|
"http://192.168.1.204:9613",
|
|
"http://192.168.1.204:9614",
|
|
"http://192.168.1.204:9612",
|
|
"http://192.168.1.204:9611",
|
|
]
|
|
else: # DEVELOPMENT
|
|
origins = [
|
|
"http://localhost:9000",
|
|
"https://localhost:9513",
|
|
"http://localhost:9514",
|
|
"http://localhost:9512",
|
|
"http://localhost:9511",
|
|
"http://localhost:5173",
|
|
"http://localhost:8000",
|
|
]
|
|
|
|
# Legacy compatibility - build SQLAlchemy URI if all parts provided
|
|
if all([POSTGRES_USERNAME, POSTGRES_PW, POSTGRES_SERVER, POSTGRES_DBNAME00]):
|
|
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}:{}/{}".format(
|
|
POSTGRES_USERNAME,
|
|
POSTGRES_PW,
|
|
POSTGRES_SERVER,
|
|
POSTGRES_PORT,
|
|
POSTGRES_DBNAME00
|
|
)
|
|
SQLALCHEMY_BINDS = {POSTGRES_DBNAME00: SQLALCHEMY_DATABASE_URI}
|
|
else:
|
|
SQLALCHEMY_DATABASE_URI = None
|
|
SQLALCHEMY_BINDS = {}
|
|
|
|
@classmethod
|
|
def validate_required(cls):
|
|
"""Validate that all required environment variables are set."""
|
|
required = {
|
|
'POSTGRES_USERNAME': cls.POSTGRES_USERNAME,
|
|
'POSTGRES_PASSWORD': cls.POSTGRES_PW,
|
|
'POSTGRES_SERVER': cls.POSTGRES_SERVER,
|
|
'POSTGRES_DBNAME': cls.POSTGRES_DBNAME00,
|
|
'JWT_SECRET_KEY': cls.JWT_SECRET_KEY,
|
|
}
|
|
|
|
missing = [key for key, value in required.items() if not value]
|
|
|
|
if missing:
|
|
raise ValueError(
|
|
f"Missing required environment variables: {', '.join(missing)}\n"
|
|
"Please set these in your .env file or docker-compose environment."
|
|
)
|
|
|
|
# Warn about weak JWT secret in production
|
|
if cls.CURRENT_SETTINGS == 'PRODUCTION':
|
|
if cls.JWT_SECRET_KEY and len(cls.JWT_SECRET_KEY) < 32:
|
|
print("\033[93mWARNING: JWT_SECRET_KEY should be at least 32 characters for production\033[0m")
|
|
|
|
return True
|
|
|
|
@classmethod
|
|
def validate_payment_config(cls):
|
|
"""Validate payment configuration (call before processing payments)."""
|
|
if not cls.AUTH_NET_API_LOGIN_ID or not cls.AUTH_NET_TRANSACTION_KEY:
|
|
raise ValueError(
|
|
"Payment processing requires AUTH_NET_API_LOGIN_ID and AUTH_NET_TRANSACTION_KEY"
|
|
)
|
|
return True
|
|
|
|
@classmethod
|
|
def validate_email_config(cls):
|
|
"""Validate email configuration (call before sending emails)."""
|
|
required = {
|
|
'SMTP_USERNAME': cls.SMTP_USERNAME,
|
|
'SMTP_PASSWORD': cls.SMTP_PASSWORD,
|
|
'SMTP_FROM_EMAIL': cls.SMTP_FROM_EMAIL,
|
|
}
|
|
|
|
missing = [key for key, value in required.items() if not value]
|
|
|
|
if missing:
|
|
raise ValueError(
|
|
f"Email sending requires: {', '.join(missing)}"
|
|
)
|
|
return True
|