From 21d5466e5cf5a277f1a5e3184323bf0a29c8c3db Mon Sep 17 00:00:00 2001 From: Kevin Wells Date: Sun, 2 Feb 2020 10:44:53 -0800 Subject: [PATCH] Re-add D type param to Repository traits --- src/client.rs | 67 +++++++++++++++++----------------- src/repository.rs | 68 +++++++++++++++++------------------ src/repository/ephemeral.rs | 40 +++++++++++++-------- src/repository/file_system.rs | 46 +++++++++++++++++------- src/repository/http.rs | 32 ++++++++++------- tests/interop/main.rs | 20 ++++++----- tests/metadata/generate.rs | 54 ++++++++++++++++------------ tests/simple_example.rs | 26 +++++++------- 8 files changed, 203 insertions(+), 150 deletions(-) diff --git a/src/client.rs b/src/client.rs index f92c028b..92f74ce8 100644 --- a/src/client.rs +++ b/src/client.rs @@ -27,7 +27,7 @@ //! .map(|k| KeyId::from_str(k).unwrap()) //! .collect(); //! -//! let local = FileSystemRepository::new(PathBuf::from("~/.rustup"))?; +//! let local = FileSystemRepository::::new(PathBuf::from("~/.rustup"))?; //! //! let remote = HttpRepositoryBuilder::new_with_uri( //! "https://static.rust-lang.org/".parse::().unwrap(), @@ -119,8 +119,8 @@ impl PathTranslator for DefaultTranslator { pub struct Client where D: DataInterchange + Sync, - L: RepositoryProvider + RepositoryStorage, - R: RepositoryProvider, + L: RepositoryProvider + RepositoryStorage, + R: RepositoryProvider, T: PathTranslator, { tuf: Tuf, @@ -132,8 +132,8 @@ where impl Client where D: DataInterchange + Sync, - L: RepositoryProvider + RepositoryStorage, - R: RepositoryProvider, + L: RepositoryProvider + RepositoryStorage, + R: RepositoryProvider, T: PathTranslator, { /// Create a new TUF client. It will attempt to load the latest root metadata from the local @@ -164,8 +164,8 @@ where /// # SignatureScheme::Ed25519, /// # )?; /// # let public_key = private_key.public().clone(); - /// let mut local = Repository::<_, Json>::new(EphemeralRepository::new()); - /// let remote = EphemeralRepository::new(); + /// let local = EphemeralRepository::::new(); + /// let remote = EphemeralRepository::::new(); /// /// let root_version = 1; /// let root = RootMetadataBuilder::new() @@ -183,7 +183,7 @@ where /// local.store_metadata( /// &root_path, /// &root_version, - /// &root.to_raw().unwrap() + /// root.to_raw().unwrap().as_bytes() /// ).await?; /// /// let client = Client::with_trusted_local( @@ -242,8 +242,8 @@ where /// # SignatureScheme::Ed25519, /// # )?; /// # let public_key = private_key.public().clone(); - /// let local = EphemeralRepository::new(); - /// let remote = Repository::<_, Json>::new(EphemeralRepository::new()); + /// let local = EphemeralRepository::::new(); + /// let remote = EphemeralRepository::::new(); /// /// let root_version = 1; /// let root_threshold = 1; @@ -311,8 +311,8 @@ where /// # SignatureScheme::Ed25519, /// # )?; /// # let public_key = private_key.public().clone(); - /// let local = EphemeralRepository::new(); - /// let mut remote = Repository::<_, Json>::new(EphemeralRepository::new()); + /// let local = EphemeralRepository::::new(); + /// let remote = EphemeralRepository::::new(); /// /// let root_version = 1; /// let root_threshold = 1; @@ -332,7 +332,7 @@ where /// remote.store_metadata( /// &root_path, /// &root_version, - /// &root.to_raw().unwrap() + /// root.to_raw().unwrap().as_bytes() /// ).await?; /// /// let client = Client::with_trusted_root_keyids( @@ -435,8 +435,8 @@ where /// # SignatureScheme::Ed25519, /// # )?; /// # let public_key = private_key.public().clone(); - /// let local = EphemeralRepository::new(); - /// let mut remote = Repository::<_, Json>::new(EphemeralRepository::new()); + /// let local = EphemeralRepository::::new(); + /// let remote = EphemeralRepository::::new(); /// /// let root_version = 1; /// let root_threshold = 1; @@ -456,7 +456,7 @@ where /// remote.store_metadata( /// &root_path, /// &root_version, - /// &root.to_raw().unwrap() + /// root.to_raw().unwrap().as_bytes() /// ).await?; /// /// let client = Client::with_trusted_root_keys( @@ -961,8 +961,8 @@ async fn fetch_metadata_from_local_or_else_remote<'a, D, L, R, M>( ) -> Result<(bool, RawSignedMetadata, SignedMetadata)> where D: DataInterchange + Sync, - L: RepositoryProvider + RepositoryStorage, - R: RepositoryProvider, + L: RepositoryProvider + RepositoryStorage, + R: RepositoryProvider, M: Metadata + 'static, { match local @@ -1157,9 +1157,8 @@ mod test { #[test] fn client_constructors_err_with_not_found() { block_on(async { - let local = EphemeralRepository::new(); - let remote = EphemeralRepository::new(); - let remote = Repository::<_, Json>::new(&remote); + let local = EphemeralRepository::::new(); + let remote = EphemeralRepository::::new(); let private_key = PrivateKey::from_pkcs8( &PrivateKey::new(KeyType::Ed25519).unwrap(), @@ -1169,7 +1168,7 @@ mod test { let public_key = private_key.public().clone(); assert_matches!( - Client::with_trusted_local(Config::default(), &local, remote.clone()).await, + Client::with_trusted_local(Config::default(), &local, &remote).await, Err(Error::NotFound) ); @@ -1180,7 +1179,7 @@ mod test { 1, once(&public_key), &local, - remote.clone() + &remote, ) .await, Err(Error::NotFound) @@ -1193,7 +1192,7 @@ mod test { 1, once(public_key.key_id()), &local, - remote, + &remote, ) .await, Err(Error::NotFound) @@ -1205,8 +1204,8 @@ mod test { fn client_constructors_err_with_invalid_keys() { block_on(async { let local = EphemeralRepository::new(); - let remote_repo = EphemeralRepository::new(); - let mut remote = Repository::<_, Json>::new(&remote_repo); + let remote = EphemeralRepository::new(); + let mut repo = Repository::<_, Json>::new(&remote); let good_private_key = PrivateKey::from_pkcs8( &PrivateKey::new(KeyType::Ed25519).unwrap(), @@ -1229,8 +1228,7 @@ mod test { let root_path = MetadataPath::from_role(&Role::Root); let root_version = MetadataVersion::Number(root_version); - remote - .store_metadata(&root_path, &root_version, &root.to_raw().unwrap()) + repo.store_metadata(&root_path, &root_version, &root.to_raw().unwrap()) .await .unwrap(); @@ -1248,7 +1246,7 @@ mod test { 1, once(&bad_public_key), &local, - remote.clone(), + &remote, ) .await, Err(Error::VerificationFailure(_)) @@ -1261,7 +1259,7 @@ mod test { 1, once(bad_public_key.key_id()), &local, - remote, + &remote, ) .await, Err(Error::VerificationFailure(_)) @@ -1272,7 +1270,8 @@ mod test { #[test] fn root_chain_update() { block_on(async { - let mut remote = Repository::<_, Json>::new(EphemeralRepository::new()); + let repo = EphemeralRepository::::new(); + let mut remote = Repository::new(&repo); //// First, create the root metadata. let root1 = RootMetadataBuilder::new() @@ -1515,7 +1514,8 @@ mod test { } async fn test_versioned_init(consistent_snapshot: bool) { - let mut remote = Repository::<_, Json>::new(EphemeralRepository::new()); + let repo = EphemeralRepository::::new(); + let mut remote = Repository::new(&repo); //// First, create the root metadata. let root1 = RootMetadataBuilder::new() @@ -1712,7 +1712,8 @@ mod test { async fn test_fetch_target_description(path: String, expected_description: TargetDescription) { // Generate an ephemeral repository with a single target. - let mut remote = Repository::<_, Json>::new(EphemeralRepository::new()); + let repo = EphemeralRepository::::new(); + let mut remote = Repository::new(&repo); let root = RootMetadataBuilder::new() .root_key(KEYS[0].public().clone()) diff --git a/src/repository.rs b/src/repository.rs index 17cf419a..619ac896 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -24,7 +24,10 @@ mod ephemeral; pub use self::ephemeral::EphemeralRepository; /// A readable TUF repository. -pub trait RepositoryProvider { +pub trait RepositoryProvider +where + D: DataInterchange + Sync, +{ /// Fetch signed metadata identified by `meta_path`, `version`, and /// [`D::extension()`][extension]. /// @@ -34,7 +37,7 @@ pub trait RepositoryProvider { /// metadata. /// /// [extension]: crate::interchange::DataInterchange::extension - fn fetch_metadata<'a, D>( + fn fetch_metadata<'a>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, @@ -59,20 +62,22 @@ pub trait RepositoryProvider { /// A writable TUF repository. Most implementors of this trait should also implement /// `RepositoryProvider`. -pub trait RepositoryStorage { +pub trait RepositoryStorage +where + D: DataInterchange + Sync, +{ /// Store the provided `metadata` in a location identified by `meta_path`, `version`, and /// [`D::extension()`][extension], overwriting any existing metadata at that location. /// /// [extension]: crate::interchange::DataInterchange::extension - fn store_metadata<'a, R, D>( + fn store_metadata<'a, R>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, metadata: R, ) -> BoxFuture<'a, Result<()>> where - R: AsyncRead + Send + Unpin + 'a, - D: DataInterchange + Sync; + R: AsyncRead + Send + Unpin + 'a; /// Store the provided `target` in a location identified by `target_path`, overwriting any /// existing target at that location. @@ -85,21 +90,19 @@ pub trait RepositoryStorage { R: AsyncRead + Send + Unpin + 'a; } -impl RepositoryProvider for &T +impl RepositoryProvider for &T where - T: RepositoryProvider, + T: RepositoryProvider, + D: DataInterchange + Sync, { - fn fetch_metadata<'a, D>( + fn fetch_metadata<'a>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, max_length: Option, hash_data: Option<(&'static HashAlgorithm, HashValue)>, - ) -> BoxFuture<'a, Result>> - where - D: DataInterchange + Sync, - { - (**self).fetch_metadata::(meta_path, version, max_length, hash_data) + ) -> BoxFuture<'a, Result>> { + (**self).fetch_metadata(meta_path, version, max_length, hash_data) } fn fetch_target<'a>( @@ -111,11 +114,12 @@ where } } -impl RepositoryStorage for &T +impl RepositoryStorage for &T where - T: RepositoryStorage, + T: RepositoryStorage, + D: DataInterchange + Sync, { - fn store_metadata<'a, R, D>( + fn store_metadata<'a, R>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, @@ -123,9 +127,8 @@ where ) -> BoxFuture<'a, Result<()>> where R: AsyncRead + Send + Unpin + 'a, - D: DataInterchange + Sync, { - (**self).store_metadata::<_, D>(meta_path, version, metadata) + (**self).store_metadata(meta_path, version, metadata) } fn store_target<'a, R>( @@ -177,7 +180,7 @@ impl Repository { impl Repository where - R: RepositoryProvider, + R: RepositoryProvider, D: DataInterchange + Sync, { /// Fetch and parse metadata identified by `meta_path`, `version`, and @@ -229,7 +232,7 @@ where // implementation should only be trusted to use those as hints to fail early. let mut reader = self .repository - .fetch_metadata::(meta_path, version, max_length, hash_data.clone()) + .fetch_metadata(meta_path, version, max_length, hash_data.clone()) .await? .check_length_and_hash(max_length.unwrap_or(::std::usize::MAX) as u64, hash_data)?; @@ -264,7 +267,7 @@ where impl Repository where - R: RepositoryStorage, + R: RepositoryStorage, D: DataInterchange + Sync, { /// Store the provided `metadata` in a location identified by `meta_path`, `version`, and @@ -283,7 +286,7 @@ where Self::check::(path)?; self.repository - .store_metadata::<_, D>(path, version, metadata.as_bytes()) + .store_metadata(path, version, metadata.as_bytes()) .await } @@ -302,7 +305,8 @@ where impl From for Repository where - R: RepositoryProvider + Sync, + R: RepositoryProvider + Sync, + D: DataInterchange + Sync, { fn from(r: R) -> Self { Repository::new(r) @@ -382,9 +386,7 @@ mod test { let data_hash = crypto::calculate_hash(data, HashAlgorithm::Sha256); let repo = EphemeralRepository::new(); - repo.store_metadata::<_, Json>(&path, &version, data) - .await - .unwrap(); + repo.store_metadata(&path, &version, data).await.unwrap(); let client = Repository::<_, Json>::new(repo); @@ -410,9 +412,7 @@ mod test { let data: &[u8] = b"corrupt metadata"; let repo = EphemeralRepository::new(); - repo.store_metadata::<_, Json>(&path, &version, data) - .await - .unwrap(); + repo.store_metadata(&path, &version, data).await.unwrap(); let client = Repository::<_, Json>::new(repo); @@ -438,9 +438,7 @@ mod test { let data: &[u8] = b"reasonably sized metadata"; let repo = EphemeralRepository::new(); - repo.store_metadata::<_, Json>(&path, &version, data) - .await - .unwrap(); + repo.store_metadata(&path, &version, data).await.unwrap(); let client = Repository::<_, Json>::new(repo); @@ -461,9 +459,7 @@ mod test { let data: &[u8] = b"very big metadata"; let repo = EphemeralRepository::new(); - repo.store_metadata::<_, Json>(&path, &version, data) - .await - .unwrap(); + repo.store_metadata(&path, &version, data).await.unwrap(); let client = Repository::<_, Json>::new(repo); diff --git a/src/repository/ephemeral.rs b/src/repository/ephemeral.rs index 0e05fe72..680dc0c8 100644 --- a/src/repository/ephemeral.rs +++ b/src/repository/ephemeral.rs @@ -5,6 +5,7 @@ use futures_util::future::{BoxFuture, FutureExt}; use futures_util::io::{AsyncReadExt, Cursor}; use parking_lot::RwLock; use std::collections::HashMap; +use std::marker::PhantomData; use std::sync::Arc; use crate::crypto::{HashAlgorithm, HashValue}; @@ -18,38 +19,46 @@ type ArcHashMap = Arc>>; /// An ephemeral repository contained solely in memory. #[derive(Debug)] -pub struct EphemeralRepository { +pub struct EphemeralRepository { metadata: ArcHashMap<(MetadataPath, MetadataVersion, &'static str), Arc<[u8]>>, targets: ArcHashMap>, + _interchange: PhantomData, } -impl EphemeralRepository { +impl EphemeralRepository +where + D: DataInterchange + Sync, +{ /// Create a new ephemercal repository. pub fn new() -> Self { - EphemeralRepository { + Self { metadata: Arc::new(RwLock::new(HashMap::new())), targets: Arc::new(RwLock::new(HashMap::new())), + _interchange: PhantomData, } } } -impl Default for EphemeralRepository { +impl Default for EphemeralRepository +where + D: DataInterchange + Sync, +{ fn default() -> Self { EphemeralRepository::new() } } -impl RepositoryProvider for EphemeralRepository { - fn fetch_metadata<'a, D>( +impl RepositoryProvider for EphemeralRepository +where + D: DataInterchange + Sync, +{ + fn fetch_metadata<'a>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, _max_length: Option, _hash_data: Option<(&'static HashAlgorithm, HashValue)>, - ) -> BoxFuture<'a, Result>> - where - D: DataInterchange + Sync, - { + ) -> BoxFuture<'a, Result>> { async move { let bytes = match self.metadata.read().get(&( meta_path.clone(), @@ -88,8 +97,11 @@ impl RepositoryProvider for EphemeralRepository { } } -impl RepositoryStorage for EphemeralRepository { - fn store_metadata<'a, R, D>( +impl RepositoryStorage for EphemeralRepository +where + D: DataInterchange + Sync, +{ + fn store_metadata<'a, R>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, @@ -97,7 +109,6 @@ impl RepositoryStorage for EphemeralRepository { ) -> BoxFuture<'a, Result<()>> where R: AsyncRead + Send + Unpin + 'a, - D: DataInterchange + Sync, { async move { let mut buf = Vec::new(); @@ -134,12 +145,13 @@ impl RepositoryStorage for EphemeralRepository { #[cfg(test)] mod test { use super::*; + use crate::interchange::Json; use futures_executor::block_on; #[test] fn ephemeral_repo_targets() { block_on(async { - let repo = EphemeralRepository::new(); + let repo = EphemeralRepository::::new(); let data: &[u8] = b"like tears in the rain"; let target_description = diff --git a/src/repository/file_system.rs b/src/repository/file_system.rs index 8d372f7f..03ad03da 100644 --- a/src/repository/file_system.rs +++ b/src/repository/file_system.rs @@ -5,6 +5,7 @@ use futures_util::future::{BoxFuture, FutureExt}; use futures_util::io::{copy, AllowStdIo}; use log::debug; use std::fs::{DirBuilder, File}; +use std::marker::PhantomData; use std::path::{Path, PathBuf}; use tempfile::NamedTempFile; @@ -16,19 +17,27 @@ use crate::repository::{RepositoryProvider, RepositoryStorage}; use crate::Result; /// A builder to create a repository contained on the local file system. -pub struct FileSystemRepositoryBuilder { +pub struct FileSystemRepositoryBuilder +where + D: DataInterchange + Sync, +{ local_path: PathBuf, metadata_prefix: Option, targets_prefix: Option, + _interchange: PhantomData, } -impl FileSystemRepositoryBuilder { +impl FileSystemRepositoryBuilder +where + D: DataInterchange + Sync, +{ /// Create a new repository with the given `local_path` prefix. pub fn new>(local_path: P) -> Self { FileSystemRepositoryBuilder { local_path: local_path.into(), metadata_prefix: None, targets_prefix: None, + _interchange: PhantomData, } } @@ -53,7 +62,7 @@ impl FileSystemRepositoryBuilder { } /// Build a `FileSystemRepository`. - pub fn build(self) -> Result { + pub fn build(self) -> Result> { let metadata_path = if let Some(metadata_prefix) = self.metadata_prefix { self.local_path.join(metadata_prefix) } else { @@ -71,17 +80,25 @@ impl FileSystemRepositoryBuilder { Ok(FileSystemRepository { metadata_path, targets_path, + _interchange: PhantomData, }) } } /// A repository contained on the local file system. -pub struct FileSystemRepository { +pub struct FileSystemRepository +where + D: DataInterchange + Sync, +{ metadata_path: PathBuf, targets_path: PathBuf, + _interchange: PhantomData, } -impl FileSystemRepository { +impl FileSystemRepository +where + D: DataInterchange + Sync, +{ /// Create a new repository on the local file system. pub fn new(local_path: PathBuf) -> Result { FileSystemRepositoryBuilder::new(local_path) @@ -91,8 +108,11 @@ impl FileSystemRepository { } } -impl RepositoryProvider for FileSystemRepository { - fn fetch_metadata<'a, D>( +impl RepositoryProvider for FileSystemRepository +where + D: DataInterchange + Sync, +{ + fn fetch_metadata<'a>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, @@ -134,8 +154,11 @@ impl RepositoryProvider for FileSystemRepository { } } -impl RepositoryStorage for FileSystemRepository { - fn store_metadata<'a, R, D>( +impl RepositoryStorage for FileSystemRepository +where + D: DataInterchange + Sync, +{ + fn store_metadata<'a, R>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, @@ -143,7 +166,6 @@ impl RepositoryStorage for FileSystemRepository { ) -> BoxFuture<'a, Result<()>> where R: AsyncRead + Send + Unpin + 'a, - D: DataInterchange + Sync, { async move { let mut path = self.metadata_path.clone(); @@ -219,7 +241,7 @@ mod test { .prefix("rust-tuf") .tempdir() .unwrap(); - let repo = FileSystemRepositoryBuilder::new(temp_dir.path()) + let repo = FileSystemRepositoryBuilder::::new(temp_dir.path()) .build() .unwrap(); @@ -244,7 +266,7 @@ mod test { .prefix("rust-tuf") .tempdir() .unwrap(); - let repo = FileSystemRepositoryBuilder::new(temp_dir.path().to_path_buf()) + let repo = FileSystemRepositoryBuilder::::new(temp_dir.path().to_path_buf()) .metadata_prefix("meta") .targets_prefix("targs") .build() diff --git a/src/repository/http.rs b/src/repository/http.rs index e5da784b..928145ad 100644 --- a/src/repository/http.rs +++ b/src/repository/http.rs @@ -11,6 +11,7 @@ use hyper::Client; use hyper::Request; use percent_encoding::utf8_percent_encode; use std::io; +use std::marker::PhantomData; use url::Url; use crate::crypto::{HashAlgorithm, HashValue}; @@ -22,9 +23,10 @@ use crate::util::SafeAsyncRead; use crate::Result; /// A builder to create a repository accessible over HTTP. -pub struct HttpRepositoryBuilder +pub struct HttpRepositoryBuilder where C: Connect + Sync + 'static, + D: DataInterchange + Sync, { uri: Uri, client: Client, @@ -32,11 +34,13 @@ where metadata_prefix: Option>, targets_prefix: Option>, min_bytes_per_second: u32, + _interchange: PhantomData, } -impl HttpRepositoryBuilder +impl HttpRepositoryBuilder where C: Connect + Sync + 'static, + D: DataInterchange + Sync, { /// Create a new repository with the given `Url` and `Client`. pub fn new(url: Url, client: Client) -> Self { @@ -47,6 +51,7 @@ where metadata_prefix: None, targets_prefix: None, min_bytes_per_second: 4096, + _interchange: PhantomData, } } @@ -59,6 +64,7 @@ where metadata_prefix: None, targets_prefix: None, min_bytes_per_second: 4096, + _interchange: PhantomData, } } @@ -99,7 +105,7 @@ where } /// Build a `HttpRepository`. - pub fn build(self) -> HttpRepository { + pub fn build(self) -> HttpRepository { let user_agent = match self.user_agent { Some(user_agent) => user_agent, None => "rust-tuf".into(), @@ -112,14 +118,16 @@ where metadata_prefix: self.metadata_prefix, targets_prefix: self.targets_prefix, min_bytes_per_second: self.min_bytes_per_second, + _interchange: PhantomData, } } } /// A repository accessible over HTTP. -pub struct HttpRepository +pub struct HttpRepository where C: Connect + Sync + 'static, + D: DataInterchange + Sync, { uri: Uri, client: Client, @@ -127,6 +135,7 @@ where metadata_prefix: Option>, targets_prefix: Option>, min_bytes_per_second: u32, + _interchange: PhantomData, } // Configuration for urlencoding URI path elements. @@ -195,9 +204,10 @@ fn extend_uri(uri: Uri, prefix: &Option>, components: &[String]) -> })?) } -impl HttpRepository +impl HttpRepository where C: Connect + Sync + 'static, + D: DataInterchange + Sync, { async fn get<'a>( &'a self, @@ -230,22 +240,20 @@ where } } -impl RepositoryProvider for HttpRepository +impl RepositoryProvider for HttpRepository where C: Connect + Sync + 'static, + D: DataInterchange + Send + Sync, { - fn fetch_metadata<'a, D>( + fn fetch_metadata<'a>( &'a self, meta_path: &'a MetadataPath, version: &'a MetadataVersion, _max_length: Option, _hash_data: Option<(&'static HashAlgorithm, HashValue)>, - ) -> BoxFuture<'a, Result>> - where - D: DataInterchange + Sync, - { + ) -> BoxFuture<'a, Result>> { + let components = meta_path.components::(&version); async move { - let components = meta_path.components::(&version); let resp = self.get(&self.metadata_prefix, &components).await?; // TODO check content length if known and fail early if the payload is too large. diff --git a/tests/interop/main.rs b/tests/interop/main.rs index ce4a76ef..e3e96a7a 100644 --- a/tests/interop/main.rs +++ b/tests/interop/main.rs @@ -35,16 +35,17 @@ //! download targets at each step of the test. use futures_executor::block_on; +use futures_util::io::AsyncReadExt; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use tuf::client::{Client, Config}; use tuf::crypto::KeyId; use tuf::interchange::Json; use tuf::metadata::{ - MetadataPath, MetadataVersion, Role, RootMetadata, SignedMetadata, TargetPath, + MetadataPath, MetadataVersion, RawSignedMetadata, Role, RootMetadata, TargetPath, }; use tuf::repository::{ - EphemeralRepository, FileSystemRepository, FileSystemRepositoryBuilder, Repository, + EphemeralRepository, FileSystemRepository, FileSystemRepositoryBuilder, RepositoryProvider, }; use tuf::Result; @@ -120,7 +121,7 @@ struct TestKeyRotation { test_steps: Vec, /// The local repository used to store the local metadata. - local: EphemeralRepository, + local: EphemeralRepository, /// The targets we expect each step of the repository to contain. It will contain a target for /// each step we've processed, named for the first step it appeared in. @@ -207,19 +208,22 @@ async fn extract_keys(dir: &Path) -> Vec { let root_path = MetadataPath::from_role(&Role::Root); - let metadata: SignedMetadata = remote + let mut buf = Vec::new(); + let mut reader = remote .fetch_metadata(&root_path, &MetadataVersion::Number(1), None, None) .await - .unwrap() - .1; + .unwrap(); + reader.read_to_end(&mut buf).await.unwrap(); + let metadata = RawSignedMetadata::::new(buf) + .parse() + .unwrap(); metadata.as_ref().root().key_ids().iter().cloned().collect() } -fn init_remote(dir: &Path) -> Result> { +fn init_remote(dir: &Path) -> Result> { FileSystemRepositoryBuilder::new(dir) .metadata_prefix(Path::new("repository")) .targets_prefix(Path::new("repository").join("targets")) .build() - .map(Into::into) } diff --git a/tests/metadata/generate.rs b/tests/metadata/generate.rs index e59452de..89e56eff 100644 --- a/tests/metadata/generate.rs +++ b/tests/metadata/generate.rs @@ -12,7 +12,7 @@ use tuf::metadata::{ MetadataPath, MetadataVersion, Role, RootMetadataBuilder, SnapshotMetadataBuilder, TargetPath, TargetsMetadataBuilder, TimestampMetadataBuilder, VirtualTargetPath, }; -use tuf::repository::{FileSystemRepository, FileSystemRepositoryBuilder, Repository}; +use tuf::repository::{FileSystemRepository, FileSystemRepositoryBuilder, RepositoryStorage}; const KEYS_PATH: &str = "./keys.json"; // These structs and functions are necessary to parse keys.json, which contains the keys @@ -82,7 +82,7 @@ fn copy_repo(dir: &str, step: u8) { // updates the root metadata. If root_signer is Some, use that to sign the // metadata, otherwise use keys["root"]. async fn update_root( - repo: &mut Repository, + repo: &FileSystemRepository, keys: &RoleKeys, root_signer: Option<&PrivateKey>, version: u32, @@ -116,18 +116,22 @@ async fn update_root( repo.store_metadata( &root_path, &MetadataVersion::Number(version), - &root.to_raw().unwrap(), + root.to_raw().unwrap().as_bytes(), + ) + .await + .unwrap(); + repo.store_metadata( + &root_path, + &MetadataVersion::None, + root.to_raw().unwrap().as_bytes(), ) .await .unwrap(); - repo.store_metadata(&root_path, &MetadataVersion::None, &root.to_raw().unwrap()) - .await - .unwrap(); } // adds a target and updates the non-root metadata files. async fn add_target( - repo: &mut Repository, + repo: &FileSystemRepository, keys: &RoleKeys, step: u8, consistent_snapshot: bool, @@ -182,9 +186,13 @@ async fn add_target( MetadataVersion::None }; - repo.store_metadata(&targets_path, &version_prefix, &targets.to_raw().unwrap()) - .await - .unwrap(); + repo.store_metadata( + &targets_path, + &version_prefix, + targets.to_raw().unwrap().as_bytes(), + ) + .await + .unwrap(); let snapshot_path = MetadataPath::from_role(&Role::Snapshot); let snapshot = SnapshotMetadataBuilder::new() @@ -195,9 +203,13 @@ async fn add_target( .signed::(&keys.get("snapshot").unwrap()) .unwrap(); - repo.store_metadata(&snapshot_path, &version_prefix, &snapshot.to_raw().unwrap()) - .await - .unwrap(); + repo.store_metadata( + &snapshot_path, + &version_prefix, + snapshot.to_raw().unwrap().as_bytes(), + ) + .await + .unwrap(); let timestamp_path = MetadataPath::from_role(&Role::Timestamp); let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256]) @@ -211,7 +223,7 @@ async fn add_target( repo.store_metadata( ×tamp_path, &MetadataVersion::None, - ×tamp.to_raw().unwrap(), + timestamp.to_raw().unwrap().as_bytes(), ) .await .unwrap(); @@ -222,14 +234,13 @@ async fn generate_repos(dir: &str, consistent_snapshot: bool) -> tuf::Result<()> let json_keys = init_json_keys(KEYS_PATH); let mut keys = init_role_keys(&json_keys); let dir0 = Path::new(dir).join("0"); - let mut repo: Repository<_, JsonPretty> = FileSystemRepositoryBuilder::new(dir0) + let repo = FileSystemRepositoryBuilder::new(dir0) .metadata_prefix(Path::new("repository")) .targets_prefix(Path::new("repository").join("targets")) - .build()? - .into(); + .build()?; - update_root(&mut repo, &keys, None, 1, consistent_snapshot).await; - add_target(&mut repo, &keys, 0, consistent_snapshot).await; + update_root(&repo, &keys, None, 1, consistent_snapshot).await; + add_target(&repo, &keys, 0, consistent_snapshot).await; let mut i: u8 = 1; let rotations = vec![ @@ -248,7 +259,6 @@ async fn generate_repos(dir: &str, consistent_snapshot: bool) -> tuf::Result<()> .build() .unwrap(); copy_repo(dir, i); - let mut repo = Repository::<_, JsonPretty>::new(repo); let root_signer = match r { Some(Role::Root) => keys.insert("root", json_keys.root[1][0].to_private_key()), @@ -267,14 +277,14 @@ async fn generate_repos(dir: &str, consistent_snapshot: bool) -> tuf::Result<()> None => None, }; update_root( - &mut repo, + &repo, &keys, root_signer.as_ref(), (i + 1).into(), consistent_snapshot, ) .await; - add_target(&mut repo, &keys, i, consistent_snapshot).await; + add_target(&repo, &keys, i, consistent_snapshot).await; i = i + 1; } Ok(()) diff --git a/tests/simple_example.rs b/tests/simple_example.rs index 1657630b..75f12dee 100644 --- a/tests/simple_example.rs +++ b/tests/simple_example.rs @@ -6,7 +6,7 @@ use tuf::metadata::{ MetadataPath, MetadataVersion, RootMetadataBuilder, SnapshotMetadataBuilder, TargetDescription, TargetPath, TargetsMetadataBuilder, TimestampMetadataBuilder, VirtualTargetPath, }; -use tuf::repository::{EphemeralRepository, Repository}; +use tuf::repository::{EphemeralRepository, RepositoryStorage}; use tuf::Result; // Ironically, this is far from simple, but it's as simple as it can be made. @@ -74,8 +74,8 @@ async fn run_tests(config: Config, consistent_snapshots: bool) where T: PathTranslator, { - let mut remote = Repository::new(EphemeralRepository::new()); - let root_key_ids = init_server(&mut remote, &config, consistent_snapshots) + let remote = EphemeralRepository::new(); + let root_key_ids = init_server(&remote, &config, consistent_snapshots) .await .unwrap(); init_client(&root_key_ids, remote, config).await.unwrap(); @@ -83,7 +83,7 @@ where async fn init_client( root_key_ids: &[KeyId], - remote: Repository, + remote: EphemeralRepository, config: Config, ) -> Result<()> where @@ -105,7 +105,7 @@ where } async fn init_server<'a, T>( - remote: &'a mut Repository, + remote: &'a EphemeralRepository, config: &'a Config, consistent_snapshot: bool, ) -> Result> @@ -133,14 +133,14 @@ where .store_metadata( &root_path, &MetadataVersion::Number(1), - &signed.to_raw().unwrap(), + signed.to_raw().unwrap().as_bytes(), ) .await?; remote .store_metadata( &root_path, &MetadataVersion::None, - &signed.to_raw().unwrap(), + signed.to_raw().unwrap().as_bytes(), ) .await?; @@ -173,14 +173,14 @@ where .store_metadata( &targets_path, &MetadataVersion::Number(1), - &targets.to_raw().unwrap(), + targets.to_raw().unwrap().as_bytes(), ) .await?; remote .store_metadata( &targets_path, &MetadataVersion::None, - &targets.to_raw().unwrap(), + targets.to_raw().unwrap().as_bytes(), ) .await?; @@ -195,14 +195,14 @@ where .store_metadata( &snapshot_path, &MetadataVersion::Number(1), - &snapshot.to_raw().unwrap(), + snapshot.to_raw().unwrap().as_bytes(), ) .await?; remote .store_metadata( &snapshot_path, &MetadataVersion::None, - &snapshot.to_raw().unwrap(), + snapshot.to_raw().unwrap().as_bytes(), ) .await?; @@ -216,14 +216,14 @@ where .store_metadata( ×tamp_path, &MetadataVersion::Number(1), - ×tamp.to_raw().unwrap(), + timestamp.to_raw().unwrap().as_bytes(), ) .await?; remote .store_metadata( ×tamp_path, &MetadataVersion::None, - ×tamp.to_raw().unwrap(), + timestamp.to_raw().unwrap().as_bytes(), ) .await?;