This commit is contained in:
Iliyan Angelov
2025-11-28 02:40:05 +02:00
parent 627959f52b
commit 312f85530c
246 changed files with 23535 additions and 3428 deletions

View File

@@ -14,6 +14,7 @@ import sys
import secrets
import os
import re
import logging
from .config.settings import settings
from .config.logging_config import setup_logging, get_logger
from .config.database import engine, Base, get_db
@@ -26,6 +27,9 @@ from .middleware.request_id import RequestIDMiddleware
from .middleware.security import SecurityHeadersMiddleware
from .middleware.timeout import TimeoutMiddleware
from .middleware.cookie_consent import CookieConsentMiddleware
from .middleware.csrf import CSRFProtectionMiddleware
from .middleware.request_size_limit import RequestSizeLimitMiddleware
from .middleware.admin_ip_whitelist import AdminIPWhitelistMiddleware
if settings.is_development:
logger.info('Creating database tables (development mode)')
Base.metadata.create_all(bind=engine)
@@ -48,6 +52,14 @@ app.add_middleware(CookieConsentMiddleware)
if settings.REQUEST_TIMEOUT > 0:
app.add_middleware(TimeoutMiddleware)
app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(RequestSizeLimitMiddleware, max_size=settings.MAX_REQUEST_BODY_SIZE)
logger.info(f'Request size limiting enabled: {settings.MAX_REQUEST_BODY_SIZE // 1024 // 1024}MB max body size')
if settings.CSRF_PROTECTION_ENABLED:
app.add_middleware(CSRFProtectionMiddleware)
logger.info('CSRF protection enabled')
if settings.IP_WHITELIST_ENABLED:
app.add_middleware(AdminIPWhitelistMiddleware)
logger.info(f'Admin IP whitelisting enabled with {len(settings.ADMIN_IP_WHITELIST)} IP(s)/CIDR range(s)')
if settings.RATE_LIMIT_ENABLED:
limiter = Limiter(key_func=get_remote_address, default_limits=[f'{settings.RATE_LIMIT_PER_MINUTE}/minute'])
app.state.limiter = limiter
@@ -57,8 +69,17 @@ if settings.is_development:
app.add_middleware(CORSMiddleware, allow_origin_regex='http://(localhost|127\\.0\\.0\\.1)(:\\d+)?', allow_credentials=True, allow_methods=['*'], allow_headers=['*'])
logger.info('CORS configured for development (allowing localhost)')
else:
app.add_middleware(CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], allow_headers=['*'])
logger.info(f'CORS configured for production with {len(settings.CORS_ORIGINS)} allowed origins')
# Validate CORS_ORIGINS in production
if not settings.CORS_ORIGINS or len(settings.CORS_ORIGINS) == 0:
logger.warning('CORS_ORIGINS is empty in production. This may block legitimate requests.')
logger.warning('Please set CORS_ORIGINS environment variable with allowed origins.')
else:
# Log CORS configuration for security audit
logger.info(f'CORS configured for production with {len(settings.CORS_ORIGINS)} allowed origin(s)')
if logger.isEnabledFor(logging.DEBUG):
logger.debug(f'Allowed CORS origins: {", ".join(settings.CORS_ORIGINS)}')
app.add_middleware(CORSMiddleware, allow_origins=settings.CORS_ORIGINS or [], allow_credentials=True, allow_methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], allow_headers=['*'])
uploads_dir = Path(__file__).parent.parent / settings.UPLOAD_DIR
uploads_dir.mkdir(exist_ok=True)
app.mount('/uploads', StaticFiles(directory=str(uploads_dir)), name='uploads')
@@ -93,93 +114,85 @@ async def health_check(db: Session=Depends(get_db)):
@app.get('/metrics', tags=['monitoring'])
async def metrics():
return {'status': 'success', 'service': settings.APP_NAME, 'version': settings.APP_VERSION, 'environment': settings.ENVIRONMENT, 'timestamp': datetime.utcnow().isoformat()}
app.include_router(auth_routes.router, prefix='/api')
app.include_router(auth_routes.router, prefix=settings.API_V1_PREFIX)
from .routes import room_routes, booking_routes, payment_routes, invoice_routes, banner_routes, favorite_routes, service_routes, service_booking_routes, promotion_routes, report_routes, review_routes, user_routes, audit_routes, admin_privacy_routes, system_settings_routes, contact_routes, page_content_routes, home_routes, about_routes, contact_content_routes, footer_routes, chat_routes, privacy_routes, terms_routes, refunds_routes, cancellation_routes, accessibility_routes, faq_routes, loyalty_routes, guest_profile_routes, analytics_routes, workflow_routes, task_routes, notification_routes, group_booking_routes, advanced_room_routes, rate_plan_routes, package_routes, security_routes, email_campaign_routes
app.include_router(room_routes.router, prefix='/api')
app.include_router(booking_routes.router, prefix='/api')
app.include_router(group_booking_routes.router, prefix='/api')
app.include_router(payment_routes.router, prefix='/api')
app.include_router(invoice_routes.router, prefix='/api')
app.include_router(banner_routes.router, prefix='/api')
app.include_router(favorite_routes.router, prefix='/api')
app.include_router(service_routes.router, prefix='/api')
app.include_router(service_booking_routes.router, prefix='/api')
app.include_router(promotion_routes.router, prefix='/api')
app.include_router(report_routes.router, prefix='/api')
app.include_router(review_routes.router, prefix='/api')
app.include_router(user_routes.router, prefix='/api')
app.include_router(audit_routes.router, prefix='/api')
app.include_router(admin_privacy_routes.router, prefix='/api')
app.include_router(system_settings_routes.router, prefix='/api')
app.include_router(contact_routes.router, prefix='/api')
app.include_router(home_routes.router, prefix='/api')
app.include_router(about_routes.router, prefix='/api')
app.include_router(contact_content_routes.router, prefix='/api')
app.include_router(footer_routes.router, prefix='/api')
app.include_router(privacy_routes.router, prefix='/api')
app.include_router(terms_routes.router, prefix='/api')
app.include_router(refunds_routes.router, prefix='/api')
app.include_router(cancellation_routes.router, prefix='/api')
app.include_router(accessibility_routes.router, prefix='/api')
app.include_router(faq_routes.router, prefix='/api')
app.include_router(chat_routes.router, prefix='/api')
app.include_router(loyalty_routes.router, prefix='/api')
app.include_router(guest_profile_routes.router, prefix='/api')
app.include_router(analytics_routes.router, prefix='/api')
app.include_router(workflow_routes.router, prefix='/api')
app.include_router(task_routes.router, prefix='/api')
app.include_router(notification_routes.router, prefix='/api')
app.include_router(advanced_room_routes.router, prefix='/api')
app.include_router(rate_plan_routes.router, prefix='/api')
app.include_router(package_routes.router, prefix='/api')
app.include_router(security_routes.router, prefix='/api')
app.include_router(email_campaign_routes.router, prefix='/api')
app.include_router(room_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(booking_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(payment_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(invoice_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(banner_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(favorite_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(service_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(service_booking_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(promotion_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(report_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(review_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(user_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(audit_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(admin_privacy_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(system_settings_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(contact_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(home_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(about_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(contact_content_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(footer_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(privacy_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(terms_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(refunds_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(cancellation_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(accessibility_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(faq_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(chat_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(loyalty_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(guest_profile_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(analytics_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(workflow_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(task_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(notification_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(advanced_room_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(rate_plan_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(package_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(page_content_routes.router, prefix='/api')
app.include_router(page_content_routes.router, prefix=settings.API_V1_PREFIX)
# Import all route modules
from .routes import (
room_routes, booking_routes, payment_routes, invoice_routes, banner_routes,
favorite_routes, service_routes, service_booking_routes, promotion_routes,
report_routes, review_routes, user_routes, audit_routes, admin_privacy_routes,
system_settings_routes, contact_routes, page_content_routes, home_routes,
about_routes, contact_content_routes, footer_routes, chat_routes, privacy_routes,
terms_routes, refunds_routes, cancellation_routes, accessibility_routes,
faq_routes, loyalty_routes, guest_profile_routes, analytics_routes,
workflow_routes, task_routes, notification_routes, group_booking_routes,
advanced_room_routes, rate_plan_routes, package_routes, security_routes,
email_campaign_routes
)
# Register all routes with /api prefix (removed duplicate registrations)
# Using /api prefix as standard, API versioning can be handled via headers if needed
api_prefix = '/api'
app.include_router(auth_routes.router, prefix=api_prefix)
app.include_router(room_routes.router, prefix=api_prefix)
app.include_router(booking_routes.router, prefix=api_prefix)
app.include_router(group_booking_routes.router, prefix=api_prefix)
app.include_router(payment_routes.router, prefix=api_prefix)
app.include_router(invoice_routes.router, prefix=api_prefix)
app.include_router(banner_routes.router, prefix=api_prefix)
app.include_router(favorite_routes.router, prefix=api_prefix)
app.include_router(service_routes.router, prefix=api_prefix)
app.include_router(service_booking_routes.router, prefix=api_prefix)
app.include_router(promotion_routes.router, prefix=api_prefix)
app.include_router(report_routes.router, prefix=api_prefix)
app.include_router(review_routes.router, prefix=api_prefix)
app.include_router(user_routes.router, prefix=api_prefix)
app.include_router(audit_routes.router, prefix=api_prefix)
app.include_router(admin_privacy_routes.router, prefix=api_prefix)
app.include_router(system_settings_routes.router, prefix=api_prefix)
app.include_router(contact_routes.router, prefix=api_prefix)
app.include_router(home_routes.router, prefix=api_prefix)
app.include_router(about_routes.router, prefix=api_prefix)
app.include_router(contact_content_routes.router, prefix=api_prefix)
app.include_router(footer_routes.router, prefix=api_prefix)
app.include_router(privacy_routes.router, prefix=api_prefix)
app.include_router(terms_routes.router, prefix=api_prefix)
app.include_router(refunds_routes.router, prefix=api_prefix)
app.include_router(cancellation_routes.router, prefix=api_prefix)
app.include_router(accessibility_routes.router, prefix=api_prefix)
app.include_router(faq_routes.router, prefix=api_prefix)
app.include_router(chat_routes.router, prefix=api_prefix)
app.include_router(loyalty_routes.router, prefix=api_prefix)
app.include_router(guest_profile_routes.router, prefix=api_prefix)
app.include_router(analytics_routes.router, prefix=api_prefix)
app.include_router(workflow_routes.router, prefix=api_prefix)
app.include_router(task_routes.router, prefix=api_prefix)
app.include_router(notification_routes.router, prefix=api_prefix)
app.include_router(advanced_room_routes.router, prefix=api_prefix)
app.include_router(rate_plan_routes.router, prefix=api_prefix)
app.include_router(package_routes.router, prefix=api_prefix)
app.include_router(security_routes.router, prefix=api_prefix)
app.include_router(email_campaign_routes.router, prefix=api_prefix)
app.include_router(page_content_routes.router, prefix=api_prefix)
logger.info('All routes registered successfully')
def ensure_jwt_secret():
"""Generate and save JWT secret if it's using the default value."""
"""Generate and save JWT secret if it's using the default value.
In production, fail fast if default secret is used for security.
In development, auto-generate a secure secret if needed.
"""
default_secret = 'dev-secret-key-change-in-production-12345'
current_secret = settings.JWT_SECRET
# Security check: Fail fast in production if using default secret
if settings.is_production and (not current_secret or current_secret == default_secret):
error_msg = (
'CRITICAL SECURITY ERROR: JWT_SECRET is using default value in production! '
'Please set a secure JWT_SECRET in your environment variables.'
)
logger.error(error_msg)
raise ValueError(error_msg)
# Development mode: Auto-generate if needed
if not current_secret or current_secret == default_secret:
new_secret = secrets.token_urlsafe(64)
@@ -219,6 +232,14 @@ def ensure_jwt_secret():
async def startup_event():
ensure_jwt_secret()
# Validate encryption key configuration
try:
settings.validate_encryption_key()
except ValueError as e:
logger.error(str(e))
if settings.is_production:
raise # Fail fast in production
logger.info(f'{settings.APP_NAME} started successfully')
logger.info(f'Environment: {settings.ENVIRONMENT}')
logger.info(f'Debug mode: {settings.DEBUG}')