aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java879
1 files changed, 173 insertions, 706 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
index c6f74538a..255939a4f 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -6,28 +6,15 @@ import android.util.Log;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.whispersystems.libaxolotl.AxolotlAddress;
-import org.whispersystems.libaxolotl.DuplicateMessageException;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.libaxolotl.InvalidKeyIdException;
-import org.whispersystems.libaxolotl.InvalidMessageException;
-import org.whispersystems.libaxolotl.InvalidVersionException;
-import org.whispersystems.libaxolotl.LegacyMessageException;
-import org.whispersystems.libaxolotl.NoSessionException;
import org.whispersystems.libaxolotl.SessionBuilder;
-import org.whispersystems.libaxolotl.SessionCipher;
import org.whispersystems.libaxolotl.UntrustedIdentityException;
-import org.whispersystems.libaxolotl.ecc.Curve;
-import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
-import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
-import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
-import org.whispersystems.libaxolotl.protocol.WhisperMessage;
-import org.whispersystems.libaxolotl.state.AxolotlStore;
import org.whispersystems.libaxolotl.state.PreKeyBundle;
import org.whispersystems.libaxolotl.state.PreKeyRecord;
-import org.whispersystems.libaxolotl.state.SessionRecord;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
import org.whispersystems.libaxolotl.util.KeyHelper;
@@ -73,547 +60,6 @@ public class AxolotlService {
private final FetchStatusMap fetchStatusMap;
private final SerialSingleThreadExecutor executor;
- public static class SQLiteAxolotlStore implements AxolotlStore {
-
- public static final String PREKEY_TABLENAME = "prekeys";
- public static final String SIGNED_PREKEY_TABLENAME = "signed_prekeys";
- public static final String SESSION_TABLENAME = "sessions";
- public static final String IDENTITIES_TABLENAME = "identities";
- public static final String ACCOUNT = "account";
- public static final String DEVICE_ID = "device_id";
- public static final String ID = "id";
- public static final String KEY = "key";
- public static final String FINGERPRINT = "fingerprint";
- public static final String NAME = "name";
- public static final String TRUSTED = "trusted";
- public static final String OWN = "ownkey";
-
- public static final String JSONKEY_REGISTRATION_ID = "axolotl_reg_id";
- public static final String JSONKEY_CURRENT_PREKEY_ID = "axolotl_cur_prekey_id";
-
- private final Account account;
- private final XmppConnectionService mXmppConnectionService;
-
- private IdentityKeyPair identityKeyPair;
- private int localRegistrationId;
- private int currentPreKeyId = 0;
-
- public enum Trust {
- UNDECIDED(0),
- TRUSTED(1),
- UNTRUSTED(2),
- COMPROMISED(3),
- INACTIVE(4);
-
- private static final Map<Integer, Trust> trustsByValue = new HashMap<>();
-
- static {
- for (Trust trust : Trust.values()) {
- trustsByValue.put(trust.getCode(), trust);
- }
- }
-
- private final int code;
-
- Trust(int code){
- this.code = code;
- }
-
- public int getCode() {
- return this.code;
- }
-
- public String toString() {
- switch(this){
- case UNDECIDED:
- return "Trust undecided "+getCode();
- case TRUSTED:
- return "Trusted "+getCode();
- case COMPROMISED:
- return "Compromised "+getCode();
- case INACTIVE:
- return "Inactive "+getCode();
- case UNTRUSTED:
- default:
- return "Untrusted "+getCode();
- }
- }
-
- public static Trust fromBoolean(Boolean trusted) {
- return trusted?TRUSTED:UNTRUSTED;
- }
-
- public static Trust fromCode(int code) {
- return trustsByValue.get(code);
- }
- };
-
- private static IdentityKeyPair generateIdentityKeyPair() {
- Log.i(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Generating axolotl IdentityKeyPair...");
- ECKeyPair identityKeyPairKeys = Curve.generateKeyPair();
- IdentityKeyPair ownKey = new IdentityKeyPair(new IdentityKey(identityKeyPairKeys.getPublicKey()),
- identityKeyPairKeys.getPrivateKey());
- return ownKey;
- }
-
- private static int generateRegistrationId() {
- Log.i(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Generating axolotl registration ID...");
- int reg_id = KeyHelper.generateRegistrationId(true);
- return reg_id;
- }
-
- public SQLiteAxolotlStore(Account account, XmppConnectionService service) {
- this.account = account;
- this.mXmppConnectionService = service;
- this.localRegistrationId = loadRegistrationId();
- this.currentPreKeyId = loadCurrentPreKeyId();
- for (SignedPreKeyRecord record : loadSignedPreKeys()) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got Axolotl signed prekey record:" + record.getId());
- }
- }
-
- public int getCurrentPreKeyId() {
- return currentPreKeyId;
- }
-
- // --------------------------------------
- // IdentityKeyStore
- // --------------------------------------
-
- private IdentityKeyPair loadIdentityKeyPair() {
- String ownName = account.getJid().toBareJid().toString();
- IdentityKeyPair ownKey = mXmppConnectionService.databaseBackend.loadOwnIdentityKeyPair(account,
- ownName);
-
- if (ownKey != null) {
- return ownKey;
- } else {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Could not retrieve axolotl key for account " + ownName);
- ownKey = generateIdentityKeyPair();
- mXmppConnectionService.databaseBackend.storeOwnIdentityKeyPair(account, ownName, ownKey);
- }
- return ownKey;
- }
-
- private int loadRegistrationId() {
- return loadRegistrationId(false);
- }
-
- private int loadRegistrationId(boolean regenerate) {
- String regIdString = this.account.getKey(JSONKEY_REGISTRATION_ID);
- int reg_id;
- if (!regenerate && regIdString != null) {
- reg_id = Integer.valueOf(regIdString);
- } else {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Could not retrieve axolotl registration id for account " + account.getJid());
- reg_id = generateRegistrationId();
- boolean success = this.account.setKey(JSONKEY_REGISTRATION_ID, Integer.toString(reg_id));
- if (success) {
- mXmppConnectionService.databaseBackend.updateAccount(account);
- } else {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Failed to write new key to the database!");
- }
- }
- return reg_id;
- }
-
- private int loadCurrentPreKeyId() {
- String regIdString = this.account.getKey(JSONKEY_CURRENT_PREKEY_ID);
- int reg_id;
- if (regIdString != null) {
- reg_id = Integer.valueOf(regIdString);
- } else {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Could not retrieve current prekey id for account " + account.getJid());
- reg_id = 0;
- }
- return reg_id;
- }
-
- public void regenerate() {
- mXmppConnectionService.databaseBackend.wipeAxolotlDb(account);
- account.setKey(JSONKEY_CURRENT_PREKEY_ID, Integer.toString(0));
- identityKeyPair = loadIdentityKeyPair();
- localRegistrationId = loadRegistrationId(true);
- currentPreKeyId = 0;
- mXmppConnectionService.updateAccountUi();
- }
-
- /**
- * Get the local client's identity key pair.
- *
- * @return The local client's persistent identity key pair.
- */
- @Override
- public IdentityKeyPair getIdentityKeyPair() {
- if(identityKeyPair == null) {
- identityKeyPair = loadIdentityKeyPair();
- }
- return identityKeyPair;
- }
-
- /**
- * Return the local client's registration ID.
- * <p/>
- * Clients should maintain a registration ID, a random number
- * between 1 and 16380 that's generated once at install time.
- *
- * @return the local client's registration ID.
- */
- @Override
- public int getLocalRegistrationId() {
- return localRegistrationId;
- }
-
- /**
- * Save a remote client's identity key
- * <p/>
- * Store a remote client's identity key as trusted.
- *
- * @param name The name of the remote client.
- * @param identityKey The remote client's identity key.
- */
- @Override
- public void saveIdentity(String name, IdentityKey identityKey) {
- if(!mXmppConnectionService.databaseBackend.loadIdentityKeys(account, name).contains(identityKey)) {
- mXmppConnectionService.databaseBackend.storeIdentityKey(account, name, identityKey);
- }
- }
-
- /**
- * Verify a remote client's identity key.
- * <p/>
- * Determine whether a remote client's identity is trusted. Convention is
- * that the TextSecure protocol is 'trust on first use.' This means that
- * an identity key is considered 'trusted' if there is no entry for the recipient
- * in the local store, or if it matches the saved key for a recipient in the local
- * store. Only if it mismatches an entry in the local store is it considered
- * 'untrusted.'
- *
- * @param name The name of the remote client.
- * @param identityKey The identity key to verify.
- * @return true if trusted, false if untrusted.
- */
- @Override
- public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
- return true;
- }
-
- public Trust getFingerprintTrust(String fingerprint) {
- return mXmppConnectionService.databaseBackend.isIdentityKeyTrusted(account, fingerprint);
- }
-
- public void setFingerprintTrust(String fingerprint, Trust trust) {
- mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, fingerprint, trust);
- }
-
- public Set<IdentityKey> getContactUndecidedKeys(String bareJid, Trust trust) {
- return mXmppConnectionService.databaseBackend.loadIdentityKeys(account, bareJid, trust);
- }
-
- public long getContactNumTrustedKeys(String bareJid) {
- return mXmppConnectionService.databaseBackend.numTrustedKeys(account, bareJid);
- }
-
- // --------------------------------------
- // SessionStore
- // --------------------------------------
-
- /**
- * Returns a copy of the {@link SessionRecord} corresponding to the recipientId + deviceId tuple,
- * or a new SessionRecord if one does not currently exist.
- * <p/>
- * It is important that implementations return a copy of the current durable information. The
- * returned SessionRecord may be modified, but those changes should not have an effect on the
- * durable session state (what is returned by subsequent calls to this method) without the
- * store method being called here first.
- *
- * @param address The name and device ID of the remote client.
- * @return a copy of the SessionRecord corresponding to the recipientId + deviceId tuple, or
- * a new SessionRecord if one does not currently exist.
- */
- @Override
- public SessionRecord loadSession(AxolotlAddress address) {
- SessionRecord session = mXmppConnectionService.databaseBackend.loadSession(this.account, address);
- return (session != null) ? session : new SessionRecord();
- }
-
- /**
- * Returns all known devices with active sessions for a recipient
- *
- * @param name the name of the client.
- * @return all known sub-devices with active sessions.
- */
- @Override
- public List<Integer> getSubDeviceSessions(String name) {
- return mXmppConnectionService.databaseBackend.getSubDeviceSessions(account,
- new AxolotlAddress(name, 0));
- }
-
- /**
- * Commit to storage the {@link SessionRecord} for a given recipientId + deviceId tuple.
- *
- * @param address the address of the remote client.
- * @param record the current SessionRecord for the remote client.
- */
- @Override
- public void storeSession(AxolotlAddress address, SessionRecord record) {
- mXmppConnectionService.databaseBackend.storeSession(account, address, record);
- }
-
- /**
- * Determine whether there is a committed {@link SessionRecord} for a recipientId + deviceId tuple.
- *
- * @param address the address of the remote client.
- * @return true if a {@link SessionRecord} exists, false otherwise.
- */
- @Override
- public boolean containsSession(AxolotlAddress address) {
- return mXmppConnectionService.databaseBackend.containsSession(account, address);
- }
-
- /**
- * Remove a {@link SessionRecord} for a recipientId + deviceId tuple.
- *
- * @param address the address of the remote client.
- */
- @Override
- public void deleteSession(AxolotlAddress address) {
- mXmppConnectionService.databaseBackend.deleteSession(account, address);
- }
-
- /**
- * Remove the {@link SessionRecord}s corresponding to all devices of a recipientId.
- *
- * @param name the name of the remote client.
- */
- @Override
- public void deleteAllSessions(String name) {
- mXmppConnectionService.databaseBackend.deleteAllSessions(account,
- new AxolotlAddress(name, 0));
- }
-
- // --------------------------------------
- // PreKeyStore
- // --------------------------------------
-
- /**
- * Load a local PreKeyRecord.
- *
- * @param preKeyId the ID of the local PreKeyRecord.
- * @return the corresponding PreKeyRecord.
- * @throws InvalidKeyIdException when there is no corresponding PreKeyRecord.
- */
- @Override
- public PreKeyRecord loadPreKey(int preKeyId) throws InvalidKeyIdException {
- PreKeyRecord record = mXmppConnectionService.databaseBackend.loadPreKey(account, preKeyId);
- if (record == null) {
- throw new InvalidKeyIdException("No such PreKeyRecord: " + preKeyId);
- }
- return record;
- }
-
- /**
- * Store a local PreKeyRecord.
- *
- * @param preKeyId the ID of the PreKeyRecord to store.
- * @param record the PreKeyRecord.
- */
- @Override
- public void storePreKey(int preKeyId, PreKeyRecord record) {
- mXmppConnectionService.databaseBackend.storePreKey(account, record);
- currentPreKeyId = preKeyId;
- boolean success = this.account.setKey(JSONKEY_CURRENT_PREKEY_ID, Integer.toString(preKeyId));
- if (success) {
- mXmppConnectionService.databaseBackend.updateAccount(account);
- } else {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Failed to write new prekey id to the database!");
- }
- }
-
- /**
- * @param preKeyId A PreKeyRecord ID.
- * @return true if the store has a record for the preKeyId, otherwise false.
- */
- @Override
- public boolean containsPreKey(int preKeyId) {
- return mXmppConnectionService.databaseBackend.containsPreKey(account, preKeyId);
- }
-
- /**
- * Delete a PreKeyRecord from local storage.
- *
- * @param preKeyId The ID of the PreKeyRecord to remove.
- */
- @Override
- public void removePreKey(int preKeyId) {
- mXmppConnectionService.databaseBackend.deletePreKey(account, preKeyId);
- }
-
- // --------------------------------------
- // SignedPreKeyStore
- // --------------------------------------
-
- /**
- * Load a local SignedPreKeyRecord.
- *
- * @param signedPreKeyId the ID of the local SignedPreKeyRecord.
- * @return the corresponding SignedPreKeyRecord.
- * @throws InvalidKeyIdException when there is no corresponding SignedPreKeyRecord.
- */
- @Override
- public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException {
- SignedPreKeyRecord record = mXmppConnectionService.databaseBackend.loadSignedPreKey(account, signedPreKeyId);
- if (record == null) {
- throw new InvalidKeyIdException("No such SignedPreKeyRecord: " + signedPreKeyId);
- }
- return record;
- }
-
- /**
- * Load all local SignedPreKeyRecords.
- *
- * @return All stored SignedPreKeyRecords.
- */
- @Override
- public List<SignedPreKeyRecord> loadSignedPreKeys() {
- return mXmppConnectionService.databaseBackend.loadSignedPreKeys(account);
- }
-
- /**
- * Store a local SignedPreKeyRecord.
- *
- * @param signedPreKeyId the ID of the SignedPreKeyRecord to store.
- * @param record the SignedPreKeyRecord.
- */
- @Override
- public void storeSignedPreKey(int signedPreKeyId, SignedPreKeyRecord record) {
- mXmppConnectionService.databaseBackend.storeSignedPreKey(account, record);
- }
-
- /**
- * @param signedPreKeyId A SignedPreKeyRecord ID.
- * @return true if the store has a record for the signedPreKeyId, otherwise false.
- */
- @Override
- public boolean containsSignedPreKey(int signedPreKeyId) {
- return mXmppConnectionService.databaseBackend.containsSignedPreKey(account, signedPreKeyId);
- }
-
- /**
- * Delete a SignedPreKeyRecord from local storage.
- *
- * @param signedPreKeyId The ID of the SignedPreKeyRecord to remove.
- */
- @Override
- public void removeSignedPreKey(int signedPreKeyId) {
- mXmppConnectionService.databaseBackend.deleteSignedPreKey(account, signedPreKeyId);
- }
- }
-
- public static class XmppAxolotlSession {
- private final SessionCipher cipher;
- private Integer preKeyId = null;
- private final SQLiteAxolotlStore sqLiteAxolotlStore;
- private final AxolotlAddress remoteAddress;
- private final Account account;
- private String fingerprint = null;
-
- public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress, String fingerprint) {
- this(account, store, remoteAddress);
- this.fingerprint = fingerprint;
- }
-
- public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress) {
- this.cipher = new SessionCipher(store, remoteAddress);
- this.remoteAddress = remoteAddress;
- this.sqLiteAxolotlStore = store;
- this.account = account;
- }
-
- public Integer getPreKeyId() {
- return preKeyId;
- }
-
- public void resetPreKeyId() {
-
- preKeyId = null;
- }
-
- public String getFingerprint() {
- return fingerprint;
- }
-
- protected void setTrust(SQLiteAxolotlStore.Trust trust) {
- sqLiteAxolotlStore.setFingerprintTrust(fingerprint, trust);
- }
-
- protected SQLiteAxolotlStore.Trust getTrust() {
- return sqLiteAxolotlStore.getFingerprintTrust(fingerprint);
- }
-
- @Nullable
- public byte[] processReceiving(XmppAxolotlMessage.XmppAxolotlMessageHeader incomingHeader) {
- byte[] plaintext = null;
- SQLiteAxolotlStore.Trust trust = getTrust();
- switch (trust) {
- case INACTIVE:
- case UNDECIDED:
- case UNTRUSTED:
- case TRUSTED:
- try {
- try {
- PreKeyWhisperMessage message = new PreKeyWhisperMessage(incomingHeader.getContents());
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId());
- String fingerprint = message.getIdentityKey().getFingerprint().replaceAll("\\s", "");
- if (this.fingerprint != null && !this.fingerprint.equals(fingerprint)) {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Had session with fingerprint "+ this.fingerprint+", received message with fingerprint "+fingerprint);
- } else {
- this.fingerprint = fingerprint;
- plaintext = cipher.decrypt(message);
- if (message.getPreKeyId().isPresent()) {
- preKeyId = message.getPreKeyId().get();
- }
- }
- } catch (InvalidMessageException | InvalidVersionException e) {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"WhisperMessage received");
- WhisperMessage message = new WhisperMessage(incomingHeader.getContents());
- plaintext = cipher.decrypt(message);
- } catch (InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
- }
- } catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error decrypting axolotl header, "+e.getClass().getName()+": " + e.getMessage());
- }
-
- if (plaintext != null && trust == SQLiteAxolotlStore.Trust.INACTIVE) {
- setTrust(SQLiteAxolotlStore.Trust.TRUSTED);
- }
-
- break;
-
- case COMPROMISED:
- default:
- // ignore
- break;
- }
- return plaintext;
- }
-
- @Nullable
- public XmppAxolotlMessage.XmppAxolotlMessageHeader processSending(@NonNull byte[] outgoingMessage) {
- SQLiteAxolotlStore.Trust trust = getTrust();
- if (trust == SQLiteAxolotlStore.Trust.TRUSTED) {
- CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
- XmppAxolotlMessage.XmppAxolotlMessageHeader header =
- new XmppAxolotlMessage.XmppAxolotlMessageHeader(remoteAddress.getDeviceId(),
- ciphertextMessage.serialize());
- return header;
- } else {
- return null;
- }
- }
- }
-
private static class AxolotlAddressMap<T> {
protected Map<String, Map<Integer, T>> map;
protected final Object MAP_LOCK = new Object();
@@ -680,7 +126,7 @@ public class AxolotlService {
private void putDevicesForJid(String bareJid, List<Integer> deviceIds, SQLiteAxolotlStore store) {
for (Integer deviceId : deviceIds) {
AxolotlAddress axolotlAddress = new AxolotlAddress(bareJid, deviceId);
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building session for remote address: "+axolotlAddress.toString());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building session for remote address: " + axolotlAddress.toString());
String fingerprint = store.loadSession(axolotlAddress).getSessionState().getRemoteIdentityKey().getFingerprint().replaceAll("\\s", "");
this.put(axolotlAddress, new XmppAxolotlSession(account, store, axolotlAddress, fingerprint));
}
@@ -704,8 +150,13 @@ public class AxolotlService {
@Override
public void put(AxolotlAddress address, XmppAxolotlSession value) {
super.put(address, value);
+ value.setNotFresh();
xmppConnectionService.syncRosterToDisk(account);
}
+
+ public void put(XmppAxolotlSession session) {
+ this.put(session.getRemoteAddress(), session);
+ }
}
private static enum FetchStatus {
@@ -717,9 +168,9 @@ public class AxolotlService {
private static class FetchStatusMap extends AxolotlAddressMap<FetchStatus> {
}
-
+
public static String getLogprefix(Account account) {
- return LOGPREFIX+" ("+account.getJid().toBareJid().toString()+"): ";
+ return LOGPREFIX + " (" + account.getJid().toBareJid().toString() + "): ";
}
public AxolotlService(Account account, XmppConnectionService connectionService) {
@@ -740,12 +191,12 @@ public class AxolotlService {
return axolotlStore.getIdentityKeyPair().getPublicKey();
}
- public Set<IdentityKey> getKeysWithTrust(SQLiteAxolotlStore.Trust trust) {
- return axolotlStore.getContactUndecidedKeys(account.getJid().toBareJid().toString(), trust);
+ public Set<IdentityKey> getKeysWithTrust(XmppAxolotlSession.Trust trust) {
+ return axolotlStore.getContactKeysWithTrust(account.getJid().toBareJid().toString(), trust);
}
- public Set<IdentityKey> getKeysWithTrust(SQLiteAxolotlStore.Trust trust, Contact contact) {
- return axolotlStore.getContactUndecidedKeys(contact.getJid().toBareJid().toString(), trust);
+ public Set<IdentityKey> getKeysWithTrust(XmppAxolotlSession.Trust trust, Contact contact) {
+ return axolotlStore.getContactKeysWithTrust(contact.getJid().toBareJid().toString(), trust);
}
public long getNumTrustedKeys(Contact contact) {
@@ -782,7 +233,7 @@ public class AxolotlService {
}
public int getOwnDeviceId() {
- return axolotlStore.loadRegistrationId();
+ return axolotlStore.getLocalRegistrationId();
}
public Set<Integer> getOwnDeviceIds() {
@@ -790,9 +241,9 @@ public class AxolotlService {
}
private void setTrustOnSessions(final Jid jid, @NonNull final Set<Integer> deviceIds,
- final SQLiteAxolotlStore.Trust from,
- final SQLiteAxolotlStore.Trust to) {
- for(Integer deviceId:deviceIds) {
+ final XmppAxolotlSession.Trust from,
+ final XmppAxolotlSession.Trust to) {
+ for (Integer deviceId : deviceIds) {
AxolotlAddress address = new AxolotlAddress(jid.toBareJid().toString(), deviceId);
XmppAxolotlSession session = sessions.get(address);
if (session != null && session.getFingerprint() != null
@@ -803,24 +254,32 @@ public class AxolotlService {
}
public void registerDevices(final Jid jid, @NonNull final Set<Integer> deviceIds) {
- if(jid.toBareJid().equals(account.getJid().toBareJid())) {
+ if (jid.toBareJid().equals(account.getJid().toBareJid())) {
if (deviceIds.contains(getOwnDeviceId())) {
deviceIds.remove(getOwnDeviceId());
}
- for(Integer deviceId : deviceIds) {
- AxolotlAddress ownDeviceAddress = new AxolotlAddress(jid.toBareJid().toString(),deviceId);
- if(sessions.get(ownDeviceAddress) == null) {
- buildSessionFromPEP(null, ownDeviceAddress, false);
+ for (Integer deviceId : deviceIds) {
+ AxolotlAddress ownDeviceAddress = new AxolotlAddress(jid.toBareJid().toString(), deviceId);
+ if (sessions.get(ownDeviceAddress) == null) {
+ buildSessionFromPEP(ownDeviceAddress);
}
}
}
Set<Integer> expiredDevices = new HashSet<>(axolotlStore.getSubDeviceSessions(jid.toBareJid().toString()));
expiredDevices.removeAll(deviceIds);
- setTrustOnSessions(jid, expiredDevices, SQLiteAxolotlStore.Trust.TRUSTED,
- SQLiteAxolotlStore.Trust.INACTIVE);
+ setTrustOnSessions(jid, expiredDevices, XmppAxolotlSession.Trust.TRUSTED,
+ XmppAxolotlSession.Trust.INACTIVE_TRUSTED);
+ setTrustOnSessions(jid, expiredDevices, XmppAxolotlSession.Trust.UNDECIDED,
+ XmppAxolotlSession.Trust.INACTIVE_UNDECIDED);
+ setTrustOnSessions(jid, expiredDevices, XmppAxolotlSession.Trust.UNTRUSTED,
+ XmppAxolotlSession.Trust.INACTIVE_UNTRUSTED);
Set<Integer> newDevices = new HashSet<>(deviceIds);
- setTrustOnSessions(jid, newDevices, SQLiteAxolotlStore.Trust.INACTIVE,
- SQLiteAxolotlStore.Trust.TRUSTED);
+ setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_TRUSTED,
+ XmppAxolotlSession.Trust.TRUSTED);
+ setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_UNDECIDED,
+ XmppAxolotlSession.Trust.UNDECIDED);
+ setTrustOnSessions(jid, newDevices, XmppAxolotlSession.Trust.INACTIVE_UNTRUSTED,
+ XmppAxolotlSession.Trust.UNTRUSTED);
this.deviceIds.put(jid, deviceIds);
mXmppConnectionService.keyStatusUpdated();
publishOwnDeviceIdIfNeeded();
@@ -830,7 +289,7 @@ public class AxolotlService {
Set<Integer> deviceIds = new HashSet<>();
deviceIds.add(getOwnDeviceId());
IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Wiping all other devices from Pep:" + publish);
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Wiping all other devices from Pep:" + publish);
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
@@ -840,7 +299,7 @@ public class AxolotlService {
}
public void purgeKey(IdentityKey identityKey) {
- axolotlStore.setFingerprintTrust(identityKey.getFingerprint().replaceAll("\\s",""), SQLiteAxolotlStore.Trust.COMPROMISED);
+ axolotlStore.setFingerprintTrust(identityKey.getFingerprint().replaceAll("\\s", ""), XmppAxolotlSession.Trust.COMPROMISED);
}
public void publishOwnDeviceIdIfNeeded() {
@@ -856,7 +315,7 @@ public class AxolotlService {
if (!deviceIds.contains(getOwnDeviceId())) {
deviceIds.add(getOwnDeviceId());
IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIds);
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist. Publishing: " + publish);
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
@@ -877,19 +336,19 @@ public class AxolotlService {
Map<Integer, ECPublicKey> keys = mXmppConnectionService.getIqParser().preKeyPublics(packet);
boolean flush = false;
if (bundle == null) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Received invalid bundle:" + packet);
- bundle = new PreKeyBundle(-1, -1, -1 , null, -1, null, null, null);
+ Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid bundle:" + packet);
+ bundle = new PreKeyBundle(-1, -1, -1, null, -1, null, null, null);
flush = true;
}
if (keys == null) {
- Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Received invalid prekeys:" + packet);
+ Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received invalid prekeys:" + packet);
}
try {
boolean changed = false;
// Validate IdentityKey
IdentityKeyPair identityKeyPair = axolotlStore.getIdentityKeyPair();
if (flush || !identityKeyPair.getPublicKey().equals(bundle.getIdentityKey())) {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Adding own IdentityKey " + identityKeyPair.getPublicKey() + " to PEP.");
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding own IdentityKey " + identityKeyPair.getPublicKey() + " to PEP.");
changed = true;
}
@@ -898,16 +357,16 @@ public class AxolotlService {
int numSignedPreKeys = axolotlStore.loadSignedPreKeys().size();
try {
signedPreKeyRecord = axolotlStore.loadSignedPreKey(bundle.getSignedPreKeyId());
- if ( flush
- ||!bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey())
+ if (flush
+ || !bundle.getSignedPreKey().equals(signedPreKeyRecord.getKeyPair().getPublicKey())
|| !Arrays.equals(bundle.getSignedPreKeySignature(), signedPreKeyRecord.getSignature())) {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
changed = true;
}
} catch (InvalidKeyIdException e) {
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding new signedPreKey with ID " + (numSignedPreKeys + 1) + " to PEP.");
signedPreKeyRecord = KeyHelper.generateSignedPreKey(identityKeyPair, numSignedPreKeys + 1);
axolotlStore.storeSignedPreKey(signedPreKeyRecord.getId(), signedPreKeyRecord);
changed = true;
@@ -929,32 +388,32 @@ public class AxolotlService {
int newKeys = NUM_KEYS_TO_PUBLISH - preKeyRecords.size();
if (newKeys > 0) {
List<PreKeyRecord> newRecords = KeyHelper.generatePreKeys(
- axolotlStore.getCurrentPreKeyId()+1, newKeys);
+ axolotlStore.getCurrentPreKeyId() + 1, newKeys);
preKeyRecords.addAll(newRecords);
for (PreKeyRecord record : newRecords) {
axolotlStore.storePreKey(record.getId(), record);
}
changed = true;
- Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Adding " + newKeys + " new preKeys to PEP.");
+ Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Adding " + newKeys + " new preKeys to PEP.");
}
- if(changed) {
+ if (changed) {
IqPacket publish = mXmppConnectionService.getIqGenerator().publishBundles(
signedPreKeyRecord, axolotlStore.getIdentityKeyPair().getPublicKey(),
preKeyRecords, getOwnDeviceId());
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+ ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": Bundle " + getOwnDeviceId() + " in PEP not current. Publishing: " + publish);
mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
// TODO: implement this!
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Published bundle, got: " + packet);
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Published bundle, got: " + packet);
}
});
}
} catch (InvalidKeyException e) {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
- return;
+ Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Failed to publish bundle " + getOwnDeviceId() + ", reason: " + e.getMessage());
+ return;
}
}
});
@@ -965,49 +424,41 @@ public class AxolotlService {
Jid jid = contact.getJid().toBareJid();
AxolotlAddress address = new AxolotlAddress(jid.toString(), 0);
return sessions.hasAny(address) ||
- ( deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty());
+ (deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty());
}
- public SQLiteAxolotlStore.Trust getFingerprintTrust(String fingerprint) {
+
+ public XmppAxolotlSession.Trust getFingerprintTrust(String fingerprint) {
return axolotlStore.getFingerprintTrust(fingerprint);
}
- public void setFingerprintTrust(String fingerprint, SQLiteAxolotlStore.Trust trust) {
+ public void setFingerprintTrust(String fingerprint, XmppAxolotlSession.Trust trust) {
axolotlStore.setFingerprintTrust(fingerprint, trust);
}
- private void buildSessionFromPEP(final Conversation conversation, final AxolotlAddress address, final boolean flushWaitingQueueAfterFetch) {
+ private void buildSessionFromPEP(final AxolotlAddress address) {
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building new sesstion for " + address.getDeviceId());
try {
IqPacket bundlesPacket = mXmppConnectionService.getIqGenerator().retrieveBundlesForDevice(
Jid.fromString(address.getName()), address.getDeviceId());
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Retrieving bundle: " + bundlesPacket);
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Retrieving bundle: " + bundlesPacket);
mXmppConnectionService.sendIqPacket(account, bundlesPacket, new OnIqPacketReceived() {
private void finish() {
- AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(),0);
+ AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0);
if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
&& !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) {
- if (flushWaitingQueueAfterFetch && conversation != null) {
- conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_AXOLOTL,
- new Conversation.OnMessageFound() {
- @Override
- public void onMessageFound(Message message) {
- processSending(message,false);
- }
- });
- }
mXmppConnectionService.keyStatusUpdated();
}
}
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Received preKey IQ packet, processing...");
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received preKey IQ packet, processing...");
final IqParser parser = mXmppConnectionService.getIqParser();
final List<PreKeyBundle> preKeyBundleList = parser.preKeys(packet);
final PreKeyBundle bundle = parser.bundle(packet);
if (preKeyBundleList.isEmpty() || bundle == null) {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"preKey IQ packet invalid: " + packet);
+ Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "preKey IQ packet invalid: " + packet);
fetchStatusMap.put(address, FetchStatus.ERROR);
finish();
return;
@@ -1034,8 +485,8 @@ public class AxolotlService {
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, bundle.getIdentityKey().getFingerprint().replaceAll("\\s", ""));
sessions.put(address, session);
fetchStatusMap.put(address, FetchStatus.SUCCESS);
- } catch (UntrustedIdentityException|InvalidKeyException e) {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Error building session for " + address + ": "
+ } catch (UntrustedIdentityException | InvalidKeyException e) {
+ Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error building session for " + address + ": "
+ e.getClass().getName() + ", " + e.getMessage());
fetchStatusMap.put(address, FetchStatus.ERROR);
}
@@ -1044,7 +495,7 @@ public class AxolotlService {
}
});
} catch (InvalidJidException e) {
- Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got address with invalid jid: " + address.getName());
+ Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Got address with invalid jid: " + address.getName());
}
}
@@ -1052,13 +503,13 @@ public class AxolotlService {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Finding devices without session for " + conversation.getContact().getJid().toBareJid());
Jid contactJid = conversation.getContact().getJid().toBareJid();
Set<AxolotlAddress> addresses = new HashSet<>();
- if(deviceIds.get(contactJid) != null) {
- for(Integer foreignId:this.deviceIds.get(contactJid)) {
+ if (deviceIds.get(contactJid) != null) {
+ for (Integer foreignId : this.deviceIds.get(contactJid)) {
AxolotlAddress address = new AxolotlAddress(contactJid.toString(), foreignId);
- if(sessions.get(address) == null) {
+ if (sessions.get(address) == null) {
IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
- if ( identityKey != null ) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already have session for " + address.toString() + ", adding to cache...");
+ if (identityKey != null) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Already have session for " + address.toString() + ", adding to cache...");
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey.getFingerprint().replaceAll("\\s", ""));
sessions.put(address, session);
} else {
@@ -1070,13 +521,13 @@ public class AxolotlService {
} else {
Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Have no target devices in PEP!");
}
- if(deviceIds.get(account.getJid().toBareJid()) != null) {
- for(Integer ownId:this.deviceIds.get(account.getJid().toBareJid())) {
+ if (deviceIds.get(account.getJid().toBareJid()) != null) {
+ for (Integer ownId : this.deviceIds.get(account.getJid().toBareJid())) {
AxolotlAddress address = new AxolotlAddress(account.getJid().toBareJid().toString(), ownId);
- if(sessions.get(address) == null) {
+ if (sessions.get(address) == null) {
IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
- if ( identityKey != null ) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already have session for " + address.toString() + ", adding to cache...");
+ if (identityKey != null) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Already have session for " + address.toString() + ", adding to cache...");
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, identityKey.getFingerprint().replaceAll("\\s", ""));
sessions.put(address, session);
} else {
@@ -1090,19 +541,21 @@ public class AxolotlService {
return addresses;
}
- public boolean createSessionsIfNeeded(final Conversation conversation, final boolean flushWaitingQueueAfterFetch) {
+ public boolean createSessionsIfNeeded(final Conversation conversation) {
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Creating axolotl sessions if needed...");
boolean newSessions = false;
Set<AxolotlAddress> addresses = findDevicesWithoutSession(conversation);
for (AxolotlAddress address : addresses) {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Processing device: " + address.toString());
FetchStatus status = fetchStatusMap.get(address);
- if ( status == null || status == FetchStatus.ERROR ) {
- fetchStatusMap.put(address, FetchStatus.PENDING);
- this.buildSessionFromPEP(conversation, address, flushWaitingQueueAfterFetch);
- newSessions = true;
+ if (status == null || status == FetchStatus.ERROR) {
+ fetchStatusMap.put(address, FetchStatus.PENDING);
+ this.buildSessionFromPEP(address);
+ newSessions = true;
+ } else if (status == FetchStatus.PENDING) {
+ newSessions = true;
} else {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Already fetching bundle for " + address.toString());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Already fetching bundle for " + address.toString());
}
}
@@ -1110,56 +563,60 @@ public class AxolotlService {
}
public boolean hasPendingKeyFetches(Conversation conversation) {
- AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(),0);
- AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(),0);
+ AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0);
+ AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(), 0);
return fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
- ||fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING);
+ || fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING);
}
@Nullable
- public XmppAxolotlMessage encrypt(Message message ){
- final String content;
- if (message.hasFileOnRemoteHost()) {
- content = message.getFileParams().url.toString();
- } else {
- content = message.getBody();
- }
- final XmppAxolotlMessage axolotlMessage;
- try {
- axolotlMessage = new XmppAxolotlMessage(message.getContact().getJid().toBareJid(),
- getOwnDeviceId(), content);
- } catch (CryptoFailedException e) {
- Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to encrypt message: " + e.getMessage());
- return null;
- }
+ private XmppAxolotlMessage buildHeader(Contact contact) {
+ final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage(
+ contact.getJid().toBareJid(), getOwnDeviceId());
- if(findSessionsforContact(message.getContact()).isEmpty()) {
+ Set<XmppAxolotlSession> contactSessions = findSessionsforContact(contact);
+ Set<XmppAxolotlSession> ownSessions = findOwnSessions();
+ if (contactSessions.isEmpty()) {
return null;
}
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building axolotl foreign headers...");
- for (XmppAxolotlSession session : findSessionsforContact(message.getContact())) {
- Log.v(Config.LOGTAG, AxolotlService.getLogprefix(account)+session.remoteAddress.toString());
- //if(!session.isTrusted()) {
- // TODO: handle this properly
- // continue;
- // }
- axolotlMessage.addHeader(session.processSending(axolotlMessage.getInnerKey()));
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building axolotl foreign keyElements...");
+ for (XmppAxolotlSession session : contactSessions) {
+ Log.v(Config.LOGTAG, AxolotlService.getLogprefix(account) + session.getRemoteAddress().toString());
+ axolotlMessage.addDevice(session);
}
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building axolotl own headers...");
- for (XmppAxolotlSession session : findOwnSessions()) {
- Log.v(Config.LOGTAG, AxolotlService.getLogprefix(account)+session.remoteAddress.toString());
- // if(!session.isTrusted()) {
- // TODO: handle this properly
- // continue;
- // }
- axolotlMessage.addHeader(session.processSending(axolotlMessage.getInnerKey()));
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building axolotl own keyElements...");
+ for (XmppAxolotlSession session : ownSessions) {
+ Log.v(Config.LOGTAG, AxolotlService.getLogprefix(account) + session.getRemoteAddress().toString());
+ axolotlMessage.addDevice(session);
+ }
+
+ return axolotlMessage;
+ }
+
+ @Nullable
+ public XmppAxolotlMessage encrypt(Message message) {
+ XmppAxolotlMessage axolotlMessage = buildHeader(message.getContact());
+
+ if (axolotlMessage != null) {
+ final String content;
+ if (message.hasFileOnRemoteHost()) {
+ content = message.getFileParams().url.toString();
+ } else {
+ content = message.getBody();
+ }
+ try {
+ axolotlMessage.encrypt(content);
+ } catch (CryptoFailedException e) {
+ Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to encrypt message: " + e.getMessage());
+ return null;
+ }
}
return axolotlMessage;
}
- private void processSending(final Message message, final boolean delay) {
+ public void preparePayloadMessage(final Message message, final boolean delay) {
executor.execute(new Runnable() {
@Override
public void run() {
@@ -1168,79 +625,89 @@ public class AxolotlService {
mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED);
//mXmppConnectionService.updateConversationUi();
} else {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Generated message, caching: " + message.getUuid());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Generated message, caching: " + message.getUuid());
messageCache.put(message.getUuid(), axolotlMessage);
- mXmppConnectionService.resendMessage(message,delay);
+ mXmppConnectionService.resendMessage(message, delay);
}
}
});
}
- public void prepareMessage(final Message message,final boolean delay) {
- if (!messageCache.containsKey(message.getUuid())) {
- boolean newSessions = createSessionsIfNeeded(message.getConversation(), true);
- if (!newSessions) {
- this.processSending(message,delay);
+ public void prepareKeyTransportMessage(final Contact contact, final OnMessageCreatedCallback onMessageCreatedCallback) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ XmppAxolotlMessage axolotlMessage = buildHeader(contact);
+ onMessageCreatedCallback.run(axolotlMessage);
}
- }
+ });
}
public XmppAxolotlMessage fetchAxolotlMessageFromCache(Message message) {
XmppAxolotlMessage axolotlMessage = messageCache.get(message.getUuid());
if (axolotlMessage != null) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Cache hit: " + message.getUuid());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Cache hit: " + message.getUuid());
messageCache.remove(message.getUuid());
} else {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Cache miss: " + message.getUuid());
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Cache miss: " + message.getUuid());
}
return axolotlMessage;
}
- public XmppAxolotlMessage.XmppAxolotlPlaintextMessage processReceiving(XmppAxolotlMessage message) {
- XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintextMessage = null;
+ private XmppAxolotlSession recreateUncachedSession(AxolotlAddress address) {
+ IdentityKey identityKey = axolotlStore.loadSession(address).getSessionState().getRemoteIdentityKey();
+ return (identityKey != null)
+ ? new XmppAxolotlSession(account, axolotlStore, address,
+ identityKey.getFingerprint().replaceAll("\\s", ""))
+ : null;
+ }
+
+ private XmppAxolotlSession getReceivingSession(XmppAxolotlMessage message) {
AxolotlAddress senderAddress = new AxolotlAddress(message.getFrom().toString(),
message.getSenderDeviceId());
-
- boolean newSession = false;
XmppAxolotlSession session = sessions.get(senderAddress);
if (session == null) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Account: "+account.getJid()+" No axolotl session found while parsing received message " + message);
- // TODO: handle this properly
- IdentityKey identityKey = axolotlStore.loadSession(senderAddress).getSessionState().getRemoteIdentityKey();
- if ( identityKey != null ) {
- session = new XmppAxolotlSession(account, axolotlStore, senderAddress, identityKey.getFingerprint().replaceAll("\\s", ""));
- } else {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Account: " + account.getJid() + " No axolotl session found while parsing received message " + message);
+ session = recreateUncachedSession(senderAddress);
+ if (session == null) {
session = new XmppAxolotlSession(account, axolotlStore, senderAddress);
}
- newSession = true;
}
+ return session;
+ }
- for (XmppAxolotlMessage.XmppAxolotlMessageHeader header : message.getHeaders()) {
- if (header.getRecipientDeviceId() == getOwnDeviceId()) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Found axolotl header matching own device ID, processing...");
- byte[] payloadKey = session.processReceiving(header);
- if (payloadKey != null) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got payload key from axolotl header. Decrypting message...");
- try{
- plaintextMessage = message.decrypt(session, payloadKey, session.getFingerprint());
- } catch (CryptoFailedException e) {
- Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to decrypt message: " + e.getMessage());
- break;
- }
- }
- Integer preKeyId = session.getPreKeyId();
- if (preKeyId != null) {
- publishBundlesIfNeeded();
- session.resetPreKeyId();
- }
- break;
+ public XmppAxolotlMessage.XmppAxolotlPlaintextMessage processReceivingPayloadMessage(XmppAxolotlMessage message) {
+ XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintextMessage = null;
+
+ XmppAxolotlSession session = getReceivingSession(message);
+ try {
+ plaintextMessage = message.decrypt(session, getOwnDeviceId());
+ Integer preKeyId = session.getPreKeyId();
+ if (preKeyId != null) {
+ publishBundlesIfNeeded();
+ session.resetPreKeyId();
}
+ } catch (CryptoFailedException e) {
+ Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to decrypt message: " + e.getMessage());
}
- if (newSession && plaintextMessage != null) {
- sessions.put(senderAddress, session);
+ if (session.isFresh() && plaintextMessage != null) {
+ sessions.put(session);
}
return plaintextMessage;
}
+
+ public XmppAxolotlMessage.XmppAxolotlKeyTransportMessage processReceivingKeyTransportMessage(XmppAxolotlMessage message) {
+ XmppAxolotlMessage.XmppAxolotlKeyTransportMessage keyTransportMessage = null;
+
+ XmppAxolotlSession session = getReceivingSession(message);
+ keyTransportMessage = message.getParameters(session, getOwnDeviceId());
+
+ if (session.isFresh() && keyTransportMessage != null) {
+ sessions.put(session);
+ }
+
+ return keyTransportMessage;
+ }
}