234 lines
8 KiB
Python
234 lines
8 KiB
Python
"""
|
|
Configuration module for Domain Check API
|
|
"""
|
|
import os
|
|
from datetime import timedelta
|
|
from typing import Dict, Any
|
|
|
|
|
|
class Config:
|
|
"""Base configuration"""
|
|
|
|
# Flask
|
|
SECRET_KEY = os.getenv('SECRET_KEY', 'dev-secret-key-change-in-production')
|
|
DEBUG = False
|
|
TESTING = False
|
|
|
|
# Database
|
|
SQLALCHEMY_DATABASE_URI = os.getenv(
|
|
'DATABASE_URL',
|
|
'postgresql://dns_admin:password@localhost:5432/domain_check'
|
|
)
|
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
SQLALCHEMY_ECHO = False
|
|
SQLALCHEMY_POOL_SIZE = 10
|
|
SQLALCHEMY_POOL_TIMEOUT = 30
|
|
SQLALCHEMY_POOL_RECYCLE = 3600
|
|
SQLALCHEMY_MAX_OVERFLOW = 20
|
|
|
|
# Redis
|
|
REDIS_URL = os.getenv('REDIS_URL', 'redis://localhost:6379/0')
|
|
REDIS_TTL_HOT = int(os.getenv('REDIS_TTL_HOT', 21600)) # 6 hours
|
|
REDIS_TTL_WARM = int(os.getenv('REDIS_TTL_WARM', 86400)) # 24 hours
|
|
REDIS_TTL_COLD = int(os.getenv('REDIS_TTL_COLD', 604800)) # 7 days
|
|
|
|
# Celery
|
|
CELERY_BROKER_URL = os.getenv('CELERY_BROKER_URL', 'redis://localhost:6379/1')
|
|
CELERY_RESULT_BACKEND = os.getenv('CELERY_RESULT_BACKEND', 'redis://localhost:6379/2')
|
|
CELERY_TASK_SERIALIZER = 'json'
|
|
CELERY_RESULT_SERIALIZER = 'json'
|
|
CELERY_ACCEPT_CONTENT = ['json']
|
|
CELERY_TIMEZONE = 'UTC'
|
|
CELERY_ENABLE_UTC = True
|
|
CELERY_TASK_TRACK_STARTED = True
|
|
CELERY_TASK_TIME_LIMIT = 300 # 5 minutes
|
|
CELERY_TASK_SOFT_TIME_LIMIT = 240 # 4 minutes
|
|
|
|
# API Keys
|
|
WHOXY_API_KEY = os.getenv('WHOXY_API_KEY', '')
|
|
VIRUSTOTAL_API_KEY = os.getenv('VIRUSTOTAL_API_KEY', '')
|
|
|
|
# Risk Scoring Thresholds
|
|
RISK_THRESHOLD_LOW = int(os.getenv('RISK_THRESHOLD_LOW', 30))
|
|
RISK_THRESHOLD_MEDIUM = int(os.getenv('RISK_THRESHOLD_MEDIUM', 60))
|
|
RISK_THRESHOLD_HIGH = int(os.getenv('RISK_THRESHOLD_HIGH', 85))
|
|
|
|
# Domain Age Thresholds (days)
|
|
DOMAIN_AGE_CRITICAL = int(os.getenv('DOMAIN_AGE_CRITICAL', 90)) # 3 months
|
|
DOMAIN_AGE_HIGH = int(os.getenv('DOMAIN_AGE_HIGH', 180)) # 6 months
|
|
DOMAIN_AGE_MEDIUM = int(os.getenv('DOMAIN_AGE_MEDIUM', 365)) # 1 year
|
|
|
|
# API Rate Limiting
|
|
WHOXY_DAILY_LIMIT = int(os.getenv('WHOXY_DAILY_LIMIT', 8000))
|
|
VIRUSTOTAL_DAILY_LIMIT = int(os.getenv('VIRUSTOTAL_DAILY_LIMIT', 500))
|
|
|
|
# Batch Processing
|
|
BATCH_CHUNK_SIZE = int(os.getenv('BATCH_CHUNK_SIZE', 50))
|
|
BATCH_TIMEOUT_SECONDS = int(os.getenv('BATCH_TIMEOUT_SECONDS', 300))
|
|
|
|
# API Settings
|
|
API_VERSION = os.getenv('API_VERSION', 'v1')
|
|
API_TITLE = 'Domain Check API - Anti-Fake News Tool'
|
|
API_DESCRIPTION = '''
|
|
**Comprehensive Domain Verification & Risk Scoring API**
|
|
|
|
This API provides powerful tools for detecting potentially malicious or newly-registered domains
|
|
commonly used in disinformation campaigns and fake news distribution.
|
|
|
|
## 🎯 Key Features
|
|
|
|
- **WHOIS Analysis**: Domain age, registrar information, privacy protection detection
|
|
- **DNS Verification**: A, AAAA, MX, TXT, NS, CNAME, SOA records with email security (SPF, DKIM, DMARC)
|
|
- **SSL Certificate Validation**: Certificate validity, issuer verification, expiration monitoring
|
|
- **Risk Scoring**: Multi-factor algorithm (0-100) with detailed breakdown
|
|
- **Comprehensive Database**: Full history tracking and audit trail
|
|
|
|
## 📊 Risk Levels
|
|
|
|
- **LOW (0-30)**: Established, trustworthy domains
|
|
- **MEDIUM (31-60)**: Moderate risk, requires attention
|
|
- **HIGH (61-85)**: Suspicious activity detected
|
|
- **CRITICAL (86-100)**: Newly registered or highly suspicious domains
|
|
|
|
## 🚀 Quick Start
|
|
|
|
Use the `/check` endpoint to verify any domain:
|
|
|
|
```bash
|
|
curl -X POST http://domain-check-api:11000/api/v1/check/check \\
|
|
-H "Content-Type: application/json" \\
|
|
-d '{"domain": "example.com", "check_options": {"whois": true, "dns": true}}'
|
|
```
|
|
|
|
## 📖 Documentation
|
|
|
|
- **Swagger UI**: Interactive API testing and documentation
|
|
- **ReDoc**: Clean, responsive API reference
|
|
- **Platformă**: modul T4 (evaluare credibilitate sursă) al platformei DIDI
|
|
'''
|
|
API_CONTACT = {
|
|
'name': 'DIDI Domain Check',
|
|
'email': 'support@didi.local'
|
|
}
|
|
API_LICENSE = {
|
|
'name': 'MIT',
|
|
'url': 'https://opensource.org/licenses/MIT'
|
|
}
|
|
API_TERMS_OF_SERVICE = ''
|
|
|
|
# CORS - use CORS_ORIGINS env var for production (comma-separated)
|
|
# Example: CORS_ORIGINS=https://didi.example.ro,https://admin.didi.example.ro
|
|
# Default '*' allows all origins (development only!)
|
|
_cors_origins_env = os.getenv('CORS_ORIGINS', '*')
|
|
CORS_ORIGINS = ['*'] if _cors_origins_env == '*' else [o.strip() for o in _cors_origins_env.split(',') if o.strip()]
|
|
CORS_ALLOW_HEADERS = ['Content-Type', 'Authorization']
|
|
CORS_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
|
|
|
|
# Security - Documentation endpoints
|
|
# Set DISABLE_SWAGGER=true in production to hide /docs and /redoc
|
|
DISABLE_SWAGGER = os.getenv('DISABLE_SWAGGER', 'false').lower() == 'true'
|
|
|
|
# Health endpoint - set SIMPLE_HEALTH=true to return only {"status":"ok"}
|
|
SIMPLE_HEALTH = os.getenv('SIMPLE_HEALTH', 'false').lower() == 'true'
|
|
|
|
# Logging
|
|
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
|
|
LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
LOG_FILE = os.path.join(os.path.dirname(__file__), '..', 'logs', 'api.log')
|
|
|
|
# External Service URLs
|
|
WHOXY_API_URL = 'https://api.whoxy.com/'
|
|
VIRUSTOTAL_API_URL = 'https://www.virustotal.com/api/v3/'
|
|
RDAP_BOOTSTRAP_URL = 'https://rdap.org/'
|
|
|
|
# Risk Scoring Weights
|
|
RISK_WEIGHT_DOMAIN_AGE = 0.30
|
|
RISK_WEIGHT_REPUTATION = 0.30
|
|
RISK_WEIGHT_SSL = 0.20
|
|
RISK_WEIGHT_DNS = 0.10
|
|
RISK_WEIGHT_WHOIS = 0.10
|
|
|
|
# Pagination
|
|
DEFAULT_PAGE_SIZE = 50
|
|
MAX_PAGE_SIZE = 100
|
|
|
|
# Timeouts (seconds)
|
|
HTTP_TIMEOUT = 30
|
|
DNS_TIMEOUT = 10
|
|
SSL_TIMEOUT = 10
|
|
|
|
@staticmethod
|
|
def init_app(app):
|
|
"""Initialize application configuration"""
|
|
# Create logs directory if it doesn't exist
|
|
log_dir = os.path.dirname(Config.LOG_FILE)
|
|
os.makedirs(log_dir, exist_ok=True)
|
|
|
|
|
|
class DevelopmentConfig(Config):
|
|
"""Development configuration"""
|
|
DEBUG = True
|
|
SQLALCHEMY_ECHO = False
|
|
LOG_LEVEL = 'DEBUG'
|
|
|
|
|
|
class ProductionConfig(Config):
|
|
"""Production configuration"""
|
|
DEBUG = False
|
|
TESTING = False
|
|
SQLALCHEMY_ECHO = False
|
|
LOG_LEVEL = 'WARNING'
|
|
|
|
# Production security defaults (can be overridden by env vars)
|
|
# If CORS_ORIGINS not set, default to empty (blocks all cross-origin)
|
|
_cors_origins_env = os.getenv('CORS_ORIGINS', '')
|
|
CORS_ORIGINS = [o.strip() for o in _cors_origins_env.split(',') if o.strip()] if _cors_origins_env else []
|
|
|
|
# Disable swagger by default in production (override with DISABLE_SWAGGER=false)
|
|
DISABLE_SWAGGER = os.getenv('DISABLE_SWAGGER', 'true').lower() != 'false'
|
|
|
|
# Simple health by default in production
|
|
SIMPLE_HEALTH = os.getenv('SIMPLE_HEALTH', 'true').lower() != 'false'
|
|
|
|
@classmethod
|
|
def init_app(cls, app):
|
|
Config.init_app(app)
|
|
|
|
# Production-specific initialization
|
|
import logging
|
|
from logging.handlers import RotatingFileHandler
|
|
|
|
# Setup file handler with rotation
|
|
file_handler = RotatingFileHandler(
|
|
cls.LOG_FILE,
|
|
maxBytes=10485760, # 10MB
|
|
backupCount=10
|
|
)
|
|
file_handler.setLevel(logging.WARNING)
|
|
file_handler.setFormatter(logging.Formatter(cls.LOG_FORMAT))
|
|
app.logger.addHandler(file_handler)
|
|
|
|
|
|
class TestingConfig(Config):
|
|
"""Testing configuration"""
|
|
TESTING = True
|
|
DEBUG = True
|
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
|
|
REDIS_URL = 'redis://localhost:6379/15' # Use separate Redis DB for testing
|
|
WTF_CSRF_ENABLED = False
|
|
|
|
|
|
# Configuration dictionary
|
|
config: Dict[str, Any] = {
|
|
'development': DevelopmentConfig,
|
|
'production': ProductionConfig,
|
|
'testing': TestingConfig,
|
|
'default': DevelopmentConfig
|
|
}
|
|
|
|
|
|
def get_config(env: str = None) -> Config:
|
|
"""Get configuration based on environment"""
|
|
if env is None:
|
|
env = os.getenv('FLASK_ENV', 'development')
|
|
return config.get(env, config['default'])
|