mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-09-11 01:59:38 +02:00
Move trust management from OmemoStore to TrustCallback
Refactor various method names to more precisely reflect what happens Introduce CachingOmemoStore, SignalCachingOmemoStore, which can be either used standalone as ephemeral OmemoStore implementations, or as wrappers around other implementations to add a cache layer for reduced storage access. Get rid of "isFreshInstallation". Keys are now - given that they don't exist - generated on startup. Bump libsignal-protocol-java to 2.6.2 Prevent offline access to some functions which require authenticated connection Create more advanced unit tests and integration tests Add async initialization function for OmemoManager Remove session handling from smack-omemo. This is now handled - in case of smack-omemo-signal - solely by libsignal-protocol-java
This commit is contained in:
parent
fb7a22a761
commit
36dae1ece4
53 changed files with 4072 additions and 3408 deletions
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo.signal;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.CachingOmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.OmemoStore;
|
||||
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.SessionCipher;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* Implementation of the CachingOmemoStore for smack-omemo-signal.
|
||||
* This Store implementation can either be used as a proxy wrapping a persistent SignalOmemoStore in order to prevent
|
||||
* excessive storage access, or it can be used standalone as an ephemeral store, which doesn't persist its contents.
|
||||
*/
|
||||
public class SignalCachingOmemoStore extends CachingOmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord,
|
||||
SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a new SignalCachingOmemoStore as a caching layer around a persisting OmemoStore
|
||||
* (eg. a SignalFileBasedOmemoStore).
|
||||
* @param wrappedStore
|
||||
*/
|
||||
public SignalCachingOmemoStore(OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord,
|
||||
SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> wrappedStore)
|
||||
{
|
||||
super(wrappedStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SignalCachingOmemoStore as an ephemeral standalone OmemoStore.
|
||||
*/
|
||||
public SignalCachingOmemoStore() {
|
||||
super(new SignalOmemoKeyUtil());
|
||||
}
|
||||
}
|
|
@ -42,7 +42,9 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
|||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SignalFileBasedOmemoStore
|
||||
extends FileBasedOmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
extends FileBasedOmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
{
|
||||
|
||||
public SignalFileBasedOmemoStore() {
|
||||
super();
|
||||
|
@ -53,7 +55,9 @@ public class SignalFileBasedOmemoStore
|
|||
}
|
||||
|
||||
@Override
|
||||
public OmemoKeyUtil<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> keyUtil() {
|
||||
public OmemoKeyUtil<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> keyUtil()
|
||||
{
|
||||
return new SignalOmemoKeyUtil();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,16 +21,13 @@
|
|||
package org.jivesoftware.smackx.omemo.signal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.OmemoFingerprint;
|
||||
import org.jivesoftware.smackx.omemo.OmemoManager;
|
||||
import org.jivesoftware.smackx.omemo.OmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoSession;
|
||||
import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil;
|
||||
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
@ -54,25 +51,27 @@ import org.whispersystems.libsignal.util.KeyHelper;
|
|||
* @author Paul Schaub
|
||||
*/
|
||||
public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord,
|
||||
SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
|
||||
SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
{
|
||||
@Override
|
||||
public IdentityKeyPair generateOmemoIdentityKeyPair() {
|
||||
return KeyHelper.generateIdentityKeyPair();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, PreKeyRecord> generateOmemoPreKeys(int currentPreKeyId, int count) {
|
||||
public TreeMap<Integer, PreKeyRecord> generateOmemoPreKeys(int currentPreKeyId, int count) {
|
||||
List<PreKeyRecord> preKeyRecords = KeyHelper.generatePreKeys(currentPreKeyId, count);
|
||||
HashMap<Integer, PreKeyRecord> hashMap = new HashMap<>();
|
||||
TreeMap<Integer, PreKeyRecord> map = new TreeMap<>();
|
||||
for (PreKeyRecord p : preKeyRecords) {
|
||||
hashMap.put(p.getId(), p);
|
||||
map.put(p.getId(), p);
|
||||
}
|
||||
return hashMap;
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignedPreKeyRecord generateOmemoSignedPreKey(IdentityKeyPair identityKeyPair, int currentPreKeyId) throws CorruptedOmemoKeyException {
|
||||
public SignedPreKeyRecord generateOmemoSignedPreKey(IdentityKeyPair identityKeyPair, int currentPreKeyId)
|
||||
throws CorruptedOmemoKeyException
|
||||
{
|
||||
try {
|
||||
return KeyHelper.generateSignedPreKey(identityKeyPair, currentPreKeyId);
|
||||
} catch (InvalidKeyException e) {
|
||||
|
@ -82,6 +81,7 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
|
|||
|
||||
@Override
|
||||
public SignedPreKeyRecord signedPreKeyFromBytes(byte[] data) throws IOException {
|
||||
if (data == null) return null;
|
||||
return new SignedPreKeyRecord(data);
|
||||
}
|
||||
|
||||
|
@ -90,21 +90,9 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
|
|||
return signedPreKeyRecord.serialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OmemoSession<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
createOmemoSession(OmemoManager omemoManager, OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> omemoStore,
|
||||
OmemoDevice contact, IdentityKey identityKey) {
|
||||
return new SignalOmemoSession(omemoManager, omemoStore, contact, identityKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OmemoSession<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
createOmemoSession(OmemoManager omemoManager, OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> omemoStore, OmemoDevice from) {
|
||||
return new SignalOmemoSession(omemoManager, omemoStore, from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionRecord rawSessionFromBytes(byte[] data) throws IOException {
|
||||
if (data == null) return null;
|
||||
return new SessionRecord(data);
|
||||
}
|
||||
|
||||
|
@ -115,6 +103,7 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
|
|||
|
||||
@Override
|
||||
public IdentityKeyPair identityKeyPairFromBytes(byte[] data) throws CorruptedOmemoKeyException {
|
||||
if (data == null) return null;
|
||||
try {
|
||||
return new IdentityKeyPair(data);
|
||||
} catch (InvalidKeyException e) {
|
||||
|
@ -124,6 +113,7 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
|
|||
|
||||
@Override
|
||||
public IdentityKey identityKeyFromBytes(byte[] data) throws CorruptedOmemoKeyException {
|
||||
if (data == null) return null;
|
||||
try {
|
||||
return new IdentityKey(data, 0);
|
||||
} catch (InvalidKeyException e) {
|
||||
|
@ -133,6 +123,7 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
|
|||
|
||||
@Override
|
||||
public ECPublicKey ellipticCurvePublicKeyFromBytes(byte[] data) throws CorruptedOmemoKeyException {
|
||||
if (data == null) return null;
|
||||
try {
|
||||
return Curve.decodePoint(data, 0);
|
||||
} catch (InvalidKeyException e) {
|
||||
|
@ -147,11 +138,14 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
|
|||
|
||||
@Override
|
||||
public PreKeyRecord preKeyFromBytes(byte[] bytes) throws IOException {
|
||||
if (bytes == null) return null;
|
||||
return new PreKeyRecord(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreKeyBundle bundleFromOmemoBundle(OmemoBundleVAxolotlElement bundle, OmemoDevice contact, int preKeyId) throws CorruptedOmemoKeyException {
|
||||
public PreKeyBundle bundleFromOmemoBundle(OmemoBundleVAxolotlElement bundle, OmemoDevice contact, int preKeyId)
|
||||
throws CorruptedOmemoKeyException
|
||||
{
|
||||
return new PreKeyBundle(0,
|
||||
contact.getDeviceId(),
|
||||
preKeyId,
|
||||
|
@ -208,20 +202,35 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
|
|||
}
|
||||
|
||||
@Override
|
||||
public OmemoFingerprint getFingerprint(IdentityKey identityKey) {
|
||||
public OmemoFingerprint getFingerprintOfIdentityKey(IdentityKey identityKey) {
|
||||
if (identityKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String fp = identityKey.getFingerprint();
|
||||
// Cut "(byte)0x" prefixes, remove spaces and commas, cut first two digits.
|
||||
fp = fp.replace("(byte)0x", "").replace(",", "").replace(" ", "").substring(2);
|
||||
fp = fp.replace("(byte)0x", "").replace(",", "")
|
||||
.replace(" ", "").substring(2);
|
||||
return new OmemoFingerprint(fp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OmemoFingerprint getFingerprintOfIdentityKeyPair(IdentityKeyPair identityKeyPair) {
|
||||
if (identityKeyPair == null) {
|
||||
return null;
|
||||
}
|
||||
return getFingerprintOfIdentityKey(identityKeyPair.getPublicKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignalProtocolAddress omemoDeviceAsAddress(OmemoDevice contact) {
|
||||
return new SignalProtocolAddress(contact.getJid().asBareJid().toString(), contact.getDeviceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OmemoDevice addressAsOmemoDevice(SignalProtocolAddress address) throws XmppStringprepException {
|
||||
public OmemoDevice addressAsOmemoDevice(SignalProtocolAddress address)
|
||||
throws XmppStringprepException
|
||||
{
|
||||
return new OmemoDevice(JidCreate.bareFrom(address.getName()), address.getDeviceId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.security.InvalidKeyException;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
@ -34,7 +33,6 @@ import javax.crypto.NoSuchPaddingException;
|
|||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.OmemoManager;
|
||||
import org.jivesoftware.smackx.omemo.OmemoService;
|
||||
import org.jivesoftware.smackx.omemo.OmemoStore;
|
||||
|
@ -59,16 +57,31 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
|||
* @author Paul Schaub
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public final class SignalOmemoService extends OmemoService<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
|
||||
public final class SignalOmemoService
|
||||
extends OmemoService<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
{
|
||||
private static SignalOmemoService INSTANCE;
|
||||
private static boolean LICENSE_ACKNOWLEDGED = false;
|
||||
|
||||
public static void setup() throws InvalidKeyException, XMPPErrorException, NoSuchPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException, SmackException, InterruptedException, CorruptedOmemoKeyException {
|
||||
@Override
|
||||
protected SignalOmemoSessionManager createOmemoSessionManager(
|
||||
OmemoManager.KnownBareJidGuard manager,
|
||||
OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> store)
|
||||
{
|
||||
return new SignalOmemoSessionManager(manager, getOmemoStoreBackend());
|
||||
}
|
||||
|
||||
public static void setup()
|
||||
throws InvalidKeyException, XMPPErrorException, NoSuchPaddingException, InvalidAlgorithmParameterException,
|
||||
UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException,
|
||||
NoSuchProviderException, SmackException, InterruptedException, CorruptedOmemoKeyException
|
||||
{
|
||||
if (!LICENSE_ACKNOWLEDGED) {
|
||||
throw new IllegalStateException("smack-omemo-signal is licensed under the terms of the GPLv3. Please be aware that you " +
|
||||
"can only use this library within the terms of the GPLv3. See for example " +
|
||||
"https://www.gnu.org/licenses/quick-guide-gplv3 for more details. Please call " +
|
||||
throw new IllegalStateException("smack-omemo-signal is licensed under the terms of the GPLv3. " +
|
||||
"Please be aware that you can only use this library within the terms of the GPLv3. " +
|
||||
"See for example https://www.gnu.org/licenses/quick-guide-gplv3 for more details. Please call " +
|
||||
"SignalOmemoService.acknowledgeLicense() prior to the setup() method in order to prevent " +
|
||||
"this exception.");
|
||||
}
|
||||
|
@ -79,8 +92,10 @@ public final class SignalOmemoService extends OmemoService<IdentityKeyPair, Iden
|
|||
}
|
||||
|
||||
@Override
|
||||
public OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> createDefaultOmemoStoreBackend() {
|
||||
return new SignalFileBasedOmemoStore();
|
||||
public OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
createDefaultOmemoStoreBackend() {
|
||||
return new SignalCachingOmemoStore();
|
||||
}
|
||||
|
||||
private SignalOmemoService()
|
||||
|
@ -96,14 +111,17 @@ public final class SignalOmemoService extends OmemoService<IdentityKeyPair, Iden
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void processBundle(OmemoManager omemoManager, PreKeyBundle preKeyBundle, OmemoDevice contact) throws CorruptedOmemoKeyException {
|
||||
SignalOmemoStoreConnector connector = new SignalOmemoStoreConnector(omemoManager, getOmemoStoreBackend());
|
||||
protected void processBundle(OmemoManager.KnownBareJidGuard managerGuard,
|
||||
PreKeyBundle preKeyBundle,
|
||||
OmemoDevice device)
|
||||
throws CorruptedOmemoKeyException
|
||||
{
|
||||
SignalOmemoStoreConnector connector = new SignalOmemoStoreConnector(managerGuard, getOmemoStoreBackend());
|
||||
SessionBuilder builder = new SessionBuilder(connector, connector, connector, connector,
|
||||
getOmemoStoreBackend().keyUtil().omemoDeviceAsAddress(contact));
|
||||
getOmemoStoreBackend().keyUtil().omemoDeviceAsAddress(device));
|
||||
try {
|
||||
builder.process(preKeyBundle);
|
||||
LOGGER.log(Level.INFO, "Session built with " + contact);
|
||||
getOmemoStoreBackend().getOmemoSessionOf(omemoManager, contact); //method puts session in session map.
|
||||
LOGGER.log(Level.FINE, "Session built with " + device);
|
||||
} catch (org.whispersystems.libsignal.InvalidKeyException e) {
|
||||
throw new CorruptedOmemoKeyException(e.getMessage());
|
||||
} catch (UntrustedIdentityException e) {
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo.signal;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.OmemoManager;
|
||||
import org.jivesoftware.smackx.omemo.OmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.element.OmemoElement;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException;
|
||||
import org.jivesoftware.smackx.omemo.internal.CiphertextTuple;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoSession;
|
||||
|
||||
import org.whispersystems.libsignal.DuplicateMessageException;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.InvalidKeyIdException;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
import org.whispersystems.libsignal.InvalidVersionException;
|
||||
import org.whispersystems.libsignal.LegacyMessageException;
|
||||
import org.whispersystems.libsignal.NoSessionException;
|
||||
import org.whispersystems.libsignal.SessionCipher;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.UntrustedIdentityException;
|
||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||
import org.whispersystems.libsignal.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libsignal.protocol.PreKeySignalMessage;
|
||||
import org.whispersystems.libsignal.protocol.SignalMessage;
|
||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* Concrete implementation of the OmemoSession using the Signal library.
|
||||
*
|
||||
* @author Paul Schaub
|
||||
*/
|
||||
public class SignalOmemoSession extends OmemoSession<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
private static final Logger LOGGER = Logger.getLogger(SignalOmemoSession.class.getName());
|
||||
|
||||
/**
|
||||
* Constructor used when the remote user initialized the session using a PreKeyOmemoMessage.
|
||||
*
|
||||
* @param omemoManager omemoManager
|
||||
* @param omemoStore omemoStoreConnector that can be used to get information from
|
||||
* @param remoteContact omemoDevice of the remote contact
|
||||
* @param identityKey identityKey of the remote contact
|
||||
*/
|
||||
SignalOmemoSession(OmemoManager omemoManager, OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> omemoStore,
|
||||
OmemoDevice remoteContact, IdentityKey identityKey) {
|
||||
super(omemoManager, omemoStore, remoteContact, identityKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used when we initiate a new Session with the remote user.
|
||||
*
|
||||
* @param omemoManager omemoManager
|
||||
* @param omemoStore omemoStore used to get information from
|
||||
* @param remoteContact omemoDevice of the remote contact
|
||||
*/
|
||||
SignalOmemoSession(OmemoManager omemoManager,
|
||||
OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> omemoStore,
|
||||
OmemoDevice remoteContact) {
|
||||
super(omemoManager, omemoStore, remoteContact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionCipher createCipher(OmemoDevice contact) {
|
||||
SignalOmemoStoreConnector connector = new SignalOmemoStoreConnector(omemoManager, omemoStore);
|
||||
return new SessionCipher(connector, connector, connector, connector,
|
||||
omemoStore.keyUtil().omemoDeviceAsAddress(contact));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CiphertextTuple encryptMessageKey(byte[] messageKey) {
|
||||
CiphertextMessage ciphertextMessage;
|
||||
ciphertextMessage = cipher.encrypt(messageKey);
|
||||
int type = (ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE ?
|
||||
OmemoElement.TYPE_OMEMO_PREKEY_MESSAGE : OmemoElement.TYPE_OMEMO_MESSAGE);
|
||||
return new CiphertextTuple(ciphertextMessage.serialize(), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decryptMessageKey(byte[] encryptedKey) throws NoRawSessionException {
|
||||
byte[] decryptedKey = null;
|
||||
try {
|
||||
try {
|
||||
PreKeySignalMessage message = new PreKeySignalMessage(encryptedKey);
|
||||
if (!message.getPreKeyId().isPresent()) {
|
||||
LOGGER.log(Level.WARNING, "PreKeySignalMessage did not contain a PreKeyId");
|
||||
return null;
|
||||
}
|
||||
LOGGER.log(Level.INFO, "PreKeySignalMessage received, new session ID: " + message.getSignedPreKeyId() + "/" + message.getPreKeyId().get());
|
||||
IdentityKey messageIdentityKey = message.getIdentityKey();
|
||||
if (this.identityKey != null && !this.identityKey.equals(messageIdentityKey)) {
|
||||
LOGGER.log(Level.INFO, "Had session with fingerprint " + getFingerprint() +
|
||||
", received message with different fingerprint " + omemoStore.keyUtil().getFingerprint(messageIdentityKey) +
|
||||
". Silently drop the message.");
|
||||
} else {
|
||||
this.identityKey = messageIdentityKey;
|
||||
decryptedKey = cipher.decrypt(message);
|
||||
this.preKeyId = message.getPreKeyId().get();
|
||||
}
|
||||
} catch (InvalidMessageException | InvalidVersionException e) {
|
||||
SignalMessage message = new SignalMessage(encryptedKey);
|
||||
decryptedKey = cipher.decrypt(message);
|
||||
} catch (InvalidKeyIdException e) {
|
||||
throw new NoRawSessionException(e);
|
||||
}
|
||||
catch (InvalidKeyException | UntrustedIdentityException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error decrypting message header, " + e.getClass().getName() + ": " + e.getMessage());
|
||||
}
|
||||
} catch (InvalidMessageException | NoSessionException e) {
|
||||
throw new NoRawSessionException(e);
|
||||
} catch (LegacyMessageException | DuplicateMessageException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error decrypting message header, " + e.getClass().getName() + ": " + e.getMessage());
|
||||
}
|
||||
return decryptedKey;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo.signal;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.OmemoManager;
|
||||
import org.jivesoftware.smackx.omemo.OmemoSessionManager;
|
||||
import org.jivesoftware.smackx.omemo.OmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.element.OmemoElement;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.UntrustedOmemoIdentityException;
|
||||
import org.jivesoftware.smackx.omemo.internal.CiphertextTuple;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
|
||||
|
||||
import org.whispersystems.libsignal.DuplicateMessageException;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.InvalidKeyIdException;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
import org.whispersystems.libsignal.InvalidVersionException;
|
||||
import org.whispersystems.libsignal.LegacyMessageException;
|
||||
import org.whispersystems.libsignal.NoSessionException;
|
||||
import org.whispersystems.libsignal.SessionCipher;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.UntrustedIdentityException;
|
||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||
import org.whispersystems.libsignal.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libsignal.protocol.PreKeySignalMessage;
|
||||
import org.whispersystems.libsignal.protocol.SignalMessage;
|
||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
public class SignalOmemoSessionManager
|
||||
extends OmemoSessionManager<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(OmemoSessionManager.class.getName());
|
||||
private final SignalOmemoStoreConnector storeConnector;
|
||||
|
||||
public SignalOmemoSessionManager(OmemoManager.KnownBareJidGuard managerGuard,
|
||||
OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord,
|
||||
SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle,
|
||||
SessionCipher> store)
|
||||
{
|
||||
super(managerGuard, store);
|
||||
this.storeConnector = new SignalOmemoStoreConnector(managerGuard, store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] doubleRatchetDecrypt(OmemoDevice sender, byte[] encryptedKey)
|
||||
throws CorruptedOmemoKeyException, NoRawSessionException, CryptoFailedException,
|
||||
UntrustedOmemoIdentityException
|
||||
{
|
||||
SessionCipher cipher = getCipher(sender);
|
||||
byte[] decryptedKey;
|
||||
|
||||
// Try to handle the message as a PreKeySignalMessage...
|
||||
try {
|
||||
PreKeySignalMessage preKeyMessage = new PreKeySignalMessage(encryptedKey);
|
||||
|
||||
if (!preKeyMessage.getPreKeyId().isPresent()) {
|
||||
throw new CryptoFailedException("PreKeyMessage did not contain a preKeyId.");
|
||||
}
|
||||
|
||||
IdentityKey messageIdentityKey = preKeyMessage.getIdentityKey();
|
||||
IdentityKey previousIdentityKey = store.loadOmemoIdentityKey(storeConnector.getOurDevice(), sender);
|
||||
|
||||
if (previousIdentityKey != null &&
|
||||
!previousIdentityKey.getFingerprint().equals(messageIdentityKey.getFingerprint())) {
|
||||
throw new UntrustedOmemoIdentityException(sender,
|
||||
store.keyUtil().getFingerprintOfIdentityKey(previousIdentityKey),
|
||||
store.keyUtil().getFingerprintOfIdentityKey(messageIdentityKey));
|
||||
}
|
||||
|
||||
try {
|
||||
decryptedKey = cipher.decrypt(preKeyMessage);
|
||||
}
|
||||
catch (UntrustedIdentityException e) {
|
||||
throw new AssertionError("Signals trust management MUST be disabled.");
|
||||
}
|
||||
catch (LegacyMessageException | InvalidKeyException e) {
|
||||
throw new CryptoFailedException(e);
|
||||
}
|
||||
catch (InvalidKeyIdException e) {
|
||||
throw new NoRawSessionException(e);
|
||||
}
|
||||
catch (DuplicateMessageException e) {
|
||||
LOGGER.log(Level.INFO, "Decryption of PreKeyMessage from " + sender +
|
||||
" failed, since the message has been decrypted before.");
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (InvalidVersionException | InvalidMessageException noPreKeyMessage) {
|
||||
// ...if that fails, handle it as a SignalMessage
|
||||
try {
|
||||
SignalMessage message = new SignalMessage(encryptedKey);
|
||||
decryptedKey = getCipher(sender).decrypt(message);
|
||||
}
|
||||
catch (UntrustedIdentityException e) {
|
||||
throw new AssertionError("Signals trust management MUST be disabled.");
|
||||
}
|
||||
catch (InvalidMessageException | NoSessionException e) {
|
||||
throw new NoRawSessionException(e);
|
||||
}
|
||||
catch (LegacyMessageException e) {
|
||||
throw new CryptoFailedException(e);
|
||||
}
|
||||
catch (DuplicateMessageException e1) {
|
||||
LOGGER.log(Level.INFO, "Decryption of SignalMessage from " + sender +
|
||||
" failed, since the message has been decrypted before.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return decryptedKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CiphertextTuple doubleRatchetEncrypt(OmemoDevice recipient, byte[] messageKey) {
|
||||
CiphertextMessage ciphertextMessage;
|
||||
try {
|
||||
ciphertextMessage = getCipher(recipient).encrypt(messageKey);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
throw new AssertionError("Signals trust management MUST be disabled.");
|
||||
}
|
||||
|
||||
// TODO: Figure out, if this is enough...
|
||||
int type = (ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE ?
|
||||
OmemoElement.TYPE_OMEMO_PREKEY_MESSAGE : OmemoElement.TYPE_OMEMO_MESSAGE);
|
||||
|
||||
return new CiphertextTuple(ciphertextMessage.serialize(), type);
|
||||
}
|
||||
|
||||
private SessionCipher getCipher(OmemoDevice device) {
|
||||
SignalOmemoKeyUtil keyUtil = (SignalOmemoKeyUtil) store.keyUtil();
|
||||
SignalProtocolAddress address = keyUtil.omemoDeviceAsAddress(device);
|
||||
return new SessionCipher(storeConnector, storeConnector, storeConnector, storeConnector, address);
|
||||
}
|
||||
}
|
|
@ -40,12 +40,14 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
|||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class SignalOmemoStore
|
||||
extends OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
extends OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
|
||||
private final SignalOmemoKeyUtil signalKeyUtil = new SignalOmemoKeyUtil();
|
||||
|
||||
@Override
|
||||
public OmemoKeyUtil<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> keyUtil() {
|
||||
public OmemoKeyUtil<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> keyUtil() {
|
||||
return signalKeyUtil;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,17 @@
|
|||
package org.jivesoftware.smackx.omemo.signal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.OmemoManager;
|
||||
import org.jivesoftware.smackx.omemo.OmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
|
||||
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
|
@ -57,21 +59,28 @@ public class SignalOmemoStoreConnector
|
|||
|
||||
private static final Logger LOGGER = Logger.getLogger(SignalOmemoStoreConnector.class.getName());
|
||||
|
||||
private final OmemoManager omemoManager;
|
||||
private final OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
private final OmemoManager.KnownBareJidGuard managerGuard;
|
||||
private final OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
|
||||
SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher>
|
||||
omemoStore;
|
||||
|
||||
public SignalOmemoStoreConnector(OmemoManager omemoManager, OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> store) {
|
||||
this.omemoManager = omemoManager;
|
||||
public SignalOmemoStoreConnector(OmemoManager.KnownBareJidGuard managerGuard, OmemoStore<IdentityKeyPair,
|
||||
IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey,
|
||||
PreKeyBundle, SessionCipher> store) {
|
||||
this.managerGuard = managerGuard;
|
||||
this.omemoStore = store;
|
||||
}
|
||||
|
||||
OmemoDevice getOurDevice() {
|
||||
return managerGuard.get().getOwnDevice();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityKeyPair getIdentityKeyPair() {
|
||||
try {
|
||||
return omemoStore.loadOmemoIdentityKeyPair(omemoManager);
|
||||
return omemoStore.loadOmemoIdentityKeyPair(getOurDevice());
|
||||
} catch (CorruptedOmemoKeyException e) {
|
||||
LOGGER.log(Level.SEVERE, "getIdentityKeyPair has failed: " + e, e);
|
||||
LOGGER.log(Level.SEVERE, "IdentityKeyPair seems to be invalid.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -86,33 +95,41 @@ public class SignalOmemoStoreConnector
|
|||
}
|
||||
|
||||
@Override
|
||||
public void saveIdentity(SignalProtocolAddress signalProtocolAddress, IdentityKey identityKey) {
|
||||
public boolean saveIdentity(SignalProtocolAddress signalProtocolAddress, IdentityKey identityKey) {
|
||||
OmemoDevice device;
|
||||
try {
|
||||
omemoStore.storeOmemoIdentityKey(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress), identityKey);
|
||||
device = omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress);
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
omemoStore.storeOmemoIdentityKey(getOurDevice(), device, identityKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrustedIdentity(SignalProtocolAddress signalProtocolAddress, IdentityKey identityKey) {
|
||||
// Disable internal trust management. Instead we use OmemoStore.isTrustedOmemoIdentity() before encrypting for a
|
||||
// recipient.
|
||||
public boolean isTrustedIdentity(SignalProtocolAddress signalProtocolAddress,
|
||||
IdentityKey identityKey,
|
||||
Direction direction) {
|
||||
// Disable internal trust management. Instead we use OmemoStore.isTrustedOmemoIdentity() before encrypting
|
||||
// for a recipient.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreKeyRecord loadPreKey(int i) throws InvalidKeyIdException {
|
||||
PreKeyRecord pr = omemoStore.loadOmemoPreKey(omemoManager, i);
|
||||
if (pr == null) {
|
||||
throw new InvalidKeyIdException("No PreKey with Id " + i + " found!");
|
||||
PreKeyRecord preKey = omemoStore.loadOmemoPreKey(getOurDevice(), i);
|
||||
|
||||
if (preKey == null) {
|
||||
throw new InvalidKeyIdException("No PreKey with Id " + i + " found.");
|
||||
}
|
||||
return pr;
|
||||
|
||||
return preKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePreKey(int i, PreKeyRecord preKeyRecord) {
|
||||
omemoStore.storeOmemoPreKey(omemoManager, i, preKeyRecord);
|
||||
omemoStore.storeOmemoPreKey(getOurDevice(), i, preKeyRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -120,96 +137,112 @@ public class SignalOmemoStoreConnector
|
|||
try {
|
||||
return (loadPreKey(i) != null);
|
||||
} catch (InvalidKeyIdException e) {
|
||||
LOGGER.log(Level.WARNING, "containsPreKey has failed: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePreKey(int i) {
|
||||
omemoStore.removeOmemoPreKey(omemoManager, i);
|
||||
omemoStore.removeOmemoPreKey(getOurDevice(), i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionRecord loadSession(SignalProtocolAddress signalProtocolAddress) {
|
||||
OmemoDevice device;
|
||||
try {
|
||||
SessionRecord s = omemoStore.loadRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress));
|
||||
return (s != null ? s : new SessionRecord());
|
||||
device = omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress);
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
SessionRecord record = omemoStore.loadRawSession(getOurDevice(), device);
|
||||
|
||||
if (record != null) {
|
||||
return record;
|
||||
} else {
|
||||
return new SessionRecord();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getSubDeviceSessions(String s) {
|
||||
HashMap<Integer, SessionRecord> contactsSessions;
|
||||
BareJid jid;
|
||||
try {
|
||||
contactsSessions = omemoStore.loadAllRawSessionsOf(omemoManager, JidCreate.bareFrom(s));
|
||||
jid = JidCreate.bareFrom(s);
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
if (contactsSessions != null) {
|
||||
return new ArrayList<>(contactsSessions.keySet());
|
||||
}
|
||||
return new ArrayList<>();
|
||||
|
||||
return new ArrayList<>(omemoStore.loadAllRawSessionsOf(getOurDevice(), jid).keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeSession(SignalProtocolAddress signalProtocolAddress, SessionRecord sessionRecord) {
|
||||
OmemoDevice device;
|
||||
try {
|
||||
omemoStore.storeRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress), sessionRecord);
|
||||
device = omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress);
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
omemoStore.storeRawSession(getOurDevice(), device, sessionRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsSession(SignalProtocolAddress signalProtocolAddress) {
|
||||
OmemoDevice device;
|
||||
try {
|
||||
return omemoStore.containsRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress));
|
||||
device = omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress);
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
return omemoStore.containsRawSession(getOurDevice(), device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSession(SignalProtocolAddress signalProtocolAddress) {
|
||||
OmemoDevice device;
|
||||
try {
|
||||
omemoStore.removeRawSession(omemoManager, omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress));
|
||||
device = omemoStore.keyUtil().addressAsOmemoDevice(signalProtocolAddress);
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
omemoStore.removeRawSession(getOurDevice(), device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAllSessions(String s) {
|
||||
BareJid jid;
|
||||
try {
|
||||
omemoStore.removeAllRawSessionsOf(omemoManager, JidCreate.bareFrom(s));
|
||||
jid = JidCreate.bareFrom(s);
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
omemoStore.removeAllRawSessionsOf(getOurDevice(), jid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignedPreKeyRecord loadSignedPreKey(int i) throws InvalidKeyIdException {
|
||||
SignedPreKeyRecord spkr = omemoStore.loadOmemoSignedPreKey(omemoManager, i);
|
||||
if (spkr == null) {
|
||||
throw new InvalidKeyIdException("No SignedPreKey with Id " + i + " found!");
|
||||
}
|
||||
return spkr;
|
||||
return omemoStore.loadOmemoSignedPreKey(getOurDevice(), i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SignedPreKeyRecord> loadSignedPreKeys() {
|
||||
HashMap<Integer, SignedPreKeyRecord> signedPreKeyRecordHashMap = omemoStore.loadOmemoSignedPreKeys(omemoManager);
|
||||
List<SignedPreKeyRecord> signedPreKeyRecordList = new ArrayList<>();
|
||||
|
||||
TreeMap<Integer, SignedPreKeyRecord> signedPreKeyRecordHashMap =
|
||||
omemoStore.loadOmemoSignedPreKeys(getOurDevice());
|
||||
signedPreKeyRecordList.addAll(signedPreKeyRecordHashMap.values());
|
||||
|
||||
return signedPreKeyRecordList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeSignedPreKey(int i, SignedPreKeyRecord signedPreKeyRecord) {
|
||||
omemoStore.storeOmemoSignedPreKey(omemoManager, i, signedPreKeyRecord);
|
||||
omemoStore.storeOmemoSignedPreKey(getOurDevice(), i, signedPreKeyRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -224,6 +257,6 @@ public class SignalOmemoStoreConnector
|
|||
|
||||
@Override
|
||||
public void removeSignedPreKey(int i) {
|
||||
omemoStore.removeOmemoSignedPreKey(omemoManager, i);
|
||||
omemoStore.removeOmemoSignedPreKey(getOurDevice(), i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smack.omemo;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertNotSame;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static junit.framework.TestCase.fail;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalOmemoKeyUtil;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* Test SignalOmemoKeyUtil methods.
|
||||
*
|
||||
* @author Paul Schaub
|
||||
*/
|
||||
public class LegacySignalOmemoKeyUtilTest extends SmackTestSuite {
|
||||
|
||||
private final SignalOmemoKeyUtil keyUtil = new SignalOmemoKeyUtil();
|
||||
|
||||
@Test
|
||||
public void omemoIdentityKeyPairSerializationTest() {
|
||||
IdentityKeyPair ikp = keyUtil.generateOmemoIdentityKeyPair();
|
||||
byte[] bytes = keyUtil.identityKeyPairToBytes(ikp);
|
||||
assertNotNull("serialized identityKeyPair must not be null.",
|
||||
bytes);
|
||||
assertNotSame("serialized identityKeyPair must not be of length 0.",
|
||||
0, bytes.length);
|
||||
try {
|
||||
IdentityKeyPair ikp2 = keyUtil.identityKeyPairFromBytes(bytes);
|
||||
assertTrue("Deserialized IdentityKeyPairs PublicKey must equal the originals one.",
|
||||
ikp.getPublicKey().equals(ikp2.getPublicKey()));
|
||||
} catch (CorruptedOmemoKeyException e) {
|
||||
fail("Caught exception while deserializing IdentityKeyPair.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void omemoIdentityKeySerializationTest() {
|
||||
IdentityKey k = keyUtil.generateOmemoIdentityKeyPair().getPublicKey();
|
||||
|
||||
try {
|
||||
assertEquals("Deserialized IdentityKey must equal the original one.",
|
||||
k, keyUtil.identityKeyFromBytes(keyUtil.identityKeyToBytes(k)));
|
||||
} catch (CorruptedOmemoKeyException e) {
|
||||
fail("Caught exception while serializing and deserializing identityKey (" + e + "): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateOmemoSignedPreKeyTest() {
|
||||
IdentityKeyPair ikp = keyUtil.generateOmemoIdentityKeyPair();
|
||||
try {
|
||||
SignedPreKeyRecord spk = keyUtil.generateOmemoSignedPreKey(ikp, 1);
|
||||
assertNotNull("SignedPreKey must not be null.", spk);
|
||||
assertEquals("SignedPreKeyId must match.", 1, spk.getId());
|
||||
assertEquals("singedPreKeyId must match here also.", 1, keyUtil.signedPreKeyIdFromKey(spk));
|
||||
} catch (CorruptedOmemoKeyException e) {
|
||||
fail("Caught an exception while generating signedPreKey (" + e + "): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFingerprintTest() {
|
||||
IdentityKeyPair ikp = keyUtil.generateOmemoIdentityKeyPair();
|
||||
IdentityKey ik = ikp.getPublicKey();
|
||||
assertTrue("Length of fingerprint must be 64.",
|
||||
keyUtil.getFingerprintOfIdentityKey(ik).length() == 64);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addressToDeviceTest() {
|
||||
SignalProtocolAddress address = new SignalProtocolAddress("test@server.tld",1337);
|
||||
try {
|
||||
OmemoDevice device = keyUtil.addressAsOmemoDevice(address);
|
||||
assertEquals(device, new OmemoDevice(JidCreate.bareFrom("test@server.tld"), 1337));
|
||||
} catch (XmppStringprepException e) {
|
||||
fail("Could not convert address to device: " + e + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceToAddressTest() {
|
||||
try {
|
||||
OmemoDevice device = new OmemoDevice(JidCreate.bareFrom("test@server.tld"), 1337);
|
||||
SignalProtocolAddress address = keyUtil.omemoDeviceAsAddress(device);
|
||||
assertEquals(address, new SignalProtocolAddress("test@server.tld", 1337));
|
||||
} catch (XmppStringprepException e) {
|
||||
fail("Could not convert device to address: " + e + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,7 +57,12 @@ import org.junit.Test;
|
|||
public class OmemoManagerTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
public void instantiationTest() throws CorruptedOmemoKeyException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException, InterruptedException, XMPPException.XMPPErrorException, NoSuchPaddingException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException, IllegalBlockSizeException, SmackException {
|
||||
public void instantiationTest()
|
||||
throws CorruptedOmemoKeyException, NoSuchAlgorithmException, UnsupportedEncodingException,
|
||||
InvalidKeyException, InterruptedException, XMPPException.XMPPErrorException, NoSuchPaddingException,
|
||||
BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException, IllegalBlockSizeException,
|
||||
SmackException
|
||||
{
|
||||
SignalOmemoService.acknowledgeLicense();
|
||||
SignalOmemoService.setup();
|
||||
|
||||
|
@ -73,8 +78,8 @@ public class OmemoManagerTest extends SmackTestSuite {
|
|||
assertNotNull(c);
|
||||
assertNotNull(d);
|
||||
|
||||
assertEquals(123, a.getDeviceId());
|
||||
assertEquals(234, b.getDeviceId());
|
||||
assertEquals(Integer.valueOf(123), a.getDeviceId());
|
||||
assertEquals(Integer.valueOf(234), b.getDeviceId());
|
||||
|
||||
assertFalse(a == b);
|
||||
assertFalse(a == c);
|
||||
|
|
|
@ -1,218 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smack.omemo;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.powermock.api.mockito.PowerMockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.FileBasedOmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.OmemoConfiguration;
|
||||
import org.jivesoftware.smackx.omemo.OmemoManager;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||
import org.jivesoftware.smackx.omemo.internal.CachedDeviceList;
|
||||
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalFileBasedOmemoStore;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* Test the file-based signalOmemoStore.
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({OmemoManager.class})
|
||||
public class SignalFileBasedOmemoStoreTest {
|
||||
|
||||
private static File storePath;
|
||||
private static SignalFileBasedOmemoStore omemoStore;
|
||||
private static OmemoManager omemoManager;
|
||||
|
||||
|
||||
private void deleteStore() {
|
||||
FileBasedOmemoStore.deleteDirectory(storePath);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws XmppStringprepException {
|
||||
String userHome = System.getProperty("user.home");
|
||||
if (userHome != null) {
|
||||
File f = new File(userHome);
|
||||
storePath = new File(f, ".config/smack-integration-test/store");
|
||||
} else {
|
||||
storePath = new File("int_test_omemo_store");
|
||||
}
|
||||
|
||||
OmemoConfiguration.setFileBasedOmemoStoreDefaultPath(storePath);
|
||||
omemoStore = new SignalFileBasedOmemoStore();
|
||||
|
||||
OmemoDevice device = new OmemoDevice(JidCreate.bareFrom("storeTest@server.tld"), 55155);
|
||||
omemoManager = PowerMockito.mock(OmemoManager.class);
|
||||
when(omemoManager.getDeviceId()).thenReturn(device.getDeviceId());
|
||||
when(omemoManager.getOwnJid()).thenReturn(device.getJid());
|
||||
when(omemoManager.getOwnDevice()).thenReturn(device);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
deleteStore();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
deleteStore();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isFreshInstallationTest() {
|
||||
assertTrue(omemoStore.isFreshInstallation(omemoManager));
|
||||
omemoStore.storeOmemoIdentityKeyPair(omemoManager, omemoStore.generateOmemoIdentityKeyPair());
|
||||
assertFalse(omemoStore.isFreshInstallation(omemoManager));
|
||||
omemoStore.purgeOwnDeviceKeys(omemoManager);
|
||||
assertTrue(omemoStore.isFreshInstallation(omemoManager));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultDeviceIdTest() throws XmppStringprepException {
|
||||
assertEquals(-1, omemoStore.getDefaultDeviceId(omemoManager.getOwnJid()));
|
||||
omemoStore.setDefaultDeviceId(omemoManager.getOwnJid(), 55);
|
||||
assertEquals(55, omemoStore.getDefaultDeviceId(omemoManager.getOwnJid()));
|
||||
assertEquals(-1, omemoStore.getDefaultDeviceId(JidCreate.bareFrom("randomGuy@server.tld")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cachedDeviceListTest() throws XmppStringprepException {
|
||||
OmemoDevice bob = new OmemoDevice(JidCreate.bareFrom("bob@builder.tv"), 666);
|
||||
OmemoDevice craig = new OmemoDevice(JidCreate.bareFrom("craig@southpark.tv"), 3333333);
|
||||
|
||||
CachedDeviceList bobsList = new CachedDeviceList();
|
||||
assertEquals(0, bobsList.getAllDevices().size());
|
||||
bobsList.getActiveDevices().add(bob.getDeviceId());
|
||||
bobsList.getActiveDevices().add(777);
|
||||
bobsList.getInactiveDevices().add(888);
|
||||
|
||||
CachedDeviceList craigsList = new CachedDeviceList();
|
||||
craigsList.addDevice(craig.getDeviceId());
|
||||
|
||||
assertEquals(3, bobsList.getAllDevices().size());
|
||||
assertEquals(2, bobsList.getActiveDevices().size());
|
||||
assertTrue(bobsList.getInactiveDevices().contains(888));
|
||||
assertTrue(bobsList.getActiveDevices().contains(777));
|
||||
assertTrue(bobsList.getAllDevices().contains(888));
|
||||
|
||||
assertEquals(0, craigsList.getInactiveDevices().size());
|
||||
assertEquals(1, craigsList.getActiveDevices().size());
|
||||
assertEquals(1, craigsList.getAllDevices().size());
|
||||
assertEquals(craig.getDeviceId(), craigsList.getActiveDevices().iterator().next().intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void omemoIdentityKeyPairTest() throws CorruptedOmemoKeyException {
|
||||
assertNull(omemoStore.loadOmemoIdentityKeyPair(omemoManager));
|
||||
omemoStore.storeOmemoIdentityKeyPair(omemoManager, omemoStore.generateOmemoIdentityKeyPair());
|
||||
IdentityKeyPair ikp = omemoStore.loadOmemoIdentityKeyPair(omemoManager);
|
||||
assertNotNull(ikp);
|
||||
|
||||
assertTrue(omemoStore.keyUtil().getFingerprint(ikp.getPublicKey()).equals(omemoStore.getFingerprint(omemoManager)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signedPreKeyTest() throws CorruptedOmemoKeyException {
|
||||
assertEquals(0, omemoStore.loadOmemoSignedPreKeys(omemoManager).size());
|
||||
IdentityKeyPair ikp = omemoStore.generateOmemoIdentityKeyPair();
|
||||
SignedPreKeyRecord spk = omemoStore.generateOmemoSignedPreKey(ikp, 14);
|
||||
omemoStore.storeOmemoSignedPreKey(omemoManager, 14, spk);
|
||||
assertEquals(1, omemoStore.loadOmemoSignedPreKeys(omemoManager).size());
|
||||
assertNotNull(omemoStore.loadOmemoSignedPreKey(omemoManager, 14));
|
||||
assertArrayEquals(spk.serialize(), omemoStore.loadOmemoSignedPreKey(omemoManager, 14).serialize());
|
||||
assertNull(omemoStore.loadOmemoSignedPreKey(omemoManager, 13));
|
||||
assertEquals(0, omemoStore.loadCurrentSignedPreKeyId(omemoManager));
|
||||
omemoStore.storeCurrentSignedPreKeyId(omemoManager, 15);
|
||||
assertEquals(15, omemoStore.loadCurrentSignedPreKeyId(omemoManager));
|
||||
omemoStore.removeOmemoSignedPreKey(omemoManager, 14);
|
||||
assertNull(omemoStore.loadOmemoSignedPreKey(omemoManager, 14));
|
||||
|
||||
assertNull(omemoStore.getDateOfLastSignedPreKeyRenewal(omemoManager));
|
||||
Date now = new Date();
|
||||
omemoStore.setDateOfLastSignedPreKeyRenewal(omemoManager, now);
|
||||
assertEquals(now, omemoStore.getDateOfLastSignedPreKeyRenewal(omemoManager));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preKeyTest() {
|
||||
assertEquals(0, omemoStore.loadOmemoPreKeys(omemoManager).size());
|
||||
assertNull(omemoStore.loadOmemoPreKey(omemoManager, 12));
|
||||
omemoStore.storeOmemoPreKeys(omemoManager,
|
||||
omemoStore.generateOmemoPreKeys(1, 20));
|
||||
assertNotNull(omemoStore.loadOmemoPreKey(omemoManager, 12));
|
||||
assertEquals(20, omemoStore.loadOmemoPreKeys(omemoManager).size());
|
||||
omemoStore.removeOmemoPreKey(omemoManager, 12);
|
||||
assertNull(omemoStore.loadOmemoPreKey(omemoManager, 12));
|
||||
assertEquals(19, omemoStore.loadOmemoPreKeys(omemoManager).size());
|
||||
|
||||
assertEquals(0, omemoStore.loadLastPreKeyId(omemoManager));
|
||||
omemoStore.storeLastPreKeyId(omemoManager, 35);
|
||||
assertEquals(35, omemoStore.loadLastPreKeyId(omemoManager));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trustingTest() throws XmppStringprepException, CorruptedOmemoKeyException {
|
||||
OmemoDevice bob = new OmemoDevice(JidCreate.bareFrom("bob@builder.tv"), 555);
|
||||
IdentityKey bobsKey = omemoStore.generateOmemoIdentityKeyPair().getPublicKey();
|
||||
assertFalse(omemoStore.isDecidedOmemoIdentity(omemoManager, bob, bobsKey));
|
||||
assertFalse(omemoStore.isTrustedOmemoIdentity(omemoManager, bob, bobsKey));
|
||||
omemoStore.trustOmemoIdentity(omemoManager, bob, bobsKey);
|
||||
assertTrue(omemoStore.isDecidedOmemoIdentity(omemoManager, bob, omemoStore.keyUtil().getFingerprint(bobsKey)));
|
||||
assertTrue(omemoStore.isTrustedOmemoIdentity(omemoManager, bob, omemoStore.keyUtil().getFingerprint(bobsKey)));
|
||||
assertNull(omemoStore.loadOmemoIdentityKey(omemoManager, bob));
|
||||
omemoStore.storeOmemoIdentityKey(omemoManager, bob, bobsKey);
|
||||
assertNotNull(omemoStore.loadOmemoIdentityKey(omemoManager, bob));
|
||||
IdentityKey bobsOtherKey = omemoStore.generateOmemoIdentityKeyPair().getPublicKey();
|
||||
assertFalse(omemoStore.isTrustedOmemoIdentity(omemoManager, bob, bobsOtherKey));
|
||||
assertFalse(omemoStore.isDecidedOmemoIdentity(omemoManager, bob, bobsOtherKey));
|
||||
omemoStore.distrustOmemoIdentity(omemoManager, bob, omemoStore.keyUtil().getFingerprint(bobsKey));
|
||||
assertTrue(omemoStore.isDecidedOmemoIdentity(omemoManager, bob, bobsKey));
|
||||
assertFalse(omemoStore.isTrustedOmemoIdentity(omemoManager, bob, bobsKey));
|
||||
|
||||
assertNull(omemoStore.getDateOfLastReceivedMessage(omemoManager, bob));
|
||||
Date now = new Date();
|
||||
omemoStore.setDateOfLastReceivedMessage(omemoManager, bob, now);
|
||||
assertEquals(now, omemoStore.getDateOfLastReceivedMessage(omemoManager, bob));
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -41,6 +41,6 @@ public class SignalOmemoStoreConnectorTest {
|
|||
@Test
|
||||
public void isTrustedIdentityTest() {
|
||||
SignalOmemoStoreConnector connector = new SignalOmemoStoreConnector(null, null);
|
||||
assertTrue("All identities must be trusted by default.", connector.isTrustedIdentity(null, null));
|
||||
assertTrue("All identities must be trusted by default.", connector.isTrustedIdentity(null, null, null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smack.omemo;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.OmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalCachingOmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalFileBasedOmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalOmemoKeyUtil;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.SessionCipher;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* smack-omemo-signal implementation of {@link OmemoStoreTest}.
|
||||
* This class executes tests of its super class with available implementations of {@link OmemoStore}.
|
||||
* So far this includes {@link SignalFileBasedOmemoStore}, {@link SignalCachingOmemoStore}.
|
||||
*/
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class SignalOmemoStoreTest extends OmemoStoreTest<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
|
||||
public SignalOmemoStoreTest(OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> store)
|
||||
throws XmppStringprepException {
|
||||
super(store);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are running this Test with multiple available OmemoStore implementations.
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@Parameterized.Parameters
|
||||
public static Collection<Object[]> getParameters() throws IOException {
|
||||
TemporaryFolder temp = initStaticTemp();
|
||||
return Arrays.asList(new Object[][] {
|
||||
// Simple file based store
|
||||
{ new SignalFileBasedOmemoStore(temp.newFolder("sigFileBased"))},
|
||||
// Ephemeral caching store
|
||||
{ new SignalCachingOmemoStore()},
|
||||
// Caching file based store
|
||||
{ new SignalCachingOmemoStore(new SignalFileBasedOmemoStore(temp.newFolder("cachingSigFileBased")))}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyUtilTest() {
|
||||
assertTrue(store.keyUtil() instanceof SignalOmemoKeyUtil);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue