Only show that have sessions in fingerprint list

Andreas Straub created

Doesn't access database directly anymore but goes through AxolotlService
now to obtain list of fingerprints associated with an Account/Contact.
This should prevent orphaned keys littering the UI which previously
couldn't be removed through the Clear Devices function.

Together with 1c79982da84964c1d81179a0927d9cd1eadf53de this fixes #1393

Change summary

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java     | 24 
src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java |  2 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java    |  4 
src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java         |  8 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java            | 15 
src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java              | 36 
src/main/java/eu/siacs/conversations/ui/XmppActivity.java                   | 19 
7 files changed, 58 insertions(+), 50 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java 🔗

@@ -190,8 +190,8 @@ public class AxolotlService {
 		this.executor = new SerialSingleThreadExecutor();
 	}
 
-	public IdentityKey getOwnPublicKey() {
-		return axolotlStore.getIdentityKeyPair().getPublicKey();
+	public String getOwnFingerprint() {
+		return axolotlStore.getIdentityKeyPair().getPublicKey().getFingerprint().replaceAll("\\s", "");
 	}
 
 	public Set<IdentityKey> getKeysWithTrust(XmppAxolotlSession.Trust trust) {
@@ -222,6 +222,22 @@ public class AxolotlService {
 		return sessions;
 	}
 
+	public Set<String> getFingerprintsForOwnSessions() {
+		Set<String> fingerprints = new HashSet<>();
+		for (XmppAxolotlSession session : findOwnSessions()) {
+			fingerprints.add(session.getFingerprint());
+		}
+		return fingerprints;
+	}
+
+	public Set<String> getFingerprintsForContact(final Contact contact) {
+		Set<String> fingerprints = new HashSet<>();
+		for (XmppAxolotlSession session : findSessionsforContact(contact)) {
+			fingerprints.add(session.getFingerprint());
+		}
+		return fingerprints;
+	}
+
 	private boolean hasAny(Contact contact) {
 		AxolotlAddress contactAddress = getAddressForJid(contact.getJid());
 		return sessions.hasAny(contactAddress);
@@ -310,8 +326,8 @@ public class AxolotlService {
 		});
 	}
 
-	public void purgeKey(IdentityKey identityKey) {
-		axolotlStore.setFingerprintTrust(identityKey.getFingerprint().replaceAll("\\s", ""), XmppAxolotlSession.Trust.COMPROMISED);
+	public void purgeKey(final String fingerprint) {
+		axolotlStore.setFingerprintTrust(fingerprint.replaceAll("\\s", ""), XmppAxolotlSession.Trust.COMPROMISED);
 	}
 
 	public void publishOwnDeviceIdIfNeeded() {

src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java 🔗

@@ -91,7 +91,7 @@ public class XmppAxolotlSession {
 
 	public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress, String fingerprint) {
 		this(account, store, remoteAddress);
-		this.fingerprint = fingerprint;
+		this.fingerprint = fingerprint.replaceAll("\\s","");
 	}
 
 	public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress) {

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -754,7 +754,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 					}
 					break;
 				case Message.ENCRYPTION_AXOLOTL:
-					message.setAxolotlFingerprint(account.getAxolotlService().getOwnPublicKey().getFingerprint().replaceAll("\\s", ""));
+					message.setAxolotlFingerprint(account.getAxolotlService().getOwnFingerprint());
 					if (message.needsUploading()) {
 						if (account.httpUploadAvailable() || message.fixCounterpart()) {
 							this.sendFileMessage(message,delay);
@@ -799,7 +799,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 					}
 					break;
 				case Message.ENCRYPTION_AXOLOTL:
-					message.setAxolotlFingerprint(account.getAxolotlService().getOwnPublicKey().getFingerprint().replaceAll("\\s", ""));
+					message.setAxolotlFingerprint(account.getAxolotlService().getOwnFingerprint());
 					break;
 			}
 		}

src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java 🔗

@@ -29,7 +29,6 @@ import android.widget.QuickContactBadge;
 import android.widget.TextView;
 
 import org.openintents.openpgp.util.OpenPgpUtils;
-import org.whispersystems.libaxolotl.IdentityKey;
 
 import java.util.List;
 
@@ -392,10 +391,9 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
 				}
 			});
 		}
-		for(final IdentityKey identityKey : xmppConnectionService.databaseBackend.loadIdentityKeys(
-				contact.getAccount(), contact.getJid().toBareJid().toString())) {
-			boolean highlight = identityKey.getFingerprint().replaceAll("\\s", "").equals(messageFingerprint);
-			hasKeys |= addFingerprintRow(keys, contact.getAccount(), identityKey, highlight);
+		for (final String fingerprint : contact.getAccount().getAxolotlService().getFingerprintsForContact(contact)) {
+			boolean highlight = fingerprint.equals(messageFingerprint);
+			hasKeys |= addFingerprintRow(keys, contact.getAccount(), fingerprint, highlight);
 		}
 		if (contact.getPgpKeyId() != 0) {
 			hasKeys = true;

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -25,8 +25,6 @@ import android.widget.TableLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import org.whispersystems.libaxolotl.IdentityKey;
-
 import java.util.Set;
 
 import eu.siacs.conversations.Config;
@@ -572,7 +570,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			} else {
 				this.mOtrFingerprintBox.setVisibility(View.GONE);
 			}
-			final String axolotlFingerprint = this.mAccount.getAxolotlService().getOwnPublicKey().getFingerprint();
+			final String axolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint();
 			if (axolotlFingerprint != null) {
 				this.mAxolotlFingerprintBox.setVisibility(View.VISIBLE);
 				this.mAxolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(axolotlFingerprint));
@@ -607,16 +605,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			} else {
 				this.mAxolotlFingerprintBox.setVisibility(View.GONE);
 			}
-			final IdentityKey ownKey = mAccount.getAxolotlService().getOwnPublicKey();
+			final String ownFingerprint = mAccount.getAxolotlService().getOwnFingerprint();
 			boolean hasKeys = false;
 			keys.removeAllViews();
-			for(final IdentityKey identityKey : xmppConnectionService.databaseBackend.loadIdentityKeys(
-					mAccount, mAccount.getJid().toBareJid().toString())) {
-				if(ownKey.equals(identityKey)) {
+			for (final String fingerprint : mAccount.getAxolotlService().getFingerprintsForOwnSessions()) {
+				if(ownFingerprint.equals(fingerprint)) {
 					continue;
 				}
-				boolean highlight = identityKey.getFingerprint().replaceAll("\\s", "").equals(messageFingerprint);
-				hasKeys |= addFingerprintRow(keys, mAccount, identityKey, highlight);
+				boolean highlight = fingerprint.equals(messageFingerprint);
+				hasKeys |= addFingerprintRow(keys, mAccount, fingerprint, highlight);
 			}
 			if (hasKeys) {
 				keysCard.setVisibility(View.VISIBLE);

src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java 🔗

@@ -43,8 +43,8 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
 	private Button mSaveButton;
 	private Button mCancelButton;
 
-	private final Map<IdentityKey, Boolean> ownKeysToTrust = new HashMap<>();
-	private final Map<IdentityKey, Boolean> foreignKeysToTrust = new HashMap<>();
+	private final Map<String, Boolean> ownKeysToTrust = new HashMap<>();
+	private final Map<String, Boolean> foreignKeysToTrust = new HashMap<>();
 
 	private final OnClickListener mSaveButtonListener = new OnClickListener() {
 		@Override
@@ -120,28 +120,28 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
 		foreignKeys.removeAllViews();
 		boolean hasOwnKeys = false;
 		boolean hasForeignKeys = false;
-		for(final IdentityKey identityKey : ownKeysToTrust.keySet()) {
+		for(final String fingerprint : ownKeysToTrust.keySet()) {
 			hasOwnKeys = true;
-			addFingerprintRowWithListeners(ownKeys, contact.getAccount(), identityKey, false,
-					XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(identityKey)), false,
+			addFingerprintRowWithListeners(ownKeys, contact.getAccount(), fingerprint, false,
+					XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)), false,
 					new CompoundButton.OnCheckedChangeListener() {
 						@Override
 						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-							ownKeysToTrust.put(identityKey, isChecked);
+							ownKeysToTrust.put(fingerprint, isChecked);
 							// own fingerprints have no impact on locked status.
 						}
 					},
 					null
 			);
 		}
-		for(final IdentityKey identityKey : foreignKeysToTrust.keySet()) {
+		for(final String fingerprint : foreignKeysToTrust.keySet()) {
 			hasForeignKeys = true;
-			addFingerprintRowWithListeners(foreignKeys, contact.getAccount(), identityKey, false,
-					XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(identityKey)), false,
+			addFingerprintRowWithListeners(foreignKeys, contact.getAccount(), fingerprint, false,
+					XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(fingerprint)), false,
 					new CompoundButton.OnCheckedChangeListener() {
 						@Override
 						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-							foreignKeysToTrust.put(identityKey, isChecked);
+							foreignKeysToTrust.put(fingerprint, isChecked);
 							lockOrUnlockAsNeeded();
 						}
 					},
@@ -181,12 +181,12 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
 		}
 		for(final IdentityKey identityKey : ownKeysSet) {
 			if(!ownKeysToTrust.containsKey(identityKey)) {
-				ownKeysToTrust.put(identityKey, false);
+				ownKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false);
 			}
 		}
 		for(final IdentityKey identityKey : foreignKeysSet) {
 			if(!foreignKeysToTrust.containsKey(identityKey)) {
-				foreignKeysToTrust.put(identityKey, false);
+				foreignKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false);
 			}
 		}
 	}
@@ -225,15 +225,15 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
 	}
 
 	private void commitTrusts() {
-		for(IdentityKey identityKey:ownKeysToTrust.keySet()) {
+		for(final String fingerprint :ownKeysToTrust.keySet()) {
 			contact.getAccount().getAxolotlService().setFingerprintTrust(
-					identityKey.getFingerprint().replaceAll("\\s", ""),
-					XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(identityKey)));
+					fingerprint,
+					XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint)));
 		}
-		for(IdentityKey identityKey:foreignKeysToTrust.keySet()) {
+		for(final String fingerprint:foreignKeysToTrust.keySet()) {
 			contact.getAccount().getAxolotlService().setFingerprintTrust(
-					identityKey.getFingerprint().replaceAll("\\s", ""),
-					XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(identityKey)));
+					fingerprint,
+					XmppAxolotlSession.Trust.fromBoolean(foreignKeysToTrust.get(fingerprint)));
 		}
 	}
 

src/main/java/eu/siacs/conversations/ui/XmppActivity.java 🔗

@@ -59,8 +59,6 @@ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
 
 import net.java.otr4j.session.SessionID;
 
-import org.whispersystems.libaxolotl.IdentityKey;
-
 import java.io.FileNotFoundException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -613,11 +611,10 @@ public abstract class XmppActivity extends Activity {
 		builder.create().show();
 	}
 
-	protected boolean addFingerprintRow(LinearLayout keys, final Account account, IdentityKey identityKey, boolean highlight) {
-		final String fingerprint = identityKey.getFingerprint().replaceAll("\\s", "");
+	protected boolean addFingerprintRow(LinearLayout keys, final Account account, final String fingerprint, boolean highlight) {
 		final XmppAxolotlSession.Trust trust = account.getAxolotlService()
 				.getFingerprintTrust(fingerprint);
-		return addFingerprintRowWithListeners(keys, account, identityKey, highlight, trust, true,
+		return addFingerprintRowWithListeners(keys, account, fingerprint, highlight, trust, true,
 				new CompoundButton.OnCheckedChangeListener() {
 					@Override
 					public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@@ -639,7 +636,7 @@ public abstract class XmppActivity extends Activity {
 	}
 
 	protected boolean addFingerprintRowWithListeners(LinearLayout keys, final Account account,
-	                                                 final IdentityKey identityKey,
+	                                                 final String fingerprint,
 	                                                 boolean highlight,
 	                                                 XmppAxolotlSession.Trust trust,
 	                                                 boolean showTag,
@@ -659,7 +656,7 @@ public abstract class XmppActivity extends Activity {
 		view.setOnLongClickListener(new View.OnLongClickListener() {
 			@Override
 			public boolean onLongClick(View v) {
-				showPurgeKeyDialog(account, identityKey);
+				showPurgeKeyDialog(account, fingerprint);
 				return true;
 			}
 		});
@@ -707,24 +704,24 @@ public abstract class XmppActivity extends Activity {
 			keyType.setText(getString(R.string.omemo_fingerprint));
 		}
 
-		key.setText(CryptoHelper.prettifyFingerprint(identityKey.getFingerprint()));
+		key.setText(CryptoHelper.prettifyFingerprint(fingerprint));
 		keys.addView(view);
 		return true;
 	}
 
-	public void showPurgeKeyDialog(final Account account, final IdentityKey identityKey) {
+	public void showPurgeKeyDialog(final Account account, final String fingerprint) {
 		Builder builder = new Builder(this);
 		builder.setTitle(getString(R.string.purge_key));
 		builder.setIconAttribute(android.R.attr.alertDialogIcon);
 		builder.setMessage(getString(R.string.purge_key_desc_part1)
-				+ "\n\n" + CryptoHelper.prettifyFingerprint(identityKey.getFingerprint())
+				+ "\n\n" + CryptoHelper.prettifyFingerprint(fingerprint)
 				+ "\n\n" + getString(R.string.purge_key_desc_part2));
 		builder.setNegativeButton(getString(R.string.cancel), null);
 		builder.setPositiveButton(getString(R.string.accept),
 				new DialogInterface.OnClickListener() {
 					@Override
 					public void onClick(DialogInterface dialog, int which) {
-						account.getAxolotlService().purgeKey(identityKey);
+						account.getAxolotlService().purgeKey(fingerprint);
 						refreshUi();
 					}
 				});