1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-25 12:27:58 +01:00

Move the API definition to wot-dijkstra

This commit is contained in:
Paul Schaub 2023-07-07 15:41:17 +02:00
parent 3d8840116c
commit 8029d031bc
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
13 changed files with 64 additions and 39 deletions

View file

@ -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 This module contains a command line interface application that acts as a front-end for
[`pgpainless-wot`](../pgpainless-wot). [`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 ## Build

View file

@ -6,10 +6,11 @@ package org.pgpainless.wot.cli
import org.pgpainless.certificate_store.PGPainlessCertD import org.pgpainless.certificate_store.PGPainlessCertD
import org.pgpainless.util.DateUtil 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.cli.subcommands.*
import org.pgpainless.wot.dijkstra.sq.Fingerprint import org.pgpainless.wot.dijkstra.sq.Fingerprint
import org.pgpainless.wot.dijkstra.sq.ReferenceTime import org.pgpainless.wot.dijkstra.sq.ReferenceTime
import org.pgpainless.wot.dijkstra.sq.api.WoTAPI
import pgp.cert_d.PGPCertificateStoreAdapter import pgp.cert_d.PGPCertificateStoreAdapter
import pgp.cert_d.subkey_lookup.InMemorySubkeyLookupFactory import pgp.cert_d.subkey_lookup.InMemorySubkeyLookupFactory
import pgp.certificate_store.PGPCertificateStore import pgp.certificate_store.PGPCertificateStore
@ -19,6 +20,11 @@ import java.io.File
import java.util.concurrent.Callable import java.util.concurrent.Callable
import kotlin.system.exitProcess import kotlin.system.exitProcess
/**
* Command Line Interface for pgpainless-wot, modelled after the reference implementation "sq-wot".
*
* @see <a href="https://gitlab.com/sequoia-pgp/sequoia-wot/">Sequoia Web of Trust Reference Implementation</a>
*/
@Command(name = "pgpainless-wot", @Command(name = "pgpainless-wot",
subcommands = [ subcommands = [
AuthenticateCmd::class, AuthenticateCmd::class,
@ -110,8 +116,10 @@ class WotCLI: Callable<Int> {
val api: WoTAPI val api: WoTAPI
get() { get() {
val network = WebOfTrust(certificateStore)
.buildNetwork(referenceTime = referenceTime)
return WoTAPI( return WoTAPI(
certStores = listOf(certificateStore), network = network,
trustRoots = trustRoots, trustRoots = trustRoots,
gossip = false, gossip = false,
certificationNetwork = false, certificationNetwork = false,

View file

@ -4,7 +4,7 @@
package org.pgpainless.wot.cli.subcommands 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.cli.WotCLI
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
@ -15,18 +15,33 @@ import picocli.CommandLine.ParentCommand
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.concurrent.Callable import java.util.concurrent.Callable
/**
* Authenticate a binding between a certification and one of its user-ids.
*/
@Command(name = "authenticate") @Command(name = "authenticate")
class AuthenticateCmd: Callable<Int> { class AuthenticateCmd: Callable<Int> {
/**
* Parent command to acquire global options from.
*/
@ParentCommand @ParentCommand
lateinit var parent: WotCLI lateinit var parent: WotCLI
/**
* Fingerprint of the certificate.
*/
@Parameters(index = "0") @Parameters(index = "0")
lateinit var fingerprint: String lateinit var fingerprint: String
/**
* User-ID to authenticate.
*/
@Parameters(index = "1") @Parameters(index = "1")
lateinit var userId: String 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."]) @CommandLine.Option(names = ["--email"], description = ["Consider all user-IDs that contain the given email address."])
var email = false var email = false
@ -46,6 +61,9 @@ class AuthenticateCmd: Callable<Int> {
return 0 return 0
} }
/**
* Format the [AuthenticateAPI.Result] as a [String] which can be printed to standard out.
*/
internal fun formatResult(result: AuthenticateAPI.Result): String { internal fun formatResult(result: AuthenticateAPI.Result): String {
if (result.percentage < 100) { if (result.percentage < 100) {
return "No paths found." return "No paths found."

View file

@ -1,7 +1,7 @@
package org.pgpainless.wot.cli.subcommands package org.pgpainless.wot.cli.subcommands
import org.junit.jupiter.api.Test 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 org.pgpainless.wot.dijkstra.sq.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import kotlin.test.assertEquals import kotlin.test.assertEquals

View file

@ -43,14 +43,23 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
* *
* @param certificateDirectory PGP-Certificate-Directory instance * @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 certificates = getAllCertificatesFromTheStore()
val networkFactory = PGPNetworkFactory.fromCertificates(certificates, policy, referenceTime) val networkFactory = PGPNetworkFactory.fromCertificates(certificates, policy, referenceTime)
return networkFactory.buildNetwork() 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<Certificate> { private fun getAllCertificatesFromTheStore(): Sequence<Certificate> {
var trustRoot: Certificate? = null var trustRoot: Certificate? = null
try { try {
@ -157,7 +166,8 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
while (userIds.hasNext()) { while (userIds.hasNext()) {
val userId = userIds.next() val userId = userIds.next()
// There are potentially multiple certifications per user-ID // There are potentially multiple certifications per user-ID
val userIdSigs = SignatureUtils.get3rdPartyCertificationsFor(userId, validatedTargetKeyRing) val userIdSigs = SignatureUtils.get3rdPartyCertificationsFor(
userId, validatedTargetKeyRing)
userIdSigs.forEach { userIdSigs.forEach {
processCertificationOnUserId(targetPrimaryKey, target, userId, it) processCertificationOnUserId(targetPrimaryKey, target, userId, it)
} }
@ -194,7 +204,8 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
} }
} catch (e: SignatureValidationException) { } catch (e: SignatureValidationException) {
val targetFingerprint = OpenPgpFingerprint.of(targetPrimaryKey) 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<KeyRingInfo> { referenceTime: ReferenceTime): List<KeyRingInfo> {
return certificates return certificates
.mapNotNull { .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) } .map { KeyRingInfo(it, policy, referenceTime.timestamp) }
.toList() .toList()

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // 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.Fingerprint
import org.pgpainless.wot.dijkstra.sq.Paths import org.pgpainless.wot.dijkstra.sq.Paths

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.api package org.pgpainless.wot.dijkstra.sq.api
/** /**
* Enum for different levels of Trust. * Enum for different levels of Trust.

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.cli.subcommands package org.pgpainless.wot.dijkstra.sq.api
/** /**
* Enum listing possible output formats. * Enum listing possible output formats.

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // 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.Fingerprint
import org.pgpainless.wot.dijkstra.sq.Paths import org.pgpainless.wot.dijkstra.sq.Paths

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // 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 import org.pgpainless.wot.dijkstra.sq.Paths

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // 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 import org.pgpainless.wot.dijkstra.sq.Paths

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // 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.Fingerprint

View file

@ -2,20 +2,16 @@
// //
// SPDX-License-Identifier: Apache-2.0 // 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.Fingerprint
import org.pgpainless.wot.dijkstra.sq.Network
import org.pgpainless.wot.dijkstra.sq.ReferenceTime 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. * 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 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
@ -24,35 +20,24 @@ import pgp.certificate_store.PGPCertificateStore
* @param knownNotationRegistry registry of known notations * @param knownNotationRegistry registry of known notations
*/ */
class WoTAPI( class WoTAPI(
val certStores: List<PGPCertificateStore> = getDefaultCertStores(), val network: Network,
val trustRoots: List<Fingerprint>, val trustRoots: List<Fingerprint>,
val gossip: Boolean = false, val gossip: Boolean = false,
val certificationNetwork: Boolean = false, val certificationNetwork: Boolean = false,
val trustAmount: Int = AuthenticationLevel.Fully.amount, val trustAmount: Int = AuthenticationLevel.Fully.amount,
val referenceTime: ReferenceTime = ReferenceTime.now(), val referenceTime: ReferenceTime = ReferenceTime.now()
val knownNotationRegistry: NotationRegistry = NotationRegistry()
): AuthenticateAPI, IdentifyAPI, ListAPI, LookupAPI, PathAPI { ): AuthenticateAPI, IdentifyAPI, ListAPI, LookupAPI, PathAPI {
/** /**
* Secondary constructor, taking an [AuthenticationLevel] instead of an [Int]. * Secondary constructor, taking an [AuthenticationLevel] instead of an [Int].
*/ */
constructor(certStores: List<PGPCertificateStore> = getDefaultCertStores(), constructor(network: Network,
trustRoots: List<Fingerprint>, trustRoots: List<Fingerprint>,
gossip: Boolean = false, gossip: Boolean = false,
certificationNetwork: Boolean = false, certificationNetwork: Boolean = false,
trustAmount: AuthenticationLevel = AuthenticationLevel.Fully, trustAmount: AuthenticationLevel = AuthenticationLevel.Fully,
referenceTime: ReferenceTime = ReferenceTime.now(), referenceTime: ReferenceTime = ReferenceTime.now()):
knownNotationRegistry: NotationRegistry = NotationRegistry()): this(network,trustRoots, gossip,certificationNetwork, trustAmount.amount, referenceTime)
this(certStores,trustRoots, gossip,certificationNetwork, trustAmount.amount, referenceTime, knownNotationRegistry)
companion object {
@JvmStatic
fun getDefaultCertStores(): List<PGPCertificateStore> {
val certD = PGPainlessCertD.fileBased(InMemorySubkeyLookupFactory())
val asStore = PGPCertificateStoreAdapter(certD)
return listOf(asStore)
}
}
override fun authenticate(arguments: AuthenticateAPI.Arguments): AuthenticateAPI.Result { override fun authenticate(arguments: AuthenticateAPI.Arguments): AuthenticateAPI.Result {
TODO("Not yet implemented") TODO("Not yet implemented")