Add SnapshotMetadataBuilder to simplify making SnapshotMetadata
diff --git a/src/metadata.rs b/src/metadata.rs
index 99315c5..5713be8 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -180,16 +180,21 @@
_ => false,
}
}
+
+ /// Return the name of the role.
+ pub fn name(&self) -> &'static str {
+ match *self {
+ Role::Root => "root",
+ Role::Snapshot => "snapshot",
+ Role::Targets => "targets",
+ Role::Timestamp => "timestamp",
+ }
+ }
}
impl Display for Role {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Role::Root => write!(f, "root"),
- Role::Snapshot => write!(f, "snapshot"),
- Role::Targets => write!(f, "targets"),
- Role::Timestamp => write!(f, "timestamp"),
- }
+ f.write_str(self.name())
}
}
@@ -1083,6 +1088,114 @@
}
}
+/// Helper to construct `SnapshotMetadata`.
+pub struct SnapshotMetadataBuilder {
+ version: u32,
+ expires: DateTime<Utc>,
+ meta: HashMap<MetadataPath, MetadataDescription>,
+}
+
+impl SnapshotMetadataBuilder {
+ /// Create a new `SnapshotMetadataBuilder`. It defaults to:
+ ///
+ /// * version: 1
+ /// * expires: 7 days from the current time.
+ pub fn new() -> Self {
+ SnapshotMetadataBuilder {
+ version: 1,
+ expires: Utc::now() + Duration::days(7),
+ meta: HashMap::new(),
+ }
+ }
+
+ /// Set the version number for this metadata.
+ pub fn version(mut self, version: u32) -> Self {
+ self.version = version;
+ self
+ }
+
+ /// Set the time this metadata expires.
+ pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
+ self.expires = expires;
+ self
+ }
+
+ /// Add metadata to the snapshot using the default path.
+ pub fn insert_metadata<D, M>(
+ self,
+ metadata: &SignedMetadata<D, M>,
+ hash_algs: &[HashAlgorithm],
+ ) -> Result<Self>
+ where
+ M: Metadata,
+ D: DataInterchange,
+ {
+ self.insert_metadata_with_path(
+ M::ROLE.name(),
+ metadata,
+ hash_algs,
+ )
+ }
+
+ /// Add metadata to the snapshot using a custom path.
+ pub fn insert_metadata_with_path<P, D, M>(
+ self,
+ path: P,
+ metadata: &SignedMetadata<D, M>,
+ hash_algs: &[HashAlgorithm],
+ ) -> Result<Self>
+ where
+ P: Into<String>,
+ M: Metadata,
+ D: DataInterchange,
+ {
+ let bytes = D::canonicalize(&D::serialize(metadata)?)?;
+ let description = MetadataDescription::from_reader(
+ &*bytes,
+ metadata.version(),
+ hash_algs,
+ )?;
+ let path = MetadataPath::new(path.into())?;
+ Ok(self.insert_metadata_description(path, description))
+ }
+
+ /// Add `MetadataDescription` to the snapshot using a custom path.
+ pub fn insert_metadata_description(
+ mut self,
+ path: MetadataPath,
+ description: MetadataDescription,
+ ) -> Self {
+ self.meta.insert(path.into(), description);
+ self
+ }
+
+ /// Construct a new `SignedMetadata`.
+ pub fn build(self) -> Result<SnapshotMetadata> {
+ SnapshotMetadata::new(
+ self.version,
+ self.expires,
+ self.meta,
+ )
+ }
+
+ /// Construct a new `SignedMetadata<D, SnapshotMetadata>`.
+ pub fn signed<D>(self, private_key: &PrivateKey) -> Result<SignedMetadata<D, SnapshotMetadata>>
+ where D: DataInterchange,
+ {
+ Ok(SignedMetadata::new(self.build()?, private_key)?)
+ }
+}
+
+impl From<SnapshotMetadata> for SnapshotMetadataBuilder {
+ fn from(meta: SnapshotMetadata) -> Self {
+ SnapshotMetadataBuilder {
+ version: meta.version,
+ expires: meta.expires,
+ meta: meta.meta,
+ }
+ }
+}
+
/// Metadata for the snapshot role.
#[derive(Debug, Clone, PartialEq)]
pub struct SnapshotMetadata {
@@ -1860,18 +1973,18 @@
#[test]
fn serde_snapshot_metadata() {
- let snapshot = SnapshotMetadata::new(
- 1,
- Utc.ymd(2017, 1, 1).and_hms(0, 0, 0),
- hashmap! {
- MetadataPath::new("foo".into()).unwrap() =>
- MetadataDescription::new(
- 1,
- 100,
- hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
- ).unwrap(),
- },
- ).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+ .insert_metadata_description(
+ MetadataPath::new("foo".into()).unwrap(),
+ MetadataDescription::new(
+ 1,
+ 100,
+ hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
+ ).unwrap(),
+ )
+ .build()
+ .unwrap();
let jsn = json!({
"type": "snapshot",
@@ -1986,18 +2099,18 @@
#[test]
fn serde_signed_metadata() {
- let snapshot = SnapshotMetadata::new(
- 1,
- Utc.ymd(2017, 1, 1).and_hms(0, 0, 0),
- hashmap! {
- MetadataPath::new("foo".into()).unwrap() =>
- MetadataDescription::new(
- 1,
- 100,
- hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
- ).unwrap(),
- },
- ).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+ .insert_metadata_description(
+ MetadataPath::new("foo".into()).unwrap(),
+ MetadataDescription::new(
+ 1,
+ 100,
+ hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
+ ).unwrap(),
+ )
+ .build()
+ .unwrap();
let key = PrivateKey::from_pkcs8(ED25519_1_PK8, SignatureScheme::Ed25519).unwrap();
@@ -2081,8 +2194,10 @@
}
fn make_snapshot() -> json::Value {
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), hashmap!()).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .expires(Utc.ymd(2038, 1, 1).and_hms(0, 0, 0))
+ .build()
+ .unwrap();
json::to_value(&snapshot).unwrap()
}
diff --git a/src/tuf.rs b/src/tuf.rs
index c6c7b5e..f7e2311 100644
--- a/src/tuf.rs
+++ b/src/tuf.rs
@@ -616,7 +616,7 @@
use chrono::prelude::*;
use crypto::{HashAlgorithm, PrivateKey, SignatureScheme};
use interchange::Json;
- use metadata::{MetadataDescription, RootMetadataBuilder};
+ use metadata::{MetadataDescription, RootMetadataBuilder, SnapshotMetadataBuilder};
lazy_static! {
static ref KEYS: Vec<PrivateKey> = {
@@ -787,10 +787,9 @@
tuf.update_timestamp(timestamp).unwrap();
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), hashmap!()).unwrap();
- let snapshot: SignedMetadata<Json, SnapshotMetadata> =
- SignedMetadata::new(snapshot, &KEYS[1]).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .signed(&KEYS[1])
+ .unwrap();
assert_eq!(tuf.update_snapshot(snapshot.clone()), Ok(true));
@@ -820,10 +819,9 @@
tuf.update_timestamp(timestamp).unwrap();
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), hashmap!()).unwrap();
- let snapshot: SignedMetadata<Json, SnapshotMetadata> =
- SignedMetadata::new(snapshot, &KEYS[2]).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
assert!(tuf.update_snapshot(snapshot).is_err());
}
@@ -850,10 +848,9 @@
tuf.update_timestamp(timestamp).unwrap();
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), hashmap!()).unwrap();
- let snapshot: SignedMetadata<Json, SnapshotMetadata> =
- SignedMetadata::new(snapshot, &KEYS[1]).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .signed::<Json>(&KEYS[1])
+ .unwrap();
assert!(tuf.update_snapshot(snapshot).is_err());
}
@@ -880,14 +877,13 @@
tuf.update_timestamp(timestamp).unwrap();
- let meta_map = hashmap!(
- MetadataPath::from_role(&Role::Targets) =>
+ let snapshot = SnapshotMetadataBuilder::new()
+ .insert_metadata_description(
+ MetadataPath::from_role(&Role::Targets),
MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- );
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map).unwrap();
- let snapshot: SignedMetadata<Json, _> =
- SignedMetadata::new(snapshot, &KEYS[1]).unwrap();
+ )
+ .signed::<Json>(&KEYS[1])
+ .unwrap();
tuf.update_snapshot(snapshot).unwrap();
@@ -925,14 +921,13 @@
tuf.update_timestamp(timestamp).unwrap();
- let meta_map = hashmap!(
- MetadataPath::from_role(&Role::Targets) =>
+ let snapshot = SnapshotMetadataBuilder::new()
+ .insert_metadata_description(
+ MetadataPath::from_role(&Role::Targets),
MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- );
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map).unwrap();
- let snapshot: SignedMetadata<Json, SnapshotMetadata> =
- SignedMetadata::new(snapshot, &KEYS[1]).unwrap();
+ )
+ .signed::<Json>(&KEYS[1])
+ .unwrap();
tuf.update_snapshot(snapshot).unwrap();
@@ -967,14 +962,13 @@
tuf.update_timestamp(timestamp).unwrap();
- let meta_map = hashmap!(
- MetadataPath::from_role(&Role::Targets) =>
+ let snapshot = SnapshotMetadataBuilder::new()
+ .insert_metadata_description(
+ MetadataPath::from_role(&Role::Targets),
MetadataDescription::from_reader(&*vec![], 2, &[HashAlgorithm::Sha256]).unwrap(),
- );
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map).unwrap();
- let snapshot: SignedMetadata<Json, SnapshotMetadata> =
- SignedMetadata::new(snapshot, &KEYS[1]).unwrap();
+ )
+ .signed::<Json>(&KEYS[1])
+ .unwrap();
tuf.update_snapshot(snapshot).unwrap();
diff --git a/tests/integration.rs b/tests/integration.rs
index f732a73..700f980 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -10,7 +10,7 @@
use tuf::interchange::Json;
use tuf::metadata::{
Delegation, Delegations, MetadataDescription, MetadataPath, RootMetadataBuilder,
- SignedMetadata, SnapshotMetadata, TargetDescription, TargetsMetadata, TimestampMetadata,
+ SignedMetadata, SnapshotMetadataBuilder, TargetDescription, TargetsMetadata, TimestampMetadata,
VirtualTargetPath,
};
use tuf::Tuf;
@@ -52,16 +52,18 @@
tuf.update_timestamp(signed).unwrap();
//// build the snapshot ////
- let meta_map = hashmap! {
- MetadataPath::new("targets".into()).unwrap() =>
- MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
- MetadataPath::new("delegation".into()).unwrap() =>
- MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
- };
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map).unwrap();
- let signed = SignedMetadata::<Json, _>::new(snapshot, &snapshot_key).unwrap();
+ let signed = SnapshotMetadataBuilder::new()
+ .insert_metadata_description(
+ MetadataPath::new("targets".into()).unwrap(),
+ MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
+ )
+ .insert_metadata_description(
+ MetadataPath::new("delegation".into()).unwrap(),
+ MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
+ )
+ .signed::<Json>(&snapshot_key)
+ .unwrap();
tuf.update_snapshot(signed).unwrap();
@@ -147,18 +149,22 @@
tuf.update_timestamp(signed).unwrap();
//// build the snapshot ////
- let meta_map = hashmap! {
- MetadataPath::new("targets".into()).unwrap() =>
- MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
- MetadataPath::new("delegation-a".into()).unwrap() =>
- MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
- MetadataPath::new("delegation-b".into()).unwrap() =>
- MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
- };
- let snapshot =
- SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map).unwrap();
- let signed = SignedMetadata::<Json, _>::new(snapshot, &snapshot_key).unwrap();
+ let signed = SnapshotMetadataBuilder::new()
+ .insert_metadata_description(
+ MetadataPath::new("targets".into()).unwrap(),
+ MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
+ )
+ .insert_metadata_description(
+ MetadataPath::new("delegation-a".into()).unwrap(),
+ MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
+ )
+ .insert_metadata_description(
+ MetadataPath::new("delegation-b".into()).unwrap(),
+ MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
+ )
+ .signed::<Json>(&snapshot_key)
+ .unwrap();
tuf.update_snapshot(signed).unwrap();
diff --git a/tests/simple_example.rs b/tests/simple_example.rs
index f264d1b..6d6ed08 100644
--- a/tests/simple_example.rs
+++ b/tests/simple_example.rs
@@ -10,7 +10,7 @@
use tuf::interchange::{DataInterchange, Json};
use tuf::metadata::{
MetadataDescription, MetadataPath, MetadataVersion, RootMetadataBuilder, SignedMetadata,
- SnapshotMetadata, TargetDescription, TargetPath, TargetsMetadata, TimestampMetadata,
+ SnapshotMetadataBuilder, TargetDescription, TargetPath, TargetsMetadata, TimestampMetadata,
VirtualTargetPath,
};
use tuf::repository::{EphemeralRepository, Repository};
@@ -89,8 +89,7 @@
.snapshot_key(snapshot_key.public().clone())
.targets_key(targets_key.public().clone())
.timestamp_key(timestamp_key.public().clone())
- .signed::<Json>(&root_key)
- .unwrap();
+ .signed::<Json>(&root_key)?;
remote.store_metadata(
&MetadataPath::new("root".into())?,
@@ -127,16 +126,11 @@
&signed,
)?;
- let targets_bytes = Json::canonicalize(&Json::serialize(&signed)?)?;
-
//// build the snapshot ////
- let meta_map = hashmap! {
- MetadataPath::new("targets".into())? =>
- MetadataDescription::from_reader(&*targets_bytes, 1, &[HashAlgorithm::Sha256])?,
- };
- let snapshot = SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map)?;
- let signed = SignedMetadata::<Json, _>::new(snapshot, &snapshot_key)?;
+ let signed = SnapshotMetadataBuilder::new()
+ .insert_metadata(&signed, &[HashAlgorithm::Sha256])?
+ .signed::<Json>(&snapshot_key)?;
remote.store_metadata(
&MetadataPath::new("snapshot".into())?,