tarantool_rs/codec/request/
auth.rs1use std::{cmp::min, io::Write};
4
5use sha1::{Digest, Sha1};
6
7use super::Request;
8use crate::{
9 codec::{
10 consts::{keys, RequestType},
11 utils::write_kv_str,
12 },
13 errors::EncodingError,
14};
15
16#[derive(Clone, Debug)]
17pub(crate) struct Auth<'a> {
18 pub user_name: &'a str,
19 pub scramble: Vec<u8>,
20}
21
22impl<'a> Auth<'a> {
23 pub(crate) fn new(user: &'a str, password: Option<&'a str>, salt: &'a [u8]) -> Self {
24 Self {
25 user_name: user,
26 scramble: prepare_scramble(password, salt),
27 }
28 }
29}
30
31impl<'a> Request for Auth<'a> {
32 fn request_type() -> RequestType
33 where
34 Self: Sized,
35 {
36 RequestType::Auth
37 }
38
39 fn encode(&self, mut buf: &mut dyn Write) -> Result<(), EncodingError> {
41 rmp::encode::write_map_len(&mut buf, 2)?;
42 write_kv_str(&mut buf, keys::USER_NAME, self.user_name)?;
43 rmp::encode::write_pfix(&mut buf, keys::TUPLE)?;
44 rmp::encode::write_array_len(&mut buf, 2)?;
45 rmp::encode::write_str(&mut buf, "chap-sha1")?;
46 rmp::encode::write_bin(&mut buf, &self.scramble)?;
47 Ok(())
48 }
49}
50
51macro_rules! sha1 {
52 ($($data:expr),+) => {
53 {
54 let mut hasher = Sha1::new();
55 $( hasher.update($data); )+
56 hasher.finalize().to_vec()
57 }
58 }
59}
60
61fn prepare_scramble(password: Option<&str>, salt: &[u8]) -> Vec<u8> {
62 let password = password.unwrap_or("");
63 let mut step_1 = sha1!(password.as_bytes());
64 let step_2 = sha1!(&step_1);
65 let step_3 = sha1!(&salt[0..min(salt.len(), 20)], &step_2);
66 step_1.iter_mut().zip(step_3).for_each(|(l, r)| *l ^= r);
68 step_1
69}