From 8bc55e8dda82cf30b42e9d674999d168762d26f6 Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 21 Aug 2024 12:34:25 -0400 Subject: [PATCH 1/3] parse fixed bitset from player chat --- pumpkin-protocol/src/bytebuf/mod.rs | 10 ++++++++-- pumpkin-protocol/src/lib.rs | 1 + pumpkin-protocol/src/server/play/s_chat_message.rs | 6 +++--- pumpkin/src/client/player_packet.rs | 6 ++++++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pumpkin-protocol/src/bytebuf/mod.rs b/pumpkin-protocol/src/bytebuf/mod.rs index fa275bb15..250d4fa1f 100644 --- a/pumpkin-protocol/src/bytebuf/mod.rs +++ b/pumpkin-protocol/src/bytebuf/mod.rs @@ -1,4 +1,4 @@ -use crate::{BitSet, VarInt, VarLongType}; +use crate::{BitSet, FixedBitSet, VarInt, VarLongType}; use bytes::{Buf, BufMut, BytesMut}; use core::str; use std::io::{self, Error, ErrorKind}; @@ -107,6 +107,10 @@ impl ByteBuffer { uuid::Uuid::from_slice(&bytes).expect("Failed to parse UUID") } + pub fn get_fixed_bitset(&mut self, bits: usize) -> FixedBitSet { + self.copy_to_bytes(bits.div_ceil(8)) + } + pub fn put_bool(&mut self, v: bool) { if v { self.buffer.put_u8(1); @@ -168,7 +172,9 @@ impl ByteBuffer { /// some, then it also calls the `write` closure. pub fn put_option(&mut self, val: &Option, write: impl FnOnce(&mut Self, &T)) { self.put_bool(val.is_some()); - if let Some(v) = val { write(self, v) } + if let Some(v) = val { + write(self, v) + } } pub fn get_list(&mut self, val: impl Fn(&mut Self) -> T) -> Vec { diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index 3f7a4b607..f44a0a811 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -21,6 +21,7 @@ pub const MAX_PACKET_SIZE: i32 = 2097152; pub type Identifier = String; pub type VarIntType = i32; pub type VarLongType = i64; +pub type FixedBitSet = bytes::Bytes; pub struct BitSet<'a>(pub VarInt, pub &'a [i64]); diff --git a/pumpkin-protocol/src/server/play/s_chat_message.rs b/pumpkin-protocol/src/server/play/s_chat_message.rs index fc153094a..e644a5bc3 100644 --- a/pumpkin-protocol/src/server/play/s_chat_message.rs +++ b/pumpkin-protocol/src/server/play/s_chat_message.rs @@ -3,7 +3,7 @@ use pumpkin_macros::packet; use crate::{ bytebuf::{ByteBuffer, DeserializerError}, - ServerPacket, VarInt, + FixedBitSet, ServerPacket, VarInt, }; // derive(Deserialize)] @@ -14,8 +14,7 @@ pub struct SChatMessage { pub salt: i64, pub signature: Option, pub messagee_count: VarInt, - // TODO: Properly implement BitSet decoding - // acknowledged: BitSet, + pub acknowledged: FixedBitSet, } // TODO @@ -27,6 +26,7 @@ impl ServerPacket for SChatMessage { salt: bytebuf.get_i64(), signature: bytebuf.get_option(|v| v.copy_to_bytes(256)), messagee_count: bytebuf.get_var_int(), + acknowledged: bytebuf.get_fixed_bitset(20), }) } } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index b8a7853d7..6f7a4d9e5 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -212,7 +212,13 @@ impl Client { pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) { dbg!("got message"); + let message = chat_message.message; + if message.len() > 256 { + self.kick("Oversized message"); + return; + } + // TODO: filter message & validation let gameprofile = self.gameprofile.as_ref().unwrap(); From cd6defe9a257e9ba4fd1bd03aa683d962c176538 Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 21 Aug 2024 17:17:33 -0400 Subject: [PATCH 2/3] implement filtering and serialization changes --- pumpkin-protocol/src/bytebuf/serializer.rs | 25 +++++-- .../src/client/play/c_player_chat_message.rs | 74 +++---------------- pumpkin/src/client/player_packet.rs | 3 +- 3 files changed, 30 insertions(+), 72 deletions(-) diff --git a/pumpkin-protocol/src/bytebuf/serializer.rs b/pumpkin-protocol/src/bytebuf/serializer.rs index 446c87650..791002c2c 100644 --- a/pumpkin-protocol/src/bytebuf/serializer.rs +++ b/pumpkin-protocol/src/bytebuf/serializer.rs @@ -48,6 +48,14 @@ impl ser::Error for SerializerError { } } +// General notes on the serializer: +// +// Primitives are written as-is +// Strings automatically pre-pend a varint +// Enums are written as a varint of the index +// Structs are ignored +// Iterables' values are written in order, but NO information (e.g. size) about the +// iterable itself is written (list sizes should be a seperate field) impl<'a> ser::Serializer for &'a mut Serializer { type Ok = (); type Error = SerializerError; @@ -121,7 +129,8 @@ impl<'a> ser::Serializer for &'a mut Serializer { where T: ?Sized + Serialize, { - unimplemented!() + self.output.put_var_int(&_variant_index.into()); + _value.serialize(self) } fn serialize_none(self) -> Result { self.output.put_bool(false); @@ -160,7 +169,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { unimplemented!() } fn serialize_tuple(self, _len: usize) -> Result { - unimplemented!() + Ok(self) } fn serialize_tuple_struct( self, @@ -176,7 +185,9 @@ impl<'a> ser::Serializer for &'a mut Serializer { _variant: &'static str, _len: usize, ) -> Result { - unimplemented!() + // Serialize ENUM index as varint + self.output.put_var_int(&_variant_index.into()); + Ok(self) } fn serialize_u128(self, _v: u128) -> Result { unimplemented!() @@ -209,7 +220,9 @@ impl<'a> ser::Serializer for &'a mut Serializer { _variant_index: u32, _variant: &'static str, ) -> Result { - todo!() + // For ENUMs, only write enum index as varint + self.output.put_var_int(&_variant_index.into()); + Ok(()) } } @@ -241,11 +254,11 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer { where T: ?Sized + Serialize, { - todo!() + _value.serialize(&mut **self) } fn end(self) -> Result<(), Self::Error> { - todo!() + Ok(()) } } 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 e47e9d225..a79d0516c 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,9 @@ -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; use pumpkin_core::text::TextComponent; use pumpkin_macros::packet; use serde::Serialize; -use crate::{bytebuf::ByteBuffer, uuid::UUID, BitSet, ClientPacket, VarInt}; - +use crate::{uuid::UUID, BitSet, VarInt}; +#[derive(Serialize)] #[packet(0x39)] pub struct CPlayerChatMessage<'a> { sender: UUID, @@ -17,12 +15,7 @@ pub struct CPlayerChatMessage<'a> { previous_messages_count: VarInt, previous_messages: &'a [PreviousMessage<'a>], // max 20 unsigned_content: Option>, - /// See `FilterType` - filter_type: VarInt, - - // TODO: Implement - #[allow(dead_code)] - filter_type_bits: Option>, + filter_type: FilterType<'a>, chat_type: VarInt, sender_name: TextComponent<'a>, target_name: Option>, @@ -39,8 +32,7 @@ impl<'a> CPlayerChatMessage<'a> { salt: i64, previous_messages: &'a [PreviousMessage<'a>], unsigned_content: Option>, - filter_type: VarInt, - filter_type_bits: Option>, + filter_type: FilterType<'a>, chat_type: VarInt, sender_name: TextComponent<'a>, target_name: Option>, @@ -56,7 +48,6 @@ impl<'a> CPlayerChatMessage<'a> { previous_messages, unsigned_content, filter_type, - filter_type_bits, chat_type, sender_name, target_name, @@ -64,64 +55,19 @@ 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 { - // TODO: validate whether this should be None or not - bytebuf.put_slice(prev_sig); - } - } - - 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) { - 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()); - bytebuf.put_option(&self.target_name, |p, v| p.put_slice(v.encode().as_slice())); - } -} - #[derive(Serialize)] pub struct PreviousMessage<'a> { message_id: VarInt, signature: Option<&'a [u8]>, } -#[derive(FromPrimitive, ToPrimitive)] -pub enum FilterType { +#[derive(Serialize)] +#[repr(i32)] +pub enum FilterType<'a> { /// Message is not filtered at all - PassThrough, + PassThrough = 0, /// Message is fully filtered - FullyFiltered, + FullyFiltered = 1, /// Only some characters in the message are filtered - PartiallyFiltered, + PartiallyFiltered(BitSet<'a>) = 2, } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 6f7a4d9e5..34806b91c 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -233,8 +233,7 @@ impl Client { chat_message.salt, &[], Some(TextComponent::text(&message)), - pumpkin_protocol::VarInt(FilterType::PassThrough as i32), - None, + FilterType::PassThrough, 1.into(), TextComponent::text(&gameprofile.name.clone()), None, From c07ea947fc6c8bbe4897874cbe488c77c524db51 Mon Sep 17 00:00:00 2001 From: kralverde Date: Thu, 22 Aug 2024 15:24:58 -0400 Subject: [PATCH 3/3] remove _ from used values --- pumpkin-protocol/src/bytebuf/serializer.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pumpkin-protocol/src/bytebuf/serializer.rs b/pumpkin-protocol/src/bytebuf/serializer.rs index 791002c2c..825288c2a 100644 --- a/pumpkin-protocol/src/bytebuf/serializer.rs +++ b/pumpkin-protocol/src/bytebuf/serializer.rs @@ -122,15 +122,15 @@ impl<'a> ser::Serializer for &'a mut Serializer { fn serialize_newtype_variant( self, _name: &'static str, - _variant_index: u32, + variant_index: u32, _variant: &'static str, - _value: &T, + value: &T, ) -> Result where T: ?Sized + Serialize, { - self.output.put_var_int(&_variant_index.into()); - _value.serialize(self) + self.output.put_var_int(&variant_index.into()); + value.serialize(self) } fn serialize_none(self) -> Result { self.output.put_bool(false); @@ -181,12 +181,12 @@ impl<'a> ser::Serializer for &'a mut Serializer { fn serialize_tuple_variant( self, _name: &'static str, - _variant_index: u32, + variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { // Serialize ENUM index as varint - self.output.put_var_int(&_variant_index.into()); + self.output.put_var_int(&variant_index.into()); Ok(self) } fn serialize_u128(self, _v: u128) -> Result { @@ -217,11 +217,11 @@ impl<'a> ser::Serializer for &'a mut Serializer { fn serialize_unit_variant( self, _name: &'static str, - _variant_index: u32, + variant_index: u32, _variant: &'static str, ) -> Result { // For ENUMs, only write enum index as varint - self.output.put_var_int(&_variant_index.into()); + self.output.put_var_int(&variant_index.into()); Ok(()) } } @@ -250,11 +250,11 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer { type Ok = (); type Error = SerializerError; - fn serialize_element(&mut self, _value: &T) -> Result<(), Self::Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: ?Sized + Serialize, { - _value.serialize(&mut **self) + value.serialize(&mut **self) } fn end(self) -> Result<(), Self::Error> {