diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/MergeCertsImpl.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/MergeCertsImpl.kt new file mode 100644 index 00000000..346fee84 --- /dev/null +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/MergeCertsImpl.kt @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2025 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.sop + +import org.bouncycastle.bcpg.KeyIdentifier +import org.bouncycastle.bcpg.PacketFormat +import org.bouncycastle.openpgp.api.OpenPGPCertificate +import org.pgpainless.PGPainless +import org.pgpainless.util.ArmoredOutputStreamFactory +import sop.Ready +import sop.operation.MergeCerts +import java.io.InputStream +import java.io.OutputStream + +class MergeCertsImpl(private val api: PGPainless) : MergeCerts { + + private var armor = true + private val baseCerts: MutableMap = mutableMapOf() + private val updateCerts: MutableList = mutableListOf() + + // from standard input + override fun baseCertificates(certs: InputStream): Ready { + return object : Ready() { + override fun writeTo(outputStream: OutputStream) { + val certList = api.readKey().parseCertificates(certs) + for (cert in certList) { + if (!baseCerts.contains(cert.keyIdentifier)) { + baseCerts[cert.keyIdentifier] = cert + } else { + val baseCert = baseCerts[cert.keyIdentifier]!! + baseCerts[cert.keyIdentifier] = api.mergeCertificate(baseCert, cert) + } + } + + for (update in updateCerts) { + if (baseCerts[update.keyIdentifier] == null) { + continue + } + + val baseCert = baseCerts[update.keyIdentifier]!! + baseCerts[update.keyIdentifier] = api.mergeCertificate(baseCert, update) + } + + val out = if (armor) { + ArmoredOutputStreamFactory.get(outputStream) + } else { + outputStream + } + + for (merged in baseCerts.values) { + out.write(merged.getEncoded(PacketFormat.CURRENT)) + } + + if (armor) { + out.close() + } + outputStream.close() + } + } + } + + override fun noArmor(): MergeCerts = apply { + armor = false + } + + // from command line + override fun updates(updateCerts: InputStream): MergeCerts = apply { + this.updateCerts.addAll(api.readKey().parseCertificates(updateCerts)) + } +} diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt index 4ad6bb26..c3ee703c 100644 --- a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt @@ -62,7 +62,7 @@ class SOPImpl( override fun listProfiles(): ListProfiles = ListProfilesImpl(api) - override fun mergeCerts(): MergeCerts? = null + override fun mergeCerts(): MergeCerts = MergeCertsImpl(api) override fun revokeKey(): RevokeKey = RevokeKeyImpl(api)