2016-03-16 14:25:35 -04:00
|
|
|
// Copyright 2016 Matthew Collins
|
2015-09-17 11:21:56 -04:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2015-09-17 11:04:25 -04:00
|
|
|
|
2018-10-03 21:28:05 -04:00
|
|
|
use sha1::{self, Digest};
|
2018-11-04 15:35:06 -05:00
|
|
|
use serde_json::json;
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
use reqwest;
|
2015-09-10 06:49:41 -04:00
|
|
|
|
2016-03-20 19:43:31 -04:00
|
|
|
#[derive(Clone, Debug)]
|
2015-09-10 06:49:41 -04:00
|
|
|
pub struct Profile {
|
2015-09-10 06:58:42 -04:00
|
|
|
pub username: String,
|
|
|
|
pub id: String,
|
2015-10-07 14:36:59 -04:00
|
|
|
pub access_token: String,
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
|
2018-11-04 16:37:57 -05:00
|
|
|
const JOIN_URL: &str = "https://sessionserver.mojang.com/session/minecraft/join";
|
|
|
|
const LOGIN_URL: &str = "https://authserver.mojang.com/authenticate";
|
|
|
|
const REFRESH_URL: &str = "https://authserver.mojang.com/refresh";
|
|
|
|
const VALIDATE_URL: &str = "https://authserver.mojang.com/validate";
|
2015-09-10 06:49:41 -04:00
|
|
|
|
|
|
|
impl Profile {
|
2016-03-20 19:43:31 -04:00
|
|
|
pub fn login(username: &str, password: &str, token: &str) -> Result<Profile, super::Error> {
|
2018-10-23 21:47:21 -04:00
|
|
|
let req_msg = json!({
|
|
|
|
"username": username,
|
|
|
|
"password": password,
|
|
|
|
"clientToken": token,
|
|
|
|
"agent": {
|
|
|
|
"name": "Minecraft",
|
|
|
|
"version": 1
|
|
|
|
}});
|
2018-11-04 14:34:53 -05:00
|
|
|
let req = serde_json::to_string(&req_msg)?;
|
2016-03-20 19:43:31 -04:00
|
|
|
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
let client = reqwest::Client::new();
|
|
|
|
let res = client.post(LOGIN_URL)
|
|
|
|
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
|
|
|
.body(req)
|
|
|
|
.send()?;
|
2016-03-20 19:43:31 -04:00
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
let ret: serde_json::Value = serde_json::from_reader(res)?;
|
2018-10-23 21:47:21 -04:00
|
|
|
if let Some(error) = ret.get("error").and_then(|v| v.as_str()) {
|
2016-03-20 19:43:31 -04:00
|
|
|
return Err(super::Error::Err(format!(
|
|
|
|
"{}: {}",
|
|
|
|
error,
|
2018-10-23 21:47:21 -04:00
|
|
|
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap())
|
2016-03-20 19:43:31 -04:00
|
|
|
));
|
|
|
|
}
|
|
|
|
Ok(Profile {
|
2018-10-23 21:47:21 -04:00
|
|
|
username: ret.pointer("/selectedProfile/name").and_then(|v| v.as_str()).unwrap().to_owned(),
|
|
|
|
id: ret.pointer("/selectedProfile/id").and_then(|v| v.as_str()).unwrap().to_owned(),
|
|
|
|
access_token: ret.get("accessToken").and_then(|v| v.as_str()).unwrap().to_owned(),
|
2016-03-20 19:43:31 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn refresh(self, token: &str) -> Result<Profile, super::Error> {
|
2018-10-23 21:47:21 -04:00
|
|
|
let req_msg = json!({
|
|
|
|
"accessToken": self.access_token.clone(),
|
|
|
|
"clientToken": token
|
|
|
|
});
|
2018-11-04 14:34:53 -05:00
|
|
|
let req = serde_json::to_string(&req_msg)?;
|
2016-03-20 19:43:31 -04:00
|
|
|
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
let client = reqwest::Client::new();
|
|
|
|
let res = client.post(VALIDATE_URL)
|
|
|
|
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
|
|
|
.body(req)
|
|
|
|
.send()?;
|
2016-03-20 19:43:31 -04:00
|
|
|
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
if res.status() != reqwest::StatusCode::NO_CONTENT {
|
2018-11-04 14:34:53 -05:00
|
|
|
let req = serde_json::to_string(&req_msg)?; // TODO: fix parsing twice to avoid move
|
2016-03-20 19:43:31 -04:00
|
|
|
// Refresh needed
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
let res = client.post(REFRESH_URL)
|
|
|
|
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
|
|
|
.body(req)
|
|
|
|
.send()?;
|
2016-03-20 19:43:31 -04:00
|
|
|
|
2018-11-04 14:34:53 -05:00
|
|
|
let ret: serde_json::Value = serde_json::from_reader(res)?;
|
2018-10-23 21:47:21 -04:00
|
|
|
if let Some(error) = ret.get("error").and_then(|v| v.as_str()) {
|
2016-03-20 19:43:31 -04:00
|
|
|
return Err(super::Error::Err(format!(
|
|
|
|
"{}: {}",
|
|
|
|
error,
|
2018-10-23 21:47:21 -04:00
|
|
|
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap())
|
2016-03-20 19:43:31 -04:00
|
|
|
));
|
|
|
|
}
|
|
|
|
return Ok(Profile {
|
2018-10-23 21:47:21 -04:00
|
|
|
username: ret.pointer("/selectedProfile/name").and_then(|v| v.as_str()).unwrap().to_owned(),
|
|
|
|
id: ret.pointer("/selectedProfile/id").and_then(|v| v.as_str()).unwrap().to_owned(),
|
|
|
|
access_token: ret.get("accessToken").and_then(|v| v.as_str()).unwrap().to_owned(),
|
2016-03-20 19:43:31 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
|
2016-03-26 10:24:26 -04:00
|
|
|
pub fn join_server(&self, server_id: &str, shared_key: &[u8], public_key: &[u8]) -> Result<(), super::Error> {
|
2018-10-03 21:28:05 -04:00
|
|
|
let mut hasher = sha1::Sha1::new();
|
|
|
|
hasher.input(server_id.as_bytes());
|
|
|
|
hasher.input(shared_key);
|
|
|
|
hasher.input(public_key);
|
|
|
|
let mut hash = hasher.result();
|
2015-09-10 06:49:41 -04:00
|
|
|
|
|
|
|
// Mojang uses a hex method which allows for
|
|
|
|
// negatives so we have to account for that.
|
2016-03-23 18:58:09 -04:00
|
|
|
let negative = (hash[0] & 0x80) == 0x80;
|
2015-09-10 06:49:41 -04:00
|
|
|
if negative {
|
|
|
|
twos_compliment(&mut hash);
|
|
|
|
}
|
2016-03-23 18:58:09 -04:00
|
|
|
let hash_str = hash.iter().map(|b| format!("{:02x}", b)).collect::<Vec<String>>().join("");
|
2019-02-23 12:02:04 -05:00
|
|
|
let hash_val = hash_str.trim_start_matches('0');
|
2015-09-10 06:49:41 -04:00
|
|
|
let hash_str = if negative {
|
|
|
|
"-".to_owned() + &hash_val[..]
|
|
|
|
} else {
|
|
|
|
hash_val.to_owned()
|
|
|
|
};
|
|
|
|
|
2018-10-23 21:47:21 -04:00
|
|
|
let join_msg = json!({
|
|
|
|
"accessToken": &self.access_token,
|
|
|
|
"selectedProfile": &self.id,
|
|
|
|
"serverId": hash_str
|
|
|
|
});
|
2015-09-10 06:49:41 -04:00
|
|
|
let join = serde_json::to_string(&join_msg).unwrap();
|
|
|
|
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
let client = reqwest::Client::new();
|
|
|
|
let res = client.post(JOIN_URL)
|
|
|
|
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
|
|
|
.body(join)
|
|
|
|
.send()?;
|
2015-09-10 06:49:41 -04:00
|
|
|
|
Replace hyper with reqwest (#7)
An old version of hyper was used before (0.8.0), in the process of updating to hyper 0.12.11, found this higher-level replacement/wrapper, reqwest 0.9.4 which is simpler to use than the latest hyper and serves the purpose of a simple HTTP client well
* Begin updating to hyper 0.12.11
https://github.com/iceiix/steven/issues/4#issuecomment-425759778
* Use type variables for hyper::Client
* Fix setting header syntax, Content-Type: application/json, 17->13
* Parse strings into URLs with url.parse::<hyper::Uri>().unwrap()
https://github.com/hyperium/hyper/blob/b20971cb4e5f158844aec5829eea1854e5b7d4b6/examples/client.rs#L25
* Use hyper::Request::post() then client.request() since client.post() removed
* wait() on the ResponseFuture to get the Result
* try! to unwrap the Result
* status() is now a method
* Concatenate body chunks unwrap into bytes, then parse JSON from byte slice, instead of from_reader which didn't compile
* Replace send() with wait() on ResponseFuture
* Parse HeaderValue to u64
* Slices implement std::io::Read trait
* Read into_bytes() instead of read_to_end()
* Disable boxed logger for now to workaround 'expected function, found macro'
* Remove unnecessary mutability, warnings
* Hack to parse twice to avoid double move
* Use hyper-rustls pure Rust implementation for TLS for HTTPS in hyper
* Start converting to reqwest: add Protocol::Error and reqwest::Error conversion
* Use reqwest, replacing hyper, in protocol
* Convert resources to use reqwest instead of hyper
* Convert skin download to reqwest, instead of hyper
* Remove hyper
* Revert unnecessary variable name change req/body to reduce diff
* Revert unnecessary whitespace change to reduce diff, align indentation on .
* Fix authenticating to server, wrong method and join URL
* Update Cargo.lock
2018-10-27 20:03:34 -04:00
|
|
|
if res.status() == reqwest::StatusCode::NO_CONTENT {
|
2016-03-21 06:55:31 -04:00
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(super::Error::Err("Failed to auth with server".to_owned()))
|
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
2016-03-20 19:43:31 -04:00
|
|
|
|
|
|
|
pub fn is_complete(&self) -> bool {
|
|
|
|
!self.username.is_empty() && !self.id.is_empty() && !self.access_token.is_empty()
|
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|
|
|
|
|
2018-09-30 01:23:48 -04:00
|
|
|
fn twos_compliment(data: &mut [u8]) {
|
2015-09-10 06:58:42 -04:00
|
|
|
let mut carry = true;
|
2015-10-07 14:36:59 -04:00
|
|
|
for i in (0..data.len()).rev() {
|
2015-09-10 06:58:42 -04:00
|
|
|
data[i] = !data[i];
|
|
|
|
if carry {
|
|
|
|
carry = data[i] == 0xFF;
|
2016-03-23 18:58:09 -04:00
|
|
|
data[i] = data[i].wrapping_add(1);
|
2015-09-10 06:58:42 -04:00
|
|
|
}
|
|
|
|
}
|
2015-09-10 06:49:41 -04:00
|
|
|
}
|