Skip to content

Commit

Permalink
make the raw values of client hints public
Browse files Browse the repository at this point in the history
  • Loading branch information
iamdual committed May 17, 2024
1 parent 7b9b2c2 commit f0e81b3
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 21 deletions.
47 changes: 26 additions & 21 deletions src/ua_generator/client_hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
Copyright: 2022-2024 Ekin Karadeniz (github.com/iamdual)
License: Apache License 2.0
"""
from . import formats, serialization, utils
from random import Random

from . import formats, serialization
from .data import platforms_mobile
from .data import generator

Expand All @@ -26,10 +28,10 @@ def __init__(self, gen: generator.Generator):
self.__generator = gen
self.__cache = {}

def __mobile(self):
def get_mobile(self):
return self.__generator.platform in platforms_mobile

def __platform(self):
def get_platform(self):
platform = self.__generator.platform

if platform == 'ios':
Expand All @@ -41,13 +43,14 @@ def __platform(self):

return platform

def __platform_version(self):
def get_platform_version(self):
if self.__generator.platform == 'windows' and formats.major_version(self.__generator.platform_version) == '10':
return utils.choice(('10.0.0', '13.0.0'))
_random = Random(self.__generator.user_agent)
return _random.choice(('10.0.0', '13.0.0'))

return formats.version(self.__generator.platform_version)

def __brands(self, full_version_list: bool = False):
def get_brands(self, full_version_list: bool = False):
brand_list = [{'brand': 'Not A(Brand', 'version': '99'}]

if full_version_list:
Expand All @@ -64,51 +67,53 @@ def __brands(self, full_version_list: bool = False):

return brand_list

def __bitness(self):
def get_bitness(self):
if self.__generator.platform == 'android':
return utils.choice(('32', '64', '32', '32'))
_random = Random(self.__generator.user_agent)
return _random.choice(('32', '64', '32', '32'))

return '64'

def __architecture(self):
def get_architecture(self):
if self.__generator.platform == 'android' or self.__generator.platform == 'ios':
return 'arm'
elif self.__generator.platform == 'macos':
return utils.choice(('arm', 'x86', 'arm', 'arm'))
_random = Random(self.__generator.user_agent)
return _random.choice(('arm', 'x86', 'arm', 'arm'))

return 'x86'

def __model(self):
def get_model(self):
if 'platform_model' in self.__generator.platform_version:
return self.__generator.platform_version['platform_model']

return ''

def __wow64(self):
def get_wow64(self):
return self.__generator.platform == 'windows'

def __getattr__(self, name):
if name in self.__cache:
return self.__cache[name]

if name == 'mobile':
self.__cache[name] = serialization.ch_bool(self.__mobile())
self.__cache[name] = serialization.ch_bool(self.get_mobile())
elif name == 'platform':
self.__cache[name] = serialization.ch_string(self.__platform())
self.__cache[name] = serialization.ch_string(self.get_platform())
elif name == 'platform_version':
self.__cache[name] = serialization.ch_string(self.__platform_version())
self.__cache[name] = serialization.ch_string(self.get_platform_version())
elif name == 'brands':
self.__cache[name] = serialization.ch_brand_list(self.__brands())
self.__cache[name] = serialization.ch_brand_list(self.get_brands())
elif name == 'brands_full_version_list':
self.__cache[name] = serialization.ch_brand_list(self.__brands(full_version_list=True))
self.__cache[name] = serialization.ch_brand_list(self.get_brands(full_version_list=True))
elif name == 'bitness':
self.__cache[name] = serialization.ch_string(self.__bitness())
self.__cache[name] = serialization.ch_string(self.get_bitness())
elif name == 'architecture':
self.__cache[name] = serialization.ch_string(self.__architecture())
self.__cache[name] = serialization.ch_string(self.get_architecture())
elif name == 'model':
self.__cache[name] = serialization.ch_string(self.__model())
self.__cache[name] = serialization.ch_string(self.get_model())
elif name == 'wow64':
self.__cache[name] = serialization.ch_bool(self.__wow64())
self.__cache[name] = serialization.ch_bool(self.get_wow64())

return self.__cache[name]

Expand Down
34 changes: 34 additions & 0 deletions tests/test_client_hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import unittest

import src.ua_generator as ua_generator
from src.ua_generator import serialization
from src.ua_generator.data import browsers_support_ch


Expand All @@ -14,92 +15,125 @@ def test_ch_platform(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=browsers_support_ch, platform='macos')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.platform) is str)
self.assertEqual(ua.ch.platform, '"macOS"')
self.assertEqual(ua.ch.get_platform(), 'macOS')

def test_ch_platform_2(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=browsers_support_ch, platform='linux')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.platform) is str)
self.assertEqual(ua.ch.platform, '"Linux"')
self.assertEqual(ua.ch.get_platform(), 'Linux')

def test_ch_platform_version(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=browsers_support_ch)
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.platform_version) is str)
self.assertTrue(len(ua.ch.platform_version) > 0)
self.assertEqual(ua.ch.platform_version, serialization.ch_string(ua.ch.get_platform_version()))

def test_ch_platform_version_windows(self):
for i in range(0, 100):
ua = ua_generator.generate(platform='windows')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.platform_version) is str)
self.assertEqual(len(ua.ch.platform_version.split('.')), 3)
self.assertEqual(ua.ch.platform_version, serialization.ch_string(ua.ch.get_platform_version()))

def test_ch_mobile(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=browsers_support_ch, platform='android')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.mobile) is str)
self.assertEqual(ua.ch.mobile, '?1')
self.assertTrue(type(ua.ch.get_mobile()) is bool)
self.assertEqual(ua.ch.get_mobile(), True)

def test_ch_non_mobile(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=browsers_support_ch, platform='windows')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.mobile) is str)
self.assertEqual(ua.ch.mobile, '?0')
self.assertTrue(type(ua.ch.get_mobile()) is bool)
self.assertEqual(ua.ch.get_mobile(), False)

def test_ch_brands(self):
for i in range(0, 100):
ua = ua_generator.generate(browser='chrome', platform='windows')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.brands) is str)
self.assertTrue(ua.ch.brands.startswith('"Not A(Brand";v="99"'))
self.assertTrue('Chromium' in ua.ch.brands)
self.assertTrue('Google Chrome' in ua.ch.brands)
self.assertTrue(type(ua.ch.get_brands()) is list)
self.assertEqual(ua.ch.brands, serialization.ch_brand_list(ua.ch.get_brands()))

def test_ch_brands_full_version_list(self):
for i in range(0, 100):
ua = ua_generator.generate(browser='edge', platform='windows')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.brands_full_version_list) is str)
self.assertTrue(ua.ch.brands_full_version_list.startswith('"Not A(Brand";v="99"'))
self.assertTrue('Chromium' in ua.ch.brands_full_version_list)
self.assertTrue('Microsoft Edge' in ua.ch.brands_full_version_list)
self.assertTrue(type(ua.ch.get_brands(full_version_list=True)) is list)
self.assertEqual(ua.ch.brands_full_version_list,
serialization.ch_brand_list(ua.ch.get_brands(full_version_list=True)))

def test_ch_bitness(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=browsers_support_ch)
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.bitness) is str)
self.assertIn(ua.ch.bitness, ('"32"', '"64"'))
self.assertIn(ua.ch.get_bitness(), ('32', '64'))

def test_ch_architecture(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=browsers_support_ch)
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.architecture) is str)
self.assertIn(ua.ch.architecture, ('"arm"', '"x86"'))
self.assertIn(ua.ch.get_architecture(), ('arm', 'x86'))

def test_ch_model(self):
for i in range(0, 100):
ua = ua_generator.generate(platform='android', browser='chrome')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.model) is str)
self.assertTrue(ua.ch.model != '""')
self.assertTrue(len(ua.ch.model) > 2)
self.assertEqual(ua.ch.model, serialization.ch_string(ua.ch.get_model()))

def test_ch_model_2(self):
for i in range(0, 100):
ua = ua_generator.generate(platform='linux', browser='firefox')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.model) is str)
self.assertTrue(ua.ch.model == '""')
self.assertEqual(ua.ch.model, serialization.ch_string(ua.ch.get_model()))

def test_ch_wow64(self):
for i in range(0, 100):
ua = ua_generator.generate(platform='windows')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.wow64) is str)
self.assertEqual(ua.ch.wow64, '?1')
self.assertTrue(type(ua.ch.get_wow64()) is bool)
self.assertEqual(ua.ch.get_wow64(), True)

def test_ch_wow64_2(self):
for i in range(0, 100):
ua = ua_generator.generate(platform='linux')
self.assertIsNotNone(ua.ch)
self.assertTrue(type(ua.ch.wow64) is str)
self.assertEqual(ua.ch.wow64, '?0')
self.assertTrue(type(ua.ch.get_wow64()) is bool)
self.assertEqual(ua.ch.get_wow64(), False)


if __name__ == '__main__':
Expand Down

0 comments on commit f0e81b3

Please sign in to comment.