mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-25 04:17:59 +01:00
Playing around with mixed opinionated/unopinionated API
This commit is contained in:
parent
251f30fae8
commit
6703a514c8
3 changed files with 287 additions and 6 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue