use std::time::SystemTime;
use clap::ArgMatches;
use sequoia_openpgp as openpgp;
use openpgp::{Cert, Result};
use openpgp::packet::prelude::*;
use openpgp::policy::HashAlgoSecurity;
use openpgp::policy::Policy;
use crate::Sq;
use crate::cli::encrypt::CompressionMode;
use crate::cli::types::FileOrStdout;
use crate::cli::types::MyAsRef;
use crate::cli::{SqCommand, SqSubcommands};
pub mod autocrypt;
pub mod cert;
pub mod config;
pub mod decrypt;
pub mod download;
pub mod encrypt;
pub mod keyring;
pub mod sign;
pub mod inspect;
pub mod key;
pub mod network;
pub mod packet;
pub mod pki;
pub mod verify;
pub mod version;
pub fn dispatch(sq: Sq, command: SqCommand, matches: &ArgMatches) -> Result<()>
{
let matches = matches.subcommand().unwrap().1;
match command.subcommand {
SqSubcommands::Encrypt(mut command) => {
command.profile_source = matches.value_source("profile");
encrypt::dispatch(sq, command)
},
SqSubcommands::Decrypt(command) =>
decrypt::dispatch(sq, command),
SqSubcommands::Sign(command) =>
sign::dispatch(sq, command),
SqSubcommands::Verify(command) =>
verify::dispatch(sq, command),
SqSubcommands::Download(command) =>
download::dispatch(sq, command),
SqSubcommands::Inspect(command) =>
inspect::dispatch(sq, command),
SqSubcommands::Cert(command) =>
cert::dispatch(sq, command),
SqSubcommands::Key(command) =>
key::dispatch(sq, command, matches),
SqSubcommands::Pki(command) =>
pki::dispatch(sq, command, matches),
SqSubcommands::Network(command) =>
network::dispatch(sq, command, matches),
SqSubcommands::Keyring(command) =>
keyring::dispatch(sq, command),
SqSubcommands::Packet(command) =>
packet::dispatch(sq, command),
SqSubcommands::Config(command) =>
config::dispatch(sq, command),
SqSubcommands::Version(command) =>
version::dispatch(sq, command),
}
}
pub fn active_certification<U>(
sq: &Sq,
cert: &Cert, userids: impl Iterator<Item=U>,
issuer: &Key<openpgp::packet::key::PublicParts,
openpgp::packet::key::UnspecifiedRole>)
-> Vec<(U, Option<Signature>)>
where
U: MyAsRef<UserID>
{
let issuer_kh = issuer.key_handle();
userids.map(|userid_ref| {
let userid = userid_ref.as_ref();
let ua = match cert.userids()
.filter(|ua| ua.userid() == userid).next()
{
Some(ua) => ua,
None => return (userid_ref, None),
};
let mut certifications = ua.bundle().certifications()
.filter(|sig| {
if let Some(ct) = sig.signature_creation_time() {
ct <= sq.time
&& sig.signature_validity_period()
.map(|vp| {
sq.time < ct + vp
})
.unwrap_or(true)
&& sig.get_issuers().iter().any(|i| i.aliases(&issuer_kh))
&& sq.policy.signature(
sig, HashAlgoSecurity::CollisionResistance).is_ok()
} else {
false
}
})
.collect::<Vec<&Signature>>();
certifications.sort_unstable_by(|a, b| {
a.signature_creation_time().unwrap()
.cmp(&b.signature_creation_time().unwrap())
.reverse()
.then(a.mpis().cmp(&b.mpis()))
});
let pk = ua.cert().primary_key().key();
let certification = certifications.into_iter()
.filter_map(|sig| {
let sig = sig.clone();
if sig.verify_userid_binding(issuer, pk, userid).is_ok() {
Some(sig)
} else {
None
}
})
.next();
(userid_ref, certification)
}).collect()
}
#[allow(dead_code)]
pub fn cert_stub(cert: Cert,
policy: &dyn Policy,
timestamp: Option<SystemTime>,
userid: Option<&UserID>)
-> Result<Cert>
{
let vc = cert.with_policy(policy, timestamp)?;
let mut packets = Vec::with_capacity(4);
packets.push(Packet::from(vc.primary_key().key().clone()));
let mut found = false;
if let Some(userid) = userid {
for u in vc.userids() {
if u.userid() == userid {
found = true;
packets.push(Packet::from(userid.clone()));
packets.push(Packet::from(u.binding_signature().clone()));
}
}
}
if ! found {
if let Ok(uid) = vc.primary_userid() {
packets.push(Packet::from(uid.userid().clone()));
packets.push(Packet::from(uid.binding_signature().clone()));
} else {
packets.push(
Packet::from(vc.primary_key().binding_signature().clone()));
}
if let Some(userid) = userid {
packets.push(Packet::from(userid.clone()));
}
}
Ok(Cert::from_packets(packets.into_iter())?)
}