musikquadrupled/src/token.rs

74 lines
2.1 KiB
Rust

use rand::Rng;
use scc::HashSet;
use std::borrow::Cow;
use std::fmt::Write;
use std::path::Path;
use std::sync::Arc;
use crate::error::AppError;
fn hash_string(data: &[u8]) -> Result<String, argon2::Error> {
argon2::hash_encoded(data, "11111111".as_bytes(), &argon2::Config::default())
}
#[derive(Debug, Clone)]
pub(crate) struct Tokens {
hashed: Arc<HashSet<Cow<'static, str>>>,
raw_contents: &'static str,
}
impl Tokens {
pub async fn read(path: impl AsRef<Path>) -> Result<Self, AppError> {
let this = Self {
hashed: Arc::new(HashSet::new()),
raw_contents: Box::leak(tokio::fs::read_to_string(path).await?.into_boxed_str()),
};
for token in this.raw_contents.lines() {
let token = token.trim();
if !token.is_empty() {
this.hashed
.insert_async(Cow::Borrowed(token))
.await
.expect("the set will be empty");
}
}
Ok(this)
}
pub async fn write(&self, path: impl AsRef<Path>) -> Result<(), AppError> {
let mut contents = String::new();
self.hashed
.for_each_async(|hash| {
writeln!(&mut contents, "{hash}").expect("if this fails then too bad")
})
.await;
tokio::fs::write(path, contents).await.map_err(Into::into)
}
pub async fn generate(&self) -> Result<String, AppError> {
let token = rand::thread_rng()
.sample_iter(rand::distributions::Alphanumeric)
.take(30)
.map(|c| c as char)
.collect::<String>();
let token_hash = hash_string(token.as_bytes())?;
self.hashed.insert_async(token_hash.into()).await?;
Ok(token)
}
pub async fn verify(&self, token: impl AsRef<str>) -> Result<bool, AppError> {
let token = token.as_ref();
let token_hash = hash_string(token.as_bytes())?;
Ok(self.hashed.contains_async(&Cow::Owned(token_hash)).await)
}
pub async fn revoke_all(&self) {
self.hashed.clear_async().await;
}
}