blob: 5c42b59f7eced7ef2a1484903d0acff202ad43af [file]
use crate::http::jwt::COMPONENT;
use crate::streaming::utils::file;
use crate::{
http::jwt::json_web_token::RevokedAccessToken, streaming::persistence::persister::PersisterKind,
};
use ahash::AHashMap;
use anyhow::Context;
use bytes::{BufMut, BytesMut};
use error_set::ErrContext;
use iggy::error::IggyError;
use std::sync::Arc;
use tokio::io::AsyncReadExt;
use tracing::{error, info};
#[derive(Debug)]
pub struct TokenStorage {
persister: Arc<PersisterKind>,
path: String,
}
impl TokenStorage {
pub fn new(persister: Arc<PersisterKind>, path: &str) -> Self {
Self {
persister,
path: path.to_owned(),
}
}
pub async fn load_all_revoked_access_tokens(
&self,
) -> Result<Vec<RevokedAccessToken>, IggyError> {
let file = file::open(&self.path).await;
if file.is_err() {
info!("No revoked access tokens found to load.");
return Ok(vec![]);
}
info!("Loading revoked access tokens from: {}", self.path);
let mut file = file.map_err(|error| {
error!("Cannot open revoked access tokens file: {error}");
IggyError::CannotReadFile
})?;
let file_size = file
.metadata()
.await
.with_error_context(|error| {
format!(
"{COMPONENT} (error: {error}) - failed to read file metadata, path: {}",
self.path
)
})
.map_err(|_| IggyError::CannotReadFileMetadata)?
.len() as usize;
let mut buffer = BytesMut::with_capacity(file_size);
buffer.put_bytes(0, file_size);
file.read_exact(&mut buffer)
.await
.with_error_context(|error| {
format!(
"{COMPONENT} (error: {error}) - failed to read file into buffer, path: {}",
self.path
)
})
.map_err(|_| IggyError::CannotReadFile)?;
let tokens: AHashMap<String, u64> = bincode::deserialize(&buffer)
.with_context(|| "Failed to deserialize revoked access tokens")
.map_err(|_| IggyError::CannotDeserializeResource)?;
let tokens = tokens
.into_iter()
.map(|(id, expiry)| RevokedAccessToken { id, expiry })
.collect::<Vec<RevokedAccessToken>>();
info!("Loaded {} revoked access tokens", tokens.len());
Ok(tokens)
}
pub async fn save_revoked_access_token(
&self,
token: &RevokedAccessToken,
) -> Result<(), IggyError> {
let tokens = self.load_all_revoked_access_tokens().await?;
let mut map = tokens
.into_iter()
.map(|token| (token.id, token.expiry))
.collect::<AHashMap<_, _>>();
map.insert(token.id.to_owned(), token.expiry);
let bytes = bincode::serialize(&map)
.with_context(|| "Failed to serialize revoked access tokens")
.map_err(|_| IggyError::CannotSerializeResource)?;
self.persister
.overwrite(&self.path, &bytes)
.await
.with_error_context(|error| {
format!(
"{COMPONENT} (error: {error}) - failed to overwrite file, path: {}",
self.path
)
})?;
Ok(())
}
pub async fn delete_revoked_access_tokens(&self, id: &[String]) -> Result<(), IggyError> {
let tokens = self
.load_all_revoked_access_tokens()
.await
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - failed to load revoked access tokens")
})?;
if tokens.is_empty() {
return Ok(());
}
let mut map = tokens
.into_iter()
.map(|token| (token.id, token.expiry))
.collect::<AHashMap<_, _>>();
for id in id {
map.remove(id);
}
let bytes = bincode::serialize(&map)
.with_context(|| "Failed to serialize revoked access tokens")
.map_err(|_| IggyError::CannotSerializeResource)?;
self.persister
.overwrite(&self.path, &bytes)
.await
.with_error_context(|error| {
format!(
"{COMPONENT} (error: {error}) - failed to overwrite file, path: {}",
self.path
)
})?;
Ok(())
}
}