keyplace 0.1.1

Keyplace - server assisted key derivation for humans
Documentation
use toboggan_kv::{Toboggan, Tree};

use crate::{keys::private::AgentKey, AgentId, Error};

pub struct KeyManager<S: Toboggan> {
    _store: S,
    agent_keys: S::Tree,
    agent_id_config: S::Tree,
}

impl<S> KeyManager<S>
where
    S: Toboggan,
{
    pub fn new(store: S) -> Result<Self, Error> {
        Ok(Self {
            agent_keys: store.open_tree("agent_keys")?,
            agent_id_config: store.open_tree("agent_id_config")?,
            _store: store,
        })
    }
    pub fn list_agents(&self) -> Result<Vec<AgentId>, Error> {
        Ok(self
            .agent_keys
            .iter()
            .map(|kv| {
                let kv = kv.unwrap();
                let agentkey: AgentKey = bincode::deserialize(&kv.1).unwrap();
                AgentId {
                    pubkey: agentkey.pubkey(),
                }
            })
            .collect())
    }
    pub fn get_agent_key(&self, agent_id: &AgentId) -> Result<Option<AgentKey>, Error> {
        match self.agent_keys.get(&agent_id.pubkey)? {
            Some(ivec) => {
                let agentkey: AgentKey = bincode::deserialize(&ivec)?;
                Ok(Some(agentkey))
            }
            None => Ok(None),
        }
    }
    pub fn put_agent_key(&self, agentkey: AgentKey) -> Result<(), Error> {
        let key_ser: Vec<u8> = bincode::serialize(&agentkey).unwrap();

        let agent_id = agentkey.id();
        self.agent_keys.insert(&agent_id.pubkey[..], key_ser)?;
        self.agent_keys.flush()?;

        Ok(())
    }
    pub fn remove_all_agent_keys(&self) -> Result<(), Error> {
        self.agent_keys.clear()?;
        Ok(())
    }

    pub fn set_current_agent(&self, id: AgentId) -> Result<(), Error> {
        let id_ser: Vec<u8> = bincode::serialize(&id).unwrap();
        self.agent_id_config.insert("current", id_ser)?;
        Ok(())
    }
    pub fn current_agent_key(&self) -> Result<Option<AgentKey>, Error> {
        match self.agent_id_config.get("current")? {
            Some(value) => {
                let id: AgentId = bincode::deserialize(&value[..])?;

                match self.get_agent_key(&id)? {
                    Some(a) => Ok(Some(a)),
                    None => Err(Error::InvalidReferent),
                }
            }
            None => Ok(None),
        }
    }
}

impl<T> Default for KeyManager<T>
where
    T: Toboggan + Default,
{
    fn default() -> Self {
        KeyManager::new(Default::default())
            .expect("should not fail for store which implements default")
    }
}

#[cfg(test)]
mod test {
    use toboggan_kv::adapter::BTreeAdapter;

    use crate::{AgentKey, KeyManager};

    #[test]
    fn init() -> Result<(), std::io::Error> {
        let keymanager = KeyManager::new(BTreeAdapter::new())?;

        let agentkey = AgentKey::create(None);
        let id = agentkey.id();
        keymanager.put_agent_key(agentkey)?;
        keymanager.set_current_agent(id.clone())?;

        assert_eq!(
            keymanager
                .current_agent_key()
                .expect("is good")
                .expect("is some")
                .id(),
            id
        );

        Ok(())
    }
}