mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-24 11:57:59 +01:00
Move the API definition to wot-dijkstra
This commit is contained in:
parent
d7bcfeedb1
commit
a0d206bb15
13 changed files with 64 additions and 39 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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."
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
Loading…
Reference in a new issue