Initial commit
Dieser Commit ist enthalten in:
243
infrastructure/services/fingerprint/fingerprint_generator_service.py
Normale Datei
243
infrastructure/services/fingerprint/fingerprint_generator_service.py
Normale Datei
@ -0,0 +1,243 @@
|
||||
"""
|
||||
Fingerprint Generator Service - Core fingerprint generation logic.
|
||||
"""
|
||||
|
||||
import random
|
||||
import uuid
|
||||
from typing import Optional, Dict, Any, List
|
||||
from datetime import datetime
|
||||
|
||||
from domain.entities.browser_fingerprint import (
|
||||
BrowserFingerprint, CanvasNoise, WebRTCConfig,
|
||||
HardwareConfig, NavigatorProperties, StaticComponents
|
||||
)
|
||||
from .fingerprint_profile_service import FingerprintProfileService
|
||||
from .timezone_location_service import TimezoneLocationService
|
||||
|
||||
|
||||
class FingerprintGeneratorService:
|
||||
"""Service for generating browser fingerprints."""
|
||||
|
||||
def __init__(self,
|
||||
profile_service: Optional[FingerprintProfileService] = None,
|
||||
timezone_service: Optional[TimezoneLocationService] = None):
|
||||
self.profile_service = profile_service or FingerprintProfileService()
|
||||
self.timezone_service = timezone_service or TimezoneLocationService()
|
||||
|
||||
def generate_fingerprint(self,
|
||||
profile_type: Optional[str] = None,
|
||||
platform: Optional[str] = None,
|
||||
proxy_location: Optional[str] = None,
|
||||
account_id: Optional[str] = None) -> BrowserFingerprint:
|
||||
"""Generate a new browser fingerprint."""
|
||||
|
||||
# Get base profile
|
||||
profile = self.profile_service.get_profile(profile_type)
|
||||
|
||||
# Get location data
|
||||
location_data = self.timezone_service.get_consistent_location_data(proxy_location)
|
||||
|
||||
# Generate components
|
||||
fingerprint_id = str(uuid.uuid4())
|
||||
hardware_config = self._generate_hardware_config(profile)
|
||||
navigator_props = self._generate_navigator_properties(profile, location_data)
|
||||
canvas_noise = self._generate_canvas_noise()
|
||||
webrtc_config = self._generate_webrtc_config(profile["platform"])
|
||||
webgl_info = self._generate_webgl_info(profile)
|
||||
audio_context = self._generate_audio_context(profile_type)
|
||||
fonts = self.profile_service.get_fonts_for_platform(profile["platform"])
|
||||
plugins = self.profile_service.get_plugin_list(profile["platform"])
|
||||
|
||||
# Generate static components if account-bound
|
||||
static_components = None
|
||||
rotation_seed = None
|
||||
if account_id:
|
||||
static_components = self._generate_static_components(profile, location_data)
|
||||
rotation_seed = random.randint(1000000, 9999999)
|
||||
|
||||
# Platform-specific config
|
||||
platform_config = self._generate_platform_specific_config(platform, profile)
|
||||
|
||||
return BrowserFingerprint(
|
||||
fingerprint_id=fingerprint_id,
|
||||
canvas_noise=canvas_noise,
|
||||
webrtc_config=webrtc_config,
|
||||
font_list=fonts,
|
||||
hardware_config=hardware_config,
|
||||
navigator_props=navigator_props,
|
||||
webgl_vendor=webgl_info["vendor"],
|
||||
webgl_renderer=webgl_info["renderer"],
|
||||
audio_context_base_latency=audio_context["base_latency"],
|
||||
audio_context_output_latency=audio_context["output_latency"],
|
||||
audio_context_sample_rate=audio_context["sample_rate"],
|
||||
timezone=location_data["timezone"],
|
||||
timezone_offset=location_data["timezone_offset"],
|
||||
plugins=plugins,
|
||||
created_at=datetime.now(),
|
||||
last_rotated=datetime.now(),
|
||||
static_components=static_components,
|
||||
rotation_seed=rotation_seed,
|
||||
account_bound=bool(account_id),
|
||||
platform_specific_config=platform_config
|
||||
)
|
||||
|
||||
def _generate_hardware_config(self, profile: Dict[str, Any]) -> HardwareConfig:
|
||||
"""Generate hardware configuration."""
|
||||
return HardwareConfig(
|
||||
hardware_concurrency=random.choice(profile["hardware_concurrency"]),
|
||||
device_memory=random.choice(profile["device_memory"]),
|
||||
max_touch_points=10 if "mobile" in profile["name"].lower() else 0,
|
||||
screen_resolution=random.choice(profile["screen_resolution"]),
|
||||
color_depth=random.choice([24, 32]),
|
||||
pixel_ratio=random.choice([1.0, 1.5, 2.0, 3.0])
|
||||
)
|
||||
|
||||
def _generate_navigator_properties(self, profile: Dict[str, Any],
|
||||
location_data: Dict[str, Any]) -> NavigatorProperties:
|
||||
"""Generate navigator properties."""
|
||||
ua_components = self.profile_service.get_user_agent_components(profile["platform"])
|
||||
|
||||
# Build user agent
|
||||
if "Chrome" in ua_components["browser"]:
|
||||
user_agent = f"Mozilla/5.0 ({ua_components['os']}) {ua_components['engine']} {ua_components['browser']} Safari/537.36"
|
||||
else:
|
||||
user_agent = f"Mozilla/5.0 ({ua_components['os']}) {ua_components['engine']} {ua_components['browser']}"
|
||||
|
||||
return NavigatorProperties(
|
||||
platform=profile["platform"],
|
||||
vendor=profile["vendor"],
|
||||
vendor_sub="",
|
||||
product="Gecko",
|
||||
product_sub="20030107",
|
||||
app_name="Netscape",
|
||||
app_version="5.0 ({})".format(ua_components["os"]),
|
||||
user_agent=user_agent,
|
||||
language=location_data["language"],
|
||||
languages=location_data["languages"],
|
||||
online=True,
|
||||
do_not_track=random.choice(["1", "unspecified"])
|
||||
)
|
||||
|
||||
def _generate_canvas_noise(self) -> CanvasNoise:
|
||||
"""Generate canvas noise configuration."""
|
||||
config = self.profile_service.get_canvas_noise_config()
|
||||
return CanvasNoise(
|
||||
noise_level=config["noise_level"],
|
||||
seed=random.randint(1000, 99999),
|
||||
algorithm=config["algorithm"]
|
||||
)
|
||||
|
||||
def _generate_webrtc_config(self, platform: str) -> WebRTCConfig:
|
||||
"""Generate WebRTC configuration."""
|
||||
config = self.profile_service.get_webrtc_config(platform)
|
||||
return WebRTCConfig(
|
||||
enabled=config["enabled"],
|
||||
ice_servers=config["ice_servers"],
|
||||
local_ip_mask=config["local_ip_mask"],
|
||||
disable_webrtc=config["disable_webrtc"]
|
||||
)
|
||||
|
||||
def _generate_webgl_info(self, profile: Dict[str, Any]) -> Dict[str, str]:
|
||||
"""Generate WebGL vendor and renderer."""
|
||||
renderer = random.choice(profile["renderer"])
|
||||
|
||||
# Ensure vendor matches renderer
|
||||
if "Intel" in renderer:
|
||||
vendor = "Intel Inc."
|
||||
elif "NVIDIA" in renderer or "GeForce" in renderer:
|
||||
vendor = "NVIDIA Corporation"
|
||||
elif "AMD" in renderer or "Radeon" in renderer:
|
||||
vendor = "AMD"
|
||||
elif "Apple" in renderer:
|
||||
vendor = "Apple Inc."
|
||||
else:
|
||||
vendor = profile["vendor"]
|
||||
|
||||
return {
|
||||
"vendor": vendor,
|
||||
"renderer": renderer
|
||||
}
|
||||
|
||||
def _generate_audio_context(self, profile_type: Optional[str]) -> Dict[str, Any]:
|
||||
"""Generate audio context parameters."""
|
||||
audio_type = "mobile" if profile_type == "mobile" else "default"
|
||||
base_config = self.profile_service.get_audio_context(audio_type)
|
||||
|
||||
# Add slight variations
|
||||
return {
|
||||
"base_latency": base_config["base_latency"] + random.uniform(-0.001, 0.001),
|
||||
"output_latency": base_config["output_latency"] + random.uniform(-0.002, 0.002),
|
||||
"sample_rate": base_config["sample_rate"]
|
||||
}
|
||||
|
||||
def _generate_static_components(self, profile: Dict[str, Any],
|
||||
location_data: Dict[str, Any]) -> StaticComponents:
|
||||
"""Generate static components for account-bound fingerprints."""
|
||||
# Determine device type
|
||||
if "mobile" in profile["name"].lower():
|
||||
device_type = "mobile"
|
||||
elif "tablet" in profile["name"].lower():
|
||||
device_type = "tablet"
|
||||
else:
|
||||
device_type = "desktop"
|
||||
|
||||
# Determine OS family
|
||||
if "Win" in profile["platform"]:
|
||||
os_family = "windows"
|
||||
elif "Mac" in profile["platform"] or "iPhone" in profile["platform"]:
|
||||
os_family = "macos"
|
||||
elif "Android" in profile["platform"] or "Linux" in profile["platform"]:
|
||||
os_family = "linux"
|
||||
else:
|
||||
os_family = "other"
|
||||
|
||||
# Determine browser family
|
||||
browser_family = "chromium" # Most common
|
||||
|
||||
# Select base fonts (these won't change during rotation)
|
||||
all_fonts = self.profile_service.get_fonts_for_platform(profile["platform"])
|
||||
base_fonts = random.sample(all_fonts, min(10, len(all_fonts)))
|
||||
|
||||
return StaticComponents(
|
||||
device_type=device_type,
|
||||
os_family=os_family,
|
||||
browser_family=browser_family,
|
||||
gpu_vendor=profile["vendor"],
|
||||
gpu_model=profile["renderer"][0] if profile["renderer"] else "Unknown",
|
||||
cpu_architecture="x86_64" if device_type == "desktop" else "arm64",
|
||||
base_fonts=base_fonts,
|
||||
base_resolution=profile["screen_resolution"][0],
|
||||
base_timezone=location_data["timezone"]
|
||||
)
|
||||
|
||||
def _generate_platform_specific_config(self, platform: Optional[str],
|
||||
profile: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate platform-specific configuration."""
|
||||
config = {
|
||||
"platform": platform or "unknown",
|
||||
"profile_name": profile["name"],
|
||||
"protection_level": "standard"
|
||||
}
|
||||
|
||||
if platform == "instagram":
|
||||
config.update({
|
||||
"app_id": "936619743392459",
|
||||
"ajax_id": "1234567890",
|
||||
"ig_did": str(uuid.uuid4()).upper(),
|
||||
"claim": "0"
|
||||
})
|
||||
elif platform == "facebook":
|
||||
config.update({
|
||||
"fb_api_version": "v18.0",
|
||||
"fb_app_id": "256281040558",
|
||||
"fb_locale": "en_US"
|
||||
})
|
||||
elif platform == "tiktok":
|
||||
config.update({
|
||||
"tt_webid": str(random.randint(10**18, 10**19)),
|
||||
"tt_csrf_token": str(uuid.uuid4()),
|
||||
"browser_name": "chrome",
|
||||
"browser_version": "120"
|
||||
})
|
||||
|
||||
return config
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren