diff --git a/pgp-cert-d-cli/build.gradle b/pgp-cert-d-cli/build.gradle new file mode 100644 index 00000000..96b652ab --- /dev/null +++ b/pgp-cert-d-cli/build.gradle @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2021 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +plugins { + id 'application' +} + +group 'org.pgpainless' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + + // Logging + testImplementation "ch.qos.logback:logback-classic:$logbackVersion" + + implementation project(":pgpainless-cert-d") + + // picocli for cli + implementation "info.picocli:picocli:4.6.2" +} + +test { + useJUnitPlatform() +} + +mainClassName = 'pgp.cert_d.cli.PGPCertDCli' + +jar { + manifest { + attributes 'Main-Class': "$mainClassName" + } + + duplicatesStrategy(DuplicatesStrategy.EXCLUDE) + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } { + exclude "META-INF/*.SF" + exclude "META-INF/*.DSA" + exclude "META-INF/*.RSA" + } +} + diff --git a/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/PGPCertDCli.java b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/PGPCertDCli.java new file mode 100644 index 00000000..41d1b9cc --- /dev/null +++ b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/PGPCertDCli.java @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.cert_d.cli; + +import org.pgpainless.certificate_store.CertificateCertificateReader; +import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter; +import pgp.cert_d.SharedPGPCertificateDirectoryImpl; +import pgp.cert_d.cli.commands.Get; +import pgp.cert_d.cli.commands.Insert; +import pgp.cert_d.cli.commands.PrintDirectory; +import pgp.cert_d.exception.NotAStoreException; +import pgp.certificate_store.CertificateStore; +import picocli.CommandLine; + +import java.io.File; + +@CommandLine.Command( + subcommands = { + Insert.class, + PrintDirectory.class, + Get.class, + } +) +public class PGPCertDCli { + + @CommandLine.Option(names = "--base-directory", paramLabel = "DIRECTORY", description = "Overwrite the default certificate directory") + File baseDirectory; + + private static CertificateStore certificateStore; + private static String baseDir; + + private int executionStrategy(CommandLine.ParseResult parseResult) { + try { + initStore(); + } catch (NotAStoreException e) { + return -1; + } + return new CommandLine.RunLast().execute(parseResult); + } + + private void initStore() throws NotAStoreException { + SharedPGPCertificateDirectoryImpl certificateDirectory; + if (baseDirectory != null) { + certificateDirectory = new SharedPGPCertificateDirectoryImpl( + baseDirectory, + new CertificateCertificateReader()); + } else { + certificateDirectory = new SharedPGPCertificateDirectoryImpl( + new CertificateCertificateReader()); + } + baseDir = certificateDirectory.getBaseDirectory().getAbsolutePath(); + certificateStore = new SharedPGPCertificateDirectoryAdapter(certificateDirectory); + } + + public static void main(String[] args) { + PGPCertDCli cli = new PGPCertDCli(); + new CommandLine(cli) + .setExecutionStrategy(parserResult -> cli.executionStrategy(parserResult)) + .execute(args); + } + + public static CertificateStore getCertificateDirectory() { + return certificateStore; + } + + public static String getBaseDir() { + return baseDir; + } +} diff --git a/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Get.java b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Get.java new file mode 100644 index 00000000..2cc5dab0 --- /dev/null +++ b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Get.java @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.cert_d.cli.commands; + +import java.io.IOException; + +import org.bouncycastle.util.io.Streams; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pgp.cert_d.cli.PGPCertDCli; +import pgp.certificate_store.Certificate; +import picocli.CommandLine; + +@CommandLine.Command(name = "get", + description = "Retrieve certificates from the store") +public class Get implements Runnable { + + private static final Logger LOGGER = LoggerFactory.getLogger(Get.class); + + @CommandLine.Parameters( + paramLabel = "IDENTIFIER", + arity = "1", + description = "Certificate identifier (fingerprint or special name)" + ) + String identifer; + + @Override + public void run() { + try { + Certificate certificate = PGPCertDCli.getCertificateDirectory() + .getCertificate(identifer); + if (certificate == null) { + return; + } + Streams.pipeAll(certificate.getInputStream(), System.out); + } catch (IOException e) { + LOGGER.info("IO Error", e); + System.exit(-1); + } + } +} diff --git a/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java new file mode 100644 index 00000000..54b6f32f --- /dev/null +++ b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.cert_d.cli.commands; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pgp.cert_d.cli.PGPCertDCli; +import pgp.certificate_store.Certificate; +import pgp.certificate_store.MergeCallback; +import picocli.CommandLine; + +@CommandLine.Command(name = "insert", + description = "Insert or update a certificate") +public class Insert implements Runnable { + + private static final Logger LOGGER = LoggerFactory.getLogger(Insert.class); + + @Override + public void run() { + try { + Certificate certificate = PGPCertDCli.getCertificateDirectory().insertCertificate(System.in, new MergeCallback() { + @Override + public Certificate merge(Certificate data, Certificate existing) { + return data; + } + }); + // CHECKSTYLE:OFF + System.out.println(certificate.getFingerprint()); + // CHECKSTYLE:ON + } catch (IOException e) { + LOGGER.info("IO-Error", e); + System.exit(-1); + } catch (InterruptedException e) { + LOGGER.info("Thread interrupted.", e); + System.exit(-1); + } + } +} diff --git a/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/PrintDirectory.java b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/PrintDirectory.java new file mode 100644 index 00000000..c5e82e7f --- /dev/null +++ b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/PrintDirectory.java @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.cert_d.cli.commands; + +import pgp.cert_d.cli.PGPCertDCli; +import picocli.CommandLine; + +@CommandLine.Command( + name = "print-directory", + description = "Print the location of the certificate directory" +) +public class PrintDirectory implements Runnable { + + @Override + public void run() { + // CHECKSTYLE:OFF + System.out.println(PGPCertDCli.getBaseDir()); + // CHECKSTYLE:ON + } +} diff --git a/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/package-info.java b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/package-info.java new file mode 100644 index 00000000..1a76e605 --- /dev/null +++ b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/package-info.java @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2018 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +/** + * Subcommands. + */ +package pgp.cert_d.cli.commands; diff --git a/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/package-info.java b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/package-info.java new file mode 100644 index 00000000..c66aad58 --- /dev/null +++ b/pgp-cert-d-cli/src/main/java/pgp/cert_d/cli/package-info.java @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2018 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +/** + * Command Line Interface for the Shared PGP Certificate Directory. + */ +package pgp.cert_d.cli; diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/SharedPGPCertificateDirectoryAdapter.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/SharedPGPCertificateDirectoryAdapter.java similarity index 97% rename from pgp-cert-d-java/src/main/java/pgp/cert_d/SharedPGPCertificateDirectoryAdapter.java rename to pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/SharedPGPCertificateDirectoryAdapter.java index b659f366..686f12b4 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/SharedPGPCertificateDirectoryAdapter.java +++ b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/SharedPGPCertificateDirectoryAdapter.java @@ -2,12 +2,14 @@ // // SPDX-License-Identifier: Apache-2.0 -package pgp.cert_d; +package org.pgpainless.certificate_store; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; +import pgp.cert_d.SharedPGPCertificateDirectory; +import pgp.cert_d.SpecialName; import pgp.cert_d.exception.BadDataException; import pgp.cert_d.exception.BadNameException; import pgp.certificate_store.Certificate; diff --git a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/package-info.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/package-info.java new file mode 100644 index 00000000..96d0094f --- /dev/null +++ b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/package-info.java @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2018 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +/** + * PGPainless + Certificate Store. + */ +package org.pgpainless.certificate_store; diff --git a/settings.gradle b/settings.gradle index 954cb07f..6d1f5e29 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,5 +9,6 @@ include 'pgpainless-core', 'pgpainless-cli', 'pgpainless-cert-d', 'pgp-certificate-store', - 'pgp-cert-d-java' + 'pgp-cert-d-java', + 'pgp-cert-d-cli'