v_2.3
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""Configuration loaded from environment variables."""
|
||||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
def _bool(val: str, default: bool = False) -> bool:
|
||||
if val is None:
|
||||
return default
|
||||
return val.strip().lower() in ("1", "true", "yes", "on")
|
||||
|
||||
|
||||
class Config:
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY", "dev-only-replace-me")
|
||||
FLASK_ENV = os.environ.get("FLASK_ENV", "production")
|
||||
|
||||
DATABASE_PATH = os.environ.get("DATABASE_PATH", "/data/alerthub.db")
|
||||
SQLALCHEMY_DATABASE_URI = f"sqlite:///{DATABASE_PATH}"
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
SQLALCHEMY_ENGINE_OPTIONS = {
|
||||
"pool_pre_ping": True,
|
||||
# Wait (instead of erroring) when another process holds the SQLite
|
||||
# write lock — both gunicorn apps share one database file.
|
||||
"connect_args": {"timeout": 30},
|
||||
}
|
||||
|
||||
# Bootstrap admin (only used on first DB init)
|
||||
INITIAL_ADMIN_USERNAME = os.environ.get("INITIAL_ADMIN_USERNAME", "admin")
|
||||
INITIAL_ADMIN_EMAIL = os.environ.get("INITIAL_ADMIN_EMAIL", "admin@example.com")
|
||||
INITIAL_ADMIN_PASSWORD = os.environ.get("INITIAL_ADMIN_PASSWORD", "ChangeMeOnFirstLogin!")
|
||||
|
||||
# Session security
|
||||
SESSION_COOKIE_SECURE = _bool(os.environ.get("SESSION_COOKIE_SECURE"), False)
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SAMESITE = "Lax"
|
||||
PERMANENT_SESSION_LIFETIME = timedelta(
|
||||
hours=int(os.environ.get("SESSION_LIFETIME_HOURS", "8"))
|
||||
)
|
||||
|
||||
PASSWORD_MIN_LENGTH = int(os.environ.get("PASSWORD_MIN_LENGTH", "10"))
|
||||
|
||||
# MFA
|
||||
MFA_ISSUER_NAME = os.environ.get("MFA_ISSUER_NAME", "AlertHub")
|
||||
|
||||
# Scheduler
|
||||
SCHEDULER_INTERVAL_MINUTES = int(os.environ.get("SCHEDULER_INTERVAL_MINUTES", "60"))
|
||||
|
||||
# Default reminder lead times in days
|
||||
DEFAULT_REMINDER_DAYS = os.environ.get("DEFAULT_REMINDER_DAYS", "30,14,7,1")
|
||||
|
||||
# SMTP defaults (seed only — admins edit live values via backoffice)
|
||||
# Purelymail outgoing: smtp.purelymail.com : 465 (SSL/TLS)
|
||||
SMTP_HOST = os.environ.get("SMTP_HOST", "smtp.purelymail.com")
|
||||
SMTP_PORT = int(os.environ.get("SMTP_PORT", "465"))
|
||||
SMTP_USERNAME = os.environ.get("SMTP_USERNAME", "")
|
||||
SMTP_PASSWORD = os.environ.get("SMTP_PASSWORD", "")
|
||||
SMTP_ENCRYPTION = os.environ.get("SMTP_ENCRYPTION", "ssl")
|
||||
SMTP_FROM_ADDRESS = os.environ.get("SMTP_FROM_ADDRESS", "")
|
||||
SMTP_FROM_NAME = os.environ.get("SMTP_FROM_NAME", "AlertHub")
|
||||
|
||||
# IMAP defaults (seed only) — used to save a copy of sent mail to the
|
||||
# mailbox's Sent folder. Purelymail incoming: imap.purelymail.com : 993 (SSL/TLS)
|
||||
IMAP_HOST = os.environ.get("IMAP_HOST", "imap.purelymail.com")
|
||||
IMAP_PORT = int(os.environ.get("IMAP_PORT", "993"))
|
||||
IMAP_USERNAME = os.environ.get("IMAP_USERNAME", "")
|
||||
IMAP_PASSWORD = os.environ.get("IMAP_PASSWORD", "")
|
||||
IMAP_SENT_FOLDER = os.environ.get("IMAP_SENT_FOLDER", "Sent")
|
||||
|
||||
# Ports (used by run scripts only)
|
||||
FRONTOFFICE_PORT = int(os.environ.get("FRONTOFFICE_PORT", "8080"))
|
||||
BACKOFFICE_PORT = int(os.environ.get("BACKOFFICE_PORT", "9001"))
|
||||
|
||||
# Optional explicit public URLs for the cross-console links in the top bar.
|
||||
# If empty, the app derives them from the request host + the ports above
|
||||
# (e.g. http://<your-host>:9001/). Set these when behind a reverse proxy
|
||||
# or when the consoles are reached at custom hostnames/paths.
|
||||
BACKOFFICE_PUBLIC_URL = os.environ.get("BACKOFFICE_PUBLIC_URL", "")
|
||||
FRONTOFFICE_PUBLIC_URL = os.environ.get("FRONTOFFICE_PUBLIC_URL", "")
|
||||
|
||||
# Resource limits
|
||||
MAX_CONTENT_LENGTH = 2 * 1024 * 1024 # 2MB upload cap
|
||||
WTF_CSRF_TIME_LIMIT = 3600
|
||||
Reference in New Issue
Block a user