""" 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