steel_protocol/packets/game/chat/
session.rs1use std::{
2 io::Cursor,
3 time::{SystemTime, UNIX_EPOCH},
4};
5
6use steel_macros::ServerPacket;
7use steel_utils::codec::VarInt;
8use steel_utils::serial::PrefixedRead;
9use uuid::Uuid;
10
11const MAX_PUBLIC_KEY_SIZE: usize = 512;
12const MAX_KEY_SIGNATURE_SIZE: usize = 4096;
13
14#[derive(Clone, Debug)]
19pub struct ProtocolRemoteChatSessionData {
20 pub session_id: Uuid,
22 pub expires_at_millis: i64,
24 pub public_key_bytes: Vec<u8>,
26 pub key_signature: Vec<u8>,
28}
29
30impl ProtocolRemoteChatSessionData {
31 #[must_use]
33 pub fn new(
34 session_id: Uuid,
35 expires_at: SystemTime,
36 public_key_bytes: Vec<u8>,
37 key_signature: Vec<u8>,
38 ) -> Self {
39 let expires_at_millis = expires_at
40 .duration_since(UNIX_EPOCH)
41 .unwrap_or_default()
42 .as_millis() as i64;
43
44 Self {
45 session_id,
46 expires_at_millis,
47 public_key_bytes,
48 key_signature,
49 }
50 }
51}
52
53impl steel_utils::serial::WriteTo for ProtocolRemoteChatSessionData {
54 fn write(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
55 self.session_id.write(writer)?;
56
57 self.expires_at_millis.write(writer)?;
59
60 VarInt(self.public_key_bytes.len() as i32).write(writer)?;
62 writer.write_all(&self.public_key_bytes)?;
63
64 VarInt(self.key_signature.len() as i32).write(writer)?;
66 writer.write_all(&self.key_signature)?;
67
68 Ok(())
69 }
70}
71
72#[derive(ServerPacket, Clone, Debug)]
79pub struct SChatSessionUpdate {
80 pub session_id: Uuid,
82
83 pub expires_at: i64,
85
86 pub public_key: Vec<u8>,
88
89 pub key_signature: Vec<u8>,
91}
92
93impl steel_utils::serial::ReadFrom for SChatSessionUpdate {
94 fn read(reader: &mut Cursor<&[u8]>) -> std::io::Result<Self> {
95 let session_id = Uuid::read(reader)?;
96 let expires_at = i64::read(reader)?;
97
98 let public_key = Vec::<u8>::read_prefixed_bound::<VarInt>(reader, MAX_PUBLIC_KEY_SIZE)?;
99 let key_signature =
100 Vec::<u8>::read_prefixed_bound::<VarInt>(reader, MAX_KEY_SIGNATURE_SIZE)?;
101
102 Ok(Self {
103 session_id,
104 expires_at,
105 public_key,
106 key_signature,
107 })
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use std::io::{Cursor, ErrorKind};
114
115 use steel_utils::serial::{ReadFrom as _, WriteTo as _};
116 use uuid::Uuid;
117
118 use super::{MAX_KEY_SIGNATURE_SIZE, MAX_PUBLIC_KEY_SIZE, SChatSessionUpdate, VarInt};
119
120 fn encoded_packet(
121 public_key_length: i32,
122 public_key: &[u8],
123 signature: Option<(i32, &[u8])>,
124 ) -> Vec<u8> {
125 let mut packet = Vec::new();
126 Uuid::nil()
127 .write(&mut packet)
128 .expect("test session ID should encode");
129 0_i64
130 .write(&mut packet)
131 .expect("test expiration should encode");
132 VarInt(public_key_length)
133 .write(&mut packet)
134 .expect("test public key length should encode");
135 packet.extend_from_slice(public_key);
136
137 if let Some((signature_length, signature)) = signature {
138 VarInt(signature_length)
139 .write(&mut packet)
140 .expect("test signature length should encode");
141 packet.extend_from_slice(signature);
142 }
143
144 packet
145 }
146
147 fn decode(packet: &[u8]) -> std::io::Result<SChatSessionUpdate> {
148 SChatSessionUpdate::read(&mut Cursor::new(packet))
149 }
150
151 #[test]
152 fn accepts_vanilla_maximum_field_lengths() {
153 let public_key = vec![1; MAX_PUBLIC_KEY_SIZE];
154 let signature = vec![2; MAX_KEY_SIGNATURE_SIZE];
155 let packet = encoded_packet(
156 MAX_PUBLIC_KEY_SIZE as i32,
157 &public_key,
158 Some((MAX_KEY_SIGNATURE_SIZE as i32, &signature)),
159 );
160
161 let decoded = decode(&packet).expect("fields at the vanilla limits should decode");
162
163 assert_eq!(decoded.public_key, public_key);
164 assert_eq!(decoded.key_signature, signature);
165 }
166
167 #[test]
168 fn rejects_fields_above_vanilla_limits() {
169 let oversized_public_key =
170 encoded_packet(MAX_PUBLIC_KEY_SIZE as i32 + 1, &[], Some((0, &[])));
171 decode(&oversized_public_key).expect_err("an oversized public key should be rejected");
172
173 let oversized_signature =
174 encoded_packet(0, &[], Some((MAX_KEY_SIGNATURE_SIZE as i32 + 1, &[])));
175 decode(&oversized_signature).expect_err("an oversized signature should be rejected");
176 }
177
178 #[test]
179 fn rejects_negative_and_extreme_field_lengths() {
180 for length in [-1, i32::MAX] {
181 let public_key = encoded_packet(length, &[], Some((0, &[])));
182 decode(&public_key).expect_err("an invalid public key length should be rejected");
183
184 let signature = encoded_packet(0, &[], Some((length, &[])));
185 decode(&signature).expect_err("an invalid signature length should be rejected");
186 }
187 }
188
189 #[test]
190 fn rejects_truncated_field_bodies() {
191 let truncated_public_key = encoded_packet(1, &[], None);
192 let error = decode(&truncated_public_key)
193 .expect_err("a truncated public key body should be rejected");
194 assert_eq!(error.kind(), ErrorKind::UnexpectedEof);
195
196 let truncated_signature = encoded_packet(0, &[], Some((1, &[])));
197 let error = decode(&truncated_signature)
198 .expect_err("a truncated signature body should be rejected");
199 assert_eq!(error.kind(), ErrorKind::UnexpectedEof);
200 }
201}