From a5d592a1029a6ecb1630dff5f54bfde48631a6d5 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 21 Jan 2022 00:11:17 +0100 Subject: [PATCH] Wip --- .../pgpainless/key/storage/CertDStore.java | 75 +++++++++++++++++++ .../key/storage/CertificateStore.java | 24 ++++++ .../java/org/pgpainless/key/storage/Item.java | 28 +++++++ .../pgpainless/key/storage/MergeCallback.java | 23 ++++++ .../key/storage/CertDStoreTest.java | 17 +++++ 5 files changed, 167 insertions(+) create mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/storage/CertDStore.java create mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/storage/CertificateStore.java create mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/storage/Item.java create mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/storage/MergeCallback.java create mode 100644 pgpainless-core/src/test/java/org/pgpainless/key/storage/CertDStoreTest.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/storage/CertDStore.java b/pgpainless-core/src/main/java/org/pgpainless/key/storage/CertDStore.java new file mode 100644 index 00000000..64780c52 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/key/storage/CertDStore.java @@ -0,0 +1,75 @@ +package org.pgpainless.key.storage; + +import java.io.File; + +public class CertDStore { + + private final File baseDirectory; + private static final String STORE_NAME = "pgp.cert.d"; + + public CertDStore() { + this(getDefaultBaseDir()); + } + + public CertDStore(File baseDirectory) { + this.baseDirectory = baseDirectory; + } + + public File fingerprintToPrefixDir(String fingerprint) { + String dirName = fingerprint.toLowerCase().substring(0, 2); + return new File(baseDirectory, dirName); + } + + public String fingerprintToCertFileName(String fingerprint) { + String certFileName = fingerprint.toLowerCase().substring(2); + return certFileName; + } + + public File fingerprintToCertFile(String fingerprint) { + File dir = fingerprintToPrefixDir(fingerprint); + File certFile = new File(dir, fingerprintToCertFileName(fingerprint)); + return certFile; + } + + public File getBaseDirectory() { + return baseDirectory; + } + + private static File getDefaultBaseDir() { + // Check for environment variable + String baseDirFromEnv = System.getenv("PGP_CERT_D"); + if (baseDirFromEnv != null) { + return new File(baseDirFromEnv); + } + + // return OS-specific default dir + String osName = System.getProperty("os.name", "generic") + .toLowerCase(); + return getDefaultBaseDirForOS(osName, File.separator); + } + + public static File getDefaultBaseDirForOS(String osName, String separator) { + if (osName.contains("win")) { + String appData = System.getenv("APPDATA"); + String roaming = appData + separator + "Roaming"; + return new File(roaming, STORE_NAME); + } + + if (osName.contains("nux")) { + String xdg_data_home = System.getenv("XDG_DATA_HOME"); + String rootPath = xdg_data_home; + if (xdg_data_home == null) { + rootPath = System.getProperty("user.home") + separator + ".local" + separator + "share"; + } + return new File(rootPath, STORE_NAME); + } + + if (osName.contains("mac")) { + String home = System.getenv("HOME"); + return new File(home + separator + "Library" + separator + "Application Support", STORE_NAME); + } + + throw new IllegalArgumentException("Unknown OS " + osName); + } + +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/storage/CertificateStore.java b/pgpainless-core/src/main/java/org/pgpainless/key/storage/CertificateStore.java new file mode 100644 index 00000000..f3c2b86d --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/key/storage/CertificateStore.java @@ -0,0 +1,24 @@ +package org.pgpainless.key.storage; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +public interface CertificateStore { + + Item get(String identifier) throws IOException; + + Item getIfChanged(String identifier, String tag) throws IOException; +< + Item insert(InputStream data, MergeCallback merge) throws IOException; + + Item tryInsert(InputStream data, MergeCallback merge) throws IOException; + + Item insertSpecial(String specialName, InputStream data, MergeCallback merge) throws IOException; + + Item tryInsertSpecial(String specialName, InputStream data, MergeCallback merge) throws IOException; + + Iterator items(); + + Iterator fingerprints(); +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/storage/Item.java b/pgpainless-core/src/main/java/org/pgpainless/key/storage/Item.java new file mode 100644 index 00000000..15113ba5 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/key/storage/Item.java @@ -0,0 +1,28 @@ +package org.pgpainless.key.storage; + +import java.io.InputStream; + +public class Item { + + private final String fingerprint; + private final String tag; + private final InputStream data; + + public Item(String fingerprint, String tag, InputStream data) { + this.fingerprint = fingerprint; + this.tag = tag; + this.data = data; + } + + public String getFingerprint() { + return fingerprint; + } + + public String getTag() { + return tag; + } + + public InputStream getData() { + return data; + } +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/storage/MergeCallback.java b/pgpainless-core/src/main/java/org/pgpainless/key/storage/MergeCallback.java new file mode 100644 index 00000000..f9cb7e1b --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/key/storage/MergeCallback.java @@ -0,0 +1,23 @@ +package org.pgpainless.key.storage; + +import javax.annotation.Nullable; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Merge a given certificate (update) with an existing certificate. + */ +public interface MergeCallback { + + /** + * Merge the given certificate data with the existing certificate and return the result. + * + * If no existing certificate is found (i.e. existing is null), this method returns the binary representation of data. + * + * @param data input stream containing the certificate + * @param existing optional input stream containing an already existing copy of the certificate + * @return output stream containing the binary representation of the merged certificate + */ + OutputStream merge(InputStream data, @Nullable InputStream existing); + +} diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/storage/CertDStoreTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/storage/CertDStoreTest.java new file mode 100644 index 00000000..71285152 --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/key/storage/CertDStoreTest.java @@ -0,0 +1,17 @@ +package org.pgpainless.key.storage; + +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CertDStoreTest { + + @Test + public void testGetDefaultBaseDir() { + CertDStore store = new CertDStore(); + File baseDir = store.getBaseDirectory(); + assertEquals("pgp.cert.d", baseDir.getName()); + } +}