Add TimestampMetadataBuilder to simplify making TimestampMetadata
diff --git a/src/metadata.rs b/src/metadata.rs
index 5713be8..68b47bf 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -257,20 +257,22 @@
/// # use chrono::prelude::*;
/// # use tuf::crypto::{PrivateKey, SignatureScheme, HashAlgorithm};
/// # use tuf::interchange::Json;
- /// # use tuf::metadata::{MetadataDescription, TimestampMetadata, SignedMetadata};
+ /// # use tuf::metadata::{MetadataDescription, TimestampMetadataBuilder};
/// #
/// # fn main() {
/// # let key: &[u8] = include_bytes!("../tests/ed25519/ed25519-1.pk8.der");
/// let key = PrivateKey::from_pkcs8(&key, SignatureScheme::Ed25519).unwrap();
///
- /// let timestamp = TimestampMetadata::new(
+ /// let description = MetadataDescription::from_reader(
+ /// &[0x01, 0x02, 0x03][..],
/// 1,
- /// Utc.ymd(2017, 1, 1).and_hms(0, 0, 0),
- /// MetadataDescription::from_reader(&*vec![0x01, 0x02, 0x03], 1,
- /// &[HashAlgorithm::Sha256]).unwrap()
+ /// &[HashAlgorithm::Sha256]
/// ).unwrap();
///
- /// SignedMetadata::<Json, _>::new(timestamp, &key).unwrap();
+ /// let timestamp = TimestampMetadataBuilder::from_metadata_description(description)
+ /// .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+ /// .signed::<Json>(&key)
+ /// .unwrap();
/// # }
/// ```
pub fn new(metadata: M, private_key: &PrivateKey) -> Result<SignedMetadata<D, M>> {
@@ -934,6 +936,78 @@
}
}
+/// Helper to construct `TimestampMetadata`.
+pub struct TimestampMetadataBuilder {
+ version: u32,
+ expires: DateTime<Utc>,
+ snapshot: MetadataDescription,
+}
+
+impl TimestampMetadataBuilder {
+ /// Create a new `TimestampMetadataBuilder` from a given snapshot. It defaults to:
+ ///
+ /// * version: 1
+ /// * expires: 1 day from the current time.
+ pub fn from_snapshot<D, M>(
+ snapshot: &SignedMetadata<D, M>,
+ hash_algs: &[HashAlgorithm],
+ ) -> Result<Self>
+ where
+ D: DataInterchange,
+ M: Metadata,
+ {
+ let bytes = D::canonicalize(&D::serialize(&snapshot)?)?;
+ let description = MetadataDescription::from_reader(
+ &*bytes,
+ snapshot.version(),
+ hash_algs,
+ )?;
+
+ Ok(Self::from_metadata_description(description))
+ }
+
+ /// Create a new `TimestampMetadataBuilder` from a given
+ /// `MetadataDescription`. It defaults to:
+ ///
+ /// * version: 1
+ /// * expires: 1 day from the current time.
+ pub fn from_metadata_description(description: MetadataDescription) -> Self {
+ TimestampMetadataBuilder {
+ version: 1,
+ expires: Utc::now() + Duration::days(1),
+ snapshot: description,
+ }
+ }
+
+ /// 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
+ }
+
+ /// Construct a new `TimestampMetadata`.
+ pub fn build(self) -> Result<TimestampMetadata> {
+ TimestampMetadata::new(
+ self.version,
+ self.expires,
+ self.snapshot,
+ )
+ }
+
+ /// Construct a new `SignedMetadata<D, TimestampMetadata>`.
+ pub fn signed<D>(self, private_key: &PrivateKey) -> Result<SignedMetadata<D, TimestampMetadata>>
+ where D: DataInterchange,
+ {
+ Ok(SignedMetadata::new(self.build()?, private_key)?)
+ }
+}
+
/// Metadata for the timestamp role.
#[derive(Debug, Clone, PartialEq)]
pub struct TimestampMetadata {
@@ -1942,16 +2016,17 @@
#[test]
fn serde_timestamp_metadata() {
- let timestamp = TimestampMetadata::new(
+ let description = MetadataDescription::new(
1,
- Utc.ymd(2017, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::new(
- 1,
- 100,
- hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
- ).unwrap(),
+ 100,
+ hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
).unwrap();
+ let timestamp = TimestampMetadataBuilder::from_metadata_description(description)
+ .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+ .build()
+ .unwrap();
+
let jsn = json!({
"type": "timestamp",
"version": 1,
@@ -2203,12 +2278,17 @@
}
fn make_timestamp() -> json::Value {
- let timestamp = TimestampMetadata::new(
+ let description = MetadataDescription::from_reader(
+ &[][..],
1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
+ &[HashAlgorithm::Sha256],
).unwrap();
+ let timestamp = TimestampMetadataBuilder::from_metadata_description(description)
+ .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+ .build()
+ .unwrap();
+
json::to_value(×tamp).unwrap()
}
diff --git a/src/tuf.rs b/src/tuf.rs
index f7e2311..d285d6d 100644
--- a/src/tuf.rs
+++ b/src/tuf.rs
@@ -616,7 +616,12 @@
use chrono::prelude::*;
use crypto::{HashAlgorithm, PrivateKey, SignatureScheme};
use interchange::Json;
- use metadata::{MetadataDescription, RootMetadataBuilder, SnapshotMetadataBuilder};
+ use metadata::{
+ MetadataDescription,
+ RootMetadataBuilder,
+ SnapshotMetadataBuilder,
+ TimestampMetadataBuilder,
+ };
lazy_static! {
static ref KEYS: Vec<PrivateKey> = {
@@ -726,13 +731,14 @@
let mut tuf = Tuf::from_root(root).unwrap();
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
- let timestamp: SignedMetadata<Json, TimestampMetadata> =
- SignedMetadata::new(timestamp, &KEYS[1]).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .signed::<Json>(&KEYS[1])
+ .unwrap();
+
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(&KEYS[1])
+ .unwrap();
assert_eq!(tuf.update_timestamp(timestamp.clone()), Ok(true));
@@ -752,15 +758,15 @@
let mut tuf = Tuf::from_root(root).unwrap();
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .signed::<Json>(&KEYS[1])
+ .unwrap();
- // sign it with the root key
- let timestamp: SignedMetadata<Json, TimestampMetadata> =
- SignedMetadata::new(timestamp, &KEYS[0]).unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ // sign it with the root key
+ .signed::<Json>(&KEYS[0])
+ .unwrap();
assert!(tuf.update_timestamp(timestamp).is_err())
}
@@ -777,20 +783,17 @@
let mut tuf = Tuf::from_root(root).unwrap();
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
- let timestamp: SignedMetadata<Json, TimestampMetadata> =
- SignedMetadata::new(timestamp, &KEYS[2]).unwrap();
-
- tuf.update_timestamp(timestamp).unwrap();
-
let snapshot = SnapshotMetadataBuilder::new()
.signed(&KEYS[1])
.unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
+
+ tuf.update_timestamp(timestamp).unwrap();
+
assert_eq!(tuf.update_snapshot(snapshot.clone()), Ok(true));
// second update should do nothing
@@ -809,20 +812,17 @@
let mut tuf = Tuf::from_root(root).unwrap();
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
- let timestamp: SignedMetadata<Json, TimestampMetadata> =
- SignedMetadata::new(timestamp, &KEYS[2]).unwrap();
-
- tuf.update_timestamp(timestamp).unwrap();
-
let snapshot = SnapshotMetadataBuilder::new()
.signed::<Json>(&KEYS[2])
.unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
+
+ tuf.update_timestamp(timestamp).unwrap();
+
assert!(tuf.update_snapshot(snapshot).is_err());
}
@@ -838,13 +838,15 @@
let mut tuf = Tuf::from_root(root).unwrap();
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 2, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
- let timestamp: SignedMetadata<Json, TimestampMetadata> =
- SignedMetadata::new(timestamp, &KEYS[2]).unwrap();
+ let snapshot = SnapshotMetadataBuilder::new()
+ .version(2)
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
+
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(&KEYS[2])
+ .unwrap();
tuf.update_timestamp(timestamp).unwrap();
@@ -865,18 +867,6 @@
.signed::<Json>(&KEYS[0])
.unwrap();
- let mut tuf = Tuf::from_root(root).unwrap();
-
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
- let timestamp: SignedMetadata<Json, _> =
- SignedMetadata::new(timestamp, &KEYS[3]).unwrap();
-
- tuf.update_timestamp(timestamp).unwrap();
-
let snapshot = SnapshotMetadataBuilder::new()
.insert_metadata_description(
MetadataPath::from_role(&Role::Targets),
@@ -885,6 +875,14 @@
.signed::<Json>(&KEYS[1])
.unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(&KEYS[3])
+ .unwrap();
+
+ let mut tuf = Tuf::from_root(root).unwrap();
+
+ tuf.update_timestamp(timestamp).unwrap();
tuf.update_snapshot(snapshot).unwrap();
let targets =
@@ -911,16 +909,6 @@
let mut tuf = Tuf::from_root(root).unwrap();
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
- let timestamp: SignedMetadata<Json, TimestampMetadata> =
- SignedMetadata::new(timestamp, &KEYS[3]).unwrap();
-
- tuf.update_timestamp(timestamp).unwrap();
-
let snapshot = SnapshotMetadataBuilder::new()
.insert_metadata_description(
MetadataPath::from_role(&Role::Targets),
@@ -929,6 +917,12 @@
.signed::<Json>(&KEYS[1])
.unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(&KEYS[3])
+ .unwrap();
+
+ tuf.update_timestamp(timestamp).unwrap();
tuf.update_snapshot(snapshot).unwrap();
let targets =
@@ -952,16 +946,6 @@
let mut tuf = Tuf::from_root(root).unwrap();
- let timestamp = TimestampMetadata::new(
- 1,
- Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
- MetadataDescription::from_reader(&*vec![], 1, &[HashAlgorithm::Sha256]).unwrap(),
- ).unwrap();
- let timestamp: SignedMetadata<Json, TimestampMetadata> =
- SignedMetadata::new(timestamp, &KEYS[3]).unwrap();
-
- tuf.update_timestamp(timestamp).unwrap();
-
let snapshot = SnapshotMetadataBuilder::new()
.insert_metadata_description(
MetadataPath::from_role(&Role::Targets),
@@ -970,6 +954,12 @@
.signed::<Json>(&KEYS[1])
.unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(&KEYS[3])
+ .unwrap();
+
+ tuf.update_timestamp(timestamp).unwrap();
tuf.update_snapshot(snapshot).unwrap();
let targets =
diff --git a/tests/integration.rs b/tests/integration.rs
index 700f980..8cd4455 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -9,8 +9,9 @@
use tuf::crypto::{HashAlgorithm, PrivateKey, SignatureScheme};
use tuf::interchange::Json;
use tuf::metadata::{
- Delegation, Delegations, MetadataDescription, MetadataPath, RootMetadataBuilder,
- SignedMetadata, SnapshotMetadataBuilder, TargetDescription, TargetsMetadata, TimestampMetadata,
+ Delegation, Delegations, MetadataDescription, MetadataPath,
+ RootMetadataBuilder, SignedMetadata, SnapshotMetadataBuilder,
+ TargetDescription, TargetsMetadata, TimestampMetadataBuilder,
VirtualTargetPath,
};
use tuf::Tuf;
@@ -32,7 +33,7 @@
//// build the root ////
- let signed = RootMetadataBuilder::new()
+ let root = RootMetadataBuilder::new()
.root_key(root_key.public().clone())
.snapshot_key(snapshot_key.public().clone())
.targets_key(targets_key.public().clone())
@@ -40,20 +41,11 @@
.signed::<Json>(&root_key)
.unwrap();
- let mut tuf = Tuf::<Json>::from_root_pinned(signed, &[root_key.key_id().clone()]).unwrap();
+ let mut tuf = Tuf::<Json>::from_root_pinned(root, &[root_key.key_id().clone()]).unwrap();
- //// build the timestamp ////
- let snap = MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap();
- let timestamp = TimestampMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), snap).unwrap();
+ //// build the snapshot and timestamp ////
- let signed =
- SignedMetadata::<Json, _>::new(timestamp, ×tamp_key).unwrap();
-
- tuf.update_timestamp(signed).unwrap();
-
- //// build the snapshot ////
-
- let signed = SnapshotMetadataBuilder::new()
+ let snapshot = SnapshotMetadataBuilder::new()
.insert_metadata_description(
MetadataPath::new("targets".into()).unwrap(),
MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
@@ -65,7 +57,13 @@
.signed::<Json>(&snapshot_key)
.unwrap();
- tuf.update_snapshot(signed).unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(×tamp_key)
+ .unwrap();
+
+ tuf.update_timestamp(timestamp).unwrap();
+ tuf.update_snapshot(snapshot).unwrap();
//// build the targets ////
let delegations = Delegations::new(
@@ -129,7 +127,7 @@
//// build the root ////
- let signed = RootMetadataBuilder::new()
+ let root = RootMetadataBuilder::new()
.root_key(root_key.public().clone())
.snapshot_key(snapshot_key.public().clone())
.targets_key(targets_key.public().clone())
@@ -137,20 +135,11 @@
.signed::<Json>(&root_key)
.unwrap();
- let mut tuf = Tuf::<Json>::from_root_pinned(signed, &[root_key.key_id().clone()]).unwrap();
+ let mut tuf = Tuf::<Json>::from_root_pinned(root, &[root_key.key_id().clone()]).unwrap();
- //// build the timestamp ////
- let snap = MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap();
- let timestamp = TimestampMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), snap).unwrap();
+ //// build the snapshot and timestamp ////
- let signed =
- SignedMetadata::<Json, _>::new(timestamp, ×tamp_key).unwrap();
-
- tuf.update_timestamp(signed).unwrap();
-
- //// build the snapshot ////
-
- let signed = SnapshotMetadataBuilder::new()
+ let snapshot = SnapshotMetadataBuilder::new()
.insert_metadata_description(
MetadataPath::new("targets".into()).unwrap(),
MetadataDescription::from_reader(&*vec![0u8], 1, &[HashAlgorithm::Sha256]).unwrap(),
@@ -166,9 +155,16 @@
.signed::<Json>(&snapshot_key)
.unwrap();
- tuf.update_snapshot(signed).unwrap();
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
+ .unwrap()
+ .signed::<Json>(×tamp_key)
+ .unwrap();
+
+ tuf.update_timestamp(timestamp).unwrap();
+ tuf.update_snapshot(snapshot).unwrap();
//// build the targets ////
+
let delegations = Delegations::new(
&hashset![delegation_a_key.public().clone()],
vec![
@@ -199,6 +195,7 @@
tuf.update_targets(signed).unwrap();
//// build delegation A ////
+
let delegations = Delegations::new(
&hashset![delegation_b_key.public().clone()],
vec![
@@ -231,6 +228,7 @@
.unwrap();
//// build delegation B ////
+
let target_file: &[u8] = b"bar";
let target_map = hashmap! {
VirtualTargetPath::new("foo".into()).unwrap() =>
diff --git a/tests/simple_example.rs b/tests/simple_example.rs
index 6d6ed08..e2b4028 100644
--- a/tests/simple_example.rs
+++ b/tests/simple_example.rs
@@ -7,11 +7,11 @@
use chrono::prelude::*;
use tuf::client::{Client, Config, PathTranslator};
use tuf::crypto::{HashAlgorithm, KeyId, PrivateKey, SignatureScheme};
-use tuf::interchange::{DataInterchange, Json};
+use tuf::interchange::Json;
use tuf::metadata::{
- MetadataDescription, MetadataPath, MetadataVersion, RootMetadataBuilder, SignedMetadata,
- SnapshotMetadataBuilder, TargetDescription, TargetPath, TargetsMetadata, TimestampMetadata,
- VirtualTargetPath,
+ MetadataPath, MetadataVersion, RootMetadataBuilder, SignedMetadata,
+ SnapshotMetadataBuilder, TargetDescription, TargetPath, TargetsMetadata,
+ TimestampMetadataBuilder, VirtualTargetPath,
};
use tuf::repository::{EphemeralRepository, Repository};
use tuf::Result;
@@ -128,38 +128,35 @@
//// build the snapshot ////
- let signed = SnapshotMetadataBuilder::new()
+ let snapshot = SnapshotMetadataBuilder::new()
.insert_metadata(&signed, &[HashAlgorithm::Sha256])?
.signed::<Json>(&snapshot_key)?;
remote.store_metadata(
&MetadataPath::new("snapshot".into())?,
&MetadataVersion::Number(1),
- &signed,
+ &snapshot,
)?;
remote.store_metadata(
&MetadataPath::new("snapshot".into())?,
&MetadataVersion::None,
- &signed,
+ &snapshot,
)?;
- let snapshot_bytes = Json::canonicalize(&Json::serialize(&signed)?)?;
-
//// build the timestamp ////
- let snap = MetadataDescription::from_reader(&*snapshot_bytes, 1, &[HashAlgorithm::Sha256])?;
- let timestamp = TimestampMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), snap)?;
- let signed = SignedMetadata::<Json, _>::new(timestamp, ×tamp_key)?;
+ let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])?
+ .signed::<Json>(×tamp_key)?;
remote.store_metadata(
&MetadataPath::new("timestamp".into())?,
&MetadataVersion::Number(1),
- &signed,
+ ×tamp,
)?;
remote.store_metadata(
&MetadataPath::new("timestamp".into())?,
&MetadataVersion::None,
- &signed,
+ ×tamp,
)?;
Ok(vec![root_key.key_id().clone()])