From e42e570911a3372f2a136d0f375366fbf7c0035d Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Wed, 28 Jun 2023 15:16:31 +0200 Subject: [PATCH] Implementation of Filters --- .../dijkstra/filter/CapCertificateFilter.kt | 39 +++++++++++++++ .../dijkstra/filter/CertificationFilter.kt | 40 +++++++++++++++ .../wot/dijkstra/filter/ChainFilter.kt | 29 +++++++++++ .../filter/IdempotentCertificationFilter.kt | 12 +++++ .../filter/SuppressCertificationFilter.kt | 50 +++++++++++++++++++ .../dijkstra/filter/SuppressIssuerFilter.kt | 50 +++++++++++++++++++ .../filter/TrustedIntroducerFilter.kt | 27 ++++++++++ 7 files changed, 247 insertions(+) create mode 100644 wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CapCertificateFilter.kt create mode 100644 wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CertificationFilter.kt create mode 100644 wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/ChainFilter.kt create mode 100644 wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/IdempotentCertificationFilter.kt create mode 100644 wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressCertificationFilter.kt create mode 100644 wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressIssuerFilter.kt create mode 100644 wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/TrustedIntroducerFilter.kt diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CapCertificateFilter.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CapCertificateFilter.kt new file mode 100644 index 00000000..ccaf8096 --- /dev/null +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CapCertificateFilter.kt @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2023 Heiko Schaefer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.dijkstra.filter + +import org.pgpainless.wot.network.EdgeComponent +import org.pgpainless.wot.network.Fingerprint + +class CapCertificateFilter() : CertificationFilter { + + // A certificate's trust amount will be limited to this amount. + private val caps: HashMap = hashMapOf() + + override fun cost(ec: EdgeComponent, values: FilterValues, ignoreRegexps: Boolean): Boolean { + caps[ec.issuer.fingerprint]?.let { + if (it < values.amount) { + values.amount = it + } + } + + return true + } + + /** + * Add rules for the certificate. + * + * Any certifications issued by the certificate have their trust + * amount limited to `cap`. If a certificate is capped multiple + * times, then the minimum cap is used. + */ + fun cap(cert: Fingerprint, cap: Int) { + val current = caps[cert] + + if ((current == null) || (current > cap)) { + caps[cert] = cap + } + } +} diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CertificationFilter.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CertificationFilter.kt new file mode 100644 index 00000000..a8cc7451 --- /dev/null +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/CertificationFilter.kt @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2023 Heiko Schaefer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.dijkstra.filter + +import org.pgpainless.wot.network.Depth +import org.pgpainless.wot.network.EdgeComponent +import org.pgpainless.wot.network.RegexSet + +/** + * Current effective values for `depth`, `amount` and `regexps`. + * + * `regexps` is optional: + * Rewriting the regular expressions may be expensive. By setting regexps to + * `null`, the caller can signal that it doesn't care about the regular expressions. + */ +data class FilterValues(var depth: Depth, var amount: Int, var regexps: RegexSet?) + +/** + * A mechanism to filter certifications. + * + * This function should change the content of `values` in place. + * This enables chaining of multiple filters. + * + * This is particularly useful when evaluating a residual network, + * i.e., a network minus the capacity used by a particular path. + */ +interface CertificationFilter { + + /** + * Filter the certification's parameters. + * + * If the function returns `false`, the certification should be skipped. + */ + fun cost(ec: EdgeComponent, values: FilterValues, ignoreRegexps: Boolean): Boolean { + return true + } + +} diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/ChainFilter.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/ChainFilter.kt new file mode 100644 index 00000000..c2664088 --- /dev/null +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/ChainFilter.kt @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2023 Heiko Schaefer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.dijkstra.filter + +import org.pgpainless.wot.network.EdgeComponent + +/** + * A filter that chains multiple filters together. + * + * The filters are called in the order that they are added. If a + * filter returns `false`, then this filter immediately returns + * false. + */ +class ChainFilter() : CertificationFilter { + private val filters: MutableList = mutableListOf() + + override fun cost(ec: EdgeComponent, values: FilterValues, ignoreRegexps: Boolean): Boolean { + + // If any inner filter returns `false`, immediately return false + return !this.filters.any { !it.cost(ec, values, ignoreRegexps) } + } + + /** + * Add `filter` to the chain + */ + fun add(filter: CertificationFilter) = filters.add(filter) +} diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/IdempotentCertificationFilter.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/IdempotentCertificationFilter.kt new file mode 100644 index 00000000..e3cb26c3 --- /dev/null +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/IdempotentCertificationFilter.kt @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2023 Heiko Schaefer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.dijkstra.filter + +/** + * A no-op filter. + * + * This filter passes certifications through as is. + */ +class IdempotentCertificationFilter : CertificationFilter \ No newline at end of file diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressCertificationFilter.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressCertificationFilter.kt new file mode 100644 index 00000000..24c7635c --- /dev/null +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressCertificationFilter.kt @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2023 Heiko Schaefer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.dijkstra.filter + +import org.pgpainless.wot.network.EdgeComponent +import org.pgpainless.wot.network.Fingerprint +import org.pgpainless.wot.query.Path + + +class SuppressCertificationFilter() : CertificationFilter { + // A certification's trust amount will be suppressed by this amount. + private val amount: HashMap, Int> = hashMapOf() + + override fun cost(ec: EdgeComponent, values: FilterValues, ignoreRegexps: Boolean): Boolean { + amount[Pair(ec.issuer.fingerprint, ec.target.fingerprint)]?.let { suppress -> + values.amount = if (values.amount > suppress) { + values.amount - suppress + } else { + 0 + } + } + + return true + } + + /** + * Add suppression rules for all certifications along the specified path. + * + * Each edge is suppressed by `amountToSuppress`. + */ + fun suppressPath(path: Path, amountToSuppress: Int) { + if (amountToSuppress == 0) { + return + } + assert(amountToSuppress <= 120) + + for (c in path.certifications) { + val a = amount[Pair(c.issuer.fingerprint, c.target.fingerprint)] + if (a != null) { + val newAmount = a + amountToSuppress + assert(newAmount <= 120) + amount[Pair(c.issuer.fingerprint, c.target.fingerprint)] = newAmount + } else { + amount[Pair(c.issuer.fingerprint, c.target.fingerprint)] = amountToSuppress + } + } + } +} \ No newline at end of file diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressIssuerFilter.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressIssuerFilter.kt new file mode 100644 index 00000000..9d88ccf2 --- /dev/null +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/SuppressIssuerFilter.kt @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2023 Heiko Schaefer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.dijkstra.filter + +import org.pgpainless.wot.network.EdgeComponent +import org.pgpainless.wot.network.Fingerprint + +/** + * A filter that suppresses some capacity of an issuer. + */ +class SuppressIssuerFilter() : CertificationFilter { + // A certification's trust amount will be suppressed by this amount. + private val amount: HashMap = hashMapOf() + + override fun cost(ec: EdgeComponent, values: FilterValues, ignoreRegexps: Boolean): Boolean { + amount[ec.issuer.fingerprint]?.let { suppress -> + values.amount = if (values.amount > suppress) { + values.amount - suppress + } else { + 0 + } + } + + return true + } + + /** + * Add suppression rules for the issuer. + * + * Any certifications that the certificate makes are suppressed + * (decreased) by that amount. + */ + fun suppressIssuer(issuer: Fingerprint, amountToSuppress: Int) { + if (amountToSuppress == 0) { + return + } + assert(amountToSuppress <= 120) + + val a = amount[issuer] + if (a != null) { + val am = a + amountToSuppress + assert(am <= 120) + amount[issuer] = am + } else { + amount[issuer] = amountToSuppress + } + } +} \ No newline at end of file diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/TrustedIntroducerFilter.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/TrustedIntroducerFilter.kt new file mode 100644 index 00000000..530a2c8f --- /dev/null +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/filter/TrustedIntroducerFilter.kt @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2023 Heiko Schaefer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.dijkstra.filter + +import org.pgpainless.wot.network.Depth +import org.pgpainless.wot.network.EdgeComponent + +/** + * A filter that treats every certification as a trust signature with unconstrained depth, + * and no regular expressions. + * + * Note: this filter doesn't change the trust amount. + * + * This filter can be used to view a network as a 'certification network'. + */ +class TrustedIntroducerFilter : CertificationFilter { + override fun cost(ec: EdgeComponent, values: FilterValues, ignoreRegexps: Boolean): Boolean { + values.depth = Depth.unconstrained() + if (!ignoreRegexps) { + values.regexps = null + } + + return true + } +}