From 92b5081b5ebac1a3108a821a270beb3f7d9c39ee Mon Sep 17 00:00:00 2001 From: Andreas Straub Date: Tue, 21 Jul 2015 14:18:16 +0200 Subject: [PATCH] Add INACTIVE state for removed keys We introduce a new trust state: INACTIVE. This state is intended for old keys that have been removed. When a TRUSTED device is removed from the PEP devicelist, it's status will be set to INACTIVE. INACTIVE keys are shown in the UI as greyed out, non-interactible key rows. Messages are not encrypted for INACTIVE devices. When an INACTIVE device reappears in PEP, or a message is received from an INACTIVE device, it is set back to trusted. --- .../crypto/axolotl/AxolotlService.java | 54 +++++++++++++++---- .../services/XmppConnectionService.java | 31 +++++------ .../ui/ContactDetailsActivity.java | 8 ++- .../conversations/ui/EditAccountActivity.java | 8 ++- .../conversations/ui/TrustKeysActivity.java | 6 +-- .../siacs/conversations/ui/XmppActivity.java | 24 +++++++-- .../xmpp/OnKeyStatusUpdated.java | 5 ++ .../xmpp/OnNewKeysAvailable.java | 5 -- src/main/res/values/colors.xml | 1 + 9 files changed, 102 insertions(+), 40 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java delete mode 100644 src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java 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 a004599d6..c30a7ab86 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -102,7 +102,8 @@ public class AxolotlService { UNDECIDED(0), TRUSTED(1), UNTRUSTED(2), - COMPROMISED(3); + COMPROMISED(3), + INACTIVE(4); private static final Map trustsByValue = new HashMap<>(); @@ -125,12 +126,16 @@ public class AxolotlService { public String toString() { switch(this){ case UNDECIDED: - return "Trust undecided"; + return "Trust undecided "+getCode(); case TRUSTED: - return "Trusted"; + return "Trusted "+getCode(); + case COMPROMISED: + return "Compromised "+getCode(); + case INACTIVE: + return "Inactive "+getCode(); case UNTRUSTED: default: - return "Untrusted"; + return "Untrusted "+getCode(); } } @@ -538,14 +543,20 @@ public class AxolotlService { return fingerprint; } - private SQLiteAxolotlStore.Trust getTrust() { + 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; - switch (getTrust()) { + SQLiteAxolotlStore.Trust trust = getTrust(); + switch (trust) { + case INACTIVE: case UNDECIDED: case UNTRUSTED: case TRUSTED: @@ -574,6 +585,10 @@ public class AxolotlService { 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: @@ -774,15 +789,32 @@ public class AxolotlService { return this.deviceIds.get(account.getJid().toBareJid()); } + private void setTrustOnSessions(final Jid jid, @NonNull final Set deviceIds, + final SQLiteAxolotlStore.Trust from, + final SQLiteAxolotlStore.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 + && session.getTrust() == from) { + session.setTrust(to); + } + } + } + public void registerDevices(final Jid jid, @NonNull final Set deviceIds) { if(deviceIds.contains(getOwnDeviceId())) { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Skipping own Device ID:"+ jid + ":"+getOwnDeviceId()); deviceIds.remove(getOwnDeviceId()); } - for(Integer i:deviceIds) { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Adding Device ID:"+ jid + ":"+i); - } + Set expiredDevices = new HashSet<>(axolotlStore.getSubDeviceSessions(jid.toBareJid().toString())); + expiredDevices.removeAll(deviceIds); + setTrustOnSessions(jid, expiredDevices, SQLiteAxolotlStore.Trust.TRUSTED, + SQLiteAxolotlStore.Trust.INACTIVE); + Set newDevices = new HashSet<>(deviceIds); + setTrustOnSessions(jid, newDevices, SQLiteAxolotlStore.Trust.INACTIVE, + SQLiteAxolotlStore.Trust.TRUSTED); this.deviceIds.put(jid, deviceIds); + mXmppConnectionService.keyStatusUpdated(); publishOwnDeviceIdIfNeeded(); } @@ -957,7 +989,7 @@ public class AxolotlService { } }); } - mXmppConnectionService.newKeysAvailable(); + mXmppConnectionService.keyStatusUpdated(); } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index e7df9e6a9..fa0a87096 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -86,7 +86,7 @@ import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnMessageAcknowledged; import eu.siacs.conversations.xmpp.OnMessagePacketReceived; -import eu.siacs.conversations.xmpp.OnNewKeysAvailable; +import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnPresencePacketReceived; import eu.siacs.conversations.xmpp.OnStatusChanged; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; @@ -309,8 +309,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa private int rosterChangedListenerCount = 0; private OnMucRosterUpdate mOnMucRosterUpdate = null; private int mucRosterChangedListenerCount = 0; - private OnNewKeysAvailable mOnNewKeysAvailable = null; - private int newKeysAvailableListenerCount = 0; + private OnKeyStatusUpdated mOnKeyStatusUpdated = null; + private int keyStatusUpdatedListenerCount = 0; private SecureRandom mRandom; private OpenPgpServiceConnection pgpServiceConnection; private PgpEngine mPgpEngine = null; @@ -1372,30 +1372,31 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void setOnNewKeysAvailableListener(final OnNewKeysAvailable listener) { + public void setOnKeyStatusUpdatedListener(final OnKeyStatusUpdated listener) { synchronized (this) { if (checkListeners()) { switchToForeground(); } - this.mOnNewKeysAvailable = listener; - if (this.newKeysAvailableListenerCount < 2) { - this.newKeysAvailableListenerCount++; + this.mOnKeyStatusUpdated = listener; + if (this.keyStatusUpdatedListenerCount < 2) { + this.keyStatusUpdatedListenerCount++; } } } public void removeOnNewKeysAvailableListener() { synchronized (this) { - this.newKeysAvailableListenerCount--; - if (this.newKeysAvailableListenerCount <= 0) { - this.newKeysAvailableListenerCount = 0; - this.mOnNewKeysAvailable = null; + this.keyStatusUpdatedListenerCount--; + if (this.keyStatusUpdatedListenerCount <= 0) { + this.keyStatusUpdatedListenerCount = 0; + this.mOnKeyStatusUpdated = null; if (checkListeners()) { switchToBackground(); } } } } + public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) { synchronized (this) { if (checkListeners()) { @@ -1427,7 +1428,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa && this.mOnRosterUpdate == null && this.mOnUpdateBlocklist == null && this.mOnShowErrorToast == null - && this.mOnNewKeysAvailable == null); + && this.mOnKeyStatusUpdated == null); } private void switchToForeground() { @@ -2316,9 +2317,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void newKeysAvailable() { - if(mOnNewKeysAvailable != null) { - mOnNewKeysAvailable.onNewKeysAvailable(); + public void keyStatusUpdated() { + if(mOnKeyStatusUpdated != null) { + mOnKeyStatusUpdated.onKeyStatusUpdated(); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 16e16cff4..a0e02c1b8 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -42,12 +42,13 @@ import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist { +public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated { public static final String ACTION_VIEW_CONTACT = "view_contact"; private Contact contact; @@ -468,4 +469,9 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd populateView(); } } + + @Override + public void onKeyStatusUpdated() { + refreshUi(); + } } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index ac0f66169..aac8788fc 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -35,12 +35,13 @@ import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.XmppConnection.Features; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.pep.Avatar; -public class EditAccountActivity extends XmppActivity implements OnAccountUpdate{ +public class EditAccountActivity extends XmppActivity implements OnAccountUpdate, OnKeyStatusUpdated { private AutoCompleteTextView mAccountJid; private EditText mPassword; @@ -618,4 +619,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate }); builder.create().show(); } + + @Override + public void onKeyStatusUpdated() { + refreshUi(); + } } diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index ccdef9c39..1bf07f3ea 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -20,11 +20,11 @@ import eu.siacs.conversations.crypto.axolotl.AxolotlService.SQLiteAxolotlStore.T import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; -import eu.siacs.conversations.xmpp.OnNewKeysAvailable; +import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -public class TrustKeysActivity extends XmppActivity implements OnNewKeysAvailable { +public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated { private Jid accountJid; private Jid contactJid; private boolean hasOtherTrustedKeys = false; @@ -215,7 +215,7 @@ public class TrustKeysActivity extends XmppActivity implements OnNewKeysAvailabl } @Override - public void onNewKeysAvailable() { + public void onKeyStatusUpdated() { final Account account = xmppConnectionService.findAccountByJid(accountJid); hasPendingFetches = false; getFingerprints(account); diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index a0a8d520d..4cb6841bc 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -83,7 +83,7 @@ import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinde import eu.siacs.conversations.ui.widget.Switch; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.ExceptionHelper; -import eu.siacs.conversations.xmpp.OnNewKeysAvailable; +import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -99,6 +99,7 @@ public abstract class XmppActivity extends Activity { protected int mPrimaryTextColor; protected int mSecondaryTextColor; + protected int mTertiaryTextColor; protected int mPrimaryBackgroundColor; protected int mSecondaryBackgroundColor; protected int mColorRed; @@ -294,8 +295,8 @@ public abstract class XmppActivity extends Activity { if (this instanceof XmppConnectionService.OnShowErrorToast) { this.xmppConnectionService.setOnShowErrorToastListener((XmppConnectionService.OnShowErrorToast) this); } - if (this instanceof OnNewKeysAvailable) { - this.xmppConnectionService.setOnNewKeysAvailableListener((OnNewKeysAvailable) this); + if (this instanceof OnKeyStatusUpdated) { + this.xmppConnectionService.setOnKeyStatusUpdatedListener((OnKeyStatusUpdated) this); } } @@ -318,7 +319,7 @@ public abstract class XmppActivity extends Activity { if (this instanceof XmppConnectionService.OnShowErrorToast) { this.xmppConnectionService.removeOnShowErrorToastListener(); } - if (this instanceof OnNewKeysAvailable) { + if (this instanceof OnKeyStatusUpdated) { this.xmppConnectionService.removeOnNewKeysAvailableListener(); } } @@ -349,6 +350,7 @@ public abstract class XmppActivity extends Activity { ExceptionHelper.init(getApplicationContext()); mPrimaryTextColor = getResources().getColor(R.color.black87); mSecondaryTextColor = getResources().getColor(R.color.black54); + mTertiaryTextColor = getResources().getColor(R.color.black12); mColorRed = getResources().getColor(R.color.red500); mColorOrange = getResources().getColor(R.color.orange500); mColorGreen = getResources().getColor(R.color.green500); @@ -668,10 +670,20 @@ public abstract class XmppActivity extends Activity { case TRUSTED: trustToggle.setChecked(trust == AxolotlService.SQLiteAxolotlStore.Trust.TRUSTED, false); trustToggle.setEnabled(true); + key.setTextColor(getPrimaryTextColor()); + keyType.setTextColor(getSecondaryTextColor()); break; case UNDECIDED: trustToggle.setChecked(false, false); trustToggle.setEnabled(false); + key.setTextColor(getPrimaryTextColor()); + keyType.setTextColor(getSecondaryTextColor()); + break; + case INACTIVE: + trustToggle.setChecked(true, false); + trustToggle.setEnabled(false); + key.setTextColor(getTertiaryTextColor()); + keyType.setTextColor(getTertiaryTextColor()); break; } @@ -824,6 +836,10 @@ public abstract class XmppActivity extends Activity { } }; + public int getTertiaryTextColor() { + return this.mTertiaryTextColor; + } + public int getSecondaryTextColor() { return this.mSecondaryTextColor; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java b/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java new file mode 100644 index 000000000..65ae133d5 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/OnKeyStatusUpdated.java @@ -0,0 +1,5 @@ +package eu.siacs.conversations.xmpp; + +public interface OnKeyStatusUpdated { + public void onKeyStatusUpdated(); +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java b/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java deleted file mode 100644 index 59dc1c1ea..000000000 --- a/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java +++ /dev/null @@ -1,5 +0,0 @@ -package eu.siacs.conversations.xmpp; - -public interface OnNewKeysAvailable { - public void onNewKeysAvailable(); -} diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml index 3a778a210..85a442c84 100644 --- a/src/main/res/values/colors.xml +++ b/src/main/res/values/colors.xml @@ -5,6 +5,7 @@ #ff0091ea #de000000 #8a000000 + #42000000 #1f000000 #ffffffff #b2ffffff