diff --git a/Cargo.lock b/Cargo.lock index 235b7f56..dc3119b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2556,7 +2556,7 @@ dependencies = [ [[package]] name = "rustls" version = "0.23.36" -source = "git+https://github.com/apify/rustls?rev=8c46c4744be711e87946d967301c8dac648f4049#8c46c4744be711e87946d967301c8dac648f4049" +source = "git+https://github.com/apify/rustls?rev=4823cdb16098938eccf91af1329e9d5b681e3554#4823cdb16098938eccf91af1329e9d5b681e3554" dependencies = [ "aws-lc-rs", "brotli", diff --git a/Cargo.toml b/Cargo.toml index 0c211faa..f7de7c43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ members = [ [patch.crates-io] h2 = { git = "https://github.com/apify/h2", rev = "7f393a728a8db07cabb1b78d2094772b33943b9a" } -rustls = { git = "https://github.com/apify/rustls", rev="8c46c4744be711e87946d967301c8dac648f4049" } +rustls = { git = "https://github.com/apify/rustls", rev="4823cdb16098938eccf91af1329e9d5b681e3554" } [profile.release] strip = true # Automatically strip symbols from the binary. diff --git a/README.md b/README.md index aa70ea92..f4c2ce57 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ use impit::{impit::Impit, fingerprint::database as fingerprints}; #[tokio::main] async fn main() { let impit = Impit::::builder() - .with_fingerprint(fingerprints::firefox_128::fingerprint()) + .with_fingerprint(fingerprints::firefox_144::fingerprint()) .with_http3() .build() .unwrap(); diff --git a/impit-cli/src/main.rs b/impit-cli/src/main.rs index 15ffdb14..8e601066 100644 --- a/impit-cli/src/main.rs +++ b/impit-cli/src/main.rs @@ -97,7 +97,7 @@ async fn main() { client.with_fingerprint(impit::fingerprint::database::chrome_125::fingerprint()) } Browser::Firefox => { - client.with_fingerprint(impit::fingerprint::database::firefox_128::fingerprint()) + client.with_fingerprint(impit::fingerprint::database::firefox_144::fingerprint()) } Browser::Impit => client, }; diff --git a/impit-node/index.d.ts b/impit-node/index.d.ts index ff2ff200..a2498482 100644 --- a/impit-node/index.d.ts +++ b/impit-node/index.d.ts @@ -206,7 +206,22 @@ export declare class ImpitResponse { * See {@link ImpitOptions.browser} for more details and usage. */ export type Browser = 'chrome'| -'firefox'; +'chrome100'| +'chrome101'| +'chrome104'| +'chrome107'| +'chrome110'| +'chrome116'| +'chrome124'| +'chrome125'| +'chrome131'| +'chrome136'| +'chrome142'| +'firefox'| +'firefox128'| +'firefox133'| +'firefox135'| +'firefox144'; export type HttpMethod = 'GET'| 'POST'| diff --git a/impit-node/src/impit_builder.rs b/impit-node/src/impit_builder.rs index 525a569b..9bf9c0b3 100644 --- a/impit-node/src/impit_builder.rs +++ b/impit-node/src/impit_builder.rs @@ -15,7 +15,22 @@ use crate::cookies::NodeCookieJar; #[napi(string_enum = "lowercase")] pub enum Browser { Chrome, + Chrome100, + Chrome101, + Chrome104, + Chrome107, + Chrome110, + Chrome116, + Chrome124, + Chrome125, + Chrome131, + Chrome136, + Chrome142, Firefox, + Firefox128, + Firefox133, + Firefox135, + Firefox144, } /// Options for configuring an {@link Impit} instance. @@ -90,8 +105,25 @@ pub struct ImpitOptions<'a> { impl From for BrowserFingerprint { fn from(val: Browser) -> Self { match val { - Browser::Chrome => impit::fingerprint::database::chrome_125::fingerprint(), - Browser::Firefox => impit::fingerprint::database::firefox_128::fingerprint(), + Browser::Chrome | Browser::Chrome124 => { + impit::fingerprint::database::chrome_124::fingerprint() + } + Browser::Chrome100 => impit::fingerprint::database::chrome_100::fingerprint(), + Browser::Chrome101 => impit::fingerprint::database::chrome_101::fingerprint(), + Browser::Chrome104 => impit::fingerprint::database::chrome_104::fingerprint(), + Browser::Chrome107 => impit::fingerprint::database::chrome_107::fingerprint(), + Browser::Chrome110 => impit::fingerprint::database::chrome_110::fingerprint(), + Browser::Chrome116 => impit::fingerprint::database::chrome_116::fingerprint(), + Browser::Chrome125 => impit::fingerprint::database::chrome_125::fingerprint(), + Browser::Chrome131 => impit::fingerprint::database::chrome_131::fingerprint(), + Browser::Chrome136 => impit::fingerprint::database::chrome_136::fingerprint(), + Browser::Chrome142 => impit::fingerprint::database::chrome_142::fingerprint(), + Browser::Firefox | Browser::Firefox128 => { + impit::fingerprint::database::firefox_128::fingerprint() + } + Browser::Firefox133 => impit::fingerprint::database::firefox_133::fingerprint(), + Browser::Firefox135 => impit::fingerprint::database::firefox_135::fingerprint(), + Browser::Firefox144 => impit::fingerprint::database::firefox_144::fingerprint(), } } } diff --git a/impit-python/python/impit/impit.pyi b/impit-python/python/impit/impit.pyi index 1e13afce..7b38966e 100644 --- a/impit-python/python/impit/impit.pyi +++ b/impit-python/python/impit/impit.pyi @@ -7,8 +7,7 @@ from collections.abc import Iterator, AsyncIterator from contextlib import AbstractAsyncContextManager, AbstractContextManager -Browser = Literal['chrome', 'firefox'] - +Browser = Literal['chrome', 'firefox', 'chrome125', 'chrome100', 'chrome101', 'chrome104', 'chrome107', 'chrome110', 'chrome116', 'chrome131', 'chrome136', 'chrome142', 'firefox128', 'firefox133', 'firefox135', 'firefox144'] class HTTPError(Exception): """Represents an HTTP-related error.""" diff --git a/impit-python/src/async_client.rs b/impit-python/src/async_client.rs index bb860fb4..422f8cd5 100644 --- a/impit-python/src/async_client.rs +++ b/impit-python/src/async_client.rs @@ -58,10 +58,36 @@ impl AsyncClient { let builder = match browser { Some(browser) => match browser.to_lowercase().as_str() { - "chrome" => builder + "chrome" | "chrome124" => builder .with_fingerprint(impit::fingerprint::database::chrome_125::fingerprint()), - "firefox" => builder + "chrome100" => builder + .with_fingerprint(impit::fingerprint::database::chrome_100::fingerprint()), + "chrome101" => builder + .with_fingerprint(impit::fingerprint::database::chrome_101::fingerprint()), + "chrome104" => builder + .with_fingerprint(impit::fingerprint::database::chrome_104::fingerprint()), + "chrome107" => builder + .with_fingerprint(impit::fingerprint::database::chrome_107::fingerprint()), + "chrome110" => builder + .with_fingerprint(impit::fingerprint::database::chrome_110::fingerprint()), + "chrome116" => builder + .with_fingerprint(impit::fingerprint::database::chrome_116::fingerprint()), + "chrome125" => builder + .with_fingerprint(impit::fingerprint::database::chrome_125::fingerprint()), + "chrome131" => builder + .with_fingerprint(impit::fingerprint::database::chrome_131::fingerprint()), + "chrome136" => builder + .with_fingerprint(impit::fingerprint::database::chrome_136::fingerprint()), + "chrome142" => builder + .with_fingerprint(impit::fingerprint::database::chrome_142::fingerprint()), + "firefox128" | "firefox" => builder .with_fingerprint(impit::fingerprint::database::firefox_128::fingerprint()), + "firefox133" => builder + .with_fingerprint(impit::fingerprint::database::firefox_133::fingerprint()), + "firefox135" => builder + .with_fingerprint(impit::fingerprint::database::firefox_135::fingerprint()), + "firefox144" => builder + .with_fingerprint(impit::fingerprint::database::firefox_144::fingerprint()), _ => { return Err(PyErr::new::( "Unsupported browser", diff --git a/impit-python/src/client.rs b/impit-python/src/client.rs index d2c10b65..ef90352a 100644 --- a/impit-python/src/client.rs +++ b/impit-python/src/client.rs @@ -55,10 +55,34 @@ impl Client { let builder = match browser { Some(browser) => match browser.to_lowercase().as_str() { - "chrome" => builder + "chrome" | "chrome125" => builder .with_fingerprint(impit::fingerprint::database::chrome_125::fingerprint()), - "firefox" => builder + "chrome100" => builder + .with_fingerprint(impit::fingerprint::database::chrome_100::fingerprint()), + "chrome101" => builder + .with_fingerprint(impit::fingerprint::database::chrome_101::fingerprint()), + "chrome104" => builder + .with_fingerprint(impit::fingerprint::database::chrome_104::fingerprint()), + "chrome107" => builder + .with_fingerprint(impit::fingerprint::database::chrome_107::fingerprint()), + "chrome110" => builder + .with_fingerprint(impit::fingerprint::database::chrome_110::fingerprint()), + "chrome116" => builder + .with_fingerprint(impit::fingerprint::database::chrome_116::fingerprint()), + "chrome131" => builder + .with_fingerprint(impit::fingerprint::database::chrome_131::fingerprint()), + "chrome136" => builder + .with_fingerprint(impit::fingerprint::database::chrome_136::fingerprint()), + "chrome142" => builder + .with_fingerprint(impit::fingerprint::database::chrome_142::fingerprint()), + "firefox128" | "firefox" => builder .with_fingerprint(impit::fingerprint::database::firefox_128::fingerprint()), + "firefox133" => builder + .with_fingerprint(impit::fingerprint::database::firefox_133::fingerprint()), + "firefox135" => builder + .with_fingerprint(impit::fingerprint::database::firefox_135::fingerprint()), + "firefox144" => builder + .with_fingerprint(impit::fingerprint::database::firefox_144::fingerprint()), _ => panic!("Unsupported browser"), }, None => builder, diff --git a/impit-python/test/setup_proxy.py b/impit-python/test/setup_proxy.py index c2967b52..5d6bfb91 100644 --- a/impit-python/test/setup_proxy.py +++ b/impit-python/test/setup_proxy.py @@ -9,7 +9,7 @@ def start_proxy_server(port: int = 3002) -> typing.Callable[[], None]: def run_proxy_server(stop_event: threading.Event) -> None: server = pproxy.Server(f'http://0.0.0.0:{port}') - args = dict(rserver=[], verbose=print) + args = {'rserver': [], 'verbose': print} loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) diff --git a/impit/examples/basic.rs b/impit/examples/basic.rs index cfdce6ed..6b010114 100644 --- a/impit/examples/basic.rs +++ b/impit/examples/basic.rs @@ -4,7 +4,7 @@ use impit::{fingerprint::database as fingerprints, impit::Impit}; #[tokio::main] async fn main() { let impit = Impit::::builder() - .with_fingerprint(fingerprints::firefox_128::fingerprint()) + .with_fingerprint(fingerprints::firefox_144::fingerprint()) .with_http3() .build() .unwrap(); diff --git a/impit/src/fingerprint/database.rs b/impit/src/fingerprint/database.rs index 9b3ebf97..afd9da6d 100644 --- a/impit/src/fingerprint/database.rs +++ b/impit/src/fingerprint/database.rs @@ -5,5 +5,8 @@ mod chrome; mod firefox; -pub use chrome::chrome_125; -pub use firefox::firefox_128; +pub use chrome::{ + chrome_100, chrome_101, chrome_104, chrome_107, chrome_110, chrome_116, chrome_124, chrome_125, + chrome_131, chrome_133, chrome_136, chrome_142, +}; +pub use firefox::{firefox_128, firefox_133, firefox_135, firefox_144}; diff --git a/impit/src/fingerprint/database/chrome.rs b/impit/src/fingerprint/database/chrome.rs index 41042967..c523c3b1 100644 --- a/impit/src/fingerprint/database/chrome.rs +++ b/impit/src/fingerprint/database/chrome.rs @@ -2,6 +2,974 @@ use crate::fingerprint::*; +/// Chrome 142 fingerprint module +pub mod chrome_142 { + use super::*; + + /// Returns the complete Chrome 142 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "142", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Chrome 142 TLS fingerprint + fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + // Cipher suites in Chrome 142 preference order + // GREASE cipher at position 1 (first) - same as Chrome 136 + vec![ + CipherSuite::Grease, + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + // Key exchange groups (includes post-quantum hybrid X25519MLKEM768) + // GREASE at position 1 (first) - same as Chrome 136 + vec![ + KeyExchangeGroup::Grease, + KeyExchangeGroup::X25519MLKEM768, + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + ], + // Signature algorithms + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha512, + ], + // TLS extensions configuration + // Chrome 142 uses new ALPS codepoint (17613) + TlsExtensions::new( + true, // server_name + true, // status_request + true, // supported_groups + true, // signature_algorithms + true, // application_layer_protocol_negotiation + true, // signed_certificate_timestamp + true, // key_share + true, // psk_key_exchange_modes + true, // supported_versions + Some(vec![CertificateCompressionAlgorithm::Brotli]), // compress_certificate + true, // application_settings + false, // delegated_credentials (Chrome doesn't use) + None, // record_size_limit (Chrome doesn't use) + // Extension order (critical for fingerprinting) + vec![ + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::SessionTicket, + ExtensionType::SignatureAlgorithms, + ExtensionType::StatusRequest, + ExtensionType::SupportedGroups, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::SignedCertificateTimestamp, + ExtensionType::KeyShare, + ExtensionType::PskKeyExchangeModes, + ExtensionType::SupportedVersions, + ExtensionType::CompressCertificate, + ExtensionType::ApplicationSettings, + ], + ) + .with_new_alps_codepoint(true), + // ECH configuration (GREASE mode) + Some(EchConfig::new( + EchMode::Grease { + hpke_suite: HpkeKemId::DhKemX25519HkdfSha256, + }, + None, + )), + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Chrome 142 HTTP/2 fingerprint + fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":path".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Chrome 142 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\"Chromium\";v=\"142\", \"Google Chrome\";v=\"142\", \"Not_A Brand\";v=\"99\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"macOS\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ] + } +} + +/// Chrome 136 fingerprint module +pub mod chrome_136 { + use super::*; + + /// Returns the complete Chrome 136 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "136", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Chrome 136 TLS fingerprint + fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + // Cipher suites in Chrome 136 preference order + // GREASE cipher at position 1 (first) based on Wireshark capture + vec![ + CipherSuite::Grease, + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + // Key exchange groups (includes post-quantum hybrid X25519MLKEM768) + // GREASE at position 1 (first) based on Wireshark capture + vec![ + KeyExchangeGroup::Grease, + KeyExchangeGroup::X25519MLKEM768, + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + ], + // Signature algorithms + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha512, + ], + // TLS extensions configuration + // Chrome 136 uses new ALPS codepoint (17613) + TlsExtensions::new( + true, // server_name + true, // status_request + true, // supported_groups + true, // signature_algorithms + true, // application_layer_protocol_negotiation + true, // signed_certificate_timestamp + true, // key_share + true, // psk_key_exchange_modes + true, // supported_versions + Some(vec![CertificateCompressionAlgorithm::Brotli]), // compress_certificate + true, // application_settings + false, // delegated_credentials (Chrome doesn't use) + None, // record_size_limit (Chrome doesn't use) + // Extension order (critical for fingerprinting) + vec![ + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::SessionTicket, + ExtensionType::SignatureAlgorithms, + ExtensionType::StatusRequest, + ExtensionType::SupportedGroups, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::SignedCertificateTimestamp, + ExtensionType::KeyShare, + ExtensionType::PskKeyExchangeModes, + ExtensionType::SupportedVersions, + ExtensionType::CompressCertificate, + ExtensionType::ApplicationSettings, + ], + ) + .with_new_alps_codepoint(true), + // ECH configuration (GREASE mode) + Some(EchConfig::new( + EchMode::Grease { + hpke_suite: HpkeKemId::DhKemX25519HkdfSha256, + }, + None, + )), + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Chrome 136 HTTP/2 fingerprint + fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":path".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Chrome 136 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\"Chromium\";v=\"136\", \"Google Chrome\";v=\"136\", \"Not.A/Brand\";v=\"99\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"macOS\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ] + } +} + +/// Chrome 133 fingerprint module +pub mod chrome_133 { + use super::*; + + /// Returns the complete Chrome 133 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "133", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Chrome 133 TLS fingerprint + fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + // Cipher suites in Chrome 133 preference order + vec![ + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + // Key exchange groups (includes post-quantum hybrid X25519MLKEM768) + vec![ + KeyExchangeGroup::X25519MLKEM768, + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + ], + // Signature algorithms + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha512, + ], + // TLS extensions configuration + TlsExtensions::new( + true, // server_name + true, // status_request + true, // supported_groups + true, // signature_algorithms + true, // application_layer_protocol_negotiation + true, // signed_certificate_timestamp + true, // key_share + true, // psk_key_exchange_modes + true, // supported_versions + Some(vec![CertificateCompressionAlgorithm::Brotli]), // compress_certificate + true, // application_settings + false, // delegated_credentials (Chrome doesn't use) + None, // record_size_limit (Chrome doesn't use) + // Extension order (critical for fingerprinting) + vec![ + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::SessionTicket, + ExtensionType::SignatureAlgorithms, + ExtensionType::StatusRequest, + ExtensionType::SupportedGroups, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::SignedCertificateTimestamp, + ExtensionType::KeyShare, + ExtensionType::PskKeyExchangeModes, + ExtensionType::SupportedVersions, + ExtensionType::CompressCertificate, + ExtensionType::ApplicationSettings, + ], + ), + // ECH configuration (GREASE mode) + Some(EchConfig::new( + EchMode::Grease { + hpke_suite: HpkeKemId::DhKemX25519HkdfSha256, + }, + None, + )), + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Chrome 133 HTTP/2 fingerprint + fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":path".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Chrome 133 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"macOS\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ] + } +} + +/// Chrome 124 fingerprint module +pub mod chrome_124 { + use super::*; + + /// Returns the complete Chrome 124 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "124", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Chrome 124 TLS fingerprint + fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + // Cipher suites in Chrome 124 preference order + vec![ + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + // Key exchange groups (X25519Kyber768Draft00 was the pre-MLKEM version) + vec![ + KeyExchangeGroup::X25519MLKEM768, // Maps to X25519Kyber768Draft00 in practice + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + ], + // Signature algorithms + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha512, + ], + // TLS extensions configuration + TlsExtensions::new( + true, // server_name + true, // status_request + true, // supported_groups + true, // signature_algorithms + true, // application_layer_protocol_negotiation + true, // signed_certificate_timestamp + true, // key_share + true, // psk_key_exchange_modes + true, // supported_versions + Some(vec![CertificateCompressionAlgorithm::Brotli]), // compress_certificate + true, // application_settings + false, // delegated_credentials (Chrome doesn't use) + None, // record_size_limit (Chrome doesn't use) + // Extension order (critical for fingerprinting) + vec![ + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::SessionTicket, + ExtensionType::SignatureAlgorithms, + ExtensionType::StatusRequest, + ExtensionType::SupportedGroups, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::SignedCertificateTimestamp, + ExtensionType::KeyShare, + ExtensionType::PskKeyExchangeModes, + ExtensionType::SupportedVersions, + ExtensionType::CompressCertificate, + ExtensionType::ApplicationSettings, + ], + ), + // ECH configuration (GREASE mode) + Some(EchConfig::new( + EchMode::Grease { + hpke_suite: HpkeKemId::DhKemX25519HkdfSha256, + }, + None, + )), + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Chrome 124 HTTP/2 fingerprint + fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":path".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Chrome 124 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\"Chromium\";v=\"124\", \"Google Chrome\";v=\"124\", \"Not-A.Brand\";v=\"99\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"macOS\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ] + } +} + +/// Chrome 131 fingerprint module +pub mod chrome_131 { + use super::*; + + /// Returns the complete Chrome 131 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "131", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Chrome 131 TLS fingerprint + fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + // Cipher suites in Chrome 131 preference order (matching CHROME_CIPHER_SUITES) + vec![ + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::Grease, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + // Key exchange groups (includes post-quantum hybrid X25519MLKEM768) + vec![ + KeyExchangeGroup::X25519MLKEM768, + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + KeyExchangeGroup::Grease, + ], + // Signature algorithms - order must match DEFAULT_SIGNATURE_VERIFICATION_ALGOS + // Note: No SHA1 algorithms for Chrome (matches original implementation) + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha512, + ], + // TLS extensions configuration + TlsExtensions::new( + true, // server_name + true, // status_request + true, // supported_groups + true, // signature_algorithms + true, // application_layer_protocol_negotiation + true, // signed_certificate_timestamp + true, // key_share + true, // psk_key_exchange_modes + true, // supported_versions + Some(vec![CertificateCompressionAlgorithm::Brotli]), // compress_certificate + true, // application_settings + false, // delegated_credentials (Chrome doesn't use) + None, // record_size_limit (Chrome doesn't use) + // Extension order (critical for fingerprinting) + vec![ + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::SessionTicket, + ExtensionType::SignatureAlgorithms, + ExtensionType::StatusRequest, + ExtensionType::SupportedGroups, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::SignedCertificateTimestamp, + ExtensionType::KeyShare, + ExtensionType::PskKeyExchangeModes, + ExtensionType::SupportedVersions, + ExtensionType::CompressCertificate, + ExtensionType::ApplicationSettings, + ], + ), + // ECH configuration (GREASE mode) + Some(EchConfig::new( + EchMode::Grease { + hpke_suite: HpkeKemId::DhKemX25519HkdfSha256, + }, + None, + )), + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Chrome 131 HTTP/2 fingerprint + fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":path".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Chrome 131 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"macOS\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ] + } +} + +/// Chrome 100 fingerprint module +pub mod chrome_100 { + use super::*; + + /// Returns the complete Chrome 100 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "100", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Chrome 100 TLS fingerprint + pub(crate) fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + vec![ + CipherSuite::Grease, + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + vec![ + KeyExchangeGroup::Grease, + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + ], + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha512, + ], + TlsExtensions::new( + true, + true, + true, + true, + true, + true, + true, + true, + true, + Some(vec![CertificateCompressionAlgorithm::Brotli]), + true, + false, + None, + vec![ + ExtensionType::Grease, + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::RenegotiationInfo, + ExtensionType::SupportedGroups, + ExtensionType::EcPointFormats, + ExtensionType::SessionTicket, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::StatusRequest, + ExtensionType::SignatureAlgorithms, + ExtensionType::SignedCertificateTimestamp, + ExtensionType::KeyShare, + ExtensionType::PskKeyExchangeModes, + ExtensionType::SupportedVersions, + ExtensionType::CompressCertificate, + ExtensionType::ApplicationSettings, + ExtensionType::Grease, + ExtensionType::Padding, + ], + ) + .with_padding(true), // Chrome 100 uses padding extension + // No ECH in Chrome 100 + None, + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Chrome 100 HTTP/2 fingerprint + pub(crate) fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":path".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Chrome 100 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"100\", \"Google Chrome\";v=\"100\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"Windows\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ] + } +} + +/// Chrome 101 fingerprint module +pub mod chrome_101 { + use super::*; + + /// Returns the complete Chrome 101 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "101", + chrome_100::tls_fingerprint(), + chrome_100::http2_fingerprint(), + headers(), + ) + } + + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"Windows\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ] + } +} + +/// Chrome 104 fingerprint module +pub mod chrome_104 { + use super::*; + + /// Returns the complete Chrome 104 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "104", + chrome_100::tls_fingerprint(), + chrome_100::http2_fingerprint(), + headers(), + ) + } + + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"104\", \"Google Chrome\";v=\"104\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"Windows\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ] + } +} + +/// Chrome 107 fingerprint module +pub mod chrome_107 { + use super::*; + + /// Returns the complete Chrome 107 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "107", + chrome_100::tls_fingerprint(), + chrome_100::http2_fingerprint(), // TODO Chrome 107 uses different HTTP/2 settings + headers(), + ) + } + + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"107\", \"Google Chrome\";v=\"107\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"Windows\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ] + } +} + +/// Chrome 110 fingerprint module +pub mod chrome_110 { + use super::*; + + /// Returns the complete Chrome 110 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "110", + chrome_100::tls_fingerprint(), + chrome_100::http2_fingerprint(), // TODO Chrome 110 uses different HTTP/2 settings + headers(), + ) + } + + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Google Chrome\";v=\"110\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"Windows\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ] + } +} + +/// Chrome 116 fingerprint module +pub mod chrome_116 { + use super::*; + + /// Returns the complete Chrome 116 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Chrome", + "116", + chrome_100::tls_fingerprint(), + chrome_100::http2_fingerprint(), // TODO Chrome 116 uses different HTTP/2 settings + headers(), + ) + } + + fn headers() -> Vec<(String, String)> { + vec![ + ("sec-ch-ua".to_string(), "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"".to_string()), + ("sec-ch-ua-mobile".to_string(), "?0".to_string()), + ("sec-ch-ua-platform".to_string(), "\"Windows\"".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("user-agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.9".to_string()), + ] + } +} + /// Chrome 125 fingerprint module pub mod chrome_125 { use super::*; diff --git a/impit/src/fingerprint/database/firefox.rs b/impit/src/fingerprint/database/firefox.rs index 17d2a800..dd9e36ac 100644 --- a/impit/src/fingerprint/database/firefox.rs +++ b/impit/src/fingerprint/database/firefox.rs @@ -139,3 +139,319 @@ pub mod firefox_128 { ] } } + +/// Firefox 133 fingerprint module +pub mod firefox_133 { + use super::*; + + /// Returns the complete Firefox 133 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Firefox", + "133", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Firefox 133 TLS fingerprint + fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + // Cipher suites in Firefox 133 preference order + vec![ + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + // Key exchange groups (Firefox includes FFDHE groups and post-quantum hybrid) + vec![ + KeyExchangeGroup::X25519MLKEM768, + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + KeyExchangeGroup::Secp521r1, + KeyExchangeGroup::Ffdhe2048, + KeyExchangeGroup::Ffdhe3072, + ], + // Signature algorithms + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::EcdsaSecp521r1Sha512, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPkcs1Sha512, + SignatureAlgorithm::EcdsaSha1Legacy, + SignatureAlgorithm::RsaPkcs1Sha1, + ], + // TLS extensions configuration + TlsExtensions::new( + true, // server_name + true, // status_request + true, // supported_groups + true, // signature_algorithms + true, // application_layer_protocol_negotiation + false, // signed_certificate_timestamp (Firefox 133 doesn't use) + true, // key_share + true, // psk_key_exchange_modes + true, // supported_versions + Some(vec![ + CertificateCompressionAlgorithm::Zlib, + CertificateCompressionAlgorithm::Brotli, + CertificateCompressionAlgorithm::Zstd, + ]), // compress_certificate (all three algorithms) + false, // application_settings + true, // delegated_credentials (Firefox uses this) + Some(4001), // record_size_limit (Firefox 133 uses 4001) + // Extension order (critical for fingerprinting) + vec![ + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::SessionTicket, + ExtensionType::SupportedGroups, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::StatusRequest, + ExtensionType::KeyShare, + ExtensionType::SupportedVersions, + ExtensionType::SignatureAlgorithms, + ExtensionType::PskKeyExchangeModes, + ], + ), + // ECH configuration (GREASE mode) + Some(EchConfig::new( + EchMode::Grease { + hpke_suite: HpkeKemId::DhKemX25519HkdfSha256, + }, + None, + )), + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Firefox 133 HTTP/2 fingerprint + fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":path".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Firefox 133 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.5".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ("te".to_string(), "trailers".to_string()), + ] + } +} + +/// Firefox 135 fingerprint module +pub mod firefox_135 { + use super::*; + + /// Returns the complete Firefox 135 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Firefox", + "135", + tls_fingerprint(), + http2_fingerprint(), + headers(), + ) + } + + /// Firefox 135 TLS fingerprint + pub(crate) fn tls_fingerprint() -> TlsFingerprint { + TlsFingerprint::new( + // Cipher suites in Firefox 135 preference order + // TLS 1.3 cipher suites first, then TLS 1.2 + vec![ + // Real TLS 1.3 cipher suites + CipherSuite::TLS13_AES_128_GCM_SHA256, + CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS13_AES_256_GCM_SHA384, + // Real TLS 1.2 cipher suites + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, + ], + // Key exchange groups (Firefox includes FFDHE groups and post-quantum hybrid) + vec![ + KeyExchangeGroup::X25519MLKEM768, + KeyExchangeGroup::X25519, + KeyExchangeGroup::Secp256r1, + KeyExchangeGroup::Secp384r1, + KeyExchangeGroup::Secp521r1, + KeyExchangeGroup::Ffdhe2048, + KeyExchangeGroup::Ffdhe3072, + ], + // Signature algorithms + vec![ + SignatureAlgorithm::EcdsaSecp256r1Sha256, + SignatureAlgorithm::EcdsaSecp384r1Sha384, + SignatureAlgorithm::EcdsaSecp521r1Sha512, + SignatureAlgorithm::RsaPssRsaSha256, + SignatureAlgorithm::RsaPssRsaSha384, + SignatureAlgorithm::RsaPssRsaSha512, + SignatureAlgorithm::RsaPkcs1Sha256, + SignatureAlgorithm::RsaPkcs1Sha384, + SignatureAlgorithm::RsaPkcs1Sha512, + SignatureAlgorithm::EcdsaSha1Legacy, + SignatureAlgorithm::RsaPkcs1Sha1, + ], + // TLS extensions configuration + TlsExtensions::new( + true, // server_name + true, // status_request + true, // supported_groups + true, // signature_algorithms + true, // application_layer_protocol_negotiation + true, // signed_certificate_timestamp (enabled in Firefox 135) + true, // key_share + true, // psk_key_exchange_modes + true, // supported_versions + Some(vec![ + CertificateCompressionAlgorithm::Zlib, + CertificateCompressionAlgorithm::Brotli, + CertificateCompressionAlgorithm::Zstd, + ]), // compress_certificate (all three algorithms) + false, // application_settings + true, // delegated_credentials (Firefox uses this) + Some(4001), // record_size_limit (Firefox 135 uses 4001) + // Extension order (critical for fingerprinting) + vec![ + ExtensionType::ServerName, + ExtensionType::ExtendedMasterSecret, + ExtensionType::SessionTicket, + ExtensionType::SupportedGroups, + ExtensionType::ApplicationLayerProtocolNegotiation, + ExtensionType::StatusRequest, + ExtensionType::SignedCertificateTimestamp, + ExtensionType::KeyShare, + ExtensionType::SupportedVersions, + ExtensionType::SignatureAlgorithms, + ExtensionType::PskKeyExchangeModes, + ], + ), + // ECH configuration (GREASE mode) + Some(EchConfig::new( + EchMode::Grease { + hpke_suite: HpkeKemId::DhKemX25519HkdfSha256, + }, + None, + )), + // ALPN protocols + vec![b"h2".to_vec(), b"http/1.1".to_vec()], + ) + } + + /// Firefox 135 HTTP/2 fingerprint + pub(crate) fn http2_fingerprint() -> Http2Fingerprint { + Http2Fingerprint { + pseudo_header_order: vec![ + ":method".to_string(), + ":path".to_string(), + ":authority".to_string(), + ":scheme".to_string(), + ":protocol".to_string(), + ":status".to_string(), + ], + } + } + + /// Firefox 135 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.5".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ("te".to_string(), "trailers".to_string()), + ] + } +} + +/// Firefox 144 fingerprint module (matches curl_firefox144) +/// Based on Firefox 135 pattern which has the same TLS fingerprint +pub mod firefox_144 { + use super::*; + + /// Returns the complete Firefox 144 fingerprint + pub fn fingerprint() -> BrowserFingerprint { + BrowserFingerprint::new( + "Firefox", + "144", + firefox_135::tls_fingerprint(), + firefox_135::http2_fingerprint(), + headers(), + ) + } + + /// Firefox 144 HTTP headers + fn headers() -> Vec<(String, String)> { + vec![ + ("user-agent".to_string(), "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:144.0) Gecko/20100101 Firefox/144.0".to_string()), + ("accept".to_string(), "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8".to_string()), + ("accept-language".to_string(), "en-US,en;q=0.5".to_string()), + ("accept-encoding".to_string(), "gzip, deflate, br, zstd".to_string()), + ("upgrade-insecure-requests".to_string(), "1".to_string()), + ("sec-fetch-dest".to_string(), "document".to_string()), + ("sec-fetch-mode".to_string(), "navigate".to_string()), + ("sec-fetch-site".to_string(), "none".to_string()), + ("sec-fetch-user".to_string(), "?1".to_string()), + ("priority".to_string(), "u=0, i".to_string()), + ("te".to_string(), "trailers".to_string()), + ] + } +} diff --git a/impit/src/fingerprint/mod.rs b/impit/src/fingerprint/mod.rs index 21d5f82f..54e2d453 100644 --- a/impit/src/fingerprint/mod.rs +++ b/impit/src/fingerprint/mod.rs @@ -86,9 +86,16 @@ pub struct TlsExtensions { pub supported_versions: bool, pub compress_certificate: Option>, pub application_settings: bool, + /// Use new ALPS codepoint (17613) instead of old (17513). Chrome 136+ uses new codepoint. + pub use_new_alps_codepoint: bool, pub delegated_credentials: bool, pub record_size_limit: Option, pub extension_order: Vec, + /// Whether to enable session tickets (TLS 1.2). Defaults to true. + /// Set to false for browsers like Safari 18.0 that don't send session_ticket extension. + pub session_ticket: bool, + /// Whether to send padding extension (RFC7685). + pub padding: bool, } impl TlsExtensions { @@ -122,11 +129,29 @@ impl TlsExtensions { supported_versions, compress_certificate, application_settings, + use_new_alps_codepoint: false, delegated_credentials, record_size_limit, extension_order, + session_ticket: true, + padding: false, } } + + pub fn with_session_ticket(mut self, enabled: bool) -> Self { + self.session_ticket = enabled; + self + } + + pub fn with_new_alps_codepoint(mut self, use_new: bool) -> Self { + self.use_new_alps_codepoint = use_new; + self + } + + pub fn with_padding(mut self, enabled: bool) -> Self { + self.padding = enabled; + self + } } /// ECH (Encrypted Client Hello) configuration. @@ -236,6 +261,7 @@ impl TlsFingerprint { .iter() .map(|kg| match kg { KeyExchangeGroup::X25519 => FingerprintKeyExchangeGroup::X25519, + KeyExchangeGroup::X25519MLKEM768 => FingerprintKeyExchangeGroup::X25519MLKEM768, KeyExchangeGroup::Secp256r1 => FingerprintKeyExchangeGroup::Secp256r1, KeyExchangeGroup::Secp384r1 => FingerprintKeyExchangeGroup::Secp384r1, KeyExchangeGroup::Secp521r1 => FingerprintKeyExchangeGroup::Secp521r1, @@ -293,9 +319,11 @@ impl TlsFingerprint { grease: has_grease, signed_certificate_timestamp: self.extensions.signed_certificate_timestamp, application_settings: self.extensions.application_settings, + use_new_alps_codepoint: self.extensions.use_new_alps_codepoint, delegated_credentials: self.extensions.delegated_credentials, record_size_limit: self.extensions.record_size_limit, renegotiation_info: true, // Common for both browsers + padding: self.extensions.padding, }; let cert_compression = self.extensions.compress_certificate.clone().map(|algos| { diff --git a/impit/src/fingerprint/types.rs b/impit/src/fingerprint/types.rs index 6f1953aa..00028f03 100644 --- a/impit/src/fingerprint/types.rs +++ b/impit/src/fingerprint/types.rs @@ -34,6 +34,8 @@ pub enum CipherSuite { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum KeyExchangeGroup { X25519, + /// X25519 with MLKEM768 (post-quantum hybrid) + X25519MLKEM768, Secp256r1, Secp384r1, Secp521r1, @@ -76,6 +78,7 @@ pub enum ExtensionType { MaxFragmentLength, StatusRequest, SupportedGroups, + EcPointFormats, SignatureAlgorithms, UseSrtp, Heartbeat, @@ -95,6 +98,7 @@ pub enum ExtensionType { SignatureAlgorithmsCert, KeyShare, ExtendedMasterSecret, + RenegotiationInfo, SessionTicket, CompressCertificate, ApplicationSettings, diff --git a/impit/src/impit.rs b/impit/src/impit.rs index 8a7437d5..f52f796b 100644 --- a/impit/src/impit.rs +++ b/impit/src/impit.rs @@ -60,7 +60,7 @@ pub enum RedirectBehavior { /// # #[tokio::main] /// # async fn main() { /// let impit = Impit::::builder() -/// .with_fingerprint(fingerprints::firefox_128::fingerprint()) +/// .with_fingerprint(fingerprints::firefox_144::fingerprint()) /// .with_ignore_tls_errors(true) /// .with_proxy("http://localhost:8080".to_string()) /// .with_default_timeout(Duration::from_secs(10)) diff --git a/impit/src/lib.rs b/impit/src/lib.rs index 66ac3829..611faaf4 100644 --- a/impit/src/lib.rs +++ b/impit/src/lib.rs @@ -11,7 +11,7 @@ //! #[tokio::main] //! async fn main() { //! let impit = Impit::::builder() -//! .with_fingerprint(fingerprints::firefox_128::fingerprint()) +//! .with_fingerprint(fingerprints::firefox_144::fingerprint()) //! .with_http3() //! .build() //! .unwrap(); diff --git a/impit/src/tls/mod.rs b/impit/src/tls/mod.rs index 63638b4e..9db22972 100644 --- a/impit/src/tls/mod.rs +++ b/impit/src/tls/mod.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex, OnceLock}; use crate::fingerprint::TlsFingerprint; use reqwest::Version; use rustls::client::danger::NoVerifier; -use rustls::client::EchGreaseConfig; +use rustls::client::{EchGreaseConfig, Resumption, Tls12Resumption}; use rustls::crypto::CryptoProvider; use rustls_platform_verifier::Verifier; @@ -134,6 +134,8 @@ impl TlsConfigBuilder { let rustls_fingerprint = fp.to_rustls_fingerprint(); let alpn_protocols = fp.alpn_protocols.to_vec(); + let enable_session_ticket = fp.extensions.session_ticket; + let ech_enabled = fp.ech_config.is_some(); let (crypto_provider_arc, verifier) = if let Some(b) = cache_browser { get_or_create_browser_provider_and_verifier(b) @@ -154,17 +156,34 @@ impl TlsConfigBuilder { (provider, verifier) }; - let mut config: rustls::ClientConfig = + // Only enable ECH if the fingerprint requests it + let mut config: rustls::ClientConfig = if ech_enabled { rustls::ClientConfig::builder_with_provider(crypto_provider_arc) .with_ech(get_ech_mode()) .unwrap() .dangerous() .with_custom_certificate_verifier(verifier) .with_tls_fingerprint(rustls_fingerprint) - .with_no_client_auth(); + .with_no_client_auth() + } else { + rustls::ClientConfig::builder_with_provider(crypto_provider_arc) + .with_safe_default_protocol_versions() + .unwrap() + .dangerous() + .with_custom_certificate_verifier(verifier) + .with_tls_fingerprint(rustls_fingerprint) + .with_no_client_auth() + }; config.alpn_protocols = alpn_protocols; + // Configure session resumption based on fingerprint + if !enable_session_ticket { + // Disable session tickets but keep session ID resumption + config.resumption = Resumption::in_memory_sessions(256) + .tls12_resumption(Tls12Resumption::SessionIdOnly); + } + if ignore_tls_errors { config .dangerous()