lib.rs (15732B)
1 #[macro_use] 2 extern crate hyper; 3 extern crate protobuf; 4 extern crate rand; 5 extern crate sha1; 6 extern crate rustc_serialize; 7 extern crate jconfig; 8 extern crate regex; 9 extern crate url; 10 extern crate tokio_core; 11 extern crate futures; 12 extern crate hyper_tls; 13 14 pub mod auth { 15 use hyper::{Client, Body, Uri, Error}; 16 use hyper::header::Headers; 17 use hyper_tls::HttpsConnector; 18 use tokio_core::reactor::Core; 19 fn do_auth_step(client: &Client<HttpsConnector, Body>, url: Uri, resp_body: &str, email: String, password: String, resp_headers_raw: Headers) -> Result<(Headers, String), Error> { 20 use hyper::header::{Headers, SetCookie, UserAgent}; 21 use hyper::client::Request; 22 use hyper::Method; 23 use regex::Regex; 24 use std::str; 25 use url::form_urlencoded; 26 use futures::{Future, Stream}; 27 use futures::future; 28 29 let mut core = Core::new().unwrap(); 30 header! { (ContentType, "content-type") => [String] } 31 header! { (GAPS, "GAPS") => [String] } 32 header! { (GALX, "GALX") => [String] } 33 34 let mut req_headers = Headers::new(); 35 if resp_headers_raw.has::<SetCookie>() { 36 let resp_headers = resp_headers_raw.get_raw("Set-Cookie").unwrap(); 37 let mut resp_headers_string = String::new(); 38 for elem in resp_headers.iter() { 39 let s = match str::from_utf8(elem) { 40 Ok(v) => v, 41 Err(e) => panic!("Invalid UTF-8 sequence: {}", e), 42 }; 43 resp_headers_string.push_str(s); 44 } 45 let resp_cookie_gaps_re = Regex::new("(?:GAPS=)(.*?)(?:;)").unwrap(); 46 let resp_cookie_gaps_captures = resp_cookie_gaps_re.captures(resp_headers_string.as_str()).unwrap(); 47 let resp_cookie_gaps = resp_cookie_gaps_captures.get(1).map_or("", |m| m.as_str()); 48 49 let resp_cookie_galx_re = Regex::new("(?:GALX=)(.*?)(?:;)").unwrap(); 50 let resp_cookie_galx_captures = resp_cookie_galx_re.captures(resp_headers_string.as_str()).unwrap(); 51 let resp_cookie_galx = resp_cookie_galx_captures.get(1).map_or("", |m| m.as_str()); 52 53 if resp_cookie_gaps != "" { 54 req_headers.set(GAPS(resp_cookie_gaps.to_owned())); 55 } 56 if resp_cookie_galx != "" { 57 req_headers.set(GALX(resp_cookie_galx.to_owned())); 58 } 59 } 60 61 let resp_page_re = Regex::new("(?:<input.*name=\"Page\".*)(?:value=\"([^\"]*))").unwrap(); 62 let resp_page = match resp_page_re.captures(resp_body) { 63 Some(caps) => { 64 caps.get(1).map_or("", |m| m.as_str()) 65 } 66 None => { 67 "" 68 } 69 }; 70 71 let resp_galx_re = Regex::new("(?:<input.*name=\"GALX\".*)(?:value=\"([^\"]*))").unwrap(); 72 let resp_galx = match resp_galx_re.captures(resp_body) { 73 Some(caps) => { 74 caps.get(1).map_or("", |m| m.as_str()) 75 } 76 None => { 77 "" 78 } 79 }; 80 81 let resp_gxf_re = Regex::new("(?:<input.*name=\"gxf\".*)(?:value=\"([^\"]*))").unwrap(); 82 let resp_gxf = match resp_gxf_re.captures(resp_body) { 83 Some(caps) => { 84 caps.get(1).map_or("", |m| m.as_str()) 85 } 86 None => { 87 "" 88 } 89 }; 90 91 let resp_continue_re = Regex::new("(?:<input.*name=\"continue\".*)(?:value=\"([^\"]*))").unwrap(); 92 let resp_gcontinue = match resp_continue_re.captures(resp_body) { 93 Some(caps) => { 94 caps.get(1).map_or("", |m| m.as_str()) 95 } 96 None => { 97 "" 98 } 99 }; 100 101 let resp_ltmpl_re = Regex::new("(?:<input.*name=\"ltmpl\".*)(?:value=\"([^\"]*))").unwrap(); 102 let resp_ltmpl = match resp_ltmpl_re.captures(resp_body) { 103 Some(caps) => { 104 caps.get(1).map_or("", |m| m.as_str()) 105 } 106 None => { 107 "" 108 } 109 }; 110 111 let resp_scc_re = Regex::new("(?:<input.*name=\"scc\".*)(?:value=\"([^\"]*))").unwrap(); 112 let resp_scc = match resp_scc_re.captures(resp_body) { 113 Some(caps) => { 114 caps.get(1).map_or("", |m| m.as_str()) 115 } 116 None => { 117 "" 118 } 119 }; 120 121 let resp_sarp_re = Regex::new("(?:<input.*name=\"sarp\".*)(?:value=\"([^\"]*))").unwrap(); 122 let resp_sarp = match resp_sarp_re.captures(resp_body) { 123 Some(caps) => { 124 caps.get(1).map_or("", |m| m.as_str()) 125 } 126 None => { 127 "" 128 } 129 }; 130 131 let resp_oauth_re = Regex::new("(?:<input.*name=\"oresp\".*)(?:value=\"([^\"]*))").unwrap(); 132 let resp_oauth = match resp_oauth_re.captures(resp_body) { 133 Some(caps) => { 134 caps.get(1).map_or("", |m| m.as_str()) 135 } 136 None => { 137 "" 138 } 139 }; 140 141 let resp_profile_information_re = Regex::new("(?:<input.*name=\"ProfileInformation\".*)(?:value=\"([^\"]*))").unwrap(); 142 let resp_profile_information = match resp_profile_information_re.captures(resp_body) { 143 Some(caps) => { 144 caps.get(1).map_or("", |m| m.as_str()) 145 } 146 None => { 147 "" 148 } 149 }; 150 151 let resp_session_state_re = Regex::new("(?:<input.*name=\"SessionState\".*)(?:value=\"([^\"]*))").unwrap(); 152 let resp_session_state = match resp_session_state_re.captures(resp_body) { 153 Some(caps) => { 154 caps.get(1).map_or("", |m| m.as_str()) 155 } 156 None => { 157 "" 158 } 159 }; 160 161 let resp__utf8_re = Regex::new("(?:<input.*name=\"_utf8\".*)(?:value=\"([^\"]*))").unwrap(); 162 let resp__utf8 = match resp__utf8_re.captures(resp_body) { 163 Some(caps) => { 164 caps.get(1).map_or("", |m| m.as_str()) 165 } 166 None => { 167 "" 168 } 169 }; 170 171 let resp_bgresponse_re = Regex::new("(?:<input.*name=\"bgresponse\".*)(?:value=\"([^\"]*))").unwrap(); 172 let resp_bgresponse = match resp_bgresponse_re.captures(resp_body) { 173 Some(caps) => { 174 caps.get(1).map_or("", |m| m.as_str()) 175 } 176 None => { 177 "" 178 } 179 }; 180 181 let body_send: String = form_urlencoded::Serializer::new(String::new()) 182 .append_pair("Page", resp_page) 183 .append_pair("GALX", resp_galx) 184 .append_pair("gxf", resp_gxf) 185 .append_pair("continue", resp_gcontinue.replace("&", "&").as_str()) 186 .append_pair("ltmpl", resp_ltmpl) 187 .append_pair("scc", resp_scc) 188 .append_pair("sarp", resp_sarp) 189 .append_pair("oauth", resp_oauth) 190 .append_pair("ProfileInformation", resp_profile_information) 191 .append_pair("SessionState", resp_session_state) 192 .append_pair("_utf8", resp__utf8) 193 .append_pair("bgresponse", resp_bgresponse) 194 .append_pair("Email", email.as_str()) 195 .append_pair("Passwd", password.as_str()) 196 .append_pair("pstMsg", "0") 197 .append_pair("checkConnection", "") 198 .append_pair("checkedDomains", "youtube") 199 .append_pair("signIn", "Anmelden") 200 .append_pair("PersistentCookie", "no") 201 .finish(); 202 203 // Do Email Login 204 let mut fresh_request = Request::new(Method::Post, url); 205 fresh_request.headers_mut().set(ContentType(String::from("application/x-www-form-urlencoded".to_owned()))); 206 fresh_request.headers_mut().set(UserAgent::new("Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36".to_owned())); 207 fresh_request.set_body(body_send); 208 209 let post = client.request(fresh_request) 210 .and_then(|res| { 211 let headers = res.headers().clone(); 212 res.body().fold(Vec::new(), |mut v, chunk| { 213 v.extend(&chunk[..]); 214 future::ok::<_, Error>(v) 215 }).and_then(|chunks| { 216 let s = String::from_utf8(chunks).unwrap(); 217 future::ok::<_, Error>((headers, s)) 218 }) 219 }); 220 221 let (headers, body) = core.run(post).unwrap(); 222 223 Ok((headers, body)) 224 } 225 226 fn write_cookie_config() { 227 // let mut config = get_configs().unwrap(); 228 // 229 // config.set::<SAPISID>().unwrap(); 230 // config.set::<HSID>().unwrap(); 231 // config.set::<SSID>().unwrap(); 232 // config.set::<SAPISID>().unwrap(); 233 // config.set::<SAPISID>().unwrap(); 234 // config.set_raw("SAPISID", ) 235 // config.set_raw("HSID", ) 236 // config.set_raw("SSID", ) 237 // config.set_raw("APISID", ) 238 // config.set_raw("SID", ) 239 } 240 241 pub fn get_auth(mut client_email: String, mut client_passwd: String) { 242 use hyper::{Uri, Client, Error}; 243 use hyper::header::Location; 244 245 use std::io::{stdin, stdout, Write}; 246 use std::str; 247 use regex::Regex; 248 249 use tokio_core::reactor::Core; 250 use futures::{Future, Stream}; 251 use futures::future; 252 253 let mut core = Core::new().unwrap(); 254 let handle = core.handle(); 255 let client = Client::configure() 256 .keep_alive(true) 257 .connector(HttpsConnector::new(4,&handle)) 258 .build(&handle); 259 260 let auth_uri = "https://accounts.google.com/o/oauth2/programmatic_auth?scope=https://www.google.com/accounts/OAuthLogin+https://www.googleapis.com/auth/userinfo.email&client_id=936475272427.apps.googleusercontent.com".parse::<Uri>().unwrap(); 261 let email_uri = "https://accounts.google.com/signin/v1/lookup".parse::<Uri>().unwrap(); 262 let passwd_uri = "https://accounts.google.com/signin/challenge/sl/password".parse::<Uri>().unwrap(); 263 264 if client_email == String::from("") { 265 println!(""); 266 println!("Please enter Google Email: "); 267 let _ = stdout().flush(); 268 stdin() 269 .read_line(&mut client_email) 270 .expect("Did not enter a correct Email"); 271 if let Some('\n') = client_email.chars().next_back() { 272 client_email.pop(); 273 } 274 if let Some('\r') = client_email.chars().next_back() { 275 client_email.pop(); 276 } 277 } 278 println!("You typed: {}", client_email); 279 280 if client_passwd == String::from("") { 281 println!("Please enter Google Password: "); 282 let _ = stdout().flush(); 283 stdin() 284 .read_line(&mut client_passwd) 285 .expect("Did not enter a correct Password"); 286 if let Some('\n') = client_passwd.chars().next_back() { 287 client_passwd.pop(); 288 } 289 if let Some('\r') = client_passwd.chars().next_back() { 290 client_passwd.pop(); 291 } 292 } 293 println!("You typed: {}", client_passwd); 294 295 // Login Step1 296 // TODO Make it pretty 297 let req1 = client.get(auth_uri) 298 .and_then(|res| { 299 let headers = res.headers().clone(); 300 future::ok::<_, Error>(headers) 301 }); 302 303 let headers = core.run(req1).unwrap(); 304 305 let new_location = format!("{:?}", headers.get::<Location>().unwrap()).parse::<Uri>().unwrap(); 306 307 let req = client.get(new_location) 308 .and_then(|res| { 309 res.body().fold(Vec::new(), |mut v, chunk| { 310 v.extend(&chunk[..]); 311 future::ok::<_, Error>(v) 312 }).and_then(|chunks| { 313 let s = String::from_utf8(chunks).unwrap(); 314 future::ok::<_, Error>(s) 315 }) 316 }); 317 318 let body = core.run(req).unwrap(); 319 320 let new_location_re = Regex::new("(?:<A.*)(?:HREF=\"([^\"]*))").unwrap(); 321 let new_location_captures = new_location_re.captures(body.as_str()).unwrap(); 322 let new_location_raw = new_location_captures.get(1).map_or("", |m| m.as_str()); 323 let new_location = new_location_raw.parse::<Uri>().unwrap(); 324 325 let req = client.get(new_location) 326 .and_then(|res| { 327 let headers = res.headers().clone(); 328 res.body().fold(Vec::new(), |mut v, chunk| { 329 v.extend(&chunk[..]); 330 future::ok::<_, Error>(v) 331 }).and_then(|chunks| { 332 let s = String::from_utf8(chunks).unwrap(); 333 future::ok::<_, Error>((headers, s)) 334 }) 335 }); 336 337 let (headers, body) = core.run(req).unwrap(); 338 339 let (headers, body) = do_auth_step(&client, email_uri, &body, client_email.clone(), client_passwd.clone(), headers).unwrap(); 340 let (headers, body) = do_auth_step(&client, passwd_uri, &body, client_email.clone(), client_passwd.clone(), headers).unwrap(); 341 342 println!(""); 343 print!("{:?}", body); 344 } 345 } 346 347 pub mod hangups; 348 349 pub mod helper{ 350 use jconfig::config::Config; 351 use jconfig::error::Error; 352 353 fn check_generate_configs() { 354 use std::fs::{File, create_dir_all}; 355 use std::env; 356 use std::io::Write; 357 // TODO Add handling if there is no home dir. 358 // match std::env::home_dir() { 359 // Some(dir) => { 360 // //There is a home directory, do something with the dir variable 361 // }, 362 // None => { 363 // //There is no home directory, do something else 364 // } 365 // } 366 367 //Memory File 368 let mut memory_path = env::home_dir().unwrap(); 369 memory_path.push(".local/share/hangups/"); 370 create_dir_all(memory_path.as_path()).unwrap(); 371 memory_path.push("memory.json"); 372 let mut f = File::create(memory_path.as_path()).unwrap(); 373 f.write_all(b"{}").unwrap(); 374 f.sync_all().unwrap(); 375 376 //Config File 377 let mut config_path = env::home_dir().unwrap(); 378 config_path.push(".local/share/hangups/"); 379 create_dir_all(config_path.as_path()).unwrap(); 380 config_path.push("config.json"); 381 let mut f = File::create(config_path.as_path()).unwrap(); 382 f.write_all(b"{}").unwrap(); 383 f.sync_all().unwrap(); 384 } 385 pub fn get_configs() -> Result<Config, Error>{ 386 use std::env; 387 388 check_generate_configs(); 389 390 let mut memory_path = env::home_dir().unwrap(); 391 memory_path.push(".local/share/hangups/"); 392 memory_path.push("memory.json"); 393 394 // Load the memory 395 let config = Config::load(memory_path.as_path()).unwrap(); 396 397 Ok(config) 398 } 399 }