diff --git a/src/error.rs b/src/error.rs index 1a1adcc8..9b40ef5c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -34,6 +34,11 @@ pub enum Error { path: DisplayPath, source: serde_yaml::Error, }, + #[snafu(display("key provided multiple times: `{key}`"))] + DuplicateKey { + backtrace: Option, + key: PublicKey, + }, #[snafu(display("{count} mismatched file{}", if *count == 1 { "" } else { "s" }))] EntryMismatch { backtrace: Option, diff --git a/src/subcommand/verify.rs b/src/subcommand/verify.rs index 86f989f9..e10dff08 100644 --- a/src/subcommand/verify.rs +++ b/src/subcommand/verify.rs @@ -6,8 +6,12 @@ pub(crate) struct Verify { fingerprint: Option, #[arg(help = "Ignore missing files", long)] ignore_missing: bool, - #[arg(help = "Verify that manifest has been signed by ", long)] - key: Option, + #[arg( + help = "Verify that manifest has been signed by ", + long = "key", + value_name = "KEY" + )] + keys: Vec, #[arg( help = "Read manifest from , defaults to `/filepack.json`", long @@ -202,7 +206,16 @@ mismatched file: `{path}` verified.signatures += 1; } - if let Some(key) = self.key { + let mut keys = BTreeSet::new(); + + for key in &self.keys { + ensure! { + keys.insert(key.clone()), + error::DuplicateKey { key: key.clone() }, + } + } + + for key in self.keys { ensure! { manifest.signatures.contains_key(&key), error::SignatureMissing { key }, diff --git a/tests/verify.rs b/tests/verify.rs index 0d0bd398..d9873ed5 100644 --- a/tests/verify.rs +++ b/tests/verify.rs @@ -1,5 +1,24 @@ use super::*; +#[test] +fn duplicate_key() { + Test::new() + .args(["create"]) + .success() + .args([ + "verify", + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + ]) + .stderr( + "error: key provided multiple times: \ + `7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b`\n", + ) + .failure(); +} + #[test] fn extra_fields_are_not_allowed() { Test::new() @@ -232,6 +251,65 @@ fn missing_signature_error() { .failure(); } +#[test] +fn multiple_keys() { + let test = Test::new() + .data_dir("alice") + .args(["keygen"]) + .success() + .data_dir("bob") + .args(["keygen"]) + .success() + .touch("foo/bar") + .args(["create", "foo"]) + .success() + .data_dir("alice") + .args(["sign", "foo"]) + .success() + .data_dir("bob") + .args(["sign", "foo"]) + .success(); + + let alice = test.read("alice/keys/master.public"); + let bob = test.read("bob/keys/master.public"); + + test + .args(["verify", "foo", "--key", &alice, "--key", &bob]) + .stderr("successfully verified 1 file totaling 0 bytes with 2 signatures\n") + .success(); +} + +#[test] +fn multiple_keys_one_missing() { + let test = Test::new() + .data_dir("alice") + .args(["keygen"]) + .success() + .touch("foo/bar") + .args(["create", "foo"]) + .success() + .data_dir("alice") + .args(["sign", "foo/filepack.json"]) + .success(); + + let alice = test.read("alice/keys/master.public"); + + test + .args([ + "verify", + "foo", + "--key", + &alice, + "--key", + "7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b", + ]) + .stderr( + "error: no signature found for key \ + 7f1420cdc898f9370fd196b9e8e5606a7992fab5144fc1873d91b8c65ef5db6b\n", + ) + .failure(); +} + #[test] fn multiple_mismatches() { Test::new()