Use PGPPublicKeyRing.join(first, second) for proper MergeCallback

This commit is contained in:
Paul Schaub 2022-07-04 12:52:49 +02:00
parent adf9e534c4
commit 32f2bbede7
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
3 changed files with 90 additions and 25 deletions

View file

@ -0,0 +1,85 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.cert_d.cli.commands;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.pgpainless.PGPainless;
import org.pgpainless.certificate_store.CertificateFactory;
import org.pgpainless.key.OpenPgpFingerprint;
import pgp.certificate_store.Certificate;
import pgp.certificate_store.MergeCallback;
import java.io.IOException;
import java.util.Iterator;
public class DefaultMergeCallback implements MergeCallback {
@Override
public Certificate merge(Certificate data, Certificate existing) throws IOException {
try {
PGPPublicKeyRing existingCert = PGPainless.readKeyRing().publicKeyRing(existing.getInputStream());
PGPPublicKeyRing updatedCert = PGPainless.readKeyRing().publicKeyRing(data.getInputStream());
PGPPublicKeyRing mergedCert = PGPPublicKeyRing.join(existingCert, updatedCert);
printOutDifferences(existingCert, mergedCert);
return CertificateFactory.certificateFromPublicKeyRing(mergedCert);
} catch (PGPException e) {
throw new RuntimeException(e);
}
}
private void printOutDifferences(PGPPublicKeyRing existingCert, PGPPublicKeyRing mergedCert) {
int numSigsBefore = countSigs(existingCert);
int numSigsAfter = countSigs(mergedCert);
int newSigs = numSigsAfter - numSigsBefore;
int numUidsBefore = count(existingCert.getPublicKey().getUserIDs());
int numUidsAfter = count(mergedCert.getPublicKey().getUserIDs());
int newUids = numUidsAfter - numUidsBefore;
if (!existingCert.equals(mergedCert)) {
OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(mergedCert);
StringBuilder sb = new StringBuilder();
sb.append(String.format("Certificate %s has", fingerprint));
if (newSigs != 0) {
sb.append(String.format(" %d new signatures", newSigs));
}
if (newUids != 0) {
if (newSigs != 0) {
sb.append(" and");
}
sb.append(String.format(" %d new UIDs", newUids));
}
if (newSigs == 0 && newUids == 0) {
sb.append(" changed");
}
// In this case it is okay to print to stdout, since we are a CLI app
// CHECKSTYLE:OFF
System.out.println(sb);
// CHECKSTYLE:ON
}
}
private static int countSigs(PGPPublicKeyRing keys) {
int numSigs = 0;
for (PGPPublicKey key : keys) {
numSigs += count(key.getSignatures());
}
return numSigs;
}
// TODO: Use CollectionUtils.count() once available
private static int count(Iterator<?> iterator) {
int num = 0;
while (iterator.hasNext()) {
iterator.next();
num++;
}
return num;
}
}

View file

@ -4,8 +4,6 @@
package pgp.cert_d.cli.commands; package pgp.cert_d.cli.commands;
import java.io.IOException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import pgp.cert_d.cli.PGPCertDCli; import pgp.cert_d.cli.PGPCertDCli;
@ -14,27 +12,19 @@ import pgp.certificate_store.MergeCallback;
import pgp.certificate_store.exception.BadDataException; import pgp.certificate_store.exception.BadDataException;
import picocli.CommandLine; import picocli.CommandLine;
import java.io.IOException;
@CommandLine.Command(name = "import", @CommandLine.Command(name = "import",
description = "Import or update a certificate") description = "Import or update a certificate")
public class Import implements Runnable { public class Import implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(Import.class); private static final Logger LOGGER = LoggerFactory.getLogger(Import.class);
private final MergeCallback mergeCallback = new DefaultMergeCallback();
// TODO: Replace with proper merge callback
private final MergeCallback dummyMerge = new MergeCallback() {
@Override
public Certificate merge(Certificate data, Certificate existing) throws IOException {
return data;
}
};
@Override @Override
public void run() { public void run() {
try { try {
Certificate certificate = PGPCertDCli.getCertificateDirectory().insertCertificate(System.in, dummyMerge); Certificate certificate = PGPCertDCli.getCertificateDirectory().insertCertificate(System.in, mergeCallback);
// CHECKSTYLE:OFF
System.out.println(certificate.getFingerprint());
// CHECKSTYLE:ON
} catch (IOException e) { } catch (IOException e) {
LOGGER.error("IO-Error.", e); LOGGER.error("IO-Error.", e);
System.exit(-1); System.exit(-1);

View file

@ -24,14 +24,7 @@ import java.io.IOException;
public class MultiImport implements Runnable { public class MultiImport implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(MultiImport.class); private static final Logger LOGGER = LoggerFactory.getLogger(MultiImport.class);
private final MergeCallback dummyMerge = new DefaultMergeCallback();
// TODO: Replace with proper merge callback
private final MergeCallback dummyMerge = new MergeCallback() {
@Override
public Certificate merge(Certificate data, Certificate existing) throws IOException {
return data;
}
};
@Override @Override
public void run() { public void run() {
@ -41,9 +34,6 @@ public class MultiImport implements Runnable {
ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded()); ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded());
Certificate certificate = PGPCertDCli.getCertificateDirectory() Certificate certificate = PGPCertDCli.getCertificateDirectory()
.insertCertificate(certIn, dummyMerge); .insertCertificate(certIn, dummyMerge);
// CHECKSTYLE:OFF
System.out.println(certificate.getFingerprint());
// CHECKSTYLE:ON
} }
} catch (IOException e) { } catch (IOException e) {
LOGGER.error("IO-Error.", e); LOGGER.error("IO-Error.", e);