diff --git a/pgpainless-wot-cli/README.md b/pgpainless-wot-cli/README.md
index e24ead9f..66f00e45 100644
--- a/pgpainless-wot-cli/README.md
+++ b/pgpainless-wot-cli/README.md
@@ -8,6 +8,8 @@ SPDX-License-Identifier: Apache-2.0
This module contains a command line interface application that acts as a front-end for
[`pgpainless-wot`](../pgpainless-wot).
+The interface of the application is modelled after the [sq-wot](https://gitlab.com/sequoia-pgp/sequoia-wot/)
+reference implementation.
## Build
diff --git a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt b/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt
index bb0a6ed3..3de88038 100644
--- a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt
+++ b/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt
@@ -6,10 +6,11 @@ package org.pgpainless.wot.cli
import org.pgpainless.certificate_store.PGPainlessCertD
import org.pgpainless.util.DateUtil
-import org.pgpainless.wot.api.WoTAPI
+import org.pgpainless.wot.WebOfTrust
import org.pgpainless.wot.cli.subcommands.*
import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.ReferenceTime
+import org.pgpainless.wot.dijkstra.sq.api.WoTAPI
import pgp.cert_d.PGPCertificateStoreAdapter
import pgp.cert_d.subkey_lookup.InMemorySubkeyLookupFactory
import pgp.certificate_store.PGPCertificateStore
@@ -19,6 +20,11 @@ import java.io.File
import java.util.concurrent.Callable
import kotlin.system.exitProcess
+/**
+ * Command Line Interface for pgpainless-wot, modelled after the reference implementation "sq-wot".
+ *
+ * @see Sequoia Web of Trust Reference Implementation
+ */
@Command(name = "pgpainless-wot",
subcommands = [
AuthenticateCmd::class,
@@ -110,8 +116,10 @@ class WotCLI: Callable {
val api: WoTAPI
get() {
+ val network = WebOfTrust(certificateStore)
+ .buildNetwork(referenceTime = referenceTime)
return WoTAPI(
- certStores = listOf(certificateStore),
+ network = network,
trustRoots = trustRoots,
gossip = false,
certificationNetwork = false,
diff --git a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmd.kt b/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmd.kt
index b87c86f9..3d7cc296 100644
--- a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmd.kt
+++ b/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmd.kt
@@ -4,7 +4,7 @@
package org.pgpainless.wot.cli.subcommands
-import org.pgpainless.wot.api.AuthenticateAPI
+import org.pgpainless.wot.dijkstra.sq.api.AuthenticateAPI
import org.pgpainless.wot.cli.WotCLI
import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.Path
@@ -15,18 +15,33 @@ import picocli.CommandLine.ParentCommand
import java.text.SimpleDateFormat
import java.util.concurrent.Callable
+/**
+ * Authenticate a binding between a certification and one of its user-ids.
+ */
@Command(name = "authenticate")
class AuthenticateCmd: Callable {
+ /**
+ * Parent command to acquire global options from.
+ */
@ParentCommand
lateinit var parent: WotCLI
+ /**
+ * Fingerprint of the certificate.
+ */
@Parameters(index = "0")
lateinit var fingerprint: String
+ /**
+ * User-ID to authenticate.
+ */
@Parameters(index = "1")
lateinit var userId: String
+ /**
+ * Handle the User-ID as an email address.
+ */
@CommandLine.Option(names = ["--email"], description = ["Consider all user-IDs that contain the given email address."])
var email = false
@@ -46,6 +61,9 @@ class AuthenticateCmd: Callable {
return 0
}
+ /**
+ * Format the [AuthenticateAPI.Result] as a [String] which can be printed to standard out.
+ */
internal fun formatResult(result: AuthenticateAPI.Result): String {
if (result.percentage < 100) {
return "No paths found."
diff --git a/pgpainless-wot-cli/src/test/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmdTest.kt b/pgpainless-wot-cli/src/test/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmdTest.kt
index e1e4072c..93831302 100644
--- a/pgpainless-wot-cli/src/test/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmdTest.kt
+++ b/pgpainless-wot-cli/src/test/kotlin/org/pgpainless/wot/cli/subcommands/AuthenticateCmdTest.kt
@@ -1,7 +1,7 @@
package org.pgpainless.wot.cli.subcommands
import org.junit.jupiter.api.Test
-import org.pgpainless.wot.api.AuthenticateAPI
+import org.pgpainless.wot.dijkstra.sq.api.AuthenticateAPI
import org.pgpainless.wot.dijkstra.sq.*
import java.text.SimpleDateFormat
import kotlin.test.assertEquals
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt b/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt
index 66500d7b..3d80ab36 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt
+++ b/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt
@@ -43,14 +43,23 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
*
* @param certificateDirectory PGP-Certificate-Directory instance
*/
- constructor(certificateDirectory: PGPCertificateDirectory): this(PGPCertificateStoreAdapter(certificateDirectory))
+ constructor(certificateDirectory: PGPCertificateDirectory):
+ this(PGPCertificateStoreAdapter(certificateDirectory))
- fun buildNetwork(policy: Policy = PGPainless.getPolicy(), referenceTime: ReferenceTime = now()): Network {
+ /**
+ *
+ */
+ fun buildNetwork(policy: Policy = PGPainless.getPolicy(),
+ referenceTime: ReferenceTime = now()): Network {
val certificates = getAllCertificatesFromTheStore()
val networkFactory = PGPNetworkFactory.fromCertificates(certificates, policy, referenceTime)
return networkFactory.buildNetwork()
}
+ /**
+ * Return a [Sequence] containing all [Certificates][Certificate] in the [PGPCertificateStore],
+ * with the specially named "trust-root" certificate optionally appended if present.
+ */
private fun getAllCertificatesFromTheStore(): Sequence {
var trustRoot: Certificate? = null
try {
@@ -157,7 +166,8 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
while (userIds.hasNext()) {
val userId = userIds.next()
// There are potentially multiple certifications per user-ID
- val userIdSigs = SignatureUtils.get3rdPartyCertificationsFor(userId, validatedTargetKeyRing)
+ val userIdSigs = SignatureUtils.get3rdPartyCertificationsFor(
+ userId, validatedTargetKeyRing)
userIdSigs.forEach {
processCertificationOnUserId(targetPrimaryKey, target, userId, it)
}
@@ -194,7 +204,8 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
}
} catch (e: SignatureValidationException) {
val targetFingerprint = OpenPgpFingerprint.of(targetPrimaryKey)
- LOGGER.warn("Cannot verify signature by $issuerFingerprint on cert of $targetFingerprint", e)
+ LOGGER.warn("Cannot verify signature by $issuerFingerprint" +
+ " on cert of $targetFingerprint", e)
}
}
}
@@ -321,7 +332,8 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
referenceTime: ReferenceTime): List {
return certificates
.mapNotNull {
- try { PGPainless.readKeyRing().publicKeyRing(it.inputStream) } catch (e: IOException) { null }
+ try { PGPainless.readKeyRing().publicKeyRing(it.inputStream) }
+ catch (e: IOException) { null }
}
.map { KeyRingInfo(it, policy, referenceTime.timestamp) }
.toList()
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/AuthenticateAPI.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/AuthenticateAPI.kt
similarity index 97%
rename from pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/AuthenticateAPI.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/AuthenticateAPI.kt
index cd19a7e4..93e36ce6 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/AuthenticateAPI.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/AuthenticateAPI.kt
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.api
+package org.pgpainless.wot.dijkstra.sq.api
import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.Paths
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/AuthenticationLevel.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/AuthenticationLevel.kt
similarity index 92%
rename from pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/AuthenticationLevel.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/AuthenticationLevel.kt
index 07303a00..680f4a56 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/AuthenticationLevel.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/AuthenticationLevel.kt
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.api
+package org.pgpainless.wot.dijkstra.sq.api
/**
* Enum for different levels of Trust.
diff --git a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/subcommands/Format.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/Format.kt
similarity index 94%
rename from pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/subcommands/Format.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/Format.kt
index 6048e5a2..d39059f5 100644
--- a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/subcommands/Format.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/Format.kt
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.cli.subcommands
+package org.pgpainless.wot.dijkstra.sq.api
/**
* Enum listing possible output formats.
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/IdentifyAPI.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/IdentifyAPI.kt
similarity index 89%
rename from pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/IdentifyAPI.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/IdentifyAPI.kt
index 647fdafb..64d179e0 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/IdentifyAPI.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/IdentifyAPI.kt
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.api
+package org.pgpainless.wot.dijkstra.sq.api
import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.Paths
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/ListAPI.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/ListAPI.kt
similarity index 85%
rename from pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/ListAPI.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/ListAPI.kt
index cf64e056..45499865 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/ListAPI.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/ListAPI.kt
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.api
+package org.pgpainless.wot.dijkstra.sq.api
import org.pgpainless.wot.dijkstra.sq.Paths
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/LookupAPI.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/LookupAPI.kt
similarity index 88%
rename from pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/LookupAPI.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/LookupAPI.kt
index 09ff9f75..f13df777 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/LookupAPI.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/LookupAPI.kt
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.api
+package org.pgpainless.wot.dijkstra.sq.api
import org.pgpainless.wot.dijkstra.sq.Paths
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/PathAPI.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/PathAPI.kt
similarity index 94%
rename from pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/PathAPI.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/PathAPI.kt
index 01faa9f9..709c6400 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/PathAPI.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/PathAPI.kt
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.api
+package org.pgpainless.wot.dijkstra.sq.api
import org.pgpainless.wot.dijkstra.sq.Fingerprint
diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/WoTAPI.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/WoTAPI.kt
similarity index 62%
rename from pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/WoTAPI.kt
rename to wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/WoTAPI.kt
index ded80e0f..70f42162 100644
--- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/api/WoTAPI.kt
+++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/sq/api/WoTAPI.kt
@@ -2,20 +2,16 @@
//
// SPDX-License-Identifier: Apache-2.0
-package org.pgpainless.wot.api
+package org.pgpainless.wot.dijkstra.sq.api
-import org.pgpainless.certificate_store.PGPainlessCertD
-import org.pgpainless.util.NotationRegistry
import org.pgpainless.wot.dijkstra.sq.Fingerprint
+import org.pgpainless.wot.dijkstra.sq.Network
import org.pgpainless.wot.dijkstra.sq.ReferenceTime
-import pgp.cert_d.PGPCertificateStoreAdapter
-import pgp.cert_d.subkey_lookup.InMemorySubkeyLookupFactory
-import pgp.certificate_store.PGPCertificateStore
/**
* Web of Trust API, offering different operations.
*
- * @param certStores one or more [PGPCertificateStores][PGPCertificateStore] to retrieve certificates from.
+ * @param network initialized [Network] containing certificates as nodes and certifications as edges.
* @param trustRoots one or more [Fingerprints][Fingerprint] of 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
@@ -24,35 +20,24 @@ import pgp.certificate_store.PGPCertificateStore
* @param knownNotationRegistry registry of known notations
*/
class WoTAPI(
- val certStores: List = getDefaultCertStores(),
+ val network: Network,
val trustRoots: List,
val gossip: Boolean = false,
val certificationNetwork: Boolean = false,
val trustAmount: Int = AuthenticationLevel.Fully.amount,
- val referenceTime: ReferenceTime = ReferenceTime.now(),
- val knownNotationRegistry: NotationRegistry = NotationRegistry()
+ val referenceTime: ReferenceTime = ReferenceTime.now()
): AuthenticateAPI, IdentifyAPI, ListAPI, LookupAPI, PathAPI {
/**
* Secondary constructor, taking an [AuthenticationLevel] instead of an [Int].
*/
- constructor(certStores: List = getDefaultCertStores(),
+ constructor(network: Network,
trustRoots: List,
gossip: Boolean = false,
certificationNetwork: Boolean = false,
trustAmount: AuthenticationLevel = AuthenticationLevel.Fully,
- referenceTime: ReferenceTime = ReferenceTime.now(),
- knownNotationRegistry: NotationRegistry = NotationRegistry()):
- this(certStores,trustRoots, gossip,certificationNetwork, trustAmount.amount, referenceTime, knownNotationRegistry)
-
- companion object {
- @JvmStatic
- fun getDefaultCertStores(): List {
- val certD = PGPainlessCertD.fileBased(InMemorySubkeyLookupFactory())
- val asStore = PGPCertificateStoreAdapter(certD)
- return listOf(asStore)
- }
- }
+ referenceTime: ReferenceTime = ReferenceTime.now()):
+ this(network,trustRoots, gossip,certificationNetwork, trustAmount.amount, referenceTime)
override fun authenticate(arguments: AuthenticateAPI.Arguments): AuthenticateAPI.Result {
TODO("Not yet implemented")