- Added copy quote functionality with clipboard integration - Implemented bulk moderation actions for admin - Created mobile responsive design with bash.org styling - Added API rate limiting per IP address - Implemented dark mode toggle with flash prevention - Enhanced error messages throughout application - Fixed all security vulnerabilities (SQL injection, XSS, CSRF) - Added comprehensive rate limiting on all endpoints - Implemented secure session configuration - Added input validation and length limits - Created centralized configuration system with config.json - Set up production deployment with Gunicorn - Added security headers and production hardening - Added password generation and config management tools
104 lines
3.0 KiB
Python
104 lines
3.0 KiB
Python
"""
|
|
Configuration loader for ircquotes application.
|
|
Loads settings from config.json and provides easy access to configuration values.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
from typing import Any, Dict
|
|
|
|
class Config:
|
|
"""Configuration manager for ircquotes application."""
|
|
|
|
def __init__(self, config_file: str = "config.json"):
|
|
"""Initialize configuration from JSON file."""
|
|
self.config_file = config_file
|
|
self._config = self._load_config()
|
|
|
|
def _load_config(self) -> Dict[str, Any]:
|
|
"""Load configuration from JSON file."""
|
|
if not os.path.exists(self.config_file):
|
|
raise FileNotFoundError(f"Configuration file {self.config_file} not found")
|
|
|
|
try:
|
|
with open(self.config_file, 'r', encoding='utf-8') as f:
|
|
return json.load(f)
|
|
except json.JSONDecodeError as e:
|
|
raise ValueError(f"Invalid JSON in configuration file: {e}")
|
|
|
|
def get(self, key: str, default: Any = None) -> Any:
|
|
"""Get configuration value using dot notation (e.g., 'app.host')."""
|
|
keys = key.split('.')
|
|
value = self._config
|
|
|
|
for k in keys:
|
|
if isinstance(value, dict) and k in value:
|
|
value = value[k]
|
|
else:
|
|
return default
|
|
|
|
return value
|
|
|
|
def get_section(self, section: str) -> Dict[str, Any]:
|
|
"""Get entire configuration section."""
|
|
return self._config.get(section, {})
|
|
|
|
def reload(self):
|
|
"""Reload configuration from file."""
|
|
self._config = self._load_config()
|
|
|
|
# Convenience properties for commonly used settings
|
|
@property
|
|
def app_name(self) -> str:
|
|
return self.get('app.name', 'ircquotes')
|
|
|
|
@property
|
|
def app_host(self) -> str:
|
|
return self.get('app.host', '0.0.0.0')
|
|
|
|
@property
|
|
def app_port(self) -> int:
|
|
return self.get('app.port', 5050)
|
|
|
|
@property
|
|
def debug_mode(self) -> bool:
|
|
return self.get('app.debug', False)
|
|
|
|
@property
|
|
def database_uri(self) -> str:
|
|
return self.get('database.uri', 'sqlite:///quotes.db')
|
|
|
|
@property
|
|
def csrf_enabled(self) -> bool:
|
|
return self.get('security.csrf_enabled', True)
|
|
|
|
@property
|
|
def rate_limiting_enabled(self) -> bool:
|
|
return self.get('rate_limiting.enabled', True)
|
|
|
|
@property
|
|
def quotes_per_page(self) -> int:
|
|
return self.get('quotes.per_page', 25)
|
|
|
|
@property
|
|
def min_quote_length(self) -> int:
|
|
return self.get('quotes.min_length', 10)
|
|
|
|
@property
|
|
def max_quote_length(self) -> int:
|
|
return self.get('quotes.max_length', 5000)
|
|
|
|
@property
|
|
def admin_username(self) -> str:
|
|
return self.get('admin.username', 'admin')
|
|
|
|
@property
|
|
def admin_password_hash(self) -> str:
|
|
return self.get('admin.password_hash', '')
|
|
|
|
@property
|
|
def logging_level(self) -> str:
|
|
return self.get('logging.level', 'WARNING')
|
|
|
|
# Global configuration instance
|
|
config = Config() |