Word-wrap lines in human-readable messages.

- Replace every eprintln by wprintln, which prints to stderr as
    well, but word-wraps the messages.
This commit is contained in:
Justus Winter 2023-11-29 16:13:37 +01:00
parent 0400ae88eb
commit 2ab3bd5efd
No known key found for this signature in database
GPG Key ID: 686F55B4AB2B3386
21 changed files with 187 additions and 146 deletions

1
Cargo.lock generated
View File

@ -3231,6 +3231,7 @@ dependencies = [
"tempfile",
"termcolor",
"terminal_size",
"textwrap",
"tokio",
]

View File

@ -53,6 +53,7 @@ roff = "0.2.1"
terminal_size = ">=0.2.6, <0.4"
is-terminal = "0.4.7"
termcolor = "1.2.0"
textwrap = "0.15"
[build-dependencies]
anyhow = "1.0.18"

View File

@ -171,7 +171,7 @@ fn get_keys<C>(certs: &[C], p: &dyn Policy,
keys.push((signer, Some(input_password.clone())));
continue 'next_cert;
},
Err(error) => eprintln!("Could not unlock key: {:?}", error),
Err(error) => wprintln!("Could not unlock key: {:?}", error),
}
}
}
@ -474,7 +474,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
p(&mut status, "bad checksum", self.bad_checksums);
p(&mut status, "broken signatures", self.broken_signatures);
if ! status.is_empty() {
eprintln!("{}.", status);
wprintln!("{}.", status);
}
}
@ -489,7 +489,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
let (sig, ka) = match result {
Ok(GoodChecksum { sig, ka, .. }) => (sig, ka),
Err(MalformedSignature { error, .. }) => {
eprintln!("Malformed signature:");
wprintln!("Malformed signature:");
print_error_chain(error);
self.broken_signatures += 1;
continue;
@ -502,19 +502,19 @@ impl<'a, 'store> VHelper<'a, 'store> {
0 => "checksum".into(),
n => format!("level {} notarizing checksum", n),
};
eprintln!("No key to check {} from {}", what, issuer);
wprintln!("No key to check {} from {}", what, issuer);
self.unknown_checksums += 1;
continue;
},
Err(UnboundKey { cert, error, .. }) => {
eprintln!("Signing key on {} is not bound:",
wprintln!("Signing key on {} is not bound:",
cert.fingerprint());
print_error_chain(error);
self.bad_checksums += 1;
continue;
},
Err(BadKey { ka, error, .. }) => {
eprintln!("Signing key on {} is bad:",
wprintln!("Signing key on {} is bad:",
ka.cert().fingerprint());
print_error_chain(error);
self.bad_checksums += 1;
@ -526,7 +526,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
0 => "checksum".into(),
n => format!("level {} notarizing checksum", n),
};
eprintln!("Error verifying {} from {}:",
wprintln!("Error verifying {} from {}:",
what, issuer);
print_error_chain(error);
self.bad_checksums += 1;
@ -549,7 +549,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
prefix = " ";
// Web of trust.
eprintln!("Authenticating {} ({:?}) using the web of trust:",
wprintln!("Authenticating {} ({:?}) using the web of trust:",
cert_fpr, signer_userid);
if let Ok(Some(cert_store)) = self.config.cert_store() {
@ -559,7 +559,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
let userids = if let Some(userid) = sig.signers_user_id() {
let userid = UserID::from(userid);
eprintln!("{}Signature was made by {}",
wprintln!("{}Signature was made by {}",
prefix,
String::from_utf8_lossy(userid.value()));
vec![ userid ]
@ -568,7 +568,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
};
if userids.is_empty() {
eprintln!("{}{} cannot be authenticated. \
wprintln!("{}{} cannot be authenticated. \
It has no User IDs",
prefix, cert_fpr);
} else if let Ok(n) = sequoia_wot::Network::new(&cert_store) {
@ -588,7 +588,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
let amount = paths.amount();
let authenticated = if amount >= sequoia_wot::FULLY_TRUSTED {
eprintln!("{}Fully authenticated \
wprintln!("{}Fully authenticated \
({} of {}) {}, {}",
prefix,
amount,
@ -597,7 +597,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
userid_str);
true
} else if amount > 0 {
eprintln!("{}Partially authenticated \
wprintln!("{}Partially authenticated \
({} of {}) {}, {:?} ",
prefix,
amount,
@ -606,7 +606,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
userid_str);
false
} else {
eprintln!("{}{}: {:?} is unauthenticated \
wprintln!("{}{}: {:?} is unauthenticated \
and may be an impersonation!",
prefix,
cert_fpr,
@ -616,7 +616,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
for (i, (path, amount)) in paths.iter().enumerate() {
let prefix = if paths.len() > 1 {
eprintln!("{} Path #{} of {}, \
wprintln!("{} Path #{} of {}, \
trust amount {}:",
prefix,
i + 1, paths.len(), amount);
@ -640,10 +640,10 @@ impl<'a, 'store> VHelper<'a, 'store> {
authenticated_userids[0].value()).to_string();
}
} else {
eprintln!("Failed to build web of trust network.");
wprintln!("Failed to build web of trust network.");
}
} else {
eprintln!("Skipping, certificate store has been disabled");
wprintln!("Skipping, certificate store has been disabled");
}
}
@ -653,27 +653,27 @@ impl<'a, 'store> VHelper<'a, 'store> {
let level = sig.level();
match (level == 0, trusted) {
(true, true) => {
eprintln!("{}Good signature from {} ({:?})",
wprintln!("{}Good signature from {} ({:?})",
prefix, label, signer_userid);
}
(false, true) => {
eprintln!("{}Good level {} notarization from {} ({:?})",
wprintln!("{}Good level {} notarization from {} ({:?})",
prefix, level, label, signer_userid);
}
(true, false) => {
eprintln!("{}Unauthenticated checksum from {} ({:?})",
wprintln!("{}Unauthenticated checksum from {} ({:?})",
prefix, label, signer_userid);
eprintln!("{} After checking that {} belongs to {:?}, \
wprintln!("{} After checking that {} belongs to {:?}, \
you can authenticate the binding using \
'sq link add {} {:?}'.",
prefix, issuer_str, signer_userid,
issuer_str, signer_userid);
}
(false, false) => {
eprintln!("{}Unauthenticated level {} notarizing \
wprintln!("{}Unauthenticated level {} notarizing \
checksum from {} ({:?})",
prefix, level, label, signer_userid);
eprintln!("{} After checking that {} belongs to {:?}, \
wprintln!("{} After checking that {} belongs to {:?}, \
you can authenticate the binding using \
'sq link add {} {:?}'.",
prefix, issuer_str, signer_userid,
@ -687,7 +687,7 @@ impl<'a, 'store> VHelper<'a, 'store> {
self.good_checksums += 1;
}
eprintln!("");
wprintln!("");
}
}
}
@ -726,13 +726,13 @@ impl<'a, 'store> VerificationHelper for VHelper<'a, 'store> {
for layer in structure {
match layer {
MessageLayer::Compression { algo } =>
eprintln!("Compressed using {}", algo),
wprintln!("Compressed using {}", algo),
MessageLayer::Encryption { sym_algo, aead_algo } =>
if let Some(aead_algo) = aead_algo {
eprintln!("Encrypted and protected using {}/{}",
wprintln!("Encrypted and protected using {}/{}",
sym_algo, aead_algo);
} else {
eprintln!("Encrypted using {}", sym_algo);
wprintln!("Encrypted using {}", sym_algo);
},
MessageLayer::SignatureGroup { ref results } =>
self.print_sigs(results),

View File

@ -65,16 +65,16 @@ pub fn certify(config: Config, c: certify::Command)
let userid = if let Some(userid) = u {
userid
} else {
eprintln!("User ID: '{}' not found.\nValid User IDs:", userid);
wprintln!("User ID: '{}' not found.\nValid User IDs:", userid);
let mut have_valid = false;
for ua in vc.userids() {
if let Ok(u) = std::str::from_utf8(ua.userid().value()) {
have_valid = true;
eprintln!(" - {}", u);
wprintln!(" - {}", u);
}
}
if ! have_valid {
eprintln!(" - Certificate has no valid User IDs.");
wprintln!(" - Certificate has no valid User IDs.");
}
return Err(anyhow::format_err!("No matching User ID found"));
};

View File

@ -215,7 +215,7 @@ impl<'a, 'certdb> Helper<'a, 'certdb> {
{
Some(sk) => {
if self.dump_session_key {
eprintln!("Session key: {}", hex::encode(&sk));
wprintln!("Session key: {}", hex::encode(&sk));
}
Some(self.key_identities.get(&keyid).cloned())
},
@ -261,7 +261,7 @@ impl<'a, 'certdb> DecryptionHelper for Helper<'a, 'certdb> {
.any(|sa| decrypt(sa, &sk.session_key))
};
if decrypted {
eprintln!("Encrypted with Session Key {}", sk.display_sensitive());
wprintln!("Encrypted with Session Key {}", sk.display_sensitive());
return Ok(None);
}
}
@ -303,7 +303,7 @@ impl<'a, 'certdb> DecryptionHelper for Helper<'a, 'certdb> {
match key.unlock(&p) {
Ok(decryptor) => break decryptor,
Err(error) => eprintln!("Could not unlock key: {:?}", error),
Err(error) => wprintln!("Could not unlock key: {:?}", error),
}
};
@ -359,7 +359,7 @@ impl<'a, 'certdb> DecryptionHelper for Helper<'a, 'certdb> {
if let Ok(decryptor) = key.unlock(&p) {
break decryptor;
} else {
eprintln!("Bad password.");
wprintln!("Bad password.");
}
};
@ -389,13 +389,13 @@ impl<'a, 'certdb> DecryptionHelper for Helper<'a, 'certdb> {
.and_then(|(algo, sk)| { if decrypt(algo, &sk) { Some(sk) } else { None }})
{
if self.dump_session_key {
eprintln!("Session key: {}", hex::encode(&sk));
wprintln!("Session key: {}", hex::encode(&sk));
}
return Ok(None);
}
}
eprintln!("Bad password.");
wprintln!("Bad password.");
}
}
}

View File

@ -45,7 +45,7 @@ pub fn dispatch<'store>(mut config: Config<'store>, cmd: import::Command)
let cert = match raw_cert {
Ok(raw_cert) => LazyCert::from(raw_cert),
Err(err) => {
eprintln!("Error parsing input: {}", err);
wprintln!("Error parsing input: {}", err);
stats.errors += 1;
continue;
}
@ -55,12 +55,12 @@ pub fn dispatch<'store>(mut config: Config<'store>, cmd: import::Command)
let userid = best_effort_primary_uid(
cert.to_cert()?, &policy, time).clone();
if let Err(err) = cert_store.update_by(Cow::Owned(cert), &mut stats) {
eprintln!("Error importing {}, {:?}: {}",
wprintln!("Error importing {}, {:?}: {}",
fingerprint, userid, err);
stats.errors += 1;
continue;
} else {
eprintln!("Imported {}, {}", fingerprint, Safe(&userid));
wprintln!("Imported {}, {}", fingerprint, Safe(&userid));
}
}
}
@ -70,7 +70,7 @@ pub fn dispatch<'store>(mut config: Config<'store>, cmd: import::Command)
let result = inner();
eprintln!("Imported {} new certificates, updated {} certificates, \
wprintln!("Imported {} new certificates, updated {} certificates, \
{} certificates unchanged, {} errors.",
stats.new, stats.updated, stats.unchanged, stats.errors);

View File

@ -56,7 +56,7 @@ pub fn dispatch(config: Config, c: inspect::Command)
if let Some(path) = input.inner() {
if ! path.exists() &&
format!("{}", input).parse::<KeyHandle>().is_ok() {
eprintln!("The file {} does not exist, \
wprintln!("The file {} does not exist, \
did you mean \"sq inspect --cert {}\"?",
input, input);
}

View File

@ -55,7 +55,7 @@ pub fn adopt(config: Config, command: cli::key::AdoptCommand) -> Result<()>
let vc = match cert.with_policy(adoptee_policy, None) {
Ok(vc) => vc,
Err(err) => {
eprintln!(
wprintln!(
"Ignoring {} from '{}': {}",
cert.keyid().to_hex(),
keyring.display(),

View File

@ -25,7 +25,7 @@ pub fn generate(
// User ID
if command.userid.is_empty() {
eprintln!("No user ID given, using direct key signature");
wprintln!("No user ID given, using direct key signature");
} else {
for uid in command.userid {
builder = builder.add_userid(uid);

View File

@ -109,14 +109,14 @@ impl<'a> SubkeyRevocation<'a> {
let rev = rev.build(&mut signer, &cert, subkey.key(), None)?;
Packet::Signature(rev)
} else {
eprintln!(
wprintln!(
"Subkey {} not found.\nValid subkeys:",
keyhandle.to_spaced_hex()
);
let mut have_valid = false;
for k in valid_cert.keys().subkeys() {
have_valid = true;
eprintln!(
wprintln!(
" - {} {} [{:?}]",
k.fingerprint().to_hex(),
DateTime::<Utc>::from(k.creation_time()).date_naive(),
@ -124,7 +124,7 @@ impl<'a> SubkeyRevocation<'a> {
);
}
if !have_valid {
eprintln!(" - Certificate has no subkeys.");
wprintln!(" - Certificate has no subkeys.");
}
return Err(anyhow!(
"The certificate does not contain the specified subkey."

View File

@ -89,7 +89,7 @@ impl<'a> UserIDRevocation<'a> {
.any(|u| u.value() == userid.as_bytes());
if !present {
eprintln!(
wprintln!(
"User ID, cert: Cert, secret: Option<Cert>: '{}' not found.\nValid User IDs:",
userid
);
@ -97,11 +97,11 @@ impl<'a> UserIDRevocation<'a> {
for ua in valid_cert.userids() {
if let Ok(u) = from_utf8(ua.userid().value()) {
have_valid = true;
eprintln!(" - {}", u);
wprintln!(" - {}", u);
}
}
if !have_valid {
eprintln!(" - Certificate has no valid User IDs.");
wprintln!(" - Certificate has no valid User IDs.");
}
return Err(anyhow!(
"The certificate does not contain the specified User \
@ -437,7 +437,7 @@ fn userid_strip(
if orig_cert_valid {
if let Err(err) = cert.with_policy(&config.policy, None) {
eprintln!(
wprintln!(
"Removing the User ID(s) has resulted in a invalid key:
{}

View File

@ -266,10 +266,10 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
Err(err) => {
if ! args.quiet {
if certi == 0 {
eprintln!("{:?} does not appear to be a keyring: {}",
wprintln!("{:?} does not appear to be a keyring: {}",
filename, err);
} else {
eprintln!("Encountered an error parsing {:?}: {}",
wprintln!("Encountered an error parsing {:?}: {}",
filename, err);
}
}
@ -296,7 +296,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
}
}
if ! args.quiet {
eprintln!($($arg)*);
wprintln!($($arg)*);
}
}
}};
@ -425,7 +425,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
}
Err(err) => {
unfixed_issue += 1;
eprintln!("Certificate {}: \
wprintln!("Certificate {}: \
Failed to update \
revocation certificate \
{:02X}{:02X}: {}",
@ -548,7 +548,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
}
Err(err) => {
unfixed_issue += 1;
eprintln!("Certificate {}: User ID {}: \
wprintln!("Certificate {}: User ID {}: \
Failed to update \
binding signature: {}",
cert.keyid().to_hex(),
@ -600,7 +600,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
Ok(sig) => updates.push(sig),
Err(err) => {
unfixed_issue += 1;
eprintln!("Certificate {}, key {}: \
wprintln!("Certificate {}, key {}: \
Failed to update \
binding signature: {}",
cert.keyid().to_hex(),
@ -649,7 +649,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
backsigs.dedup();
if backsigs.len() > 1 {
eprintln!("Warning: multiple cryptographically \
wprintln!("Warning: multiple cryptographically \
valid backsigs.");
}
@ -688,7 +688,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
Ok(sig) => updates.push(sig),
Err(err) => {
unfixed_issue += 1;
eprintln!("Certificate {}, key: {}: \
wprintln!("Certificate {}, key: {}: \
Failed to update \
binding signature: {}",
cert.keyid().to_hex(),
@ -751,12 +751,12 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
eprint!("GOOD");
}
}
eprintln!(")");
wprintln!(")");
}};
}
if certs_with_issues > 0 {
eprintln!("Examined {} {}.",
wprintln!("Examined {} {}.",
certs_valid + certs_invalid,
pl(certs_valid + certs_invalid,
"certificate", "certificates"));
@ -768,7 +768,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
pl(certs_invalid, "certificate is", "certificates are"),
pl(certs_invalid, "was", "were"));
if certs_valid > 0 {
eprintln!(" {} {} linted.",
wprintln!(" {} {} linted.",
certs_valid,
pl(certs_valid,
"certificate was", "certificates were"));
@ -779,7 +779,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
certs_valid + certs_invalid,
certs_with_issues * 100 / (certs_valid + certs_invalid),
pl(certs_with_issues, "has", "have"));
eprintln!("{} of the linted certificates {} revoked.",
wprintln!("{} of the linted certificates {} revoked.",
certs_revoked,
pl(certs_revoked, "was", "were"));
err!(certs_with_inadequota_revocations,
@ -788,10 +788,10 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
recreated.",
certs_with_inadequota_revocations,
certs_revoked);
eprintln!("{} of the linted certificates {} expired.",
wprintln!("{} of the linted certificates {} expired.",
certs_expired,
pl(certs_expired, "was", "were"));
eprintln!("{} of the non-revoked linted {} at least one non-revoked User ID:",
wprintln!("{} of the non-revoked linted {} at least one non-revoked User ID:",
certs_sp_sha1_userids,
pl(certs_sp_sha1_userids,
"certificate has", "certificates have"));
@ -804,7 +804,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
certs_with_only_sha1_protected_userids,
pl(certs_with_only_sha1_protected_userids,
"has", "have"));
eprintln!("{} of the non-revoked linted certificates {} at least one \
wprintln!("{} of the non-revoked linted certificates {} at least one \
non-revoked, live subkey:",
certs_with_subkeys,
pl(certs_with_subkeys,
@ -815,7 +815,7 @@ pub fn lint(config: Config, mut args: LintCommand) -> Result<()> {
certs_with_a_sha1_protected_binding_sig,
pl(certs_with_a_sha1_protected_binding_sig,
"has", "have"));
eprintln!("{} of the non-revoked linted certificates {} at least one non-revoked, live, \
wprintln!("{} of the non-revoked linted certificates {} at least one non-revoked, live, \
signing-capable subkey:",
certs_with_signing_subkeys,
pl(certs_with_signing_subkeys,

View File

@ -157,18 +157,18 @@ pub fn check_userids(config: &Config, cert: &Cert, self_signed: bool,
if known_userids.is_empty() {
if self_signed {
eprintln!("{} has no self-signed User IDs.",
wprintln!("{} has no self-signed User IDs.",
cert.fingerprint());
} else {
eprintln!("{} has no known User IDs.",
wprintln!("{} has no known User IDs.",
cert.fingerprint());
}
} else {
if self_signed {
eprintln!("{} has the following self-signed User IDs:",
wprintln!("{} has the following self-signed User IDs:",
cert.fingerprint());
} else {
eprintln!("{} has the following known User IDs:",
wprintln!("{} has the following known User IDs:",
cert.fingerprint());
}
@ -182,7 +182,7 @@ pub fn check_userids(config: &Config, cert: &Cert, self_signed: bool,
};
for (i, userid) in known_userids.iter().enumerate() {
eprintln!(
wprintln!(
" {}. {:?}{}",
i + 1, String::from_utf8_lossy(userid.value()),
if self_signed_userids.contains(userid) {
@ -219,7 +219,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
};
if a_expiration != b_expiration {
changed = true;
eprintln!(
wprintln!(
" Updating expiration time: {} -> {}.",
if let Some(a_expiration) = a_expiration {
chrono::DateTime::<chrono::offset::Utc>::from(
@ -240,12 +240,12 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
if a_amount != b_amount {
changed = true;
eprintln!(" Updating trust amount: {} -> {}.",
wprintln!(" Updating trust amount: {} -> {}.",
a_amount, b_amount);
}
if a_depth != b_depth {
changed = true;
eprintln!(" Update trust depth: {} -> {}.",
wprintln!(" Update trust depth: {} -> {}.",
a_depth, b_depth);
}
@ -258,7 +258,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
if a_regex != b_regex {
changed = true;
eprintln!(" Updating regular expressions:");
wprintln!(" Updating regular expressions:");
let a_regex: Vec<String> = a_regex.into_iter()
.enumerate()
.map(|(i, r)| {
@ -266,7 +266,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
i + 1, String::from_utf8_lossy(r))
})
.collect();
eprintln!(" Current link:\n {}",
wprintln!(" Current link:\n {}",
a_regex.join("\n "));
let b_regex: Vec<String> = b_regex.into_iter()
@ -276,7 +276,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
i + 1, String::from_utf8_lossy(r))
})
.collect();
eprintln!(" Updated link:\n {}",
wprintln!(" Updated link:\n {}",
b_regex.join("\n "));
}
@ -288,14 +288,14 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
.collect();
if a_notations != b_notations {
changed = true;
eprintln!(" Updating notations.");
wprintln!(" Updating notations.");
let a_notations: Vec<String> = a_notations.into_iter()
.enumerate()
.map(|(i, n)| {
format!("{}. {:?}", i + 1, n)
})
.collect();
eprintln!(" Current link:\n {}",
wprintln!(" Current link:\n {}",
a_notations.join("\n "));
let b_notations: Vec<String> = b_notations.into_iter()
@ -304,7 +304,7 @@ fn diff_link(old: &Signature, new: &SignatureBuilder, new_ct: SystemTime)
format!("{}. {:?}", i + 1, n)
})
.collect();
eprintln!(" Updated link:\n {}",
wprintln!(" Updated link:\n {}",
b_notations.join("\n "));
}
@ -312,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;
eprintln!(" Updating exportable flag: {} -> {}.",
wprintln!(" Updating exportable flag: {} -> {}.",
a_exportable, b_exportable);
}
@ -354,12 +354,12 @@ pub fn add(mut config: Config, c: link::AddCommand)
if c.all {
userids = vc.userids().map(|ua| ua.userid().clone()).collect();
} else {
eprintln!("No User IDs specified. \
wprintln!("No User IDs specified. \
Pass \"--all\" or one or more User IDs. \
{}'s self-signed User IDs are:",
cert.fingerprint());
for (i, userid) in vc.userids().enumerate() {
eprintln!(" {}. {:?}",
wprintln!(" {}. {:?}",
i + 1,
String::from_utf8_lossy(userid.value()));
}
@ -510,7 +510,7 @@ pub fn add(mut config: Config, c: link::AddCommand)
}
}
} else {
eprintln!("Note: {:?} is NOT a self signed User ID. \
wprintln!("Note: {:?} is NOT a self signed User ID. \
If this was a mistake, use \
`sq link retract {} \"{}\"` to undo it.",
userid_str(), cert.fingerprint(), userid);
@ -524,12 +524,12 @@ pub fn add(mut config: Config, c: link::AddCommand)
let retracted = matches!(active_certification.trust_signature(),
Some((_depth, 0)));
if retracted {
eprintln!("{}, {} was retracted at {}.",
wprintln!("{}, {} was retracted at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
} else {
eprintln!("{}, {} was already linked at {}.",
wprintln!("{}, {} was already linked at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
@ -540,13 +540,13 @@ pub fn add(mut config: Config, c: link::AddCommand)
&builders[0], config.time);
if ! changed && config.force {
eprintln!(" Link parameters are unchanged, but \
wprintln!(" Link parameters are unchanged, but \
updating anyway as \"--force\" was specified.");
} else if c.temporary {
eprintln!(" Creating a temporary link, \
wprintln!(" Creating a temporary link, \
which expires in a week.");
} else if ! changed {
eprintln!(" Link parameters are unchanged, no update \
wprintln!(" Link parameters are unchanged, no update \
needed (specify \"--force\" to update anyway).");
// Return a signature packet to indicate that we
@ -554,11 +554,11 @@ pub fn add(mut config: Config, c: link::AddCommand)
// signature.
return Ok(vec![ Packet::from(userid.clone()) ]);
} else {
eprintln!(" Link parameters changed, updating link.");
wprintln!(" Link parameters changed, updating link.");
}
}
eprintln!("Linking {} and {:?}.",
wprintln!("Linking {} and {:?}.",
cert.fingerprint(), userid_str());
let mut sigs = builders.iter()
@ -575,7 +575,7 @@ pub fn add(mut config: Config, c: link::AddCommand)
})
.collect::<Result<Vec<Packet>>>()?;
eprintln!();
wprintln!();
let mut packets = vec![ Packet::from(userid.clone()) ];
packets.append(&mut sigs);
@ -666,7 +666,7 @@ pub fn retract(mut config: Config, c: link::RetractCommand)
.any(|issuer| issuer.aliases(&trust_root_kh))
})
{
eprintln!("You never linked {:?} to {}, \
wprintln!("You never linked {:?} to {}, \
no need to retract it.",
userid_str(), cert.fingerprint());
return Ok(vec![]);
@ -681,12 +681,12 @@ pub fn retract(mut config: Config, c: link::RetractCommand)
let retracted = matches!(active_certification.trust_signature(),
Some((_depth, 0)));
if retracted {
eprintln!("{}, {} was already retracted at {}.",
wprintln!("{}, {} was already retracted at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
} else {
eprintln!("{}, {} was linked at {}.",
wprintln!("{}, {} was linked at {}.",
cert.fingerprint(), userid_str(),
chrono::DateTime::<chrono::offset::Utc>::from(
active_certification_ct));
@ -697,10 +697,10 @@ pub fn retract(mut config: Config, c: link::RetractCommand)
&builder, config.time);
if ! changed && config.force {
eprintln!(" Link parameters are unchanged, but \
wprintln!(" Link parameters are unchanged, but \
updating anyway as \"--force\" was specified.");
} else if ! changed {
eprintln!(" Link parameters are unchanged, no update \
wprintln!(" Link parameters are unchanged, no update \
needed (specify \"--force\" to update anyway).");
// Return a signature packet to indicate that we
@ -708,14 +708,14 @@ pub fn retract(mut config: Config, c: link::RetractCommand)
// signature.
return Ok(vec![ Packet::from(userid.clone()) ]);
} else {
eprintln!(" Link parameters changed, updating link.");
wprintln!(" Link parameters changed, updating link.");
}
} else if config.force {
eprintln!("There is no link to retract between {} and {:?}, \
wprintln!("There is no link to retract between {} and {:?}, \
retracting anyways as \"--force\" was specified.",
cert.fingerprint(), userid_str());
} else {
eprintln!("There is no link to retract between {} and {:?} \
wprintln!("There is no link to retract between {} and {:?} \
(specify \"--force\" to mark as retracted anyways).",
cert.fingerprint(), userid_str());
@ -725,7 +725,7 @@ pub fn retract(mut config: Config, c: link::RetractCommand)
return Ok(vec![ Packet::from(userid.clone()) ]);
}
eprintln!("Breaking link between {} and {:?}.",
wprintln!("Breaking link between {} and {:?}.",
cert.fingerprint(), userid_str());
// XXX: If we already have exactly this signature (modulo
@ -749,7 +749,7 @@ pub fn retract(mut config: Config, c: link::RetractCommand)
.collect::<Vec<Packet>>();
if certifications.is_empty() {
eprintln!("Nothing to retract.");
wprintln!("Nothing to retract.");
return Ok(());
}
@ -793,7 +793,7 @@ pub fn list(mut config: Config, c: link::ListCommand)
}
if amount == 0 {
eprintln!("{}, {:?}'s link was retracted.",
wprintln!("{}, {:?}'s link was retracted.",
cert.fingerprint(),
String::from_utf8_lossy(userid.value()));
} else {
@ -844,9 +844,9 @@ pub fn list(mut config: Config, c: link::ListCommand)
}
if ! params.is_empty() {
eprintln!(": {}.", params.join(", "));
wprintln!(": {}.", params.join(", "));
} else {
eprintln!(".");
wprintln!(".");
}
}
}

View File

@ -82,22 +82,22 @@ pub fn import_certs(config: &mut Config, certs: Vec<Cert>) -> Result<()> {
let mut stats
= cert_store::store::MergePublicCollectStats::new();
eprintln!("\nImporting {} certificates into the certificate store:\n",
wprintln!("\nImporting {} certificates into the certificate store:\n",
certs.len());
for (i, (fpr, userid, cert)) in certs.into_iter().enumerate() {
cert_store.update_by(Cow::Owned(cert.into()), &mut stats)
.with_context(|| format!("Inserting {}, {}", fpr, Safe(&userid)))?;
eprintln!(" {}. {} {}", i + 1, fpr, Safe(&userid));
wprintln!(" {}. {} {}", i + 1, fpr, Safe(&userid));
}
eprintln!("\nImported {} new certificates, \
wprintln!("\nImported {} new certificates, \
updated {} certificates, \
{} certificates unchanged, \
{} errors.",
stats.new, stats.updated, stats.unchanged,
stats.errors);
eprintln!("\nAfter checking that a certificate really belongs to the \
wprintln!("\nAfter checking that a certificate really belongs to the \
stated owner, you can mark the certificate as authenticated \
using: \n\
\n sq link add FINGERPRINT\n");
@ -235,7 +235,7 @@ fn get_ca(config: &mut Config,
})?;
if config.verbose {
eprintln!(
wprintln!(
"Created the local CA {:?} for certifying \
certificates downloaded from this service. \
The CA's trust amount is set to {} of {}. \
@ -249,7 +249,7 @@ fn get_ca(config: &mut Config,
use std::sync::Once;
static MSG: Once = Once::new();
MSG.call_once(|| {
eprintln!("Note: Created a local CA to record \
wprintln!("Note: Created a local CA to record \
provenance information.\n\
Note: See `sq link list --ca` \
and `sq link --help` for more \
@ -490,12 +490,12 @@ impl Response {
certs.push(cert);
}
},
Err(e) => eprintln!("{}: {}: {}",
Err(e) => wprintln!("{}: {}: {}",
response.method, response.query, e),
}
},
Err(e) =>
eprintln!("{}: {}: {}", response.method, response.query, e),
wprintln!("{}: {}: {}", response.method, response.query, e),
}
}
@ -676,14 +676,14 @@ pub fn dispatch_keyserver(config: Config, c: cli::keyserver::Command)
let (url, response) = response?;
match response {
Ok(()) => {
eprintln!("{}: ok", url);
wprintln!("{}: ok", url);
one_ok = true;
},
Err(e) => {
if result.is_ok() {
result = Err((url, e));
} else {
eprintln!("{}: {}", url, e);
wprintln!("{}: {}", url, e);
}
},
}
@ -695,7 +695,7 @@ pub fn dispatch_keyserver(config: Config, c: cli::keyserver::Command)
// error that we didn't yet report. Report that now,
// and clear it.
let (url, e) = result.unwrap_err();
eprintln!("{}: {}", url, e);
wprintln!("{}: {}", url, e);
result = Ok(());
}

View File

@ -76,8 +76,8 @@ fn compare_and_write_literal<'a, 'b, 'c>(
let lp1 = normalize_literal(lp1)?;
let lp2 = normalize_literal(lp2)?;
eprintln!("lp1: {:?}", lp1);
eprintln!("lp2: {:?}", lp2);
wprintln!("lp1: {:?}", lp1);
wprintln!("lp2: {:?}", lp2);
if lp1 == lp2 {
Ok((sink, ppr1, ppr2))

View File

@ -308,7 +308,7 @@ fn authenticate<S>(
if let Some(kh) = certificate {
match q.network().lookup_synopses(kh) {
Err(err) => {
eprintln!("Looking up target certificate ({}): {}",
wprintln!("Looking up target certificate ({}): {}",
kh, err);
}
Ok(certs) => {
@ -325,7 +325,7 @@ fn authenticate<S>(
match cert.revocation_status() {
RevocationStatus::Soft(_)
| RevocationStatus::Hard => {
eprintln!("Warning: {} is revoked.", kh);
wprintln!("Warning: {} is revoked.", kh);
}
RevocationStatus::NotAsFarAsWeKnow => (),
}
@ -333,14 +333,14 @@ fn authenticate<S>(
// Check if the certificate has expired.
if let Some(e) = cert.expiration_time() {
if e <= q.network().reference_time() {
eprintln!("Warning: {} is expired.", kh);
wprintln!("Warning: {} is expired.", kh);
}
}
// See if there is a matching self-signed User ID.
if let Some(userid) = userid {
if ! have_self_signed_userid(cert, userid, email) {
eprintln!("Warning: {} is not a \
wprintln!("Warning: {} is not a \
self-signed User ID for {}.",
userid, kh);
}
@ -358,7 +358,7 @@ fn authenticate<S>(
})
})
{
eprintln!("Warning: {} has no valid \
wprintln!("Warning: {} has no valid \
certifications.",
kh);
}
@ -377,7 +377,7 @@ fn authenticate<S>(
let userid_check = UserID::from(format!("<{}>", email));
if let Ok(Some(email_check)) = userid_check.email2() {
if email == email_check {
eprintln!("WARNING: {} appears to be a bare \
wprintln!("WARNING: {} appears to be a bare \
email address. Perhaps you forgot \
to specify --email.",
email);
@ -392,7 +392,7 @@ fn authenticate<S>(
if q.roots().iter().all(|r| {
let fpr = r.fingerprint();
if let Err(err) = q.network().lookup_synopsis_by_fpr(&fpr) {
eprintln!("Looking up trust root ({}): {}.",
wprintln!("Looking up trust root ({}): {}.",
fpr, err);
true
} else {
@ -400,16 +400,16 @@ fn authenticate<S>(
}
})
{
eprintln!("No trust roots found.");
wprintln!("No trust roots found.");
}
}
}
if ! authenticated {
if ! lint_input {
eprintln!("Could not authenticate any paths.");
wprintln!("Could not authenticate any paths.");
} else {
eprintln!("No paths found.");
wprintln!("No paths found.");
}
std::process::exit(1);
}
@ -446,7 +446,7 @@ where S: wot::store::Store + wot::store::Backend<'a>
match config.output_format {
#[cfg(feature = "dot-writer")]
crate::output::OutputFormat::DOT => {
eprintln!(
wprintln!(
"DOT output for \"sq wot path\" is not yet \
implemented!");
}
@ -469,7 +469,7 @@ where S: wot::store::Store + wot::store::Backend<'a>
match config.output_format {
#[cfg(feature = "dot-writer")]
crate::output::OutputFormat::DOT => {
eprintln!(
wprintln!(
"DOT output for \"sq wot path\" is not yet \
implemented!");
}
@ -494,7 +494,7 @@ struct KeyServerUpdate {
impl StatusListener for KeyServerUpdate {
fn update(&self, update: &StatusUpdate) {
eprintln!("{}", update);
wprintln!("{}", update);
}
}

View File

@ -12,3 +12,13 @@ macro_rules! platform {
}
}
}
/// Like eprintln, but nicely wraps lines.
macro_rules! wprintln {
{} => {
eprintln!();
};
{ $($arg: expr),* } => {
crate::output::wrapping::wprintln(format_args!($($arg),*))
};
}

View File

@ -11,6 +11,7 @@ use anyhow::{anyhow, Result};
use serde::Serialize;
pub mod sanitize;
pub mod wrapping;
pub use keyring::ListItem as KeyringListItem;
pub use wkd::WkdUrlVariant;

28
src/output/wrapping.rs Normal file
View File

@ -0,0 +1,28 @@
//! Line wrapping human-readable output.
use std::fmt;
use std::sync::OnceLock;
/// Prints the given message to stderr.
///
/// Hint: Use `wprintln!(..)` instead of invoking this function
/// directly.
pub fn wprintln(msg: fmt::Arguments) {
static OPTIONS: OnceLock<textwrap::Options> = OnceLock::new();
let options = OPTIONS.get_or_init(|| {
// It is better to use terminal_size instead of letting
// textwrap do it, because textwrap uses an older version,
// leading to duplicate crates.
let width =
terminal_size::terminal_size().map(|(w, _h)| w.0)
.unwrap_or(80)
.into();
textwrap::Options::new(width)
}).clone();
let m = format!("{}", msg);
for l in textwrap::wrap(&m, options) {
eprintln!("{}", l);
}
}

View File

@ -292,7 +292,7 @@ fn decrypt_key<R>(key: Key<key::SecretParts, R>, passwords: &mut Vec<String>)
}
}
Err(err) => {
eprintln!("While reading password: {}", err);
wprintln!("While reading password: {}", err);
break;
}
}
@ -313,7 +313,7 @@ fn decrypt_key<R>(key: Key<key::SecretParts, R>, passwords: &mut Vec<String>)
#[allow(dead_code)]
fn help_warning(arg: &str) {
if arg == "help" {
eprintln!("Warning: \"help\" is not a subcommand here. \
wprintln!("Warning: \"help\" is not a subcommand here. \
Did you mean --help?");
}
}
@ -611,11 +611,11 @@ impl<'store> Config<'store> {
}
if checked_id {
eprintln!("Error: {} does not have a key with \
wprintln!("Error: {} does not have a key with \
the required capabilities ({:?})",
cert.keyid(), keyflags);
} else {
eprintln!("Error: The subkey {} (cert: {}) \
wprintln!("Error: The subkey {} (cert: {}) \
does not the required capabilities \
({:?})",
kh, cert.keyid(), keyflags);
@ -685,7 +685,7 @@ impl<'store> Config<'store> {
for userid in userid.iter() {
let matches: Vec<(Fingerprint, UserID)> = if email {
if let Err(err) = UserIDQueryParams::is_email(userid) {
eprintln!("{:?} is not a valid email address", userid);
wprintln!("{:?} is not a valid email address", userid);
if error.is_none() {
error = Some(err);
}
@ -836,14 +836,14 @@ impl<'store> Config<'store> {
}
};
eprintln!("{:?}:\n", err);
wprintln!("{:?}:\n", err);
if error.is_none() {
error = Some(err);
}
// Print the errors.
for (i, Entry { fpr, userid, cert }) in bad.into_iter().enumerate() {
eprintln!("{}. When considering {} ({}):",
wprintln!("{}. When considering {} ({}):",
i + 1, fpr,
String::from_utf8_lossy(userid.value()));
let err = match cert {
@ -1008,7 +1008,7 @@ impl<'store> Config<'store> {
// Not found.
Ok(None) => None,
Err(err) => {
eprintln!("Error looking up local trust root: {}",
wprintln!("Error looking up local trust root: {}",
err);
None
}
@ -1020,20 +1020,20 @@ impl<'store> Config<'store> {
match parser.next() {
Some(Ok(cert)) => Some(cert.fingerprint()),
Some(Err(err)) => {
eprintln!("Local trust root is \
wprintln!("Local trust root is \
corrupted: {}",
err);
None
}
None => {
eprintln!("Local trust root is \
wprintln!("Local trust root is \
corrupted: no data");
None
}
}
}
Err(err) => {
eprintln!("Error parsing local trust root: {}",
wprintln!("Error parsing local trust root: {}",
err);
None
}
@ -1053,7 +1053,7 @@ impl<'store> Config<'store> {
/// Prints additional information in verbose mode.
fn info(&self, msg: fmt::Arguments) {
if self.verbose {
eprintln!("{}", msg);
wprintln!("{}", msg);
}
}
}
@ -1254,6 +1254,6 @@ fn error_chain(err: &anyhow::Error) -> Vec<String> {
/// Prints the error and causes, if any.
pub fn print_error_chain(err: &anyhow::Error) {
eprintln!(" {}", err);
err.chain().skip(1).for_each(|cause| eprintln!(" because: {}", cause));
wprintln!(" {}", err);
err.chain().skip(1).for_each(|cause| wprintln!(" because: {}", cause));
}

View File

@ -523,7 +523,7 @@ fn sq_link_update_detection() -> Result<()> {
// Make Alice a CA.
let output = sq_link(&certd, &alice_fpr, &[],
&["--ca", "*", "--all"], true);
assert!(output.2.contains("was already linked at"),
assert!(output.2.contains("was already linked"),
"stdout:\n{}\nstderr:\n{}", output.1, output.2);
let bytes = compare(bytes, &alice_cert_pgp, false);
@ -536,7 +536,7 @@ fn sq_link_update_detection() -> Result<()> {
// Make her a partially trusted CA.
let output = sq_link(&certd, &alice_fpr, &[],
&["--amount", "30", "--all"], true);
assert!(output.2.contains("was already linked at"),
assert!(output.2.contains("was already linked"),
"stdout:\n{}\nstderr:\n{}", output.1, output.2);
let bytes = compare(bytes, &alice_cert_pgp, false);