Implement sq --quiet.

- Also, go over the commands and change some prints to be disabled
    when --quiet is given, use the hint framework.

  - Fixes #314.
This commit is contained in:
Justus Winter
2024-09-11 17:12:17 +02:00
parent 65af1e6ef8
commit 5b1336c4e1
8 changed files with 74 additions and 52 deletions

View File

@ -73,10 +73,6 @@ $ sq cert lint --list-keys keyring.pgp \\
)]
#[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))]
pub struct Command {
/// Quiet; does not output any diagnostics.
#[arg(long)]
pub quiet: bool,
/// Attempts to fix certificates, when possible.
#[arg(long)]
pub fix: bool,

View File

@ -443,6 +443,7 @@ Note that the entire key file will be used as the password, including \
any surrounding whitespace like a trailing newline.",
)]
pub password_file: Vec<PathBuf>,
#[clap(
short = 'v',
long,
@ -452,6 +453,16 @@ any surrounding whitespace like a trailing newline.",
)]
pub verbose: bool,
#[clap(
short = 'q',
long = "quiet",
global = true,
help_heading = GLOBAL_OPTIONS_HEADER,
help = "Be more quiet.",
conflicts_with = "verbose",
)]
pub quiet: bool,
#[clap(
long = "batch",
global = true,

View File

@ -262,7 +262,7 @@ impl<'c, 'store, 'rstore> VHelper<'c, 'store, 'rstore> {
bad_signatures: 0,
bad_checksums: 0,
broken_signatures: 0,
quiet: false,
quiet: sq.quiet,
}
}

View File

@ -191,7 +191,7 @@ fn update_subkey_binding<P>(sq: &Sq,
Ok(sig)
}
pub fn lint(sq: Sq, mut args: Command) -> Result<()> {
pub fn lint(mut sq: Sq, args: Command) -> Result<()> {
// If there were any errors reading the input.
let mut bad_input = false;
@ -233,7 +233,7 @@ pub fn lint(sq: Sq, mut args: Command) -> Result<()> {
let mut certs_with_sha1_protected_backsig = 0;
if args.list_keys {
args.quiet = true;
sq.quiet = true;
}
let reference_time = sq.time;
@ -276,7 +276,7 @@ pub fn lint(sq: Sq, mut args: Command) -> Result<()> {
for (certi, certo) in certp.enumerate() {
match certo {
Err(err) => {
if ! args.quiet {
if ! sq.quiet {
if certi == 0 {
wprintln!("{:?} does not appear to be a keyring: {}",
filename, err);
@ -314,7 +314,7 @@ pub fn lint(sq: Sq, mut args: Command) -> Result<()> {
cert.fingerprint().to_hex());
}
}
if ! args.quiet {
if ! sq.quiet {
wprintln!($($arg)*);
}
}
@ -790,7 +790,7 @@ pub fn lint(sq: Sq, mut args: Command) -> Result<()> {
pl(certs_valid + certs_invalid,
"certificate", "certificates"));
if ! args.quiet {
if ! sq.quiet {
err!(certs_invalid,
" {} {} invalid and {} not linted.",
certs_invalid,
@ -867,7 +867,7 @@ pub fn lint(sq: Sq, mut args: Command) -> Result<()> {
exit(0);
}
} else {
if ! args.quiet {
if ! sq.quiet {
err!(unfixed_issue,
"Failed to fix {} {}.",
unfixed_issue,

View File

@ -93,6 +93,8 @@ pub fn dispatch(sq: Sq, c: cli::network::Command)
///
/// This does not certify the certificates.
pub fn import_certs(sq: &Sq, certs: Vec<Cert>) -> Result<()> {
make_qprintln!(sq.quiet);
if certs.is_empty() {
// No need to do and say anything.
return Ok(());
@ -106,7 +108,7 @@ pub fn import_certs(sq: &Sq, certs: Vec<Cert>) -> Result<()> {
let certs = merge_keyring(certs)?.into_values().collect::<Vec<_>>();
wprintln!("\nImporting {} into the certificate store:\n",
qprintln!("\nImporting {} into the certificate store:\n",
certs.len().of("certificate"));
for cert in certs.iter() {
cert_store.update_by(Arc::new(cert.clone().into()), &mut stats)
@ -129,19 +131,20 @@ pub fn import_certs(sq: &Sq, certs: Vec<Cert>) -> Result<()> {
certs.sort_unstable_by_key(|cert| usize::MAX - cert.0.trust_amount());
for (i, (userid, cert)) in certs.into_iter().enumerate() {
wprintln!(" {}. {} {}", i + 1, cert.fingerprint(), userid);
qprintln!(" {}. {} {}", i + 1, cert.fingerprint(), userid);
}
wprintln!("\nImported {}, updated {}, {} unchanged, {}.",
qprintln!("\nImported {}, updated {}, {} unchanged, {}.",
stats.new_certs().of("new certificate"),
stats.updated_certs().of("certificate"),
stats.unchanged_certs().of("certificate"),
stats.errors().of("error"));
wprintln!("\nAfter checking that a certificate really belongs to the \
stated owner, you can mark the certificate as authenticated \
using: \n\
\n sq pki link add FINGERPRINT\n");
sq.hint(format_args!(
"\nAfter checking that a certificate really belongs to the \
stated owner, you can mark the certificate as authenticated \
using:"))
.command(format_args!("sq pki link add FINGERPRINT"));
Ok(())
}
@ -492,6 +495,8 @@ impl Method {
-> Option<Arc<LazyCert<'store>>>
where 'store: 'rstore
{
make_qprintln!(sq.quiet);
let ca = || -> Result<_> {
let certd = sq.certd_or_else()?;
let (cert, created) = match self {
@ -578,7 +583,7 @@ impl Method {
use std::sync::Once;
static MSG: Once = Once::new();
MSG.call_once(|| {
wprintln!("Note: Created a local CA to record \
qprintln!("Note: Created a local CA to record \
provenance information.\n\
Note: See `sq pki link list --ca` \
and `sq pki link --help` for more \
@ -873,6 +878,8 @@ pub fn dispatch_keyserver(mut sq: Sq,
c: cli::network::keyserver::Command)
-> Result<()>
{
make_qprintln!(sq.quiet);
let default_servers = default_keyservers_p(&c.servers);
let servers = c.servers.iter().map(
|uri| KeyServer::with_client(uri, http_client()?)
@ -947,7 +954,7 @@ pub fn dispatch_keyserver(mut sq: Sq,
let (url, response) = response?;
match response {
Ok(()) => {
wprintln!("{}: ok", url);
qprintln!("{}: ok", url);
one_ok = true;
},
Err(e) if default_servers

View File

@ -205,9 +205,10 @@ pub fn check_userids(sq: &Sq, cert: &Cert, self_signed: bool,
//
// This does some normalization and only considers things that are
// relevant to links.
fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
fn diff_link(sq: &Sq, old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
-> bool
{
make_qprintln!(sq.quiet);
let mut changed = false;
let a_expiration = old.signature_expiration_time();
@ -218,7 +219,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
};
if a_expiration != b_expiration {
changed = true;
wprintln!(
qprintln!(
" Updating expiration time: {} -> {}.",
if let Some(a_expiration) = a_expiration {
chrono::DateTime::<chrono::offset::Utc>::from(
@ -239,12 +240,12 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
if a_amount != b_amount {
changed = true;
wprintln!(" Updating trust amount: {} -> {}.",
qprintln!(" Updating trust amount: {} -> {}.",
a_amount, b_amount);
}
if a_depth != b_depth {
changed = true;
wprintln!(" Update trust depth: {} -> {}.",
qprintln!(" Update trust depth: {} -> {}.",
a_depth, b_depth);
}
@ -257,7 +258,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
if a_regex != b_regex {
changed = true;
wprintln!(" Updating regular expressions:");
qprintln!(" Updating regular expressions:");
let a_regex: Vec<String> = a_regex.into_iter()
.enumerate()
.map(|(i, r)| {
@ -265,7 +266,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
i + 1, String::from_utf8_lossy(r))
})
.collect();
wprintln!(" Current link:\n {}",
qprintln!(" Current link:\n {}",
a_regex.join("\n "));
let b_regex: Vec<String> = b_regex.into_iter()
@ -275,7 +276,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
i + 1, String::from_utf8_lossy(r))
})
.collect();
wprintln!(" Updated link:\n {}",
qprintln!(" Updated link:\n {}",
b_regex.join("\n "));
}
@ -287,14 +288,14 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
.collect();
if a_notations != b_notations {
changed = true;
wprintln!(" Updating notations.");
qprintln!(" Updating notations.");
let a_notations: Vec<String> = a_notations.into_iter()
.enumerate()
.map(|(i, n)| {
format!("{}. {:?}", i + 1, n)
})
.collect();
wprintln!(" Current link:\n {}",
qprintln!(" Current link:\n {}",
a_notations.join("\n "));
let b_notations: Vec<String> = b_notations.into_iter()
@ -303,7 +304,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
format!("{}. {:?}", i + 1, n)
})
.collect();
wprintln!(" Updated link:\n {}",
qprintln!(" Updated link:\n {}",
b_notations.join("\n "));
}
@ -311,7 +312,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
let b_exportable = new.exportable_certification().unwrap_or(true);
if a_exportable != b_exportable {
changed = true;
wprintln!(" Updating exportable flag: {} -> {}.",
qprintln!(" Updating exportable flag: {} -> {}.",
a_exportable, b_exportable);
}
@ -331,6 +332,8 @@ pub fn link(sq: Sq, c: link::Command) -> Result<()> {
pub fn add(sq: Sq, c: link::AddCommand)
-> Result<()>
{
make_qprintln!(sq.quiet);
let trust_root = sq.local_trust_root()?;
let trust_root = trust_root.to_cert()?;
@ -504,7 +507,7 @@ pub fn add(sq: Sq, c: link::AddCommand)
}
}
} else {
wprintln!("Note: {:?} is NOT a self signed User ID. \
qprintln!("Note: {:?} is NOT a self signed User ID. \
If this was a mistake, use \
`sq pki link retract {} \"{}\"` to undo it.",
userid_str(), cert.fingerprint(), userid);
@ -518,29 +521,30 @@ pub fn add(sq: Sq, c: link::AddCommand)
let retracted = matches!(active_certification.trust_signature(),
Some((_depth, 0)));
if retracted {
wprintln!("{}, {} was retracted at {}.",
qprintln!("{}, {} was retracted at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
} else {
wprintln!("{}, {} was already linked at {}.",
qprintln!("{}, {} was already linked at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
}
let changed = diff_link(
&sq,
&active_certification,
&builders[0], sq.time);
if ! changed && sq.force {
wprintln!(" Link parameters are unchanged, but \
qprintln!(" Link parameters are unchanged, but \
updating anyway as \"--force\" was specified.");
} else if c.temporary {
wprintln!(" Creating a temporary link, \
qprintln!(" Creating a temporary link, \
which expires in a week.");
} else if ! changed {
wprintln!(" Link parameters are unchanged, no update \
qprintln!(" Link parameters are unchanged, no update \
needed (specify \"--force\" to update anyway).");
// Return a signature packet to indicate that we
@ -548,11 +552,11 @@ pub fn add(sq: Sq, c: link::AddCommand)
// signature.
return Ok(vec![ Packet::from(userid.clone()) ]);
} else {
wprintln!(" Link parameters changed, updating link.");
qprintln!(" Link parameters changed, updating link.");
}
}
wprintln!("Linking {} and {:?}.",
qprintln!("Linking {} and {:?}.",
cert.fingerprint(), userid_str());
let mut sigs = builders.iter()
@ -569,7 +573,7 @@ pub fn add(sq: Sq, c: link::AddCommand)
})
.collect::<Result<Vec<Packet>>>()?;
wprintln!();
qprintln!();
let mut packets = vec![ Packet::from(userid.clone()) ];
packets.append(&mut sigs);
@ -604,6 +608,8 @@ pub fn add(sq: Sq, c: link::AddCommand)
pub fn retract(sq: Sq, c: link::RetractCommand)
-> Result<()>
{
make_qprintln!(sq.quiet);
let trust_root = sq.local_trust_root()?;
let trust_root = trust_root.to_cert()?;
let trust_root_kh = trust_root.key_handle();
@ -655,7 +661,7 @@ pub fn retract(sq: Sq, c: link::RetractCommand)
.any(|issuer| issuer.aliases(&trust_root_kh))
})
{
wprintln!("You never linked {:?} to {}, \
qprintln!("You never linked {:?} to {}, \
no need to retract it.",
userid_str(), cert.fingerprint());
return Ok(vec![]);
@ -670,26 +676,27 @@ pub fn retract(sq: Sq, c: link::RetractCommand)
let retracted = matches!(active_certification.trust_signature(),
Some((_depth, 0)));
if retracted {
wprintln!("{}, {} was already retracted at {}.",
qprintln!("{}, {} was already retracted at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
} else {
wprintln!("{}, {} was linked at {}.",
qprintln!("{}, {} was linked at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
}
let changed = diff_link(
&sq,
&active_certification,
&builder, sq.time);
if ! changed && sq.force {
wprintln!(" Link parameters are unchanged, but \
qprintln!(" Link parameters are unchanged, but \
updating anyway as \"--force\" was specified.");
} else if ! changed {
wprintln!(" Link parameters are unchanged, no update \
qprintln!(" Link parameters are unchanged, no update \
needed (specify \"--force\" to update anyway).");
// Return a signature packet to indicate that we
@ -697,14 +704,14 @@ pub fn retract(sq: Sq, c: link::RetractCommand)
// signature.
return Ok(vec![ Packet::from(userid.clone()) ]);
} else {
wprintln!(" Link parameters changed, updating link.");
qprintln!(" Link parameters changed, updating link.");
}
} else if sq.force {
wprintln!("There is no link to retract between {} and {:?}, \
qprintln!("There is no link to retract between {} and {:?}, \
retracting anyways as \"--force\" was specified.",
cert.fingerprint(), userid_str());
} else {
wprintln!("There is no link to retract between {} and {:?} \
qprintln!("There is no link to retract between {} and {:?} \
(specify \"--force\" to mark as retracted anyways).",
cert.fingerprint(), userid_str());
@ -714,7 +721,7 @@ pub fn retract(sq: Sq, c: link::RetractCommand)
return Ok(vec![ Packet::from(userid.clone()) ]);
}
wprintln!("Breaking link between {} and {:?}.",
qprintln!("Breaking link between {} and {:?}.",
cert.fingerprint(), userid_str());
// XXX: If we already have exactly this signature (modulo
@ -738,7 +745,7 @@ pub fn retract(sq: Sq, c: link::RetractCommand)
.collect::<Vec<Packet>>();
if certifications.is_empty() {
wprintln!("Nothing to retract.");
qprintln!("Nothing to retract.");
return Ok(());
}

View File

@ -296,6 +296,7 @@ fn main() -> Result<()> {
let sq = Sq {
verbose: c.verbose,
quiet: c.quiet,
force,
batch: c.batch,
policy: &policy,

View File

@ -79,6 +79,7 @@ pub struct Sq<'store, 'rstore>
where 'store: 'rstore
{
pub verbose: bool,
pub quiet: bool,
pub force: bool,
/// Prevent any kind of interactive prompting.
@ -1617,8 +1618,7 @@ impl<'store: 'rstore, 'rstore> Sq<'store, 'rstore> {
/// Prints a hint for the user.
pub fn hint(&self, msg: fmt::Arguments) -> Hint {
// XXX: If we gain a --quiet, pass it to Hint::new.
Hint::new(false)
Hint::new(self.quiet)
.hint(msg)
}
}