diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpKeyStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpKeyStore.java index 22174097e..24367c884 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpKeyStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpKeyStore.java @@ -43,6 +43,14 @@ public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore { protected Map publicKeys = new HashMap<>(); protected Map secretKeys = new HashMap<>(); + protected abstract PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner) throws IOException, PGPException; + + protected abstract void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys) throws IOException; + + protected abstract PGPSecretKeyRingCollection readSecretKeysOf(BareJid owner) throws IOException, PGPException; + + protected abstract void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys) throws IOException; + @Override public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException { PGPPublicKeyRingCollection keys = publicKeys.get(owner); diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpMetadataStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpMetadataStore.java index 8a49f136b..03158dbf1 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpMetadataStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpMetadataStore.java @@ -38,4 +38,14 @@ public abstract class AbstractOpenPgpMetadataStore implements OpenPgpMetadataSto } return fingerprints; } + + @Override + public void setAnnouncedFingerprintsOf(BareJid contact, Map data) throws IOException { + announcedFingerprints.put(contact, data); + writeAnnouncedFingerprintsOf(contact, data); + } + + protected abstract Map readAnnouncedFingerprintsOf(BareJid contact) throws IOException; + + protected abstract void writeAnnouncedFingerprintsOf(BareJid contact, Map metadata) throws IOException; } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpTrustStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpTrustStore.java new file mode 100644 index 000000000..b290b4bdd --- /dev/null +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/AbstractOpenPgpTrustStore.java @@ -0,0 +1,55 @@ +package org.jivesoftware.smackx.ox.v2.store; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; + +import org.jxmpp.jid.BareJid; + +public abstract class AbstractOpenPgpTrustStore implements OpenPgpTrustStore { + + private final Map> trustCache = new HashMap<>(); + + protected abstract Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException; + + protected abstract void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException; + + @Override + public Trust getTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException { + Trust trust; + Map trustMap = trustCache.get(owner); + + if (trustMap != null) { + trust = trustMap.get(fingerprint); + if (trust != null) { + return trust; + } + } else { + trustMap = new HashMap<>(); + trustCache.put(owner, trustMap); + } + + trust = readTrust(owner, fingerprint); + trustMap.put(fingerprint, trust); + + return trust; + } + + @Override + public void setTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException { + Map trustMap = trustCache.get(owner); + if (trust == null) { + trustMap = new HashMap<>(); + trustCache.put(owner, trustMap); + } + + if (trustMap.get(fingerprint) == trust) { + return; + } + + trustMap.put(fingerprint, trust); + writeTrust(owner, fingerprint, trust); + } +} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpKeyStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpKeyStore.java index 108ad4471..57d1fce1d 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpKeyStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpKeyStore.java @@ -32,16 +32,10 @@ import org.jxmpp.jid.BareJid; public interface OpenPgpKeyStore { - PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner) throws IOException, PGPException; - void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys) throws IOException; PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException; - PGPSecretKeyRingCollection readSecretKeysOf(BareJid owner) throws IOException, PGPException; - - void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys) throws IOException; - PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException; PGPPublicKeyRing getPublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpMetadataStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpMetadataStore.java index c28b2ea87..a02b49697 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpMetadataStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpMetadataStore.java @@ -21,7 +21,6 @@ import java.util.Date; import java.util.Map; import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.element.PublicKeysListElement; import org.jxmpp.jid.BareJid; @@ -29,9 +28,5 @@ public interface OpenPgpMetadataStore { Map getAnnouncedFingerprintsOf(BareJid contact) throws IOException; - Map readAnnouncedFingerprintsOf(BareJid contact) throws IOException; - - void writeAnnouncedFingerprintsOf(BareJid contact, PublicKeysListElement metadata) throws IOException; - - + void setAnnouncedFingerprintsOf(BareJid contact, Map data) throws IOException; } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpTrustStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpTrustStore.java index babb0c676..8edf18aa6 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpTrustStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/OpenPgpTrustStore.java @@ -16,15 +16,17 @@ */ package org.jivesoftware.smackx.ox.v2.store; +import java.io.IOException; + import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jxmpp.jid.BareJid; public interface OpenPgpTrustStore { - Trust getTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint); + Trust getTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException; - void setTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust); + void setTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException; enum Trust { trusted, diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpKeyStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpKeyStore.java index 52090f7fb..ca5488d91 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpKeyStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpKeyStore.java @@ -21,6 +21,7 @@ import static org.jivesoftware.smackx.ox.util.FileUtils.prepareFileOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; @@ -48,17 +49,41 @@ public class FileBasedOpenPgpKeyStore extends AbstractOpenPgpKeyStore { @Override public void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys) throws IOException { File file = getPublicKeyRingPath(owner); - OutputStream outputStream = prepareFileOutputStream(file); - publicKeys.encode(outputStream); - outputStream.close(); + OutputStream outputStream = null; + try { + outputStream = prepareFileOutputStream(file); + publicKeys.encode(outputStream); + outputStream.close(); + } catch (IOException e) { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException ignored) { + // Don't care + } + } + throw e; + } } @Override public void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys) throws IOException { File file = getSecretKeyRingPath(owner); - OutputStream outputStream = prepareFileOutputStream(file); - secretKeys.encode(outputStream); - outputStream.close(); + OutputStream outputStream = null; + try { + outputStream = prepareFileOutputStream(file); + secretKeys.encode(outputStream); + outputStream.close(); + } catch (IOException e) { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException ignored) { + // Don't care + } + } + throw e; + } } @Override @@ -69,7 +94,7 @@ public class FileBasedOpenPgpKeyStore extends AbstractOpenPgpKeyStore { FileInputStream inputStream; try { inputStream = prepareFileInputStream(file); - } catch (IOException e) { + } catch (FileNotFoundException e) { return null; } @@ -85,7 +110,7 @@ public class FileBasedOpenPgpKeyStore extends AbstractOpenPgpKeyStore { FileInputStream inputStream; try { inputStream = prepareFileInputStream(file); - } catch (IOException e) { + } catch (FileNotFoundException e) { return null; } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpMetadataStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpMetadataStore.java index caaaa31bb..5305bad4c 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpMetadataStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpMetadataStore.java @@ -29,7 +29,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.element.PublicKeysListElement; import org.jivesoftware.smackx.ox.util.Util; import org.jivesoftware.smackx.ox.v2.store.AbstractOpenPgpMetadataStore; @@ -55,15 +54,10 @@ public class FileBasedOpenPgpMetadataStore extends AbstractOpenPgpMetadataStore } @Override - public void writeAnnouncedFingerprintsOf(BareJid contact, PublicKeysListElement metadata) + public void writeAnnouncedFingerprintsOf(BareJid contact, Map metadata) throws IOException { File destination = getAnnouncedFingerprintsPath(contact); - Map fingerprintDateMap = new HashMap<>(); - for (OpenPgpV4Fingerprint fingerprint : metadata.getMetadata().keySet()) { - fingerprintDateMap.put(fingerprint, metadata.getMetadata().get(fingerprint).getDate()); - } - - writeFingerprintsAndDates(fingerprintDateMap, destination); + writeFingerprintsAndDates(metadata, destination); } private Map readFingerprintsAndDates(File source) throws IOException { @@ -120,6 +114,7 @@ public class FileBasedOpenPgpMetadataStore extends AbstractOpenPgpMetadataStore (date != null ? XmppDateTime.formatXEP0082Date(date) : XmppDateTime.formatXEP0082Date(new Date())); writer.write(line); } + writer.flush(); writer.close(); } catch (IOException e) { if (writer != null) { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpTrustStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpTrustStore.java index 8c77ce5e3..300eb44a2 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpTrustStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpTrustStore.java @@ -16,18 +16,24 @@ */ package org.jivesoftware.smackx.ox.v2.store.filebased; -import static org.jivesoftware.smackx.ox.util.FileUtils.prepareFileInputStream; - +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; +import java.nio.file.Files; +import java.util.logging.Level; +import java.util.logging.Logger; import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.v2.store.OpenPgpTrustStore; +import org.jivesoftware.smackx.ox.util.Util; +import org.jivesoftware.smackx.ox.v2.store.AbstractOpenPgpTrustStore; import org.jxmpp.jid.BareJid; -public class FileBasedOpenPgpTrustStore implements OpenPgpTrustStore { +public class FileBasedOpenPgpTrustStore extends AbstractOpenPgpTrustStore { + + private static final Logger LOGGER = Logger.getLogger(FileBasedOpenPgpTrustStore.class.getName()); private final File basePath; @@ -40,20 +46,72 @@ public class FileBasedOpenPgpTrustStore implements OpenPgpTrustStore { } @Override - public Trust getTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) { + protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException { File file = getTrustPath(owner, fingerprint); + BufferedReader reader = null; try { - InputStream inputStream = prepareFileInputStream(file); - return Trust.trusted; + reader = Files.newBufferedReader(file.toPath(), Util.UTF8); + Trust trust = null; + String line; int lineNr = 0; + while ((line = reader.readLine()) != null) { + lineNr++; + try { + trust = Trust.valueOf(line); + break; + } catch (IllegalArgumentException e) { + LOGGER.log(Level.WARNING, "Skipping invalid trust record in line " + lineNr + " of file " + + file.getAbsolutePath()); + } + } + reader.close(); + return trust != null ? trust : Trust.undecided; } catch (IOException e) { - return Trust.undecided; + if (reader != null) { + try { + reader.close(); + } catch (IOException ignored) { + // Don't care + } + } + + if (e instanceof FileNotFoundException) { + return Trust.undecided; + } + throw e; } } @Override - public void setTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) { + protected void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException { + File file = getTrustPath(owner, fingerprint); + if (!file.exists()) { + if (!file.createNewFile()) { + throw new IOException("Cannot create file " + file.getAbsolutePath()); + } + } else { + if (file.isDirectory()) { + throw new IOException("File " + file.getAbsolutePath() + " is a directory."); + } + } + + BufferedWriter writer = null; + try { + writer = Files.newBufferedWriter(file.toPath(), Util.UTF8); + writer.write(trust.toString()); + writer.flush(); + writer.close(); + } catch (IOException e) { + if (writer != null) { + try { + writer.close(); + } catch (IOException ignored) { + // Don't care + } + } + throw e; + } } private File getTrustPath(BareJid owner, OpenPgpV4Fingerprint fingerprint) {