stealth_features.py•16.1 kB
"""
Módulo de características avanzadas para evasión de detección.
"""
import time
import random
import json
from typing import Dict, Any, Optional, List
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.common.exceptions import WebDriverException
from session_manager import SessionManager
class StealthFeatures:
"""Características avanzadas para evasión de detección."""
def __init__(self, session_manager: SessionManager):
self.session_manager = session_manager
# Scripts para evasión de detección
self.stealth_scripts = {
"webdriver_property": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined,
});
""",
"chrome_runtime": """
window.chrome = {
runtime: {},
};
""",
"permissions": """
const originalQuery = window.navigator.permissions.query;
return window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
""",
"plugins": """
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5],
});
""",
"languages": """
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en'],
});
""",
"webgl_vendor": """
const getParameter = WebGLRenderingContext.getParameter;
WebGLRenderingContext.prototype.getParameter = function(parameter) {
if (parameter === 37445) {
return 'Intel Inc.';
}
if (parameter === 37446) {
return 'Intel Iris OpenGL Engine';
}
return getParameter(parameter);
};
""",
"iframe_contentWindow": """
try {
if (window.outerHeight === 0) {
window.outerHeight = window.innerHeight;
}
if (window.outerWidth === 0) {
window.outerWidth = window.innerWidth;
}
} catch (e) {}
""",
"hairline": """
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
get: function() {
if (this.id === 'modernizr') {
return 1;
}
return this.getBoundingClientRect().height;
}
});
"""
}
# User agents realistas
self.realistic_user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/121.0"
]
# Resoluciones de pantalla comunes
self.common_resolutions = [
(1920, 1080),
(1366, 768),
(1536, 864),
(1440, 900),
(1280, 720),
(1600, 900),
(1024, 768),
(1280, 1024)
]
def apply_stealth_mode(self, session_id: str) -> Dict[str, Any]:
"""Aplica todas las técnicas de evasión de detección a una sesión."""
session = self.session_manager.get_session(session_id)
if not session:
return {"success": False, "error": "Sesión no encontrada"}
try:
applied_scripts = []
# Aplicar scripts de evasión
for script_name, script_code in self.stealth_scripts.items():
try:
session.driver.execute_script(script_code)
applied_scripts.append(script_name)
except Exception as e:
# Continuar aunque algunos scripts fallen
pass
# Configurar propiedades adicionales
self._set_navigator_properties(session.driver)
return {
"success": True,
"applied_scripts": applied_scripts,
"message": "Modo stealth aplicado exitosamente"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": "Error al aplicar modo stealth"
}
def randomize_user_agent(self, session_id: str) -> Dict[str, Any]:
"""Cambia el user agent a uno aleatorio."""
session = self.session_manager.get_session(session_id)
if not session:
return {"success": False, "error": "Sesión no encontrada"}
try:
new_user_agent = random.choice(self.realistic_user_agents)
# Cambiar user agent via JavaScript
script = f"""
Object.defineProperty(navigator, 'userAgent', {{
get: () => '{new_user_agent}',
}});
"""
session.driver.execute_script(script)
return {
"success": True,
"new_user_agent": new_user_agent,
"message": "User agent randomizado exitosamente"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": "Error al randomizar user agent"
}
def randomize_viewport(self, session_id: str) -> Dict[str, Any]:
"""Cambia el tamaño de la ventana a una resolución aleatoria."""
session = self.session_manager.get_session(session_id)
if not session:
return {"success": False, "error": "Sesión no encontrada"}
try:
width, height = random.choice(self.common_resolutions)
# Agregar variación aleatoria
width += random.randint(-50, 50)
height += random.randint(-30, 30)
session.driver.set_window_size(width, height)
return {
"success": True,
"new_size": {"width": width, "height": height},
"message": "Viewport randomizado exitosamente"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": "Error al randomizar viewport"
}
def manage_cookies(
self,
session_id: str,
action: str,
cookie_data: Optional[Dict[str, Any]] = None,
cookie_name: Optional[str] = None
) -> Dict[str, Any]:
"""Gestiona cookies de la sesión."""
session = self.session_manager.get_session(session_id)
if not session:
return {"success": False, "error": "Sesión no encontrada"}
try:
if action == "get_all":
cookies = session.driver.get_cookies()
return {
"success": True,
"cookies": cookies,
"count": len(cookies),
"message": f"Obtenidas {len(cookies)} cookies"
}
elif action == "add":
if not cookie_data:
return {"success": False, "error": "cookie_data requerido para agregar"}
session.driver.add_cookie(cookie_data)
return {
"success": True,
"message": f"Cookie '{cookie_data.get('name')}' agregada"
}
elif action == "delete":
if cookie_name:
session.driver.delete_cookie(cookie_name)
return {
"success": True,
"message": f"Cookie '{cookie_name}' eliminada"
}
else:
session.driver.delete_all_cookies()
return {
"success": True,
"message": "Todas las cookies eliminadas"
}
elif action == "get":
if not cookie_name:
return {"success": False, "error": "cookie_name requerido para obtener"}
cookie = session.driver.get_cookie(cookie_name)
return {
"success": True,
"cookie": cookie,
"message": f"Cookie '{cookie_name}' obtenida"
}
else:
return {
"success": False,
"error": f"Acción no válida: {action}. Disponibles: get_all, add, delete, get"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": f"Error al gestionar cookies: {action}"
}
def add_random_delay(
self,
min_seconds: float = 0.5,
max_seconds: float = 2.0
) -> Dict[str, Any]:
"""Agrega un delay aleatorio entre acciones."""
try:
delay = random.uniform(min_seconds, max_seconds)
time.sleep(delay)
return {
"success": True,
"delay_seconds": round(delay, 2),
"message": f"Delay de {round(delay, 2)} segundos aplicado"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": "Error al aplicar delay"
}
def simulate_human_typing(
self,
session_id: str,
strategy: str,
value: str,
text: str,
min_delay: float = 0.05,
max_delay: float = 0.15,
element_index: int = 0
) -> Dict[str, Any]:
"""Simula escritura humana con delays aleatorios entre teclas."""
session = self.session_manager.get_session(session_id)
if not session:
return {"success": False, "error": "Sesión no encontrada"}
try:
# Importar herramientas de selenium para encontrar elemento
from selenium_tools import SeleniumTools
selenium_tools = SeleniumTools(self.session_manager)
# Encontrar elemento
element = selenium_tools._find_element_helper(
session.driver, strategy, value, 10, element_index
)
# Limpiar campo
element.clear()
# Escribir caracter por caracter con delays
for char in text:
element.send_keys(char)
delay = random.uniform(min_delay, max_delay)
time.sleep(delay)
return {
"success": True,
"text_typed": text,
"characters": len(text),
"message": "Texto escrito con simulación humana"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": "Error al simular escritura humana"
}
def scroll_like_human(
self,
session_id: str,
direction: str = "down",
distance: int = 300,
steps: int = 5
) -> Dict[str, Any]:
"""Simula scroll humano con movimientos graduales."""
session = self.session_manager.get_session(session_id)
if not session:
return {"success": False, "error": "Sesión no encontrada"}
try:
step_distance = distance // steps
for i in range(steps):
if direction == "down":
session.driver.execute_script(f"window.scrollBy(0, {step_distance});")
elif direction == "up":
session.driver.execute_script(f"window.scrollBy(0, -{step_distance});")
else:
return {"success": False, "error": "Dirección debe ser 'up' o 'down'"}
# Delay aleatorio entre pasos
delay = random.uniform(0.1, 0.3)
time.sleep(delay)
return {
"success": True,
"direction": direction,
"total_distance": distance,
"steps": steps,
"message": f"Scroll {direction} simulado exitosamente"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": "Error al simular scroll"
}
def _set_navigator_properties(self, driver: WebDriver):
"""Configura propiedades del navegador para parecer más humano."""
scripts = [
# Configurar timezone
"""
try {
Object.defineProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', {
value: function() {
return {
timeZone: 'America/New_York',
locale: 'en-US'
};
}
});
} catch (e) {}
""",
# Configurar memoria del dispositivo
"""
try {
Object.defineProperty(navigator, 'deviceMemory', {
get: () => 8,
});
} catch (e) {}
""",
# Configurar número de núcleos de CPU
"""
try {
Object.defineProperty(navigator, 'hardwareConcurrency', {
get: () => 4,
});
} catch (e) {}
""",
# Configurar plataforma
"""
try {
Object.defineProperty(navigator, 'platform', {
get: () => 'Win32',
});
} catch (e) {}
"""
]
for script in scripts:
try:
driver.execute_script(script)
except:
pass # Continuar aunque algunos scripts fallen