#!/usr/bin/env python3
"""API Web Sentinel avec installation automatique des dépendances."""

import subprocess
import sys

# Installer les dépendances
print("🔧 Installation des dépendances Flask...")
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'Flask', 'Flask-CORS'])

from flask import Flask, request, jsonify
from flask_cors import CORS
import os
import re
from datetime import datetime
import logging

# Configuration
app = Flask(__name__)
CORS(app)

# Configuration du logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

print("=== Web Sentinel API SAST v2.0 ===")

# Patterns de vulnérabilités SAST
VULNERABILITY_PATTERNS = {
    'python': [
        {
            'pattern': r'eval\s*\(',
            'severity': 'critical',
            'title': 'Utilisation dangereuse d\'eval()',
            'description': 'L\'utilisation d\'eval() peut permettre l\'exécution de code arbitraire'
        },
        {
            'pattern': r'exec\s*\(',
            'severity': 'critical',
            'title': 'Utilisation dangereuse d\'exec()',
            'description': 'L\'utilisation d\'exec() peut permettre l\'exécution de code arbitraire'
        },
        {
            'pattern': r'os\.system\s*\(',
            'severity': 'high',
            'title': 'Injection de commande potentielle',
            'description': 'os.system() peut être vulnérable aux injections de commandes'
        },
        {
            'pattern': r'subprocess\.call\s*\(',
            'severity': 'medium',
            'title': 'Appel de sous-processus non sécurisé',
            'description': 'subprocess.call() sans validation peut être dangereux'
        },
        {
            'pattern': r'(password|secret|key|token)\s*=\s*["\'][^"\']+["\']',
            'severity': 'high',
            'title': 'Secrets codés en dur détectés',
            'description': 'Des secrets ou mots de passe sont codés en dur dans le code'
        },
        {
            'pattern': r'SELECT\s+.*\s+FROM\s+.*\s+WHERE\s+.*=\s*["\']?\s*\+',
            'severity': 'critical',
            'title': 'Injection SQL potentielle',
            'description': 'Requête SQL construite par concaténation de chaînes'
        }
    ],
    'javascript': [
        {
            'pattern': r'eval\s*\(',
            'severity': 'critical',
            'title': 'Utilisation dangereuse d\'eval()',
            'description': 'eval() peut exécuter du code JavaScript malveillant'
        },
        {
            'pattern': r'innerHTML\s*=\s*.*\+',
            'severity': 'high',
            'title': 'XSS potentiel avec innerHTML',
            'description': 'innerHTML avec du contenu non échappé peut causer des XSS'
        },
        {
            'pattern': r'document\.write\s*\(',
            'severity': 'medium',
            'title': 'Utilisation de document.write',
            'description': 'document.write() peut être vulnérable aux injections'
        }
    ],
    'php': [
        {
            'pattern': r'eval\s*\(',
            'severity': 'critical',
            'title': 'Utilisation dangereuse d\'eval()',
            'description': 'eval() permet l\'exécution de code PHP arbitraire'
        },
        {
            'pattern': r'\$_(GET|POST|REQUEST)\[.*\].*mysql_query',
            'severity': 'critical',
            'title': 'Injection SQL directe',
            'description': 'Données utilisateur directement dans une requête SQL'
        },
        {
            'pattern': r'echo\s+\$_(GET|POST|REQUEST)',
            'severity': 'high',
            'title': 'XSS potentiel',
            'description': 'Affichage direct de données utilisateur sans échappement'
        }
    ]
}

def validate_api_key_mock(api_key):
    """Validation des clés API (version mock pour démo)."""
    # Aurelien's SYSOP key
    if api_key == "ws_sysop_CUsMkeL6jdDHXrA14rot9Vj0Yegg4KiPuYqiHMKhRC0":
        return {
            'valid': True,
            'user': 'aurelien.mossini@example.com',
            'tier': 'sysop',
            'can_scan_source': True
        }
    
    return {'valid': False, 'error': 'Clé API invalide'}

def analyze_source_code(code, language='python'):
    """Analyse le code source pour détecter les vulnérabilités."""
    vulnerabilities = []
    
    if language not in VULNERABILITY_PATTERNS:
        return vulnerabilities
    
    lines = code.split('\n')
    patterns = VULNERABILITY_PATTERNS[language]
    
    for line_num, line in enumerate(lines, 1):
        for pattern_info in patterns:
            if re.search(pattern_info['pattern'], line, re.IGNORECASE):
                vulnerabilities.append({
                    'line': line_num,
                    'severity': pattern_info['severity'],
                    'title': pattern_info['title'],
                    'description': pattern_info['description'],
                    'code_snippet': line.strip()
                })
    
    return vulnerabilities

@app.route('/health', methods=['GET'])
def health_check():
    """Point de terminaison de santé."""
    return jsonify({
        'status': 'healthy',
        'timestamp': datetime.now().isoformat(),
        'version': '2.0'
    })

@app.route('/api/v1/scan', methods=['POST'])
def scan_source():
    """Scanner le code source pour les vulnérabilités."""
    # Validation de la clé API
    api_key = request.headers.get('X-API-Key')
    if not api_key:
        return jsonify({'error': 'Clé API manquante'}), 401
    
    auth_result = validate_api_key_mock(api_key)
    if not auth_result['valid']:
        return jsonify({'error': auth_result.get('error', 'Non autorisé')}), 401
    
    if not auth_result.get('can_scan_source'):
        return jsonify({'error': 'Tier insuffisant pour le scan de code'}), 403
    
    # Récupération des données
    try:
        data = request.get_json()
        code = data.get('code', '')
        language = data.get('language', 'python')
        filename = data.get('filename', 'unknown')
    except Exception as e:
        return jsonify({'error': f'Données JSON invalides: {str(e)}'}), 400
    
    if not code:
        return jsonify({'error': 'Code source manquant'}), 400
    
    # Analyse des vulnérabilités
    vulnerabilities = analyze_source_code(code, language)
    
    # Statistiques
    severity_counts = {'critical': 0, 'high': 0, 'medium': 0, 'low': 0}
    for vuln in vulnerabilities:
        severity = vuln.get('severity', 'low')
        if severity in severity_counts:
            severity_counts[severity] += 1
    
    logger.info(f"Scan effectué par {auth_result['user']} sur {filename}: {len(vulnerabilities)} vulnérabilités trouvées")
    
    return jsonify({
        'success': True,
        'filename': filename,
        'language': language,
        'vulnerabilities': vulnerabilities,
        'summary': {
            'total_vulnerabilities': len(vulnerabilities),
            'severity_breakdown': severity_counts
        },
        'scanned_by': auth_result['user'],
        'scan_timestamp': datetime.now().isoformat()
    })

@app.route('/api/v1/user', methods=['GET'])
def get_user_info():
    """Obtenir les informations utilisateur."""
    api_key = request.headers.get('X-API-Key')
    if not api_key:
        return jsonify({'error': 'Clé API manquante'}), 401
    
    auth_result = validate_api_key_mock(api_key)
    if not auth_result['valid']:
        return jsonify({'error': 'Non autorisé'}), 401
    
    return jsonify({
        'user': auth_result['user'],
        'tier': auth_result['tier'],
        'permissions': {
            'can_scan_source': auth_result.get('can_scan_source', False)
        }
    })

@app.route('/api/v1/stats', methods=['GET'])
def get_stats():
    """Statistiques de l'API."""
    return jsonify({
        'total_scans': 1337,
        'active_users': 42,
        'vulnerabilities_found': 9001,
        'uptime': '99.9%',
        'version': '2.0'
    })

@app.route('/api/v1/modules', methods=['GET'])
def get_modules():
    """Liste des modules de scan disponibles."""
    return jsonify({
        'modules': [
            {'name': 'python', 'description': 'Scanner Python SAST', 'enabled': True},
            {'name': 'javascript', 'description': 'Scanner JavaScript SAST', 'enabled': True},
            {'name': 'php', 'description': 'Scanner PHP SAST', 'enabled': True}
        ],
        'total': 3
    })

@app.route('/api/v1/health', methods=['GET'])
def api_health():
    """Point de santé pour l'API (différent du endpoint racine)."""
    return jsonify({
        'status': 'healthy',
        'api_version': '2.0',
        'timestamp': datetime.now().isoformat(),
        'services': {
            'sast_scanner': 'operational',
            'auth': 'operational'
        }
    })

# Configuration des clés API disponibles
print("Clés API disponibles:")
print("  - ws_sysop_CUsMkeL6jdD... (aurelien.mossini@example.com, tier: sysop)")

print("Patterns de vulnérabilités chargés pour:", ', '.join(VULNERABILITY_PATTERNS.keys()))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)