Refactor: Use PathBuf instead of String for file related CLI options

- Replace `Option<String>` and `Vec<String>` based CLI options dealing
  with files with `Option<PathBuf>` and `Vec<PathBuf>` based ones
  (respectively).
  This allows us to unify the use of input and output facilities using
  globally available CLI options while ensuring (cross-platform) type
  safety.
This commit is contained in:
David Runge 2023-06-06 21:57:30 +02:00
parent 3f147af820
commit 8f57c0d9f2
No known key found for this signature in database
GPG Key ID: BB992F9864FAD168
24 changed files with 131 additions and 106 deletions

View File

@ -1,4 +1,5 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::path::PathBuf;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp::{ use openpgp::{
@ -22,7 +23,7 @@ pub fn dispatch<'store>(mut config: Config<'store>, cmd: import::Command)
-> Result<()> -> Result<()>
{ {
let inputs = if cmd.input.is_empty() { let inputs = if cmd.input.is_empty() {
vec![ "-".to_string() ] vec![ PathBuf::from("-") ]
} else { } else {
cmd.input cmd.input
}; };
@ -32,7 +33,7 @@ pub fn dispatch<'store>(mut config: Config<'store>, cmd: import::Command)
let inner = || -> Result<()> { let inner = || -> Result<()> {
for input in inputs.into_iter() { for input in inputs.into_iter() {
let input = open_or_stdin( let input = open_or_stdin(
if input == "-" { None } else { Some(&input) })?; if input == PathBuf::from("-") { None } else { Some(&input) })?;
let raw_certs = RawCertParser::from_reader(input)?; let raw_certs = RawCertParser::from_reader(input)?;
let cert_store = config.cert_store_mut_or_else()?; let cert_store = config.cert_store_mut_or_else()?;

View File

@ -1,6 +1,5 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use std::io::{self, Read}; use std::io::{self, Read};
use std::path::Path;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use anyhow::Context; use anyhow::Context;
@ -40,7 +39,11 @@ pub fn inspect(mut config: Config, c: inspect::Command)
let print_certifications = c.certifications; let print_certifications = c.certifications;
let input = c.input.as_deref(); let input = c.input.as_deref();
let input_name = input.unwrap_or("-"); let input_name = if let Some(input) = c.input.as_ref() {
format!("{}", input.display())
} else {
"-".to_string()
};
write!(output, "{}: ", input_name)?; write!(output, "{}: ", input_name)?;
let mut type_called = false; // Did we print the type yet? let mut type_called = false; // Did we print the type yet?
@ -53,11 +56,12 @@ pub fn inspect(mut config: Config, c: inspect::Command)
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
let mut ppr = if c.cert.is_empty() { let mut ppr = if c.cert.is_empty() {
if let Some(input) = input.as_ref() { if let Some(input) = input {
if ! Path::new(input).exists() && input.parse::<KeyHandle>().is_ok() { if ! input.exists() &&
format!("{}", input.display()).parse::<KeyHandle>().is_ok() {
eprintln!("The file {} does not exist, \ eprintln!("The file {} does not exist, \
did you mean \"sq inspect --cert {}\"?", did you mean \"sq inspect --cert {}\"?",
input, input); input.display(), input.display());
} }
} }

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use chrono::DateTime; use chrono::DateTime;
use chrono::Utc; use chrono::Utc;
@ -111,33 +113,30 @@ pub fn generate(
} }
} }
if command.export.is_none() {
return Err(anyhow::anyhow!(
"Saving generated key to the store isn't implemented yet."
));
}
// Generate the key // Generate the key
let (cert, rev) = builder.generate()?; let (cert, rev) = builder.generate()?;
// Export // Export
if command.export.is_some() { if let Some(key_path) = command.export.as_ref() {
let (key_path, rev_path) = if &format!("{}", key_path.display()) == "-"
match (command.export.as_deref(), command.rev_cert.as_deref()) { && command.rev_cert.is_none()
(Some("-"), Some("-")) => ("-".to_string(), "-".to_string()), {
(Some("-"), Some(ref rp)) => ("-".to_string(), rp.to_string()), return Err(anyhow::anyhow!(
(Some("-"), None) => { "Missing arguments: --rev-cert is mandatory if --export is '-'."
return Err(anyhow::anyhow!( ))
"Missing arguments: --rev-cert is mandatory \ }
if --export is '-'."
)) let rev_path = if command.rev_cert.is_some() {
} command.rev_cert
(Some(ref kp), None) => (kp.to_string(), format!("{}.rev", kp)), } else {
(Some(ref kp), Some("-")) => (kp.to_string(), "-".to_string()), Some(PathBuf::from(format!("{}.rev", key_path.display())))
(Some(ref kp), Some(ref rp)) => { };
(kp.to_string(), rp.to_string())
}
_ => {
return Err(anyhow::anyhow!(
"Conflicting arguments --rev-cert and \
--export"
))
}
};
let headers = cert.armor_headers(); let headers = cert.armor_headers();
@ -148,7 +147,7 @@ pub fn generate(
.map(|value| ("Comment", value.as_str())) .map(|value| ("Comment", value.as_str()))
.collect(); .collect();
let w = config.create_or_stdout_safe(Some(&key_path))?; let w = config.create_or_stdout_safe(Some(key_path))?;
let mut w = Writer::with_headers(w, Kind::SecretKey, headers)?; let mut w = Writer::with_headers(w, Kind::SecretKey, headers)?;
cert.as_tsk().serialize(&mut w)?; cert.as_tsk().serialize(&mut w)?;
w.finalize()?; w.finalize()?;
@ -162,16 +161,11 @@ pub fn generate(
.collect(); .collect();
headers.insert(0, ("Comment", "Revocation certificate for")); headers.insert(0, ("Comment", "Revocation certificate for"));
let w = config.create_or_stdout_safe(Some(&rev_path))?; let w = config.create_or_stdout_safe(rev_path.as_deref())?;
let mut w = Writer::with_headers(w, Kind::Signature, headers)?; let mut w = Writer::with_headers(w, Kind::Signature, headers)?;
Packet::Signature(rev).serialize(&mut w)?; Packet::Signature(rev).serialize(&mut w)?;
w.finalize()?; w.finalize()?;
} }
} else {
return Err(anyhow::anyhow!(
"Saving generated key to the store isn't implemented \
yet."
));
} }
Ok(()) Ok(())

View File

@ -5,6 +5,7 @@ use std::{
io, io,
path::PathBuf, path::PathBuf,
}; };
use std::ops::Deref;
use anyhow::Context; use anyhow::Context;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -162,7 +163,7 @@ pub fn dispatch(config: Config, c: keyring::Command) -> Result<()> {
config.create_or_stdout_pgp(c.output.as_deref(), config.create_or_stdout_pgp(c.output.as_deref(),
c.binary, c.binary,
armor::Kind::PublicKey)?; armor::Kind::PublicKey)?;
merge(c.input, &mut output)?; merge(&c.input, &mut output)?;
output.finalize() output.finalize()
}, },
List(c) => { List(c) => {
@ -190,16 +191,16 @@ pub fn dispatch(config: Config, c: keyring::Command) -> Result<()> {
} }
/// Joins certificates and keyrings into a keyring, applying a filter. /// Joins certificates and keyrings into a keyring, applying a filter.
fn filter<F>(inputs: &[String], output: &mut dyn io::Write, fn filter<F>(inputs: &[PathBuf], output: &mut dyn io::Write,
mut filter: F, to_certificate: bool) mut filter: F, to_certificate: bool)
-> Result<()> -> Result<()>
where F: FnMut(Cert) -> Option<Cert>, where F: FnMut(Cert) -> Option<Cert>,
{ {
if !inputs.is_empty() { if !inputs.is_empty() {
for name in inputs { for name in inputs {
for cert in CertParser::from_file(name)? { for cert in CertParser::from_file(name.deref())? {
let cert = cert.context( let cert = cert.context(
format!("Malformed certificate in keyring {:?}", name))?; format!("Malformed certificate in keyring {:?}", name.display()))?;
if let Some(cert) = filter(cert) { if let Some(cert) = filter(cert) {
if to_certificate { if to_certificate {
cert.serialize(output)?; cert.serialize(output)?;
@ -318,7 +319,7 @@ fn split(input: &mut (dyn io::Read + Sync + Send), prefix: &str, binary: bool)
} }
/// Merge multiple keyrings. /// Merge multiple keyrings.
fn merge(inputs: Vec<String>, output: &mut dyn io::Write) fn merge(inputs: &[PathBuf], output: &mut dyn io::Write)
-> Result<()> -> Result<()>
{ {
let mut certs: HashMap<Fingerprint, Option<Cert>> = HashMap::new(); let mut certs: HashMap<Fingerprint, Option<Cert>> = HashMap::new();

View File

@ -4,6 +4,7 @@ use std::cmp::Ordering;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fs::File; use std::fs::File;
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::Path;
use std::time::SystemTime; use std::time::SystemTime;
use sequoia_net::pks; use sequoia_net::pks;
@ -962,7 +963,7 @@ pub fn join(config: Config, c: packet::JoinCommand) -> Result<()> {
/// OUTPUT. /// OUTPUT.
fn copy(config: &Config, fn copy(config: &Config,
mut ppr: PacketParserResult, mut ppr: PacketParserResult,
output: Option<&str>, output: Option<&Path>,
sink: &mut Option<Message>) sink: &mut Option<Message>)
-> Result<()> { -> Result<()> {
while let PacketParserResult::Some(pp) = ppr { while let PacketParserResult::Some(pp) = ppr {

View File

@ -1,4 +1,5 @@
use anyhow::Context as _; use anyhow::Context as _;
use std::path::Path;
use std::time::SystemTime; use std::time::SystemTime;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -145,7 +146,7 @@ pub fn revoke_userid(config: Config, c: revoke::UseridCommand) -> Result<()> {
} }
/// Parse the cert from input and ensure it is only one cert. /// Parse the cert from input and ensure it is only one cert.
fn read_cert(input: Option<&str>) -> Result<Cert> { fn read_cert(input: Option<&Path>) -> Result<Cert> {
let input = open_or_stdin(input)?; let input = open_or_stdin(input)?;
let cert = CertParser::from_reader(input)?.collect::<Vec<_>>(); let cert = CertParser::from_reader(input)?.collect::<Vec<_>>();
@ -159,7 +160,7 @@ fn read_cert(input: Option<&str>) -> Result<Cert> {
} }
/// Parse the secret key and ensure it is at most one. /// Parse the secret key and ensure it is at most one.
fn read_secret(skf: Option<&str>) -> Result<Option<Cert>> { fn read_secret(skf: Option<&Path>) -> Result<Option<Cert>> {
let secret = load_certs(skf.into_iter())?; let secret = load_certs(skf.into_iter())?;
if secret.len() > 1 { if secret.len() > 1 {
Err(anyhow::anyhow!("Multiple secret keys provided."))?; Err(anyhow::anyhow!("Multiple secret keys provided."))?;

View File

@ -1,6 +1,7 @@
use anyhow::Context as _; use anyhow::Context as _;
use std::fs; use std::fs;
use std::io; use std::io;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::SystemTime; use std::time::SystemTime;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
@ -27,7 +28,7 @@ pub struct SignOpts<'a, 'certdb> {
pub config: Config<'certdb>, pub config: Config<'certdb>,
pub private_key_store: Option<&'a str>, pub private_key_store: Option<&'a str>,
pub input: &'a mut (dyn io::Read + Sync + Send), pub input: &'a mut (dyn io::Read + Sync + Send),
pub output_path: Option<&'a str>, pub output_path: Option<&'a Path>,
pub secrets: Vec<openpgp::Cert>, pub secrets: Vec<openpgp::Cert>,
pub detached: bool, pub detached: bool,
pub binary: bool, pub binary: bool,

View File

@ -71,19 +71,19 @@ pub mod output;
pub use output::{wkd::WkdUrlVariant, Model, OutputFormat, OutputVersion}; pub use output::{wkd::WkdUrlVariant, Model, OutputFormat, OutputVersion};
fn open_or_stdin(f: Option<&str>) fn open_or_stdin(f: Option<&Path>)
-> Result<Box<dyn BufferedReader<()>>> { -> Result<Box<dyn BufferedReader<()>>> {
match f { match f {
Some(f) => Ok(Box::new( Some(f) => Ok(Box::new(
File::open(f) File::open(f)
.with_context(|| format!("Failed to open {}", f))?)), .with_context(|| format!("Failed to open {}", f.display()))?)),
None => Ok(Box::new(Generic::new(io::stdin(), None))), None => Ok(Box::new(Generic::new(io::stdin(), None))),
} }
} }
/// Loads one TSK from every given file. /// Loads one TSK from every given file.
fn load_keys<'a, I>(files: I) -> openpgp::Result<Vec<Cert>> fn load_keys<'a, I>(files: I) -> openpgp::Result<Vec<Cert>>
where I: Iterator<Item=&'a str> where I: Iterator<Item=&'a Path>
{ {
let mut certs = vec![]; let mut certs = vec![];
for f in files { for f in files {
@ -100,7 +100,7 @@ fn load_keys<'a, I>(files: I) -> openpgp::Result<Vec<Cert>>
/// Loads one or more certs from every given file. /// Loads one or more certs from every given file.
fn load_certs<'a, I>(files: I) -> openpgp::Result<Vec<Cert>> fn load_certs<'a, I>(files: I) -> openpgp::Result<Vec<Cert>>
where I: Iterator<Item=&'a str> where I: Iterator<Item=&'a Path>
{ {
let mut certs = vec![]; let mut certs = vec![];
for f in files { for f in files {
@ -302,7 +302,7 @@ impl<'store> Config<'store> {
/// ///
/// This is suitable for any kind of OpenPGP data, or decrypted or /// This is suitable for any kind of OpenPGP data, or decrypted or
/// authenticated payloads. /// authenticated payloads.
fn create_or_stdout_safe(&self, f: Option<&str>) fn create_or_stdout_safe(&self, f: Option<&Path>)
-> Result<Box<dyn io::Write + Sync + Send>> { -> Result<Box<dyn io::Write + Sync + Send>> {
Config::create_or_stdout(f, self.force) Config::create_or_stdout(f, self.force)
} }
@ -312,7 +312,7 @@ impl<'store> Config<'store> {
/// ///
/// If our heuristic detects non-interactive use, we will emit a /// If our heuristic detects non-interactive use, we will emit a
/// warning. /// warning.
fn create_or_stdout_unsafe(&mut self, f: Option<&str>) fn create_or_stdout_unsafe(&mut self, f: Option<&Path>)
-> Result<Box<dyn io::Write + Sync + Send>> { -> Result<Box<dyn io::Write + Sync + Send>> {
if ! self.unstable_cli_warning_emitted { if ! self.unstable_cli_warning_emitted {
emit_unstable_cli_warning(); emit_unstable_cli_warning();
@ -323,7 +323,7 @@ impl<'store> Config<'store> {
/// Opens the file (or stdout) for writing data that is safe for /// Opens the file (or stdout) for writing data that is safe for
/// non-interactive use because it is an OpenPGP data stream. /// non-interactive use because it is an OpenPGP data stream.
fn create_or_stdout_pgp<'a>(&self, f: Option<&str>, fn create_or_stdout_pgp<'a>(&self, f: Option<&Path>,
binary: bool, kind: armor::Kind) binary: bool, kind: armor::Kind)
-> Result<Message<'a>> { -> Result<Message<'a>> {
let sink = self.create_or_stdout_safe(f)?; let sink = self.create_or_stdout_safe(f)?;
@ -337,15 +337,14 @@ impl<'store> Config<'store> {
/// Helper function, do not use directly. Instead, use create_or_stdout_safe /// Helper function, do not use directly. Instead, use create_or_stdout_safe
/// or create_or_stdout_unsafe. /// or create_or_stdout_unsafe.
fn create_or_stdout( fn create_or_stdout(
f: Option<&str>, f: Option<&Path>,
force: bool, force: bool,
) -> Result<Box<dyn io::Write + Sync + Send>> { ) -> Result<Box<dyn io::Write + Sync + Send>> {
match f { match f {
None => Ok(Box::new(io::stdout())), None => Ok(Box::new(io::stdout())),
Some(p) if p == "-" => Ok(Box::new(io::stdout())), Some(p) if p == Path::new("-") => Ok(Box::new(io::stdout())),
Some(f) => { Some(f) => {
let p = Path::new(f); if !f.exists() || force {
if !p.exists() || force {
Ok(Box::new( Ok(Box::new(
OpenOptions::new() OpenOptions::new()
.write(true) .write(true)
@ -358,7 +357,7 @@ impl<'store> Config<'store> {
Err(anyhow::anyhow!(format!( Err(anyhow::anyhow!(format!(
"File {:?} exists, use \"sq --force ...\" to \ "File {:?} exists, use \"sq --force ...\" to \
overwrite", overwrite",
p f.display()
))) )))
} }
} }

View File

@ -3,7 +3,6 @@ use clap::Parser;
use crate::sq_cli::types::{ArmorKind, IoArgs}; use crate::sq_cli::types::{ArmorKind, IoArgs};
// TODO?: Option<_> conflicts with default value // TODO?: Option<_> conflicts with default value
// TODO: Use PathBuf as input type for more type safety? Investigate conversion
// TODO: use indoc to transparently (de-)indent static strings // TODO: use indoc to transparently (de-)indent static strings
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[clap( #[clap(

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use crate::sq_cli::THIRD_PARTY_CERTIFICATION_VALIDITY_DURATION; use crate::sq_cli::THIRD_PARTY_CERTIFICATION_VALIDITY_DURATION;
@ -52,7 +54,7 @@ pub struct Command {
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE or stdout if omitted" help = "Writes to FILE or stdout if omitted"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
short = 'B', short = 'B',
long, long,
@ -184,7 +186,7 @@ pub struct Command {
index = 1, index = 1,
help = "Creates the certification using CERTIFIER-KEY.", help = "Creates the certification using CERTIFIER-KEY.",
)] )]
pub certifier: String, pub certifier: PathBuf,
#[clap( #[clap(
value_name = "CERTIFICATE", value_name = "CERTIFICATE",
required = true, required = true,

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use crate::sq_cli::types::NetworkPolicy; use crate::sq_cli::types::NetworkPolicy;
@ -66,5 +68,5 @@ pub struct GetCommand {
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE instead of importing into the certificate store" help = "Writes to FILE instead of importing into the certificate store"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
} }

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use crate::sq_cli::types::{IoArgs, SessionKey}; use crate::sq_cli::types::{IoArgs, SessionKey};
@ -62,13 +64,13 @@ pub struct Command {
value_name = "CERT_FILE", value_name = "CERT_FILE",
help = "Verifies signatures using the certificates in CERT_FILE", help = "Verifies signatures using the certificates in CERT_FILE",
)] )]
pub sender_cert_file: Vec<String>, pub sender_cert_file: Vec<PathBuf>,
#[clap( #[clap(
long = "recipient-file", long = "recipient-file",
value_name = "KEY_FILE", value_name = "KEY_FILE",
help = "Decrypts the message using the key in KEY_FILE", help = "Decrypts the message using the key in KEY_FILE",
)] )]
pub secret_key_file: Vec<String>, pub secret_key_file: Vec<PathBuf>,
#[clap( #[clap(
long = "private-key-store", long = "private-key-store",
value_name = "KEY_STORE", value_name = "KEY_STORE",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::ArgAction::Count; use clap::ArgAction::Count;
use clap::{ValueEnum, Parser}; use clap::{ValueEnum, Parser};
@ -71,14 +73,14 @@ pub struct Command {
value_name = "CERT_RING_FILE", value_name = "CERT_RING_FILE",
help = "Encrypts to all certificates in CERT_RING_FILE", help = "Encrypts to all certificates in CERT_RING_FILE",
)] )]
pub recipients_file: Vec<String>, pub recipients_file: Vec<PathBuf>,
#[clap( #[clap(
long = "signer-file", long = "signer-file",
value_name = "KEY_FILE", value_name = "KEY_FILE",
help = "Signs the message using the key in KEY_FILE", help = "Signs the message using the key in KEY_FILE",
)] )]
pub signer_key_file: Vec<String>, pub signer_key_file: Vec<PathBuf>,
#[clap( #[clap(
long = "private-key-store", long = "private-key-store",
value_name = "KEY_STORE", value_name = "KEY_STORE",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -16,5 +18,5 @@ $ sq import < juliet.pgp
)] )]
pub struct Command { pub struct Command {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")] #[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Vec<String>, pub input: Vec<PathBuf>,
} }

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -43,7 +45,7 @@ pub struct Command {
value_name = "FILE", value_name = "FILE",
help = "Reads from FILE or stdin if omitted", help = "Reads from FILE or stdin if omitted",
)] )]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
long = "cert", long = "cert",
value_name = "FINGERPRINT|KEYID", value_name = "FINGERPRINT|KEYID",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{ValueEnum, ArgGroup, Args, Parser, Subcommand}; use clap::{ValueEnum, ArgGroup, Args, Parser, Subcommand};
use sequoia_openpgp::cert::CipherSuite as SqCipherSuite; use sequoia_openpgp::cert::CipherSuite as SqCipherSuite;
@ -180,8 +182,7 @@ pub struct GenerateCommand {
value_name = "OUTFILE", value_name = "OUTFILE",
help = "Writes the key to OUTFILE", help = "Writes the key to OUTFILE",
)] )]
// TODO this represents a filename, so it should be a Path pub export: Option<PathBuf>,
pub export: Option<String>,
#[clap( #[clap(
long = "rev-cert", long = "rev-cert",
value_name = "FILE or -", value_name = "FILE or -",
@ -192,8 +193,7 @@ pub struct GenerateCommand {
mandatory if OUTFILE is \"-\". \ mandatory if OUTFILE is \"-\". \
[default: <OUTFILE>.rev]", [default: <OUTFILE>.rev]",
)] )]
// TODO this represents a filename, so it should be a Path pub rev_cert: Option<PathBuf>
pub rev_cert: Option<String>
} }
#[derive(ValueEnum, Clone, Debug)] #[derive(ValueEnum, Clone, Debug)]
@ -472,14 +472,14 @@ pub struct AdoptCommand {
value_name = "TARGET-KEY", value_name = "TARGET-KEY",
help = "Adds keys to TARGET-KEY", help = "Adds keys to TARGET-KEY",
)] )]
pub certificate: Option<String>, pub certificate: Option<PathBuf>,
#[clap( #[clap(
short, short,
long, long,
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE or stdout if omitted" help = "Writes to FILE or stdout if omitted"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
short = 'B', short = 'B',
long, long,
@ -532,14 +532,14 @@ pub struct AttestCertificationsCommand {
value_name = "KEY", value_name = "KEY",
help = "Changes attestations on KEY", help = "Changes attestations on KEY",
)] )]
pub key: Option<String>, pub key: Option<PathBuf>,
#[clap( #[clap(
short, short,
long, long,
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE or stdout if omitted" help = "Writes to FILE or stdout if omitted"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
short = 'B', short = 'B',
long, long,

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -75,14 +77,14 @@ $ sq keyring filter --domain example.org --prune-certs certs.pgp
)] )]
pub struct FilterCommand { pub struct FilterCommand {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")] #[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Vec<String>, pub input: Vec<PathBuf>,
#[clap( #[clap(
short, short,
long, long,
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE or stdout if omitted" help = "Writes to FILE or stdout if omitted"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
long = "userid", long = "userid",
value_name = "USERID", value_name = "USERID",
@ -173,14 +175,14 @@ $ sq keyring join juliet.pgp romeo.pgp alice.pgp
)] )]
pub struct JoinCommand { pub struct JoinCommand {
#[clap(value_name = "FILE", help = "Sets the input files to use")] #[clap(value_name = "FILE", help = "Sets the input files to use")]
pub input: Vec<String>, pub input: Vec<PathBuf>,
#[clap( #[clap(
short, short,
long, long,
value_name = "FILE", value_name = "FILE",
help = "Sets the output file to use" help = "Sets the output file to use"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
short = 'B', short = 'B',
long = "binary", long = "binary",
@ -212,14 +214,14 @@ pub struct MergeCommand {
value_name = "FILE", value_name = "FILE",
help = "Reads from FILE", help = "Reads from FILE",
)] )]
pub input: Vec<String>, pub input: Vec<PathBuf>,
#[clap( #[clap(
short, short,
long, long,
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE or stdout if omitted" help = "Writes to FILE or stdout if omitted"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
short = 'B', short = 'B',
long = "binary", long = "binary",
@ -252,7 +254,7 @@ pub struct ListCommand {
value_name = "FILE", value_name = "FILE",
help = "Reads from FILE or stdin if omitted", help = "Reads from FILE or stdin if omitted",
)] )]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
long = "all-userids", long = "all-userids",
help = "Lists all user ids", help = "Lists all user ids",
@ -289,7 +291,7 @@ pub struct SplitCommand {
value_name = "FILE", value_name = "FILE",
help = "Reads from FILE or stdin if omitted", help = "Reads from FILE or stdin if omitted",
)] )]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
short = 'p', short = 'p',
long = "prefix", long = "prefix",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use crate::sq_cli::types::NetworkPolicy; use crate::sq_cli::types::NetworkPolicy;
@ -65,7 +67,7 @@ pub struct GetCommand {
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE instead of importing into the certificate store" help = "Writes to FILE instead of importing into the certificate store"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
short = 'B', short = 'B',
long, long,
@ -87,5 +89,5 @@ pub struct GetCommand {
)] )]
pub struct SendCommand { pub struct SendCommand {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")] #[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Option<String>, pub input: Option<PathBuf>,
} }

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use crate::sq_cli::types::{ArmorKind, IoArgs, SessionKey}; use crate::sq_cli::types::{ArmorKind, IoArgs, SessionKey};
@ -113,7 +115,7 @@ pub struct DecryptCommand {
value_name = "KEY_FILE", value_name = "KEY_FILE",
help = "Decrypts the message using the key in KEY_FILE", help = "Decrypts the message using the key in KEY_FILE",
)] )]
pub secret_key_file: Vec<String>, pub secret_key_file: Vec<PathBuf>,
#[clap( #[clap(
long = "private-key-store", long = "private-key-store",
value_name = "KEY_STORE", value_name = "KEY_STORE",
@ -153,7 +155,7 @@ $ sq packet split juliet.pgp
)] )]
pub struct SplitCommand { pub struct SplitCommand {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")] #[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
short = 'p', short = 'p',
long = "prefix", long = "prefix",
@ -187,14 +189,14 @@ $ sq packet join juliet.pgp-[0-3]*
)] )]
pub struct JoinCommand { pub struct JoinCommand {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")] #[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Vec<String>, pub input: Vec<PathBuf>,
#[clap( #[clap(
short, short,
long, long,
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE or stdout if omitted" help = "Writes to FILE or stdout if omitted"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
#[clap( #[clap(
long = "label", long = "label",
value_name = "LABEL", value_name = "LABEL",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use clap::{ValueEnum, Args, Subcommand}; use clap::{ValueEnum, Args, Subcommand};
@ -89,7 +91,7 @@ pub struct CertificateCommand {
"Reads the certificate to revoke from FILE or stdin, if omitted. It is \ "Reads the certificate to revoke from FILE or stdin, if omitted. It is \
an error for the file to contain more than one certificate.", an error for the file to contain more than one certificate.",
)] )]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
long = "revocation-file", long = "revocation-file",
value_name = "KEY_FILE", value_name = "KEY_FILE",
@ -100,7 +102,7 @@ different from the certificate, this creates a third-party revocation. If \
this option is not provided, and the certificate includes secret key material, \ this option is not provided, and the certificate includes secret key material, \
then that key is used to sign the revocation certificate.", then that key is used to sign the revocation certificate.",
)] )]
pub secret_key_file: Option<String>, pub secret_key_file: Option<PathBuf>,
#[clap( #[clap(
long = "private-key-store", long = "private-key-store",
value_name = "KEY_STORE", value_name = "KEY_STORE",
@ -234,7 +236,7 @@ pub struct SubkeyCommand {
if omitted. It is an error for the file to contain more than one \ if omitted. It is an error for the file to contain more than one \
certificate." certificate."
)] )]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
long = "revocation-file", long = "revocation-file",
value_name = "KEY_FILE", value_name = "KEY_FILE",
@ -246,7 +248,7 @@ is different from the certificate, this creates a third-party revocation. \
If this option is not provided, and the certificate includes secret key \ If this option is not provided, and the certificate includes secret key \
material, then that key is used to sign the revocation certificate.", material, then that key is used to sign the revocation certificate.",
)] )]
pub secret_key_file: Option<String>, pub secret_key_file: Option<PathBuf>,
#[clap( #[clap(
long = "private-key-store", long = "private-key-store",
value_name = "KEY_STORE", value_name = "KEY_STORE",
@ -365,7 +367,7 @@ pub struct UseridCommand {
if omitted. It is an error for the file to contain more than one \ if omitted. It is an error for the file to contain more than one \
certificate." certificate."
)] )]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
long = "revocation-file", long = "revocation-file",
value_name = "KEY_FILE", value_name = "KEY_FILE",
@ -376,7 +378,7 @@ different from the certificate, this creates a third-party revocation. If \
this option is not provided, and the certificate includes secret key material, \ this option is not provided, and the certificate includes secret key material, \
then that key is used to sign the revocation certificate.", then that key is used to sign the revocation certificate.",
)] )]
pub secret_key_file: Option<String>, pub secret_key_file: Option<PathBuf>,
#[clap( #[clap(
long = "private-key-store", long = "private-key-store",
value_name = "KEY_STORE", value_name = "KEY_STORE",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use crate::sq_cli::types::IoArgs; use crate::sq_cli::types::IoArgs;
@ -91,13 +93,13 @@ pub struct Command {
], ],
help = "Merges signatures from the input and SIGNED-MESSAGE", help = "Merges signatures from the input and SIGNED-MESSAGE",
)] )]
pub merge: Option<String>, pub merge: Option<PathBuf>,
#[clap( #[clap(
long = "signer-file", long = "signer-file",
value_name = "KEY_FILE", value_name = "KEY_FILE",
help = "Signs the message using the key in KEY_FILE", help = "Signs the message using the key in KEY_FILE",
)] )]
pub secret_key_file: Vec<String>, pub secret_key_file: Vec<PathBuf>,
#[clap( #[clap(
long, long,
value_names = &["NAME", "VALUE"], value_names = &["NAME", "VALUE"],

View File

@ -1,5 +1,6 @@
use std::fmt::Display; use std::fmt::Display;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
use std::time::SystemTime; use std::time::SystemTime;
@ -22,14 +23,14 @@ use crate::sq_cli::SECONDS_IN_YEAR;
#[derive(Debug, Args)] #[derive(Debug, Args)]
pub struct IoArgs { pub struct IoArgs {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")] #[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
short, short,
long, long,
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE or stdout if omitted" help = "Writes to FILE or stdout if omitted"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
} }
#[derive(ValueEnum, Debug, Clone)] #[derive(ValueEnum, Debug, Clone)]

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -83,10 +85,7 @@ pub struct Command {
)] )]
// TODO: Should at least one sender_file be required? Verification does not make sense // TODO: Should at least one sender_file be required? Verification does not make sense
// without one, does it? // without one, does it?
// TODO Use PathBuf instead of String. Path representation is platform dependent, so Rust's pub sender_file: Vec<PathBuf>,
// utf-8 Strings are not quite appropriate.
// TODO: And adapt load_certs in sq.rs
pub sender_file: Vec<String>,
#[clap( #[clap(
long = "signer-cert", long = "signer-cert",
value_name = "FINGERPRINT|KEYID", value_name = "FINGERPRINT|KEYID",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use crate::sq_cli::types::NetworkPolicy; use crate::sq_cli::types::NetworkPolicy;
@ -92,7 +94,7 @@ pub struct GetCommand {
value_name = "FILE", value_name = "FILE",
help = "Writes to FILE instead of importing into the certificate store" help = "Writes to FILE instead of importing into the certificate store"
)] )]
pub output: Option<String>, pub output: Option<PathBuf>,
} }
#[derive(Debug, Args)] #[derive(Debug, Args)]
@ -139,7 +141,7 @@ pub struct GenerateCommand {
value_name = "CERT-RING", value_name = "CERT-RING",
help = "Adds certificates from CERT-RING to the WKD", help = "Adds certificates from CERT-RING to the WKD",
)] )]
pub input: Option<String>, pub input: Option<PathBuf>,
#[clap( #[clap(
short = 'd', short = 'd',
long = "direct-method", long = "direct-method",