tuf 0.2.0

Library for The Update Framework (TUF)
Documentation
use chrono::DateTime;
use chrono::offset::Utc;
use data_encoding::BASE64URL;
use std::collections::{HashMap, HashSet};

use Result;
use crypto;
use error::Error;
use metadata;

#[derive(Debug, Serialize, Deserialize)]
pub struct RootMetadata {
    #[serde(rename = "type")]
    typ: metadata::Role,
    version: u32,
    consistent_snapshot: bool,
    expires: DateTime<Utc>,
    keys: HashMap<crypto::KeyId, crypto::PublicKey>,
    roles: HashMap<metadata::Role, metadata::RoleDefinition>,
}

impl RootMetadata {
    pub fn from(meta: &metadata::RootMetadata) -> Result<Self> {
        let mut roles = HashMap::new();
        let _ = roles.insert(metadata::Role::Root, meta.root().clone());
        let _ = roles.insert(metadata::Role::Snapshot, meta.snapshot().clone());
        let _ = roles.insert(metadata::Role::Targets, meta.targets().clone());
        let _ = roles.insert(metadata::Role::Timestamp, meta.timestamp().clone());

        Ok(RootMetadata {
            typ: metadata::Role::Root,
            version: meta.version(),
            expires: meta.expires().clone(),
            consistent_snapshot: meta.consistent_snapshot(),
            keys: meta.keys().clone(),
            roles: roles,
        })
    }

    pub fn try_into(mut self) -> Result<metadata::RootMetadata> {
        if self.typ != metadata::Role::Root {
            return Err(Error::Encoding(format!(
                "Attempted to decode root metdata labeled as {:?}",
                self.typ
            )));
        }

        let mut keys = Vec::new();
        for (key_id, value) in self.keys.drain() {
            if &key_id != value.key_id() {
                warn!(
                    "Received key with ID {:?} but calculated it's value as {:?}. \
                       Refusing to add it to the set of trusted keys.",
                    key_id,
                    value.key_id()
                );
            } else {
                debug!(
                    "Found key with good ID {:?}. Adding it to the set of trusted keys.",
                    key_id
                );
                keys.push(value);
            }
        }

        let root = self.roles.remove(&metadata::Role::Root).ok_or_else(|| {
            Error::Encoding("Missing root role definition".into())
        })?;
        let snapshot = self.roles.remove(&metadata::Role::Snapshot).ok_or_else(
            || {
                Error::Encoding("Missing snapshot role definition".into())
            },
        )?;
        let targets = self.roles.remove(&metadata::Role::Targets).ok_or_else(|| {
            Error::Encoding("Missing targets role definition".into())
        })?;
        let timestamp = self.roles.remove(&metadata::Role::Timestamp).ok_or_else(
            || {
                Error::Encoding("Missing timestamp role definition".into())
            },
        )?;

        metadata::RootMetadata::new(
            self.version,
            self.expires,
            self.consistent_snapshot,
            keys,
            root,
            snapshot,
            targets,
            timestamp,
        )
    }
}

#[derive(Serialize, Deserialize)]
pub struct RoleDefinition {
    threshold: u32,
    key_ids: Vec<crypto::KeyId>,
}

impl RoleDefinition {
    pub fn from(role: &metadata::RoleDefinition) -> Result<Self> {
        let mut key_ids = role.key_ids()
            .iter()
            .cloned()
            .collect::<Vec<crypto::KeyId>>();
        key_ids.sort();

        Ok(RoleDefinition {
            threshold: role.threshold(),
            key_ids: key_ids,
        })
    }

    pub fn try_into(mut self) -> Result<metadata::RoleDefinition> {
        let vec_len = self.key_ids.len();
        if vec_len < 1 {
            return Err(Error::Encoding(
                "Role defined with no assoiciated key IDs.".into(),
            ));
        }

        let key_ids = self.key_ids.drain(0..).collect::<HashSet<crypto::KeyId>>();
        let dupes = vec_len - key_ids.len();

        if dupes != 0 {
            return Err(Error::Encoding(
                format!("Found {} duplicate key IDs.", dupes),
            ));
        }

        Ok(metadata::RoleDefinition::new(self.threshold, key_ids)?)
    }
}

#[derive(Serialize, Deserialize)]
pub struct TimestampMetadata {
    #[serde(rename = "type")]
    typ: metadata::Role,
    version: u32,
    expires: DateTime<Utc>,
    meta: HashMap<metadata::MetadataPath, metadata::MetadataDescription>,
}

impl TimestampMetadata {
    pub fn from(metadata: &metadata::TimestampMetadata) -> Result<Self> {
        Ok(TimestampMetadata {
            typ: metadata::Role::Timestamp,
            version: metadata.version(),
            expires: metadata.expires().clone(),
            meta: metadata.meta().clone(),
        })
    }

    pub fn try_into(self) -> Result<metadata::TimestampMetadata> {
        if self.typ != metadata::Role::Timestamp {
            return Err(Error::Encoding(format!(
                "Attempted to decode timestamp metdata labeled as {:?}",
                self.typ
            )));
        }

        metadata::TimestampMetadata::new(self.version, self.expires, self.meta)
    }
}

#[derive(Serialize, Deserialize)]
pub struct SnapshotMetadata {
    #[serde(rename = "type")]
    typ: metadata::Role,
    version: u32,
    expires: DateTime<Utc>,
    meta: HashMap<metadata::MetadataPath, metadata::MetadataDescription>,
}

impl SnapshotMetadata {
    pub fn from(metadata: &metadata::SnapshotMetadata) -> Result<Self> {
        Ok(SnapshotMetadata {
            typ: metadata::Role::Snapshot,
            version: metadata.version(),
            expires: metadata.expires().clone(),
            meta: metadata.meta().clone(),
        })
    }

    pub fn try_into(self) -> Result<metadata::SnapshotMetadata> {
        if self.typ != metadata::Role::Snapshot {
            return Err(Error::Encoding(format!(
                "Attempted to decode snapshot metdata labeled as {:?}",
                self.typ
            )));
        }

        metadata::SnapshotMetadata::new(self.version, self.expires, self.meta)
    }
}


#[derive(Serialize, Deserialize)]
pub struct TargetsMetadata {
    #[serde(rename = "type")]
    typ: metadata::Role,
    version: u32,
    expires: DateTime<Utc>,
    targets: HashMap<metadata::TargetPath, metadata::TargetDescription>,
}

impl TargetsMetadata {
    pub fn from(metadata: &metadata::TargetsMetadata) -> Result<Self> {
        Ok(TargetsMetadata {
            typ: metadata::Role::Targets,
            version: metadata.version(),
            expires: metadata.expires().clone(),
            targets: metadata.targets().clone(),
        })
    }

    pub fn try_into(self) -> Result<metadata::TargetsMetadata> {
        if self.typ != metadata::Role::Targets {
            return Err(Error::Encoding(format!(
                "Attempted to decode targets metdata labeled as {:?}",
                self.typ
            )));
        }

        metadata::TargetsMetadata::new(self.version, self.expires, self.targets)
    }
}

#[derive(Serialize, Deserialize)]
pub struct PublicKey {
    #[serde(rename = "type")]
    typ: crypto::KeyType,
    public_key: String,
}

impl PublicKey {
    pub fn new(typ: crypto::KeyType, public_key_bytes: &[u8]) -> Self {
        PublicKey {
            typ: typ,
            public_key: BASE64URL.encode(public_key_bytes),
        }
    }

    pub fn public_key(&self) -> &String {
        &self.public_key
    }
}