Files
AccountForger-neuerUpload/infrastructure/services/fingerprint/account_fingerprint_service.py
Claude Project Manager 04585e95b6 Initial commit
2025-08-01 23:50:28 +02:00

217 Zeilen
9.0 KiB
Python

"""
Account Fingerprint Service - Manages account-bound fingerprints.
"""
import hashlib
import random
from typing import Optional, Dict, Any
from datetime import datetime, timedelta
from domain.entities.browser_fingerprint import BrowserFingerprint
from .fingerprint_generator_service import FingerprintGeneratorService
from .fingerprint_rotation_service import FingerprintRotationService, RotationStrategy
class AccountFingerprintService:
"""Service for managing account-bound fingerprints."""
def __init__(self,
generator_service: Optional[FingerprintGeneratorService] = None,
rotation_service: Optional[FingerprintRotationService] = None):
self.generator_service = generator_service or FingerprintGeneratorService()
self.rotation_service = rotation_service or FingerprintRotationService()
def generate_account_fingerprint(self,
account_id: str,
platform: str,
proxy_location: Optional[str] = None) -> BrowserFingerprint:
"""Generate a fingerprint bound to a specific account."""
# Generate base fingerprint with account binding
fingerprint = self.generator_service.generate_fingerprint(
platform=platform,
proxy_location=proxy_location,
account_id=account_id
)
# Apply deterministic variations based on account ID
self._apply_account_variations(fingerprint, account_id)
return fingerprint
def get_daily_fingerprint(self,
base_fingerprint: BrowserFingerprint,
account_id: str) -> BrowserFingerprint:
"""Get deterministic daily variation of account fingerprint."""
if not base_fingerprint.account_bound:
raise ValueError("Fingerprint must be account-bound for daily variations")
# Calculate days since creation
days_since_creation = (datetime.now() - base_fingerprint.created_at).days
# Generate deterministic seed for today
today_seed = self._generate_daily_seed(account_id, days_since_creation)
# Apply deterministic variations
varied = self._apply_daily_variations(base_fingerprint, today_seed)
return varied
def _apply_account_variations(self, fingerprint: BrowserFingerprint, account_id: str) -> None:
"""Apply account-specific variations to fingerprint."""
# Use account ID to seed variations
account_hash = int(hashlib.md5(account_id.encode()).hexdigest()[:8], 16)
# Deterministic but unique variations
random.seed(account_hash)
# Vary canvas noise seed within range
base_seed = fingerprint.canvas_noise.seed
fingerprint.canvas_noise.seed = base_seed + (account_hash % 1000)
# Vary audio latencies slightly
fingerprint.audio_context_base_latency += (account_hash % 10) * 0.0001
fingerprint.audio_context_output_latency += (account_hash % 10) * 0.0002
# Select subset of fonts deterministically
if len(fingerprint.font_list) > 5:
num_to_remove = account_hash % 3 + 1
for _ in range(num_to_remove):
fingerprint.font_list.pop(random.randint(0, len(fingerprint.font_list) - 1))
# Reset random seed
random.seed()
def _generate_daily_seed(self, account_id: str, day_number: int) -> int:
"""Generate deterministic seed for a specific day."""
# Combine account ID with day number
seed_string = f"{account_id}:{day_number}"
seed_hash = hashlib.sha256(seed_string.encode()).hexdigest()
# Convert to integer seed
return int(seed_hash[:8], 16)
def _apply_daily_variations(self, fingerprint: BrowserFingerprint, daily_seed: int) -> BrowserFingerprint:
"""Apply deterministic daily variations."""
# Use rotation service with controlled randomness
original_seed = random.getstate()
random.seed(daily_seed)
# Minimal rotation for daily changes
varied = self.rotation_service.rotate_fingerprint(fingerprint, RotationStrategy.MINIMAL)
# Additional deterministic changes
self._apply_time_based_changes(varied, daily_seed)
# Restore original random state
random.setstate(original_seed)
return varied
def _apply_time_based_changes(self, fingerprint: BrowserFingerprint, seed: int) -> None:
"""Apply time-based changes that would naturally occur."""
# Browser version might update weekly
week_number = seed % 52
if week_number % 4 == 0: # Every 4 weeks
self._increment_browser_version(fingerprint)
# System uptime affects audio latency
hour_of_day = datetime.now().hour
fingerprint.audio_context_base_latency += (hour_of_day / 24) * 0.001
# Network conditions affect WebRTC
if seed % 3 == 0:
# Change local IP mask (different network)
fingerprint.webrtc_config.local_ip_mask = f"192.168.{seed % 255}.x"
def _increment_browser_version(self, fingerprint: BrowserFingerprint) -> None:
"""Increment browser version number."""
import re
user_agent = fingerprint.navigator_props.user_agent
# Find Chrome version
match = re.search(r'Chrome/(\d+)\.(\d+)\.(\d+)\.(\d+)', user_agent)
if match:
major = int(match.group(1))
minor = int(match.group(2))
build = int(match.group(3))
patch = int(match.group(4))
# Increment build number
build += 1
# Update user agent
old_version = match.group(0)
new_version = f"Chrome/{major}.{minor}.{build}.{patch}"
fingerprint.navigator_props.user_agent = user_agent.replace(old_version, new_version)
def validate_account_binding(self, fingerprint: BrowserFingerprint, account_id: str) -> bool:
"""Validate that a fingerprint is properly bound to an account."""
if not fingerprint.account_bound:
return False
if not fingerprint.static_components:
return False
if not fingerprint.rotation_seed:
return False
# Could add more validation here (e.g., check against database)
return True
def get_fingerprint_age_days(self, fingerprint: BrowserFingerprint) -> int:
"""Get age of fingerprint in days."""
if not fingerprint.created_at:
return 0
return (datetime.now() - fingerprint.created_at).days
def should_rotate_fingerprint(self, fingerprint: BrowserFingerprint) -> bool:
"""Determine if fingerprint should be rotated."""
age_days = self.get_fingerprint_age_days(fingerprint)
# Rotate after 30 days
if age_days > 30:
return True
# Check last rotation
if fingerprint.last_rotated:
days_since_rotation = (datetime.now() - fingerprint.last_rotated).days
if days_since_rotation > 7: # Weekly rotation check
return True
return False
def prepare_session_fingerprint(self,
fingerprint: BrowserFingerprint,
session_data: Dict[str, Any]) -> BrowserFingerprint:
"""Prepare fingerprint for use with existing session."""
# Sessions might have slightly different characteristics
session_fp = self._deep_copy_fingerprint(fingerprint)
# Apply session-specific adjustments
if "browser_version" in session_data:
self._update_to_browser_version(session_fp, session_data["browser_version"])
if "screen_resolution" in session_data:
session_fp.hardware_config.screen_resolution = tuple(session_data["screen_resolution"])
return session_fp
def _update_to_browser_version(self, fingerprint: BrowserFingerprint, version: str) -> None:
"""Update fingerprint to specific browser version."""
import re
user_agent = fingerprint.navigator_props.user_agent
# Replace Chrome version
user_agent = re.sub(r'Chrome/[\d.]+', f'Chrome/{version}', user_agent)
fingerprint.navigator_props.user_agent = user_agent
# Update app version
app_version = fingerprint.navigator_props.app_version
app_version = re.sub(r'Chrome/[\d.]+', f'Chrome/{version}', app_version)
fingerprint.navigator_props.app_version = app_version
def _deep_copy_fingerprint(self, fingerprint: BrowserFingerprint) -> BrowserFingerprint:
"""Create a deep copy of fingerprint."""
# Delegate to rotation service's implementation
return self.rotation_service._deep_copy_fingerprint(fingerprint)