Advertisement
Guest User

Untitled

a guest
Apr 28th, 2016
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 6.52 KB | None | 0 0
  1. // Copyright 2016 Matthew Collins
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. //     http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14.  
  15. use openssl::crypto::hash;
  16. use serde_json;
  17. use serde_json::builder::ObjectBuilder;
  18. use hyper;
  19.  
  20. #[derive(Clone, Debug)]
  21. pub struct Profile {
  22.     pub username: String,
  23.     pub id: String,
  24.     pub access_token: String,
  25. }
  26.  
  27. const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join";
  28. const LOGIN_URL: &'static str = "https://authserver.mojang.com/authenticate";
  29. const REFRESH_URL: &'static str = "https://authserver.mojang.com/refresh";
  30. const VALIDATE_URL: &'static str = "https://authserver.mojang.com/validate";
  31.  
  32. impl Profile {
  33.     pub fn login(username: &str, password: &str, token: &str) -> Result<Profile, super::Error> {
  34.         let req_msg = ObjectBuilder::new()
  35.                            .insert("username", username)
  36.                            .insert("password", password)
  37.                            .insert("clientToken", token)
  38.                            .insert_object("agent", |b| b
  39.                                 .insert("name", "Minecraft")
  40.                                 .insert("version", 1)
  41.                             )
  42.                            .unwrap();
  43.         let req = try!(serde_json::to_string(&req_msg));
  44.  
  45.         let client = hyper::Client::new();
  46.         let res = try!(client.post(LOGIN_URL)
  47.                         .body(&req)
  48.                         .header(hyper::header::ContentType("application/json".parse().unwrap()))
  49.                         .send());
  50.  
  51.         let ret: serde_json::Value = try!(serde_json::from_reader(res));
  52.         if let Some(error) = ret.find("error").and_then(|v| v.as_string()) {
  53.             return Err(super::Error::Err(format!(
  54.                 "{}: {}",
  55.                 error,
  56.                 ret.find("errorMessage").and_then(|v| v.as_string()).unwrap())
  57.             ));
  58.         }
  59.         Ok(Profile {
  60.             username: ret.lookup("selectedProfile.name").and_then(|v| v.as_string()).unwrap().to_owned(),
  61.             id: ret.lookup("selectedProfile.id").and_then(|v| v.as_string()).unwrap().to_owned(),
  62.             access_token: ret.find("accessToken").and_then(|v| v.as_string()).unwrap().to_owned(),
  63.         })
  64.     }
  65.  
  66.     pub fn refresh(self, token: &str) -> Result<Profile, super::Error> {
  67.         let req_msg = ObjectBuilder::new()
  68.                            .insert("accessToken", self.access_token.clone())
  69.                            .insert("clientToken", token)
  70.                            .unwrap();
  71.         let req = try!(serde_json::to_string(&req_msg));
  72.  
  73.         let client = hyper::Client::new();
  74.         let res = try!(client.post(VALIDATE_URL)
  75.                         .body(&req)
  76.                         .header(hyper::header::ContentType("application/json".parse().unwrap()))
  77.                         .send());
  78.  
  79.         if res.status != hyper::status::StatusCode::NoContent {
  80.             // Refresh needed
  81.             let res = try!(client.post(REFRESH_URL)
  82.                             .body(&req)
  83.                             .header(hyper::header::ContentType("application/json".parse().unwrap()))
  84.                             .send());
  85.  
  86.             let ret: serde_json::Value = try!(serde_json::from_reader(res));
  87.             if let Some(error) = ret.find("error").and_then(|v| v.as_string()) {
  88.                 return Err(super::Error::Err(format!(
  89.                     "{}: {}",
  90.                     error,
  91.                     ret.find("errorMessage").and_then(|v| v.as_string()).unwrap())
  92.                 ));
  93.             }
  94.             return Ok(Profile {
  95.                 username: ret.lookup("selectedProfile.name").and_then(|v| v.as_string()).unwrap().to_owned(),
  96.                 id: ret.lookup("selectedProfile.id").and_then(|v| v.as_string()).unwrap().to_owned(),
  97.                 access_token: ret.find("accessToken").and_then(|v| v.as_string()).unwrap().to_owned(),
  98.             });
  99.         }
  100.         Ok(self)
  101.     }
  102.  
  103.     pub fn join_server(&self, server_id: &str, shared_key: &[u8], public_key: &[u8]) -> Result<(), super::Error> {
  104.         use std::io::Write;
  105.         let mut sha1 = hash::Hasher::new(hash::Type::SHA1);
  106.         sha1.write_all(server_id.as_bytes()).unwrap();
  107.         sha1.write_all(shared_key).unwrap();
  108.         sha1.write_all(public_key).unwrap();
  109.         let mut hash = sha1.finish();
  110.  
  111.         // Mojang uses a hex method which allows for
  112.         // negatives so we have to account for that.
  113.         let negative = (hash[0] & 0x80) == 0x80;
  114.         if negative {
  115.             twos_compliment(&mut hash);
  116.         }
  117.         let hash_str = hash.iter().map(|b| format!("{:02x}", b)).collect::<Vec<String>>().join("");
  118.         let hash_val = hash_str.trim_left_matches('0');
  119.         let hash_str = if negative {
  120.             "-".to_owned() + &hash_val[..]
  121.         } else {
  122.             hash_val.to_owned()
  123.         };
  124.  
  125.         let join_msg = ObjectBuilder::new()
  126.                            .insert("accessToken", &self.access_token)
  127.                            .insert("selectedProfile", &self.id)
  128.                            .insert("serverId", hash_str)
  129.                            .unwrap();
  130.         let join = serde_json::to_string(&join_msg).unwrap();
  131.  
  132.         let client = hyper::Client::new();
  133.         let res = try!(client.post(JOIN_URL)
  134.                         .body(&join)
  135.                         .header(hyper::header::ContentType("application/json".parse().unwrap()))
  136.                         .send());
  137.  
  138.         if res.status == hyper::status::StatusCode::NoContent {
  139.             Ok(())
  140.         } else {
  141.             Err(super::Error::Err("Failed to auth with server".to_owned()))
  142.         }
  143.     }
  144.  
  145.     pub fn is_complete(&self) -> bool {
  146.         !self.username.is_empty() && !self.id.is_empty() && !self.access_token.is_empty()
  147.     }
  148. }
  149.  
  150. fn twos_compliment(data: &mut Vec<u8>) {
  151.     let mut carry = true;
  152.     for i in (0..data.len()).rev() {
  153.         data[i] = !data[i];
  154.         if carry {
  155.             carry = data[i] == 0xFF;
  156.             data[i] = data[i].wrapping_add(1);
  157.         }
  158.     }
  159. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement