use crate::dat::DatPayload;
use crate::dat_key::{DatKeySet, DatKeySetActive, Kid};
use crate::error::DatError;
use crate::util::{now_unix_timestamp, to_kid};
use itertools::Itertools;
use std::sync::RwLock;
pub struct DatKeyStore<T: Kid> {
keys: RwLock<Vec<DatKeySet<T>>>,
issue_key: RwLock<Option<DatKeySetActive<T>>>,
verify_keys: RwLock<Vec<DatKeySetActive<T>>>,
}
impl <T: Kid> DatKeyStore<T> {
pub fn new() -> Self {
DatKeyStore {
keys: RwLock::new(vec![]),
issue_key: RwLock::new(None),
verify_keys: RwLock::new(vec![]),
}
}
pub fn verify(&self, dat: String) -> Result<DatPayload, DatError> {
let data = DatKeySetActive::<T>::split(&dat)?;
let kid = to_kid::<T>(data[0])?;
if let Some(ks) = self.verify_keys.read().unwrap().iter().find(|e| e.kid == kid) {
ks.verify_by_split_unsafe(data)
} else {
Err(DatError::DatError(format!("kid not found: {kid}")))
}
}
pub fn clear_key(&self) {
*self.keys.write().unwrap() = vec![];
}
pub fn add_key(&self, key: DatKeySet<T>) -> Result<(), DatError> {
self.add_keys(vec![key], false)
}
pub fn add_keys_by_format(&self, format: String, clear: bool) -> Result<(), DatError> {
let keys = format
.lines()
.filter(|e| !e.is_empty())
.map(|e| DatKeySet::parse(e)).collect::<Result<Vec<DatKeySet<T>>, DatError>>()?;
self.add_keys(keys, clear)
}
pub fn add_keys(&self, keys: Vec<DatKeySet<T>>, clear: bool) -> Result<(), DatError> {
let mut p_list = if clear { vec![] } else { self.keys.read().unwrap().clone() };
let now = now_unix_timestamp()?;
keys.into_iter().for_each(|key| {
if !p_list.contains(&key) {
p_list.push(key);
}
});
let p_list = p_list.into_iter()
.filter(|key| key.get_key_expire() >= now)
.sorted_by(|a, b| a.issue_begin.cmp(&b.issue_begin))
.collect::<Vec<DatKeySet<T>>>();
*self.keys.write().unwrap() = p_list;
Ok(())
}
pub fn format(&self, verify_only: bool) -> String {
self.keys.read().unwrap().iter().map(|key| key.format(verify_only).unwrap()).join("\n")
}
pub fn get_keys(&self) -> Vec<DatKeySet<T>> {
self.keys.read().unwrap().clone()
}
pub fn apply(&self) -> Result<(), DatError> {
let now = now_unix_timestamp()?;
let list = self.keys.read().unwrap().clone()
.into_iter().filter(|e| (e.issue_end + e.token_ttl) >= now)
.collect::<Vec<DatKeySet<T>>>();
let issue_key_set: Option<DatKeySetActive<T>> = list.iter()
.rev()
.find(|e| e.issue_begin < now)
.map(|e| e.clone().into_active())
.transpose()?;
let verify_key_set_list: Vec<DatKeySetActive<T>> = list.into_iter()
.map(|e| e.into_active())
.collect::<Result<Vec<DatKeySetActive<T>>, DatError>>()?;
*self.issue_key.write().unwrap() = issue_key_set;
*self.verify_keys.write().unwrap() = verify_key_set_list;
Ok(())
}
}