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 3eb6f99b..34feaad7 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -25,7 +25,11 @@ import java.security.PrivateKey; import java.security.Security; import java.security.Signature; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -296,16 +300,20 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { return new AxolotlAddress(jid.toPreppedString(), 0); } - public Set findOwnSessions() { + public Collection findOwnSessions() { AxolotlAddress ownAddress = getAddressForJid(account.getJid().toBareJid()); - return new HashSet<>(this.sessions.getAll(ownAddress).values()); + ArrayList s = new ArrayList<>(this.sessions.getAll(ownAddress).values()); + Collections.sort(s); + return s; } - public Set findSessionsForContact(Contact contact) { + public Collection findSessionsForContact(Contact contact) { AxolotlAddress contactAddress = getAddressForJid(contact.getJid()); - return new HashSet<>(this.sessions.getAll(contactAddress).values()); + ArrayList s = new ArrayList<>(this.sessions.getAll(contactAddress).values()); + Collections.sort(s); + return s; } private Set findSessionsForConversation(Conversation conversation) { @@ -932,7 +940,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { account.getJid().toBareJid(), getOwnDeviceId()); Set remoteSessions = findSessionsForConversation(conversation); - Set ownSessions = findOwnSessions(); + Collection ownSessions = findOwnSessions(); if (remoteSessions.isEmpty()) { return null; } diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java index b594b5de..7830b317 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java @@ -3,10 +3,13 @@ package eu.siacs.conversations.crypto.axolotl; import android.content.ContentValues; import android.database.Cursor; -public class FingerprintStatus { +public class FingerprintStatus implements Comparable { + + private static final long DO_NOT_OVERWRITE = -1; private Trust trust = Trust.UNTRUSTED; private boolean active = false; + private long lastActivation = DO_NOT_OVERWRITE; @Override public boolean equals(Object o) { @@ -34,6 +37,9 @@ public class FingerprintStatus { final ContentValues contentValues = new ContentValues(); contentValues.put(SQLiteAxolotlStore.TRUST,trust.toString()); contentValues.put(SQLiteAxolotlStore.ACTIVE,active ? 1 : 0); + if (lastActivation != DO_NOT_OVERWRITE) { + contentValues.put(SQLiteAxolotlStore.LAST_ACTIVATION,lastActivation); + } return contentValues; } @@ -45,6 +51,7 @@ public class FingerprintStatus { status.trust = Trust.UNTRUSTED; } status.active = cursor.getInt(cursor.getColumnIndex(SQLiteAxolotlStore.ACTIVE)) > 0; + status.lastActivation = cursor.getLong(cursor.getColumnIndex(SQLiteAxolotlStore.LAST_ACTIVATION)); return status; } @@ -52,6 +59,7 @@ public class FingerprintStatus { final FingerprintStatus status = new FingerprintStatus(); status.trust = Trust.UNDECIDED; status.active = true; + status.lastActivation = System.currentTimeMillis(); return status; } @@ -92,6 +100,9 @@ public class FingerprintStatus { public FingerprintStatus toActive() { FingerprintStatus status = new FingerprintStatus(); status.trust = trust; + if (!status.active) { + status.lastActivation = System.currentTimeMillis(); + } status.active = true; return status; } @@ -128,6 +139,23 @@ public class FingerprintStatus { return status; } + @Override + public int compareTo(FingerprintStatus o) { + if (active == o.active) { + if (lastActivation > o.lastActivation) { + return -1; + } else if (lastActivation < o.lastActivation) { + return 1; + } else { + return 0; + } + } else if (active){ + return -1; + } else { + return 1; + } + } + public enum Trust { COMPROMISED, UNDECIDED, diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java index a3647be7..cd605248 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java @@ -38,6 +38,7 @@ public class SQLiteAxolotlStore implements AxolotlStore { public static final String TRUSTED = "trusted"; //no longer used public static final String TRUST = "trust"; public static final String ACTIVE = "active"; + public static final String LAST_ACTIVATION = "last_activation"; public static final String OWN = "ownkey"; public static final String CERTIFICATE = "certificate"; diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java index 0697f34c..725757a3 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java @@ -22,7 +22,7 @@ import org.whispersystems.libaxolotl.protocol.WhisperMessage; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; -public class XmppAxolotlSession { +public class XmppAxolotlSession implements Comparable { private final SessionCipher cipher; private final SQLiteAxolotlStore sqLiteAxolotlStore; private final AxolotlAddress remoteAddress; @@ -136,4 +136,9 @@ public class XmppAxolotlSession { public Account getAccount() { return account; } + + @Override + public int compareTo(XmppAxolotlSession o) { + return getTrust().compareTo(o.getTrust()); + } } diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 1e50ce9c..931c2279 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -55,7 +55,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 31; + private static final int DATABASE_VERSION = 32; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -132,6 +132,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + SQLiteAxolotlStore.CERTIFICATE + " BLOB, " + SQLiteAxolotlStore.TRUST + " TEXT, " + SQLiteAxolotlStore.ACTIVE + " NUMBER, " + + SQLiteAxolotlStore.LAST_ACTIVATION + " NUMBER," + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" + SQLiteAxolotlStore.ACCOUNT + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " @@ -377,6 +378,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { } } + if (oldVersion < 32 && newVersion >= 32) { + db.execSQL("ALTER TABLE "+ SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN "+SQLiteAxolotlStore.LAST_ACTIVATION + " NUMBER"); + ContentValues defaults = new ContentValues(); + defaults.put(SQLiteAxolotlStore.LAST_ACTIVATION,System.currentTimeMillis()); + db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME,defaults,null,null); + } } private static ContentValues createFingerprintStatusContentValues(FingerprintStatus.Trust trust, boolean active) { @@ -1046,6 +1053,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private Cursor getIdentityKeyCursor(SQLiteDatabase db, Account account, String name, Boolean own, String fingerprint) { String[] columns = {SQLiteAxolotlStore.TRUST, SQLiteAxolotlStore.ACTIVE, + SQLiteAxolotlStore.LAST_ACTIVATION, SQLiteAxolotlStore.KEY}; ArrayList selectionArgs = new ArrayList<>(4); selectionArgs.add(account.getUuid());