diff --git a/Cargo.toml b/Cargo.toml index 4a614ba..cdc9012 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,11 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -purple_cello_mc_protocol = { git = "https://github.com/PurpleCelloServer/purple_cello_mc_protocol.git", rev = "505adfb92c44db44a89effa4d38ebb863c2c60d0" } +purple_cello_mc_protocol = { git = "https://github.com/PurpleCelloServer/purple_cello_mc_protocol.git", rev = "9ff2e95c66b1d773362936733273350e4bdd399a" } tokio = { version = "1", features = ["full"] } serde = { version = "1", features = ["derive"] } serde_json = "1" base64 = "0.21.5" rand = "0.8.5" lazy_static = "1.4" +rsa = "0.6" diff --git a/src/client.rs b/src/client.rs index 98df22b..2cda450 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,6 +1,6 @@ // Yeahbut May 2024 -use std::error::Error; +use std::mem; use tokio::net::{TcpStream, tcp::{OwnedReadHalf, OwnedWriteHalf}}; use purple_cello_mc_protocol::{ @@ -64,6 +64,7 @@ pub async fn handle_client( match server_conn { Some(mut server_conn) => { if login_handle::respond_login( + &proxy_info, &mut client_conn, &mut server_conn, ).await.expect( @@ -79,7 +80,9 @@ pub async fn handle_client( } None => { login::clientbound::Disconnect { - reason: "\"Server Error (Server may be starting)\"" + reason: "\"Server Error (Server is down or \ +restarting)\nPlease contact the admins if the issue persists:\n\ +purplecelloserver@gmail.com\"" .to_string() } .write(&mut client_conn) @@ -122,24 +125,34 @@ Failed to connect to the backend server"); println!("Connection Closed"); } -async fn handle_play( - mut client_conn: ProtocolConnection<'_>, - mut server_conn: ProtocolConnection<'_>, -) -> Result<(), Box> { +async fn handle_play<'a>( + mut client_conn: ProtocolConnection<'a>, + mut server_conn: ProtocolConnection<'a>, +) { + let client_conn: &mut ProtocolConnection<'static> = + unsafe { mem::transmute(&mut client_conn) }; + let server_conn: &mut ProtocolConnection<'static> = + unsafe { mem::transmute(&mut server_conn) }; + + let (mut client_write_conn, mut client_read_conn) = + client_conn.split_conn().expect( + "Error copying from client to backend"); + let (mut server_write_conn, mut server_read_conn) = + server_conn.split_conn().expect( + "Error copying from backend to client"); + // Forward from client to backend - let to_backend = tokio::spawn(client_conn.forward_play(&mut server_conn)); + let to_backend = tokio::spawn(async move { + client_read_conn.forward_play(&mut server_write_conn).await.expect( + "Error copying from client to backend"); + }); // Forward from backend to client - // let to_client = tokio::spawn(async move { - // io::copy( - // &mut server_conn.stream_read, - // &mut client_conn.stream_write, - // ).await.expect( - // "Error copying from backend to client"); - // }); - let to_client = tokio::spawn(server_conn.forward_play(&mut client_conn)); + let to_client = tokio::spawn(async move { + server_read_conn.forward_play(&mut client_write_conn).await.expect( + "Error copying from backend to client"); + }); - tokio::try_join!(to_backend, to_client)?; - - Ok(()) + tokio::try_join!(to_backend, to_client).expect( + "Error copying between the client and backend"); } diff --git a/src/listener.rs b/src/listener.rs index 19891ec..29e9cd6 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -2,6 +2,7 @@ use tokio::net::TcpListener; use std::error::Error; +use rsa::RsaPrivateKey; #[derive(Copy, Clone)] pub enum OnlineStatus { @@ -16,6 +17,7 @@ pub struct ProxyInfo { pub online_status: OnlineStatus, pub backend_addr: String, pub backend_port: u16, + pub private_key: RsaPrivateKey, } impl ProxyInfo { diff --git a/src/login_handle.rs b/src/login_handle.rs index e09e390..0df256e 100644 --- a/src/login_handle.rs +++ b/src/login_handle.rs @@ -13,6 +13,8 @@ use purple_cello_mc_protocol::{ login, }; +use crate::listener; + const EXPIRATION_DURATION: Duration = Duration::from_secs(3600); struct CachedWhitelist { @@ -150,27 +152,46 @@ fn check_player_whitelist(player: Player) -> PlayerAllowed { PlayerAllowed::False("Invalid UUID".to_string()) } else if invalid_username { PlayerAllowed::False( - "Invalid Username, please contact the server admin to update your \ - username: purplecelloserver@gmail.com".to_string() + "Invalid Username!\nPlease contact the admins to update your \ +username:\npurplecelloserver@gmail.com".to_string() ) } else { - PlayerAllowed::False("Not whitelisted on this server".to_string()) + PlayerAllowed::False("Not whitelisted on this server.\n\ +Please direct whitelist requests to the admins:\n\ +purplecelloserver@gmail.com".to_string()) } } -fn check_player(player: Player) -> Result { +async fn check_player_online( + proxy_info: &listener::ProxyInfo, + player: Player, + client_conn: &mut ProtocolConnection<'_>, +) -> Result { + let encryption_request = client_conn.create_encryption_request( + proxy_info.private_key.clone())?; + encryption_request.write(client_conn).await?; + let encryption_response = + login::serverbound::EncryptionResponse::read(client_conn).await?; + client_conn.handle_encryption_response(encryption_response)?; + // TODO: Make authentication verification request + Ok(check_player_whitelist(player)) +} + +fn check_player_offline(player: Player) -> Result { Ok(check_player_whitelist(player)) } pub async fn respond_login( + proxy_info: &listener::ProxyInfo, client_conn: &mut ProtocolConnection<'_>, server_conn: &mut ProtocolConnection<'_>, ) -> Result { - let proxy_login = login_to_proxy(client_conn).await?; + let proxy_login = login_to_proxy(proxy_info, client_conn).await?; match proxy_login { PlayerAllowed::True(player) => { println!("Player allowed"); login_to_backend( + proxy_info, player, client_conn, server_conn, @@ -188,6 +209,7 @@ pub async fn respond_login( } async fn login_to_proxy( + proxy_info: &listener::ProxyInfo, client_conn: &mut ProtocolConnection<'_>, ) -> Result { println!("Logging into proxy"); @@ -200,10 +222,16 @@ async fn login_to_proxy( player_uuid: start_packet.player_uuid, }; - check_player(player) + match proxy_info.online_status { + listener::OnlineStatus::Online => + check_player_online(proxy_info, player, client_conn).await, + listener::OnlineStatus::Offline => + check_player_offline(player), + } } async fn login_to_backend( + proxy_info: &listener::ProxyInfo, player: Player, client_conn: &mut ProtocolConnection<'_>, server_conn: &mut ProtocolConnection<'_>, @@ -211,8 +239,8 @@ async fn login_to_backend( println!("Logging into backend"); handshake::serverbound::Handshake { protocol_version: mc_types::VERSION_PROTOCOL, - server_address: "localhost".to_string(), - server_port: 25565, + server_address: proxy_info.backend_addr.clone(), + server_port: proxy_info.backend_port, next_state: 2, }.write(server_conn).await?; diff --git a/src/main.rs b/src/main.rs index 9bb05d2..aac69a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,20 +2,23 @@ use std::error::Error; +use purple_cello_mc_protocol::encrypt; + mod status_handle; mod login_handle; mod client; mod listener; - #[tokio::main] async fn main() -> Result<(), Box> { + let private_key = encrypt::generate_rsa_keys()?; let offline_info = listener::ProxyInfo{ proxy_addr: "127.0.0.1".to_string(), proxy_port: 25565, online_status: listener::OnlineStatus::Offline, backend_addr: "127.0.0.1".to_string(), backend_port: 25564, + private_key: private_key.clone(), }; let online_info = listener::ProxyInfo{ proxy_addr: "127.0.0.1".to_string(), @@ -23,6 +26,7 @@ async fn main() -> Result<(), Box> { online_status: listener::OnlineStatus::Online, backend_addr: "127.0.0.1".to_string(), backend_port: 25564, + private_key: private_key.clone(), }; let listener_offline: listener::TcpListenerWrapper =