use std::borrow::Borrow;
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use sequoia_openpgp as openpgp;
use openpgp::Fingerprint;
use openpgp::regex::RegexSet;
use crate::Certification;
use crate::Depth;
use crate::Path;
use crate::TRACE;
pub trait CertificationFilter {
fn cost(&self,
_c: &Certification,
_depth: &mut Depth,
_amount: &mut usize,
_ignores_regex: bool,
_regexs: &mut Option<RegexSet>)
-> bool
{
true
}
}
pub struct IdempotentCertificationFilter {
}
#[allow(dead_code)]
impl IdempotentCertificationFilter {
pub(crate) fn new() -> Self {
Self {}
}
}
impl CertificationFilter for IdempotentCertificationFilter {}
pub struct ChainFilter<'a> {
filters: Vec<Box<dyn CertificationFilter + 'a>>,
}
impl CertificationFilter for ChainFilter<'_> {
fn cost(&self,
c: &Certification,
depth: &mut Depth,
amount: &mut usize,
ignore_regex: bool,
regexs: &mut Option<RegexSet>)
-> bool
{
tracer!(TRACE, "ChainFilter::cost");
for (i, f) in self.filters.iter().enumerate() {
let old_depth = depth.clone();
let old_amount = *amount;
if ! f.cost(c, depth, amount, ignore_regex, regexs) {
return false;
}
t!("{}.: {}/{} -> {}/{}",
i, old_depth, old_amount, depth, amount);
}
return true;
}
}
impl<'a> ChainFilter<'a> {
pub fn new() -> Self {
Self {
filters: Vec::new(),
}
}
pub fn push<F>(&mut self, filter: F)
where F: 'a + CertificationFilter
{
self.filters.push(Box::new(filter));
}
}
pub struct SuppressCertificationFilter {
amount: BTreeMap<(Fingerprint, Fingerprint), usize>,
}
impl CertificationFilter for SuppressCertificationFilter {
fn cost(&self,
c: &Certification,
_depth: &mut Depth,
amount: &mut usize,
_ignore_regexs: bool,
_regexs: &mut Option<RegexSet>)
-> bool
{
tracer!(TRACE, "SuppressCertificationFilter::cost");
if let Some(&delta) = self.amount.get(
&(c.issuer().fingerprint(), c.target().fingerprint()))
{
let new_amount = std::cmp::max(*amount, delta) - delta;
t!("Suppressing trust amount: {} -> {}", amount, new_amount);
*amount = new_amount;
}
return true;
}
}
impl SuppressCertificationFilter {
pub fn new() -> Self {
Self {
amount: BTreeMap::new(),
}
}
pub fn suppress_path(&mut self, path: &Path, amount_to_suppress: usize) {
if amount_to_suppress == 0 {
return;
}
assert!(amount_to_suppress <= 120);
for c in path.certifications() {
match self.amount.entry(
(c.issuer().fingerprint(), c.target().fingerprint()))
{
Entry::Occupied(mut oe) => {
let amount = oe.get_mut();
*amount += amount_to_suppress;
assert!(*amount <= 120);
}
e @ Entry::Vacant(_) => {
e.or_insert(amount_to_suppress);
}
}
}
}
}
pub struct SuppressIssuerFilter {
amount: BTreeMap<Fingerprint, usize>,
}
impl CertificationFilter for SuppressIssuerFilter {
fn cost(&self,
c: &Certification,
_depth: &mut Depth,
amount: &mut usize,
_ignore_regexs: bool,
_regexs: &mut Option<RegexSet>)
-> bool
{
tracer!(TRACE, "SuppressIssuerFilter::cost");
if let Some(&delta) = self.amount.get(&c.issuer().fingerprint()) {
let new_amount = std::cmp::max(*amount, delta) - delta;
t!("Suppressing trust amount: {} -> {}", amount, new_amount);
*amount = new_amount;
}
return true;
}
}
impl SuppressIssuerFilter {
pub fn new() -> Self {
Self {
amount: BTreeMap::new(),
}
}
pub fn suppress_issuer<F>(&mut self, fingerprint: F,
amount_to_suppress: usize)
where F: Borrow<Fingerprint>
{
let fingerprint = fingerprint.borrow();
if amount_to_suppress == 0 {
return;
}
assert!(amount_to_suppress <= 120);
match self.amount.entry(fingerprint.clone()) {
Entry::Occupied(mut oe) => {
let amount = oe.get_mut();
*amount += amount_to_suppress;
assert!(*amount <= 120);
}
e @ Entry::Vacant(_) => {
e.or_insert(amount_to_suppress);
}
}
}
}
pub struct CapCertificateFilter {
cap: BTreeMap<Fingerprint, usize>,
}
impl CertificationFilter for CapCertificateFilter {
fn cost(&self,
c: &Certification,
_depth: &mut Depth,
amount: &mut usize,
_ignore_regexs: bool,
_regexs: &mut Option<RegexSet>)
-> bool
{
tracer!(TRACE, "CapCertificateFilter::cost");
if let Some(&cap) = self.cap.get(&c.issuer().fingerprint()) {
let new_amount = std::cmp::min(*amount, cap);
t!("Capping trust amount: {} -> {}", amount, new_amount);
*amount = new_amount;
}
return true;
}
}
impl CapCertificateFilter {
pub fn new() -> Self {
Self {
cap: BTreeMap::new(),
}
}
pub fn cap(&mut self, cert: Fingerprint, cap: usize) {
match self.cap.entry(cert) {
Entry::Occupied(mut oe) => {
let current_cap = oe.get_mut();
*current_cap = std::cmp::min(*current_cap, cap);
}
e @ Entry::Vacant(_) => {
e.or_insert(cap);
}
}
}
}
pub struct TrustedIntroducerFilter {
}
impl CertificationFilter for TrustedIntroducerFilter {
fn cost(&self,
_c: &Certification,
depth: &mut Depth,
_amount: &mut usize,
ignore_regexs: bool,
regexs: &mut Option<RegexSet>)
-> bool
{
tracer!(TRACE, "TrustedIntroducerFilter::cost");
*depth = Depth::Unconstrained;
if ! ignore_regexs {
*regexs = None;
}
return true;
}
}
impl TrustedIntroducerFilter {
pub fn new() -> Self {
Self {
}
}
}
pub struct CapDepthFilter {
cap: Depth,
}
impl CertificationFilter for CapDepthFilter {
fn cost(&self,
_c: &Certification,
depth: &mut Depth,
_amount: &mut usize,
_ignore_regexs: bool,
_regexs: &mut Option<RegexSet>)
-> bool
{
*depth = (*depth).min(self.cap);
true
}
}
impl CapDepthFilter {
pub fn new(cap: usize) -> Self {
Self {
cap: Depth::Limit(cap),
}
}
}