Skip to main content

rustenium_identity/
lib.rs

1pub mod cdp;
2pub mod error;
3pub mod identity;
4pub mod local_proxy_server;
5pub mod preset;
6pub mod script;
7pub mod tz;
8pub mod ua;
9
10use error::IdentityError;
11use local_proxy_server::start_overlay;
12use rustenium::browsers::{
13    BidiBrowser,
14    chrome::browser::{ChromeBrowser, ChromeConfig},
15};
16
17pub use error::IdentityError as Error;
18pub use identity::*;
19
20/// Configuration for launching an identity-spoofed browser session.
21pub struct IdentityConfig {
22    pub identity: Identity,
23    pub chrome: ChromeConfig,
24}
25
26impl From<Identity> for IdentityConfig {
27    fn from(identity: Identity) -> Self {
28        Self {
29            identity,
30            chrome: ChromeConfig {
31                enable_bidi: false,
32                enable_cdp: true,
33                ..Default::default()
34            },
35        }
36    }
37}
38
39impl IdentityConfig {
40    pub fn new(identity: Identity, chrome: ChromeConfig) -> Self {
41        Self { identity, chrome }
42    }
43}
44
45/// A rustenium browser session with an identity applied.
46pub struct IdentitySession {
47    identity: Identity,
48    browser: ChromeBrowser,
49}
50
51impl IdentitySession {
52    /// Launch a new Chromium instance from the given config.
53    /// Applies all CDP emulation overrides and registers the stealth
54    /// bootstrap script before returning.
55    pub async fn launch(config: impl Into<IdentityConfig>) -> Result<Self, IdentityError> {
56        let config = config.into();
57        let timezone = tz::resolve_timezone(
58            config.identity.timezone.as_deref(),
59            config.identity.proxy.as_deref(),
60        )
61        .await?;
62
63        let mut chrome_config = config.chrome;
64        chrome_config.enable_bidi = false;
65        chrome_config.enable_cdp = true;
66
67        if let Some(ref proxy_url) = config.identity.proxy {
68            if !proxy_url.is_empty() {
69                let local_addr = start_overlay(proxy_url)
70                    .await
71                    .map_err(|e| IdentityError::ProxyError(e.to_string()))?;
72                let mut flags = chrome_config.browser_flags.unwrap_or_default();
73                flags.push(format!(
74                    "--proxy-server=http://127.0.0.1:{}",
75                    local_addr.port()
76                ));
77                chrome_config.browser_flags = Some(flags);
78            }
79        }
80
81        let mut browser = ChromeBrowser::new(chrome_config).await;
82
83        cdp::apply_identity(&mut browser, &config.identity, &timezone).await?;
84
85        Ok(Self {
86            identity: config.identity,
87            browser,
88        })
89    }
90
91    /// Access the underlying rustenium ChromeBrowser.
92    pub fn browser(&self) -> &ChromeBrowser {
93        &self.browser
94    }
95
96    /// Mutable access to the underlying rustenium ChromeBrowser.
97    pub fn browser_mut(&mut self) -> &mut ChromeBrowser {
98        &mut self.browser
99    }
100
101    /// Get the identity.
102    pub fn identity(&self) -> &Identity {
103        &self.identity
104    }
105
106    pub async fn close(self) -> bool {
107        self.browser.close().await.map_err(|_| false).is_ok()
108    }
109}