This commit is contained in:
2025-03-10 22:56:58 +01:00
parent f7fa5d5be4
commit c750dbd8f1
7 changed files with 129 additions and 34 deletions
+19 -1
View File
@@ -1 +1,19 @@
/target # Generated by Cargo
# will have compiled files and executables
debug/
target/
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
token.key
Generated
+23
View File
@@ -60,6 +60,7 @@ dependencies = [
name = "auraclient-api" name = "auraclient-api"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"minreq",
"mongodb", "mongodb",
"serde", "serde",
] ]
@@ -952,6 +953,22 @@ dependencies = [
"adler2", "adler2",
] ]
[[package]]
name = "minreq"
version = "2.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0c420feb01b9fb5061f8c8f452534361dd783756dcf38ec45191ce55e7a161"
dependencies = [
"log",
"once_cell",
"rustls",
"rustls-webpki",
"serde",
"serde_json",
"urlencoding",
"webpki-roots",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.0.3" version = "1.0.3"
@@ -1739,6 +1756,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]] [[package]]
name = "utf16_iter" name = "utf16_iter"
version = "1.0.5" version = "1.0.5"
+2 -1
View File
@@ -4,5 +4,6 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
minreq = { version = "2.13.2", features = ["https", "urlencoding", "json-using-serde"] }
mongodb = { version = "3.2.1", features = ["sync"] } mongodb = { version = "3.2.1", features = ["sync"] }
serde = "1.0.218" serde = { version ="1.0.218", features = ["derive"] }
+26 -11
View File
@@ -23,18 +23,33 @@ fn main() -> std::io::Result<()> {
move || { move || {
let mut stream = stream.unwrap(); let mut stream = stream.unwrap();
let mut reader = BufReader::new(stream.try_clone().unwrap()); let mut reader = BufReader::new(stream.try_clone().unwrap());
let session = methods::Session::new(&mut reader, database).unwrap();
loop { match methods::Session::new(&mut reader, database) {
let mut request_string = String::new(); Ok(session) => loop {
match reader.read_line(&mut request_string).unwrap() { let mut request_string = String::new();
0 => break, match reader.read_line(&mut request_string).unwrap() {
_ => { 0 => break,
let (method, params) = parser::parse(&request_string).unwrap(); _ => {
let response = session.handle_request(&method, &params); let (method, params) = parser::parse(&request_string).unwrap();
stream.write_all(response.to_string().as_bytes()).unwrap(); let response = session.handle_request(&method, &params);
} stream
}; .write_all(
match response {
Ok(response) => response.to_string(),
Err(e) => format!("!{e}"),
}
.as_bytes(),
)
.unwrap();
}
};
},
Err(e) => {
stream.write_all(format!("!{e}").as_bytes()).unwrap();
stream
.shutdown(std::net::Shutdown::Both)
.expect("shutdown call failed");
}
} }
} }
}); });
+47 -13
View File
@@ -1,38 +1,72 @@
mod set_cloak;
use std::{ use std::{
collections::HashMap, collections::HashMap,
io::{self, BufRead, BufReader}, io::{BufRead, BufReader},
net::TcpStream, net::TcpStream,
sync::Arc, sync::Arc,
}; };
use serde::{Deserialize, Serialize};
use crate::{
parser::ParamMap,
response::{Response, Result},
};
#[derive(Debug, Deserialize, Serialize)]
pub struct LocalPlayer {
pub id: String,
pub name: String,
}
pub struct Session { pub struct Session {
pub session_id: String, pub session_token: String,
pub database: Arc<crate::database::Database>, pub database: Arc<crate::database::Database>,
pub player: LocalPlayer,
} }
impl Session { impl Session {
pub fn new( pub fn new(
reader: &mut BufReader<TcpStream>, reader: &mut BufReader<TcpStream>,
database: Arc<crate::database::Database>, database: Arc<crate::database::Database>,
) -> io::Result<Self> { ) -> Result<Self> {
let mut session_id = String::new(); // Read the session token
reader.read_line(&mut session_id)?; let mut session_token = String::new();
reader
.read_line(&mut session_token)
.map_err(|_| crate::response::Error::InvalidHandshake)?;
// Validate session id
let response = minreq::get("https://api.minecraftservices.com/minecraft/profile")
.with_header("Authorization", &format!("Bearer {session_token}"))
.send()
.map_err(|_| crate::response::Error::InvalidSession)?;
// If the session is invalid, return an error
if response.status_code != 200 {
return Err(crate::response::Error::InvalidSession);
}
// Parse the player data
let player: LocalPlayer = response
.json()
.map_err(|_| crate::response::Error::InvalidSession)?;
Ok(Self { Ok(Self {
session_id, session_token,
database, database,
player,
}) })
} }
pub fn handle_request( pub fn handle_request(&self, method: &str, params: &HashMap<String, String>) -> Result {
&self,
method: &str,
params: &HashMap<String, String>,
) -> crate::response::Response {
match method { match method {
"ping" => crate::response::Response::Pong, "ping" => Ok(Response::Pong),
_ => crate::response::Response::Error(crate::response::Error::InvalidRequest), "set_cloak" => set_cloak::set_cloak(self, params.parse_param("cloak")?),
_ => Err(crate::response::Error::InvalidRequest),
} }
} }
} }
+4 -4
View File
@@ -1,14 +1,14 @@
use std::{collections::HashMap, str::FromStr}; use std::{collections::HashMap, str::FromStr};
pub trait ParamMap { pub trait ParamMap {
fn parse_param<T: FromStr>(&self, param: &str) -> Result<T, String>; fn parse_param<T: FromStr>(&self, param: &str) -> Result<T, crate::response::Error>;
} }
impl ParamMap for HashMap<String, String> { impl ParamMap for HashMap<String, String> {
fn parse_param<T: FromStr>(&self, param: &str) -> Result<T, String> { fn parse_param<T: FromStr>(&self, param: &str) -> Result<T, crate::response::Error> {
match self.get(param) { match self.get(param) {
Some(value) => T::from_str(value).map_err(|_| format!("Invalid parameter: {}", param)), Some(value) => T::from_str(value).map_err(|_| crate::response::Error::InvalidParameter),
None => Err(format!("Parameter not found: {}", param)), None => Err(crate::response::Error::InvalidParameter),
} }
} }
} }
+8 -4
View File
@@ -1,14 +1,16 @@
pub type Result<T = Response> = std::result::Result<T, Error>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Response { pub enum Response {
Pong, Pong,
Error(Error), Success,
} }
impl std::fmt::Display for Response { impl std::fmt::Display for Response {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Response::Pong => write!(f, "Pong"), Response::Pong => write!(f, "Pong"),
Response::Error(error) => write!(f, "!{}", error), Response::Success => write!(f, "Success"),
} }
} }
} }
@@ -19,7 +21,8 @@ pub enum Error {
InvalidMethod, InvalidMethod,
InvalidParameter, InvalidParameter,
ParameterNotFound, ParameterNotFound,
InvalidSessionToken, InvalidSession,
InvalidHandshake,
} }
impl std::fmt::Display for Error { impl std::fmt::Display for Error {
@@ -29,7 +32,8 @@ impl std::fmt::Display for Error {
Error::InvalidMethod => write!(f, "Invalid method"), Error::InvalidMethod => write!(f, "Invalid method"),
Error::InvalidParameter => write!(f, "Invalid parameter"), Error::InvalidParameter => write!(f, "Invalid parameter"),
Error::ParameterNotFound => write!(f, "Parameter not found"), Error::ParameterNotFound => write!(f, "Parameter not found"),
Error::InvalidSessionToken => write!(f, "Invalid session token"), Error::InvalidSession => write!(f, "Invalid session"),
Error::InvalidHandshake => write!(f, "Invalid handshake"),
} }
} }
} }