mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-16 01:12:05 +01:00
Refactor - Renaming
CertSynopsis = Node Certification = Edge CertificationSet = EdgeSet
This commit is contained in:
parent
dd4e44b8f0
commit
3c4088a89e
25 changed files with 322 additions and 322 deletions
|
@ -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 edge = Edge(
|
||||||
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(edge), 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>",
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -141,7 +141,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all verifiable certifications on the certificate as incoming edges to
|
* Add all verifiable certifications on the certificate as incoming edgeSet to
|
||||||
* the [Network.Builder].
|
* the [Network.Builder].
|
||||||
*
|
*
|
||||||
* @param validatedTarget validated certificate
|
* @param validatedTarget validated certificate
|
||||||
|
@ -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
|
// Edge 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
|
||||||
|
|
|
@ -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.Edge
|
||||||
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): Edge {
|
||||||
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): Edge {
|
||||||
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): Edge {
|
||||||
return Certification(
|
return Edge(
|
||||||
issuer,
|
issuer,
|
||||||
target,
|
target,
|
||||||
targetUserId,
|
targetUserId,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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.EdgeSet
|
||||||
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
|
||||||
|
@ -55,7 +55,7 @@ class WebOfTrustTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val fooBankCaEdges = network.edges[fooBankCa]!!
|
val fooBankCaEdges = network.edgeSet[fooBankCa]!!
|
||||||
assertEquals(2, fooBankCaEdges.size)
|
assertEquals(2, fooBankCaEdges.size)
|
||||||
|
|
||||||
val fbc2fbe = getEdgeFromTo(network, fooBankCa, fooBankEmployee)
|
val fbc2fbe = getEdgeFromTo(network, fooBankCa, fooBankEmployee)
|
||||||
|
@ -80,8 +80,8 @@ class WebOfTrustTest {
|
||||||
val network = WebOfTrust(certD).buildNetwork()
|
val network = WebOfTrust(certD).buildNetwork()
|
||||||
|
|
||||||
assertTrue { network.nodes.isEmpty() }
|
assertTrue { network.nodes.isEmpty() }
|
||||||
assertTrue { network.edges.isEmpty() }
|
assertTrue { network.edgeSet.isEmpty() }
|
||||||
assertTrue { network.reverseEdges.isEmpty() }
|
assertTrue { network.reverseEdgeSet.isEmpty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -94,7 +94,7 @@ class WebOfTrustTest {
|
||||||
|
|
||||||
|
|
||||||
private fun assertHasIssuerAndTarget(
|
private fun assertHasIssuerAndTarget(
|
||||||
certifications: CertificationSet,
|
certifications: EdgeSet,
|
||||||
issuer: Fingerprint,
|
issuer: Fingerprint,
|
||||||
target: Fingerprint) {
|
target: Fingerprint) {
|
||||||
assertEquals(issuer, certifications.issuer.fingerprint)
|
assertEquals(issuer, certifications.issuer.fingerprint)
|
||||||
|
@ -119,13 +119,13 @@ 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): EdgeSet? {
|
||||||
val edges = network.edges[issuer] ?: return null
|
val edges = network.edgeSet[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): EdgeSet? {
|
||||||
val revEdges = network.reverseEdges[target] ?: return null
|
val revEdges = network.reverseEdgeSet[target] ?: return null
|
||||||
return revEdges.find { issuer == it.issuer.fingerprint }
|
return revEdges.find { issuer == it.issuer.fingerprint }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -51,7 +51,7 @@ class WebOfTrustUnitTest {
|
||||||
@Test
|
@Test
|
||||||
fun simple() {
|
fun simple() {
|
||||||
val network = getNetwork("/home/heiko/src/sequoia-wot/tests/data/simple.pgp")
|
val network = getNetwork("/home/heiko/src/sequoia-wot/tests/data/simple.pgp")
|
||||||
println("Network contains " + network.nodes.size + " nodes with " + network.numberOfEdges + " edges built from " + network.numberOfSignatures + " signatures.")
|
println("Network contains " + network.nodes.size + " nodes with " + network.numberOfEdges + " edgeSet built from " + network.numberOfSignatures + " signatures.")
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ class WebOfTrustUnitTest {
|
||||||
// Certified by: 78C3814EFD16E68F4F1AB4B874E30AE11FFCFB1B
|
// Certified by: 78C3814EFD16E68F4F1AB4B874E30AE11FFCFB1B
|
||||||
|
|
||||||
val network = getNetwork("/home/heiko/src/sequoia-wot/tests/data/cycle.pgp")
|
val network = getNetwork("/home/heiko/src/sequoia-wot/tests/data/cycle.pgp")
|
||||||
println("Network contains " + network.nodes.size + " nodes with " + network.numberOfEdges + " edges built from " + network.numberOfSignatures + " signatures.")
|
println("Network contains " + network.nodes.size + " nodes with " + network.numberOfEdges + " edgeSet built from " + network.numberOfSignatures + " signatures.")
|
||||||
val q = Query(network, Roots(), false)
|
val q = Query(network, Roots(), false)
|
||||||
|
|
||||||
val a1 = q.backwardPropagate(frankFpr, frankUid, false, IdempotentCertificationFilter());
|
val a1 = q.backwardPropagate(frankFpr, frankUid, false, IdempotentCertificationFilter());
|
||||||
|
|
|
@ -11,7 +11,7 @@ import org.pgpainless.wot.dijkstra.sq.ReferenceTime
|
||||||
/**
|
/**
|
||||||
* Web of Trust API, offering different operations.
|
* Web of Trust API, offering different operations.
|
||||||
*
|
*
|
||||||
* @param network initialized [Network] containing certificates as nodes and certifications as edges.
|
* @param network initialized [Network] containing certificates as nodes and certifications as edgeSet.
|
||||||
* @param trustRoots one or more [Fingerprints][Fingerprint] of trust-roots.
|
* @param trustRoots one or more [Fingerprints][Fingerprint] of trust-roots.
|
||||||
* @param gossip if true, consider all certificates as weakly trusted trust-roots
|
* @param gossip if true, consider all certificates as weakly trusted trust-roots
|
||||||
* @param certificationNetwork if true, all certifications are treated as delegations with infinite trust depth and no regular expressions
|
* @param certificationNetwork if true, all certifications are treated as delegations with infinite trust depth and no regular expressions
|
||||||
|
|
|
@ -48,7 +48,7 @@ internal class Cost(
|
||||||
// We perform a Dijkstra in reserve from the target towards the roots.
|
// We perform a Dijkstra in reserve from the target towards the roots.
|
||||||
internal data class ForwardPointer(
|
internal data class ForwardPointer(
|
||||||
// If null, then the target.
|
// If null, then the target.
|
||||||
val next: Certification?
|
val next: Edge?
|
||||||
)
|
)
|
||||||
|
|
||||||
class Query(
|
class Query(
|
||||||
|
@ -174,7 +174,7 @@ class Query(
|
||||||
///
|
///
|
||||||
/// # Algorithm
|
/// # Algorithm
|
||||||
///
|
///
|
||||||
/// This algorithm reverses the edges in the network and then
|
/// This algorithm reverses the edgeSet in the network and then
|
||||||
/// executes a variant of [Dijkstra's shortest path algorithm].
|
/// executes a variant of [Dijkstra's shortest path algorithm].
|
||||||
/// The algorithm sets the initial node to be the target and works
|
/// The algorithm sets the initial node to be the target and works
|
||||||
/// outwards. Consider the following network:
|
/// outwards. Consider the following network:
|
||||||
|
@ -362,7 +362,7 @@ class Query(
|
||||||
var depth: Int = if (selfSigned) 1 else 0
|
var depth: Int = if (selfSigned) 1 else 0
|
||||||
|
|
||||||
while (fp.next != null) {
|
while (fp.next != null) {
|
||||||
val c: Certification = fp.next!! // FIXME
|
val c: Edge = fp.next!! // FIXME
|
||||||
|
|
||||||
val a = c.trustAmount
|
val a = c.trustAmount
|
||||||
val d = c.trustDepth
|
val d = c.trustDepth
|
||||||
|
@ -430,10 +430,10 @@ class Query(
|
||||||
// Get signeeFp
|
// Get signeeFp
|
||||||
|
|
||||||
// Not limiting by required_depth, because 'network' doesn't expose an interface for this
|
// Not limiting by required_depth, because 'network' doesn't expose an interface for this
|
||||||
val certificationSets: List<CertificationSet> =
|
val edges: List<EdgeSet> =
|
||||||
network.reverseEdges[signeeFpr].orEmpty() // "certifications_of"
|
network.reverseEdgeSet[signeeFpr].orEmpty() // "certifications_of"
|
||||||
|
|
||||||
if (certificationSets.isEmpty()) {
|
if (edges.isEmpty()) {
|
||||||
// Nothing certified it. The path is a dead end.
|
// Nothing certified it. The path is a dead end.
|
||||||
logger.debug("{} was not certified, dead end", signeeFpr)
|
logger.debug("{} was not certified, dead end", signeeFpr)
|
||||||
continue;
|
continue;
|
||||||
|
@ -442,9 +442,9 @@ class Query(
|
||||||
logger.debug("Visiting {} ({}), certified {} times",
|
logger.debug("Visiting {} ({}), certified {} times",
|
||||||
signee.fingerprint,
|
signee.fingerprint,
|
||||||
signee.toString(),
|
signee.toString(),
|
||||||
certificationSets.size)
|
edges.size)
|
||||||
|
|
||||||
for (certification in certificationSets
|
for (certification in edges
|
||||||
.map { cs ->
|
.map { cs ->
|
||||||
cs.certifications
|
cs.certifications
|
||||||
.map { it.value }.flatten()
|
.map { it.value }.flatten()
|
||||||
|
@ -472,7 +472,7 @@ class Query(
|
||||||
|
|
||||||
|
|
||||||
if (fv.amount == 0) {
|
if (fv.amount == 0) {
|
||||||
logger.debug(" Certification amount is 0, skipping")
|
logger.debug(" Edge amount is 0, skipping")
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,20 +481,20 @@ class Query(
|
||||||
&& certification.userId != targetUserid) {
|
&& certification.userId != targetUserid) {
|
||||||
assert(signeeFp.next == null)
|
assert(signeeFp.next == null)
|
||||||
|
|
||||||
logger.debug(" Certification certifies target, but for the wrong user id (want: {}, got: {})",
|
logger.debug(" Edge certifies target, but for the wrong user id (want: {}, got: {})",
|
||||||
targetUserid, certification.userId)
|
targetUserid, certification.userId)
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fv.depth < Depth.auto(signeeFpCost.depth)) {
|
if (fv.depth < Depth.auto(signeeFpCost.depth)) {
|
||||||
logger.debug(" Certification does not have enough depth ({}, needed: {}), skipping", fv.depth, signeeFpCost.depth)
|
logger.debug(" Edge does not have enough depth ({}, needed: {}), skipping", fv.depth, signeeFpCost.depth)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
val re = fv.regexps
|
val re = fv.regexps
|
||||||
if ((re != null) && !re.matches(targetUserid)) {
|
if ((re != null) && !re.matches(targetUserid)) {
|
||||||
logger.debug(" Certification's re does not match target User ID, skipping.")
|
logger.debug(" Edge's re does not match target User ID, skipping.")
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,7 +538,7 @@ class Query(
|
||||||
cn?.target ?: "target", currentFpCost.amount, currentFpCost.depth)
|
cn?.target ?: "target", currentFpCost.amount, currentFpCost.depth)
|
||||||
|
|
||||||
// We prefer a shorter path (in terms of
|
// We prefer a shorter path (in terms of
|
||||||
// edges) as this allows us to reach more of
|
// edgeSet) as this allows us to reach more of
|
||||||
// the graph.
|
// the graph.
|
||||||
//
|
//
|
||||||
// If the path length is equal, we prefer the
|
// If the path length is equal, we prefer the
|
||||||
|
@ -615,7 +615,7 @@ class Query(
|
||||||
//
|
//
|
||||||
// XXX: Self-signatures should be first class and not
|
// XXX: Self-signatures should be first class and not
|
||||||
// synthesized like this on the fly.
|
// synthesized like this on the fly.
|
||||||
val selfsig = Certification(
|
val selfsig = Edge(
|
||||||
target, target, targetUserid,
|
target, target, targetUserid,
|
||||||
|
|
||||||
// FIXME! Use userid binding signature by default, reference time only as fallback:
|
// FIXME! Use userid binding signature by default, reference time only as fallback:
|
||||||
|
@ -651,7 +651,7 @@ class Query(
|
||||||
var amount = 120;
|
var amount = 120;
|
||||||
|
|
||||||
// nodes[0] is the root; nodes[nodes.len() - 1] is the target.
|
// nodes[0] is the root; nodes[nodes.len() - 1] is the target.
|
||||||
val nodes: MutableList<Certification> = mutableListOf();
|
val nodes: MutableList<Edge> = mutableListOf();
|
||||||
while (true) {
|
while (true) {
|
||||||
val c = fp.next ?: break
|
val c = fp.next ?: break
|
||||||
|
|
||||||
|
@ -673,7 +673,7 @@ class Query(
|
||||||
if (selfSigned) {
|
if (selfSigned) {
|
||||||
val tail = nodes.last()
|
val tail = nodes.last()
|
||||||
if (tail.userId != targetUserid) {
|
if (tail.userId != targetUserid) {
|
||||||
val selfsig = Certification(target, target, targetUserid, Date());
|
val selfsig = Edge(target, target, targetUserid, Date());
|
||||||
nodes.add(selfsig);
|
nodes.add(selfsig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -725,7 +725,7 @@ class Query(
|
||||||
// .unwrap_or("<missing User ID>".into());
|
// .unwrap_or("<missing User ID>".into());
|
||||||
// t!(" <{}, {}>: {}",
|
// t!(" <{}, {}>: {}",
|
||||||
// fpr, userid,
|
// fpr, userid,
|
||||||
// format!("{} trust amount (max: {}), {} edges",
|
// format!("{} trust amount (max: {}), {} edgeSet",
|
||||||
// amount, path.amount(),
|
// amount, path.amount(),
|
||||||
// path.len() - 1));
|
// path.len() - 1));
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package org.pgpainless.wot.dijkstra.filter
|
package org.pgpainless.wot.dijkstra.filter
|
||||||
|
|
||||||
import org.pgpainless.wot.dijkstra.sq.Certification
|
import org.pgpainless.wot.dijkstra.sq.Edge
|
||||||
import org.pgpainless.wot.dijkstra.sq.Fingerprint
|
import org.pgpainless.wot.dijkstra.sq.Fingerprint
|
||||||
|
|
||||||
class CapCertificateFilter() : CertificationFilter {
|
class CapCertificateFilter() : CertificationFilter {
|
||||||
|
@ -12,7 +12,7 @@ class CapCertificateFilter() : CertificationFilter {
|
||||||
// A certificate's trust amount will be limited to this amount.
|
// A certificate's trust amount will be limited to this amount.
|
||||||
private val caps: HashMap<Fingerprint, Int> = hashMapOf()
|
private val caps: HashMap<Fingerprint, Int> = hashMapOf()
|
||||||
|
|
||||||
override fun cost(c: Certification, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
override fun cost(c: Edge, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
||||||
caps[c.issuer.fingerprint]?.let {
|
caps[c.issuer.fingerprint]?.let {
|
||||||
if (it < values.amount) {
|
if (it < values.amount) {
|
||||||
values.amount = it
|
values.amount = it
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package org.pgpainless.wot.dijkstra.filter
|
package org.pgpainless.wot.dijkstra.filter
|
||||||
|
|
||||||
import org.pgpainless.wot.dijkstra.sq.Certification
|
import org.pgpainless.wot.dijkstra.sq.Edge
|
||||||
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
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ interface CertificationFilter {
|
||||||
*
|
*
|
||||||
* If the function returns `false`, the certification should be skipped.
|
* If the function returns `false`, the certification should be skipped.
|
||||||
*/
|
*/
|
||||||
fun cost(c: Certification, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
fun cost(c: Edge, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package org.pgpainless.wot.dijkstra.filter
|
package org.pgpainless.wot.dijkstra.filter
|
||||||
|
|
||||||
import org.pgpainless.wot.dijkstra.sq.Certification
|
import org.pgpainless.wot.dijkstra.sq.Edge
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filter that chains multiple filters together.
|
* A filter that chains multiple filters together.
|
||||||
|
@ -15,7 +15,7 @@ import org.pgpainless.wot.dijkstra.sq.Certification
|
||||||
*/
|
*/
|
||||||
class ChainFilter(val filters: MutableList<CertificationFilter>) : CertificationFilter {
|
class ChainFilter(val filters: MutableList<CertificationFilter>) : CertificationFilter {
|
||||||
|
|
||||||
override fun cost(c: Certification, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
override fun cost(c: Edge, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
||||||
|
|
||||||
// If any inner filter returns `false`, immediately return false
|
// If any inner filter returns `false`, immediately return false
|
||||||
return !this.filters.any { !it.cost(c, values, ignoreRegexps) }
|
return !this.filters.any { !it.cost(c, values, ignoreRegexps) }
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package org.pgpainless.wot.dijkstra.filter
|
package org.pgpainless.wot.dijkstra.filter
|
||||||
|
|
||||||
import org.pgpainless.wot.dijkstra.sq.Certification
|
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.Path
|
import org.pgpainless.wot.dijkstra.sq.Path
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ class SuppressCertificationFilter() : CertificationFilter {
|
||||||
// A certification's trust amount will be suppressed by this amount.
|
// A certification's trust amount will be suppressed by this amount.
|
||||||
private val amount: HashMap<Pair<Fingerprint, Fingerprint>, Int> = hashMapOf()
|
private val amount: HashMap<Pair<Fingerprint, Fingerprint>, Int> = hashMapOf()
|
||||||
|
|
||||||
override fun cost(c: Certification, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
override fun cost(c: Edge, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
||||||
amount[Pair(c.issuer.fingerprint, c.issuer.fingerprint)]?.let { suppress ->
|
amount[Pair(c.issuer.fingerprint, c.issuer.fingerprint)]?.let { suppress ->
|
||||||
values.amount = if (values.amount > suppress) {
|
values.amount = if (values.amount > suppress) {
|
||||||
values.amount - suppress
|
values.amount - suppress
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package org.pgpainless.wot.dijkstra.filter
|
package org.pgpainless.wot.dijkstra.filter
|
||||||
|
|
||||||
import org.pgpainless.wot.dijkstra.sq.Certification
|
import org.pgpainless.wot.dijkstra.sq.Edge
|
||||||
import org.pgpainless.wot.dijkstra.sq.Fingerprint
|
import org.pgpainless.wot.dijkstra.sq.Fingerprint
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,7 @@ class SuppressIssuerFilter() : CertificationFilter {
|
||||||
// A certification's trust amount will be suppressed by this amount.
|
// A certification's trust amount will be suppressed by this amount.
|
||||||
private val amount: HashMap<Fingerprint, Int> = hashMapOf()
|
private val amount: HashMap<Fingerprint, Int> = hashMapOf()
|
||||||
|
|
||||||
override fun cost(c: Certification, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
override fun cost(c: Edge, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
||||||
amount[c.issuer.fingerprint]?.let { suppress ->
|
amount[c.issuer.fingerprint]?.let { suppress ->
|
||||||
values.amount = if (values.amount > suppress) {
|
values.amount = if (values.amount > suppress) {
|
||||||
values.amount - suppress
|
values.amount - suppress
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package org.pgpainless.wot.dijkstra.filter
|
package org.pgpainless.wot.dijkstra.filter
|
||||||
|
|
||||||
import org.pgpainless.wot.dijkstra.sq.Certification
|
import org.pgpainless.wot.dijkstra.sq.Edge
|
||||||
import org.pgpainless.wot.dijkstra.sq.Depth
|
import org.pgpainless.wot.dijkstra.sq.Depth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +16,7 @@ import org.pgpainless.wot.dijkstra.sq.Depth
|
||||||
* This filter can be used to view a network as a 'certification network'.
|
* This filter can be used to view a network as a 'certification network'.
|
||||||
*/
|
*/
|
||||||
class TrustedIntroducerFilter : CertificationFilter {
|
class TrustedIntroducerFilter : CertificationFilter {
|
||||||
override fun cost(c: Certification, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
override fun cost(c: Edge, values: FilterValues, ignoreRegexps: Boolean): Boolean {
|
||||||
values.depth = Depth.unconstrained()
|
values.depth = Depth.unconstrained()
|
||||||
if (!ignoreRegexps) {
|
if (!ignoreRegexps) {
|
||||||
values.regexps = null
|
values.regexps = null
|
||||||
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.
|
* A [Edge] 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 synopsis of the certificate that issued the [Edge]
|
||||||
* @param target synopsis of the certificate that is target of this [Certification]
|
* @param target synopsis of the certificate that is target of this [Edge]
|
||||||
* @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 [Edge] is made over the primary key of the target.
|
||||||
* @param creationTime creation time of the [Certification]
|
* @param creationTime creation time of the [Edge]
|
||||||
* @param expirationTime optional expiration time of the [Certification]
|
* @param expirationTime optional expiration time of the [Edge]
|
||||||
* @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 Edge(
|
||||||
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 [Edge] 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 [Edge]
|
||||||
* @param target synopsis of the certificate that is target of this [Certification]
|
* @param target synopsis of the certificate that is target of this [Edge]
|
||||||
* @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 [Edge] is made over the primary key of the target.
|
||||||
* @param creationTime creation time of the [Certification]
|
* @param creationTime creation time of the [Edge]
|
||||||
*/
|
*/
|
||||||
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())
|
|
@ -0,0 +1,115 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.wot.dijkstra.sq
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [EdgeSet] is a set of [Certifications][Edge] made by the same issuer, on the same
|
||||||
|
* target certificate.
|
||||||
|
* In some sense, a [EdgeSet] can be considered an edge in the web of trust.
|
||||||
|
*
|
||||||
|
* @param issuer synopsis of the certificate that issued the [Certifications][Edge]
|
||||||
|
* @param target synopsis of the certificate that is targeted by the [Certifications][Edge]
|
||||||
|
* @param certifications [Map] keyed by user-ids, whose values are [Lists][List] of
|
||||||
|
* [Certifications][Edge] that are calculated over the key user-id. Note, that the key can also be null for
|
||||||
|
* [Certifications][Edge] over the targets primary key.
|
||||||
|
*/
|
||||||
|
class EdgeSet(
|
||||||
|
val issuer: Node,
|
||||||
|
val target: Node,
|
||||||
|
certifications: Map<String?, List<Edge>>) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
certifications.forEach { (_, certifications) ->
|
||||||
|
certifications.forEach {
|
||||||
|
add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _certifications: MutableMap<String?, MutableList<Edge>> = mutableMapOf()
|
||||||
|
val certifications: Map<String?, List<Edge>>
|
||||||
|
get() = _certifications.toMutableMap()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an empty [EdgeSet].
|
||||||
|
*
|
||||||
|
* @param issuer the certificate that issued the [Certifications][Edge].
|
||||||
|
* @param target the certificate that is targeted by the [Certifications][Edge].
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun empty(issuer: Node, target: Node): EdgeSet {
|
||||||
|
return EdgeSet(issuer, target, HashMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a [EdgeSet] from a single [Edge].
|
||||||
|
*
|
||||||
|
* @param edge edge
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun fromCertification(edge: Edge): EdgeSet {
|
||||||
|
val set = empty(edge.issuer, edge.target)
|
||||||
|
set.add(edge)
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge the given [EdgeSet] into this.
|
||||||
|
* This method copies all [Certifications][Edge] from the other [EdgeSet] into [certifications].
|
||||||
|
*
|
||||||
|
* @param other [EdgeSet] with the same issuer fingerprint and target fingerprint as this object.
|
||||||
|
*/
|
||||||
|
fun merge(other: EdgeSet) {
|
||||||
|
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 [Edge] into this objects [certifications].
|
||||||
|
* Adding multiple [Certifications][Edge] for the same datum, but with different creation times results in
|
||||||
|
* only the most recent [Edge(s)][Edge] to be preserved.
|
||||||
|
*
|
||||||
|
* @param edge [Edge] with the same issuer fingerprint and target fingerprint as this object.
|
||||||
|
*/
|
||||||
|
fun add(edge: Edge) {
|
||||||
|
require(issuer.fingerprint == edge.issuer.fingerprint) { "Issuer fingerprint mismatch." }
|
||||||
|
require(target.fingerprint == edge.target.fingerprint) { "Target fingerprint mismatch." }
|
||||||
|
|
||||||
|
val certificationsForUserId = _certifications.getOrPut(edge.userId) { mutableListOf() }
|
||||||
|
if (certificationsForUserId.isEmpty()) {
|
||||||
|
certificationsForUserId.add(edge)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val existing = certificationsForUserId[0]
|
||||||
|
// if existing is older than this edge
|
||||||
|
if (existing.creationTime.before(edge.creationTime)) {
|
||||||
|
// throw away older certifications
|
||||||
|
certificationsForUserId.clear()
|
||||||
|
}
|
||||||
|
// If this edge is newest (or equally old!)
|
||||||
|
if (!existing.creationTime.after(edge.creationTime)) {
|
||||||
|
certificationsForUserId.add(edge)
|
||||||
|
}
|
||||||
|
// else this edge is older, so don't add it
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return certifications.map { it.value }.flatten().joinToString("\n")
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,20 +5,20 @@
|
||||||
package org.pgpainless.wot.dijkstra.sq
|
package org.pgpainless.wot.dijkstra.sq
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A network consists of nodes, and edges between them.
|
* A network consists of nodes, and edgeSet between them.
|
||||||
* For the Web of Trust, nodes consist of [CertSynopses][CertSynopsis], while the edges between the nodes are
|
* For the Web of Trust, nodes consist of [CertSynopses][Node], while the edgeSet between the nodes are
|
||||||
* [CertificationSets][CertificationSet].
|
* [CertificationSets][EdgeSet].
|
||||||
*
|
*
|
||||||
* @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 edgeSet [Map] keyed by the [fingerprint][Fingerprint] of an issuer, whose values are [Lists][List] containing all edgeSet originating from the issuer.
|
||||||
* @param reverseEdges [Map] keyed by the [fingerprint][Fingerprint] of a target, whose values are [Lists][List] containing all edges pointing to the target
|
* @param reverseEdgeSet [Map] keyed by the [fingerprint][Fingerprint] of a target, whose values are [Lists][List] containing all edgeSet pointing to the 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 edgeSet: Map<Fingerprint, List<EdgeSet>>,
|
||||||
val reverseEdges: Map<Fingerprint, List<CertificationSet>>,
|
val reverseEdgeSet: Map<Fingerprint, List<EdgeSet>>,
|
||||||
val referenceTime: ReferenceTime) {
|
val referenceTime: ReferenceTime) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -34,13 +34,13 @@ class Network(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The total number of edges on the network.
|
* The total number of edgeSet on the network.
|
||||||
*
|
*
|
||||||
* @return number of edges
|
* @return number of edgeSet
|
||||||
*/
|
*/
|
||||||
val numberOfEdges: Int
|
val numberOfEdges: Int
|
||||||
get() {
|
get() {
|
||||||
return edges.values.sumOf { it.size }
|
return edgeSet.values.sumOf { it.size }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,7 @@ class Network(
|
||||||
*/
|
*/
|
||||||
val numberOfSignatures: Int
|
val numberOfSignatures: Int
|
||||||
get() {
|
get() {
|
||||||
return edges.values
|
return edgeSet.values
|
||||||
.flatten()
|
.flatten()
|
||||||
.flatMap { it.certifications.values }
|
.flatMap { it.certifications.values }
|
||||||
.sumOf { it.size }
|
.sumOf { it.size }
|
||||||
|
@ -56,9 +56,9 @@ class Network(
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
sb.append("Network with ${nodes.size} nodes, $numberOfEdges edges:\n")
|
sb.append("Network with ${nodes.size} nodes, $numberOfEdges edgeSet:\n")
|
||||||
for (issuer in nodes.keys) {
|
for (issuer in nodes.keys) {
|
||||||
val outEdges = edges[issuer] ?: continue
|
val outEdges = edgeSet[issuer] ?: continue
|
||||||
for (edge in outEdges) {
|
for (edge in outEdges) {
|
||||||
sb.appendLine(edge)
|
sb.appendLine(edge)
|
||||||
}
|
}
|
||||||
|
@ -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 protoEdgeSet: MutableMap<Pair<Fingerprint, Fingerprint>, EdgeSet> = 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: Edge): Builder {
|
||||||
protoEdges.getOrPut(Pair(edge.issuer.fingerprint, edge.target.fingerprint)) {
|
protoEdgeSet.getOrPut(Pair(edge.issuer.fingerprint, edge.target.fingerprint)) {
|
||||||
CertificationSet.empty(edge.issuer, edge.target)
|
EdgeSet.empty(edge.issuer, edge.target)
|
||||||
}.add(edge)
|
}.add(edge)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -93,20 +93,20 @@ class Network(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): Network {
|
fun build(): Network {
|
||||||
val edges = mutableMapOf<Fingerprint, MutableList<CertificationSet>>()
|
val edgeSet = mutableMapOf<Fingerprint, MutableList<EdgeSet>>()
|
||||||
val revEdges = mutableMapOf<Fingerprint, MutableList<CertificationSet>>()
|
val revEdgeSet = mutableMapOf<Fingerprint, MutableList<EdgeSet>>()
|
||||||
|
|
||||||
protoEdges.forEach { (pair, certificationSet) ->
|
protoEdgeSet.forEach { (pair, certificationSet) ->
|
||||||
edges.getOrPut(pair.first) {
|
edgeSet.getOrPut(pair.first) {
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
}.add(certificationSet)
|
}.add(certificationSet)
|
||||||
|
|
||||||
revEdges.getOrPut(pair.second) {
|
revEdgeSet.getOrPut(pair.second) {
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
}.add(certificationSet)
|
}.add(certificationSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Network(nodes, edges, revEdges, referenceTime)
|
return Network(nodes, edgeSet, revEdgeSet, referenceTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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(),
|
|
@ -7,33 +7,33 @@ 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 edgeSet ([Certifications][Edge]), as well as a
|
||||||
* residual depth.
|
* residual depth.
|
||||||
*
|
*
|
||||||
* @param root root of the path
|
* @param root root of the path
|
||||||
* @param edges list of edges from the root to the target
|
* @param edges list of edgeSet from the root to the target
|
||||||
* @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<Edge>,
|
||||||
var residualDepth: Depth
|
var residualDepth: Depth
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a [Path] only consisting of the trust root.
|
* Construct a [Path] only consisting of the trust root.
|
||||||
* The [Path] will have an empty list of edges and an unconstrained residual [Depth].
|
* The [Path] will have an empty list of edgeSet and an unconstrained residual [Depth].
|
||||||
*
|
*
|
||||||
* @param root trust root
|
* @param root trust root
|
||||||
*/
|
*/
|
||||||
constructor(root: CertSynopsis) : this(
|
constructor(root: Node) : this(
|
||||||
root, mutableListOf<Certification>(), Depth.unconstrained())
|
root, mutableListOf<Edge>(), 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 [CertSynopses][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 edgeSet.
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,9 @@ class Path(
|
||||||
get() = edges.size + 1
|
get() = edges.size + 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of edges.
|
* List of edgeSet.
|
||||||
*/
|
*/
|
||||||
val certifications: List<Certification>
|
val certifications: List<Edge>
|
||||||
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 [Edge] would result in a cyclic path
|
||||||
*/
|
*/
|
||||||
fun append(certification: Certification) {
|
fun append(aEdge: Edge) {
|
||||||
require(target.fingerprint == certification.issuer.fingerprint) {
|
require(target.fingerprint == aEdge.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 == aEdge.target.fingerprint
|
||||||
for ((i, edge) in edges.withIndex()) {
|
for ((i, edge) 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 (aEdge.target.fingerprint == edge.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
|
aEdge.userId == edge.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 = aEdge.trustDepth.min(residualDepth.decrease(1))
|
||||||
edges.add(certification)
|
edges.add(aEdge)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
|
|
@ -11,20 +11,20 @@ import java.util.*
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class CertificationSetTest {
|
class EdgeSetTest {
|
||||||
|
|
||||||
private val alice = CertSynopsis(Fingerprint("A"), null, RevocationState.notRevoked(), mapOf())
|
private val alice = Node(Fingerprint("A"), null, RevocationState.notRevoked(), mapOf())
|
||||||
private val bob = CertSynopsis(Fingerprint("B"), null, RevocationState.notRevoked(), mapOf())
|
private val bob = Node(Fingerprint("B"), null, RevocationState.notRevoked(), mapOf())
|
||||||
private val charlie = CertSynopsis(Fingerprint("C"), null, RevocationState.notRevoked(), mapOf())
|
private val charlie = Node(Fingerprint("C"), null, RevocationState.notRevoked(), mapOf())
|
||||||
|
|
||||||
private val aliceSignsBob = Certification(alice, bob, null, Date())
|
private val aliceSignsBob = Edge(alice, bob, null, Date())
|
||||||
private val aliceSignsBobUserId = Certification(alice, bob, "Bob <bob@example.org>", Date())
|
private val aliceSignsBobUserId = Edge(alice, bob, "Bob <bob@example.org>", Date())
|
||||||
private val aliceSignsCharlie = Certification(alice, charlie, null, Date())
|
private val aliceSignsCharlie = Edge(alice, charlie, null, Date())
|
||||||
private val charlieSignsBob = Certification(charlie, bob, null, Date())
|
private val charlieSignsBob = Edge(charlie, bob, null, Date())
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that properties of an empty CertificationSet are also empty`() {
|
fun `verify that properties of an empty CertificationSet are also empty`() {
|
||||||
val empty = CertificationSet.empty(alice, bob)
|
val empty = EdgeSet.empty(alice, bob)
|
||||||
assert(empty.certifications.isEmpty())
|
assert(empty.certifications.isEmpty())
|
||||||
assertEquals(alice, empty.issuer)
|
assertEquals(alice, empty.issuer)
|
||||||
assertEquals(bob, empty.target)
|
assertEquals(bob, empty.target)
|
||||||
|
@ -32,7 +32,7 @@ class CertificationSetTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that add()ing Certification objects works if issuer and target match that of the CertificationSet`() {
|
fun `verify that add()ing Certification objects works if issuer and target match that of the CertificationSet`() {
|
||||||
val set = CertificationSet.empty(alice, bob)
|
val set = EdgeSet.empty(alice, bob)
|
||||||
|
|
||||||
set.add(aliceSignsBob)
|
set.add(aliceSignsBob)
|
||||||
assertTrue {
|
assertTrue {
|
||||||
|
@ -48,20 +48,20 @@ class CertificationSetTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that add()ing another Certification object fails if the issuer mismatches`() {
|
fun `verify that add()ing another Certification object fails if the issuer mismatches`() {
|
||||||
val set = CertificationSet.empty(alice, bob)
|
val set = EdgeSet.empty(alice, bob)
|
||||||
assertThrows<IllegalArgumentException> { set.add(charlieSignsBob) }
|
assertThrows<IllegalArgumentException> { set.add(charlieSignsBob) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that add()ing another Certification object fails if the target mismatches`() {
|
fun `verify that add()ing another Certification object fails if the target mismatches`() {
|
||||||
val set = CertificationSet.empty(alice, bob)
|
val set = EdgeSet.empty(alice, bob)
|
||||||
assertThrows<IllegalArgumentException> { set.add(aliceSignsCharlie) }
|
assertThrows<IllegalArgumentException> { set.add(aliceSignsCharlie) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that merge()ing another CertificationSet works if issuer and target match that of the CertificationSet`() {
|
fun `verify that merge()ing another CertificationSet works if issuer and target match that of the CertificationSet`() {
|
||||||
val set = CertificationSet.fromCertification(aliceSignsBob)
|
val set = EdgeSet.fromCertification(aliceSignsBob)
|
||||||
val others = CertificationSet.fromCertification(aliceSignsBobUserId)
|
val others = EdgeSet.fromCertification(aliceSignsBobUserId)
|
||||||
|
|
||||||
set.merge(others)
|
set.merge(others)
|
||||||
assertEquals(2, set.certifications.size)
|
assertEquals(2, set.certifications.size)
|
||||||
|
@ -71,23 +71,23 @@ class CertificationSetTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that merge()ing another CertificationSet with mismatched issuer fails`() {
|
fun `verify that merge()ing another CertificationSet with mismatched issuer fails`() {
|
||||||
val set = CertificationSet.fromCertification(aliceSignsBob)
|
val set = EdgeSet.fromCertification(aliceSignsBob)
|
||||||
val issuerMismatch = CertificationSet.fromCertification(charlieSignsBob)
|
val issuerMismatch = EdgeSet.fromCertification(charlieSignsBob)
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> { set.merge(issuerMismatch) }
|
assertThrows<IllegalArgumentException> { set.merge(issuerMismatch) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that merge()ing another CertificationSet with mismatched target fails`() {
|
fun `verify that merge()ing another CertificationSet with mismatched target fails`() {
|
||||||
val set = CertificationSet.fromCertification(aliceSignsBob)
|
val set = EdgeSet.fromCertification(aliceSignsBob)
|
||||||
val targetMismatch = CertificationSet.fromCertification(aliceSignsCharlie)
|
val targetMismatch = EdgeSet.fromCertification(aliceSignsCharlie)
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> { set.merge(targetMismatch) }
|
assertThrows<IllegalArgumentException> { set.merge(targetMismatch) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that merge()ing a CertificationSet with itself is idempotent`() {
|
fun `verify that merge()ing a CertificationSet with itself is idempotent`() {
|
||||||
val set = CertificationSet.fromCertification(aliceSignsBob)
|
val set = EdgeSet.fromCertification(aliceSignsBob)
|
||||||
assertEquals(1, set.certifications.size)
|
assertEquals(1, set.certifications.size)
|
||||||
set.merge(set)
|
set.merge(set)
|
||||||
assertEquals(1, set.certifications.size)
|
assertEquals(1, set.certifications.size)
|
||||||
|
@ -95,13 +95,13 @@ class CertificationSetTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that toString() of an empty CertificationSet is the empty string`() {
|
fun `verify that toString() of an empty CertificationSet is the empty string`() {
|
||||||
val empty = CertificationSet.empty(alice, bob)
|
val empty = EdgeSet.empty(alice, bob)
|
||||||
assertEquals("", empty.toString())
|
assertEquals("", empty.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify that toString() of a CertificationSet with two Certifications matches our expectations`() {
|
fun `verify that toString() of a CertificationSet with two Certifications matches our expectations`() {
|
||||||
val twoCerts = CertificationSet.fromCertification(aliceSignsBob)
|
val twoCerts = EdgeSet.fromCertification(aliceSignsBob)
|
||||||
twoCerts.add(aliceSignsBobUserId)
|
twoCerts.add(aliceSignsBobUserId)
|
||||||
|
|
||||||
assertEquals("A certifies binding: null <-> B [120]\n" +
|
assertEquals("A certifies binding: null <-> B [120]\n" +
|
||||||
|
@ -112,11 +112,11 @@ class CertificationSetTest {
|
||||||
fun `verify that for multiple Certifications over the same datum, only the most recent certifications are preserved`() {
|
fun `verify that for multiple Certifications over the same datum, only the most recent certifications are preserved`() {
|
||||||
val now = Date()
|
val now = Date()
|
||||||
val fiveSecondsBefore = Date(now.time - 5000)
|
val fiveSecondsBefore = Date(now.time - 5000)
|
||||||
val old = Certification(alice, bob, "Bob <bob@example.org>", fiveSecondsBefore)
|
val old = Edge(alice, bob, "Bob <bob@example.org>", fiveSecondsBefore)
|
||||||
val new = Certification(alice, bob, "Bob <bob@example.org>", now)
|
val new = Edge(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())
|
val new2 = Edge(alice, bob, "Bob <bob@example.org>", now, null, true, 44, Depth.auto(10), RegexSet.wildcard())
|
||||||
|
|
||||||
var set = CertificationSet(alice, bob, mapOf())
|
var set = EdgeSet(alice, bob, mapOf())
|
||||||
set.add(old)
|
set.add(old)
|
||||||
|
|
||||||
assertEquals(listOf(old), set.certifications["Bob <bob@example.org>"])
|
assertEquals(listOf(old), set.certifications["Bob <bob@example.org>"])
|
|
@ -1,26 +1,26 @@
|
||||||
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.Edge
|
||||||
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 EdgeTest {
|
||||||
|
|
||||||
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(),
|
||||||
|
@ -28,21 +28,21 @@ class CertificationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify result of toString() on certification`() {
|
fun `verify result of toString() on certification`() {
|
||||||
val certification = Certification(alice, bob, "Bob <bob@example.org>", Date())
|
val edge = Edge(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())
|
edge.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `verify result of toString() on delegation`() {
|
fun `verify result of toString() on delegation`() {
|
||||||
val delegation = Certification(alice, bob, null, Date())
|
val delegation = Edge(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 with userId-less issuer`() {
|
||||||
val delegation = Certification(charlie, bob, null, Date())
|
val delegation = Edge(charlie, bob, null, Date())
|
||||||
assertEquals("C certifies binding: null <-> B [120]",
|
assertEquals("C certifies binding: null <-> B [120]",
|
||||||
delegation.toString())
|
delegation.toString())
|
||||||
}
|
}
|
|
@ -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 CertSynopsis(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 CertSynopsis(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 CertSynopsis(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 [Edge] from two [Node] nodes.
|
||||||
*/
|
*/
|
||||||
fun Certification(issuer: CertSynopsis, target: CertSynopsis): Certification =
|
fun Certification(issuer: Node, target: Node): Edge =
|
||||||
Certification(issuer, target, null, Date())
|
Edge(issuer, target, null, Date())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create [Certification] from two [CertSynopsis] nodes and a target [userId].
|
* Create [Edge] from two [Node] nodes and a target [userId].
|
||||||
*/
|
*/
|
||||||
fun Certification(issuer: CertSynopsis, target: CertSynopsis, userId: String): Certification =
|
fun Certification(issuer: Node, target: Node, userId: String): Edge =
|
||||||
Certification(issuer, target, userId, Date())
|
Edge(issuer, target, userId, Date())
|
||||||
|
|
||||||
fun Certification(issuer: CertSynopsis, target: CertSynopsis, amount: Int, depth: Depth): Certification =
|
fun Certification(issuer: Node, target: Node, amount: Int, depth: Depth): Edge =
|
||||||
Certification(issuer, target, null, Date(), null, true, amount, depth, RegexSet.wildcard())
|
Edge(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(CertSynopsis(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(CertSynopsis(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,8 +67,8 @@ 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 {
|
||||||
|
@ -78,8 +78,8 @@ interface NetworkDSL {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 {
|
||||||
|
@ -113,13 +113,13 @@ interface NetworkDSL {
|
||||||
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)) { CertSynopsis(issuer) }
|
||||||
val targetNode = nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target) }
|
val targetNode = nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target) }
|
||||||
return addEdge(Certification(issuerNode, targetNode, null, Date(), null, true, amount, Depth.auto(depth), RegexSet.wildcard()))
|
return addEdge(Edge(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)) { CertSynopsis(issuer) }
|
||||||
val targetNode = nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target) }
|
val targetNode = nodes.getOrPut(Fingerprint(target)) { CertSynopsis(target) }
|
||||||
return addEdge(Certification(issuerNode, targetNode, null, Date(), null, true, amount, Depth.auto(depth), regexSet))
|
return addEdge(Edge(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): EdgeSet? {
|
||||||
return edges[issuer]?.find { it.target.fingerprint == target }
|
return edgeSet[issuer]?.find { it.target.fingerprint == target }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Network.getEdgesFor(issuer: String, target: String): CertificationSet? {
|
fun Network.getEdgesFor(issuer: String, target: String): EdgeSet? {
|
||||||
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<Edge>? {
|
||||||
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<Edge>? {
|
||||||
return getEdgesFor(issuer, target)?.certifications?.get(userId)
|
return getEdgesFor(issuer, target)?.certifications?.get(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Network.getEdgeFor(issuer: String, target: String): List<Certification>? {
|
fun Network.getEdgeFor(issuer: String, target: String): List<Edge>? {
|
||||||
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<Edge>? {
|
||||||
return getEdgeFor(Fingerprint(issuer), Fingerprint(target), userId)
|
return getEdgeFor(Fingerprint(issuer), Fingerprint(target), userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ class NetworkTest: NetworkDSL {
|
||||||
val referenceTime = now()
|
val referenceTime = now()
|
||||||
val network = empty(referenceTime)
|
val network = empty(referenceTime)
|
||||||
assert(network.nodes.isEmpty())
|
assert(network.nodes.isEmpty())
|
||||||
assert(network.edges.isEmpty())
|
assert(network.edgeSet.isEmpty())
|
||||||
assert(network.reverseEdges.isEmpty())
|
assert(network.reverseEdgeSet.isEmpty())
|
||||||
assertEquals(referenceTime, network.referenceTime)
|
assertEquals(referenceTime, network.referenceTime)
|
||||||
assertEquals(0, network.numberOfEdges)
|
assertEquals(0, network.numberOfEdges)
|
||||||
assertEquals(0, network.numberOfSignatures)
|
assertEquals(0, network.numberOfSignatures)
|
||||||
|
@ -57,7 +57,7 @@ class NetworkTest: NetworkDSL {
|
||||||
buildEdge("A", "C", "Charlie <charlie@example.org>")
|
buildEdge("A", "C", "Charlie <charlie@example.org>")
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals("Network with 3 nodes, 2 edges:\n" +
|
assertEquals("Network with 3 nodes, 2 edgeSet:\n" +
|
||||||
"A certifies binding: null <-> B [120]\n" +
|
"A certifies binding: null <-> B [120]\n" +
|
||||||
"A certifies binding: Charlie <charlie@example.org> <-> C [120]\n",
|
"A certifies binding: Charlie <charlie@example.org> <-> C [120]\n",
|
||||||
network.toString())
|
network.toString())
|
||||||
|
|
|
@ -7,7 +7,7 @@ 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`() {
|
Loading…
Reference in a new issue