Allow disable encryption
This commit is contained in:
parent
92fef82bda
commit
1ddaca1406
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2031,6 +2031,7 @@ dependencies = [
|
||||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pumpkin-config",
|
||||
"pumpkin-core",
|
||||
"pumpkin-macros",
|
||||
"pumpkin-world",
|
||||
|
||||
@ -1,24 +1,39 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
// Packet compression
|
||||
/// Packet compression
|
||||
pub struct CompressionConfig {
|
||||
/// Is compression enabled ?
|
||||
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
|
||||
pub compression_threshold: u32,
|
||||
pub threshold: u32,
|
||||
/// A value between 0..9
|
||||
/// 1 = Optimize for the best speed of encoding.
|
||||
/// 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 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
compression_threshold: 256,
|
||||
compression_level: 4,
|
||||
compression_info: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ pub use pvp::PVPConfig;
|
||||
pub use rcon::RCONConfig;
|
||||
|
||||
mod commands;
|
||||
mod compression;
|
||||
pub mod compression;
|
||||
mod pvp;
|
||||
mod rcon;
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
pumpkin-config = { path = "../pumpkin-config" }
|
||||
pumpkin-macros = { path = "../pumpkin-macros" }
|
||||
pumpkin-world = { path = "../pumpkin-world" }
|
||||
pumpkin-core = { path = "../pumpkin-core" }
|
||||
|
||||
@ -19,7 +19,7 @@ type Cipher = cfb8::Decryptor<aes::Aes128>;
|
||||
pub struct PacketDecoder {
|
||||
buf: BytesMut,
|
||||
decompress_buf: BytesMut,
|
||||
compression: Option<u32>,
|
||||
compression: bool,
|
||||
cipher: Option<Cipher>,
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ impl PacketDecoder {
|
||||
let packet_len_len = VarInt(packet_len).written_size();
|
||||
|
||||
let mut data;
|
||||
if self.compression.is_some() {
|
||||
if self.compression {
|
||||
r = &r[..packet_len as usize];
|
||||
|
||||
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]) {
|
||||
assert!(self.cipher.is_none(), "encryption is already enabled");
|
||||
pub fn set_encryption(&mut self, key: Option<&[u8; 16]>) {
|
||||
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.
|
||||
Self::decrypt_bytes(&mut cipher, &mut self.buf);
|
||||
// Don't forget to decrypt the data we already have.
|
||||
|
||||
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
|
||||
pub fn set_compression(&mut self, compression: Option<u32>) {
|
||||
/// Sets ZLib Deompression
|
||||
pub fn set_compression(&mut self, compression: bool) {
|
||||
self.compression = compression;
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ use std::io::Write;
|
||||
|
||||
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use pumpkin_config::compression::CompressionInfo;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
@ -19,7 +20,7 @@ type Cipher = cfb8::Encryptor<aes::Aes128>;
|
||||
pub struct PacketEncoder {
|
||||
buf: BytesMut,
|
||||
compress_buf: Vec<u8>,
|
||||
compression: Option<(u32, u32)>,
|
||||
compression: Option<CompressionInfo>,
|
||||
cipher: Option<Cipher>,
|
||||
}
|
||||
|
||||
@ -40,10 +41,10 @@ impl PacketEncoder {
|
||||
|
||||
let data_len = self.buf.len() - start_len;
|
||||
|
||||
if let Some((threshold, compression_level)) = self.compression {
|
||||
if data_len > threshold as usize {
|
||||
if let Some(compression) = &self.compression {
|
||||
if data_len > compression.threshold as usize {
|
||||
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();
|
||||
|
||||
@ -117,13 +118,20 @@ impl PacketEncoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable_encryption(&mut self, key: &[u8; 16]) {
|
||||
assert!(self.cipher.is_none(), "encryption is already enabled");
|
||||
self.cipher = Some(Cipher::new_from_slices(key, key).expect("invalid key"));
|
||||
pub fn set_encryption(&mut self, key: Option<&[u8; 16]>) {
|
||||
if let Some(key) = 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
|
||||
pub fn set_compression(&mut self, compression: Option<(u32, u32)>) {
|
||||
pub fn set_compression(&mut self, compression: Option<CompressionInfo>) {
|
||||
self.compression = compression;
|
||||
}
|
||||
|
||||
|
||||
@ -26,10 +26,9 @@ impl BlockId {
|
||||
.iter();
|
||||
|
||||
let block_state = match properties {
|
||||
Some(properties) => match block_states.find(|state| &state.properties == properties) {
|
||||
Some(state) => state,
|
||||
None => return Err(WorldError::BlockStateIdNotFound),
|
||||
},
|
||||
Some(properties) => block_states
|
||||
.find(|state| &state.properties == properties)
|
||||
.ok_or_else(|| WorldError::BlockStateIdNotFound)?,
|
||||
None => block_states
|
||||
.find(|state| state.is_default)
|
||||
.expect("Every Block should have at least 1 default state"),
|
||||
|
||||
@ -135,6 +135,8 @@ impl Level {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_block() {}
|
||||
|
||||
/// Reads/Generates many chunks in a world
|
||||
/// MUST be called from a tokio runtime thread
|
||||
///
|
||||
@ -147,7 +149,6 @@ impl Level {
|
||||
) {
|
||||
chunks.into_par_iter().for_each(|at| {
|
||||
if is_alive {
|
||||
dbg!("a");
|
||||
return;
|
||||
}
|
||||
let mut loaded_chunks = self.loaded_chunks.lock();
|
||||
@ -235,29 +236,21 @@ impl Level {
|
||||
|
||||
// Read the file using the offset and size
|
||||
let mut file_buf = {
|
||||
let seek_result = region_file.seek(std::io::SeekFrom::Start(offset));
|
||||
if seek_result.is_err() {
|
||||
return Err(WorldError::RegionIsInvalid);
|
||||
}
|
||||
region_file
|
||||
.seek(std::io::SeekFrom::Start(offset))
|
||||
.map_err(|_| WorldError::RegionIsInvalid)?;
|
||||
let mut out = vec![0; size];
|
||||
let read_result = region_file.read_exact(&mut out);
|
||||
if read_result.is_err() {
|
||||
return Err(WorldError::RegionIsInvalid);
|
||||
}
|
||||
region_file
|
||||
.read_exact(&mut out)
|
||||
.map_err(|_| WorldError::RegionIsInvalid)?;
|
||||
out
|
||||
};
|
||||
|
||||
// TODO: check checksum to make sure chunk is not corrupted
|
||||
let header = file_buf.drain(0..5).collect_vec();
|
||||
|
||||
let compression = match Compression::from_byte(header[4]) {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(WorldError::Compression(
|
||||
CompressionError::UnknownCompression,
|
||||
))
|
||||
}
|
||||
};
|
||||
let compression = Compression::from_byte(header[4])
|
||||
.ok_or_else(|| WorldError::Compression(CompressionError::UnknownCompression))?;
|
||||
|
||||
let size = u32::from_be_bytes(header[..4].try_into().unwrap());
|
||||
|
||||
@ -277,23 +270,15 @@ impl Level {
|
||||
Compression::Gzip => {
|
||||
let mut z = GzDecoder::new(&compressed_data[..]);
|
||||
let mut chunk_data = Vec::with_capacity(compressed_data.len());
|
||||
match z.read_to_end(&mut chunk_data) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return Err(CompressionError::GZipError(e));
|
||||
}
|
||||
}
|
||||
z.read_to_end(&mut chunk_data)
|
||||
.map_err(CompressionError::GZipError)?;
|
||||
Ok(chunk_data)
|
||||
}
|
||||
Compression::Zlib => {
|
||||
let mut z = ZlibDecoder::new(&compressed_data[..]);
|
||||
let mut chunk_data = Vec::with_capacity(compressed_data.len());
|
||||
match z.read_to_end(&mut chunk_data) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return Err(CompressionError::ZlibError(e));
|
||||
}
|
||||
}
|
||||
z.read_to_end(&mut chunk_data)
|
||||
.map_err(CompressionError::ZlibError)?;
|
||||
Ok(chunk_data)
|
||||
}
|
||||
Compression::None => Ok(compressed_data),
|
||||
|
||||
@ -107,7 +107,7 @@ impl Client {
|
||||
) {
|
||||
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()));
|
||||
|
||||
let mut gameprofile = self.gameprofile.lock();
|
||||
@ -115,6 +115,7 @@ impl Client {
|
||||
if BASIC_CONFIG.online_mode {
|
||||
let hash = server.digest_secret(&shared_secret);
|
||||
let ip = self.address.lock().ip();
|
||||
|
||||
match authentication::authenticate(
|
||||
&gameprofile.as_ref().unwrap().name,
|
||||
&hash,
|
||||
@ -123,15 +124,15 @@ impl Client {
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(p) => {
|
||||
Ok(profile) => {
|
||||
// Check if player should join
|
||||
if let Some(p) = &p.profile_actions {
|
||||
if let Some(actions) = &profile.profile_actions {
|
||||
if !ADVANCED_CONFIG
|
||||
.authentication
|
||||
.player_profile
|
||||
.allow_banned_players
|
||||
{
|
||||
if !p.is_empty() {
|
||||
if !actions.is_empty() {
|
||||
self.kick("Your account can't join");
|
||||
}
|
||||
} else {
|
||||
@ -140,28 +141,27 @@ impl Client {
|
||||
.player_profile
|
||||
.allowed_actions
|
||||
{
|
||||
if !p.contains(allowed) {
|
||||
if !actions.contains(allowed) {
|
||||
self.kick("Your account can't join");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*gameprofile = Some(p);
|
||||
*gameprofile = Some(profile);
|
||||
}
|
||||
Err(e) => self.kick(&e.to_string()),
|
||||
}
|
||||
}
|
||||
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)
|
||||
let _ = unpack_textures(property, &ADVANCED_CONFIG.authentication.textures);
|
||||
unpack_textures(property, &ADVANCED_CONFIG.authentication.textures)
|
||||
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||
}
|
||||
|
||||
// enable compression
|
||||
if ADVANCED_CONFIG.packet_compression.enabled {
|
||||
let threshold = ADVANCED_CONFIG.packet_compression.compression_threshold;
|
||||
let level = ADVANCED_CONFIG.packet_compression.compression_level;
|
||||
self.send_packet(&CSetCompression::new(threshold.into()));
|
||||
self.set_compression(Some((threshold, level)));
|
||||
let compression = ADVANCED_CONFIG.packet_compression.compression_info.clone();
|
||||
self.send_packet(&CSetCompression::new(compression.threshold.into()));
|
||||
self.set_compression(Some(compression));
|
||||
}
|
||||
|
||||
if let Some(profile) = gameprofile.as_ref() {
|
||||
|
||||
@ -16,6 +16,7 @@ use authentication::GameProfile;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use mio::{event::Event, net::TcpStream, Token};
|
||||
use parking_lot::Mutex;
|
||||
use pumpkin_config::compression::CompressionInfo;
|
||||
use pumpkin_protocol::{
|
||||
bytebuf::{packet_id::Packet, DeserializerError},
|
||||
client::{config::CConfigDisconnect, login::CLoginDisconnect},
|
||||
@ -151,24 +152,29 @@ impl Client {
|
||||
client_packets_queue.push(packet);
|
||||
}
|
||||
|
||||
/// Enables encryption
|
||||
pub fn enable_encryption(
|
||||
/// Sets the Packet encryption
|
||||
pub fn set_encryption(
|
||||
&self,
|
||||
shared_secret: &[u8], // decrypted
|
||||
shared_secret: Option<&[u8]>, // decrypted
|
||||
) -> Result<(), EncryptionError> {
|
||||
self.encryption
|
||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
let crypt_key: [u8; 16] = shared_secret
|
||||
.try_into()
|
||||
.map_err(|_| EncryptionError::SharedWrongLength)?;
|
||||
self.dec.lock().enable_encryption(&crypt_key);
|
||||
self.enc.lock().enable_encryption(&crypt_key);
|
||||
if let Some(shared_secret) = shared_secret {
|
||||
self.encryption
|
||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
let crypt_key: [u8; 16] = shared_secret
|
||||
.try_into()
|
||||
.map_err(|_| EncryptionError::SharedWrongLength)?;
|
||||
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(())
|
||||
}
|
||||
|
||||
/// Compression threshold, Compression level
|
||||
pub fn set_compression(&self, compression: Option<(u32, u32)>) {
|
||||
self.dec.lock().set_compression(compression.map(|v| v.0));
|
||||
/// Sets the Packet compression
|
||||
pub fn set_compression(&self, compression: Option<CompressionInfo>) {
|
||||
self.dec.lock().set_compression(compression.is_some());
|
||||
self.enc.lock().set_compression(compression);
|
||||
}
|
||||
|
||||
@ -200,14 +206,11 @@ impl Client {
|
||||
/// Processes all packets send by the client
|
||||
pub async fn process_packets(&self, server: &Arc<Server>) {
|
||||
while let Some(mut packet) = self.client_packets_queue.lock().pop() {
|
||||
match self.handle_packet(server, &mut packet).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let text = format!("Error while reading incoming packet {}", e);
|
||||
log::error!("{}", text);
|
||||
self.kick(&text)
|
||||
}
|
||||
};
|
||||
let _ = self.handle_packet(server, &mut packet).await.map_err(|e| {
|
||||
let text = format!("Error while reading incoming packet {}", e);
|
||||
log::error!("{}", text);
|
||||
self.kick(&text)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -131,7 +131,7 @@ impl Player {
|
||||
self.kick(TextComponent::text("Invalid movement"));
|
||||
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"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -140,13 +140,10 @@ impl RCONClient {
|
||||
}
|
||||
}
|
||||
// If we get a close here, we might have a reply, which we still want to write.
|
||||
match self.poll(server, password).await {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
log::error!("rcon error: {e}");
|
||||
self.closed = true;
|
||||
}
|
||||
}
|
||||
let _ = self.poll(server, password).await.map_err(|e| {
|
||||
log::error!("rcon error: {e}");
|
||||
self.closed = true;
|
||||
});
|
||||
}
|
||||
self.closed
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ impl CachedStatus {
|
||||
}
|
||||
|
||||
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() {
|
||||
Some(Self::load_icon(icon_path))
|
||||
} else {
|
||||
|
||||
@ -103,11 +103,11 @@ impl Server {
|
||||
};
|
||||
// Basically the default world
|
||||
// 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));
|
||||
world.add_player(token, player.clone());
|
||||
(player, world)
|
||||
(player, world.clone())
|
||||
}
|
||||
|
||||
pub fn try_get_container(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user