Add TargetsMetadataBuilder to simplify making TargetsMetadata
diff --git a/src/metadata.rs b/src/metadata.rs
index 6bbb1da..dbc5770 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -1613,6 +1613,88 @@
}
}
+/// Helper to construct `TargetsMetadata`.
+pub struct TargetsMetadataBuilder {
+ version: u32,
+ expires: DateTime<Utc>,
+ targets: HashMap<VirtualTargetPath, TargetDescription>,
+ delegations: Option<Delegations>,
+}
+
+impl TargetsMetadataBuilder {
+ /// Create a new `TargetsMetadata`. It defaults to:
+ ///
+ /// * version: 1
+ /// * expires: 90 days from the current time.
+ pub fn new() -> Self {
+ TargetsMetadataBuilder {
+ version: 1,
+ expires: Utc::now() + Duration::days(90),
+ targets: HashMap::new(),
+ delegations: None,
+ }
+ }
+
+ /// 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 target to the target metadata.
+ pub fn insert_target_from_reader<R>(
+ self,
+ path: VirtualTargetPath,
+ read: R,
+ hash_algs: &[HashAlgorithm],
+ ) -> Result<Self>
+ where
+ R: Read,
+ {
+ let description = TargetDescription::from_reader(read, hash_algs)?;
+ Ok(self.insert_target_description(path, description))
+ }
+
+ /// Add `TargetDescription` to this target metadata target description.
+ pub fn insert_target_description(
+ mut self,
+ path: VirtualTargetPath,
+ description: TargetDescription,
+ ) -> Self {
+ self.targets.insert(path, description);
+ self
+ }
+
+ /// Add `Delegatiuons` to this target metadata.
+ pub fn delegations(mut self, delegations: Delegations) -> Self {
+ self.delegations = Some(delegations);
+ self
+ }
+
+ /// Construct a new `TargetsMetadata`.
+ pub fn build(self) -> Result<TargetsMetadata> {
+ TargetsMetadata::new(
+ self.version,
+ self.expires,
+ self.targets,
+ self.delegations,
+ )
+ }
+
+ /// Construct a new `SignedMetadata<D, TargetsMetadata>`.
+ pub fn signed<D>(self, private_key: &PrivateKey) -> Result<SignedMetadata<D, TargetsMetadata>>
+ where D: DataInterchange,
+ {
+ Ok(SignedMetadata::new(self.build()?, private_key)?)
+ }
+}
+
/// Wrapper to described a collections of delegations.
#[derive(Debug, PartialEq, Clone)]
pub struct Delegations {
@@ -2066,18 +2148,17 @@
#[test]
fn serde_targets_metadata() {
- let targets = TargetsMetadata::new(
- 1,
- Utc.ymd(2017, 1, 1).and_hms(0, 0, 0),
- hashmap! {
- VirtualTargetPath::new("foo".into()).unwrap() =>
- TargetDescription::from_reader(
- b"foo" as &[u8],
- &[HashAlgorithm::Sha256],
- ).unwrap(),
- },
- None,
- ).unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+ .insert_target_description(
+ VirtualTargetPath::new("foo".into()).unwrap(),
+ TargetDescription::from_reader(
+ &b"foo"[..],
+ &[HashAlgorithm::Sha256],
+ ).unwrap(),
+ )
+ .build()
+ .unwrap();
let jsn = json!({
"type": "targets",
@@ -2115,12 +2196,11 @@
],
).unwrap();
- let targets = TargetsMetadata::new(
- 1,
- Utc.ymd(2017, 1, 1).and_hms(0, 0, 0),
- HashMap::new(),
- Some(delegations),
- ).unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+ .delegations(delegations)
+ .build()
+ .unwrap();
let jsn = json!({
"type": "targets",
diff --git a/src/tuf.rs b/src/tuf.rs
index d285d6d..a5c60d6 100644
--- a/src/tuf.rs
+++ b/src/tuf.rs
@@ -613,14 +613,13 @@
#[cfg(test)]
mod test {
use super::*;
- use chrono::prelude::*;
use crypto::{HashAlgorithm, PrivateKey, SignatureScheme};
use interchange::Json;
use metadata::{
- MetadataDescription,
RootMetadataBuilder,
SnapshotMetadataBuilder,
TimestampMetadataBuilder,
+ TargetsMetadataBuilder,
};
lazy_static! {
@@ -818,6 +817,7 @@
let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
.unwrap()
+ // sign it with the targets key
.signed::<Json>(&KEYS[2])
.unwrap();
@@ -851,6 +851,7 @@
tuf.update_timestamp(timestamp).unwrap();
let snapshot = SnapshotMetadataBuilder::new()
+ .version(1)
.signed::<Json>(&KEYS[1])
.unwrap();
@@ -867,11 +868,12 @@
.signed::<Json>(&KEYS[0])
.unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
+
let snapshot = SnapshotMetadataBuilder::new()
- .insert_metadata_description(
- MetadataPath::from_role(&Role::Targets),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- )
+ .insert_metadata(&targets, &[HashAlgorithm::Sha256]).unwrap()
.signed::<Json>(&KEYS[1])
.unwrap();
@@ -885,12 +887,6 @@
tuf.update_timestamp(timestamp).unwrap();
tuf.update_snapshot(snapshot).unwrap();
- let targets =
- TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), hashmap!(), None)
- .unwrap();
- let targets: SignedMetadata<Json, _> =
- SignedMetadata::new(targets, &KEYS[2]).unwrap();
-
assert_eq!(tuf.update_targets(targets.clone()), Ok(true));
// second update should do nothing
@@ -909,11 +905,13 @@
let mut tuf = Tuf::from_root(root).unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ // sign it with the timestamp key
+ .signed::<Json>(&KEYS[3])
+ .unwrap();
+
let snapshot = SnapshotMetadataBuilder::new()
- .insert_metadata_description(
- MetadataPath::from_role(&Role::Targets),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- )
+ .insert_metadata(&targets, &[HashAlgorithm::Sha256]).unwrap()
.signed::<Json>(&KEYS[1])
.unwrap();
@@ -925,12 +923,6 @@
tuf.update_timestamp(timestamp).unwrap();
tuf.update_snapshot(snapshot).unwrap();
- let targets =
- TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), hashmap!(), None)
- .unwrap();
- let targets: SignedMetadata<Json, TargetsMetadata> =
- SignedMetadata::new(targets, &KEYS[3]).unwrap();
-
assert!(tuf.update_targets(targets).is_err());
}
@@ -946,11 +938,13 @@
let mut tuf = Tuf::from_root(root).unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ .version(2)
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
+
let snapshot = SnapshotMetadataBuilder::new()
- .insert_metadata_description(
- MetadataPath::from_role(&Role::Targets),
- MetadataDescription::from_reader(&*vec![], 2, &[HashAlgorithm::Sha256]).unwrap(),
- )
+ .insert_metadata(&targets, &[HashAlgorithm::Sha256]).unwrap()
.signed::<Json>(&KEYS[1])
.unwrap();
@@ -962,11 +956,10 @@
tuf.update_timestamp(timestamp).unwrap();
tuf.update_snapshot(snapshot).unwrap();
- let targets =
- TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), hashmap!(), None)
- .unwrap();
- let targets: SignedMetadata<Json, TargetsMetadata> =
- SignedMetadata::new(targets, &KEYS[2]).unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ .version(1)
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
assert!(tuf.update_targets(targets).is_err());
}
diff --git a/tests/integration.rs b/tests/integration.rs
index 8cd4455..ac0dcd6 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -1,17 +1,13 @@
-extern crate chrono;
#[macro_use]
extern crate maplit;
extern crate tuf;
-use chrono::offset::Utc;
-use chrono::prelude::*;
-use std::collections::HashMap;
use tuf::crypto::{HashAlgorithm, PrivateKey, SignatureScheme};
use tuf::interchange::Json;
use tuf::metadata::{
Delegation, Delegations, MetadataDescription, MetadataPath,
- RootMetadataBuilder, SignedMetadata, SnapshotMetadataBuilder,
- TargetDescription, TargetsMetadata, TimestampMetadataBuilder,
+ RootMetadataBuilder, SnapshotMetadataBuilder,
+ TargetsMetadataBuilder, TimestampMetadataBuilder,
VirtualTargetPath,
};
use tuf::Tuf;
@@ -84,30 +80,25 @@
).unwrap(),
],
).unwrap();
- let targets = TargetsMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- HashMap::new(),
- Some(delegations),
- ).unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ .delegations(delegations)
+ .signed::<Json>(&targets_key)
+ .unwrap();
- let signed = SignedMetadata::<Json, _>::new(targets, &targets_key).unwrap();
-
- tuf.update_targets(signed).unwrap();
+ tuf.update_targets(targets).unwrap();
//// build the delegation ////
let target_file: &[u8] = b"bar";
- let target_map = hashmap! {
- VirtualTargetPath::new("foo".into()).unwrap() =>
- TargetDescription::from_reader(target_file, &[HashAlgorithm::Sha256]).unwrap(),
- };
- let delegation =
- TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), target_map, None).unwrap();
+ let delegation = TargetsMetadataBuilder::new()
+ .insert_target_from_reader(
+ VirtualTargetPath::new("foo".into()).unwrap(),
+ target_file,
+ &[HashAlgorithm::Sha256],
+ ).unwrap()
+ .signed::<Json>(&delegation_key)
+ .unwrap();
- let signed =
- SignedMetadata::<Json, _>::new(delegation, &delegation_key).unwrap();
-
- tuf.update_delegation(&MetadataPath::new("delegation".into()).unwrap(), signed)
+ tuf.update_delegation(&MetadataPath::new("delegation".into()).unwrap(), delegation)
.unwrap();
assert!(
@@ -183,16 +174,12 @@
).unwrap(),
],
).unwrap();
- let targets = TargetsMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- HashMap::new(),
- Some(delegations),
- ).unwrap();
+ let targets = TargetsMetadataBuilder::new()
+ .delegations(delegations)
+ .signed::<Json>(&targets_key)
+ .unwrap();
- let signed = SignedMetadata::<Json, _>::new(targets, &targets_key).unwrap();
-
- tuf.update_targets(signed).unwrap();
+ tuf.update_targets(targets).unwrap();
//// build delegation A ////
@@ -214,34 +201,29 @@
).unwrap(),
],
).unwrap();
- let delegation = TargetsMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- HashMap::new(),
- Some(delegations),
- ).unwrap();
- let signed =
- SignedMetadata::<Json, _>::new(delegation, &delegation_a_key).unwrap();
+ let delegation = TargetsMetadataBuilder::new()
+ .delegations(delegations)
+ .signed::<Json>(&delegation_a_key)
+ .unwrap();
- tuf.update_delegation(&MetadataPath::new("delegation-a".into()).unwrap(), signed)
+ tuf.update_delegation(&MetadataPath::new("delegation-a".into()).unwrap(), delegation)
.unwrap();
//// build delegation B ////
let target_file: &[u8] = b"bar";
- let target_map = hashmap! {
- VirtualTargetPath::new("foo".into()).unwrap() =>
- TargetDescription::from_reader(target_file, &[HashAlgorithm::Sha256]).unwrap(),
- };
- let delegation =
- TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), target_map, None).unwrap();
+ let delegation = TargetsMetadataBuilder::new()
+ .insert_target_from_reader(
+ VirtualTargetPath::new("foo".into()).unwrap(),
+ target_file,
+ &[HashAlgorithm::Sha256],
+ ).unwrap()
+ .signed::<Json>(&delegation_b_key)
+ .unwrap();
- let signed =
- SignedMetadata::<Json, _>::new(delegation, &delegation_b_key).unwrap();
-
- tuf.update_delegation(&MetadataPath::new("delegation-b".into()).unwrap(), signed)
+ tuf.update_delegation(&MetadataPath::new("delegation-b".into()).unwrap(), delegation)
.unwrap();
assert!(
diff --git a/tests/simple_example.rs b/tests/simple_example.rs
index e2b4028..2b1d639 100644
--- a/tests/simple_example.rs
+++ b/tests/simple_example.rs
@@ -1,16 +1,12 @@
extern crate chrono;
-#[macro_use]
-extern crate maplit;
extern crate tuf;
-use chrono::offset::Utc;
-use chrono::prelude::*;
use tuf::client::{Client, Config, PathTranslator};
use tuf::crypto::{HashAlgorithm, KeyId, PrivateKey, SignatureScheme};
use tuf::interchange::Json;
use tuf::metadata::{
- MetadataPath, MetadataVersion, RootMetadataBuilder, SignedMetadata,
- SnapshotMetadataBuilder, TargetDescription, TargetPath, TargetsMetadata,
+ MetadataPath, MetadataVersion, RootMetadataBuilder,
+ SnapshotMetadataBuilder, TargetPath, TargetsMetadataBuilder,
TimestampMetadataBuilder, VirtualTargetPath,
};
use tuf::repository::{EphemeralRepository, Repository};
@@ -105,31 +101,33 @@
//// build the targets ////
let target_file: &[u8] = b"things fade, alternatives exclude";
+
let target_path = TargetPath::new("foo-bar".into())?;
- let target_description = TargetDescription::from_reader(target_file, &[HashAlgorithm::Sha256])?;
let _ = remote.store_target(target_file, &target_path);
- let target_map =
- hashmap!(config.path_translator().real_to_virtual(&target_path)? => target_description);
- let targets = TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), target_map, None)?;
-
- let signed = SignedMetadata::<Json, _>::new(targets, &targets_key)?;
+ let targets = TargetsMetadataBuilder::new()
+ .insert_target_from_reader(
+ config.path_translator().real_to_virtual(&target_path)?,
+ target_file,
+ &[HashAlgorithm::Sha256],
+ )?
+ .signed::<Json>(&targets_key)?;
remote.store_metadata(
&MetadataPath::new("targets".into())?,
&MetadataVersion::Number(1),
- &signed,
+ &targets,
)?;
remote.store_metadata(
&MetadataPath::new("targets".into())?,
&MetadataVersion::None,
- &signed,
+ &targets,
)?;
//// build the snapshot ////
let snapshot = SnapshotMetadataBuilder::new()
- .insert_metadata(&signed, &[HashAlgorithm::Sha256])?
+ .insert_metadata(&targets, &[HashAlgorithm::Sha256])?
.signed::<Json>(&snapshot_key)?;
remote.store_metadata(