diff --git a/NEWS b/NEWS index 13708b2e..d6ea3efc 100644 --- a/NEWS +++ b/NEWS @@ -65,6 +65,10 @@ has its desired name. There are two benefits: no one sees partially written files, and one can safely use the same file as input and output. + - `sq download --signature` is now called `sq download + --signature-url`. + - `sq download` now requires one of `--signature-url`, `--message`, + or `--cleartext` like `sq verify`. * Changes in 0.41.0 ** New functionality diff --git a/src/cli/download.rs b/src/cli/download.rs index d60d903b..4a1e2257 100644 --- a/src/cli/download.rs +++ b/src/cli/download.rs @@ -1,6 +1,6 @@ //! Command-line parser for `sq download`. -use clap::Parser; +use clap::{ArgGroup, Parser}; use crate::cli::examples; use examples::Action; @@ -21,7 +21,7 @@ const EXAMPLES: Actions = Actions { ).command(&[ "sq", "download", "--url=file://debian/SHA512SUMS", - "--signature=file://debian/SHA512SUMS.sign", + "--signature-url=file://debian/SHA512SUMS.sign", "--signer=DF9B9C49EAA9298432589D76DA87E80D6294BE9B", "--output=SHA512SUMS", ]).build(), @@ -42,6 +42,8 @@ authenticated, the data is deleted, if possible. ", after_help = EXAMPLES, )] +#[clap(group(ArgGroup::new("kind") + .args(&["detached", "message", "cleartext"]).required(true)))] pub struct Command { #[clap( long = "url", @@ -51,7 +53,7 @@ pub struct Command { pub url: String, #[clap( - long = "signature", + long = "signature-url", value_name = "URL", help = "URL of the signature", long_help = "\ @@ -63,7 +65,21 @@ If no signature is specified, then the signature is assumed to be \ inline. ", )] - pub signature: Option, + pub detached: Option, + + #[clap( + long = "message", + value_name = "SIG", + help = "Verify an inline signed message" + )] + pub message: bool, + + #[clap( + long = "cleartext", + value_name = "SIG", + help = "Verify a cleartext-signed message" + )] + pub cleartext: bool, #[command(flatten)] pub signers: CertDesignators Result<()> { let url = c.url; - let signature = c.signature; + let signature_url = c.detached; let signatures = c.signatures; let signers = sq.resolve_certs_or_fail(&c.signers, sequoia_wot::FULLY_TRUSTED)?; @@ -285,9 +285,10 @@ pub fn dispatch(sq: Sq, c: download::Command) // than 'static. Instead, we set up a scoped thread, which can // use variables with lifetimes less than static, and then do the // processing there. + let signature_url_ = signature_url.clone(); let (mut data_file, signature_file) = std::thread::scope(|scope| { // Schedule the download of the signature. - if let Some(ref url) = signature { + if let Some(ref url) = signature_url_ { let sig_file = tempfile::NamedTempFile::new()?; let getter = get!( @@ -508,7 +509,7 @@ pub fn dispatch(sq: Sq, c: download::Command) "Internal error while downloading data file")); }; - if signature.is_some() && signature_file.is_none() { + if signature_url_.is_some() && signature_file.is_none() { return Err(anyhow::anyhow!( "Internal error while downloading signature file")); } @@ -533,6 +534,8 @@ pub fn dispatch(sq: Sq, c: download::Command) data_file.as_ref().try_clone()?, data_file.path(), Default::default())?.into_boxed(), signature_file.as_ref().map(|f| f.path().to_path_buf()), + "--signature-url", + signature_url.map(PathBuf::from), &mut output_file, signatures, signers); diff --git a/src/commands/verify.rs b/src/commands/verify.rs index d5afa0cb..5145d2cc 100644 --- a/src/commands/verify.rs +++ b/src/commands/verify.rs @@ -42,6 +42,8 @@ pub fn dispatch(sq: Sq, command: cli::verify::Command) sq.resolve_certs_or_fail(&command.signers, sequoia_wot::FULLY_TRUSTED)?; let result = verify(sq, input, + command.detached.clone(), + "--signature-file", command.detached, &mut output, signatures, signers); if result.is_err() { @@ -63,6 +65,8 @@ pub fn dispatch(sq: Sq, command: cli::verify::Command) pub fn verify(mut sq: Sq, input: Box>, detached: Option, + detached_sig_arg: &str, + detached_sig_value: Option, output: &mut dyn io::Write, signatures: usize, certs: Vec) -> Result<()> { @@ -71,7 +75,8 @@ pub fn verify(mut sq: Sq, let (kind, sig) = Kind::identify(&mut sq, sig)?; kind.expect_or_else(&sq, "verify", Kind::DetachedSig, - "--signature-file", Some(&sig_path))?; + detached_sig_arg, + detached_sig_value.as_deref())?; Some(sig) } else {