1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-24 11:57:59 +01:00

Rename classes

This commit is contained in:
Paul Schaub 2023-07-09 13:01:13 +02:00
parent 3cd0718416
commit 8c71afc250
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
18 changed files with 412 additions and 415 deletions

View file

@ -13,7 +13,7 @@ class AuthenticateCmdTest {
val dateFormat = SimpleDateFormat("yyyy-MM-dd") val dateFormat = SimpleDateFormat("yyyy-MM-dd")
val cmd = AuthenticateCmd() val cmd = AuthenticateCmd()
val paths = Paths() val paths = Paths()
val neal = CertSynopsis( val neal = Node(
Fingerprint("F7173B3C7C685CD9ECC4191B74E445BA0E15C957"), Fingerprint("F7173B3C7C685CD9ECC4191B74E445BA0E15C957"),
null, null,
RevocationState.notRevoked(), RevocationState.notRevoked(),
@ -21,7 +21,7 @@ class AuthenticateCmdTest {
Pair("Neal H. Walfield (Code Signing Key) <neal@pep.foundation>", RevocationState.notRevoked()) Pair("Neal H. Walfield (Code Signing Key) <neal@pep.foundation>", RevocationState.notRevoked())
) )
) )
val justus = CertSynopsis( val justus = Node(
Fingerprint("CBCD8F030588653EEDD7E2659B7DD433F254904A"), Fingerprint("CBCD8F030588653EEDD7E2659B7DD433F254904A"),
null, null,
RevocationState.notRevoked(), RevocationState.notRevoked(),
@ -29,7 +29,7 @@ class AuthenticateCmdTest {
Pair("Justus Winter <justus@sequoia-pgp.org>", RevocationState.notRevoked()) Pair("Justus Winter <justus@sequoia-pgp.org>", RevocationState.notRevoked())
) )
) )
val certification = Certification( val edgeComponent = EdgeComponent(
neal, neal,
justus, justus,
"Justus Winter <justus@sequoia-pgp.org>", "Justus Winter <justus@sequoia-pgp.org>",
@ -39,7 +39,7 @@ class AuthenticateCmdTest {
120, 120,
Depth.limited(0), Depth.limited(0),
RegexSet.wildcard()) RegexSet.wildcard())
paths.add(Path(neal, mutableListOf(certification), Depth.auto(0)), 120) paths.add(Path(neal, mutableListOf(edgeComponent), Depth.auto(0)), 120)
val testResult = AuthenticateAPI.Result( val testResult = AuthenticateAPI.Result(
Fingerprint("CBCD8F030588653EEDD7E2659B7DD433F254904A"), Fingerprint("CBCD8F030588653EEDD7E2659B7DD433F254904A"),
"Justus Winter <justus@sequoia-pgp.org>", "Justus Winter <justus@sequoia-pgp.org>",

View file

@ -95,7 +95,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
private val byKeyId: MutableMap<Long, MutableList<KeyRingInfo>> = HashMap() private val byKeyId: MutableMap<Long, MutableList<KeyRingInfo>> = HashMap()
// nodes keyed by fingerprint // nodes keyed by fingerprint
private val nodeMap: MutableMap<Fingerprint, CertSynopsis> = HashMap() private val nodeMap: MutableMap<Fingerprint, Node> = HashMap()
init { init {
validatedCertificates.forEach { indexAsNode(it) } validatedCertificates.forEach { indexAsNode(it) }
@ -131,7 +131,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
// map user-ids to revocation states // map user-ids to revocation states
val userIds = cert.userIds.associateWith { RevocationState(cert.getUserIdRevocation(it)) } val userIds = cert.userIds.associateWith { RevocationState(cert.getUserIdRevocation(it)) }
val node = CertSynopsis(certFingerprint, val node = Node(certFingerprint,
expirationDate, expirationDate,
RevocationState(cert.revocationSelfSignature), RevocationState(cert.revocationSelfSignature),
userIds) userIds)
@ -158,7 +158,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
processDelegation(targetPrimaryKey, target, delegation) processDelegation(targetPrimaryKey, target, delegation)
} }
// Certification Signatures by X on Y over user-ID U // EdgeComponent Signatures by X on Y over user-ID U
val userIds = targetPrimaryKey.userIDs val userIds = targetPrimaryKey.userIDs
while (userIds.hasNext()) { while (userIds.hasNext()) {
val userId = userIds.next() val userId = userIds.next()
@ -180,7 +180,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
* @param delegation delegation signature * @param delegation delegation signature
*/ */
private fun processDelegation(targetPrimaryKey: PGPPublicKey, private fun processDelegation(targetPrimaryKey: PGPPublicKey,
target: CertSynopsis, target: Node,
delegation: PGPSignature) { delegation: PGPSignature) {
// There might be more than one cert with a subkey of matching key-id // There might be more than one cert with a subkey of matching key-id
val issuerCandidates = byKeyId[delegation.keyID] val issuerCandidates = byKeyId[delegation.keyID]
@ -217,7 +217,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
* @param certification certification signature * @param certification certification signature
*/ */
private fun processCertificationOnUserId(targetPrimaryKey: PGPPublicKey, private fun processCertificationOnUserId(targetPrimaryKey: PGPPublicKey,
target: CertSynopsis, target: Node,
userId: String, userId: String,
certification: PGPSignature) { certification: PGPSignature) {
// There might be more than one cert with a subkey of matching key-id // There might be more than one cert with a subkey of matching key-id

View file

@ -6,8 +6,8 @@ package org.pgpainless.wot.util
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil
import org.pgpainless.wot.dijkstra.sq.CertSynopsis import org.pgpainless.wot.dijkstra.sq.Node
import org.pgpainless.wot.dijkstra.sq.Certification import org.pgpainless.wot.dijkstra.sq.EdgeComponent
import org.pgpainless.wot.dijkstra.sq.Depth import org.pgpainless.wot.dijkstra.sq.Depth
import org.pgpainless.wot.dijkstra.sq.RegexSet import org.pgpainless.wot.dijkstra.sq.RegexSet
import org.pgpainless.wot.dijkstra.sq.RegexSet.Companion.fromExpressionList import org.pgpainless.wot.dijkstra.sq.RegexSet.Companion.fromExpressionList
@ -16,26 +16,26 @@ class CertificationFactory {
companion object { companion object {
@JvmStatic @JvmStatic
fun fromDelegation(issuer: CertSynopsis, fun fromDelegation(issuer: Node,
target: CertSynopsis, target: Node,
signature: PGPSignature): Certification { signature: PGPSignature): EdgeComponent {
return fromSignature(issuer, target, null, signature) return fromSignature(issuer, target, null, signature)
} }
@JvmStatic @JvmStatic
fun fromCertification(issuer: CertSynopsis, fun fromCertification(issuer: Node,
target: CertSynopsis, target: Node,
targetUserId: String, targetUserId: String,
signature: PGPSignature): Certification { signature: PGPSignature): EdgeComponent {
return fromSignature(issuer, target, targetUserId, signature) return fromSignature(issuer, target, targetUserId, signature)
} }
@JvmStatic @JvmStatic
fun fromSignature(issuer: CertSynopsis, fun fromSignature(issuer: Node,
target: CertSynopsis, target: Node,
targetUserId: String?, targetUserId: String?,
signature: PGPSignature): Certification { signature: PGPSignature): EdgeComponent {
return Certification( return EdgeComponent(
issuer, issuer,
target, target,
targetUserId, targetUserId,

View file

@ -5,18 +5,18 @@ import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.RevocationStateType import org.pgpainless.algorithm.RevocationStateType
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.info.KeyRingInfo import org.pgpainless.key.info.KeyRingInfo
import org.pgpainless.wot.dijkstra.sq.CertSynopsis import org.pgpainless.wot.dijkstra.sq.Node
import org.pgpainless.wot.dijkstra.sq.Fingerprint import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.RevocationState import org.pgpainless.wot.dijkstra.sq.RevocationState
interface PGPDSL { interface PGPDSL {
fun CertSynopsis(certificate: PGPPublicKeyRing): CertSynopsis { fun CertSynopsis(certificate: PGPPublicKeyRing): Node {
return CertSynopsis(Fingerprint(certificate), ) return Node(Fingerprint(certificate), )
} }
fun CertSynopsis(validatedCert: KeyRingInfo): CertSynopsis { fun CertSynopsis(validatedCert: KeyRingInfo): Node {
return CertSynopsis( return Node(
Fingerprint(validatedCert.fingerprint), Fingerprint(validatedCert.fingerprint),
validatedCert.primaryKeyExpirationDate, validatedCert.primaryKeyExpirationDate,
RevocationState(validatedCert.revocationState), RevocationState(validatedCert.revocationState),

View file

@ -7,7 +7,7 @@ package org.pgpainless.wot
import org.bouncycastle.openpgp.PGPPublicKeyRing import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.wot.dijkstra.sq.CertificationSet import org.pgpainless.wot.dijkstra.sq.Edge
import org.pgpainless.wot.dijkstra.sq.Fingerprint import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.Network import org.pgpainless.wot.dijkstra.sq.Network
import org.pgpainless.wot.testfixtures.TestCertificateStores import org.pgpainless.wot.testfixtures.TestCertificateStores
@ -94,7 +94,7 @@ class WebOfTrustTest {
private fun assertHasIssuerAndTarget( private fun assertHasIssuerAndTarget(
certifications: CertificationSet, certifications: Edge,
issuer: Fingerprint, issuer: Fingerprint,
target: Fingerprint) { target: Fingerprint) {
assertEquals(issuer, certifications.issuer.fingerprint) assertEquals(issuer, certifications.issuer.fingerprint)
@ -119,12 +119,12 @@ class WebOfTrustTest {
assertNull(reverseEdge, "Expected no reverse edge on $target from $issuer but got $reverseEdge") assertNull(reverseEdge, "Expected no reverse edge on $target from $issuer but got $reverseEdge")
} }
private fun getEdgeFromTo(network: Network, issuer: Fingerprint, target: Fingerprint): CertificationSet? { private fun getEdgeFromTo(network: Network, issuer: Fingerprint, target: Fingerprint): Edge? {
val edges = network.edges[issuer] ?: return null val edges = network.edges[issuer] ?: return null
return edges.find { target == it.target.fingerprint } return edges.find { target == it.target.fingerprint }
} }
private fun getReverseEdgeFromTo(network: Network, issuer: Fingerprint, target: Fingerprint): CertificationSet? { private fun getReverseEdgeFromTo(network: Network, issuer: Fingerprint, target: Fingerprint): Edge? {
val revEdges = network.reverseEdges[target] ?: return null val revEdges = network.reverseEdges[target] ?: return null
return revEdges.find { issuer == it.issuer.fingerprint } return revEdges.find { issuer == it.issuer.fingerprint }
} }

View file

@ -1,115 +0,0 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.dijkstra.sq
/**
* A [CertificationSet] is a set of [Certifications][Certification] made by the same issuer, on the same
* target certificate.
* In some sense, a [CertificationSet] can be considered an edge in the web of trust.
*
* @param issuer synopsis of the certificate that issued the [Certifications][Certification]
* @param target synopsis of the certificate that is targeted by the [Certifications][Certification]
* @param certifications [Map] keyed by user-ids, whose values are [Lists][List] of
* [Certifications][Certification] that are calculated over the key user-id. Note, that the key can also be null for
* [Certifications][Certification] over the targets primary key.
*/
class CertificationSet(
val issuer: CertSynopsis,
val target: CertSynopsis,
certifications: Map<String?, List<Certification>>) {
init {
certifications.forEach { (_, certifications) ->
certifications.forEach {
add(it)
}
}
}
private val _certifications: MutableMap<String?, MutableList<Certification>> = mutableMapOf()
val certifications: Map<String?, List<Certification>>
get() = _certifications.toMutableMap()
companion object {
/**
* Create an empty [CertificationSet].
*
* @param issuer the certificate that issued the [Certifications][Certification].
* @param target the certificate that is targeted by the [Certifications][Certification].
*/
@JvmStatic
fun empty(issuer: CertSynopsis, target: CertSynopsis): CertificationSet {
return CertificationSet(issuer, target, HashMap())
}
/**
* Create a [CertificationSet] from a single [Certification].
*
* @param certification certification
*/
@JvmStatic
fun fromCertification(certification: Certification): CertificationSet {
val set = empty(certification.issuer, certification.target)
set.add(certification)
return set
}
}
/**
* Merge the given [CertificationSet] into this.
* This method copies all [Certifications][Certification] from the other [CertificationSet] into [certifications].
*
* @param other [CertificationSet] with the same issuer fingerprint and target fingerprint as this object.
*/
fun merge(other: CertificationSet) {
if (other == this) {
return
}
require(issuer.fingerprint == other.issuer.fingerprint) { "Issuer fingerprint mismatch." }
require(target.fingerprint == other.target.fingerprint) { "Target fingerprint mismatch." }
for (userId in other.certifications.keys) {
for (certification in other.certifications[userId]!!) {
add(certification)
}
}
}
/**
* Add a single [Certification] into this objects [certifications].
* Adding multiple [Certifications][Certification] for the same datum, but with different creation times results in
* only the most recent [Certification(s)][Certification] to be preserved.
*
* @param certification [Certification] with the same issuer fingerprint and target fingerprint as this object.
*/
fun add(certification: Certification) {
require(issuer.fingerprint == certification.issuer.fingerprint) { "Issuer fingerprint mismatch." }
require(target.fingerprint == certification.target.fingerprint) { "Target fingerprint mismatch." }
val certificationsForUserId = _certifications.getOrPut(certification.userId) { mutableListOf() }
if (certificationsForUserId.isEmpty()) {
certificationsForUserId.add(certification)
return
}
val existing = certificationsForUserId[0]
// if existing is older than this certification
if (existing.creationTime.before(certification.creationTime)) {
// throw away older certifications
certificationsForUserId.clear()
}
// If this certification is newest (or equally old!)
if (!existing.creationTime.after(certification.creationTime)) {
certificationsForUserId.add(certification)
}
// else this certification is older, so don't add it
}
override fun toString(): String {
return certifications.map { it.value }.flatten().joinToString("\n")
}
}

View file

@ -0,0 +1,114 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.dijkstra.sq
/**
* An [Edge] is a set of [components][EdgeComponent] made by the same issuer, on the same
* target.
*
* @param issuer origin node
* @param target target node
* @param components [Map] keyed by datum, whose values are [Lists][List] of
* [EdgeComponents][EdgeComponent] that are calculated over the key datum.
* Note, that the key can also be null for [EdgeComponents][EdgeComponent] over the targets primary key.
*/
class Edge(
val issuer: Node,
val target: Node,
components: Map<String?, List<EdgeComponent>>) {
init {
components.forEach { (_, certifications) ->
certifications.forEach {
add(it)
}
}
}
private val _components: MutableMap<String?, MutableList<EdgeComponent>> = mutableMapOf()
val components: Map<String?, List<EdgeComponent>>
get() = _components.toMutableMap()
companion object {
/**
* Create an empty [Edge] with no [components][EdgeComponent].
*
* @param issuer the certificate that issued the [EdgeComponents][EdgeComponent].
* @param target the certificate that is targeted by the [EdgeComponents][EdgeComponent].
*/
@JvmStatic
fun empty(issuer: Node, target: Node): Edge {
return Edge(issuer, target, HashMap())
}
/**
* Create a [Edge] from a single [EdgeComponent].
*
* @param certification certification
*/
@JvmStatic
fun fromCertification(certification: EdgeComponent): Edge {
val set = empty(certification.issuer, certification.target)
set.add(certification)
return set
}
}
/**
* Merge the given [Edge] into this.
* This method copies all [EdgeComponents][EdgeComponent] from the other [Edge] into [components].
*
* @param other [Edge] with the same issuer fingerprint and target fingerprint as this object.
*/
fun merge(other: Edge) {
if (other == this) {
return
}
require(issuer.fingerprint == other.issuer.fingerprint) { "Issuer fingerprint mismatch." }
require(target.fingerprint == other.target.fingerprint) { "Target fingerprint mismatch." }
for (userId in other.components.keys) {
for (certification in other.components[userId]!!) {
add(certification)
}
}
}
/**
* Add a single [EdgeComponent] into this objects [components].
* Adding multiple [EdgeComponents][EdgeComponent] for the same datum, but with different creation times results in
* only the most recent [EdgeComponent(s)][EdgeComponent] to be preserved.
*
* @param component [EdgeComponent] with the same issuer fingerprint and target fingerprint as this object.
*/
fun add(component: EdgeComponent) {
require(issuer.fingerprint == component.issuer.fingerprint) { "Issuer fingerprint mismatch." }
require(target.fingerprint == component.target.fingerprint) { "Target fingerprint mismatch." }
val certificationsForUserId = _components.getOrPut(component.userId) { mutableListOf() }
if (certificationsForUserId.isEmpty()) {
certificationsForUserId.add(component)
return
}
val existing = certificationsForUserId[0]
// if existing is older than this component
if (existing.creationTime.before(component.creationTime)) {
// throw away older certifications
certificationsForUserId.clear()
}
// If this component is newest (or equally old!)
if (!existing.creationTime.after(component.creationTime)) {
certificationsForUserId.add(component)
}
// else this component is older, so don't add it
}
override fun toString(): String {
return components.map { it.value }.flatten().joinToString("\n")
}
}

View file

@ -7,22 +7,22 @@ package org.pgpainless.wot.dijkstra.sq
import java.util.* import java.util.*
/** /**
* A [Certification] is a signature issued by one certificate over a datum on another target certificate. * An [EdgeComponent] is a signature issued by one certificate over a datum on another target certificate.
* Such a datum could be either a user-id, or the primary key of the target certificate. * Such a datum could be either a user-id, or the primary key of the target certificate.
* *
* @param issuer synopsis of the certificate that issued the [Certification] * @param issuer certificate that issued the [EdgeComponent]
* @param target synopsis of the certificate that is target of this [Certification] * @param target certificate that is target of this [EdgeComponent]
* @param userId optional user-id. If this is null, the [Certification] is made over the primary key of the target. * @param userId optional user-id. If this is null, the [EdgeComponent] is made over the primary key of the target.
* @param creationTime creation time of the [Certification] * @param creationTime creation time of the [EdgeComponent]
* @param expirationTime optional expiration time of the [Certification] * @param expirationTime optional expiration time of the [EdgeComponent]
* @param exportable if false, the certification is marked as "not exportable" * @param exportable if false, the certification is marked as "not exportable"
* @param trustAmount amount of trust the issuer places in the binding * @param trustAmount amount of trust the issuer places in the binding
* @param trustDepth degree to which the issuer trusts the target as trusted introducer * @param trustDepth degree to which the issuer trusts the target as trusted introducer
* @param regexes regular expressions for user-ids which the target is allowed to introduce * @param regexes regular expressions for user-ids which the target is allowed to introduce
*/ */
data class Certification( data class EdgeComponent(
val issuer: CertSynopsis, val issuer: Node,
val target: CertSynopsis, val target: Node,
val userId: String?, val userId: String?,
val creationTime: Date, val creationTime: Date,
val expirationTime: Date?, val expirationTime: Date?,
@ -33,17 +33,17 @@ data class Certification(
) { ) {
/** /**
* Construct a [Certification] with default values. The result is non-expiring, will be exportable and has a * Construct a [EdgeComponent] with default values. The result is non-expiring, will be exportable and has a
* trust amount of 120, a depth of 0 and a wildcard regex. * trust amount of 120, a depth of 0 and a wildcard regex.
* *
* @param issuer synopsis of the certificate that issued the [Certification] * @param issuer synopsis of the certificate that issued the [EdgeComponent]
* @param target synopsis of the certificate that is target of this [Certification] * @param target synopsis of the certificate that is target of this [EdgeComponent]
* @param targetUserId optional user-id. If this is null, the [Certification] is made over the primary key of the target. * @param targetUserId optional user-id. If this is null, the [EdgeComponent] is made over the primary key of the target.
* @param creationTime creation time of the [Certification] * @param creationTime creation time of the [EdgeComponent]
*/ */
constructor( constructor(
issuer: CertSynopsis, issuer: Node,
target: CertSynopsis, target: Node,
targetUserId: String? = null, targetUserId: String? = null,
creationTime: Date) : creationTime: Date) :
this(issuer, target, targetUserId, creationTime, null, true, 120, Depth.limited(0), RegexSet.wildcard()) this(issuer, target, targetUserId, creationTime, null, true, 120, Depth.limited(0), RegexSet.wildcard())

View file

@ -6,19 +6,19 @@ package org.pgpainless.wot.dijkstra.sq
/** /**
* A network consists of nodes, and edges between them. * A network consists of nodes, and edges between them.
* For the Web of Trust, nodes consist of [CertSynopses][CertSynopsis], while the edges between the nodes are * For the Web of Trust, a [Node] is a certificate, while the [Edges][Edge] between them are sets of signatures
* [CertificationSets][CertificationSet]. * ([EdgeComponent]).
* *
* @constructor creates a new network * @constructor creates a new network
* @param nodes contains a [Map] of [CertSynopsis] keyed by their [Fingerprint] * @param nodes contains a [Map] of [Node] keyed by their [Fingerprint]
* @param edges [Map] keyed by the [fingerprint][Fingerprint] of an issuer, whose values are [Lists][List] containing all edges originating from the issuer. * @param edges [Edges][Edges] keyed by origin
* @param reverseEdges [Map] keyed by the [fingerprint][Fingerprint] of a target, whose values are [Lists][List] containing all edges pointing to the target * @param reverseEdges [Edges][Edge] keyed by target
* @param referenceTime reference time at which the [Network] was built * @param referenceTime reference time at which the [Network] was built
*/ */
class Network( class Network(
val nodes: Map<Fingerprint, CertSynopsis>, val nodes: Map<Fingerprint, Node>,
val edges: Map<Fingerprint, List<CertificationSet>>, val edges: Map<Fingerprint, List<Edge>>,
val reverseEdges: Map<Fingerprint, List<CertificationSet>>, val reverseEdges: Map<Fingerprint, List<Edge>>,
val referenceTime: ReferenceTime) { val referenceTime: ReferenceTime) {
companion object { companion object {
@ -34,7 +34,7 @@ class Network(
} }
/** /**
* The total number of edges on the network. * The total number of [Edges][Edge] on the network.
* *
* @return number of edges * @return number of edges
*/ */
@ -44,13 +44,13 @@ class Network(
} }
/** /**
* The total number of signatures the network comprises. * The total number of signatures ([EdgeComponents][EdgeComponent]) the network comprises.
*/ */
val numberOfSignatures: Int val numberOfSignatures: Int
get() { get() {
return edges.values return edges.values
.flatten() .flatten()
.flatMap { it.certifications.values } .flatMap { it.components.values }
.sumOf { it.size } .sumOf { it.size }
} }
@ -67,22 +67,22 @@ class Network(
} }
class Builder internal constructor() { class Builder internal constructor() {
val nodes: MutableMap<Fingerprint, CertSynopsis> = mutableMapOf() val nodes: MutableMap<Fingerprint, Node> = mutableMapOf()
private val protoEdges: MutableMap<Pair<Fingerprint, Fingerprint>, CertificationSet> = mutableMapOf() private val protoEdges: MutableMap<Pair<Fingerprint, Fingerprint>, Edge> = mutableMapOf()
private var referenceTime: ReferenceTime = ReferenceTime.now() private var referenceTime: ReferenceTime = ReferenceTime.now()
fun addNode(node: CertSynopsis): Builder { fun addNode(node: Node): Builder {
nodes[node.fingerprint] = node nodes[node.fingerprint] = node
return this return this
} }
fun getNode(fingerprint: Fingerprint): CertSynopsis? { fun getNode(fingerprint: Fingerprint): Node? {
return nodes[fingerprint] return nodes[fingerprint]
} }
fun addEdge(edge: Certification): Builder { fun addEdge(edge: EdgeComponent): Builder {
protoEdges.getOrPut(Pair(edge.issuer.fingerprint, edge.target.fingerprint)) { protoEdges.getOrPut(Pair(edge.issuer.fingerprint, edge.target.fingerprint)) {
CertificationSet.empty(edge.issuer, edge.target) Edge.empty(edge.issuer, edge.target)
}.add(edge) }.add(edge)
return this return this
} }
@ -93,8 +93,8 @@ class Network(
} }
fun build(): Network { fun build(): Network {
val edges = mutableMapOf<Fingerprint, MutableList<CertificationSet>>() val edges = mutableMapOf<Fingerprint, MutableList<Edge>>()
val revEdges = mutableMapOf<Fingerprint, MutableList<CertificationSet>>() val revEdges = mutableMapOf<Fingerprint, MutableList<Edge>>()
protoEdges.forEach { (pair, certificationSet) -> protoEdges.forEach { (pair, certificationSet) ->
edges.getOrPut(pair.first) { edges.getOrPut(pair.first) {

View file

@ -7,14 +7,14 @@ package org.pgpainless.wot.dijkstra.sq
import java.util.* import java.util.*
/** /**
* A [CertSynopsis] is a proxy object containing information about a certificate. * A [Node] is a proxy object containing information about a certificate.
* *
* @param fingerprint [Fingerprint] of the certificate * @param fingerprint [Fingerprint] of the certificate
* @param expirationTime optional expiration time of the certificate * @param expirationTime optional expiration time of the certificate
* @param revocationState [RevocationState] denoting whether the certificate is revoked or not * @param revocationState [RevocationState] denoting whether the certificate is revoked or not
* @param userIds [Map] of user-ids on the certificate, along with their revocation states * @param userIds [Map] of user-ids on the certificate, along with their revocation states
*/ */
data class CertSynopsis( data class Node(
val fingerprint: Fingerprint, val fingerprint: Fingerprint,
val expirationTime: Date? = null, val expirationTime: Date? = null,
val revocationState: RevocationState = RevocationState.notRevoked(), val revocationState: RevocationState = RevocationState.notRevoked(),

View file

@ -7,7 +7,7 @@ package org.pgpainless.wot.dijkstra.sq
import kotlin.math.min import kotlin.math.min
/** /**
* A [Path] comprises a root [CertSynopsis], a list of edges ([Certifications][Certification]), as well as a * A [Path] comprises a root [Node], a list of edges ([EdgeComponents][EdgeComponent]), as well as a
* residual depth. * residual depth.
* *
* @param root root of the path * @param root root of the path
@ -15,8 +15,8 @@ import kotlin.math.min
* @param residualDepth residual depth that is decreased each time another edge is appended * @param residualDepth residual depth that is decreased each time another edge is appended
*/ */
class Path( class Path(
val root: CertSynopsis, val root: Node,
private val edges: MutableList<Certification>, private val edges: MutableList<EdgeComponent>,
var residualDepth: Depth var residualDepth: Depth
) { ) {
@ -26,14 +26,14 @@ class Path(
* *
* @param root trust root * @param root trust root
*/ */
constructor(root: CertSynopsis) : this( constructor(root: Node) : this(
root, mutableListOf<Certification>(), Depth.unconstrained()) root, mutableListOf<EdgeComponent>(), Depth.unconstrained())
/** /**
* Current target of the path. * Current target of the path.
* This corresponds to the target of the last entry in the edge list. * This corresponds to the target of the last entry in the edge list.
*/ */
val target: CertSynopsis val target: Node
get() { get() {
return if (edges.isEmpty()) { return if (edges.isEmpty()) {
root root
@ -43,12 +43,12 @@ class Path(
} }
/** /**
* List of [CertSynopses][CertSynopsis] (nodes) of the path. * List of [Nodes][Node] (nodes) of the path.
* The first entry is the [root]. The other entries are the targets of the edges. * The first entry is the [root]. The other entries are the targets of the edges.
*/ */
val certificates: List<CertSynopsis> val certificates: List<Node>
get() { get() {
val certs: MutableList<CertSynopsis> = mutableListOf(root) val certs: MutableList<Node> = mutableListOf(root)
for (certification in edges) { for (certification in edges) {
certs.add(certification.target) certs.add(certification.target)
} }
@ -65,7 +65,7 @@ class Path(
/** /**
* List of edges. * List of edges.
*/ */
val certifications: List<Certification> val certifications: List<EdgeComponent>
get() = edges.toList() get() = edges.toList()
/** /**
@ -88,37 +88,37 @@ class Path(
* *
* @throws IllegalArgumentException if the target at the end of the path is not equal to the issuer of the edge. * @throws IllegalArgumentException if the target at the end of the path is not equal to the issuer of the edge.
* @throws IllegalArgumentException if the path runs out of residual depth * @throws IllegalArgumentException if the path runs out of residual depth
* @throws IllegalArgumentException if the addition of the [Certification] would result in a cyclic path * @throws IllegalArgumentException if the addition of the [EdgeComponent] would result in a cyclic path
*/ */
fun append(certification: Certification) { fun append(nComponent: EdgeComponent) {
require(target.fingerprint == certification.issuer.fingerprint) { require(target.fingerprint == nComponent.issuer.fingerprint) {
"Cannot append certification to path: Path's tail is not issuer of the certification." "Cannot append edge to path: Path's tail is not issuer of the edge."
} }
require(residualDepth.isUnconstrained() || residualDepth.limit!! > 0) { require(residualDepth.isUnconstrained() || residualDepth.limit!! > 0) {
"Not enough depth." "Not enough depth."
} }
// root is c's target -> illegal cycle // root is c's target -> illegal cycle
var cyclic = root.fingerprint == certification.target.fingerprint var cyclic = root.fingerprint == nComponent.target.fingerprint
for ((i, edge) in edges.withIndex()) { for ((i, component) in edges.withIndex()) {
if (cyclic) { if (cyclic) {
break break
} }
// existing edge points to c's target -> illegal cycle // existing edge points to c's target -> illegal cycle
if (edge.target.fingerprint == certification.target.fingerprint) { if (nComponent.target.fingerprint == component.target.fingerprint) {
cyclic = if (edges.lastIndex != i) { cyclic = if (edges.lastIndex != i) {
// Cycle in the middle of the ~~street~~ path // Cycle in the middle of the ~~street~~ path
true true
} else { } else {
// Not a cycle, if we point to a different user-id // Not a cycle, if we point to a different user-id
edge.userId == certification.userId nComponent.userId == component.userId
} }
} }
} }
require(!cyclic) { "Adding the certification to the path would create a cycle." } require(!cyclic) { "Adding the edge to the path would create a cycle." }
residualDepth = certification.trustDepth.min(residualDepth.decrease(1)) residualDepth = nComponent.trustDepth.min(residualDepth.decrease(1))
edges.add(certification) edges.add(nComponent)
} }
override fun toString(): String { override fun toString(): String {

View file

@ -1,133 +0,0 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.dijkstra
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pgpainless.wot.dijkstra.sq.*
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class CertificationSetTest {
private val alice = CertSynopsis(Fingerprint("A"), null, RevocationState.notRevoked(), mapOf())
private val bob = CertSynopsis(Fingerprint("B"), null, RevocationState.notRevoked(), mapOf())
private val charlie = CertSynopsis(Fingerprint("C"), null, RevocationState.notRevoked(), mapOf())
private val aliceSignsBob = Certification(alice, bob, null, Date())
private val aliceSignsBobUserId = Certification(alice, bob, "Bob <bob@example.org>", Date())
private val aliceSignsCharlie = Certification(alice, charlie, null, Date())
private val charlieSignsBob = Certification(charlie, bob, null, Date())
@Test
fun `verify that properties of an empty CertificationSet are also empty`() {
val empty = CertificationSet.empty(alice, bob)
assert(empty.certifications.isEmpty())
assertEquals(alice, empty.issuer)
assertEquals(bob, empty.target)
}
@Test
fun `verify that add()ing Certification objects works if issuer and target match that of the CertificationSet`() {
val set = CertificationSet.empty(alice, bob)
set.add(aliceSignsBob)
assertTrue {
set.certifications.values.any {
it.contains(aliceSignsBob)
}
}
set.add(aliceSignsBobUserId)
assertTrue {
set.certifications["Bob <bob@example.org>"]!!.contains(aliceSignsBobUserId)
}
}
@Test
fun `verify that add()ing another Certification object fails if the issuer mismatches`() {
val set = CertificationSet.empty(alice, bob)
assertThrows<IllegalArgumentException> { set.add(charlieSignsBob) }
}
@Test
fun `verify that add()ing another Certification object fails if the target mismatches`() {
val set = CertificationSet.empty(alice, bob)
assertThrows<IllegalArgumentException> { set.add(aliceSignsCharlie) }
}
@Test
fun `verify that merge()ing another CertificationSet works if issuer and target match that of the CertificationSet`() {
val set = CertificationSet.fromCertification(aliceSignsBob)
val others = CertificationSet.fromCertification(aliceSignsBobUserId)
set.merge(others)
assertEquals(2, set.certifications.size)
assertTrue { set.certifications[null]!!.contains(aliceSignsBob) }
assertTrue { set.certifications["Bob <bob@example.org>"]!!.contains(aliceSignsBobUserId) }
}
@Test
fun `verify that merge()ing another CertificationSet with mismatched issuer fails`() {
val set = CertificationSet.fromCertification(aliceSignsBob)
val issuerMismatch = CertificationSet.fromCertification(charlieSignsBob)
assertThrows<IllegalArgumentException> { set.merge(issuerMismatch) }
}
@Test
fun `verify that merge()ing another CertificationSet with mismatched target fails`() {
val set = CertificationSet.fromCertification(aliceSignsBob)
val targetMismatch = CertificationSet.fromCertification(aliceSignsCharlie)
assertThrows<IllegalArgumentException> { set.merge(targetMismatch) }
}
@Test
fun `verify that merge()ing a CertificationSet with itself is idempotent`() {
val set = CertificationSet.fromCertification(aliceSignsBob)
assertEquals(1, set.certifications.size)
set.merge(set)
assertEquals(1, set.certifications.size)
}
@Test
fun `verify that toString() of an empty CertificationSet is the empty string`() {
val empty = CertificationSet.empty(alice, bob)
assertEquals("", empty.toString())
}
@Test
fun `verify that toString() of a CertificationSet with two Certifications matches our expectations`() {
val twoCerts = CertificationSet.fromCertification(aliceSignsBob)
twoCerts.add(aliceSignsBobUserId)
assertEquals("A certifies binding: null <-> B [120]\n" +
"A certifies binding: Bob <bob@example.org> <-> B [120]", twoCerts.toString())
}
@Test
fun `verify that for multiple Certifications over the same datum, only the most recent certifications are preserved`() {
val now = Date()
val fiveSecondsBefore = Date(now.time - 5000)
val old = Certification(alice, bob, "Bob <bob@example.org>", fiveSecondsBefore)
val new = Certification(alice, bob, "Bob <bob@example.org>", now)
val new2 = Certification(alice, bob, "Bob <bob@example.org>", now, null, true, 44, Depth.auto(10), RegexSet.wildcard())
var set = CertificationSet(alice, bob, mapOf())
set.add(old)
assertEquals(listOf(old), set.certifications["Bob <bob@example.org>"])
set.add(new)
assertEquals(listOf(new), set.certifications["Bob <bob@example.org>"])
set.add(new2)
assertEquals(listOf(new, new2), set.certifications["Bob <bob@example.org>"])
set.add(old)
assertEquals(listOf(new, new2), set.certifications["Bob <bob@example.org>"])
}
}

View file

@ -1,48 +1,48 @@
package org.pgpainless.wot.dijkstra package org.pgpainless.wot.dijkstra
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.pgpainless.wot.dijkstra.sq.CertSynopsis import org.pgpainless.wot.dijkstra.sq.Node
import org.pgpainless.wot.dijkstra.sq.Certification import org.pgpainless.wot.dijkstra.sq.EdgeComponent
import org.pgpainless.wot.dijkstra.sq.Fingerprint import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.RevocationState import org.pgpainless.wot.dijkstra.sq.RevocationState
import java.util.* import java.util.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
class CertificationTest { class EdgeComponentTest {
private val alice = CertSynopsis( private val alice = Node(
Fingerprint("A"), Fingerprint("A"),
null, null,
RevocationState.notRevoked(), RevocationState.notRevoked(),
mapOf(Pair("Alice <alice@pgpainless.org>", RevocationState.notRevoked()))) mapOf(Pair("Alice <alice@pgpainless.org>", RevocationState.notRevoked())))
private val bob = CertSynopsis( private val bob = Node(
Fingerprint("B"), Fingerprint("B"),
null, null,
RevocationState.notRevoked(), RevocationState.notRevoked(),
mapOf(Pair("Bob <bob@example.org>", RevocationState.notRevoked()))) mapOf(Pair("Bob <bob@example.org>", RevocationState.notRevoked())))
private val charlie = CertSynopsis( private val charlie = Node(
Fingerprint("C"), Fingerprint("C"),
null, null,
RevocationState.notRevoked(), RevocationState.notRevoked(),
mapOf()) mapOf())
@Test @Test
fun `verify result of toString() on certification`() { fun `verify result of toString() on certification signature`() {
val certification = Certification(alice, bob, "Bob <bob@example.org>", Date()) val edgeComponent = EdgeComponent(alice, bob, "Bob <bob@example.org>", Date())
assertEquals("A certifies binding: Bob <bob@example.org> <-> B [120]", assertEquals("A certifies binding: Bob <bob@example.org> <-> B [120]",
certification.toString()) edgeComponent.toString())
} }
@Test @Test
fun `verify result of toString() on delegation`() { fun `verify result of toString() on delegation signature`() {
val delegation = Certification(alice, bob, null, Date()) val delegation = EdgeComponent(alice, bob, null, Date())
assertEquals("A certifies binding: null <-> B [120]", assertEquals("A certifies binding: null <-> B [120]",
delegation.toString()) delegation.toString())
} }
@Test @Test
fun `verify result of toString() on delegation with userId-less issuer`() { fun `verify result of toString() on delegation signature with userId-less issuer`() {
val delegation = Certification(charlie, bob, null, Date()) val delegation = EdgeComponent(charlie, bob, null, Date())
assertEquals("C certifies binding: null <-> B [120]", assertEquals("C certifies binding: null <-> B [120]",
delegation.toString()) delegation.toString())
} }

View file

@ -0,0 +1,133 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.dijkstra
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pgpainless.wot.dijkstra.sq.*
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class EdgeTest {
private val alice = Node(Fingerprint("A"), null, RevocationState.notRevoked(), mapOf())
private val bob = Node(Fingerprint("B"), null, RevocationState.notRevoked(), mapOf())
private val charlie = Node(Fingerprint("C"), null, RevocationState.notRevoked(), mapOf())
private val aliceSignsBob = EdgeComponent(alice, bob, null, Date())
private val aliceSignsBobUserId = EdgeComponent(alice, bob, "Bob <bob@example.org>", Date())
private val aliceSignsCharlie = EdgeComponent(alice, charlie, null, Date())
private val charlieSignsBob = EdgeComponent(charlie, bob, null, Date())
@Test
fun `verify that properties of an empty edge are also empty`() {
val empty = Edge.empty(alice, bob)
assert(empty.components.isEmpty())
assertEquals(alice, empty.issuer)
assertEquals(bob, empty.target)
}
@Test
fun `verify that add()ing edge components works if issuer and target match that of the edge`() {
val set = Edge.empty(alice, bob)
set.add(aliceSignsBob)
assertTrue {
set.components.values.any {
it.contains(aliceSignsBob)
}
}
set.add(aliceSignsBobUserId)
assertTrue {
set.components["Bob <bob@example.org>"]!!.contains(aliceSignsBobUserId)
}
}
@Test
fun `verify that add()ing another component fails if the issuer mismatches`() {
val set = Edge.empty(alice, bob)
assertThrows<IllegalArgumentException> { set.add(charlieSignsBob) }
}
@Test
fun `verify that add()ing another component fails if the target mismatches`() {
val set = Edge.empty(alice, bob)
assertThrows<IllegalArgumentException> { set.add(aliceSignsCharlie) }
}
@Test
fun `verify that merge()ing another edge works if issuer and target match that of the edge`() {
val set = Edge.fromCertification(aliceSignsBob)
val others = Edge.fromCertification(aliceSignsBobUserId)
set.merge(others)
assertEquals(2, set.components.size)
assertTrue { set.components[null]!!.contains(aliceSignsBob) }
assertTrue { set.components["Bob <bob@example.org>"]!!.contains(aliceSignsBobUserId) }
}
@Test
fun `verify that merge()ing another edge with mismatched issuer fails`() {
val set = Edge.fromCertification(aliceSignsBob)
val issuerMismatch = Edge.fromCertification(charlieSignsBob)
assertThrows<IllegalArgumentException> { set.merge(issuerMismatch) }
}
@Test
fun `verify that merge()ing another edge with mismatched target fails`() {
val set = Edge.fromCertification(aliceSignsBob)
val targetMismatch = Edge.fromCertification(aliceSignsCharlie)
assertThrows<IllegalArgumentException> { set.merge(targetMismatch) }
}
@Test
fun `verify that merge()ing an edge with itself is idempotent`() {
val set = Edge.fromCertification(aliceSignsBob)
assertEquals(1, set.components.size)
set.merge(set)
assertEquals(1, set.components.size)
}
@Test
fun `verify that toString() of an empty edge is the empty string`() {
val empty = Edge.empty(alice, bob)
assertEquals("", empty.toString())
}
@Test
fun `verify that toString() of a edge with two components matches our expectations`() {
val twoCerts = Edge.fromCertification(aliceSignsBob)
twoCerts.add(aliceSignsBobUserId)
assertEquals("A certifies binding: null <-> B [120]\n" +
"A certifies binding: Bob <bob@example.org> <-> B [120]", twoCerts.toString())
}
@Test
fun `verify that for multiple components over the same datum, only the most recent components are preserved`() {
val now = Date()
val fiveSecondsBefore = Date(now.time - 5000)
val old = EdgeComponent(alice, bob, "Bob <bob@example.org>", fiveSecondsBefore)
val new = EdgeComponent(alice, bob, "Bob <bob@example.org>", now)
val new2 = EdgeComponent(alice, bob, "Bob <bob@example.org>", now, null, true, 44, Depth.auto(10), RegexSet.wildcard())
var set = Edge(alice, bob, mapOf())
set.add(old)
assertEquals(listOf(old), set.components["Bob <bob@example.org>"])
set.add(new)
assertEquals(listOf(new), set.components["Bob <bob@example.org>"])
set.add(new2)
assertEquals(listOf(new, new2), set.components["Bob <bob@example.org>"])
set.add(old)
assertEquals(listOf(new, new2), set.components["Bob <bob@example.org>"])
}
}

View file

@ -13,52 +13,52 @@ import java.util.*
interface NetworkDSL { interface NetworkDSL {
/** /**
* Create [CertSynopsis] from [String] fingerprint. * Create [Node] from [String] fingerprint.
*/ */
fun CertSynopsis(fingerprint: String): CertSynopsis = fun Node(fingerprint: String): Node =
CertSynopsis(Fingerprint(fingerprint), null, RevocationState.notRevoked(), mapOf()) Node(Fingerprint(fingerprint), null, RevocationState.notRevoked(), mapOf())
/** /**
* Create [CertSynopsis] from [String] fingerprint and non-revoked [userId]. * Create [Node] from [String] fingerprint and non-revoked [userId].
*/ */
fun CertSynopsis(fingerprint: String, userId: String): CertSynopsis = CertSynopsis( fun Node(fingerprint: String, userId: String): Node = Node(
Fingerprint(fingerprint), null, RevocationState.notRevoked(), mapOf(userId to RevocationState.notRevoked())) Fingerprint(fingerprint), null, RevocationState.notRevoked(), mapOf(userId to RevocationState.notRevoked()))
fun CertSynopsis(original: CertSynopsis, userId: String): CertSynopsis = CertSynopsis( fun Node(original: Node, userId: String): Node = Node(
original.fingerprint, original.expirationTime, original.revocationState, original.userIds.plus(userId to RevocationState.notRevoked()) original.fingerprint, original.expirationTime, original.revocationState, original.userIds.plus(userId to RevocationState.notRevoked())
) )
/** /**
* Create [Certification] from two [CertSynopsis] nodes. * Create [EdgeComponent] from two [Node] nodes.
*/ */
fun Certification(issuer: CertSynopsis, target: CertSynopsis): Certification = fun EdgeComponent(issuer: Node, target: Node): EdgeComponent =
Certification(issuer, target, null, Date()) EdgeComponent(issuer, target, null, Date())
/** /**
* Create [Certification] from two [CertSynopsis] nodes and a target [userId]. * Create [EdgeComponent] from two [Node] nodes and a target [userId].
*/ */
fun Certification(issuer: CertSynopsis, target: CertSynopsis, userId: String): Certification = fun EdgeComponent(issuer: Node, target: Node, userId: String): EdgeComponent =
Certification(issuer, target, userId, Date()) EdgeComponent(issuer, target, userId, Date())
fun Certification(issuer: CertSynopsis, target: CertSynopsis, amount: Int, depth: Depth): Certification = fun EdgeComponent(issuer: Node, target: Node, amount: Int, depth: Depth): EdgeComponent =
Certification(issuer, target, null, Date(), null, true, amount, depth, RegexSet.wildcard()) EdgeComponent(issuer, target, null, Date(), null, true, amount, depth, RegexSet.wildcard())
/** /**
* Add a single [CertSynopsis] built from a [String] fingerprint to the builder. * Add a single [Node] built from a [String] fingerprint to the builder.
*/ */
fun Network.Builder.addNode(fingerprint: String): Network.Builder { fun Network.Builder.addNode(fingerprint: String): Network.Builder {
return addNode(CertSynopsis(fingerprint)) return addNode(Node(fingerprint))
} }
/** /**
* Add a single [CertSynopsis] built from a [String] fingerprint and [userId] to the builder. * Add a single [Node] built from a [String] fingerprint and [userId] to the builder.
*/ */
fun Network.Builder.addNode(fingerprint: String, userId: String): Network.Builder { fun Network.Builder.addNode(fingerprint: String, userId: String): Network.Builder {
return addNode(CertSynopsis(fingerprint, userId)) return addNode(Node(fingerprint, userId))
} }
/** /**
* Add multiple [CertSynopsis] nodes built from [String] fingerprints to the builder. * Add multiple [Node] nodes built from [String] fingerprints to the builder.
*/ */
fun Network.Builder.addNodes(vararg fingerprints: String) { fun Network.Builder.addNodes(vararg fingerprints: String) {
for (fingerprint in fingerprints) { for (fingerprint in fingerprints) {
@ -67,25 +67,25 @@ interface NetworkDSL {
} }
/** /**
* Add an edge between the [CertSynopsis] with fingerprint [issuer] and * Add an edge between the [Node] with fingerprint [issuer] and
* the [CertSynopsis] with fingerprint [target]. * the [Node] with fingerprint [target].
* If either the issuer or target node doesn't exist, throw an [IllegalArgumentException]. * If either the issuer or target node doesn't exist, throw an [IllegalArgumentException].
*/ */
fun Network.Builder.addEdge(issuer: String, target: String): Network.Builder { fun Network.Builder.addEdge(issuer: String, target: String): Network.Builder {
val issuerNode = nodes[Fingerprint(issuer)]!! val issuerNode = nodes[Fingerprint(issuer)]!!
val targetNode = nodes[Fingerprint(target)]!! val targetNode = nodes[Fingerprint(target)]!!
return addEdge(Certification(issuerNode, targetNode)) return addEdge(EdgeComponent(issuerNode, targetNode))
} }
/** /**
* Add an edge for [userId] between the [CertSynopsis] with fingerprint [issuer] and * Add an edge for [userId] between the [Node] with fingerprint [issuer] and
* the [CertSynopsis] with fingerprint [target]. * the [Node] with fingerprint [target].
* If either the issuer or target node doesn't exist, throw an [IllegalArgumentException]. * If either the issuer or target node doesn't exist, throw an [IllegalArgumentException].
*/ */
fun Network.Builder.addEdge(issuer: String, target: String, userId: String): Network.Builder { fun Network.Builder.addEdge(issuer: String, target: String, userId: String): Network.Builder {
val issuerNode = nodes[Fingerprint(issuer)]!! val issuerNode = nodes[Fingerprint(issuer)]!!
val targetNode = nodes[Fingerprint(target)]!! val targetNode = nodes[Fingerprint(target)]!!
return addEdge(Certification(issuerNode, targetNode, userId)) return addEdge(EdgeComponent(issuerNode, targetNode, userId))
} }
/** /**
@ -93,9 +93,9 @@ interface NetworkDSL {
* a new node for them to the builder. * a new node for them to the builder.
*/ */
fun Network.Builder.buildEdge(issuer: String, target: String): Network.Builder { fun Network.Builder.buildEdge(issuer: String, target: String): Network.Builder {
val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { CertSynopsis(issuer) } val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { Node(issuer) }
val targetNode = nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target) } val targetNode = nodes.getOrPut(Fingerprint(target)) { Node(target) }
return addEdge(Certification(issuerNode, targetNode)) return addEdge(EdgeComponent(issuerNode, targetNode))
} }
/** /**
@ -105,21 +105,21 @@ interface NetworkDSL {
* the [userId] inserted. * the [userId] inserted.
*/ */
fun Network.Builder.buildEdge(issuer: String, target: String, userId: String): Network.Builder { fun Network.Builder.buildEdge(issuer: String, target: String, userId: String): Network.Builder {
val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { CertSynopsis(issuer)} val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { Node(issuer)}
val targetNode = CertSynopsis(nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target, userId) }, userId) val targetNode = Node(nodes.getOrPut(Fingerprint(target)) { Node(target, userId) }, userId)
return addEdge(Certification(issuerNode, targetNode, userId)) return addEdge(EdgeComponent(issuerNode, targetNode, userId))
} }
fun Network.Builder.buildEdge(issuer: String, target: String, amount: Int, depth: Int): Network.Builder { fun Network.Builder.buildEdge(issuer: String, target: String, amount: Int, depth: Int): Network.Builder {
val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { CertSynopsis(issuer) } val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { Node(issuer) }
val targetNode = nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target) } val targetNode = nodes.getOrPut(Fingerprint(target)) { Node(target) }
return addEdge(Certification(issuerNode, targetNode, null, Date(), null, true, amount, Depth.auto(depth), RegexSet.wildcard())) return addEdge(EdgeComponent(issuerNode, targetNode, null, Date(), null, true, amount, Depth.auto(depth), RegexSet.wildcard()))
} }
fun Network.Builder.buildEdge(issuer: String, target: String, amount: Int, depth: Int, regexSet: RegexSet): Network.Builder { fun Network.Builder.buildEdge(issuer: String, target: String, amount: Int, depth: Int, regexSet: RegexSet): Network.Builder {
val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { CertSynopsis(issuer) } val issuerNode = nodes.getOrPut(Fingerprint(issuer)) { Node(issuer) }
val targetNode = nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target) } val targetNode = nodes.getOrPut(Fingerprint(target)) { Node(target) }
return addEdge(Certification(issuerNode, targetNode, null, Date(), null, true, amount, Depth.auto(depth), regexSet)) return addEdge(EdgeComponent(issuerNode, targetNode, null, Date(), null, true, amount, Depth.auto(depth), regexSet))
} }
/** /**
@ -129,27 +129,27 @@ interface NetworkDSL {
return setReferenceTime(ReferenceTime.now()) return setReferenceTime(ReferenceTime.now())
} }
fun Network.getEdgesFor(issuer: Fingerprint, target: Fingerprint): CertificationSet? { fun Network.getEdgesFor(issuer: Fingerprint, target: Fingerprint): Edge? {
return edges[issuer]?.find { it.target.fingerprint == target } return edges[issuer]?.find { it.target.fingerprint == target }
} }
fun Network.getEdgesFor(issuer: String, target: String): CertificationSet? { fun Network.getEdgesFor(issuer: String, target: String): Edge? {
return getEdgesFor(Fingerprint(issuer), Fingerprint(target)) return getEdgesFor(Fingerprint(issuer), Fingerprint(target))
} }
fun Network.getEdgeFor(issuer: Fingerprint, target: Fingerprint): List<Certification>? { fun Network.getEdgeFor(issuer: Fingerprint, target: Fingerprint): List<EdgeComponent>? {
return getEdgeFor(issuer, target, null) return getEdgeFor(issuer, target, null)
} }
fun Network.getEdgeFor(issuer: Fingerprint, target: Fingerprint, userId: String?): List<Certification>? { fun Network.getEdgeFor(issuer: Fingerprint, target: Fingerprint, userId: String?): List<EdgeComponent>? {
return getEdgesFor(issuer, target)?.certifications?.get(userId) return getEdgesFor(issuer, target)?.components?.get(userId)
} }
fun Network.getEdgeFor(issuer: String, target: String): List<Certification>? { fun Network.getEdgeFor(issuer: String, target: String): List<EdgeComponent>? {
return getEdgeFor(issuer, target, null) return getEdgeFor(issuer, target, null)
} }
fun Network.getEdgeFor(issuer: String, target: String, userId: String?): List<Certification>? { fun Network.getEdgeFor(issuer: String, target: String, userId: String?): List<EdgeComponent>? {
return getEdgeFor(Fingerprint(issuer), Fingerprint(target), userId) return getEdgeFor(Fingerprint(issuer), Fingerprint(target), userId)
} }

View file

@ -7,23 +7,23 @@ package org.pgpainless.wot.dijkstra
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class CertSynopsisTest: NetworkDSL { class NodeTest: NetworkDSL {
@Test @Test
fun `Fingerprint 'A' toString`() { fun `Fingerprint 'A' toString`() {
val node = CertSynopsis("A") val node = Node("A")
assertEquals("A", node.toString()) assertEquals("A", node.toString())
} }
@Test @Test
fun `Fingerprint 'a' toString`() { fun `Fingerprint 'a' toString`() {
val node = CertSynopsis("a") val node = Node("a")
assertEquals("A", node.toString()) assertEquals("A", node.toString())
} }
@Test @Test
fun `Fingerprint 'A' and UserID toString`() { fun `Fingerprint 'A' and UserID toString`() {
val node = CertSynopsis("A", "Alice <alice@example.org>") val node = Node("A", "Alice <alice@example.org>")
assertEquals("A (Alice <alice@example.org>)", node.toString()) assertEquals("A (Alice <alice@example.org>)", node.toString())
} }
} }

View file

@ -3,26 +3,25 @@ package org.pgpainless.wot.dijkstra
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import org.pgpainless.wot.dijkstra.sq.* import org.pgpainless.wot.dijkstra.sq.*
import java.util.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
class PathTest: NetworkDSL { class PathTest: NetworkDSL {
private val root = CertSynopsis("aabbccddeeAABBCCDDEEaabbccddeeAABBCCDDEE") private val root = Node("aabbccddeeAABBCCDDEEaabbccddeeAABBCCDDEE")
private val alice = CertSynopsis("0000000000000000000000000000000000000000") private val alice = Node("0000000000000000000000000000000000000000")
private val bob = CertSynopsis("1111111111111111111111111111111111111111") private val bob = Node("1111111111111111111111111111111111111111")
// Root -(255, 255)-> Alice // Root -(255, 255)-> Alice
private val root_alice__fully_trusted = Certification(root, alice, 255, Depth.unconstrained()) private val root_alice__fully_trusted = EdgeComponent(root, alice, 255, Depth.unconstrained())
// Root -(60,0)-> Alice // Root -(60,0)-> Alice
private val root_alice__marginally_trusted = Certification(root, alice, 60, Depth.limited(0)) private val root_alice__marginally_trusted = EdgeComponent(root, alice, 60, Depth.limited(0))
// Alice -(255,255)-> Root // Alice -(255,255)-> Root
private val alice_root = Certification(alice, root, 255, Depth.unconstrained()) private val alice_root = EdgeComponent(alice, root, 255, Depth.unconstrained())
// Alice -(120, 1)-> Bob // Alice -(120, 1)-> Bob
private val alice_bob = Certification(alice, bob) private val alice_bob = EdgeComponent(alice, bob)
// Root -> Root // Root -> Root
private val root_root = Certification(root, root, 120, Depth.limited(1)) private val root_root = EdgeComponent(root, root, 120, Depth.limited(1))
@Test @Test
fun `verify that an empty Path is properly initialized`() { fun `verify that an empty Path is properly initialized`() {
@ -35,7 +34,7 @@ class PathTest: NetworkDSL {
} }
@Test @Test
fun `verify that append()ing multiple Certifications properly changes the trust amount of the Path`() { fun `verify that append()ing multiple components properly changes the trust amount of the Path`() {
val path = Path(root) val path = Path(root)
assertEquals(1, path.length) assertEquals(1, path.length)
assertEquals(120, path.amount) // default amount of an empty path assertEquals(120, path.amount) // default amount of an empty path
@ -56,7 +55,7 @@ class PathTest: NetworkDSL {
} }
@Test @Test
fun `verify that append()ing a Certification whose issuer mismatches the target of the Path fails`() { fun `verify that append()ing a component whose issuer mismatches the target of the Path fails`() {
val path = Path(root) val path = Path(root)
assertEquals(listOf(root), path.certificates) assertEquals(listOf(root), path.certificates)
assertEquals(1, path.length) assertEquals(1, path.length)
@ -64,7 +63,7 @@ class PathTest: NetworkDSL {
} }
@Test @Test
fun `verify that append()ing a Certification fails if it exceeds the Path's depth`() { fun `verify that append()ing a component fails if it exceeds the Path's depth`() {
val path = Path(root) val path = Path(root)
path.append(root_alice__marginally_trusted) path.append(root_alice__marginally_trusted)
assertEquals(60, path.amount) assertEquals(60, path.amount)
@ -76,7 +75,7 @@ class PathTest: NetworkDSL {
} }
@Test @Test
fun `verify that append()ing a Certification fails of the result would contain cycles`() { fun `verify that append()ing a component fails of the result would contain cycles`() {
val path = Path(root) val path = Path(root)
path.append(root_alice__fully_trusted) path.append(root_alice__fully_trusted)
assertThrows<IllegalArgumentException> { assertThrows<IllegalArgumentException> {

View file

@ -3,16 +3,15 @@ package org.pgpainless.wot.dijkstra
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import org.pgpainless.wot.dijkstra.sq.* import org.pgpainless.wot.dijkstra.sq.*
import java.util.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
class PathsTest: NetworkDSL { class PathsTest: NetworkDSL {
private val alice = CertSynopsis("0000000000000000000000000000000000000000") private val alice = Node("0000000000000000000000000000000000000000")
private val bob = CertSynopsis("1111111111111111111111111111111111111111") private val bob = Node("1111111111111111111111111111111111111111")
private val alice_bob_1 = Certification(alice, bob, 140, Depth.unconstrained()) private val alice_bob_1 = EdgeComponent(alice, bob, 140, Depth.unconstrained())
private val alice_bob_2 = Certification(alice, bob, 160, Depth.limited(1)) private val alice_bob_2 = EdgeComponent(alice, bob, 160, Depth.limited(1))
@Test @Test
fun `verify that an empty Paths object has an amount of zero`() { fun `verify that an empty Paths object has an amount of zero`() {