Cybersecurity-Projects/PROJECTS/advanced/bug-bounty-platform/backend/app/config.py

205 lines
5.1 KiB
Python

"""
ⒸAngelaMos | 2026
config.py
"""
from pathlib import Path
from typing import Literal
from functools import lru_cache
from pydantic import (
EmailStr,
Field,
RedisDsn,
SecretStr,
PostgresDsn,
model_validator,
)
from pydantic_settings import (
BaseSettings,
SettingsConfigDict,
)
from core.constants import (
API_PREFIX,
API_VERSION,
ASSET_DESCRIPTION_MAX_LENGTH,
ASSET_IDENTIFIER_MAX_LENGTH,
BIO_MAX_LENGTH,
COMMENT_MAX_LENGTH,
COMPANY_NAME_MAX_LENGTH,
CURRENCY_MAX_LENGTH,
CWE_ID_MAX_LENGTH,
DEVICE_ID_MAX_LENGTH,
DEVICE_NAME_MAX_LENGTH,
EMAIL_MAX_LENGTH,
FILENAME_MAX_LENGTH,
FULL_NAME_MAX_LENGTH,
IP_ADDRESS_MAX_LENGTH,
MIME_TYPE_MAX_LENGTH,
PASSWORD_HASH_MAX_LENGTH,
PASSWORD_MAX_LENGTH,
PASSWORD_MIN_LENGTH,
PROGRAM_DESCRIPTION_MAX_LENGTH,
PROGRAM_NAME_MAX_LENGTH,
PROGRAM_RULES_MAX_LENGTH,
PROGRAM_SLUG_MAX_LENGTH,
REPORT_DESCRIPTION_MAX_LENGTH,
REPORT_IMPACT_MAX_LENGTH,
REPORT_STEPS_MAX_LENGTH,
REPORT_TITLE_MAX_LENGTH,
STORAGE_PATH_MAX_LENGTH,
TOKEN_HASH_LENGTH,
WEBSITE_MAX_LENGTH,
)
from core.enums import (
AssetType,
Environment,
HealthStatus,
ProgramStatus,
ProgramVisibility,
ReportStatus,
SafeEnum,
Severity,
TokenType,
UserRole,
)
__all__ = [
"API_PREFIX",
"API_VERSION",
"ASSET_DESCRIPTION_MAX_LENGTH",
"ASSET_IDENTIFIER_MAX_LENGTH",
"BIO_MAX_LENGTH",
"COMMENT_MAX_LENGTH",
"COMPANY_NAME_MAX_LENGTH",
"CURRENCY_MAX_LENGTH",
"CWE_ID_MAX_LENGTH",
"DEVICE_ID_MAX_LENGTH",
"DEVICE_NAME_MAX_LENGTH",
"EMAIL_MAX_LENGTH",
"FILENAME_MAX_LENGTH",
"FULL_NAME_MAX_LENGTH",
"IP_ADDRESS_MAX_LENGTH",
"MIME_TYPE_MAX_LENGTH",
"PASSWORD_HASH_MAX_LENGTH",
"PASSWORD_MAX_LENGTH",
"PASSWORD_MIN_LENGTH",
"PROGRAM_DESCRIPTION_MAX_LENGTH",
"PROGRAM_NAME_MAX_LENGTH",
"PROGRAM_RULES_MAX_LENGTH",
"PROGRAM_SLUG_MAX_LENGTH",
"REPORT_DESCRIPTION_MAX_LENGTH",
"REPORT_IMPACT_MAX_LENGTH",
"REPORT_STEPS_MAX_LENGTH",
"REPORT_TITLE_MAX_LENGTH",
"STORAGE_PATH_MAX_LENGTH",
"TOKEN_HASH_LENGTH",
"WEBSITE_MAX_LENGTH",
"AssetType",
"Environment",
"HealthStatus",
"ProgramStatus",
"ProgramVisibility",
"ReportStatus",
"SafeEnum",
"Settings",
"Severity",
"TokenType",
"UserRole",
"get_settings",
"settings",
]
_PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
_ENV_FILE = _PROJECT_ROOT / ".env"
class Settings(BaseSettings):
"""
Application settings loaded from environment variables
"""
model_config = SettingsConfigDict(
env_file = _ENV_FILE,
env_file_encoding = "utf-8",
case_sensitive = False,
extra = "ignore",
)
APP_NAME: str = "bug-bounty-platform"
APP_VERSION: str = "1.0.0"
APP_SUMMARY: str = "Developed CarterPerez-dev"
APP_DESCRIPTION: str = "FastAPI async first boilerplate - JWT, Asyncdb, PostgreSQL"
APP_CONTACT_NAME: str = "AngelaMos LLC"
APP_CONTACT_EMAIL: str = "support@certgames.com"
APP_LICENSE_NAME: str = "MIT"
APP_LICENSE_URL: str = "https://github.com/CarterPerez-dev/Cybersecurity-Projects/blob/main/LICENSE"
ENVIRONMENT: Environment = Environment.DEVELOPMENT
DEBUG: bool = False
HOST: str = "0.0.0.0"
PORT: int = 8000
RELOAD: bool = True
DATABASE_URL: PostgresDsn
DB_POOL_SIZE: int = Field(default = 20, ge = 5, le = 100)
DB_MAX_OVERFLOW: int = Field(default = 10, ge = 0, le = 50)
DB_POOL_TIMEOUT: int = Field(default = 30, ge = 10)
DB_POOL_RECYCLE: int = Field(default = 1800, ge = 300)
SECRET_KEY: SecretStr = Field(..., min_length = 32)
JWT_ALGORITHM: Literal["HS256", "HS384", "HS512"] = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(default = 15, ge = 5, le = 60)
REFRESH_TOKEN_EXPIRE_DAYS: int = Field(default = 7, ge = 1, le = 30)
ADMIN_EMAIL: EmailStr | None = None
REDIS_URL: RedisDsn | None = None
CORS_ORIGINS: list[str] = ["*"]
CORS_ALLOW_CREDENTIALS: bool = True
CORS_ALLOW_METHODS: list[str] = [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS"
]
CORS_ALLOW_HEADERS: list[str] = ["*"]
RATE_LIMIT_DEFAULT: str = "100/minute"
RATE_LIMIT_AUTH: str = "20/minute"
PAGINATION_DEFAULT_SIZE: int = Field(default = 20, ge = 1, le = 100)
PAGINATION_MAX_SIZE: int = Field(default = 100, ge = 1, le = 500)
LOG_LEVEL: Literal["DEBUG",
"INFO",
"WARNING",
"ERROR",
"CRITICAL"] = "INFO"
LOG_JSON_FORMAT: bool = True
@model_validator(mode = "after")
def validate_production_settings(self) -> "Settings":
"""
Enforce security constraints in production environment.
"""
if self.ENVIRONMENT == Environment.PRODUCTION and self.DEBUG:
raise ValueError("DEBUG must be False in production")
return self
@lru_cache
def get_settings() -> Settings:
"""
Cached settings instance to avoid repeated env parsing
"""
return Settings()
settings = get_settings()