diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2021-03-12 16:23:04 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-03-12 16:32:15 +0100 |
commit | 3c9351ade65fa888a13018765ba058363314d677 (patch) | |
tree | 817b3a554e0578e79356d2486566bf08ba0d7a52 | |
parent | efcf130fb2635848a609fb7d897aa0258bfaa9a2 (diff) |
sq: Improve keyring list.
- Try hard to list the most relevant (i.e. primary) user id.
- Add a flag --all-userids to list all userids.
-rw-r--r-- | sq/src/commands/keyring.rs | 71 | ||||
-rw-r--r-- | sq/src/sq-usage.rs | 9 | ||||
-rw-r--r-- | sq/src/sq_cli.rs | 11 |
3 files changed, 75 insertions, 16 deletions
diff --git a/sq/src/commands/keyring.rs b/sq/src/commands/keyring.rs index bb561c8e..be8fae21 100644 --- a/sq/src/commands/keyring.rs +++ b/sq/src/commands/keyring.rs @@ -156,7 +156,7 @@ pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> { }, ("list", Some(m)) => { let mut input = open_or_stdin(m.value_of("input"))?; - list(&mut input) + list(config, &mut input, m.is_present("all-userids")) }, ("split", Some(m)) => { let mut input = open_or_stdin(m.value_of("input"))?; @@ -217,19 +217,68 @@ fn filter<F>(inputs: Option<clap::Values>, output: &mut dyn io::Write, } /// Lists certs in a keyring. -fn list(input: &mut (dyn io::Read + Sync + Send)) - -> Result<()> { +fn list(config: Config, + input: &mut (dyn io::Read + Sync + Send), + list_all_uids: bool) + -> Result<()> +{ for (i, cert) in CertParser::from_reader(input)?.enumerate() { let cert = cert.context("Malformed certificate in keyring")?; - print!("{}. {:X}", i, cert.fingerprint()); - // Try to be more helpful by including the first userid in the - // listing. - if let Some(email) = cert.userids().nth(0) - .and_then(|uid| uid.email().unwrap_or(None)) - { - print!(" {}", email); + let line = format!("{}. {:X}", i, cert.fingerprint()); + let indent = line.chars().map(|_| ' ').collect::<String>(); + print!("{}", line); + + // Try to be more helpful by including a User ID in the + // listing. We'd like it to be the primary one. Use + // decreasingly strict policies. + let mut primary_uid = None; + + // First, apply our policy. + if let Ok(vcert) = cert.with_policy(&config.policy, None) { + if let Ok(primary) = vcert.primary_userid() { + println!(" {}", String::from_utf8_lossy(primary.value())); + primary_uid = Some(primary.value().to_vec()); + } + } + + // Second, apply the null policy. + if primary_uid.is_none() { + let null = openpgp::policy::NullPolicy::new(); + if let Ok(vcert) = cert.with_policy(&null, None) { + if let Ok(primary) = vcert.primary_userid() { + println!(" {}", String::from_utf8_lossy(primary.value())); + primary_uid = Some(primary.value().to_vec()); + } + } + } + + // As a last resort, pick the first user id. + if primary_uid.is_none() { + if let Some(primary) = cert.userids().nth(0) { + println!(" {}", String::from_utf8_lossy(primary.value())); + primary_uid = Some(primary.value().to_vec()); + } + } + + if primary_uid.is_none() { + // No dice. + println!(); + } + + if list_all_uids { + // List all user ids independently of their validity. + for u in cert.userids() { + if primary_uid.as_ref() + .map(|p| &p[..] == u.value()).unwrap_or(false) + { + // Skip the user id we already printed. + continue; + } + + println!("{} {}", indent, + String::from_utf8_lossy(u.value())); + } } - println!(); } Ok(()) } diff --git a/sq/src/sq-usage.rs b/sq/src/sq-usage.rs index bd7acefb..94938f4e 100644 --- a/sq/src/sq-usage.rs +++ b/sq/src/sq-usage.rs @@ -621,13 +621,16 @@ //! ```text //! Lists keys in a keyring //! -//! Prints the fingerprint as well one userid for every certificate -//! encountered in the keyring. +//! Prints the fingerprint as well as the primary userid for every +//! certificate encountered in the keyring. //! //! USAGE: -//! sq keyring list [FILE] +//! sq keyring list [FLAGS] [FILE] //! //! FLAGS: +//! --all-userids +//! Lists all user ids, even those that are expired, revoked, or not +//! valid under the standard policy. //! -h, --help //! Prints help information //! diff --git a/sq/src/sq_cli.rs b/sq/src/sq_cli.rs index c76758ba..0948363c 100644 --- a/sq/src/sq_cli.rs +++ b/sq/src/sq_cli.rs @@ -889,8 +889,8 @@ $ sq keyring merge certs.pgp romeo-updates.pgp .long_about( "Lists keys in a keyring -Prints the fingerprint as well one userid for every certificate -encountered in the keyring. +Prints the fingerprint as well as the primary userid for every +certificate encountered in the keyring. ") .after_help( "EXAMPLES: @@ -904,6 +904,13 @@ $ sq keyring filter --domain example.org certs.pgp | sq keyring list .arg(Arg::with_name("input") .value_name("FILE") .help("Reads from FILE or stdin if omitted")) + .arg(Arg::with_name("all-userids") + .long("--all-userids") + .help("Lists all user ids") + .long_help( + "Lists all user ids, even those that are \ + expired, revoked, or not valid under the \ + standard policy.")) ) .subcommand( SubCommand::with_name("split") |