kojacoord_protocol/versions/v1_7_10/login/
mod.rs1use bytes::{Buf, BufMut, Bytes, BytesMut};
2
3use crate::codec::{Decode, Encode, PacketId};
4use crate::error::ProtocolError;
5use crate::types::VarInt;
6
7pub use clientbound::{
8 ClientboundEncryptionRequest, ClientboundLoginDisconnect, ClientboundLoginSuccess,
9};
10pub use serverbound::{ServerboundEncryptionResponse, ServerboundLoginStart};
11
12mod clientbound {
13 use super::*;
14
15 #[derive(Debug, Clone, PartialEq)]
16 pub struct ClientboundLoginDisconnect {
17 pub reason: String,
18 }
19
20 impl PacketId for ClientboundLoginDisconnect {
21 fn packet_id(_ver: u32) -> u8 {
22 0x00
23 }
24 }
25
26 impl Encode for ClientboundLoginDisconnect {
27 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
28 let bytes = self.reason.as_bytes();
29 VarInt(bytes.len() as i32).encode(dst)?;
30 dst.put_slice(bytes);
31 Ok(())
32 }
33 }
34
35 impl Decode for ClientboundLoginDisconnect {
36 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
37 let len = VarInt::decode(src)?.0 as usize;
38 if src.remaining() < len {
39 return Err(ProtocolError::Io(std::io::Error::new(
40 std::io::ErrorKind::UnexpectedEof,
41 "Missing bytes for ClientboundLoginDisconnect reason",
42 )));
43 }
44 let mut buf = vec![0u8; len];
45 src.copy_to_slice(&mut buf);
46 let reason = String::from_utf8(buf).map_err(|_| {
47 ProtocolError::Io(std::io::Error::new(
48 std::io::ErrorKind::InvalidData,
49 "Invalid UTF-8 in ClientboundLoginDisconnect reason",
50 ))
51 })?;
52 Ok(Self { reason })
53 }
54 }
55
56 #[derive(Debug, Clone, PartialEq)]
57 pub struct ClientboundEncryptionRequest {
58 pub server_id: String,
59 pub public_key: Vec<u8>,
60 pub verify_token: Vec<u8>,
61 }
62
63 impl PacketId for ClientboundEncryptionRequest {
64 fn packet_id(_ver: u32) -> u8 {
65 0x01
66 }
67 }
68
69 impl Encode for ClientboundEncryptionRequest {
70 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
71 let id_bytes = self.server_id.as_bytes();
72 VarInt(id_bytes.len() as i32).encode(dst)?;
73 dst.put_slice(id_bytes);
74
75 VarInt(self.public_key.len() as i32).encode(dst)?;
76 dst.put_slice(&self.public_key);
77
78 VarInt(self.verify_token.len() as i32).encode(dst)?;
79 dst.put_slice(&self.verify_token);
80
81 Ok(())
82 }
83 }
84
85 impl Decode for ClientboundEncryptionRequest {
86 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
87 let id_len = VarInt::decode(src)?.0 as usize;
88 if src.remaining() < id_len {
89 return Err(ProtocolError::Io(std::io::Error::new(
90 std::io::ErrorKind::UnexpectedEof,
91 "Missing bytes for ClientboundEncryptionRequest server_id",
92 )));
93 }
94 let mut id_bytes = vec![0u8; id_len];
95 src.copy_to_slice(&mut id_bytes);
96 let server_id = String::from_utf8(id_bytes).map_err(|_| {
97 ProtocolError::Io(std::io::Error::new(
98 std::io::ErrorKind::InvalidData,
99 "Invalid UTF-8 in ClientboundEncryptionRequest server_id",
100 ))
101 })?;
102
103 let key_len = VarInt::decode(src)?.0 as usize;
104 if src.remaining() < key_len {
105 return Err(ProtocolError::Io(std::io::Error::new(
106 std::io::ErrorKind::UnexpectedEof,
107 "Missing bytes for ClientboundEncryptionRequest public_key",
108 )));
109 }
110 let mut public_key = vec![0u8; key_len];
111 src.copy_to_slice(&mut public_key);
112
113 let tok_len = VarInt::decode(src)?.0 as usize;
114 if src.remaining() < tok_len {
115 return Err(ProtocolError::Io(std::io::Error::new(
116 std::io::ErrorKind::UnexpectedEof,
117 "Missing bytes for ClientboundEncryptionRequest verify_token",
118 )));
119 }
120 let mut verify_token = vec![0u8; tok_len];
121 src.copy_to_slice(&mut verify_token);
122
123 Ok(Self {
124 server_id,
125 public_key,
126 verify_token,
127 })
128 }
129 }
130
131 #[derive(Debug, Clone, PartialEq)]
132 pub struct ClientboundLoginSuccess {
133 pub uuid: uuid::Uuid,
134 pub username: String,
135 }
136
137 impl PacketId for ClientboundLoginSuccess {
138 fn packet_id(_ver: u32) -> u8 {
139 0x02
140 }
141 }
142
143 impl Encode for ClientboundLoginSuccess {
144 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
145 let uuid_str = self.uuid.hyphenated().to_string();
146 let uuid_bytes = uuid_str.as_bytes();
147 VarInt(uuid_bytes.len() as i32).encode(dst)?;
148 dst.put_slice(uuid_bytes);
149
150 let name_bytes = self.username.as_bytes();
151 VarInt(name_bytes.len() as i32).encode(dst)?;
152 dst.put_slice(name_bytes);
153
154 Ok(())
155 }
156 }
157
158 impl Decode for ClientboundLoginSuccess {
159 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
160 let uuid_len = VarInt::decode(src)?.0 as usize;
161 if src.remaining() < uuid_len {
162 return Err(ProtocolError::Io(std::io::Error::new(
163 std::io::ErrorKind::UnexpectedEof,
164 "Missing bytes for ClientboundLoginSuccess uuid",
165 )));
166 }
167 let mut uuid_bytes = vec![0u8; uuid_len];
168 src.copy_to_slice(&mut uuid_bytes);
169 let uuid_str = String::from_utf8(uuid_bytes).map_err(|_| {
170 ProtocolError::Io(std::io::Error::new(
171 std::io::ErrorKind::InvalidData,
172 "Invalid UTF-8 in ClientboundLoginSuccess uuid",
173 ))
174 })?;
175 let uuid = uuid::Uuid::parse_str(&uuid_str).map_err(|_| {
176 ProtocolError::Io(std::io::Error::new(
177 std::io::ErrorKind::InvalidData,
178 "Invalid UUID in ClientboundLoginSuccess",
179 ))
180 })?;
181
182 let name_len = VarInt::decode(src)?.0 as usize;
183 if src.remaining() < name_len {
184 return Err(ProtocolError::Io(std::io::Error::new(
185 std::io::ErrorKind::UnexpectedEof,
186 "Missing bytes for ClientboundLoginSuccess username",
187 )));
188 }
189 let mut name_bytes = vec![0u8; name_len];
190 src.copy_to_slice(&mut name_bytes);
191 let username = String::from_utf8(name_bytes).map_err(|_| {
192 ProtocolError::Io(std::io::Error::new(
193 std::io::ErrorKind::InvalidData,
194 "Invalid UTF-8 in ClientboundLoginSuccess username",
195 ))
196 })?;
197
198 Ok(Self { uuid, username })
199 }
200 }
201}
202
203mod serverbound {
204 use super::*;
205
206 #[derive(Debug, Clone, PartialEq)]
207 pub struct ServerboundLoginStart {
208 pub username: String,
209 }
210
211 impl PacketId for ServerboundLoginStart {
212 fn packet_id(_ver: u32) -> u8 {
213 0x00
214 }
215 }
216
217 impl Encode for ServerboundLoginStart {
218 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
219 let bytes = self.username.as_bytes();
220 VarInt(bytes.len() as i32).encode(dst)?;
221 dst.put_slice(bytes);
222 Ok(())
223 }
224 }
225
226 impl Decode for ServerboundLoginStart {
227 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
228 let len = VarInt::decode(src)?.0 as usize;
229 if src.remaining() < len {
230 return Err(ProtocolError::Io(std::io::Error::new(
231 std::io::ErrorKind::UnexpectedEof,
232 "Missing bytes for ServerboundLoginStart username",
233 )));
234 }
235 let mut buf = vec![0u8; len];
236 src.copy_to_slice(&mut buf);
237 let username = String::from_utf8(buf).map_err(|_| {
238 ProtocolError::Io(std::io::Error::new(
239 std::io::ErrorKind::InvalidData,
240 "Invalid UTF-8 in ServerboundLoginStart username",
241 ))
242 })?;
243 Ok(Self { username })
244 }
245 }
246
247 #[derive(Debug, Clone, PartialEq)]
248 pub struct ServerboundEncryptionResponse {
249 pub shared_secret: Vec<u8>,
250
251 pub verify_token: Vec<u8>,
252 }
253
254 impl PacketId for ServerboundEncryptionResponse {
255 fn packet_id(_ver: u32) -> u8 {
256 0x01
257 }
258 }
259
260 impl Encode for ServerboundEncryptionResponse {
261 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
262 VarInt(self.shared_secret.len() as i32).encode(dst)?;
263 dst.put_slice(&self.shared_secret);
264
265 VarInt(self.verify_token.len() as i32).encode(dst)?;
266 dst.put_slice(&self.verify_token);
267
268 Ok(())
269 }
270 }
271
272 impl Decode for ServerboundEncryptionResponse {
273 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
274 let ss_len = VarInt::decode(src)?.0 as usize;
275 if src.remaining() < ss_len {
276 return Err(ProtocolError::Io(std::io::Error::new(
277 std::io::ErrorKind::UnexpectedEof,
278 "Missing bytes for ServerboundEncryptionResponse shared_secret",
279 )));
280 }
281 let mut shared_secret = vec![0u8; ss_len];
282 src.copy_to_slice(&mut shared_secret);
283
284 let vt_len = VarInt::decode(src)?.0 as usize;
285 if src.remaining() < vt_len {
286 return Err(ProtocolError::Io(std::io::Error::new(
287 std::io::ErrorKind::UnexpectedEof,
288 "Missing bytes for ServerboundEncryptionResponse verify_token",
289 )));
290 }
291 let mut verify_token = vec![0u8; vt_len];
292 src.copy_to_slice(&mut verify_token);
293
294 Ok(Self {
295 shared_secret,
296 verify_token,
297 })
298 }
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305
306 #[test]
307 fn login_disconnect_roundtrip() {
308 let p = ClientboundLoginDisconnect {
309 reason: r#"{"text":"You are banned."}"#.to_string(),
310 };
311 let mut buf = BytesMut::new();
312 p.encode(&mut buf).unwrap();
313 let mut b = buf.freeze();
314 assert_eq!(ClientboundLoginDisconnect::decode(&mut b).unwrap(), p);
315 }
316
317 #[test]
318 fn encryption_request_roundtrip() {
319 let p = ClientboundEncryptionRequest {
320 server_id: String::new(),
321 public_key: vec![0xDE, 0xAD, 0xBE, 0xEF],
322 verify_token: vec![0x01, 0x02, 0x03, 0x04],
323 };
324 let mut buf = BytesMut::new();
325 p.encode(&mut buf).unwrap();
326 let mut b = buf.freeze();
327 assert_eq!(ClientboundEncryptionRequest::decode(&mut b).unwrap(), p);
328 }
329
330 #[test]
331 fn login_success_roundtrip() {
332 let p = ClientboundLoginSuccess {
333 uuid: uuid::Uuid::new_v4(),
334 username: "Steve".to_string(),
335 };
336 let mut buf = BytesMut::new();
337 p.encode(&mut buf).unwrap();
338 let mut b = buf.freeze();
339 let d = ClientboundLoginSuccess::decode(&mut b).unwrap();
340 assert_eq!(d.uuid, p.uuid);
341 assert_eq!(d.username, p.username);
342 }
343
344 #[test]
345 fn login_start_roundtrip() {
346 let p = ServerboundLoginStart {
347 username: "Steve".to_string(),
348 };
349 let mut buf = BytesMut::new();
350 p.encode(&mut buf).unwrap();
351 let mut b = buf.freeze();
352 assert_eq!(ServerboundLoginStart::decode(&mut b).unwrap(), p);
353 }
354
355 #[test]
356 fn encryption_response_roundtrip() {
357 let p = ServerboundEncryptionResponse {
358 shared_secret: vec![0u8; 128],
359 verify_token: vec![0xAA; 128],
360 };
361 let mut buf = BytesMut::new();
362 p.encode(&mut buf).unwrap();
363 let mut b = buf.freeze();
364 assert_eq!(ServerboundEncryptionResponse::decode(&mut b).unwrap(), p);
365 }
366
367 #[test]
368 fn packet_ids_are_correct() {
369 assert_eq!(ClientboundLoginDisconnect::packet_id(5), 0x00);
370 assert_eq!(ClientboundEncryptionRequest::packet_id(5), 0x01);
371 assert_eq!(ClientboundLoginSuccess::packet_id(5), 0x02);
372
373 assert_eq!(ServerboundLoginStart::packet_id(5), 0x00);
374 assert_eq!(ServerboundEncryptionResponse::packet_id(5), 0x01);
375 }
376}