Skip to content

Commit

Permalink
Add from_path() to Target
Browse files Browse the repository at this point in the history
This function allows one to get a Target object from a given
Path, provided it is a file.
  • Loading branch information
zmrow committed May 14, 2020
1 parent b4e68a4 commit f1e3e12
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
29 changes: 29 additions & 0 deletions tough/src/schema/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use crate::schema::RoleType;
use snafu::{Backtrace, Snafu};
use std::fmt::{self, Debug, Display};
use std::path::PathBuf;

/// Alias for `Result<T, Error>`.
pub type Result<T> = std::result::Result<T, Error>;
Expand All @@ -17,6 +18,22 @@ pub enum Error {
#[snafu(display("Duplicate key ID: {}", keyid))]
DuplicateKeyId { keyid: String },

/// Unable to open a file
#[snafu(display("Failed to open '{}': {}", path.display(), source))]
FileOpen {
path: PathBuf,
source: std::io::Error,
backtrace: Backtrace,
},

/// Unable to read the file
#[snafu(display("Failed to read '{}': {}", path.display(), source))]
FileRead {
path: PathBuf,
source: std::io::Error,
backtrace: Backtrace,
},

/// A downloaded target's checksum does not match the checksum listed in the repository
/// metadata.
#[snafu(display("Invalid key ID {}: calculated {}", keyid, calculated))]
Expand Down Expand Up @@ -48,13 +65,21 @@ pub enum Error {
backtrace: Backtrace,
},

/// Unable to determine file name (path ends in '..' or is '/')
#[snafu(display("Unable to determine file name from path: '{}'", path.display()))]
NoFileName { path: PathBuf, backtrace: Backtrace },

/// Failed to decode a PEM-encoded key.
#[snafu(display("Invalid PEM string: {}", source))]
PemDecode {
source: Compat<pem::PemError>,
backtrace: Backtrace,
},

/// Path isn't a valid UTF8 string
#[snafu(display("Path '{}' is not valid UTF-8", path.display()))]
PathUtf8 { path: PathBuf, backtrace: Backtrace },

/// A signature threshold specified in root.json was not met when verifying a signature.
#[snafu(display(
"Signature threshold of {} not met for role {} ({} valid signatures)",
Expand All @@ -72,6 +97,10 @@ pub enum Error {
/// Failed to extract a bit string from a `SubjectPublicKeyInfo` document.
#[snafu(display("Invalid SubjectPublicKeyInfo document"))]
SpkiDecode { backtrace: Backtrace },

/// Unable to create a TUF target from anything but a file
#[snafu(display("TUF targets must be files, given: '{}'", path.display()))]
TargetNotAFile { path: PathBuf, backtrace: Backtrace },
}

/// Wrapper for error types that don't impl [`std::error::Error`].
Expand Down
43 changes: 43 additions & 0 deletions tough/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ use crate::schema::iter::KeysIter;
use crate::schema::key::Key;
use chrono::{DateTime, Utc};
use olpc_cjson::CanonicalFormatter;
use ring::digest::{Context, SHA256};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_plain::{forward_display_to_serde, forward_from_str_to_serde};
use snafu::ResultExt;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::num::NonZeroU64;
use std::path::Path;

/// A role type.
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -224,6 +228,45 @@ pub struct Target {
pub _extra: HashMap<String, Value>,
}

impl Target {
/// Given a path, returns the target filename and Target object
pub fn from_path<P>(path: P) -> Result<Target>
where
P: AsRef<Path>,
{
// Ensure the given path is a file
let path = path.as_ref();
if !path.is_file() {
return error::TargetNotAFile { path }.fail();
}

// Get the sha256 and length of the target
let mut file = File::open(path).context(error::FileOpen { path })?;
let mut digest = Context::new(&SHA256);
let mut buf = [0; 8 * 1024];
let mut length = 0;
loop {
match file.read(&mut buf).context(error::FileRead { path })? {
0 => break,
n => {
digest.update(&buf[..n]);
length += n as u64;
}
}
}

Ok(Target {
length,
hashes: Hashes {
sha256: Decoded::from(digest.finish().as_ref().to_vec()),
_extra: HashMap::new(),
},
custom: HashMap::new(),
_extra: HashMap::new(),
})
}
}

impl Role for Targets {
const TYPE: RoleType = RoleType::Targets;

Expand Down

0 comments on commit f1e3e12

Please sign in to comment.