File size: 7,312 Bytes
4e4664a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0d7b8ed
 
 
 
 
 
4e4664a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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()