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.
This commit is contained in:
Andreas Straub 2015-07-21 14:18:16 +02:00
parent 3c5c0c7d3b
commit 92b5081b5e
9 changed files with 102 additions and 40 deletions

View file

@ -102,7 +102,8 @@ public class AxolotlService {
UNDECIDED(0),
TRUSTED(1),
UNTRUSTED(2),
COMPROMISED(3);
COMPROMISED(3),
INACTIVE(4);
private static final Map<Integer, Trust> 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<Integer> 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<Integer> 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<Integer> expiredDevices = new HashSet<>(axolotlStore.getSubDeviceSessions(jid.toBareJid().toString()));
expiredDevices.removeAll(deviceIds);
setTrustOnSessions(jid, expiredDevices, SQLiteAxolotlStore.Trust.TRUSTED,
SQLiteAxolotlStore.Trust.INACTIVE);
Set<Integer> 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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -0,0 +1,5 @@
package eu.siacs.conversations.xmpp;
public interface OnKeyStatusUpdated {
public void onKeyStatusUpdated();
}

View file

@ -1,5 +0,0 @@
package eu.siacs.conversations.xmpp;
public interface OnNewKeysAvailable {
public void onNewKeysAvailable();
}

View file

@ -5,6 +5,7 @@
<color name="accent">#ff0091ea</color>
<color name="black87">#de000000</color>
<color name="black54">#8a000000</color>
<color name="black26">#42000000</color>
<color name="black12">#1f000000</color>
<color name="white">#ffffffff</color>
<color name="white70">#b2ffffff</color>