parent
81037e50d4
commit
b5ca6e27fe
@ -1,5 +1,3 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use buffered_reader::{BufferedReader, Dup};
|
||||
@ -9,12 +7,12 @@ use openpgp::{
|
||||
parse::{Cookie, Parse, stream::DecryptorBuilder},
|
||||
};
|
||||
use sequoia_autocrypt as autocrypt;
|
||||
use sequoia_cert_store::{LazyCert, StoreUpdate};
|
||||
|
||||
use crate::{
|
||||
Sq,
|
||||
commands::network::{
|
||||
certify_downloads,
|
||||
commands::{
|
||||
cert::import::import_and_report,
|
||||
network::certify_downloads,
|
||||
},
|
||||
output::import::ImportStats,
|
||||
};
|
||||
@ -26,6 +24,7 @@ pub fn import_certs(sq: &mut Sq, source: &mut Box<dyn BufferedReader<Cookie>>,
|
||||
stats: &mut ImportStats)
|
||||
-> Result<()>
|
||||
{
|
||||
let o = &mut std::io::stdout();
|
||||
let mut acc = Vec::new();
|
||||
|
||||
// First, get the Autocrypt headers from the outside.
|
||||
@ -39,6 +38,7 @@ pub fn import_certs(sq: &mut Sq, source: &mut Box<dyn BufferedReader<Cookie>>,
|
||||
|
||||
use autocrypt::AutocryptHeaderType::*;
|
||||
let mut sender_cert = None;
|
||||
let mut provenance_recorded = false;
|
||||
for h in ac.headers.into_iter().filter(|h| h.header_type == Sender) {
|
||||
if let Some(addr) = h.attributes.iter()
|
||||
.find_map(|a| (&a.key == "addr"
|
||||
@ -54,6 +54,7 @@ pub fn import_certs(sq: &mut Sq, source: &mut Box<dyn BufferedReader<Cookie>>,
|
||||
acc.append(&mut certify_downloads(
|
||||
sq, false, ca,
|
||||
vec![cert], Some(&addr[..])));
|
||||
provenance_recorded = true;
|
||||
} else {
|
||||
acc.push(cert);
|
||||
}
|
||||
@ -61,10 +62,14 @@ pub fn import_certs(sq: &mut Sq, source: &mut Box<dyn BufferedReader<Cookie>>,
|
||||
}
|
||||
}
|
||||
|
||||
let cert_store = sq.cert_store_or_else()?;
|
||||
for cert in acc.drain(..) {
|
||||
cert_store.update_by(Arc::new(LazyCert::from(cert)), stats)?;
|
||||
}
|
||||
import_and_report(o, sq, acc, None, stats, |o, _| {
|
||||
if provenance_recorded {
|
||||
wwriteln!(stream = o, initial_indent = " - ",
|
||||
"provenance information recorded");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// If there is no Autocrypt header, don't bother looking for
|
||||
// gossip.
|
||||
@ -108,6 +113,7 @@ pub fn import_certs(sq: &mut Sq, source: &mut Box<dyn BufferedReader<Cookie>>,
|
||||
return Err(anyhow::anyhow!("Message is not encrypted."));
|
||||
}
|
||||
|
||||
let mut acc = Vec::new();
|
||||
for h in ac.headers.into_iter().filter(|h| h.header_type == Gossip) {
|
||||
if let Some(_addr) = h.attributes.iter()
|
||||
.find_map(|a| (&a.key == "addr").then(|| a.value.clone()))
|
||||
@ -118,9 +124,7 @@ pub fn import_certs(sq: &mut Sq, source: &mut Box<dyn BufferedReader<Cookie>>,
|
||||
}
|
||||
}
|
||||
|
||||
for cert in acc {
|
||||
cert_store.update_by(Arc::new(LazyCert::from(cert)), stats)?;
|
||||
}
|
||||
import_and_report(o, sq, acc, None, stats, |_, _| Ok(()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -124,6 +124,67 @@ where 'store: 'rstore
|
||||
Ok(result?)
|
||||
}
|
||||
|
||||
/// Reports on a successfully imported cert.
|
||||
pub fn emit_cert(o: &mut dyn std::io::Write, sq: &Sq, cert: &openpgp::Cert)
|
||||
-> Result<()>
|
||||
{
|
||||
wwriteln!(stream = o,
|
||||
initial_indent = " - ┌ ", subsequent_indent = " │ ",
|
||||
"{}", cert.fingerprint());
|
||||
wwriteln!(stream = o,
|
||||
initial_indent = " └ ",
|
||||
"{}", sq.best_userid(cert, true));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Imports the certs and reports on the individual certs.
|
||||
pub fn import_and_report<F>(o: &mut dyn std::io::Write,
|
||||
sq: &mut Sq,
|
||||
certs: Vec<openpgp::Cert>,
|
||||
source_path: Option<&PathBuf>,
|
||||
stats: &mut ImportStats,
|
||||
additional: F)
|
||||
-> Result<()>
|
||||
where
|
||||
F: Fn(&mut dyn std::io::Write, &openpgp::Cert)
|
||||
-> Result<()>,
|
||||
{
|
||||
let cert_store = sq.cert_store_or_else()?;
|
||||
|
||||
for cert in certs {
|
||||
emit_cert(o, sq, &cert)?;
|
||||
let cert = Arc::new(LazyCert::from(cert));
|
||||
if let Err(err) = cert_store.update_by(cert.clone(), stats) {
|
||||
wwriteln!(stream = o,
|
||||
initial_indent = " - ", "failed: {}", err);
|
||||
wwriteln!(o);
|
||||
stats.certs.inc_errors();
|
||||
continue;
|
||||
} else {
|
||||
wwriteln!(stream = o,
|
||||
initial_indent = " - ", "imported");
|
||||
}
|
||||
|
||||
additional(o, cert.to_cert().expect("was a cert"))?;
|
||||
|
||||
if cert.is_tsk() {
|
||||
let mut cmd = sq.hint(format_args!(
|
||||
"Certificate {} contains secret key material. \
|
||||
To import keys, do:", cert.fingerprint()))
|
||||
.sq().arg("key").arg("import");
|
||||
|
||||
if let Some(file) = source_path {
|
||||
cmd = cmd.arg(file.display());
|
||||
}
|
||||
|
||||
cmd.done();
|
||||
}
|
||||
}
|
||||
|
||||
wwriteln!(o);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Imports certs encoded as OpenPGP keyring.
|
||||
fn import_certs(o: &mut dyn std::io::Write,
|
||||
sq: &mut Sq,
|
||||
@ -134,7 +195,6 @@ fn import_certs(o: &mut dyn std::io::Write,
|
||||
{
|
||||
let dup = Dup::with_cookie(source, Cookie::default());
|
||||
let raw_certs = RawCertParser::from_buffered_reader(dup)?;
|
||||
let cert_store = sq.cert_store_or_else()?;
|
||||
|
||||
let mut one_ok = false;
|
||||
let mut errors = Vec::new();
|
||||
@ -153,32 +213,8 @@ fn import_certs(o: &mut dyn std::io::Write,
|
||||
}
|
||||
};
|
||||
|
||||
if cert.is_tsk() {
|
||||
let mut cmd = sq.hint(format_args!(
|
||||
"Certificate {} contains secret key material. \
|
||||
To import keys, do:", cert.fingerprint()))
|
||||
.sq().arg("key").arg("import");
|
||||
|
||||
if let Some(file) = source_path {
|
||||
cmd = cmd.arg(file.display());
|
||||
}
|
||||
|
||||
cmd.done();
|
||||
}
|
||||
|
||||
|
||||
let fingerprint = cert.fingerprint();
|
||||
let sanitized_userid = sq.best_userid(&cert, true);
|
||||
if let Err(err) = cert_store.update_by(Arc::new(cert.into()),
|
||||
stats)
|
||||
{
|
||||
wwriteln!(o, "Error importing {}, {}: {}",
|
||||
fingerprint, sanitized_userid, err);
|
||||
stats.certs.inc_errors();
|
||||
continue;
|
||||
} else {
|
||||
wwriteln!(o, "Imported {}, {}", fingerprint, sanitized_userid);
|
||||
}
|
||||
import_and_report(o, sq, vec![cert], source_path, stats,
|
||||
|_, _| Ok(()))?;
|
||||
}
|
||||
|
||||
if ! one_ok {
|
||||
|
Loading…
Reference in New Issue
Block a user