Add Cookies (#325)

* COKKIES PROTOCOL

* Update pumpkin-protocol/src/client/config/c_store_cookie.rs

Co-authored-by: DataModel <183248792+DataM0del@users.noreply.github.com>

* Update pumpkin-protocol/src/server/config/s_cookie_response.rs

Co-authored-by: DataModel <183248792+DataM0del@users.noreply.github.com>

* Update pumpkin-protocol/src/server/play/s_cookie_response.rs

Co-authored-by: DataModel <183248792+DataM0del@users.noreply.github.com>

* Add read fn

* Finished

* Add to readme

* remove async

* use payload.len()

* fix payload_length

* fix all

---------

Co-authored-by: DataModel <183248792+DataM0del@users.noreply.github.com>
This commit is contained in:
Commandcracker
2024-11-25 23:15:02 +01:00
committed by GitHub
parent 0f3e0e936d
commit e43e9f4575
20 changed files with 326 additions and 15 deletions

View File

@@ -42,7 +42,7 @@ and customizable experience. It prioritizes performance and player enjoyment whi
- [x] Server Brand
- [ ] Server Links
- [x] Set Resource Pack
- [ ] Cookies
- [x] Cookies
- World
- [x] World Joining
- [x] Player Tab-list

View File

@@ -4,6 +4,13 @@ use crate::Identifier;
#[derive(serde::Serialize)]
#[client_packet("config:cookie_request")]
pub struct CCookieRequest {
key: Identifier,
/// Requests a cookie that was previously stored.
pub struct CCookieRequest<'a> {
key: &'a Identifier,
}
impl<'a> CCookieRequest<'a> {
pub fn new(key: &'a Identifier) -> Self {
Self { key }
}
}

View File

@@ -0,0 +1,22 @@
use crate::{Identifier, VarInt};
use pumpkin_macros::client_packet;
#[derive(serde::Serialize)]
#[client_packet("config:store_cookie")]
/// Stores some arbitrary data on the client, which persists between server transfers.
/// The Notchian (vanilla) client only accepts cookies of up to 5 kiB in size.
pub struct CStoreCookie<'a> {
key: &'a Identifier,
payload_length: VarInt,
payload: &'a [u8], // 5120,
}
impl<'a> CStoreCookie<'a> {
pub fn new(key: &'a Identifier, payload: &'a [u8]) -> Self {
Self {
key,
payload_length: VarInt(payload.len() as i32),
payload,
}
}
}

View File

@@ -0,0 +1,16 @@
use crate::VarInt;
use pumpkin_macros::client_packet;
use serde::Serialize;
#[derive(Serialize)]
#[client_packet("config:transfer")]
pub struct CTransfer<'a> {
host: &'a str,
port: &'a VarInt,
}
impl<'a> CTransfer<'a> {
pub fn new(host: &'a str, port: &'a VarInt) -> Self {
Self { host, port }
}
}

View File

@@ -5,6 +5,8 @@ mod c_finish_config;
mod c_known_packs;
mod c_plugin_message;
mod c_registry_data;
mod c_store_cookie;
mod c_transfer;
pub use c_add_resource_pack::*;
pub use c_config_disconnect::*;
@@ -13,3 +15,5 @@ pub use c_finish_config::*;
pub use c_known_packs::*;
pub use c_plugin_message::*;
pub use c_registry_data::*;
pub use c_store_cookie::*;
pub use c_transfer::*;

View File

@@ -0,0 +1,16 @@
use crate::Identifier;
use pumpkin_macros::client_packet;
use serde::Serialize;
#[derive(Serialize)]
#[client_packet("login:cookie_request")]
/// Requests a cookie that was previously stored.
pub struct CCookieRequest<'a> {
key: &'a Identifier,
}
impl<'a> CCookieRequest<'a> {
pub fn new(key: &'a Identifier) -> Self {
Self { key }
}
}

View File

@@ -1,9 +1,11 @@
mod c_cookie_request;
mod c_encryption_request;
mod c_login_disconnect;
mod c_login_success;
mod c_plugin_request;
mod c_set_compression;
pub use c_cookie_request::*;
pub use c_encryption_request::*;
pub use c_login_disconnect::*;
pub use c_login_success::*;

View File

@@ -0,0 +1,16 @@
use crate::Identifier;
use pumpkin_macros::client_packet;
use serde::Serialize;
#[derive(Serialize)]
#[client_packet("play:cookie_request")]
/// Requests a cookie that was previously stored.
pub struct CCookieRequest<'a> {
key: &'a Identifier,
}
impl<'a> CCookieRequest<'a> {
pub fn new(key: &'a Identifier) -> Self {
Self { key }
}
}

View File

@@ -0,0 +1,23 @@
use crate::{Identifier, VarInt};
use pumpkin_macros::client_packet;
use serde::Serialize;
/// Stores some arbitrary data on the client, which persists between server transfers.
/// The Notchian client only accepts cookies of up to 5 kiB in size.
#[derive(Serialize)]
#[client_packet("play:store_cookie")]
pub struct CStoreCookie<'a> {
key: &'a Identifier,
payload_length: VarInt,
payload: &'a [u8], // 5120,
}
impl<'a> CStoreCookie<'a> {
pub fn new(key: &'a Identifier, payload: &'a [u8]) -> Self {
Self {
key,
payload_length: VarInt(payload.len() as i32),
payload,
}
}
}

View File

@@ -9,6 +9,7 @@ mod c_close_container;
mod c_combat_death;
mod c_command_suggestions;
mod c_commands;
mod c_cookie_request;
mod c_damage_event;
mod c_disguised_chat_message;
mod c_display_objective;
@@ -47,6 +48,7 @@ mod c_set_held_item;
mod c_set_title;
mod c_sound_effect;
mod c_spawn_entity;
mod c_store_cookie;
mod c_subtitle;
mod c_sync_player_position;
mod c_system_chat_message;
@@ -72,6 +74,7 @@ pub use c_close_container::*;
pub use c_combat_death::*;
pub use c_command_suggestions::*;
pub use c_commands::*;
pub use c_cookie_request::*;
pub use c_damage_event::*;
pub use c_disguised_chat_message::*;
pub use c_display_objective::*;
@@ -110,6 +113,7 @@ pub use c_set_held_item::*;
pub use c_set_title::*;
pub use c_sound_effect::*;
pub use c_spawn_entity::*;
pub use c_store_cookie::*;
pub use c_subtitle::*;
pub use c_sync_player_position::*;
pub use c_system_chat_message::*;

View File

@@ -1,9 +1,11 @@
mod s_acknowledge_finish_config;
mod s_client_information;
mod s_cookie_response;
mod s_known_packs;
mod s_plugin_message;
pub use s_acknowledge_finish_config::*;
pub use s_client_information::*;
pub use s_cookie_response::*;
pub use s_known_packs::*;
pub use s_plugin_message::*;

View File

@@ -0,0 +1,51 @@
use pumpkin_macros::server_packet;
use serde::de;
use crate::bytebuf::{ByteBuffer, DeserializerError};
use crate::{Identifier, ServerPacket, VarInt};
#[server_packet("config:cookie_response")]
/// Response to a Cookie Request (configuration) from the server.
/// The Notchian (vanilla) server only accepts responses of up to 5 kiB in size.
pub struct SCookieResponse {
pub key: Identifier,
pub has_payload: bool,
pub payload_length: Option<VarInt>,
pub payload: Option<Vec<u8>>, // 5120,
}
const MAX_PAYLOAD_SIZE: i32 = 5120;
impl ServerPacket for SCookieResponse {
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
let key = bytebuf.get_string()?;
let has_payload = bytebuf.get_bool()?;
if !has_payload {
return Ok(Self {
key,
has_payload,
payload_length: None,
payload: None,
});
}
let payload_length = bytebuf.get_var_int()?;
let length = payload_length.0;
if length > MAX_PAYLOAD_SIZE {
return Err(de::Error::custom(
"Payload exceeds the maximum allowed size (5120 bytes)",
));
}
let payload = bytebuf.copy_to_bytes(length as usize)?.to_vec();
Ok(Self {
key,
has_payload,
payload_length: Some(payload_length),
payload: Some(payload),
})
}
}

View File

@@ -1,8 +1,10 @@
mod s_cookie_response;
mod s_encryption_response;
mod s_login_response;
mod s_login_start;
mod s_plugin_response;
pub use s_cookie_response::*;
pub use s_encryption_response::*;
pub use s_login_response::*;
pub use s_login_start::*;

View File

@@ -0,0 +1,50 @@
use crate::bytebuf::{ByteBuffer, DeserializerError};
use crate::{Identifier, ServerPacket, VarInt};
use pumpkin_macros::server_packet;
use serde::de;
#[server_packet("login:cookie_response")]
/// Response to a Cookie Request (login) from the server.
/// The Notchian server only accepts responses of up to 5 kiB in size.
pub struct SCookieResponse {
pub key: Identifier,
pub has_payload: bool,
pub payload_length: Option<VarInt>,
pub payload: Option<Vec<u8>>, // 5120,
}
const MAX_PAYLOAD_SIZE: i32 = 5120;
impl ServerPacket for SCookieResponse {
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
let key = bytebuf.get_string()?;
let has_payload = bytebuf.get_bool()?;
if !has_payload {
return Ok(Self {
key,
has_payload,
payload_length: None,
payload: None,
});
}
let payload_length = bytebuf.get_var_int()?;
let length = payload_length.0;
if length > MAX_PAYLOAD_SIZE {
return Err(de::Error::custom(
"Payload exceeds the maximum allowed size (5120 bytes)",
));
}
let payload = bytebuf.copy_to_bytes(length as usize)?.to_vec();
Ok(Self {
key,
has_payload,
payload_length: Some(payload_length),
payload: Some(payload),
})
}
}

View File

@@ -7,6 +7,7 @@ mod s_client_tick_end;
mod s_close_container;
mod s_command_suggestion;
mod s_confirm_teleport;
mod s_cookie_response;
mod s_interact;
mod s_keep_alive;
mod s_ping_request;
@@ -33,6 +34,7 @@ pub use s_client_tick_end::*;
pub use s_close_container::*;
pub use s_command_suggestion::*;
pub use s_confirm_teleport::*;
pub use s_cookie_response::*;
pub use s_interact::*;
pub use s_keep_alive::*;
pub use s_ping_request::*;

View File

@@ -0,0 +1,50 @@
use crate::bytebuf::{ByteBuffer, DeserializerError};
use crate::{Identifier, ServerPacket, VarInt};
use pumpkin_macros::server_packet;
use serde::de;
#[server_packet("play:cookie_response")]
/// Response to a Cookie Request (play) from the server.
/// The Notchian (vanilla) server only accepts responses of up to 5 kiB in size.
pub struct SCookieResponse {
pub key: Identifier,
pub has_payload: bool,
pub payload_length: Option<VarInt>,
pub payload: Option<Vec<u8>>, // 5120,
}
const MAX_PAYLOAD_SIZE: i32 = 5120;
impl ServerPacket for SCookieResponse {
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
let key = bytebuf.get_string()?;
let has_payload = bytebuf.get_bool()?;
if !has_payload {
return Ok(Self {
key,
has_payload,
payload_length: None,
payload: None,
});
}
let payload_length = bytebuf.get_var_int()?;
let length = payload_length.0;
if length > MAX_PAYLOAD_SIZE {
return Err(de::Error::custom(
"Payload exceeds the maximum allowed size (5120 bytes)",
));
}
let payload = bytebuf.copy_to_bytes(length as usize)?.to_vec();
Ok(Self {
key,
has_payload,
payload_length: Some(payload_length),
payload: Some(payload),
})
}
}

View File

@@ -1,6 +1,17 @@
use crate::{
client::authentication::{self, offline_uuid, validate_textures, GameProfile},
entity::player::{ChatMode, Hand},
proxy::{
bungeecord,
velocity::{self, velocity_login},
},
server::{Server, CURRENT_MC_VERSION},
};
use num_traits::FromPrimitive;
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
use pumpkin_core::text::TextComponent;
use pumpkin_protocol::server::config::SCookieResponse as SCCookieResponse;
use pumpkin_protocol::server::login::SCookieResponse as SLCookieResponse;
use pumpkin_protocol::{
client::{
config::{CConfigAddResourcePack, CFinishConfig, CKnownPacks, CRegistryData},
@@ -13,20 +24,10 @@ use pumpkin_protocol::{
login::{SEncryptionResponse, SLoginPluginResponse, SLoginStart},
status::SStatusPingRequest,
},
ConnectionState, KnownPack, CURRENT_MC_PROTOCOL,
ConnectionState, KnownPack, VarInt, CURRENT_MC_PROTOCOL,
};
use uuid::Uuid;
use crate::{
client::authentication::{self, offline_uuid, validate_textures, GameProfile},
entity::player::{ChatMode, Hand},
proxy::{
bungeecord,
velocity::{self, velocity_login},
},
server::{Server, CURRENT_MC_VERSION},
};
use super::{authentication::AuthError, Client, PlayerConfig};
/// Processes incoming Packets from the Client to the Server
@@ -251,6 +252,16 @@ impl Client {
Err(AuthError::MissingAuthClient)
}
pub fn handle_login_cookie_response(&self, packet: SLCookieResponse) {
// TODO: allow plugins to access this
log::debug!(
"Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"",
packet.key,
packet.has_payload,
packet.payload_length.unwrap_or(VarInt::from(0)).0
);
}
pub async fn handle_plugin_response(&self, plugin_response: SLoginPluginResponse) {
log::debug!("Handling plugin");
let velocity_config = &ADVANCED_CONFIG.proxy.velocity;
@@ -342,6 +353,16 @@ impl Client {
}
}
pub fn handle_config_cookie_response(&self, packet: SCCookieResponse) {
// TODO: allow plugins to access this
log::debug!(
"Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"",
packet.key,
packet.has_payload,
packet.payload_length.unwrap_or(VarInt::from(0)).0
);
}
pub async fn handle_known_packs(&self, server: &Server, _config_acknowledged: SKnownPacks) {
log::debug!("Handling known packs");
for registry in &server.cached_registry {

View File

@@ -32,8 +32,9 @@ use pumpkin_protocol::{
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::sync::Mutex;
use pumpkin_protocol::server::config::SCookieResponse as SCCookieResponse;
use pumpkin_protocol::server::login::SCookieResponse as SLCookieResponse;
use thiserror::Error;
pub mod authentication;
mod client_packet;
pub mod combat;
@@ -433,6 +434,9 @@ impl Client {
SLoginAcknowledged::PACKET_ID => {
self.handle_login_acknowledged(server).await;
}
SLCookieResponse::PACKET_ID => {
self.handle_login_cookie_response(SLCookieResponse::read(bytebuf)?);
}
_ => {
log::error!(
"Failed to handle client packet id {} in Login State",
@@ -467,6 +471,9 @@ impl Client {
self.handle_known_packs(server, SKnownPacks::read(bytebuf)?)
.await;
}
SCCookieResponse::PACKET_ID => {
self.handle_config_cookie_response(SCCookieResponse::read(bytebuf)?);
}
_ => {
log::error!(
"Failed to handle client packet id {} in Config State",

View File

@@ -16,9 +16,11 @@ use pumpkin_core::{
GameMode,
};
use pumpkin_inventory::{InventoryError, WindowType};
use pumpkin_protocol::server::play::SCookieResponse as SPCookieResponse;
use pumpkin_protocol::{
client::play::CCommandSuggestions,
server::play::{SCloseContainer, SCommandSuggestion, SKeepAlive, SSetPlayerGround, SUseItem},
VarInt,
};
use pumpkin_protocol::{
client::play::{
@@ -751,4 +753,14 @@ impl Player {
self.client.send_packet(&response).await;
}
pub fn handle_cookie_response(&self, packet: SPCookieResponse) {
// TODO: allow plugins to access this
log::debug!(
"Received cookie_response[play]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"",
packet.key,
packet.has_payload,
packet.payload_length.unwrap_or(VarInt::from(0)).0
);
}
}

View File

@@ -24,6 +24,7 @@ use pumpkin_core::{
use pumpkin_entity::{entity_type::EntityType, EntityId};
use pumpkin_inventory::player::PlayerInventory;
use pumpkin_macros::sound;
use pumpkin_protocol::server::play::SCookieResponse as SPCookieResponse;
use pumpkin_protocol::server::play::{SClickContainer, SKeepAlive};
use pumpkin_protocol::{
bytebuf::packet_id::Packet,
@@ -793,6 +794,9 @@ impl Player {
self.handle_command_suggestion(SCommandSuggestion::read(bytebuf)?, server)
.await;
}
SPCookieResponse::PACKET_ID => {
self.handle_cookie_response(SPCookieResponse::read(bytebuf)?);
}
_ => {
log::warn!("Failed to handle player packet id {}", packet.id.0);
// TODO: We give an error if all play packets are implemented