From 1b32a6d5124f7be5e3f0b8cf013d14125ed54570 Mon Sep 17 00:00:00 2001 From: kralverde Date: Tue, 20 Aug 2024 21:46:07 -0400 Subject: [PATCH 1/5] fix OBO error --- pumpkin-protocol/src/server/play/s_chat_message.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin-protocol/src/server/play/s_chat_message.rs b/pumpkin-protocol/src/server/play/s_chat_message.rs index c0a98964..2dfed42d 100644 --- a/pumpkin-protocol/src/server/play/s_chat_message.rs +++ b/pumpkin-protocol/src/server/play/s_chat_message.rs @@ -24,7 +24,7 @@ impl ServerPacket for SChatMessage { message: bytebuf.get_string().unwrap(), timestamp: bytebuf.get_i64(), salt: bytebuf.get_i64(), - signature: bytebuf.get_option(|v| v.copy_to_bytes(255)), + signature: bytebuf.get_option(|v| v.copy_to_bytes(256)), messagee_count: bytebuf.get_var_int(), }) } From 90d10da97f46d8b95fc6ba209f993f2884bd1334 Mon Sep 17 00:00:00 2001 From: kralverde Date: Tue, 20 Aug 2024 23:00:47 -0400 Subject: [PATCH 2/5] manually implement basic chat serialization --- .../src/client/play/c_player_chat_message.rs | 60 ++++++++++++++++++- pumpkin-protocol/src/packet_encoder.rs | 4 ++ .../src/server/play/s_chat_message.rs | 1 + 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_player_chat_message.rs b/pumpkin-protocol/src/client/play/c_player_chat_message.rs index ade16d85..500cc264 100644 --- a/pumpkin-protocol/src/client/play/c_player_chat_message.rs +++ b/pumpkin-protocol/src/client/play/c_player_chat_message.rs @@ -1,11 +1,11 @@ use num_derive::{FromPrimitive, ToPrimitive}; +use num_traits::FromPrimitive; use pumpkin_macros::packet; use pumpkin_text::TextComponent; use serde::Serialize; -use crate::{uuid::UUID, BitSet, VarInt}; +use crate::{bytebuf::ByteBuffer, uuid::UUID, BitSet, ClientPacket, VarInt}; -#[derive(Serialize)] #[packet(0x39)] pub struct CPlayerChatMessage<'a> { sender: UUID, @@ -19,6 +19,9 @@ pub struct CPlayerChatMessage<'a> { unsigned_content: Option>, /// See `FilterType` filter_type: VarInt, + + // TODO: Implement + #[allow(dead_code)] filter_type_bits: Option>, chat_type: VarInt, sender_name: TextComponent<'a>, @@ -61,6 +64,59 @@ impl<'a> CPlayerChatMessage<'a> { } } +impl<'a> ClientPacket for CPlayerChatMessage<'a> { + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_uuid(self.sender.0); + bytebuf.put_var_int(&self.index); + bytebuf.put_option(&self.message_signature, |p, v| p.put_slice(v)); + bytebuf.put_string(self.message); + bytebuf.put_i64(self.timestamp); + bytebuf.put_i64(self.salt); + + if self.previous_messages_count.0 > 20 { + // TODO: Assert this is <=20 + } + + bytebuf.put_var_int(&self.previous_messages_count); + for previous_message in self.previous_messages { + bytebuf.put_var_int(&previous_message.message_id); + if let Some(prev_sig) = previous_message.signature { + bytebuf.put_slice(prev_sig); + } + } + + if let Some(unsigned_component) = self.unsigned_content.as_ref() { + bytebuf.put_bool(true); + bytebuf.put_slice(unsigned_component.encode().as_slice()); + } else { + bytebuf.put_bool(false); + } + + bytebuf.put_var_int(&self.filter_type); + match FilterType::from_i32(self.filter_type.0) { + Some(FilterType::PassThrough) => (), + Some(FilterType::FullyFiltered) => { + // TODO: Implement + } + Some(FilterType::PartiallyFiltered) => { + // TODO: Implement + } + None => { + // TODO: Implement + } + } + + bytebuf.put_var_int(&self.chat_type); + bytebuf.put_slice(self.sender_name.encode().as_slice()); + if let Some(target) = &self.target_name { + bytebuf.put_bool(true); + bytebuf.put_slice(target.encode().as_slice()); + } else { + bytebuf.put_bool(false); + } + } +} + #[derive(Serialize)] pub struct PreviousMessage<'a> { message_id: VarInt, diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs index 511d095d..8bf231f9 100644 --- a/pumpkin-protocol/src/packet_encoder.rs +++ b/pumpkin-protocol/src/packet_encoder.rs @@ -115,6 +115,10 @@ impl PacketEncoder { VarInt(packet_len as i32) .encode(front) .map_err(|_| PacketError::EncodeID)?; + + if P::PACKET_ID == 0x39 { + println!("PACKET: {:X}", self.buf); + } Ok(()) } diff --git a/pumpkin-protocol/src/server/play/s_chat_message.rs b/pumpkin-protocol/src/server/play/s_chat_message.rs index 2dfed42d..fc153094 100644 --- a/pumpkin-protocol/src/server/play/s_chat_message.rs +++ b/pumpkin-protocol/src/server/play/s_chat_message.rs @@ -14,6 +14,7 @@ pub struct SChatMessage { pub salt: i64, pub signature: Option, pub messagee_count: VarInt, + // TODO: Properly implement BitSet decoding // acknowledged: BitSet, } From 8c7759b10873a3e47d615cfef33db25baedd79fa Mon Sep 17 00:00:00 2001 From: kralverde Date: Tue, 20 Aug 2024 23:01:43 -0400 Subject: [PATCH 3/5] remove print test --- pumpkin-protocol/src/packet_encoder.rs | 144 ------------------------- 1 file changed, 144 deletions(-) delete mode 100644 pumpkin-protocol/src/packet_encoder.rs diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs deleted file mode 100644 index 8bf231f9..00000000 --- a/pumpkin-protocol/src/packet_encoder.rs +++ /dev/null @@ -1,144 +0,0 @@ -use std::io::Write; - -use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; -use bytes::{BufMut, BytesMut}; - -use std::io::Read; - -use flate2::bufread::ZlibEncoder; -use flate2::Compression; - -use crate::{bytebuf::ByteBuffer, ClientPacket, PacketError, VarInt, MAX_PACKET_SIZE}; - -type Cipher = cfb8::Encryptor; - -// Encoder: Server -> Client -#[derive(Default)] -pub struct PacketEncoder { - buf: BytesMut, - compress_buf: Vec, - compression: Option<(u32, u32)>, - cipher: Option, -} - -impl PacketEncoder { - // i think clippy is broken - #[allow(clippy::needless_borrows_for_generic_args)] - pub fn append_packet(&mut self, packet: &P) -> Result<(), PacketError> { - let start_len = self.buf.len(); - - let mut writer = (&mut self.buf).writer(); - - let mut packet_buf = ByteBuffer::empty(); - VarInt(P::PACKET_ID) - .encode(&mut writer) - .map_err(|_| PacketError::EncodeID)?; - packet.write(&mut packet_buf); - - writer - .write(packet_buf.buf()) - .map_err(|_| PacketError::EncodeFailedWrite)?; - - let data_len = self.buf.len() - start_len; - - if let Some((threshold, compression_level)) = self.compression { - if data_len > threshold as usize { - let mut z = - ZlibEncoder::new(&self.buf[start_len..], Compression::new(compression_level)); - - self.compress_buf.clear(); - - let data_len_size = VarInt(data_len as i32).written_size(); - - let packet_len = data_len_size + z.read_to_end(&mut self.compress_buf).unwrap(); - - if packet_len >= MAX_PACKET_SIZE as usize { - Err(PacketError::TooLong)? - } - - drop(z); - - self.buf.truncate(start_len); - - let mut writer = (&mut self.buf).writer(); - - VarInt(packet_len as i32) - .encode(&mut writer) - .map_err(|_| PacketError::EncodeLength)?; - VarInt(data_len as i32) - .encode(&mut writer) - .map_err(|_| PacketError::EncodeData)?; - self.buf.extend_from_slice(&self.compress_buf); - } else { - let data_len_size = 1; - let packet_len = data_len_size + data_len; - - if packet_len >= MAX_PACKET_SIZE as usize { - Err(PacketError::TooLong)? - } - - let packet_len_size = VarInt(packet_len as i32).written_size(); - - let data_prefix_len = packet_len_size + data_len_size; - - self.buf.put_bytes(0, data_prefix_len); - self.buf - .copy_within(start_len..start_len + data_len, start_len + data_prefix_len); - - let mut front = &mut self.buf[start_len..]; - - VarInt(packet_len as i32) - .encode(&mut front) - .map_err(|_| PacketError::EncodeLength)?; - // Zero for no compression on this packet. - VarInt(0) - .encode(front) - .map_err(|_| PacketError::EncodeData)?; - } - - return Ok(()); - } - - let packet_len = data_len; - - if packet_len >= MAX_PACKET_SIZE as usize { - Err(PacketError::TooLong)? - } - - let packet_len_size = VarInt(packet_len as i32).written_size(); - - self.buf.put_bytes(0, packet_len_size); - self.buf - .copy_within(start_len..start_len + data_len, start_len + packet_len_size); - - let front = &mut self.buf[start_len..]; - VarInt(packet_len as i32) - .encode(front) - .map_err(|_| PacketError::EncodeID)?; - - if P::PACKET_ID == 0x39 { - println!("PACKET: {:X}", self.buf); - } - 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_compression(&mut self, compression: Option<(u32, u32)>) { - self.compression = compression; - } - - pub fn take(&mut self) -> BytesMut { - if let Some(cipher) = &mut self.cipher { - for chunk in self.buf.chunks_mut(Cipher::block_size()) { - let gen_arr = GenericArray::from_mut_slice(chunk); - cipher.encrypt_block_mut(gen_arr); - } - } - - self.buf.split() - } -} From 9cf6d406c6827a492717b7526e9e974db9338112 Mon Sep 17 00:00:00 2001 From: kralverde Date: Tue, 20 Aug 2024 23:02:56 -0400 Subject: [PATCH 4/5] re-add erroneously removed file --- pumpkin-protocol/src/packet_encoder.rs | 140 +++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 pumpkin-protocol/src/packet_encoder.rs diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs new file mode 100644 index 00000000..511d095d --- /dev/null +++ b/pumpkin-protocol/src/packet_encoder.rs @@ -0,0 +1,140 @@ +use std::io::Write; + +use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; +use bytes::{BufMut, BytesMut}; + +use std::io::Read; + +use flate2::bufread::ZlibEncoder; +use flate2::Compression; + +use crate::{bytebuf::ByteBuffer, ClientPacket, PacketError, VarInt, MAX_PACKET_SIZE}; + +type Cipher = cfb8::Encryptor; + +// Encoder: Server -> Client +#[derive(Default)] +pub struct PacketEncoder { + buf: BytesMut, + compress_buf: Vec, + compression: Option<(u32, u32)>, + cipher: Option, +} + +impl PacketEncoder { + // i think clippy is broken + #[allow(clippy::needless_borrows_for_generic_args)] + pub fn append_packet(&mut self, packet: &P) -> Result<(), PacketError> { + let start_len = self.buf.len(); + + let mut writer = (&mut self.buf).writer(); + + let mut packet_buf = ByteBuffer::empty(); + VarInt(P::PACKET_ID) + .encode(&mut writer) + .map_err(|_| PacketError::EncodeID)?; + packet.write(&mut packet_buf); + + writer + .write(packet_buf.buf()) + .map_err(|_| PacketError::EncodeFailedWrite)?; + + let data_len = self.buf.len() - start_len; + + if let Some((threshold, compression_level)) = self.compression { + if data_len > threshold as usize { + let mut z = + ZlibEncoder::new(&self.buf[start_len..], Compression::new(compression_level)); + + self.compress_buf.clear(); + + let data_len_size = VarInt(data_len as i32).written_size(); + + let packet_len = data_len_size + z.read_to_end(&mut self.compress_buf).unwrap(); + + if packet_len >= MAX_PACKET_SIZE as usize { + Err(PacketError::TooLong)? + } + + drop(z); + + self.buf.truncate(start_len); + + let mut writer = (&mut self.buf).writer(); + + VarInt(packet_len as i32) + .encode(&mut writer) + .map_err(|_| PacketError::EncodeLength)?; + VarInt(data_len as i32) + .encode(&mut writer) + .map_err(|_| PacketError::EncodeData)?; + self.buf.extend_from_slice(&self.compress_buf); + } else { + let data_len_size = 1; + let packet_len = data_len_size + data_len; + + if packet_len >= MAX_PACKET_SIZE as usize { + Err(PacketError::TooLong)? + } + + let packet_len_size = VarInt(packet_len as i32).written_size(); + + let data_prefix_len = packet_len_size + data_len_size; + + self.buf.put_bytes(0, data_prefix_len); + self.buf + .copy_within(start_len..start_len + data_len, start_len + data_prefix_len); + + let mut front = &mut self.buf[start_len..]; + + VarInt(packet_len as i32) + .encode(&mut front) + .map_err(|_| PacketError::EncodeLength)?; + // Zero for no compression on this packet. + VarInt(0) + .encode(front) + .map_err(|_| PacketError::EncodeData)?; + } + + return Ok(()); + } + + let packet_len = data_len; + + if packet_len >= MAX_PACKET_SIZE as usize { + Err(PacketError::TooLong)? + } + + let packet_len_size = VarInt(packet_len as i32).written_size(); + + self.buf.put_bytes(0, packet_len_size); + self.buf + .copy_within(start_len..start_len + data_len, start_len + packet_len_size); + + let front = &mut self.buf[start_len..]; + VarInt(packet_len as i32) + .encode(front) + .map_err(|_| PacketError::EncodeID)?; + 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_compression(&mut self, compression: Option<(u32, u32)>) { + self.compression = compression; + } + + pub fn take(&mut self) -> BytesMut { + if let Some(cipher) = &mut self.cipher { + for chunk in self.buf.chunks_mut(Cipher::block_size()) { + let gen_arr = GenericArray::from_mut_slice(chunk); + cipher.encrypt_block_mut(gen_arr); + } + } + + self.buf.split() + } +} From bf698b657184f5df01e9cf31537e468601012da8 Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 21 Aug 2024 00:51:08 -0400 Subject: [PATCH 5/5] use optional method --- .../src/client/play/c_player_chat_message.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_player_chat_message.rs b/pumpkin-protocol/src/client/play/c_player_chat_message.rs index 500cc264..03f2160b 100644 --- a/pumpkin-protocol/src/client/play/c_player_chat_message.rs +++ b/pumpkin-protocol/src/client/play/c_player_chat_message.rs @@ -81,16 +81,14 @@ impl<'a> ClientPacket for CPlayerChatMessage<'a> { for previous_message in self.previous_messages { bytebuf.put_var_int(&previous_message.message_id); if let Some(prev_sig) = previous_message.signature { + // TODO: validate whether this should be None or not bytebuf.put_slice(prev_sig); } } - if let Some(unsigned_component) = self.unsigned_content.as_ref() { - bytebuf.put_bool(true); - bytebuf.put_slice(unsigned_component.encode().as_slice()); - } else { - bytebuf.put_bool(false); - } + bytebuf.put_option(&self.unsigned_content, |p, v| { + p.put_slice(v.encode().as_slice()) + }); bytebuf.put_var_int(&self.filter_type); match FilterType::from_i32(self.filter_type.0) { @@ -108,12 +106,7 @@ impl<'a> ClientPacket for CPlayerChatMessage<'a> { bytebuf.put_var_int(&self.chat_type); bytebuf.put_slice(self.sender_name.encode().as_slice()); - if let Some(target) = &self.target_name { - bytebuf.put_bool(true); - bytebuf.put_slice(target.encode().as_slice()); - } else { - bytebuf.put_bool(false); - } + bytebuf.put_option(&self.target_name, |p, v| p.put_slice(v.encode().as_slice())); } }