from pydantic_settings import BaseSettings from typing import List, Optional from pathlib import Path class Settings(BaseSettings): # SECURITY: Must be set via .env file. No default for production safety. SECRET_KEY: str # Required - generate with: openssl rand -base64 32 ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 # MongoDB Atlas configuration # Example: mongodb+srv://user:pass@cluster.mongodb.net/ # NOTE: Credentials present here only for legacy/dev; MUST be overridden in environment (.env) # Recommendation: remove secrets before committing publicly. # IMPORTANT: Provide via environment (.env). Default points to localhost for safety. MONGODB_URI: str = "mongodb://localhost:27017" # Override in .env for Atlas or remote MONGODB_DB_NAME: str = "atriumchain" # SECURITY: Explicit allowed origins only - no wildcard "*" for production # Add production domains here when deploying (e.g., "https://yourdomain.com") CORS_ORIGINS: List[str] = [ "http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:5174", "http://127.0.0.1:5174", "http://localhost:5175", "http://127.0.0.1:5175", # Production domains "https://atriumchain.web.app", "https://atriumchain.firebaseapp.com", "https://jainish1808-atriumchain-api.hf.space", "https://huggingface.co" ] ALLOWED_ORIGINS: Optional[str] = None # comma-separated override list; if set replaces CORS_ORIGINS XRPL_NETWORK: str = "testnet" # testnet only ISSUER_SEED: str | None = None # DEPRECATED: Use admin wallet instead (kept for backward compatibility) # TOKEN MODEL: IOU for fractional real estate ownership # Uses XRPL issued currencies for fungible property tokens XRPL_TOKEN_MODEL: str = "IOU" # Fixed to IOU - the correct model for fractional ownership # Blockchain integration is mandatory for production XRPL_LEDGER_PURCHASE_ENABLED: bool = True # Configurable AED to XRP demo conversion rate (used only for displaying estimated costs # and in IOU path cost calculation). Previously hard-coded to 1e-6. # NOTE: This should be replaced with real-time oracle in production XRPL_RATE_AED_TO_XRP: float = 0.000001 # Unified explorer base (avoid hard-coded duplicates elsewhere) XRPL_EXPLORER_BASE: str = "https://testnet.xrpl.org/transactions/" # Unified RPC URL (replace ad-hoc constants in services) XRPL_RPC_URL: str = "https://s.altnet.rippletest.net:51234/" # Optional encryption key (32 byte raw, hex, or Fernet base64). If absent seeds remain legacy/base64. ENCRYPTION_KEY: str | None = None # Security Configuration RATE_LIMIT_ENABLED: bool = True MAX_LOGIN_ATTEMPTS: int = 5 LOGIN_LOCKOUT_MINUTES: int = 15 REQUIRE_STRONG_PASSWORDS: bool = True MIN_PASSWORD_LENGTH: int = 8 # Session Configuration SESSION_TIMEOUT_MINUTES: int = 60 REFRESH_TOKEN_EXPIRE_DAYS: int = 7 # IPFS Configuration for Decentralized Document Storage WEB3_STORAGE_API_TOKEN: str | None = None # Get free token from https://web3.storage PINATA_API_KEY: str | None = None # Get free API key from https://pinata.cloud PINATA_SECRET_KEY: str | None = None # Secret key from Pinata dashboard IPFS_GATEWAY: str = "ipfs.io" # Default public IPFS gateway IPFS_BACKUP_GATEWAY: str = "cloudflare-ipfs.com" # Backup gateway IPFS_PROVIDER: str = "local_simulation" # Options: "pinata", "web3storage", "local_simulation" # Monitoring and Logging Configuration LOG_LEVEL: str = "INFO" # DEBUG, INFO, WARNING, ERROR, CRITICAL LOG_FILE_ENABLED: bool = True LOG_FILE_PATH: str = "logs/app.log" LOG_FILE_MAX_SIZE: int = 10485760 # 10MB in bytes LOG_FILE_BACKUP_COUNT: int = 5 # Performance Monitoring ENABLE_PERFORMANCE_MONITORING: bool = True SLOW_QUERY_THRESHOLD: float = 1.0 # Log queries taking longer than 1 second # Transaction Monitoring ENABLE_TRANSACTION_MONITORING: bool = True BLOCKCHAIN_TIMEOUT_SECONDS: int = 30 # Environment-specific settings ENVIRONMENT: str = "development" # development, staging, production DEBUG_MODE: bool = True # Set to False in production def encryption_enabled(self) -> bool: return bool(self.ENCRYPTION_KEY) def is_production(self) -> bool: return self.ENVIRONMENT.lower() == "production" def is_development(self) -> bool: return self.ENVIRONMENT.lower() == "development" def validate_configuration(self): # renamed from validate_issuer_seed for clarity """Validate configuration settings and log important information""" # Validate IOU token configuration if not self.ISSUER_SEED: print("[CONFIG][INFO] ISSUER_SEED not set – using admin wallet for token issuance (recommended).") # Configure CORS origins if self.ALLOWED_ORIGINS: self.CORS_ORIGINS = [o.strip() for o in self.ALLOWED_ORIGINS.split(',') if o.strip()] # Validate environment-specific settings if self.is_production(): # CRITICAL: Validate production security requirements if self.DEBUG_MODE: print("[CONFIG][ERROR] DEBUG_MODE is enabled in production environment!") print("[CONFIG][ERROR] Set DEBUG_MODE=false in .env file immediately!") raise ValueError("DEBUG_MODE must be disabled in production environment") # H1/H3: Enforce encryption key in production for wallet seed security if not self.ENCRYPTION_KEY: print("[CONFIG][ERROR] ENCRYPTION_KEY not set in production environment!") print("[CONFIG][ERROR] Wallet seeds will not be encrypted. This is a security risk.") print("[CONFIG][INFO] Generate key: python -c \"from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())\"") raise ValueError("ENCRYPTION_KEY is required in production environment") else: print("[CONFIG][INFO] ✅ Encryption enabled for wallet seeds.") else: # Development environment warnings if not self.ENCRYPTION_KEY: print("[CONFIG][WARNING] ENCRYPTION_KEY not set – wallet seeds stored with legacy obfuscation.") print("[CONFIG][WARNING] For production, generate with: python -c \"from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())\"") else: print("[CONFIG][INFO] ✅ Encryption enabled for wallet seeds.") # Log monitoring configuration print(f"[CONFIG][INFO] Logging level: {self.LOG_LEVEL}") print(f"[CONFIG][INFO] Environment: {self.ENVIRONMENT}") print(f"[CONFIG][INFO] Performance monitoring: {'Enabled' if self.ENABLE_PERFORMANCE_MONITORING else 'Disabled'}") print(f"[CONFIG][INFO] Transaction monitoring: {'Enabled' if self.ENABLE_TRANSACTION_MONITORING else 'Disabled'}") class Config: env_file = Path(__file__).parent / ".env" settings = Settings() settings.validate_configuration()