socks5_impl/protocol/handshake/password_method/
request.rs1#[cfg(feature = "tokio")]
2use crate::protocol::AsyncStreamOperation;
3use crate::protocol::{StreamOperation, UserKey};
4#[cfg(feature = "tokio")]
5use tokio::io::{AsyncRead, AsyncReadExt};
6
7#[derive(Clone, Debug)]
18pub struct Request {
19 pub user_key: UserKey,
20}
21
22impl Request {
23 pub fn new(username: &str, password: &str) -> Self {
24 let user_key = UserKey::new(username, password);
25 Self { user_key }
26 }
27}
28
29impl StreamOperation for Request {
30 fn retrieve_from_stream<R: std::io::Read>(r: &mut R) -> std::io::Result<Self> {
31 let mut ver = [0; 1];
32 r.read_exact(&mut ver)?;
33 let ver = ver[0];
34
35 if ver != super::SUBNEGOTIATION_VERSION {
36 let err = format!("Unsupported sub-negotiation version {ver:#x}");
37 return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, err));
38 }
39
40 let mut ulen = [0; 1];
41 r.read_exact(&mut ulen)?;
42 let ulen = ulen[0];
43 let mut buf = vec![0; ulen as usize + 1];
44 r.read_exact(&mut buf)?;
45
46 let plen = buf[ulen as usize];
47 buf.truncate(ulen as usize);
48 let username = String::from_utf8(buf).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
49
50 let mut password = vec![0; plen as usize];
51 r.read_exact(&mut password)?;
52 let pwd = String::from_utf8(password).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
53
54 let user_key = UserKey::new(username, pwd);
55 Ok(Self { user_key })
56 }
57
58 fn write_to_buf<B: bytes::BufMut>(&self, buf: &mut B) {
59 buf.put_u8(super::SUBNEGOTIATION_VERSION);
60
61 let username = self.user_key.username_arr();
62 buf.put_u8(username.len() as u8);
63 buf.put_slice(&username);
64
65 let password = self.user_key.password_arr();
66 buf.put_u8(password.len() as u8);
67 buf.put_slice(&password);
68 }
69
70 fn len(&self) -> usize {
71 3 + self.user_key.username_arr().len() + self.user_key.password_arr().len()
72 }
73}
74
75#[cfg(feature = "tokio")]
76#[async_trait::async_trait]
77impl AsyncStreamOperation for Request {
78 async fn retrieve_from_async_stream<R>(r: &mut R) -> std::io::Result<Self>
79 where
80 R: AsyncRead + Unpin + Send + ?Sized,
81 {
82 let ver = r.read_u8().await?;
83
84 if ver != super::SUBNEGOTIATION_VERSION {
85 let err = format!("Unsupported sub-negotiation version {ver:#x}");
86 return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, err));
87 }
88
89 let ulen = r.read_u8().await?;
90 let mut buf = vec![0; ulen as usize + 1];
91 r.read_exact(&mut buf).await?;
92
93 let plen = buf[ulen as usize];
94 buf.truncate(ulen as usize);
95 let username = String::from_utf8(buf).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
96
97 let mut password = vec![0; plen as usize];
98 r.read_exact(&mut password).await?;
99 let pwd = String::from_utf8(password).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
100
101 let user_key = UserKey::new(username, pwd);
102 Ok(Self { user_key })
103 }
104}