1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-23 20:42:06 +01:00

Stale devices: Consider date of deviceId publication

This commit is contained in:
Paul Schaub 2018-01-29 18:37:04 +01:00
parent 38d9d96d1f
commit 15083fa3b0
6 changed files with 160 additions and 22 deletions

View file

@ -165,6 +165,28 @@ public class CachingOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Se
return last; return last;
} }
@Override
public void setDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date) {
getCache(userDevice).lastDeviceIdPublicationDates.put(contactsDevice, date);
if (persistent != null) {
persistent.setDateOfLastReceivedMessage(userDevice, contactsDevice, date);
}
}
@Override
public Date getDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice) {
Date last = getCache(userDevice).lastDeviceIdPublicationDates.get(contactsDevice);
if (last == null && persistent != null) {
last = persistent.getDateOfLastDeviceIdPublication(userDevice, contactsDevice);
if (last != null) {
getCache(userDevice).lastDeviceIdPublicationDates.put(contactsDevice, last);
}
}
return last;
}
@Override @Override
public void setDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice, Date date) { public void setDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice, Date date) {
getCache(userDevice).lastRenewalDate = date; getCache(userDevice).lastRenewalDate = date;
@ -420,6 +442,7 @@ public class CachingOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Se
private final HashMap<BareJid, HashMap<Integer, T_Sess>> sessions = new HashMap<>(); private final HashMap<BareJid, HashMap<Integer, T_Sess>> sessions = new HashMap<>();
private final HashMap<OmemoDevice, T_IdKey> identityKeys = new HashMap<>(); private final HashMap<OmemoDevice, T_IdKey> identityKeys = new HashMap<>();
private final HashMap<OmemoDevice, Date> lastMessagesDates = new HashMap<>(); private final HashMap<OmemoDevice, Date> lastMessagesDates = new HashMap<>();
private final HashMap<OmemoDevice, Date> lastDeviceIdPublicationDates = new HashMap<>();
private final HashMap<BareJid, OmemoCachedDeviceList> deviceLists = new HashMap<>(); private final HashMap<BareJid, OmemoCachedDeviceList> deviceLists = new HashMap<>();
private Date lastRenewalDate = null; private Date lastRenewalDate = null;
} }

View file

@ -105,12 +105,6 @@ public abstract class FileBasedOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigP
} }
} }
@Override
public void setDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date) {
File lastMessageReceived = hierarchy.getLastMessageReceivedDatePath(userDevice, contactsDevice);
writeLong(lastMessageReceived, date.getTime());
}
@Override @Override
public SortedSet<Integer> localDeviceIdsOf(BareJid localUser) { public SortedSet<Integer> localDeviceIdsOf(BareJid localUser) {
SortedSet<Integer> deviceIds = new TreeSet<>(); SortedSet<Integer> deviceIds = new TreeSet<>();
@ -128,6 +122,12 @@ public abstract class FileBasedOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigP
return deviceIds; return deviceIds;
} }
@Override
public void setDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date) {
File lastMessageReceived = hierarchy.getLastMessageReceivedDatePath(userDevice, contactsDevice);
writeLong(lastMessageReceived, date.getTime());
}
@Override @Override
public Date getDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice) { public Date getDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice) {
File lastMessageReceived = hierarchy.getLastMessageReceivedDatePath(userDevice, contactsDevice); File lastMessageReceived = hierarchy.getLastMessageReceivedDatePath(userDevice, contactsDevice);
@ -135,6 +135,19 @@ public abstract class FileBasedOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigP
return date != null ? new Date(date) : null; return date != null ? new Date(date) : null;
} }
@Override
public void setDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date) {
File lastDeviceIdPublished = hierarchy.getLastDeviceIdPublicationDatePath(userDevice, contactsDevice);
writeLong(lastDeviceIdPublished, date.getTime());
}
@Override
public Date getDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice) {
File lastDeviceIdPublished = hierarchy.getLastDeviceIdPublicationDatePath(userDevice, contactsDevice);
Long date = readLong(lastDeviceIdPublished);
return date != null ? new Date(date) : null;
}
@Override @Override
public void setDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice, Date date) { public void setDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice, Date date) {
File lastSignedPreKeyRenewal = hierarchy.getLastSignedPreKeyRenewal(userDevice); File lastSignedPreKeyRenewal = hierarchy.getLastSignedPreKeyRenewal(userDevice);
@ -753,6 +766,7 @@ public abstract class FileBasedOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigP
static final String IDENTITY_KEY_PAIR = "identityKeyPair"; static final String IDENTITY_KEY_PAIR = "identityKeyPair";
static final String PRE_KEYS = "preKeys"; static final String PRE_KEYS = "preKeys";
static final String LAST_MESSAGE_RECEVIED_DATE = "lastMessageReceivedDate"; static final String LAST_MESSAGE_RECEVIED_DATE = "lastMessageReceivedDate";
static final String LAST_DEVICEID_PUBLICATION_DATE = "lastDeviceIdPublicationDate";
static final String SIGNED_PRE_KEYS = "signedPreKeys"; static final String SIGNED_PRE_KEYS = "signedPreKeys";
static final String LAST_SIGNED_PRE_KEY_RENEWAL = "lastSignedPreKeyRenewal"; static final String LAST_SIGNED_PRE_KEY_RENEWAL = "lastSignedPreKeyRenewal";
static final String SESSION = "session"; static final String SESSION = "session";
@ -812,6 +826,10 @@ public abstract class FileBasedOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigP
return new File(getContactsDir(userDevice, device), LAST_MESSAGE_RECEVIED_DATE); return new File(getContactsDir(userDevice, device), LAST_MESSAGE_RECEVIED_DATE);
} }
File getLastDeviceIdPublicationDatePath(OmemoDevice userDevice, OmemoDevice device) {
return new File(getContactsDir(userDevice, device), LAST_DEVICEID_PUBLICATION_DATE);
}
File getSignedPreKeysDirectory(OmemoDevice userDevice) { File getSignedPreKeysDirectory(OmemoDevice userDevice) {
return createDirectory(getUserDeviceDirectory(userDevice), SIGNED_PRE_KEYS); return createDirectory(getUserDeviceDirectory(userDevice), SIGNED_PRE_KEYS);
} }

View file

@ -22,6 +22,7 @@ import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PEP_NODE_DEVICE_
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -245,6 +246,10 @@ public final class OmemoManager extends Manager {
throw new SmackException.NotLoggedInException(); throw new SmackException.NotLoggedInException();
} }
if (getTrustCallback() == null) {
throw new IllegalStateException("No TrustCallback set.");
}
getOmemoService().init(new LoggedInOmemoManager(this)); getOmemoService().init(new LoggedInOmemoManager(this));
ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(PEP_NODE_DEVICE_LIST_NOTIFY); ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(PEP_NODE_DEVICE_LIST_NOTIFY);
} }
@ -1061,6 +1066,9 @@ public final class OmemoManager extends Manager {
final OmemoDeviceListElement_VAxolotl newDeviceList = new OmemoDeviceListElement_VAxolotl(deviceList); final OmemoDeviceListElement_VAxolotl newDeviceList = new OmemoDeviceListElement_VAxolotl(deviceList);
if (!newDeviceList.copyDeviceIds().equals(receivedDeviceList.copyDeviceIds())) { if (!newDeviceList.copyDeviceIds().equals(receivedDeviceList.copyDeviceIds())) {
LOGGER.log(Level.FINE, "Republish deviceList due to changes:" +
" Received: " + Arrays.toString(receivedDeviceList.copyDeviceIds().toArray()) +
" Published: " + Arrays.toString(newDeviceList.copyDeviceIds().toArray()));
Async.go(new Runnable() { Async.go(new Runnable() {
@Override @Override
public void run() { public void run() {

View file

@ -386,16 +386,25 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
// Ignore stale devices // Ignore stale devices
if (OmemoConfiguration.getIgnoreStaleDevices()) { if (OmemoConfiguration.getIgnoreStaleDevices()) {
Date lastActivity = getOmemoStoreBackend().getDateOfLastReceivedMessage(userDevice, contactsDevice); Date lastMessageDate = getOmemoStoreBackend().getDateOfLastReceivedMessage(userDevice, contactsDevice);
if (lastActivity == null) { if (lastMessageDate == null) {
lastActivity = new Date(); lastMessageDate = new Date();
getOmemoStoreBackend().setDateOfLastReceivedMessage(userDevice, contactsDevice, lastActivity); getOmemoStoreBackend().setDateOfLastReceivedMessage(userDevice, contactsDevice, lastMessageDate);
} }
if (isStale(userDevice, contactsDevice, lastActivity, OmemoConfiguration.getIgnoreStaleDevicesAfterHours())) { Date lastPublicationDate = getOmemoStoreBackend().getDateOfLastDeviceIdPublication(userDevice, contactsDevice);
if (lastPublicationDate == null) {
lastPublicationDate = new Date();
getOmemoStoreBackend().setDateOfLastDeviceIdPublication(userDevice, contactsDevice, lastPublicationDate);
}
boolean stale = isStale(userDevice, contactsDevice, lastPublicationDate, OmemoConfiguration.getIgnoreStaleDevicesAfterHours());
stale &= isStale(userDevice, contactsDevice, lastMessageDate, OmemoConfiguration.getIgnoreStaleDevicesAfterHours());
if (stale) {
LOGGER.log(Level.FINE, "Device " + contactsDevice + " seems to be stale (last message received " LOGGER.log(Level.FINE, "Device " + contactsDevice + " seems to be stale (last message received "
+ lastActivity + "). Ignore it."); + lastMessageDate + ", last publication of deviceId: " + lastPublicationDate + "). Ignore it.");
skippedRecipients.put(contactsDevice, new StaleDeviceException(contactsDevice, lastActivity)); skippedRecipients.put(contactsDevice, new StaleDeviceException(contactsDevice, lastMessageDate, lastPublicationDate));
continue; continue;
} }
} }
@ -860,6 +869,15 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
return devicesWithSessions; return devicesWithSessions;
} }
/**
* Return a set of all devices from the provided set, which trust level is undecided.
* A device is also considered undecided, if its fingerprint cannot be loaded.
*
* @param userDevice our OmemoDevice
* @param callback OmemoTrustCallback to query the trust decisions from
* @param devices set of OmemoDevices
* @return set of OmemoDevices which contains all devices from the set devices, which are undecided
*/
private Set<OmemoDevice> getUndecidedDevices(OmemoDevice userDevice, OmemoTrustCallback callback, Set<OmemoDevice> devices) { private Set<OmemoDevice> getUndecidedDevices(OmemoDevice userDevice, OmemoTrustCallback callback, Set<OmemoDevice> devices) {
Set<OmemoDevice> undecidedDevices = new HashSet<>(); Set<OmemoDevice> undecidedDevices = new HashSet<>();
@ -883,6 +901,15 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
return undecidedDevices; return undecidedDevices;
} }
/**
* Return a set of all devices from the provided set, which are untrusted.
* A device is also considered untrusted, if its fingerprint cannot be loaded.
*
* @param userDevice our own OmemoDevice
* @param trustCallback OmemoTrustCallback to query trust decisions from
* @param devices set of OmemoDevices
* @return set of OmemoDevices from devices, which contains all devices which are untrusted
*/
private Set<OmemoDevice> getUntrustedDeviced(OmemoDevice userDevice, OmemoTrustCallback trustCallback, Set<OmemoDevice> devices) { private Set<OmemoDevice> getUntrustedDeviced(OmemoDevice userDevice, OmemoTrustCallback trustCallback, Set<OmemoDevice> devices) {
Set<OmemoDevice> untrustedDevices = new HashSet<>(); Set<OmemoDevice> untrustedDevices = new HashSet<>();
@ -1009,13 +1036,22 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
for (int deviceId : deviceList.getActiveDevices()) { for (int deviceId : deviceList.getActiveDevices()) {
OmemoDevice device = new OmemoDevice(contact, deviceId); OmemoDevice device = new OmemoDevice(contact, deviceId);
Date lastDeviceIdPublication = getOmemoStoreBackend().getDateOfLastDeviceIdPublication(userDevice, device);
if (lastDeviceIdPublication == null) {
lastDeviceIdPublication = new Date();
getOmemoStoreBackend().setDateOfLastDeviceIdPublication(userDevice, device, lastDeviceIdPublication);
}
Date lastMessageReceived = getOmemoStoreBackend().getDateOfLastReceivedMessage(userDevice, device); Date lastMessageReceived = getOmemoStoreBackend().getDateOfLastReceivedMessage(userDevice, device);
if (lastMessageReceived == null) { if (lastMessageReceived == null) {
lastMessageReceived = new Date(); lastMessageReceived = new Date();
getOmemoStoreBackend().setDateOfLastReceivedMessage(userDevice, device, lastMessageReceived); getOmemoStoreBackend().setDateOfLastReceivedMessage(userDevice, device, lastMessageReceived);
} }
if (isStale(userDevice, device, lastMessageReceived, maxAgeHours)) { boolean stale = isStale(userDevice, device, lastDeviceIdPublication, maxAgeHours);
stale &= isStale(userDevice, device, lastMessageReceived, maxAgeHours);
if (stale) {
deviceList.addInactiveDevice(deviceId); deviceList.addInactiveDevice(deviceId);
} }
} }

View file

@ -108,11 +108,19 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
cached = new OmemoCachedDeviceList(); cached = new OmemoCachedDeviceList();
} }
if (list != null) { if (list == null) {
cached.merge(list.getDeviceIds()); return cached;
storeCachedDeviceList(userDevice, contact, cached);
} }
for (int devId : list.getDeviceIds()) {
if (!cached.contains(devId)) {
setDateOfLastDeviceIdPublication(userDevice, new OmemoDevice(contact, devId), new Date());
}
}
cached.merge(list.getDeviceIds());
storeCachedDeviceList(userDevice, contact, cached);
return cached; return cached;
} }
@ -300,6 +308,26 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
*/ */
public abstract Date getDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice); public abstract Date getDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice);
/**
* Set the date of the last time the deviceId was published. This method only gets called, when the deviceId
* was inactive/non-existent before it was published.
*
* @param userDevice our OmemoDevice
* @param contactsDevice OmemoDevice in question
* @param date date of the last publication after not being published
*/
public abstract void setDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date);
/**
* Return the date of the last time the deviceId was published after previously being not published.
* (Point in time, where the status of the deviceId changed from inactive/non-existent to active).
*
* @param userDevice our OmemoDevice
* @param contactsDevice OmemoDevice in question
* @return date of the last publication after not being published
*/
public abstract Date getDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice);
/** /**
* Set the date of the last time the signed preKey was renewed. * Set the date of the last time the signed preKey was renewed.
* *

View file

@ -24,17 +24,42 @@ public class StaleDeviceException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final OmemoDevice device; private final OmemoDevice device;
private final Date lastActivity; private final Date lastMessageDate;
private final Date lastDeviceIdPublication;
public StaleDeviceException(OmemoDevice device, Date lastActivity) { /**
* This exception gets thrown if a message cannot be encrypted for a device due to the device being inactive for too long (stale).
*
* @param device OmemoDevice.
* @param lastMessageDate
* @param lastDeviceIdPublicationDate
*/
public StaleDeviceException(OmemoDevice device, Date lastMessageDate, Date lastDeviceIdPublicationDate) {
this.device = device; this.device = device;
this.lastActivity = lastActivity; this.lastMessageDate = lastMessageDate;
this.lastDeviceIdPublication = lastDeviceIdPublicationDate;
} }
public Date getLastActivity() { /**
return lastActivity; * Return the date on which the last OMEMO message sent from the device was received.
* @return last messages date
*/
public Date getLastMessageDate() {
return lastMessageDate;
} }
/**
* Return the date of the last time the deviceId was republished after being inactive/non-existent before.
* @return date of last deviceId (re)publication.
*/
public Date getLastDeviceIdPublicationDate() {
return lastDeviceIdPublication;
}
/**
* Return the stale OMEMO device.
* @return stale device
*/
public OmemoDevice getDevice() { public OmemoDevice getDevice() {
return device; return device;
} }