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

Playing around with mixed opinionated/unopinionated API

This commit is contained in:
Paul Schaub 2024-02-05 14:08:16 +01:00
parent 251f30fae8
commit 6703a514c8
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
3 changed files with 287 additions and 6 deletions

View file

@ -36,7 +36,7 @@ open class GenerateOpenPgpKey(
) { ) {
/** Builder for OpenPGP secret keys. */ /** Builder for OpenPGP secret keys. */
abstract class OpenPgpKeyBuilder( abstract class OpinionatedPgpKeyBuilder(
protected val policy: Policy, protected val policy: Policy,
protected val referenceTime: Date, protected val referenceTime: Date,
protected val preferences: AlgorithmSuite protected val preferences: AlgorithmSuite
@ -67,13 +67,13 @@ open class GenerateOpenPgpKey(
* *
* @param keyType type of the primary key * @param keyType type of the primary key
* @param flags key flags for the primary key. Defaults to [KeyFlag.CERTIFY_OTHER]. * @param flags key flags for the primary key. Defaults to [KeyFlag.CERTIFY_OTHER].
* @return [V4GenerateOpenPgpKey] which can be further modified, e.g. add subkeys, user-ids etc. * @return [OpinionatedV4KeyBuilder] which can be further modified, e.g. add subkeys, user-ids etc.
*/ */
fun buildV4Key( fun buildV4Key(
keyType: KeyType, keyType: KeyType,
flags: List<KeyFlag>? = listOf(KeyFlag.CERTIFY_OTHER) flags: List<KeyFlag>? = listOf(KeyFlag.CERTIFY_OTHER)
): V4GenerateOpenPgpKey = ): OpinionatedV4KeyBuilder =
V4GenerateOpenPgpKey(keyType, flags, policy, referenceTime, preferences) OpinionatedV4KeyBuilder(keyType, flags, policy, referenceTime, preferences)
/** /**
* Builder for version 4 OpenPGP keys. * Builder for version 4 OpenPGP keys.
@ -84,14 +84,14 @@ open class GenerateOpenPgpKey(
* @param referenceTime reference time for key generation * @param referenceTime reference time for key generation
* @param preferences set of algorithm preferences and enabled features for the key * @param preferences set of algorithm preferences and enabled features for the key
*/ */
class V4GenerateOpenPgpKey class OpinionatedV4KeyBuilder
internal constructor( internal constructor(
primaryKeyType: KeyType, primaryKeyType: KeyType,
primaryFlags: List<KeyFlag>?, primaryFlags: List<KeyFlag>?,
policy: Policy, policy: Policy,
referenceTime: Date, referenceTime: Date,
preferences: AlgorithmSuite preferences: AlgorithmSuite
) : OpenPgpKeyBuilder(policy, referenceTime, preferences) { ) : OpinionatedPgpKeyBuilder(policy, referenceTime, preferences) {
init { init {
require(primaryKeyType.canCertify) { require(primaryKeyType.canCertify) {

View file

@ -0,0 +1,243 @@
package org.pgpainless.key.generation
import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.pgpainless.PGPainless
import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
import org.pgpainless.key.generation.type.xdh.XDHSpec
import org.pgpainless.policy.Policy
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import java.util.Date
fun buildV4(
policy: Policy = PGPainless.getPolicy(),
creationTime: Date = Date()
): OpinionatedPrimaryKeyBuilder.V4 {
return OpinionatedPrimaryKeyBuilder.V4(policy, creationTime)
}
fun buildV6(
policy: Policy = PGPainless.getPolicy(),
creationTime: Date = Date()
): OpinionatedPrimaryKeyBuilder.V6 {
return OpinionatedPrimaryKeyBuilder.V6(policy, creationTime)
}
fun test() {
// Unopinionated
buildV4()
.unopinionated()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), Date()) {
addDirectKeySignature(SelfSignatureSubpackets.nop())
addUserId("Alice <alice@pgpainless.org>")
}
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519), Date()) {
addBindingSignature(SelfSignatureSubpackets.nop())
}
.addSubkey(KeyType.XDH(XDHSpec._X25519), Date()) {
addBindingSignature(SelfSignatureSubpackets.nop())
}
.build()
// Opinionated
buildV4()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), Date()) {
addDirectKeySignature(SelfSignatureSubpackets.nop())
addUserId("Alice")
}
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519), Date()) {
//
}
.build()
// Unopinionated
buildV6()
.unopinionated()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), Date())
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519), Date())
.build()
// Opinionated
buildV6()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), Date())
.addSubkey(KeyType.XDH(XDHSpec._X25519), Date())
.build()
}
abstract class PrimaryKeyBuilder<B : KeyBuilder<B>>(
protected val creationTime: Date
) {
abstract fun setPrimaryKey(
type: KeyType,
creationTime: Date = this.creationTime,
function: ApplyToPrimaryKey.() -> Unit = {}): B
}
abstract class OpinionatedPrimaryKeyBuilder<B : Opinionated, U : Unopinionated>(
protected val policy: Policy,
creationTime: Date,
protected val unopinionated: UnopinionatedPrimaryKeyBuilder<U>
) : PrimaryKeyBuilder<Opinionated>(creationTime) {
fun unopinionated() = unopinionated
class V4(
policy: Policy,
creationTime: Date
) : OpinionatedPrimaryKeyBuilder<Opinionated.V4, Unopinionated.V4>(
policy,
creationTime,
UnopinionatedPrimaryKeyBuilder.V4(creationTime)
) {
override fun setPrimaryKey(
type: KeyType,
creationTime: Date,
function: ApplyToPrimaryKey.() -> Unit
): Opinionated.V4 {
return Opinionated.V4(
policy,
unopinionated.setPrimaryKey(type, creationTime, function) as Unopinionated.V4)
}
}
class V6(
policy: Policy,
creationTime: Date
) : OpinionatedPrimaryKeyBuilder<Opinionated.V6, Unopinionated.V6>(
policy,
creationTime,
UnopinionatedPrimaryKeyBuilder.V6(creationTime)
) {
override fun setPrimaryKey(
type: KeyType,
creationTime: Date,
function: ApplyToPrimaryKey.() -> Unit
): Opinionated.V6 {
return Opinionated.V6(
policy,
unopinionated.setPrimaryKey(type, creationTime, function) as Unopinionated.V6)
}
}
}
abstract class UnopinionatedPrimaryKeyBuilder<B : Unopinionated>(
creationTime: Date
) : PrimaryKeyBuilder<Unopinionated>(
creationTime
) {
class V4(creationTime: Date) : UnopinionatedPrimaryKeyBuilder<Unopinionated.V4>(creationTime) {
override fun setPrimaryKey(
type: KeyType,
creationTime: Date,
function: ApplyToPrimaryKey.() -> Unit
): Unopinionated.V4 {
return Unopinionated.V4()
}
}
class V6(creationTime: Date) : UnopinionatedPrimaryKeyBuilder<Unopinionated.V6>(creationTime) {
override fun setPrimaryKey(
type: KeyType,
creationTime: Date,
function: ApplyToPrimaryKey.() -> Unit
): Unopinionated.V6 {
return Unopinionated.V6()
}
}
}
interface KeyBuilder<B : KeyBuilder<B>> {
fun addSubkey(type: KeyType, creationTime: Date, function: ApplyToSubkey.() -> Unit = {}): B
fun addEncryptionSubkey(type: KeyType, creationTime: Date, function: ApplyToSubkey.() -> Unit = {}): B {
return addSubkey(type, creationTime, function)
}
fun build(): PGPSecretKeyRing
}
@JvmDefaultWithoutCompatibility
abstract class Opinionated(
protected val policy: Policy
) : KeyBuilder<Opinionated> {
abstract val unopinionated: Unopinionated
override fun build(): PGPSecretKeyRing = unopinionated.build()
class V4(
policy: Policy,
override val unopinionated: Unopinionated.V4 = Unopinionated.V4()
) : Opinionated(policy) {
override fun addSubkey(
type: KeyType,
creationTime: Date,
function: ApplyToSubkey.() -> Unit
): V4 = apply {
unopinionated.addSubkey(type, creationTime, function)
}
}
class V6(
policy: Policy,
override val unopinionated: Unopinionated.V6 = Unopinionated.V6()
) : Opinionated(policy) {
override fun addSubkey(
type: KeyType,
creationTime: Date,
function: ApplyToSubkey.() -> Unit
): V6 = apply {
unopinionated.addSubkey(type, creationTime, function)
}
}
}
@JvmDefaultWithoutCompatibility
abstract class Unopinionated : KeyBuilder<Unopinionated> {
class V4 : Unopinionated() {
override fun addSubkey(
type: KeyType,
creationTime: Date,
function: ApplyToSubkey.() -> Unit
): V4 = apply {
// Add key
}
override fun build(): PGPSecretKeyRing {
TODO("Not yet implemented")
}
}
class V6 : Unopinionated() {
override fun addSubkey(
type: KeyType,
creationTime: Date,
function: ApplyToSubkey.() -> Unit
): V6 = apply {
// Add Key
}
override fun build(): PGPSecretKeyRing {
TODO("Not yet implemented")
}
}
}
interface ApplyToPrimaryKey {
fun addUserId(userId: CharSequence)
fun addDirectKeySignature(subpacketsCallback: SelfSignatureSubpackets.Callback)
}
interface ApplyToSubkey {
fun addBindingSignature(subpacketsCallback: SelfSignatureSubpackets.Callback)
}

View file

@ -124,4 +124,42 @@ class GenerateOpenPgpKeyTest {
?: throw TestAbortedException( ?: throw TestAbortedException(
"Cannot read resource $resourceName: InputStream is null.") "Cannot read resource $resourceName: InputStream is null.")
} }
fun testAround() {
GenerateOpenPgpKey(Policy.getInstance())
.buildKeyV4()
.primaryKey(RSA, listOf(KeyFlag.CERTIFY_OTHER))
GenerateOpenPgpKey(Policy.getInstance())
.buildKey()
.unopinionated()
.apply {
primaryKey(RSA, creationTime)
.directKeySignature(callback)
}
}
interface TestInterface<T : TestInterface<T>> {
fun doSomething(): T
}
class LowerTestClass : TestInterface<LowerTestClass> {
override fun doSomething(): LowerTestClass {
TODO("Not yet implemented")
}
}
class TestClass : TestInterface<TestClass> {
override fun doSomething(): TestClass {
TODO("Not yet implemented")
}
fun lower(): LowerTestClass {
return LowerTestClass()
}
}
} }