Skip to main content

steel_protocol/packets/game/chat/
session.rs

1use std::{
2    io::{Cursor, Read},
3    time::{SystemTime, UNIX_EPOCH},
4};
5
6use steel_macros::ServerPacket;
7use steel_utils::codec::VarInt;
8use uuid::Uuid;
9
10/// Network-serializable chat session data.
11///
12/// This is a simplified version that holds raw byte data for transmission.
13/// The full version with validated keys lives in steel-core.
14#[derive(Clone, Debug)]
15pub struct ProtocolRemoteChatSessionData {
16    /// The session ID
17    pub session_id: Uuid,
18    /// When the key expires (as milliseconds since UNIX epoch)
19    pub expires_at_millis: i64,
20    /// The public key bytes
21    pub public_key_bytes: Vec<u8>,
22    /// The key signature bytes
23    pub key_signature: Vec<u8>,
24}
25
26impl ProtocolRemoteChatSessionData {
27    /// Creates new chat session data from raw components
28    #[must_use]
29    pub fn new(
30        session_id: Uuid,
31        expires_at: SystemTime,
32        public_key_bytes: Vec<u8>,
33        key_signature: Vec<u8>,
34    ) -> Self {
35        let expires_at_millis = expires_at
36            .duration_since(UNIX_EPOCH)
37            .unwrap_or_default()
38            .as_millis() as i64;
39
40        Self {
41            session_id,
42            expires_at_millis,
43            public_key_bytes,
44            key_signature,
45        }
46    }
47}
48
49impl steel_utils::serial::WriteTo for ProtocolRemoteChatSessionData {
50    fn write(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
51        self.session_id.write(writer)?;
52
53        // Write expires_at (i64 millis)
54        self.expires_at_millis.write(writer)?;
55
56        // Write public key (length as VarInt, then bytes)
57        VarInt(self.public_key_bytes.len() as i32).write(writer)?;
58        writer.write_all(&self.public_key_bytes)?;
59
60        // Write key signature (length as VarInt, then bytes)
61        VarInt(self.key_signature.len() as i32).write(writer)?;
62        writer.write_all(&self.key_signature)?;
63
64        Ok(())
65    }
66}
67
68/// Client -> Server: Updates the player's chat session with their public key.
69///
70/// Sent when the player first joins or when their key needs to be updated.
71/// Contains the session ID and the player's public key signed by Mojang.
72///
73/// Equivalent to `ServerboundChatSessionUpdatePacket` in Minecraft.
74#[derive(ServerPacket, Clone, Debug)]
75pub struct SChatSessionUpdate {
76    /// The session ID for this chat session
77    pub session_id: Uuid,
78
79    /// Public key expiry timestamp (milliseconds since epoch)
80    pub expires_at: i64,
81
82    /// The player's RSA public key (DER encoded)
83    pub public_key: Vec<u8>,
84
85    /// Mojang's signature of the key (validates authenticity)
86    pub key_signature: Vec<u8>,
87}
88
89impl steel_utils::serial::ReadFrom for SChatSessionUpdate {
90    fn read(reader: &mut Cursor<&[u8]>) -> std::io::Result<Self> {
91        let session_id = Uuid::read(reader)?;
92        let expires_at = i64::read(reader)?;
93
94        let key_len = VarInt::read(reader)?.0 as usize;
95        let mut public_key = vec![0u8; key_len];
96        reader.read_exact(&mut public_key)?;
97
98        let sig_len = VarInt::read(reader)?.0 as usize;
99        let mut key_signature = vec![0u8; sig_len];
100        reader.read_exact(&mut key_signature)?;
101
102        Ok(Self {
103            session_id,
104            expires_at,
105            public_key,
106            key_signature,
107        })
108    }
109}