use failure::{self, ResultExt};
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::PathBuf;
use time;
use rpassword;
use tempfile::NamedTempFile;
extern crate openpgp;
use sequoia_core::Context;
use openpgp::armor;
use openpgp::constants::DataFormat;
use openpgp::{Packet, TPK, KeyID, Error, Result};
use openpgp::packet::Signature;
use openpgp::parse::PacketParserResult;
use openpgp::parse::stream::{
Verifier, VerificationResult, VerificationHelper,
};
use openpgp::serialize::Serialize;
use openpgp::serialize::stream::{
Message, Signer, LiteralWriter, Encryptor, EncryptionMode,
};
extern crate sequoia_store as store;
use super::create_or_stdout;
mod decrypt;
pub use self::decrypt::decrypt;
mod dump;
pub use self::dump::dump;
const TIMEFMT: &'static str = "%Y-%m-%dT%H:%M";
fn tm2str(t: &time::Tm) -> String {
time::strftime(TIMEFMT, t).expect("TIMEFMT is correct")
}
pub fn encrypt(store: &mut store::Store,
input: &mut io::Read, output: &mut io::Write,
npasswords: usize, recipients: Vec<&str>,
mut tpks: Vec<openpgp::TPK>, signers: Vec<openpgp::TPK>)
-> Result<()> {
for r in recipients {
tpks.push(store.lookup(r).context("No such key found")?.tpk()?);
}
let mut passwords = Vec::with_capacity(npasswords);
for n in 0..npasswords {
let nprompt = format!("Enter password {}: ", n + 1);
passwords.push(rpassword::prompt_password_stderr(
if npasswords > 1 {
&nprompt
} else {
"Enter password: "
})?.into());
}
// Build a vector of references to hand to Encryptor.
let recipients: Vec<&openpgp::TPK> = tpks.iter().collect();
let passwords_: Vec<&openpgp::Password> =
passwords.iter().collect();
// Stream an OpenPGP message.
let message = Message::new(output);
// We want to encrypt a literal data packet.
let mut sink = Encryptor::new(message,
&passwords_,
&recipients,
EncryptionMode::AtRest)
.context("Failed to create encryptor")?;
// Optionally sign message.
if ! signers.is_empty() {
let signers_: Vec<&openpgp::TPK> = signers.iter().collect();
sink = Signer::with_intended_recipients(sink, &signers_, &recipients)?;
}
let mut literal_writer = LiteralWriter::new(sink, DataFormat::Binary,
None, None)
.context("Failed to create literal writer")?;
// Finally, copy stdin to our writer stack to encrypt the data.
io::copy(input, &mut literal_writer)
.context("Failed to encrypt")?;
literal_writer.finalize()
.context("Failed to encrypt")?;
Ok(())
}
pub fn sign(input: &mut io::Read, output_path: Option<&str>,
secrets: Vec<openpgp::TPK>, detached: bool, binary: bool,
append: bool, notarize: bool)
-> Result<()> {
match (detached, append|notarize) {
(_, false) | (true, true) =>
sign_data(input, output_path, secrets, detached, binary, append),
(false, true) =>
sign_message(input, output_path, secrets, binary, notarize),
}
}
fn sign_data(input: &mut io::Read, output_path: Option<&str>,
secrets: Vec<openpgp::TPK>, detached: bool, binary: bool,
append: bool)