1use crate::cursor::{Cursor, CursorMut};
7use crate::wrappers::Hide;
8use crate::{CursorError, Error};
9
10pub const HASH_LEN: usize = 64;
12pub const HASH_KEY: &str = "Half-Life";
14pub const HASH_PERSONAL: &str = "Freeman";
16
17#[derive(Clone, Debug, PartialEq)]
19pub struct AdminChallenge;
20
21impl AdminChallenge {
22 pub const HEADER: &'static [u8] = b"adminchallenge";
24
25 pub fn decode(src: &[u8]) -> Result<Self, Error> {
27 if src == Self::HEADER {
28 Ok(Self)
29 } else {
30 Err(CursorError::Expect)?
31 }
32 }
33
34 pub fn encode(&self, buf: &mut [u8]) -> Result<usize, Error> {
36 Ok(CursorMut::new(buf).put_bytes(Self::HEADER)?.pos())
37 }
38}
39
40#[derive(Clone, Debug, PartialEq)]
42pub struct AdminCommand<'a> {
43 pub master_challenge: u32,
45 pub hash: Hide<&'a [u8]>,
47 pub command: &'a str,
49}
50
51impl<'a> AdminCommand<'a> {
52 pub const HEADER: &'static [u8] = b"admin";
54
55 pub fn new(master_challenge: u32, hash: &'a [u8], command: &'a str) -> Self {
57 Self {
58 master_challenge,
59 hash: Hide(hash),
60 command,
61 }
62 }
63
64 pub fn decode_with_hash_len(hash_len: usize, src: &'a [u8]) -> Result<Self, Error> {
66 let mut cur = Cursor::new(src);
67 cur.expect(Self::HEADER)?;
68 let master_challenge = cur.get_u32_le()?;
69 let hash = Hide(cur.get_bytes(hash_len)?);
70 let command = cur.get_str(cur.remaining())?;
71 cur.expect_empty()?;
72 Ok(Self {
73 master_challenge,
74 hash,
75 command,
76 })
77 }
78
79 #[inline]
81 pub fn decode(src: &'a [u8]) -> Result<Self, Error> {
82 Self::decode_with_hash_len(HASH_LEN, src)
83 }
84
85 pub fn encode(&self, buf: &mut [u8]) -> Result<usize, Error> {
87 Ok(CursorMut::new(buf)
88 .put_bytes(Self::HEADER)?
89 .put_u32_le(self.master_challenge)?
90 .put_bytes(&self.hash)?
91 .put_str(self.command)?
92 .pos())
93 }
94}
95
96#[derive(Clone, Debug, PartialEq)]
98pub enum Packet<'a> {
99 AdminChallenge,
101 AdminCommand(AdminCommand<'a>),
103}
104
105impl<'a> Packet<'a> {
106 pub fn decode(hash_len: usize, src: &'a [u8]) -> Result<Option<Self>, Error> {
108 if src.starts_with(AdminChallenge::HEADER) {
109 AdminChallenge::decode(src).map(|_| Self::AdminChallenge)
110 } else if src.starts_with(AdminCommand::HEADER) {
111 AdminCommand::decode_with_hash_len(hash_len, src).map(Self::AdminCommand)
112 } else {
113 return Ok(None);
114 }
115 .map(Some)
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn admin_challenge() {
125 let p = AdminChallenge;
126 let mut buf = [0; 512];
127 let n = p.encode(&mut buf).unwrap();
128 assert_eq!(
129 Packet::decode(HASH_LEN, &buf[..n]),
130 Ok(Some(Packet::AdminChallenge))
131 );
132 }
133
134 #[test]
135 fn admin_command() {
136 let p = AdminCommand::new(0x12345678, &[1; HASH_LEN], "foo bar baz");
137 let mut buf = [0; 512];
138 let n = p.encode(&mut buf).unwrap();
139 assert_eq!(
140 Packet::decode(HASH_LEN, &buf[..n]),
141 Ok(Some(Packet::AdminCommand(p)))
142 );
143 }
144}