Spaces:
Sleeping
Sleeping
File size: 7,668 Bytes
494c89b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | """
Спуфинг Client Hints API (navigator.userAgentData)
Новый API который заменяет User-Agent строку.
AWS может проверять соответствие между UA и Client Hints.
"""
import re
from typing import Tuple
from .base import BaseSpoofModule
def parse_platform_from_ua(user_agent: str) -> Tuple[str, str, str, str]:
"""
Извлекает информацию о платформе из User-Agent строки.
Returns:
Tuple[platform, platform_version, architecture, bitness]
Примеры User-Agent:
- Windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..."
- macOS: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36..."
- Linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36..."
"""
# Defaults (Windows 10 как безопасный вариант)
platform = "Windows"
platform_version = "10.0.0"
architecture = "x86"
bitness = "64"
# Определяем платформу
if "Macintosh" in user_agent or "Mac OS X" in user_agent:
platform = "macOS"
# macOS версия из UA: "Mac OS X 10_15_7" -> "10.15.7"
mac_match = re.search(r'Mac OS X (\d+)[_.](\d+)[_.]?(\d+)?', user_agent)
if mac_match:
major = mac_match.group(1)
minor = mac_match.group(2)
patch = mac_match.group(3) or "0"
platform_version = f"{major}.{minor}.{patch}"
else:
platform_version = "10.15.7" # Безопасный default для macOS
architecture = "arm" # Современные Mac на Apple Silicon
bitness = "64"
elif "Linux" in user_agent:
platform = "Linux"
platform_version = "" # Linux не передаёт версию в Client Hints
if "x86_64" in user_agent:
architecture = "x86"
bitness = "64"
elif "aarch64" in user_agent or "arm64" in user_agent:
architecture = "arm"
bitness = "64"
else:
architecture = "x86"
bitness = "64"
elif "Windows" in user_agent:
platform = "Windows"
architecture = "x86"
# Определяем битность
if "Win64" in user_agent or "x64" in user_agent or "WOW64" in user_agent:
bitness = "64"
else:
bitness = "32"
# Windows NT версия
# Windows NT 10.0 может быть Windows 10 или Windows 11
# Различаем по build number если есть, иначе default = Windows 10
nt_match = re.search(r'Windows NT (\d+\.\d+)', user_agent)
if nt_match:
nt_version = nt_match.group(1)
if nt_version == "10.0":
# Пытаемся найти build number в UA (редко, но бывает)
# Формат: "Windows NT 10.0; Win64; x64; rv:..." или с build
# Некоторые UA содержат build: "Windows NT 10.0.22621"
build_match = re.search(r'Windows NT 10\.0\.(\d+)', user_agent)
if build_match:
build = int(build_match.group(1))
if build >= 22000:
# Windows 11 (build 22000+)
platform_version = "15.0.0"
else:
# Windows 10
platform_version = "10.0.0"
else:
# Нет build number - безопасный default Windows 10
platform_version = "10.0.0"
elif nt_version == "6.3":
platform_version = "6.3.0" # Windows 8.1
elif nt_version == "6.2":
platform_version = "6.2.0" # Windows 8
elif nt_version == "6.1":
platform_version = "6.1.0" # Windows 7
else:
platform_version = "10.0.0" # Default
return platform, platform_version, architecture, bitness
class ClientHintsSpoofModule(BaseSpoofModule):
"""Спуфинг Client Hints API"""
name = "client_hints"
description = "Spoof navigator.userAgentData (Client Hints)"
def get_js(self) -> str:
p = self.profile
# Извлекаем версию Chrome из user_agent
chrome_match = re.search(r'Chrome/(\d+)', p.user_agent)
chrome_version = chrome_match.group(1) if chrome_match else '131'
# Извлекаем информацию о платформе из User-Agent
platform, platform_version, architecture, bitness = parse_platform_from_ua(p.user_agent)
return f'''
(function() {{
'use strict';
const CHROME_VERSION = '{chrome_version}';
const PLATFORM = '{platform}';
const PLATFORM_VERSION = '{platform_version}';
const ARCHITECTURE = '{architecture}';
const BITNESS = '{bitness}';
// Brands array (как в реальном Chrome)
const brands = [
{{ brand: 'Google Chrome', version: CHROME_VERSION }},
{{ brand: 'Chromium', version: CHROME_VERSION }},
{{ brand: 'Not_A Brand', version: '24' }}
];
const fullVersionList = [
{{ brand: 'Google Chrome', version: CHROME_VERSION + '.0.0.0' }},
{{ brand: 'Chromium', version: CHROME_VERSION + '.0.0.0' }},
{{ brand: 'Not_A Brand', version: '24.0.0.0' }}
];
// Создаём fake userAgentData с правильным prototype
const NavigatorUAData = function() {{}};
NavigatorUAData.prototype.brands = brands;
NavigatorUAData.prototype.mobile = false;
NavigatorUAData.prototype.platform = PLATFORM;
NavigatorUAData.prototype.getHighEntropyValues = function(hints) {{
return Promise.resolve({{
architecture: ARCHITECTURE,
bitness: BITNESS,
brands: brands,
fullVersionList: fullVersionList,
mobile: false,
model: '',
platform: PLATFORM,
platformVersion: PLATFORM_VERSION,
uaFullVersion: CHROME_VERSION + '.0.0.0',
wow64: false,
formFactors: ['Desktop']
}});
}};
NavigatorUAData.prototype.toJSON = function() {{
return {{
brands: brands,
mobile: false,
platform: PLATFORM
}};
}};
const fakeUserAgentData = new NavigatorUAData();
fakeUserAgentData.brands = brands;
fakeUserAgentData.mobile = false;
fakeUserAgentData.platform = PLATFORM;
// Замораживаем brands array
Object.freeze(fakeUserAgentData.brands);
// Регистрируем в Proxy системе (если доступна)
if (typeof window.__registerSpoofedProp === 'function') {{
window.__registerSpoofedProp('userAgentData', () => fakeUserAgentData);
}}
// Также пробуем напрямую переопределить (для случаев без Proxy)
try {{
Object.defineProperty(navigator, 'userAgentData', {{
get: () => fakeUserAgentData,
configurable: true,
enumerable: true
}});
}} catch(e) {{}}
// Добавляем Symbol.toStringTag для правильного typeof
try {{
Object.defineProperty(NavigatorUAData.prototype, Symbol.toStringTag, {{
value: 'NavigatorUAData',
configurable: true
}});
}} catch(e) {{}}
}})();
'''
|