🚀 Major Enhancement: Complete AI-Powered LifeRPG Platform with Git LFS
✨ New Features: - AI-powered habit creation with natural language processing - HuggingFace transformers integration for sentiment analysis (tracked via Git LFS) - Advanced predictive analytics and behavioral insights - Voice & image input capabilities for hands-free habit tracking - Real-time notifications and community features - Plugin system with extensible architecture 🔧 Technical Improvements: - Comprehensive FastAPI backend with 30+ endpoints - React frontend with PWA capabilities - Advanced authentication with 2FA support - RBAC authorization system - Comprehensive security features (CSRF, rate limiting, audit logging) - Database migrations and health monitoring - Docker containerization support - Git LFS configured for large AI model files (2+ GB) 📚 Documentation & DevOps: - Complete deployment guides for multiple platforms - Professional README with feature highlights - GitHub Actions CI/CD workflows - Comprehensive API documentation - Security audit roadmap and compliance framework - Setup scripts for development environment 🧪 Testing & Quality: - Comprehensive test suite with 20+ test modules - Setup verification scripts - Working development environment with both backend and frontend - Health checks and monitoring systems 🌟 Ready for: - Portfolio showcasing - Community contributions - Production deployment - Professional presentation
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
"""
|
||||
Secure logging utilities that sanitize sensitive data
|
||||
"""
|
||||
import logging
|
||||
import re
|
||||
import json
|
||||
from typing import Any, Dict, Union
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class SecureLogger:
|
||||
"""Logger that automatically sanitizes sensitive data"""
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.logger = logging.getLogger(name)
|
||||
|
||||
# Patterns for sensitive data detection
|
||||
self.sensitive_patterns = {
|
||||
'password': [
|
||||
r'password["\']?\s*[:=]\s*["\']?([^"\';\s]+)',
|
||||
r'pwd["\']?\s*[:=]\s*["\']?([^"\';\s]+)',
|
||||
r'passwd["\']?\s*[:=]\s*["\']?([^"\';\s]+)',
|
||||
],
|
||||
'token': [
|
||||
r'token["\']?\s*[:=]\s*["\']?([A-Za-z0-9+/=]{20,})',
|
||||
r'jwt["\']?\s*[:=]\s*["\']?([A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)',
|
||||
r'bearer\s+([A-Za-z0-9+/=]{20,})',
|
||||
],
|
||||
'api_key': [
|
||||
r'api[_-]?key["\']?\s*[:=]\s*["\']?([A-Za-z0-9]{16,})',
|
||||
r'secret[_-]?key["\']?\s*[:=]\s*["\']?([A-Za-z0-9]{16,})',
|
||||
],
|
||||
'email': [
|
||||
r'([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})',
|
||||
],
|
||||
'phone': [
|
||||
r'(\+?1?[-.\s]?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4})',
|
||||
],
|
||||
'ssn': [
|
||||
r'(\d{3}-?\d{2}-?\d{4})',
|
||||
],
|
||||
'credit_card': [
|
||||
r'(\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4})',
|
||||
],
|
||||
'private_key': [
|
||||
r'(-----BEGIN PRIVATE KEY-----.*?-----END PRIVATE KEY-----)',
|
||||
r'(-----BEGIN RSA PRIVATE KEY-----.*?-----END RSA PRIVATE KEY-----)',
|
||||
]
|
||||
}
|
||||
|
||||
def sanitize_message(self, message: str) -> str:
|
||||
"""Sanitize sensitive data from log message"""
|
||||
sanitized = message
|
||||
|
||||
for data_type, patterns in self.sensitive_patterns.items():
|
||||
for pattern in patterns:
|
||||
# Replace sensitive data with placeholder
|
||||
sanitized = re.sub(
|
||||
pattern,
|
||||
lambda m: f'[REDACTED_{data_type.upper()}]',
|
||||
sanitized,
|
||||
flags=re.IGNORECASE | re.DOTALL
|
||||
)
|
||||
|
||||
return sanitized
|
||||
|
||||
def sanitize_data(self, data: Any) -> Any:
|
||||
"""Recursively sanitize data structures"""
|
||||
if isinstance(data, dict):
|
||||
sanitized = {}
|
||||
for key, value in data.items():
|
||||
# Sanitize key names that might contain sensitive info
|
||||
safe_key = self.sanitize_message(str(key))
|
||||
# Recursively sanitize values
|
||||
safe_value = self.sanitize_data(value)
|
||||
sanitized[safe_key] = safe_value
|
||||
return sanitized
|
||||
|
||||
elif isinstance(data, list):
|
||||
return [self.sanitize_data(item) for item in data]
|
||||
|
||||
elif isinstance(data, str):
|
||||
return self.sanitize_message(data)
|
||||
|
||||
else:
|
||||
return data
|
||||
|
||||
def _log_with_sanitization(self, level: int, message: str, *args, **kwargs):
|
||||
"""Internal method to log with sanitization"""
|
||||
# Sanitize the message
|
||||
safe_message = self.sanitize_message(message)
|
||||
|
||||
# Sanitize args
|
||||
safe_args = tuple(self.sanitize_data(arg) for arg in args)
|
||||
|
||||
# Sanitize kwargs
|
||||
safe_kwargs = self.sanitize_data(kwargs)
|
||||
|
||||
# Log with sanitized data
|
||||
self.logger.log(level, safe_message, *safe_args, **safe_kwargs)
|
||||
|
||||
def debug(self, message: str, *args, **kwargs):
|
||||
"""Debug level logging with sanitization"""
|
||||
self._log_with_sanitization(logging.DEBUG, message, *args, **kwargs)
|
||||
|
||||
def info(self, message: str, *args, **kwargs):
|
||||
"""Info level logging with sanitization"""
|
||||
self._log_with_sanitization(logging.INFO, message, *args, **kwargs)
|
||||
|
||||
def warning(self, message: str, *args, **kwargs):
|
||||
"""Warning level logging with sanitization"""
|
||||
self._log_with_sanitization(logging.WARNING, message, *args, **kwargs)
|
||||
|
||||
def error(self, message: str, *args, **kwargs):
|
||||
"""Error level logging with sanitization"""
|
||||
self._log_with_sanitization(logging.ERROR, message, *args, **kwargs)
|
||||
|
||||
def critical(self, message: str, *args, **kwargs):
|
||||
"""Critical level logging with sanitization"""
|
||||
self._log_with_sanitization(logging.CRITICAL, message, *args, **kwargs)
|
||||
|
||||
def log_request(self, request_data: Dict[str, Any]):
|
||||
"""Log HTTP request with sanitization"""
|
||||
safe_data = self.sanitize_data({
|
||||
'method': request_data.get('method'),
|
||||
'path': request_data.get('path'),
|
||||
'user_agent': request_data.get('user_agent'),
|
||||
'ip_address_hash': request_data.get('ip_hash'),
|
||||
'timestamp': datetime.utcnow().isoformat(),
|
||||
'headers': {k: v for k, v in request_data.get('headers', {}).items()
|
||||
if k.lower() not in ['authorization', 'cookie']},
|
||||
})
|
||||
|
||||
self.info(f"HTTP Request: {json.dumps(safe_data)}")
|
||||
|
||||
def log_auth_event(self, event_data: Dict[str, Any]):
|
||||
"""Log authentication events with sanitization"""
|
||||
safe_data = self.sanitize_data({
|
||||
'event_type': event_data.get('event_type'),
|
||||
'user_id_hash': event_data.get('user_id_hash'),
|
||||
'ip_address_hash': event_data.get('ip_hash'),
|
||||
'success': event_data.get('success'),
|
||||
'timestamp': datetime.utcnow().isoformat(),
|
||||
'details': event_data.get('details', {}),
|
||||
})
|
||||
|
||||
level = logging.INFO if event_data.get('success') else logging.WARNING
|
||||
self._log_with_sanitization(level, f"Auth Event: {json.dumps(safe_data)}")
|
||||
|
||||
|
||||
class StructuredLogFormatter(logging.Formatter):
|
||||
"""Structured logging formatter for security events"""
|
||||
|
||||
def format(self, record):
|
||||
# Create structured log entry
|
||||
log_entry = {
|
||||
'timestamp': datetime.utcnow().isoformat(),
|
||||
'level': record.levelname,
|
||||
'logger': record.name,
|
||||
'message': record.getMessage(),
|
||||
'module': record.module,
|
||||
'function': record.funcName,
|
||||
'line': record.lineno,
|
||||
}
|
||||
|
||||
# Add extra fields if present
|
||||
if hasattr(record, 'user_id'):
|
||||
log_entry['user_id'] = record.user_id
|
||||
if hasattr(record, 'request_id'):
|
||||
log_entry['request_id'] = record.request_id
|
||||
if hasattr(record, 'ip_address'):
|
||||
log_entry['ip_address'] = record.ip_address
|
||||
|
||||
return json.dumps(log_entry)
|
||||
|
||||
|
||||
# Global secure loggers for different components
|
||||
auth_logger = SecureLogger('liferpg.auth')
|
||||
api_logger = SecureLogger('liferpg.api')
|
||||
security_logger = SecureLogger('liferpg.security')
|
||||
plugin_logger = SecureLogger('liferpg.plugins')
|
||||
|
||||
|
||||
def setup_secure_logging():
|
||||
"""Setup secure logging configuration"""
|
||||
# Create structured formatter
|
||||
formatter = StructuredLogFormatter()
|
||||
|
||||
# Setup handler
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
# Configure root logger
|
||||
root_logger = logging.getLogger('liferpg')
|
||||
root_logger.setLevel(logging.INFO)
|
||||
root_logger.addHandler(handler)
|
||||
|
||||
# Prevent duplicate logs
|
||||
root_logger.propagate = False
|
||||
Reference in New Issue
Block a user