Allow disable encryption

This commit is contained in:
Snowiiii 2024-09-28 13:03:31 +02:00
parent 92fef82bda
commit 1ddaca1406
14 changed files with 117 additions and 101 deletions

1
Cargo.lock generated
View File

@ -2031,6 +2031,7 @@ dependencies = [
"log", "log",
"num-derive", "num-derive",
"num-traits", "num-traits",
"pumpkin-config",
"pumpkin-core", "pumpkin-core",
"pumpkin-macros", "pumpkin-macros",
"pumpkin-world", "pumpkin-world",

View File

@ -1,24 +1,39 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
// Packet compression /// Packet compression
pub struct CompressionConfig { pub struct CompressionConfig {
/// Is compression enabled ? /// Is compression enabled ?
pub enabled: bool, pub enabled: bool,
#[serde(flatten)]
pub compression_info: CompressionInfo,
}
#[derive(Deserialize, Serialize, Clone)]
/// We have this in a Seperate struct so we can use it outside of the Config
pub struct CompressionInfo {
/// The compression threshold used when compression is enabled /// The compression threshold used when compression is enabled
pub compression_threshold: u32, pub threshold: u32,
/// A value between 0..9 /// A value between 0..9
/// 1 = Optimize for the best speed of encoding. /// 1 = Optimize for the best speed of encoding.
/// 9 = Optimize for the size of data being encoded. /// 9 = Optimize for the size of data being encoded.
pub compression_level: u32, pub level: u32,
}
impl Default for CompressionInfo {
fn default() -> Self {
Self {
threshold: 256,
level: 4,
}
}
} }
impl Default for CompressionConfig { impl Default for CompressionConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: true, enabled: true,
compression_threshold: 256, compression_info: Default::default(),
compression_level: 4,
} }
} }
} }

View File

@ -20,7 +20,7 @@ pub use pvp::PVPConfig;
pub use rcon::RCONConfig; pub use rcon::RCONConfig;
mod commands; mod commands;
mod compression; pub mod compression;
mod pvp; mod pvp;
mod rcon; mod rcon;

View File

@ -4,6 +4,7 @@ version.workspace = true
edition.workspace = true edition.workspace = true
[dependencies] [dependencies]
pumpkin-config = { path = "../pumpkin-config" }
pumpkin-macros = { path = "../pumpkin-macros" } pumpkin-macros = { path = "../pumpkin-macros" }
pumpkin-world = { path = "../pumpkin-world" } pumpkin-world = { path = "../pumpkin-world" }
pumpkin-core = { path = "../pumpkin-core" } pumpkin-core = { path = "../pumpkin-core" }

View File

@ -19,7 +19,7 @@ type Cipher = cfb8::Decryptor<aes::Aes128>;
pub struct PacketDecoder { pub struct PacketDecoder {
buf: BytesMut, buf: BytesMut,
decompress_buf: BytesMut, decompress_buf: BytesMut,
compression: Option<u32>, compression: bool,
cipher: Option<Cipher>, cipher: Option<Cipher>,
} }
@ -45,7 +45,7 @@ impl PacketDecoder {
let packet_len_len = VarInt(packet_len).written_size(); let packet_len_len = VarInt(packet_len).written_size();
let mut data; let mut data;
if self.compression.is_some() { if self.compression {
r = &r[..packet_len as usize]; r = &r[..packet_len as usize];
let data_len = VarInt::decode(&mut r).map_err(|_| PacketError::TooLong)?.0; let data_len = VarInt::decode(&mut r).map_err(|_| PacketError::TooLong)?.0;
@ -96,19 +96,26 @@ impl PacketDecoder {
})) }))
} }
pub fn enable_encryption(&mut self, key: &[u8; 16]) { pub fn set_encryption(&mut self, key: Option<&[u8; 16]>) {
assert!(self.cipher.is_none(), "encryption is already enabled"); if let Some(key) = key {
assert!(self.cipher.is_none(), "encryption is already enabled");
let mut cipher = Cipher::new_from_slices(key, key).expect("invalid key"); let mut cipher = Cipher::new_from_slices(key, key).expect("invalid key");
// Don't forget to decrypt the data we already have. // Don't forget to decrypt the data we already have.
Self::decrypt_bytes(&mut cipher, &mut self.buf);
self.cipher = Some(cipher); Self::decrypt_bytes(&mut cipher, &mut self.buf);
self.cipher = Some(cipher);
} else {
assert!(self.cipher.is_some(), "encryption is already disabled");
self.cipher = None;
}
} }
/// Enables ZLib Deompression /// Sets ZLib Deompression
pub fn set_compression(&mut self, compression: Option<u32>) { pub fn set_compression(&mut self, compression: bool) {
self.compression = compression; self.compression = compression;
} }

View File

@ -2,6 +2,7 @@ use std::io::Write;
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
use pumpkin_config::compression::CompressionInfo;
use std::io::Read; use std::io::Read;
@ -19,7 +20,7 @@ type Cipher = cfb8::Encryptor<aes::Aes128>;
pub struct PacketEncoder { pub struct PacketEncoder {
buf: BytesMut, buf: BytesMut,
compress_buf: Vec<u8>, compress_buf: Vec<u8>,
compression: Option<(u32, u32)>, compression: Option<CompressionInfo>,
cipher: Option<Cipher>, cipher: Option<Cipher>,
} }
@ -40,10 +41,10 @@ impl PacketEncoder {
let data_len = self.buf.len() - start_len; let data_len = self.buf.len() - start_len;
if let Some((threshold, compression_level)) = self.compression { if let Some(compression) = &self.compression {
if data_len > threshold as usize { if data_len > compression.threshold as usize {
let mut z = let mut z =
ZlibEncoder::new(&self.buf[start_len..], Compression::new(compression_level)); ZlibEncoder::new(&self.buf[start_len..], Compression::new(compression.level));
self.compress_buf.clear(); self.compress_buf.clear();
@ -117,13 +118,20 @@ impl PacketEncoder {
Ok(()) Ok(())
} }
pub fn enable_encryption(&mut self, key: &[u8; 16]) { pub fn set_encryption(&mut self, key: Option<&[u8; 16]>) {
assert!(self.cipher.is_none(), "encryption is already enabled"); if let Some(key) = key {
self.cipher = Some(Cipher::new_from_slices(key, key).expect("invalid key")); assert!(self.cipher.is_none(), "encryption is already enabled");
self.cipher = Some(Cipher::new_from_slices(key, key).expect("invalid key"));
} else {
assert!(self.cipher.is_some(), "encryption is disabled");
self.cipher = None;
}
} }
/// Enables ZLib Compression /// Enables ZLib Compression
pub fn set_compression(&mut self, compression: Option<(u32, u32)>) { pub fn set_compression(&mut self, compression: Option<CompressionInfo>) {
self.compression = compression; self.compression = compression;
} }

View File

@ -26,10 +26,9 @@ impl BlockId {
.iter(); .iter();
let block_state = match properties { let block_state = match properties {
Some(properties) => match block_states.find(|state| &state.properties == properties) { Some(properties) => block_states
Some(state) => state, .find(|state| &state.properties == properties)
None => return Err(WorldError::BlockStateIdNotFound), .ok_or_else(|| WorldError::BlockStateIdNotFound)?,
},
None => block_states None => block_states
.find(|state| state.is_default) .find(|state| state.is_default)
.expect("Every Block should have at least 1 default state"), .expect("Every Block should have at least 1 default state"),

View File

@ -135,6 +135,8 @@ impl Level {
} }
} }
pub fn get_block() {}
/// Reads/Generates many chunks in a world /// Reads/Generates many chunks in a world
/// MUST be called from a tokio runtime thread /// MUST be called from a tokio runtime thread
/// ///
@ -147,7 +149,6 @@ impl Level {
) { ) {
chunks.into_par_iter().for_each(|at| { chunks.into_par_iter().for_each(|at| {
if is_alive { if is_alive {
dbg!("a");
return; return;
} }
let mut loaded_chunks = self.loaded_chunks.lock(); let mut loaded_chunks = self.loaded_chunks.lock();
@ -235,29 +236,21 @@ impl Level {
// Read the file using the offset and size // Read the file using the offset and size
let mut file_buf = { let mut file_buf = {
let seek_result = region_file.seek(std::io::SeekFrom::Start(offset)); region_file
if seek_result.is_err() { .seek(std::io::SeekFrom::Start(offset))
return Err(WorldError::RegionIsInvalid); .map_err(|_| WorldError::RegionIsInvalid)?;
}
let mut out = vec![0; size]; let mut out = vec![0; size];
let read_result = region_file.read_exact(&mut out); region_file
if read_result.is_err() { .read_exact(&mut out)
return Err(WorldError::RegionIsInvalid); .map_err(|_| WorldError::RegionIsInvalid)?;
}
out out
}; };
// TODO: check checksum to make sure chunk is not corrupted // TODO: check checksum to make sure chunk is not corrupted
let header = file_buf.drain(0..5).collect_vec(); let header = file_buf.drain(0..5).collect_vec();
let compression = match Compression::from_byte(header[4]) { let compression = Compression::from_byte(header[4])
Some(c) => c, .ok_or_else(|| WorldError::Compression(CompressionError::UnknownCompression))?;
None => {
return Err(WorldError::Compression(
CompressionError::UnknownCompression,
))
}
};
let size = u32::from_be_bytes(header[..4].try_into().unwrap()); let size = u32::from_be_bytes(header[..4].try_into().unwrap());
@ -277,23 +270,15 @@ impl Level {
Compression::Gzip => { Compression::Gzip => {
let mut z = GzDecoder::new(&compressed_data[..]); let mut z = GzDecoder::new(&compressed_data[..]);
let mut chunk_data = Vec::with_capacity(compressed_data.len()); let mut chunk_data = Vec::with_capacity(compressed_data.len());
match z.read_to_end(&mut chunk_data) { z.read_to_end(&mut chunk_data)
Ok(_) => {} .map_err(CompressionError::GZipError)?;
Err(e) => {
return Err(CompressionError::GZipError(e));
}
}
Ok(chunk_data) Ok(chunk_data)
} }
Compression::Zlib => { Compression::Zlib => {
let mut z = ZlibDecoder::new(&compressed_data[..]); let mut z = ZlibDecoder::new(&compressed_data[..]);
let mut chunk_data = Vec::with_capacity(compressed_data.len()); let mut chunk_data = Vec::with_capacity(compressed_data.len());
match z.read_to_end(&mut chunk_data) { z.read_to_end(&mut chunk_data)
Ok(_) => {} .map_err(CompressionError::ZlibError)?;
Err(e) => {
return Err(CompressionError::ZlibError(e));
}
}
Ok(chunk_data) Ok(chunk_data)
} }
Compression::None => Ok(compressed_data), Compression::None => Ok(compressed_data),

View File

@ -107,7 +107,7 @@ impl Client {
) { ) {
let shared_secret = server.decrypt(&encryption_response.shared_secret).unwrap(); let shared_secret = server.decrypt(&encryption_response.shared_secret).unwrap();
self.enable_encryption(&shared_secret) self.set_encryption(Some(&shared_secret))
.unwrap_or_else(|e| self.kick(&e.to_string())); .unwrap_or_else(|e| self.kick(&e.to_string()));
let mut gameprofile = self.gameprofile.lock(); let mut gameprofile = self.gameprofile.lock();
@ -115,6 +115,7 @@ impl Client {
if BASIC_CONFIG.online_mode { if BASIC_CONFIG.online_mode {
let hash = server.digest_secret(&shared_secret); let hash = server.digest_secret(&shared_secret);
let ip = self.address.lock().ip(); let ip = self.address.lock().ip();
match authentication::authenticate( match authentication::authenticate(
&gameprofile.as_ref().unwrap().name, &gameprofile.as_ref().unwrap().name,
&hash, &hash,
@ -123,15 +124,15 @@ impl Client {
) )
.await .await
{ {
Ok(p) => { Ok(profile) => {
// Check if player should join // Check if player should join
if let Some(p) = &p.profile_actions { if let Some(actions) = &profile.profile_actions {
if !ADVANCED_CONFIG if !ADVANCED_CONFIG
.authentication .authentication
.player_profile .player_profile
.allow_banned_players .allow_banned_players
{ {
if !p.is_empty() { if !actions.is_empty() {
self.kick("Your account can't join"); self.kick("Your account can't join");
} }
} else { } else {
@ -140,28 +141,27 @@ impl Client {
.player_profile .player_profile
.allowed_actions .allowed_actions
{ {
if !p.contains(allowed) { if !actions.contains(allowed) {
self.kick("Your account can't join"); self.kick("Your account can't join");
} }
} }
} }
} }
*gameprofile = Some(p); *gameprofile = Some(profile);
} }
Err(e) => self.kick(&e.to_string()), Err(e) => self.kick(&e.to_string()),
} }
} }
for property in &gameprofile.as_ref().unwrap().properties { for property in &gameprofile.as_ref().unwrap().properties {
// TODO: use this (this was the todo here before, ill add it again cuz its prob here for a reason) unpack_textures(property, &ADVANCED_CONFIG.authentication.textures)
let _ = unpack_textures(property, &ADVANCED_CONFIG.authentication.textures); .unwrap_or_else(|e| self.kick(&e.to_string()));
} }
// enable compression // enable compression
if ADVANCED_CONFIG.packet_compression.enabled { if ADVANCED_CONFIG.packet_compression.enabled {
let threshold = ADVANCED_CONFIG.packet_compression.compression_threshold; let compression = ADVANCED_CONFIG.packet_compression.compression_info.clone();
let level = ADVANCED_CONFIG.packet_compression.compression_level; self.send_packet(&CSetCompression::new(compression.threshold.into()));
self.send_packet(&CSetCompression::new(threshold.into())); self.set_compression(Some(compression));
self.set_compression(Some((threshold, level)));
} }
if let Some(profile) = gameprofile.as_ref() { if let Some(profile) = gameprofile.as_ref() {

View File

@ -16,6 +16,7 @@ use authentication::GameProfile;
use crossbeam::atomic::AtomicCell; use crossbeam::atomic::AtomicCell;
use mio::{event::Event, net::TcpStream, Token}; use mio::{event::Event, net::TcpStream, Token};
use parking_lot::Mutex; use parking_lot::Mutex;
use pumpkin_config::compression::CompressionInfo;
use pumpkin_protocol::{ use pumpkin_protocol::{
bytebuf::{packet_id::Packet, DeserializerError}, bytebuf::{packet_id::Packet, DeserializerError},
client::{config::CConfigDisconnect, login::CLoginDisconnect}, client::{config::CConfigDisconnect, login::CLoginDisconnect},
@ -151,24 +152,29 @@ impl Client {
client_packets_queue.push(packet); client_packets_queue.push(packet);
} }
/// Enables encryption /// Sets the Packet encryption
pub fn enable_encryption( pub fn set_encryption(
&self, &self,
shared_secret: &[u8], // decrypted shared_secret: Option<&[u8]>, // decrypted
) -> Result<(), EncryptionError> { ) -> Result<(), EncryptionError> {
self.encryption if let Some(shared_secret) = shared_secret {
.store(true, std::sync::atomic::Ordering::Relaxed); self.encryption
let crypt_key: [u8; 16] = shared_secret .store(true, std::sync::atomic::Ordering::Relaxed);
.try_into() let crypt_key: [u8; 16] = shared_secret
.map_err(|_| EncryptionError::SharedWrongLength)?; .try_into()
self.dec.lock().enable_encryption(&crypt_key); .map_err(|_| EncryptionError::SharedWrongLength)?;
self.enc.lock().enable_encryption(&crypt_key); self.dec.lock().set_encryption(Some(&crypt_key));
self.enc.lock().set_encryption(Some(&crypt_key));
} else {
self.dec.lock().set_encryption(None);
self.enc.lock().set_encryption(None);
}
Ok(()) Ok(())
} }
/// Compression threshold, Compression level /// Sets the Packet compression
pub fn set_compression(&self, compression: Option<(u32, u32)>) { pub fn set_compression(&self, compression: Option<CompressionInfo>) {
self.dec.lock().set_compression(compression.map(|v| v.0)); self.dec.lock().set_compression(compression.is_some());
self.enc.lock().set_compression(compression); self.enc.lock().set_compression(compression);
} }
@ -200,14 +206,11 @@ impl Client {
/// Processes all packets send by the client /// Processes all packets send by the client
pub async fn process_packets(&self, server: &Arc<Server>) { pub async fn process_packets(&self, server: &Arc<Server>) {
while let Some(mut packet) = self.client_packets_queue.lock().pop() { while let Some(mut packet) = self.client_packets_queue.lock().pop() {
match self.handle_packet(server, &mut packet).await { let _ = self.handle_packet(server, &mut packet).await.map_err(|e| {
Ok(_) => {} let text = format!("Error while reading incoming packet {}", e);
Err(e) => { log::error!("{}", text);
let text = format!("Error while reading incoming packet {}", e); self.kick(&text)
log::error!("{}", text); });
self.kick(&text)
}
};
} }
} }

View File

@ -131,7 +131,7 @@ impl Player {
self.kick(TextComponent::text("Invalid movement")); self.kick(TextComponent::text("Invalid movement"));
return; return;
} }
if !position_rotation.yaw.is_finite() || !position_rotation.pitch.is_finite() { if position_rotation.yaw.is_infinite() || position_rotation.pitch.is_infinite() {
self.kick(TextComponent::text("Invalid rotation")); self.kick(TextComponent::text("Invalid rotation"));
return; return;
} }

View File

@ -140,13 +140,10 @@ impl RCONClient {
} }
} }
// If we get a close here, we might have a reply, which we still want to write. // If we get a close here, we might have a reply, which we still want to write.
match self.poll(server, password).await { let _ = self.poll(server, password).await.map_err(|e| {
Ok(()) => {} log::error!("rcon error: {e}");
Err(e) => { self.closed = true;
log::error!("rcon error: {e}"); });
self.closed = true;
}
}
} }
self.closed self.closed
} }

View File

@ -58,7 +58,7 @@ impl CachedStatus {
} }
pub fn build_response(config: &BasicConfiguration) -> StatusResponse { pub fn build_response(config: &BasicConfiguration) -> StatusResponse {
let icon_path = concat!(env!("CARGO_MANIFEST_DIR"), "/icon.png"); let icon_path = "/icon.png";
let icon = if Path::new(icon_path).exists() { let icon = if Path::new(icon_path).exists() {
Some(Self::load_icon(icon_path)) Some(Self::load_icon(icon_path))
} else { } else {

View File

@ -103,11 +103,11 @@ impl Server {
}; };
// Basically the default world // Basically the default world
// TODO: select default from config // TODO: select default from config
let world = self.worlds[0].clone(); let world = &self.worlds[0];
let player = Arc::new(Player::new(client, world.clone(), entity_id, gamemode)); let player = Arc::new(Player::new(client, world.clone(), entity_id, gamemode));
world.add_player(token, player.clone()); world.add_player(token, player.clone());
(player, world) (player, world.clone())
} }
pub fn try_get_container( pub fn try_get_container(