1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::collections::HashMap;
use std::sync::Mutex;
use headless_chrome::{Browser, LaunchOptionsBuilder};
use reqwest::header::{HeaderName, HeaderValue};
use std::str::FromStr;
use headless_chrome::protocol::network::Cookie;
#[derive(Clone)]
pub struct LoginCaptureBrowserConfig {
pub login_page_url: String,
pub login_post_url: String,
pub is_correct_login_check_fn: &'static (dyn Fn(&str) -> bool + Sync),
}
pub struct LoginCaptureBrowser {
config: LoginCaptureBrowserConfig
}
#[derive(Debug, Clone)]
pub struct LoginCaptureBrowserLoginResult {
pub headers: HashMap<String, String>,
pub response: String,
pub cookies: Vec<Cookie>,
}
impl LoginCaptureBrowser {
pub fn new(config: LoginCaptureBrowserConfig) -> Self {
LoginCaptureBrowser {
config
}
}
pub fn run(&self) -> Result<LoginCaptureBrowserLoginResult, failure::Error> {
let (tx, rx) = std::sync::mpsc::channel();
let tx_mutex = Mutex::new(tx);
let browser = Browser::new(
LaunchOptionsBuilder::default()
.headless(false)
.build()
.expect("Could not find chrome-executable")
)?;
let tab = browser.wait_for_initial_tab()?;
tab.navigate_to(self.config.login_page_url.as_str())?;
tab.wait_until_navigated()?;
let config = self.config.clone();
tab.enable_request_interception(
&[
headless_chrome::protocol::network::methods::RequestPattern {
url_pattern: Some(self.config.login_post_url.as_str()),
resource_type: Some("XHR"),
interception_stage: Some("HeadersReceived"),
}
],
Box::new(move |_transport, _session_id, event_params| {
let post_data = event_params.request.post_data.unwrap();
let headers = event_params.request.headers;
let client = reqwest::Client::new();
let mut header_map = reqwest::header::HeaderMap::new();
for (key, value) in &headers {
let header_name = HeaderName::from_str(key.as_str()).unwrap();
let header_value = HeaderValue::from_str(value.as_str()).unwrap();
header_map.append(header_name, header_value);
}
let mut response = client.post(config.login_post_url.as_str())
.headers(header_map)
.body(post_data)
.send()
.unwrap();
let response_text = response.text().unwrap();
let success = (config.is_correct_login_check_fn)(response_text.as_str());
if success {
let tx = tx_mutex.lock().unwrap();
tx.send((
String::from(response_text),
headers,
)).unwrap();
}
headless_chrome::browser::tab::RequestInterceptionDecision::Continue
}),
)?;
let ret = rx.recv()?;
let result = LoginCaptureBrowserLoginResult {
response: ret.0,
headers: ret.1,
cookies: tab.get_cookies()?
};
Ok(result)
}
}