parent
81037e50d4
commit
b5ca6e27fe
@ -1,5 +1,3 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use buffered_reader::{BufferedReader, Dup};
|
use buffered_reader::{BufferedReader, Dup};
|
||||||
@ -9,12 +7,12 @@ use openpgp::{
|
|||||||
parse::{Cookie, Parse, stream::DecryptorBuilder},
|
parse::{Cookie, Parse, stream::DecryptorBuilder},
|
||||||
};
|
};
|
||||||
use sequoia_autocrypt as autocrypt;
|
use sequoia_autocrypt as autocrypt;
|
||||||
use sequoia_cert_store::{LazyCert, StoreUpdate};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Sq,
|
Sq,
|
||||||
commands::network::{
|
commands::{
|
||||||
certify_downloads,
|
cert::import::import_and_report,
|
||||||
|
network::certify_downloads,
|
||||||
},
|
},
|
||||||
output::import::ImportStats,
|
output::import::ImportStats,
|
||||||
};
|
};
|
||||||
@ -26,6 +24,7 @@ pub fn import_certs(sq: &mut Sq, source: &mut Box<dyn BufferedReader<Cookie>>,
|
|||||||
stats: &mut ImportStats)
|
stats: &mut ImportStats)
|
||||||
-> Result<()>
|
-> Result<()>
|
||||||
{
|
{
|
||||||
|
let o = &mut std::io::stdout();
|
||||||
let mut acc = Vec::new();
|
let mut acc = Vec::new();
|
||||||
|
|
||||||
// First, get the Autocrypt headers from the outside.
|
// 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::*;
|
use autocrypt::AutocryptHeaderType::*;
|
||||||
let mut sender_cert = None;
|
let mut sender_cert = None;
|
||||||
|
let mut provenance_recorded = false;
|
||||||
for h in ac.headers.into_iter().filter(|h| h.header_type == Sender) {
|
for h in ac.headers.into_iter().filter(|h| h.header_type == Sender) {
|
||||||
if let Some(addr) = h.attributes.iter()
|
if let Some(addr) = h.attributes.iter()
|
||||||
.find_map(|a| (&a.key == "addr"
|
.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(
|
acc.append(&mut certify_downloads(
|
||||||
sq, false, ca,
|
sq, false, ca,
|
||||||
vec![cert], Some(&addr[..])));
|
vec![cert], Some(&addr[..])));
|
||||||
|
provenance_recorded = true;
|
||||||
} else {
|
} else {
|
||||||
acc.push(cert);
|
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()?;
|
import_and_report(o, sq, acc, None, stats, |o, _| {
|
||||||
for cert in acc.drain(..) {
|
if provenance_recorded {
|
||||||
cert_store.update_by(Arc::new(LazyCert::from(cert)), stats)?;
|
wwriteln!(stream = o, initial_indent = " - ",
|
||||||
}
|
"provenance information recorded");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
// If there is no Autocrypt header, don't bother looking for
|
// If there is no Autocrypt header, don't bother looking for
|
||||||
// gossip.
|
// 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."));
|
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) {
|
for h in ac.headers.into_iter().filter(|h| h.header_type == Gossip) {
|
||||||
if let Some(_addr) = h.attributes.iter()
|
if let Some(_addr) = h.attributes.iter()
|
||||||
.find_map(|a| (&a.key == "addr").then(|| a.value.clone()))
|
.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 {
|
import_and_report(o, sq, acc, None, stats, |_, _| Ok(()))?;
|
||||||
cert_store.update_by(Arc::new(LazyCert::from(cert)), stats)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,67 @@ where 'store: 'rstore
|
|||||||
Ok(result?)
|
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.
|
/// Imports certs encoded as OpenPGP keyring.
|
||||||
fn import_certs(o: &mut dyn std::io::Write,
|
fn import_certs(o: &mut dyn std::io::Write,
|
||||||
sq: &mut Sq,
|
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 dup = Dup::with_cookie(source, Cookie::default());
|
||||||
let raw_certs = RawCertParser::from_buffered_reader(dup)?;
|
let raw_certs = RawCertParser::from_buffered_reader(dup)?;
|
||||||
let cert_store = sq.cert_store_or_else()?;
|
|
||||||
|
|
||||||
let mut one_ok = false;
|
let mut one_ok = false;
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
@ -153,32 +213,8 @@ fn import_certs(o: &mut dyn std::io::Write,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if cert.is_tsk() {
|
import_and_report(o, sq, vec![cert], source_path, stats,
|
||||||
let mut cmd = sq.hint(format_args!(
|
|_, _| Ok(()))?;
|
||||||
"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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! one_ok {
|
if ! one_ok {
|
||||||
|
Loading…
Reference in New Issue
Block a user