Skip to content

Modifications for Firefox #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 22, 2025
9 changes: 8 additions & 1 deletion playwright_stealth/js/navigator.userAgent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const override = {
hardwareConcurrency: opts.navigator.hardwareConcurrency,
maxTouchPoints: opts.navigator.maxTouchPoints,
appVersion: opts.navigator.appVersion,
productSub: opts.navigator.productSub,
userAgentData: {
brands: opts.navigator.brands,
fullVersion: opts.navigator.userAgent,
Expand Down Expand Up @@ -62,4 +63,10 @@ utils.replaceGetterWithProxy(
Object.getPrototypeOf(navigator),
"appVersion",
utils.makeHandler().getterValue(override.appVersion)
);
);

utils.replaceGetterWithProxy(
Object.getPrototypeOf(navigator),
"productSub",
utils.makeHandler().getterValue(override.productSub)
);
19 changes: 13 additions & 6 deletions playwright_stealth/properties/_navigator_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,23 @@ def __init__(self, brands: List[dict], dnt: str, **kwargs):
self.languages = self._generate_languages(kwargs["Accept-language"])
self.appVersion = self._generate_app_version(kwargs["User-Agent"])
self.vendor = self._generate_vendor(kwargs["User-Agent"])
self.deviceMemory = self._generate_device_memory()
self.deviceMemory = self._generate_device_memory(kwargs["User-Agent"])
self.hardwareConcurrency = self._generate_hardware_concurrency(self.deviceMemory)
self.maxTouchPoints = self._generate_max_touch_points()
self.mobile = self._generate_mobile()
self.productSub = self._generate_product_sub(kwargs["User-Agent"])

def _generate_platform(self, user_agent: str) -> str:
"""Generates the platform based on the user agent."""

# Change regarding this article: \
# https://filipvitas.medium.com/how-to-set-user-agent-header-with-puppeteer-js-and-not-fail-28c7a02165da
if "Macintosh" in user_agent:
return "Macintosh"
return "MacIntel"
elif "Linux" in user_agent:
return "Linux"
return "Linux x86_x64"
else:
return "Windows"
return "Win64"

def _generate_language(self) -> str:
"""Generates the language based on the accept language."""
Expand Down Expand Up @@ -75,10 +78,10 @@ def _generate_vendor(self, user_agent: str) -> str:

return "Google Inc."

def _generate_device_memory(self) -> int:
def _generate_device_memory(self, user_agent: str) -> int:
"""Generates the device memory."""

return 8
return None if "Firefox" in user_agent else 8

def _generate_hardware_concurrency(self, device_memory: int) -> int:
"""Generates the hardware concurrency."""
Expand All @@ -95,5 +98,9 @@ def _generate_mobile(self) -> bool:

return False

def _generate_product_sub(self, user_agent: str) -> int:
"""Generate product sub depending on the Browser"""
return 20100101 if "Firefox" in user_agent else 20030107

def as_dict(self) -> dict:
return self.__dict__
2 changes: 1 addition & 1 deletion playwright_stealth/stealth.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async def generate_stealth_headers_async(properties: Properties, page: AsyncPage

def stealth_sync(page: SyncPage, config: StealthConfig = None):
"""teaches synchronous playwright Page to be stealthy like a ninja!"""
properties = Properties()
properties = Properties(browser_type=config.browser_type if config else BrowserType.CHROME)
combined_script = combine_scripts(properties, config)
generate_stealth_headers_sync(properties, page)

Expand Down
8 changes: 4 additions & 4 deletions tests/unit/navigator_properties_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def navigator_properties(fake_headers, brands):
def test_initialization(navigator_properties, fake_headers, brands):
"""Test that NavigatorProperties initializes with correct attributes."""
assert navigator_properties.userAgent == fake_headers["User-Agent"]
assert navigator_properties.platform in ["Macintosh", "Windows", "Linux"]
assert navigator_properties.platform in ["MacIntel", "Win64", "Linux x86_x64"]
assert navigator_properties.language == "en-US"
assert isinstance(navigator_properties.languages, list)
assert (
Expand All @@ -48,9 +48,9 @@ def test_generate_platform(navigator_properties):
ua_mac = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
ua_windows = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
ua_linux = "Mozilla/5.0 (X11; Linux x86_64)"
assert navigator_properties._generate_platform(ua_mac) == "Macintosh"
assert navigator_properties._generate_platform(ua_windows) == "Windows"
assert navigator_properties._generate_platform(ua_linux) == "Linux"
assert navigator_properties._generate_platform(ua_mac) == "MacIntel"
assert navigator_properties._generate_platform(ua_windows) == "Win64"
assert navigator_properties._generate_platform(ua_linux) == "Linux x86_x64"


def test_generate_languages(navigator_properties):
Expand Down