use crate::Parameter;
#[derive(Default)]
pub struct AuthBuilder {
user: String,
version: String,
salt: Option<String>,
client_name: Option<String>,
}
impl AuthBuilder {
pub fn new(user: impl Into<String>, version: impl Into<String>) -> Self {
Self {
user: user.into(),
version: version.into(),
..Default::default()
}
}
pub fn client_name(mut self, name: &str) -> Self {
self.client_name = Some(String::from(name));
self
}
pub(crate) fn _salt(mut self, salt: impl Into<String>) -> Self {
self.salt = Some(salt.into());
self
}
pub fn hashed(self, password: &str) -> Auth {
let (hash, salt) = if let Some(salt) = self.salt {
(Auth::hash_with_salt(password, &salt), salt)
} else {
Auth::hash(password)
};
Auth {
user: self.user,
version: self.version,
client_name: self.client_name.unwrap_or(String::from("submarine-lib")),
hash,
salt,
}
}
}
#[derive(Clone, Debug)]
pub struct Auth {
pub user: String,
pub version: String,
pub client_name: String,
pub hash: String,
pub salt: String,
}
impl Auth {
fn hash(password: &str) -> (String, String) {
let salt = Self::create_salt(24);
let hash = md5::compute(password.to_owned() + &salt);
(format!("{:x}", hash), salt)
}
fn hash_with_salt(password: impl Into<String>, salt: &str) -> String {
let hash = md5::compute(password.into() + salt);
format!("{:x}", hash)
}
fn create_salt(size: usize) -> String {
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use std::iter;
let mut rng = thread_rng();
iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
.map(char::from)
.take(size)
.collect()
}
pub(crate) fn add_parameter(&self, paras: &mut Parameter) {
paras.push("u", &self.user);
paras.push("v", &self.version);
paras.push("c", &self.client_name);
paras.push("t", &self.hash);
paras.push("s", &self.salt);
paras.push("f", "json");
}
}