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::path::PathBuf;
use sequoia_openpgp as openpgp;
use openpgp::{
@ -22,7 +23,7 @@ pub fn dispatch<'store>(mut config: Config<'store>, cmd: import::Command)
-> Result<()>
{
let inputs = if cmd.input.is_empty() {
vec![ "-".to_string() ]
vec![ PathBuf::from("-") ]
} else {
cmd.input
};
@ -32,7 +33,7 @@ pub fn dispatch<'store>(mut config: Config<'store>, cmd: import::Command)
let inner = || -> Result<()> {
for input in inputs.into_iter() {
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 cert_store = config.cert_store_mut_or_else()?;

View File

@ -1,6 +1,5 @@
use std::convert::TryFrom;
use std::io::{self, Read};
use std::path::Path;
use std::time::{Duration, SystemTime};
use anyhow::Context;
@ -40,7 +39,11 @@ pub fn inspect(mut config: Config, c: inspect::Command)
let print_certifications = c.certifications;
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)?;
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 ppr = if c.cert.is_empty() {
if let Some(input) = input.as_ref() {
if ! Path::new(input).exists() && input.parse::<KeyHandle>().is_ok() {
if let Some(input) = input {
if ! input.exists() &&
format!("{}", input.display()).parse::<KeyHandle>().is_ok() {
eprintln!("The file {} does not exist, \
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::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
let (cert, rev) = builder.generate()?;
// Export
if command.export.is_some() {
let (key_path, rev_path) =
match (command.export.as_deref(), command.rev_cert.as_deref()) {
(Some("-"), Some("-")) => ("-".to_string(), "-".to_string()),
(Some("-"), Some(ref rp)) => ("-".to_string(), rp.to_string()),
(Some("-"), None) => {
return Err(anyhow::anyhow!(
"Missing arguments: --rev-cert is mandatory \
if --export is '-'."
))
}
(Some(ref kp), None) => (kp.to_string(), format!("{}.rev", kp)),
(Some(ref kp), Some("-")) => (kp.to_string(), "-".to_string()),
(Some(ref kp), Some(ref rp)) => {
(kp.to_string(), rp.to_string())
}
_ => {
return Err(anyhow::anyhow!(
"Conflicting arguments --rev-cert and \
--export"
))
}
};
if let Some(key_path) = command.export.as_ref() {
if &format!("{}", key_path.display()) == "-"
&& command.rev_cert.is_none()
{
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
} else {
Some(PathBuf::from(format!("{}.rev", key_path.display())))
};
let headers = cert.armor_headers();
@ -148,7 +147,7 @@ pub fn generate(
.map(|value| ("Comment", value.as_str()))
.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)?;
cert.as_tsk().serialize(&mut w)?;
w.finalize()?;
@ -162,16 +161,11 @@ pub fn generate(
.collect();
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)?;
Packet::Signature(rev).serialize(&mut w)?;
w.finalize()?;
}
} else {
return Err(anyhow::anyhow!(
"Saving generated key to the store isn't implemented \
yet."
));
}
Ok(())

View File

@ -5,6 +5,7 @@ use std::{
io,
path::PathBuf,
};
use std::ops::Deref;
use anyhow::Context;
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(),
c.binary,
armor::Kind::PublicKey)?;
merge(c.input, &mut output)?;
merge(&c.input, &mut output)?;
output.finalize()
},
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.
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)
-> Result<()>
where F: FnMut(Cert) -> Option<Cert>,
{
if !inputs.is_empty() {
for name in inputs {
for cert in CertParser::from_file(name)? {
for cert in CertParser::from_file(name.deref())? {
let cert = cert.context(
format!("Malformed certificate in keyring {:?}", name))?;
format!("Malformed certificate in keyring {:?}", name.display()))?;
if let Some(cert) = filter(cert) {
if to_certificate {
cert.serialize(output)?;
@ -318,7 +319,7 @@ fn split(input: &mut (dyn io::Read + Sync + Send), prefix: &str, binary: bool)
}
/// Merge multiple keyrings.
fn merge(inputs: Vec<String>, output: &mut dyn io::Write)
fn merge(inputs: &[PathBuf], output: &mut dyn io::Write)
-> Result<()>
{
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::fs::File;
use std::io::{self, Write};
use std::path::Path;
use std::time::SystemTime;
use sequoia_net::pks;
@ -962,7 +963,7 @@ pub fn join(config: Config, c: packet::JoinCommand) -> Result<()> {
/// OUTPUT.
fn copy(config: &Config,
mut ppr: PacketParserResult,
output: Option<&str>,
output: Option<&Path>,
sink: &mut Option<Message>)
-> Result<()> {
while let PacketParserResult::Some(pp) = ppr {

View File

@ -1,4 +1,5 @@
use anyhow::Context as _;
use std::path::Path;
use std::time::SystemTime;
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.
fn read_cert(input: Option<&str>) -> Result<Cert> {
fn read_cert(input: Option<&Path>) -> Result<Cert> {
let input = open_or_stdin(input)?;
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.
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())?;
if secret.len() > 1 {
Err(anyhow::anyhow!("Multiple secret keys provided."))?;

View File

@ -1,6 +1,7 @@
use anyhow::Context as _;
use std::fs;
use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::time::SystemTime;
use tempfile::NamedTempFile;
@ -27,7 +28,7 @@ pub struct SignOpts<'a, 'certdb> {
pub config: Config<'certdb>,
pub private_key_store: Option<&'a str>,
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 detached: bool,
pub binary: bool,

View File

@ -71,19 +71,19 @@ pub mod output;
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<()>>> {
match f {
Some(f) => Ok(Box::new(
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))),
}
}
/// Loads one TSK from every given file.
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![];
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.
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![];
for f in files {
@ -302,7 +302,7 @@ impl<'store> Config<'store> {
///
/// This is suitable for any kind of OpenPGP data, or decrypted or
/// 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>> {
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
/// 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>> {
if ! self.unstable_cli_warning_emitted {
emit_unstable_cli_warning();
@ -323,7 +323,7 @@ impl<'store> Config<'store> {
/// Opens the file (or stdout) for writing data that is safe for
/// 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)
-> Result<Message<'a>> {
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
/// or create_or_stdout_unsafe.
fn create_or_stdout(
f: Option<&str>,
f: Option<&Path>,
force: bool,
) -> Result<Box<dyn io::Write + Sync + Send>> {
match f {
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) => {
let p = Path::new(f);
if !p.exists() || force {
if !f.exists() || force {
Ok(Box::new(
OpenOptions::new()
.write(true)
@ -358,7 +357,7 @@ impl<'store> Config<'store> {
Err(anyhow::anyhow!(format!(
"File {:?} exists, use \"sq --force ...\" to \
overwrite",
p
f.display()
)))
}
}

View File

@ -3,7 +3,6 @@ use clap::Parser;
use crate::sq_cli::types::{ArmorKind, IoArgs};
// 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
#[derive(Parser, Debug)]
#[clap(

View File

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

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand};
use crate::sq_cli::types::NetworkPolicy;
@ -66,5 +68,5 @@ pub struct GetCommand {
value_name = "FILE",
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 crate::sq_cli::types::{IoArgs, SessionKey};
@ -62,13 +64,13 @@ pub struct Command {
value_name = "CERT_FILE",
help = "Verifies signatures using the certificates in CERT_FILE",
)]
pub sender_cert_file: Vec<String>,
pub sender_cert_file: Vec<PathBuf>,
#[clap(
long = "recipient-file",
value_name = "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(
long = "private-key-store",
value_name = "KEY_STORE",

View File

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

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser;
#[derive(Parser, Debug)]
@ -16,5 +18,5 @@ $ sq import < juliet.pgp
)]
pub struct Command {
#[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 sequoia_openpgp as openpgp;
@ -43,7 +45,7 @@ pub struct Command {
value_name = "FILE",
help = "Reads from FILE or stdin if omitted",
)]
pub input: Option<String>,
pub input: Option<PathBuf>,
#[clap(
long = "cert",
value_name = "FINGERPRINT|KEYID",

View File

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

View File

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

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand};
use crate::sq_cli::types::NetworkPolicy;
@ -65,7 +67,7 @@ pub struct GetCommand {
value_name = "FILE",
help = "Writes to FILE instead of importing into the certificate store"
)]
pub output: Option<String>,
pub output: Option<PathBuf>,
#[clap(
short = 'B',
long,
@ -87,5 +89,5 @@ pub struct GetCommand {
)]
pub struct SendCommand {
#[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 crate::sq_cli::types::{ArmorKind, IoArgs, SessionKey};
@ -113,7 +115,7 @@ pub struct DecryptCommand {
value_name = "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(
long = "private-key-store",
value_name = "KEY_STORE",
@ -153,7 +155,7 @@ $ sq packet split juliet.pgp
)]
pub struct SplitCommand {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Option<String>,
pub input: Option<PathBuf>,
#[clap(
short = 'p',
long = "prefix",
@ -187,14 +189,14 @@ $ sq packet join juliet.pgp-[0-3]*
)]
pub struct JoinCommand {
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
pub input: Vec<String>,
pub input: Vec<PathBuf>,
#[clap(
short,
long,
value_name = "FILE",
help = "Writes to FILE or stdout if omitted"
)]
pub output: Option<String>,
pub output: Option<PathBuf>,
#[clap(
long = "label",
value_name = "LABEL",

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser;
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 \
an error for the file to contain more than one certificate.",
)]
pub input: Option<String>,
pub input: Option<PathBuf>,
#[clap(
long = "revocation-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, \
then that key is used to sign the revocation certificate.",
)]
pub secret_key_file: Option<String>,
pub secret_key_file: Option<PathBuf>,
#[clap(
long = "private-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 \
certificate."
)]
pub input: Option<String>,
pub input: Option<PathBuf>,
#[clap(
long = "revocation-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 \
material, then that key is used to sign the revocation certificate.",
)]
pub secret_key_file: Option<String>,
pub secret_key_file: Option<PathBuf>,
#[clap(
long = "private-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 \
certificate."
)]
pub input: Option<String>,
pub input: Option<PathBuf>,
#[clap(
long = "revocation-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, \
then that key is used to sign the revocation certificate.",
)]
pub secret_key_file: Option<String>,
pub secret_key_file: Option<PathBuf>,
#[clap(
long = "private-key-store",
value_name = "KEY_STORE",

View File

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

View File

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

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use clap::Parser;
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
// without one, does it?
// TODO Use PathBuf instead of String. Path representation is platform dependent, so Rust's
// utf-8 Strings are not quite appropriate.
// TODO: And adapt load_certs in sq.rs
pub sender_file: Vec<String>,
pub sender_file: Vec<PathBuf>,
#[clap(
long = "signer-cert",
value_name = "FINGERPRINT|KEYID",

View File

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