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

245 Zeilen
9.7 KiB
Python

"""
Fingerprint Validation Service - Validates fingerprint consistency and quality.
"""
import logging
from typing import Dict, List, Tuple, Optional, Any
from datetime import datetime, timedelta
from domain.entities.browser_fingerprint import BrowserFingerprint
logger = logging.getLogger("fingerprint_validation_service")
class FingerprintValidationService:
"""Service for validating fingerprint consistency and quality."""
def validate_fingerprint(self, fingerprint: BrowserFingerprint) -> Tuple[bool, List[str]]:
"""Validate a fingerprint for consistency and realism."""
errors = []
# Hardware consistency
hw_errors = self._validate_hardware_consistency(fingerprint)
errors.extend(hw_errors)
# Platform consistency
platform_errors = self._validate_platform_consistency(fingerprint)
errors.extend(platform_errors)
# WebGL consistency
webgl_errors = self._validate_webgl_consistency(fingerprint)
errors.extend(webgl_errors)
# Canvas consistency
canvas_errors = self._validate_canvas_consistency(fingerprint)
errors.extend(canvas_errors)
# Timezone consistency
tz_errors = self._validate_timezone_consistency(fingerprint)
errors.extend(tz_errors)
# Mobile-specific validation
if self._is_mobile_fingerprint(fingerprint):
mobile_errors = self._validate_mobile_fingerprint(fingerprint)
errors.extend(mobile_errors)
is_valid = len(errors) == 0
return is_valid, errors
def _validate_hardware_consistency(self, fp: BrowserFingerprint) -> List[str]:
"""Validate hardware configuration consistency."""
errors = []
# CPU cores should be power of 2 or common values
valid_cores = [1, 2, 4, 6, 8, 10, 12, 16, 20, 24, 32]
if fp.hardware_config.hardware_concurrency not in valid_cores:
errors.append(f"Unusual CPU core count: {fp.hardware_config.hardware_concurrency}")
# Device memory should be reasonable
valid_memory = [0.5, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 64]
if fp.hardware_config.device_memory not in valid_memory:
errors.append(f"Unusual device memory: {fp.hardware_config.device_memory}GB")
# Screen resolution should be common
width, height = fp.hardware_config.screen_resolution
common_resolutions = [
(1366, 768), (1920, 1080), (2560, 1440), (3840, 2160), # Desktop
(375, 667), (375, 812), (414, 896), (390, 844), # Mobile
(1440, 900), (2560, 1600), (2880, 1800) # Mac
]
if (width, height) not in common_resolutions:
# Check if it's at least a reasonable aspect ratio
aspect_ratio = width / height
if aspect_ratio < 1.2 or aspect_ratio > 2.5:
errors.append(f"Unusual screen resolution: {width}x{height}")
return errors
def _validate_platform_consistency(self, fp: BrowserFingerprint) -> List[str]:
"""Validate platform and navigator consistency."""
errors = []
platform = fp.navigator_props.platform
user_agent = fp.navigator_props.user_agent
# Check platform matches user agent
if "Win" in platform and "Windows" not in user_agent:
errors.append("Platform claims Windows but user agent doesn't")
elif "Mac" in platform and "Mac" not in user_agent:
errors.append("Platform claims Mac but user agent doesn't")
elif "Linux" in platform and "Android" not in user_agent and "Linux" not in user_agent:
errors.append("Platform claims Linux but user agent doesn't match")
# Check vendor consistency
if fp.navigator_props.vendor == "Google Inc." and "Chrome" not in user_agent:
errors.append("Google vendor but not Chrome browser")
elif fp.navigator_props.vendor == "Apple Inc." and "Safari" not in user_agent:
errors.append("Apple vendor but not Safari browser")
return errors
def _validate_webgl_consistency(self, fp: BrowserFingerprint) -> List[str]:
"""Validate WebGL renderer and vendor consistency."""
errors = []
vendor = fp.webgl_vendor
renderer = fp.webgl_renderer
# Common vendor/renderer pairs
if "Intel" in vendor and "Intel" not in renderer:
errors.append("WebGL vendor/renderer mismatch for Intel")
elif "NVIDIA" in vendor and "NVIDIA" not in renderer and "GeForce" not in renderer:
errors.append("WebGL vendor/renderer mismatch for NVIDIA")
elif "AMD" in vendor and "AMD" not in renderer and "Radeon" not in renderer:
errors.append("WebGL vendor/renderer mismatch for AMD")
# Platform-specific WebGL
if "Mac" in fp.navigator_props.platform:
if "ANGLE" in renderer:
errors.append("ANGLE renderer unexpected on Mac")
elif "Win" in fp.navigator_props.platform:
if "ANGLE" not in renderer and "Direct3D" not in renderer:
errors.append("Expected ANGLE or Direct3D renderer on Windows")
return errors
def _validate_canvas_consistency(self, fp: BrowserFingerprint) -> List[str]:
"""Validate canvas noise configuration."""
errors = []
noise_level = fp.canvas_noise.noise_level
if noise_level < 0 or noise_level > 0.1:
errors.append(f"Canvas noise level out of range: {noise_level}")
algorithm = fp.canvas_noise.algorithm
valid_algorithms = ["gaussian", "uniform", "perlin"]
if algorithm not in valid_algorithms:
errors.append(f"Invalid canvas noise algorithm: {algorithm}")
return errors
def _validate_timezone_consistency(self, fp: BrowserFingerprint) -> List[str]:
"""Validate timezone consistency with locale."""
errors = []
timezone = fp.timezone
language = fp.navigator_props.language
# Basic timezone/language consistency
tz_lang_map = {
"Europe/Berlin": ["de", "de-DE"],
"Europe/London": ["en-GB"],
"America/New_York": ["en-US"],
"Asia/Tokyo": ["ja", "ja-JP"]
}
for tz, langs in tz_lang_map.items():
if timezone == tz:
if not any(lang in language for lang in langs):
# It's okay if it's not a perfect match, just log it
logger.debug(f"Timezone {timezone} with language {language} might be unusual")
return errors
def _is_mobile_fingerprint(self, fp: BrowserFingerprint) -> bool:
"""Check if fingerprint is for a mobile device."""
mobile_indicators = ["Android", "iPhone", "iPad", "Mobile", "Tablet"]
platform = fp.navigator_props.platform
user_agent = fp.navigator_props.user_agent
return any(indicator in platform or indicator in user_agent for indicator in mobile_indicators)
def _validate_mobile_fingerprint(self, fp: BrowserFingerprint) -> List[str]:
"""Validate mobile-specific fingerprint attributes."""
errors = []
# Mobile should have touch points
if fp.hardware_config.max_touch_points == 0:
errors.append("Mobile device with no touch points")
# Mobile screen should be portrait or square-ish
width, height = fp.hardware_config.screen_resolution
if width > height:
errors.append("Mobile device with landscape resolution")
# Mobile typically has less memory
if fp.hardware_config.device_memory > 8:
errors.append("Mobile device with unusually high memory")
return errors
def calculate_fingerprint_quality_score(self, fp: BrowserFingerprint) -> float:
"""Calculate a quality score for the fingerprint (0.0 to 1.0)."""
score = 1.0
is_valid, errors = self.validate_fingerprint(fp)
# Deduct points for each error
score -= len(errors) * 0.1
# Bonus points for completeness
if fp.static_components:
score += 0.1
if fp.platform_specific_config:
score += 0.05
if fp.rotation_seed:
score += 0.05
# Ensure score is between 0 and 1
return max(0.0, min(1.0, score))
def assess_fingerprint_risk(self, fp: BrowserFingerprint) -> Dict[str, Any]:
"""Assess the risk level of using this fingerprint."""
risk_factors = []
risk_score = 0.0
# Check age
if fp.created_at:
age_days = (datetime.now() - fp.created_at).days
if age_days > 30:
risk_factors.append("Fingerprint is over 30 days old")
risk_score += 0.2
# Check validation
is_valid, errors = self.validate_fingerprint(fp)
if not is_valid:
risk_factors.extend(errors)
risk_score += len(errors) * 0.1
# Check for common/overused values
if fp.webgl_renderer == "ANGLE (Intel HD Graphics)":
risk_factors.append("Very common WebGL renderer")
risk_score += 0.1
# Determine risk level
if risk_score < 0.3:
risk_level = "low"
elif risk_score < 0.6:
risk_level = "medium"
else:
risk_level = "high"
return {
"risk_level": risk_level,
"risk_score": min(1.0, risk_score),
"risk_factors": risk_factors
}