From 1bce378e6ddeeb3aa5842c1c1c41263aae09fe91 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 5 Aug 2019 08:28:42 +0200 Subject: [PATCH] smack-omemo*: Do not swallow IOException deep within the library Those exception are caused by I/O operations in the OmemoStore, which is now declaring that it throws those (since it is not uncommon for I/O operations to cause IOExceptions). After all, this is nicely demonstrated as this change is caused by switching with this commit to the Android API 19 compatible methods in FileBasedOmemoStore, which throw. The library can not decide what to do in case of those exceptions, hence it is sensible to expose them to the user. --- .../AbstractTwoUsersOmemoIntegrationTest.java | 3 +- .../smackx/omemo/OmemoMamDecryptionTest.java | 3 +- .../smackx/omemo/OmemoManagerSetupHelper.java | 7 +- .../omemo/ReadOnlyDeviceIntegrationTest.java | 6 +- .../omemo/signal/SignalOmemoRatchet.java | 3 +- .../signal/SignalOmemoStoreConnector.java | 62 ++++- .../smackx/omemo/CachingOmemoStore.java | 47 ++-- .../smackx/omemo/FileBasedOmemoStore.java | 232 +++--------------- .../smackx/omemo/OmemoManager.java | 71 ++++-- .../smackx/omemo/OmemoRatchet.java | 7 +- .../smackx/omemo/OmemoService.java | 65 +++-- .../jivesoftware/smackx/omemo/OmemoStore.java | 105 +++++--- ...OmemoCarbonCopyStanzaReceivedListener.java | 5 +- .../OmemoMessageStanzaReceivedListener.java | 4 +- .../omemo/util/OmemoMessageBuilder.java | 4 +- .../smackx/omemo/OmemoStoreTest.java | 6 +- 16 files changed, 299 insertions(+), 331 deletions(-) diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java index 4903fe72b..68cd5f30c 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java @@ -19,6 +19,7 @@ package org.jivesoftware.smackx.omemo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import java.io.IOException; import java.util.logging.Level; import org.jivesoftware.smack.SmackException; @@ -64,7 +65,7 @@ public abstract class AbstractTwoUsersOmemoIntegrationTest extends AbstractOmemo } @AfterClass - public void cleanUp() { + public void cleanUp() throws IOException { alice.stopStanzaAndPEPListeners(); bob.stopStanzaAndPEPListeners(); OmemoManagerSetupHelper.cleanUpPubSub(alice); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoMamDecryptionTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoMamDecryptionTest.java index 2c3017e74..b562db8f8 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoMamDecryptionTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoMamDecryptionTest.java @@ -18,6 +18,7 @@ package org.jivesoftware.smackx.omemo; import static org.junit.Assert.assertEquals; +import java.io.IOException; import java.util.List; import org.jivesoftware.smack.SmackException; @@ -50,7 +51,7 @@ public class OmemoMamDecryptionTest extends AbstractTwoUsersOmemoIntegrationTest @SmackIntegrationTest public void mamDecryptionTest() throws XMPPException.XMPPErrorException, SmackException.NotLoggedInException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, - CryptoFailedException, UndecidedOmemoIdentityException { + CryptoFailedException, UndecidedOmemoIdentityException, IOException { // Make sure, Bobs server stores messages in the archive MamManager bobsMamManager = MamManager.getInstanceFor(bob.getConnection()); bobsMamManager.enableMamForAllMessages(); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java index 83234924d..97fa93820 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.IOException; import java.util.HashMap; import org.jivesoftware.smack.SmackException; @@ -46,7 +47,7 @@ public class OmemoManagerSetupHelper { public static void trustAllIdentities(OmemoManager alice, OmemoManager bob) throws InterruptedException, SmackException.NotConnectedException, SmackException.NotLoggedInException, SmackException.NoResponseException, CannotEstablishOmemoSessionException, CorruptedOmemoKeyException, - XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException { + XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException, IOException { Roster roster = Roster.getInstanceFor(alice.getConnection()); if (alice.getOwnJid() != bob.getOwnJid() && @@ -66,7 +67,7 @@ public class OmemoManagerSetupHelper { public static void trustAllIdentitiesWithTests(OmemoManager alice, OmemoManager bob) throws InterruptedException, SmackException.NotConnectedException, SmackException.NotLoggedInException, SmackException.NoResponseException, CannotEstablishOmemoSessionException, CorruptedOmemoKeyException, - XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException { + XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException, IOException { alice.requestDeviceListUpdateFor(bob.getOwnJid()); HashMap fps1 = alice.getActiveFingerprints(bob.getOwnJid()); @@ -124,7 +125,7 @@ public class OmemoManagerSetupHelper { } } - public static void cleanUpPubSub(OmemoManager omemoManager) { + public static void cleanUpPubSub(OmemoManager omemoManager) throws IOException { PubSubManager pm = PubSubManager.getInstanceFor(omemoManager.getConnection(), omemoManager.getOwnJid()); try { omemoManager.requestDeviceListUpdateFor(omemoManager.getOwnJid()); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/ReadOnlyDeviceIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/ReadOnlyDeviceIntegrationTest.java index 3164d6668..815d4a032 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/ReadOnlyDeviceIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/ReadOnlyDeviceIntegrationTest.java @@ -20,6 +20,8 @@ import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; +import java.io.IOException; + import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException; @@ -37,7 +39,9 @@ public class ReadOnlyDeviceIntegrationTest extends AbstractTwoUsersOmemoIntegrat } @SmackIntegrationTest - public void test() throws InterruptedException, SmackException.NoResponseException, SmackException.NotLoggedInException, SmackException.NotConnectedException, CryptoFailedException, UndecidedOmemoIdentityException { + public void test() throws InterruptedException, SmackException.NoResponseException, + SmackException.NotLoggedInException, SmackException.NotConnectedException, CryptoFailedException, + UndecidedOmemoIdentityException, IOException { boolean prevIgnoreReadOnlyConf = OmemoConfiguration.getIgnoreReadOnlyDevices(); int prevMaxMessageCounter = OmemoConfiguration.getMaxReadOnlyMessageCount(); diff --git a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoRatchet.java b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoRatchet.java index de20f69a9..c219b6f14 100644 --- a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoRatchet.java +++ b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoRatchet.java @@ -20,6 +20,7 @@ */ package org.jivesoftware.smackx.omemo.signal; +import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -73,7 +74,7 @@ public class SignalOmemoRatchet @Override public byte[] doubleRatchetDecrypt(OmemoDevice sender, byte[] encryptedKey) throws CorruptedOmemoKeyException, NoRawSessionException, CryptoFailedException, - UntrustedOmemoIdentityException { + UntrustedOmemoIdentityException, IOException { SessionCipher cipher = getCipher(sender); byte[] decryptedKey; diff --git a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java index 0f607603a..1aae64856 100644 --- a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java +++ b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java @@ -20,6 +20,7 @@ */ package org.jivesoftware.smackx.omemo.signal; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.TreeMap; @@ -79,7 +80,7 @@ public class SignalOmemoStoreConnector public IdentityKeyPair getIdentityKeyPair() { try { return omemoStore.loadOmemoIdentityKeyPair(getOurDevice()); - } catch (CorruptedOmemoKeyException e) { + } catch (CorruptedOmemoKeyException | IOException e) { LOGGER.log(Level.SEVERE, "IdentityKeyPair seems to be invalid.", e); return null; } @@ -103,7 +104,11 @@ public class SignalOmemoStoreConnector throw new AssertionError(e); } - omemoStore.storeOmemoIdentityKey(getOurDevice(), device, identityKey); + try { + omemoStore.storeOmemoIdentityKey(getOurDevice(), device, identityKey); + } catch (IOException e) { + throw new IllegalStateException(e); + } return true; } @@ -118,7 +123,12 @@ public class SignalOmemoStoreConnector @Override public PreKeyRecord loadPreKey(int i) throws InvalidKeyIdException { - PreKeyRecord preKey = omemoStore.loadOmemoPreKey(getOurDevice(), i); + PreKeyRecord preKey; + try { + preKey = omemoStore.loadOmemoPreKey(getOurDevice(), i); + } catch (IOException e) { + throw new IllegalStateException(e); + } if (preKey == null) { throw new InvalidKeyIdException("No PreKey with Id " + i + " found."); @@ -129,7 +139,11 @@ public class SignalOmemoStoreConnector @Override public void storePreKey(int i, PreKeyRecord preKeyRecord) { - omemoStore.storeOmemoPreKey(getOurDevice(), i, preKeyRecord); + try { + omemoStore.storeOmemoPreKey(getOurDevice(), i, preKeyRecord); + } catch (IOException e) { + throw new IllegalStateException(e); + } } @Override @@ -155,7 +169,12 @@ public class SignalOmemoStoreConnector throw new AssertionError(e); } - SessionRecord record = omemoStore.loadRawSession(getOurDevice(), device); + SessionRecord record; + try { + record = omemoStore.loadRawSession(getOurDevice(), device); + } catch (IOException e) { + throw new IllegalStateException(e); + } if (record != null) { return record; @@ -173,7 +192,11 @@ public class SignalOmemoStoreConnector throw new AssertionError(e); } - return new ArrayList<>(omemoStore.loadAllRawSessionsOf(getOurDevice(), jid).keySet()); + try { + return new ArrayList<>(omemoStore.loadAllRawSessionsOf(getOurDevice(), jid).keySet()); + } catch (IOException e) { + throw new IllegalStateException(e); + } } @Override @@ -185,7 +208,11 @@ public class SignalOmemoStoreConnector throw new AssertionError(e); } - omemoStore.storeRawSession(getOurDevice(), device, sessionRecord); + try { + omemoStore.storeRawSession(getOurDevice(), device, sessionRecord); + } catch (IOException e) { + throw new IllegalStateException(e); + } } @Override @@ -226,7 +253,12 @@ public class SignalOmemoStoreConnector @Override public SignedPreKeyRecord loadSignedPreKey(int i) throws InvalidKeyIdException { - SignedPreKeyRecord signedPreKeyRecord = omemoStore.loadOmemoSignedPreKey(getOurDevice(), i); + SignedPreKeyRecord signedPreKeyRecord; + try { + signedPreKeyRecord = omemoStore.loadOmemoSignedPreKey(getOurDevice(), i); + } catch (IOException e) { + throw new IllegalStateException(e); + } if (signedPreKeyRecord == null) { throw new InvalidKeyIdException("No signed preKey with id " + i + " found."); } @@ -236,14 +268,22 @@ public class SignalOmemoStoreConnector @Override public List loadSignedPreKeys() { - TreeMap signedPreKeyRecordHashMap = - omemoStore.loadOmemoSignedPreKeys(getOurDevice()); + TreeMap signedPreKeyRecordHashMap; + try { + signedPreKeyRecordHashMap = omemoStore.loadOmemoSignedPreKeys(getOurDevice()); + } catch (IOException e) { + throw new IllegalStateException(e); + } return new ArrayList<>(signedPreKeyRecordHashMap.values()); } @Override public void storeSignedPreKey(int i, SignedPreKeyRecord signedPreKeyRecord) { - omemoStore.storeOmemoSignedPreKey(getOurDevice(), i, signedPreKeyRecord); + try { + omemoStore.storeOmemoSignedPreKey(getOurDevice(), i, signedPreKeyRecord); + } catch (IOException e) { + throw new IllegalStateException(e); + } } @Override diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/CachingOmemoStore.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/CachingOmemoStore.java index 7ab0bcde6..d83984e6c 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/CachingOmemoStore.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/CachingOmemoStore.java @@ -16,6 +16,7 @@ */ package org.jivesoftware.smackx.omemo; +import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.SortedSet; @@ -80,7 +81,7 @@ public class CachingOmemoStore loadOmemoPreKeys(OmemoDevice userDevice) { + public TreeMap loadOmemoPreKeys(OmemoDevice userDevice) throws IOException { TreeMap preKeys = getCache(userDevice).preKeys; if (preKeys.isEmpty() && persistent != null) { @@ -272,7 +273,7 @@ public class CachingOmemoStore loadOmemoSignedPreKeys(OmemoDevice userDevice) { + public TreeMap loadOmemoSignedPreKeys(OmemoDevice userDevice) throws IOException { TreeMap sigPreKeys = getCache(userDevice).signedPreKeys; if (sigPreKeys.isEmpty() && persistent != null) { @@ -299,7 +300,7 @@ public class CachingOmemoStore contactSessions = getCache(userDevice).sessions.get(contactsDevice.getJid()); if (contactSessions == null) { contactSessions = new HashMap<>(); @@ -334,7 +335,7 @@ public class CachingOmemoStore loadAllRawSessionsOf(OmemoDevice userDevice, BareJid contact) { + public HashMap loadAllRawSessionsOf(OmemoDevice userDevice, BareJid contact) throws IOException { HashMap sessions = getCache(userDevice).sessions.get(contact); if (sessions == null) { sessions = new HashMap<>(); @@ -349,7 +350,7 @@ public class CachingOmemoStore sessions = getCache(userDevice).sessions.get(contactsDevicece.getJid()); if (sessions == null) { sessions = new HashMap<>(); @@ -391,7 +392,7 @@ public class CachingOmemoStore loadOmemoPreKeys(OmemoDevice userDevice) { + public TreeMap loadOmemoPreKeys(OmemoDevice userDevice) throws IOException { File preKeyDirectory = hierarchy.getPreKeysDirectory(userDevice); TreeMap preKeys = new TreeMap<>(); @@ -221,7 +219,7 @@ public abstract class FileBasedOmemoStore loadOmemoSignedPreKeys(OmemoDevice userDevice) { + public TreeMap loadOmemoSignedPreKeys(OmemoDevice userDevice) throws IOException { File signedPreKeysDirectory = hierarchy.getSignedPreKeysDirectory(userDevice); TreeMap signedPreKeys = new TreeMap<>(); @@ -263,7 +261,7 @@ public abstract class FileBasedOmemoStore loadAllRawSessionsOf(OmemoDevice userDevice, BareJid contact) { + public HashMap loadAllRawSessionsOf(OmemoDevice userDevice, BareJid contact) throws IOException { File contactsDirectory = hierarchy.getContactsDir(userDevice, contact); HashMap sessions = new HashMap<>(); String[] devices = contactsDirectory.list(); @@ -322,7 +320,7 @@ public abstract class FileBasedOmemoStore integers = readIntegers(messageCounterFile); @@ -375,7 +373,7 @@ public abstract class FileBasedOmemoStore integers) { - if (target == null) { - LOGGER.log(Level.WARNING, "Could not write integers to null-path."); - return; - } - - DataOutputStream out = null; - - try { - out = new DataOutputStream(new FileOutputStream(target)); - for (int i : integers) { - out.writeInt(i); - } - - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Could not write integers to file.", e); - } finally { - CloseableUtil.maybeClose(out, LOGGER); - } - } - - private static Set readIntegers(File target) { - if (target == null) { - LOGGER.log(Level.WARNING, "Could not read integers from null-path."); - return null; - } - - HashSet integers = new HashSet<>(); - DataInputStream in = null; - - try { - in = new DataInputStream(new FileInputStream(target)); - - try { - while (true) { - integers.add(in.readInt()); - } - } catch (EOFException e) { - // Reached end of the list. - } - - } catch (FileNotFoundException e) { - integers = null; - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Could not read integers.", e); - } finally { - CloseableUtil.maybeClose(in, LOGGER); - } - - return integers; - } - - /** - * One day... *sheds a tear* - * TODO Use methods below once Smack's minimum Android API level is 19 or higher - */ - /* - private static void writeLong(File target, long i) - throws IOException - { + private static void writeLong(File target, long i) throws IOException { if (target == null) { throw new IOException("Could not write long to null-path."); } @@ -591,9 +430,7 @@ public abstract class FileBasedOmemoStore integers) - throws IOException - { + private static void writeIntegers(File target, Set integers) throws IOException { if (target == null) { throw new IOException("Could not write integers to null-path."); } @@ -657,9 +488,7 @@ public abstract class FileBasedOmemoStore readIntegers(File target) - throws IOException - { + private static Set readIntegers(File target) throws IOException { if (target == null) { throw new IOException("Could not write integers to null-path."); } @@ -682,7 +511,6 @@ public abstract class FileBasedOmemoStore getDevicesOf(BareJid contact) { + public Set getDevicesOf(BareJid contact) throws IOException { OmemoCachedDeviceList list = getOmemoService().getOmemoStoreBackend().loadCachedDeviceList(getOwnDevice(), contact); HashSet devices = new HashSet<>(); @@ -304,11 +307,12 @@ public final class OmemoManager extends Manager { * @throws SmackException.NotConnectedException * @throws SmackException.NoResponseException * @throws SmackException.NotLoggedInException + * @throws IOException */ public OmemoMessage.Sent encrypt(BareJid recipient, String message) throws CryptoFailedException, UndecidedOmemoIdentityException, InterruptedException, SmackException.NotConnectedException, - SmackException.NoResponseException, SmackException.NotLoggedInException { + SmackException.NoResponseException, SmackException.NotLoggedInException, IOException { synchronized (LOCK) { Set recipients = new HashSet<>(); recipients.add(recipient); @@ -328,11 +332,12 @@ public final class OmemoManager extends Manager { * @throws SmackException.NotConnectedException * @throws SmackException.NoResponseException * @throws SmackException.NotLoggedInException + * @throws IOException */ public OmemoMessage.Sent encrypt(Set recipients, String message) throws CryptoFailedException, UndecidedOmemoIdentityException, InterruptedException, SmackException.NotConnectedException, - SmackException.NoResponseException, SmackException.NotLoggedInException { + SmackException.NoResponseException, SmackException.NotLoggedInException, IOException { synchronized (LOCK) { LoggedInOmemoManager guard = new LoggedInOmemoManager(this); Set devices = getDevicesOf(getOwnJid()); @@ -357,12 +362,13 @@ public final class OmemoManager extends Manager { * @throws SmackException.NoResponseException * @throws NoOmemoSupportException When the muc doesn't support OMEMO. * @throws SmackException.NotLoggedInException + * @throws IOException */ public OmemoMessage.Sent encrypt(MultiUserChat muc, String message) throws UndecidedOmemoIdentityException, CryptoFailedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, NoOmemoSupportException, - SmackException.NotLoggedInException { + SmackException.NotLoggedInException, IOException { synchronized (LOCK) { if (!multiUserChatSupportsOmemo(muc)) { throw new NoOmemoSupportException(); @@ -390,10 +396,11 @@ public final class OmemoManager extends Manager { * @throws CorruptedOmemoKeyException if our or their key is corrupted * @throws NoRawSessionException if the message was not a preKeyMessage, but we had no session with the contact * @throws CryptoFailedException if decryption fails + * @throws IOException */ public OmemoMessage.Received decrypt(BareJid sender, OmemoElement omemoElement) throws SmackException.NotLoggedInException, CorruptedOmemoKeyException, NoRawSessionException, - CryptoFailedException { + CryptoFailedException, IOException { LoggedInOmemoManager managerGuard = new LoggedInOmemoManager(this); return getOmemoService().decryptMessage(managerGuard, sender, omemoElement); } @@ -404,9 +411,10 @@ public final class OmemoManager extends Manager { * @param mamQuery The MAM query * @return list of decrypted OmemoMessages * @throws SmackException.NotLoggedInException if the Manager is not authenticated. + * @throws IOException */ public List decryptMamQueryResult(MamManager.MamQuery mamQuery) - throws SmackException.NotLoggedInException { + throws SmackException.NotLoggedInException, IOException { return new ArrayList<>(getOmemoService().decryptMamQueryResult(new LoggedInOmemoManager(this), mamQuery)); } @@ -486,11 +494,12 @@ public final class OmemoManager extends Manager { * @throws SmackException.NoResponseException * @throws NoSuchAlgorithmException * @throws SmackException.NotConnectedException + * @throws IOException */ public void sendRatchetUpdateMessage(OmemoDevice recipient) throws SmackException.NotLoggedInException, CorruptedOmemoKeyException, InterruptedException, SmackException.NoResponseException, NoSuchAlgorithmException, SmackException.NotConnectedException, - CryptoFailedException, CannotEstablishOmemoSessionException { + CryptoFailedException, CannotEstablishOmemoSessionException, IOException { synchronized (LOCK) { Message message = new Message(); message.setFrom(getOwnJid()); @@ -516,10 +525,11 @@ public final class OmemoManager extends Manager { * @throws SmackException.NoResponseException * @throws PubSubException.NotALeafNodeException * @throws XMPPException.XMPPErrorException + * @throws IOException */ public boolean contactSupportsOmemo(BareJid contact) throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { + SmackException.NotConnectedException, SmackException.NoResponseException, IOException { synchronized (LOCK) { OmemoCachedDeviceList deviceList = getOmemoService().refreshDeviceList(connection(), getOwnDevice(), contact); return !deviceList.getActiveDevices().isEmpty(); @@ -569,9 +579,10 @@ public final class OmemoManager extends Manager { * @return fingerprint * @throws SmackException.NotLoggedInException if we don't know our bareJid yet. * @throws CorruptedOmemoKeyException if our identityKey is corrupted. + * @throws IOException */ public OmemoFingerprint getOwnFingerprint() - throws SmackException.NotLoggedInException, CorruptedOmemoKeyException { + throws SmackException.NotLoggedInException, CorruptedOmemoKeyException, IOException { synchronized (LOCK) { if (getOwnJid() == null) { throw new SmackException.NotLoggedInException(); @@ -591,11 +602,12 @@ public final class OmemoManager extends Manager { * @throws SmackException.NotConnectedException * @throws InterruptedException * @throws SmackException.NoResponseException + * @throws IOException */ public OmemoFingerprint getFingerprint(OmemoDevice device) throws CannotEstablishOmemoSessionException, SmackException.NotLoggedInException, CorruptedOmemoKeyException, SmackException.NotConnectedException, InterruptedException, - SmackException.NoResponseException { + SmackException.NoResponseException, IOException { synchronized (LOCK) { if (getOwnJid() == null) { throw new SmackException.NotLoggedInException(); @@ -621,11 +633,12 @@ public final class OmemoManager extends Manager { * @throws SmackException.NotConnectedException * @throws InterruptedException * @throws SmackException.NoResponseException + * @throws IOException */ public HashMap getActiveFingerprints(BareJid contact) throws SmackException.NotLoggedInException, CorruptedOmemoKeyException, CannotEstablishOmemoSessionException, SmackException.NotConnectedException, InterruptedException, - SmackException.NoResponseException { + SmackException.NoResponseException, IOException { synchronized (LOCK) { if (getOwnJid() == null) { throw new SmackException.NotLoggedInException(); @@ -692,10 +705,11 @@ public final class OmemoManager extends Manager { * @throws XMPPException.XMPPErrorException * @throws SmackException.NotConnectedException * @throws SmackException.NoResponseException + * @throws IOException */ public void requestDeviceListUpdateFor(BareJid contact) throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { + SmackException.NotConnectedException, SmackException.NoResponseException, IOException { synchronized (LOCK) { getOmemoService().refreshDeviceList(connection(), getOwnDevice(), contact); } @@ -709,10 +723,11 @@ public final class OmemoManager extends Manager { * @throws XMPPException.XMPPErrorException * @throws SmackException.NotConnectedException * @throws SmackException.NoResponseException + * @throws IOException */ public void purgeDeviceList() throws SmackException.NotLoggedInException, InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { + SmackException.NotConnectedException, SmackException.NoResponseException, IOException { synchronized (LOCK) { getOmemoService().purgeDeviceList(new LoggedInOmemoManager(this)); } @@ -729,10 +744,11 @@ public final class OmemoManager extends Manager { * @throws SmackException.NotConnectedException XMPP error * @throws SmackException.NoResponseException XMPP error * @throws SmackException.NotLoggedInException + * @throws IOException */ public void rotateSignedPreKey() throws CorruptedOmemoKeyException, SmackException.NotLoggedInException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, IOException { synchronized (LOCK) { if (!connection().isAuthenticated()) { throw new SmackException.NotLoggedInException(); @@ -956,8 +972,8 @@ public final class OmemoManager extends Manager { try { getOmemoService().onOmemoMessageStanzaReceived(packet, new LoggedInOmemoManager(OmemoManager.this)); - } catch (SmackException.NotLoggedInException e) { - LOGGER.warning("Received OMEMO stanza while being offline: " + e); + } catch (SmackException.NotLoggedInException | IOException e) { + LOGGER.log(Level.SEVERE, "Exception while processing OMEMO stanza", e); } } }); @@ -979,8 +995,8 @@ public final class OmemoManager extends Manager { try { getOmemoService().onOmemoCarbonCopyReceived(direction, carbonCopy, wrappingMessage, new LoggedInOmemoManager(OmemoManager.this)); - } catch (SmackException.NotLoggedInException e) { - LOGGER.warning("Received OMEMO carbon copy while being offline: " + e); + } catch (SmackException.NotLoggedInException | IOException e) { + LOGGER.log(Level.SEVERE, "Exception while processing OMEMO stanza", e); } } } @@ -1018,14 +1034,23 @@ public final class OmemoManager extends Manager { } // Device List + OmemoCachedDeviceList deviceList; OmemoDeviceListElement receivedDeviceList = (OmemoDeviceListElement) payloadItem.getPayload(); - getOmemoService().getOmemoStoreBackend().mergeCachedDeviceList(getOwnDevice(), from, receivedDeviceList); + try { + getOmemoService().getOmemoStoreBackend().mergeCachedDeviceList(getOwnDevice(), from, + receivedDeviceList); - if (!from.asBareJid().equals(getOwnJid())) { + if (!from.asBareJid().equals(getOwnJid())) { + continue; + } + + deviceList = getOmemoService().cleanUpDeviceList(getOwnDevice()); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, + "IOException while processing OMEMO PEP device updates. Message: " + message, + e); continue; } - - OmemoCachedDeviceList deviceList = getOmemoService().cleanUpDeviceList(getOwnDevice()); final OmemoDeviceListElement_VAxolotl newDeviceList = new OmemoDeviceListElement_VAxolotl(deviceList); if (!newDeviceList.copyDeviceIds().equals(receivedDeviceList.copyDeviceIds())) { diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java index 28ffc50ef..7ad0f6b6e 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java @@ -16,6 +16,7 @@ */ package org.jivesoftware.smackx.omemo; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -65,10 +66,11 @@ public abstract class OmemoRatchet decryptExceptions = new ArrayList<>(); diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java index 91eb51034..1130e63fc 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java @@ -19,6 +19,7 @@ package org.jivesoftware.smackx.omemo; import static org.jivesoftware.smackx.omemo.util.OmemoConstants.Crypto.KEYLENGTH; import static org.jivesoftware.smackx.omemo.util.OmemoConstants.Crypto.KEYTYPE; +import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -234,11 +235,12 @@ public abstract class OmemoService contactsDevices, @@ -341,7 +345,7 @@ public abstract class OmemoService contactsDevices, byte[] key, byte[] iv) throws InterruptedException, UndecidedOmemoIdentityException, CryptoFailedException, - SmackException.NotConnectedException, SmackException.NoResponseException { + SmackException.NotConnectedException, SmackException.NoResponseException, IOException { return encrypt(managerGuard, contactsDevices, key, iv, null); } @@ -511,12 +517,13 @@ public abstract class OmemoService contactsDevices, String message) throws InterruptedException, UndecidedOmemoIdentityException, CryptoFailedException, - SmackException.NotConnectedException, SmackException.NoResponseException { + SmackException.NotConnectedException, SmackException.NoResponseException, IOException { byte[] key, iv; iv = OmemoMessageBuilder.generateIv(); @@ -643,10 +650,11 @@ public abstract class OmemoService buildMissingSessionsWithDevices(XMPPConnection connection, OmemoDevice userDevice, Set devices) - throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, IOException { Set devicesWithSession = new HashSet<>(); for (OmemoDevice device : devices) { @@ -828,8 +839,9 @@ public abstract class OmemoService getUndecidedDevices(OmemoDevice userDevice, OmemoTrustCallback callback, Set devices) { + private Set getUndecidedDevices(OmemoDevice userDevice, OmemoTrustCallback callback, Set devices) throws IOException { Set undecidedDevices = new HashSet<>(); for (OmemoDevice device : devices) { @@ -858,8 +870,9 @@ public abstract class OmemoService decryptMamQueryResult(OmemoManager.LoggedInOmemoManager managerGuard, - MamManager.MamQuery mamQuery) { + MamManager.MamQuery mamQuery) throws IOException { List result = new ArrayList<>(); for (Message message : mamQuery.getMessages()) { if (OmemoManager.stanzaContainsOmemoElement(message)) { @@ -1055,7 +1072,7 @@ public abstract class OmemoService preKeyHashMap) { + public void storeOmemoPreKeys(OmemoDevice userDevice, TreeMap preKeyHashMap) throws IOException { for (Map.Entry entry : preKeyHashMap.entrySet()) { storeOmemoPreKey(userDevice, entry.getKey(), entry.getValue()); } @@ -422,8 +444,9 @@ public abstract class OmemoStore loadOmemoPreKeys(OmemoDevice userDevice); + public abstract TreeMap loadOmemoPreKeys(OmemoDevice userDevice) throws IOException; /** * Return the signedPreKey with the id 'singedPreKeyId'. @@ -431,10 +454,11 @@ public abstract class OmemoStore loadOmemoSignedPreKeys(OmemoDevice userDevice); + public abstract TreeMap loadOmemoSignedPreKeys(OmemoDevice userDevice) throws IOException; /** * Generate a new signed preKey. @@ -465,8 +490,9 @@ public abstract class OmemoStore loadAllRawSessionsOf(OmemoDevice userDevice, BareJid contact); + public abstract HashMap loadAllRawSessionsOf(OmemoDevice userDevice, BareJid contact) throws IOException; /** * Store a crypto-lib specific session to storage. @@ -500,8 +528,9 @@ public abstract class OmemoStore sessions = store.loadAllRawSessionsOf(alice, bob.getJid()); assertNotNull(sessions); assertEquals(0, sessions.size()); } @Test - public void loadNonExistentRawSessionReturnsNullTest() { + public void loadNonExistentRawSessionReturnsNullTest() throws IOException { T_Sess session = store.loadRawSession(alice, bob); assertNull(session); } @Test - public void loadStoreMessageCounterTest() { + public void loadStoreMessageCounterTest() throws IOException { assertEquals(0, store.loadOmemoMessageCounter(alice, bob)); store.storeOmemoMessageCounter(alice, bob, 20); assertEquals(20, store.loadOmemoMessageCounter(alice, bob));