dat 0.4.0

DAT - Data Access Token
Documentation
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(())
    }
}