mod.rs (8022B)
1 #[path = "proto/hangouts.rs"] mod hangouts; 2 3 pub mod hangups { 4 use hangups::hangouts::{MessageContent, Segment, SegmentType, RequestHeader, 5 EventRequestHeader, SendChatMessageRequest, DeliveryMediumType, 6 OffTheRecordStatus, EventType, SendChatMessageResponse, 7 DeliveryMedium, ConversationId}; 8 use protobuf::RepeatedField; 9 use rand::random; 10 use hyper::header::Cookie; 11 use hyper::client::Request; 12 use hyper::{Method, Uri}; 13 use hyper::error::Error; 14 use protobuf::Message; 15 use std::collections::HashMap; 16 use std::time::*; 17 use sha1::Sha1; 18 use rustc_serialize::hex::ToHex; 19 use rustc_serialize::base64::FromBase64; 20 use protobuf::core::parse_from_bytes; 21 use auth::get_auth; 22 use helper::get_configs; 23 use std; 24 25 header! { (ContentType, "content-type") => [String] } 26 header! { 27 (XGoogEncodeResponseIfExecutable, "X-Goog-Encode-Response-If-Executable") => [String] 28 } 29 30 fn get_cookies() -> Result<HashMap<String, String>, Error> { 31 let config = get_configs().unwrap(); 32 if (config.get_raw("SAPISID") == None) || (config.get_raw("HSID") == None) || (config.get_raw("SSID") == None) || (config.get_raw("APISID") == None) || (config.get_raw("SID") == None) { 33 get_auth(String::from(""), String::from("")); 34 } 35 36 let sapisid_cookie = String::from(config.get_raw("SAPISID").unwrap().as_string().unwrap()); 37 let hsid_cookie = String::from(config.get_raw("HSID").unwrap().as_string().unwrap()); 38 let ssid_cookie = String::from(config.get_raw("SSID").unwrap().as_string().unwrap()); 39 let apisid_cookie = String::from(config.get_raw("APISID").unwrap().as_string().unwrap()); 40 let sid_cookie = String::from(config.get_raw("SID").unwrap().as_string().unwrap()); 41 42 let mut cookies = HashMap::new(); 43 cookies.insert(String::from("SAPISID"), sapisid_cookie); 44 cookies.insert(String::from("HSID"), hsid_cookie); 45 cookies.insert(String::from("SSID"), ssid_cookie); 46 cookies.insert(String::from("APISID"), apisid_cookie); 47 cookies.insert(String::from("SID"), sid_cookie); 48 Ok(cookies) 49 } 50 51 fn get_auth_headers(sapisid: String) -> Result<HashMap<String, String>, Error> { 52 let origin_url = String::from("https://talkgadget.google.com"); 53 let now = SystemTime::now(); 54 let dur = now.duration_since(UNIX_EPOCH).unwrap(); 55 let timestamp_msec = dur.as_secs(); 56 57 58 let auth_string = String::from(format!("{} {} {}", timestamp_msec, sapisid, origin_url)); 59 let mut hash = Sha1::new(); 60 hash.update(auth_string.as_bytes()); 61 let hash_bytes = hash.digest().bytes(); 62 let hex_sha1 = hash_bytes.to_hex(); 63 let sapisid_hash = format!("SAPISIDHASH {}_{}", timestamp_msec, hex_sha1); 64 let mut auth_cookies = HashMap::new(); 65 auth_cookies.insert(String::from("authorization"), sapisid_hash); 66 auth_cookies.insert(String::from("x-origin"), origin_url); 67 auth_cookies.insert(String::from("x-goog-authuser"), String::from("0")); 68 Ok(auth_cookies) 69 } 70 71 fn api_request(endpoint_url: String, 72 content_type: String, 73 response_type: String, 74 payload: std::vec::Vec<u8>) 75 -> Result<String, Error> { 76 use hyper::Client; 77 use tokio_core::reactor::Core; 78 use futures::Future; 79 80 let mut core = Core::new().unwrap(); 81 let handle = core.handle(); 82 let client = Client::configure() 83 .keep_alive(true) 84 .build(&handle); 85 let url = format!("{}?key=AIzaSyAfFJCeph-euFSwtmqFZi0kaKk-cZ5wufM&alt={}", 86 endpoint_url, 87 response_type).parse::<Uri>().unwrap();; 88 let auth_header = get_auth_headers(String::from("PLACEHOLDER")) 89 .unwrap(); 90 let mut fresh_request = Request::new(Method::Post, url); 91 let cookies = get_cookies().unwrap(); 92 let mut cookie_vec = Vec::new(); 93 for (key, val) in cookies { 94 cookie_vec.push(format!("{}={}", key, val)) 95 } 96 fresh_request.headers_mut().set(Cookie(cookie_vec)); 97 fresh_request.headers_mut().set(ContentType(String::from(content_type.to_owned()))); 98 fresh_request.headers_mut().set(XGoogEncodeResponseIfExecutable(String::from("base64".to_owned()))); 99 fresh_request.set_body(payload); 100 for (key, val) in auth_header { 101 fresh_request.headers_mut().append_raw(key, val.as_bytes().to_vec()); 102 } 103 let body = String::new(); 104 105 let post = client.request(fresh_request) 106 .map(|res| { 107 let body = res.body(); 108 println!("\n\nDone."); 109 body 110 }); 111 112 core.run(post).unwrap(); 113 114 Ok(body) 115 } 116 117 fn protobuf_api_request(api_endpoint: String, 118 request_struct: SendChatMessageRequest) 119 -> Result<SendChatMessageResponse, Error> { 120 let url = format!("https://clients6.google.com/chat/v1/{}", api_endpoint); 121 let payload = request_struct.write_to_bytes().unwrap(); 122 let output = api_request(url, 123 String::from("application/x-protobuf"), 124 String::from("proto"), 125 payload); 126 let decoded_output = output.unwrap().as_str().from_base64().unwrap(); 127 let response_proto = parse_from_bytes::<SendChatMessageResponse>(&decoded_output[..]) 128 .unwrap(); 129 Ok(response_proto) 130 } 131 132 pub fn send_message(message: String, 133 conv_id_raw: String) 134 -> Result<SendChatMessageResponse, Error> { 135 //Prepare message 136 let segment_type = SegmentType::SEGMENT_TYPE_TEXT; 137 let mut segment_raw = Segment::new(); 138 segment_raw.set_field_type(segment_type); 139 segment_raw.set_text(message); 140 let mut segment = RepeatedField::new(); 141 segment.push(segment_raw); 142 let mut message_content = MessageContent::new(); 143 message_content.set_segment(segment); 144 145 146 //Prepare Request 147 let mut request_header = RequestHeader::new(); 148 request_header.set_language_code(String::from("en")); 149 150 let mut delivery_medium = DeliveryMedium::new(); 151 delivery_medium.set_medium_type(DeliveryMediumType::DELIVERY_MEDIUM_BABEL); 152 let expected_otr = OffTheRecordStatus::OFF_THE_RECORD_STATUS_ON_THE_RECORD; 153 let client_generated_id = random::<u64>(); 154 let event_type = EventType::EVENT_TYPE_REGULAR_CHAT_MESSAGE; 155 let mut event_request_header = EventRequestHeader::new(); 156 let mut conv_id = ConversationId::new(); 157 conv_id.set_id(conv_id_raw); 158 event_request_header.set_conversation_id(conv_id); 159 event_request_header.set_delivery_medium(delivery_medium); 160 event_request_header.set_expected_otr(expected_otr); 161 event_request_header.set_client_generated_id(client_generated_id); 162 event_request_header.set_event_type(event_type); 163 164 let mut request = SendChatMessageRequest::new(); 165 request.set_request_header(request_header); 166 request.set_message_content(message_content); 167 request.set_event_request_header(event_request_header); 168 169 let output = protobuf_api_request(String::from("conversations/sendchatmessage"), request) 170 .unwrap(); 171 Ok(output) 172 } 173 } 174 175 #[cfg(test)] 176 mod tests { 177 #[test] 178 fn test_send_message() { 179 use super::hangups::send_message; 180 181 let test_message = String::from("Diese Nachricht sendet der Bot!"); 182 let test_conv = String::from("Ugxu9JRlbNPSqk5Ye1V4AaABAQ"); 183 send_message(test_message, test_conv); 184 } 185 }