hangups-rs

Rust version of hangups (WIP) Currently Login not possible
git clone git://archive.git.mtrnord.blog/Nordgedanken/hangups-rs.git
Log | Files | Refs | README | LICENSE

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("&amp;", "&").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 }