Skip to content

Commit

Permalink
Various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
perklet committed Jun 26, 2024
1 parent 16d75be commit 5e6bb41
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 5 deletions.
33 changes: 31 additions & 2 deletions curl_cffi/requests/impersonate.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import warnings
from enum import Enum

from ..const import CurlSslVersion, CurlOpt
from ..curl import ffi, lib


class BrowserType(str, Enum):
Expand Down Expand Up @@ -216,7 +216,7 @@ class BrowserSpec:
}


def toggle_extension(curl, extension_id, enable: bool):
def toggle_extension(curl, extension_id: int, enable: bool):
# ECH
if extension_id == 65037:
if enable:
Expand All @@ -236,3 +236,32 @@ def toggle_extension(curl, extension_id, enable: bool):
curl.setopt(CurlOpt.SSL_ENABLE_ALPS, 1)
else:
curl.setopt(CurlOpt.SSL_ENABLE_ALPS, 0)
# server_name
elif extension_id == 0:
raise NotImplementedError("It's unlikely that the server_name(0) extension being changed.")
# ALPN
elif extension_id == 16:
raise NotImplementedError("It's unlikely that the ALPN(0) extension being changed.")
# status_request
elif extension_id == 5:
if enable:
pass # It's now always enabled
else:
raise NotImplementedError("This extension(5) is always on for now, it will be updated later.")
# signed_certificate_timestamp
elif extension_id == 18:
if enable:
pass # It's now always enabled
else:
raise NotImplementedError("This extension(18) is always on for now, it will be updated later.")
# session_ticket
elif extension_id == 35:
if enable:
curl.setopt(CurlOpt.SSL_ENABLE_TICKET, 1)
else:
curl.setopt(CurlOpt.SSL_ENABLE_TICKET, 0)
# padding
elif extension_id == 21:
pass
else:
raise NotImplementedError(f"This extension({extension_id}) can not be toggled for now, it may be updated later.")
17 changes: 14 additions & 3 deletions curl_cffi/requests/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,18 @@ def __init__(
def _toggle_extensions_by_ids(self, curl, extension_ids):
default_enabled = {0, 51, 13, 43, 5, 18, 65281, 23, 10, 45, 35, 11, 16}

to_enable_ids = set(extension_ids) - default_enabled
to_enable_ids = extension_ids - default_enabled
for ext_id in to_enable_ids:
toggle_extension(curl, ext_id, enable=True)

to_disable_ids = default_enabled - set(extension_ids)
# print("to_enable: ", to_enable_ids)

to_disable_ids = default_enabled - extension_ids
for ext_id in to_disable_ids:
toggle_extension(curl, ext_id, enable=False)

# print("to_disable: ", to_disable_ids)

def _set_ja3_options(self, curl, ja3: str):
"""
Detailed explanation: https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967/
Expand All @@ -244,7 +248,14 @@ def _set_ja3_options(self, curl, ja3: str):

curl.setopt(CurlOpt.SSL_CIPHER_LIST, ":".join(cipher_names))

extension_ids = [int(e) for e in extensions.split("-")]
if extensions.endswith("-21"):
extensions = extensions[:-3]
warnings.warn(
"Padding(21) extension found in ja3 string, whether to add it should "
"be decided by the SSL engine. The TLS hello packet may contain "
"or not contain this extension, any of which should be correct."
)
extension_ids = set(int(e) for e in extensions.split("-"))
self._toggle_extensions_by_ids(curl, extension_ids)

curl.setopt(CurlOpt.TLS_EXTENSION_ORDER, extensions)
Expand Down
21 changes: 21 additions & 0 deletions examples/impersonate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from curl_cffi import requests


# OKHTTP impersonatation examples
# credits: https://github.com/bogdanfinn/tls-client/blob/master/profiles/contributed_custom_profiles.go

url = "https://tls.browserleaks.com/json"

okhttp4_android10_ja3 = ",".join([
"771",
"4865-4866-4867-49195-49196-52393-49199-49200-52392-49171-49172-156-157-47-53",
"0-23-65281-10-11-35-16-5-13-51-45-43-18-21", # FIXME: 18 should not be here.
"29-23-24",
"0"
])

okhttp4_android10_akamai = "4:16777216|16711681|0|m,p,a,s"


r = requests.get(url, ja3=okhttp4_android10_ja3, akamai=okhttp4_android10_akamai)
print(r.json())
12 changes: 12 additions & 0 deletions tests/unittest/test_impersonate.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,25 @@ def test_customized_ja3_ciphers():
assert ciphers == "4865-4866-4867-49195-49199-49196-49200-52393-52392-49171"


# TODO change to parameterized test
def test_customized_ja3_extensions():
url = "https://tls.browserleaks.com/json"
ja3 = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,65037-65281-0-11-23-5-18-27-16-17513-10-35-43-45-13-51,25497-29-23-24,0"
r = requests.get(url, ja3=ja3).json()
_, _, extensions, _, _ = r["ja3_text"].split(",")
assert extensions == "65037-65281-0-11-23-5-18-27-16-17513-10-35-43-45-13-51"

ja3 = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,65281-0-11-23-5-18-27-16-17513-10-35-43-45-13-51,25497-29-23-24,0"
r = requests.get(url, ja3=ja3).json()
_, _, extensions, _, _ = r["ja3_text"].split(",")
assert extensions == "65281-0-11-23-5-18-27-16-17513-10-35-43-45-13-51"

# removed enable session_ticket()
ja3 = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,65281-0-11-23-5-18-27-16-17513-10-43-45-13-51,25497-29-23-24,0"
r = requests.get(url, ja3=ja3).json()
_, _, extensions, _, _ = r["ja3_text"].split(",")
assert extensions == "65281-0-11-23-5-18-27-16-17513-10-43-45-13-51"


def test_customized_ja3_curves():
url = "https://tls.browserleaks.com/json"
Expand Down

0 comments on commit 5e6bb41

Please sign in to comment.