Fully implement the login screen (Closes #6)
This commit is contained in:
parent
3d6f5ba904
commit
0d42d59ed9
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
use openssl;
|
use openssl;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use hyper;
|
||||||
|
|
||||||
pub mod mojang;
|
pub mod mojang;
|
||||||
|
|
||||||
|
@ -633,6 +634,8 @@ pub enum Error {
|
||||||
Err(String),
|
Err(String),
|
||||||
Disconnect(format::Component),
|
Disconnect(format::Component),
|
||||||
IOError(io::Error),
|
IOError(io::Error),
|
||||||
|
Json(serde_json::Error),
|
||||||
|
Hyper(hyper::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl convert::From<io::Error> for Error {
|
impl convert::From<io::Error> for Error {
|
||||||
|
@ -641,12 +644,26 @@ impl convert::From<io::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl convert::From<serde_json::Error> for Error {
|
||||||
|
fn from(e: serde_json::Error) -> Error {
|
||||||
|
Error::Json(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl convert::From<hyper::Error> for Error {
|
||||||
|
fn from(e: hyper::Error) -> Error {
|
||||||
|
Error::Hyper(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ::std::error::Error for Error {
|
impl ::std::error::Error for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Err(ref val) => &val[..],
|
Error::Err(ref val) => &val[..],
|
||||||
Error::Disconnect(_) => "Disconnect",
|
Error::Disconnect(_) => "Disconnect",
|
||||||
Error::IOError(ref e) => e.description(),
|
Error::IOError(ref e) => e.description(),
|
||||||
|
Error::Json(ref e) => e.description(),
|
||||||
|
Error::Hyper(ref e) => e.description(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -657,6 +674,8 @@ impl ::std::fmt::Display for Error {
|
||||||
Error::Err(ref val) => write!(f, "protocol error: {}", val),
|
Error::Err(ref val) => write!(f, "protocol error: {}", val),
|
||||||
Error::Disconnect(ref val) => write!(f, "{}", val),
|
Error::Disconnect(ref val) => write!(f, "{}", val),
|
||||||
Error::IOError(ref e) => e.fmt(f),
|
Error::IOError(ref e) => e.fmt(f),
|
||||||
|
Error::Json(ref e) => e.fmt(f),
|
||||||
|
Error::Hyper(ref e) => e.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@
|
||||||
|
|
||||||
use openssl;
|
use openssl;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use serde_json::builder::ObjectBuilder;
|
||||||
use hyper;
|
use hyper;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Profile {
|
pub struct Profile {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -23,9 +25,85 @@ pub struct Profile {
|
||||||
}
|
}
|
||||||
|
|
||||||
const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join";
|
const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join";
|
||||||
|
const LOGIN_URL: &'static str = "https://authserver.mojang.com/authenticate";
|
||||||
|
const REFRESH_URL: &'static str = "https://authserver.mojang.com/refresh";
|
||||||
|
const VALIDATE_URL: &'static str = "https://authserver.mojang.com/validate";
|
||||||
|
|
||||||
impl Profile {
|
impl Profile {
|
||||||
pub fn join_server(&self, server_id: &String, shared_key: &Vec<u8>, public_key: &Vec<u8>) {
|
pub fn login(username: &str, password: &str, token: &str) -> Result<Profile, super::Error> {
|
||||||
|
let req_msg = ObjectBuilder::new()
|
||||||
|
.insert("username", username)
|
||||||
|
.insert("password", password)
|
||||||
|
.insert("clientToken", token)
|
||||||
|
.insert_object("agent", |b| b
|
||||||
|
.insert("name", "Minecraft")
|
||||||
|
.insert("version", 1)
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let req = try!(serde_json::to_string(&req_msg));
|
||||||
|
|
||||||
|
let client = hyper::Client::new();
|
||||||
|
let res = try!(client.post(LOGIN_URL)
|
||||||
|
.body(&req)
|
||||||
|
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
||||||
|
.send());
|
||||||
|
|
||||||
|
let ret: serde_json::Value = try!(serde_json::from_reader(res));
|
||||||
|
if let Some(error) = ret.find("error").and_then(|v| v.as_string()) {
|
||||||
|
return Err(super::Error::Err(format!(
|
||||||
|
"{}: {}",
|
||||||
|
error,
|
||||||
|
ret.find("errorMessage").and_then(|v| v.as_string()).unwrap())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(Profile {
|
||||||
|
username: ret.lookup("selectedProfile.name").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
id: ret.lookup("selectedProfile.id").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
access_token: ret.find("accessToken").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn refresh(self, token: &str) -> Result<Profile, super::Error> {
|
||||||
|
let req_msg = ObjectBuilder::new()
|
||||||
|
.insert("accessToken", self.access_token.clone())
|
||||||
|
.insert("clientToken", token)
|
||||||
|
.unwrap();
|
||||||
|
let req = try!(serde_json::to_string(&req_msg));
|
||||||
|
|
||||||
|
let client = hyper::Client::new();
|
||||||
|
let res = try!(client.post(VALIDATE_URL)
|
||||||
|
.body(&req)
|
||||||
|
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
||||||
|
.send());
|
||||||
|
|
||||||
|
if res.status != hyper::status::StatusCode::NoContent {
|
||||||
|
println!("Rerefeshing");
|
||||||
|
// Refresh needed
|
||||||
|
let res = try!(client.post(REFRESH_URL)
|
||||||
|
.body(&req)
|
||||||
|
.header(hyper::header::ContentType("application/json".parse().unwrap()))
|
||||||
|
.send());
|
||||||
|
|
||||||
|
let ret: serde_json::Value = try!(serde_json::from_reader(res));
|
||||||
|
if let Some(error) = ret.find("error").and_then(|v| v.as_string()) {
|
||||||
|
return Err(super::Error::Err(format!(
|
||||||
|
"{}: {}",
|
||||||
|
error,
|
||||||
|
ret.find("errorMessage").and_then(|v| v.as_string()).unwrap())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return Ok(Profile {
|
||||||
|
username: ret.lookup("selectedProfile.name").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
id: ret.lookup("selectedProfile.id").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
access_token: ret.find("accessToken").and_then(|v| v.as_string()).unwrap().to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
println!("Reuse");
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
pub fn join_server(&self, server_id: &str, shared_key: &Vec<u8>, public_key: &Vec<u8>) {
|
||||||
let mut sha1 = openssl::SHA1::new();
|
let mut sha1 = openssl::SHA1::new();
|
||||||
sha1.update(server_id.as_bytes());
|
sha1.update(server_id.as_bytes());
|
||||||
sha1.update(&shared_key[..]);
|
sha1.update(&shared_key[..]);
|
||||||
|
@ -46,7 +124,7 @@ impl Profile {
|
||||||
hash_val.to_owned()
|
hash_val.to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let join_msg = serde_json::builder::ObjectBuilder::new()
|
let join_msg = ObjectBuilder::new()
|
||||||
.insert("accessToken", &self.access_token)
|
.insert("accessToken", &self.access_token)
|
||||||
.insert("selectedProfile", &self.id)
|
.insert("selectedProfile", &self.id)
|
||||||
.insert("serverId", hash_str)
|
.insert("serverId", hash_str)
|
||||||
|
@ -66,6 +144,10 @@ impl Profile {
|
||||||
};
|
};
|
||||||
panic!("{:?}", ret);
|
panic!("{:?}", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_complete(&self) -> bool {
|
||||||
|
!self.username.is_empty() && !self.id.is_empty() && !self.access_token.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn twos_compliment(data: &mut Vec<u8>) {
|
fn twos_compliment(data: &mut Vec<u8>) {
|
||||||
|
|
Loading…
Reference in New Issue