mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-14 00:02:05 +01:00
Stale devices: Consider date of deviceId publication
This commit is contained in:
parent
38d9d96d1f
commit
15083fa3b0
6 changed files with 160 additions and 22 deletions
|
@ -165,6 +165,28 @@ public class CachingOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Se
|
|||
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
|
||||
public void setDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice, Date 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<OmemoDevice, T_IdKey> identityKeys = 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 Date lastRenewalDate = null;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
public SortedSet<Integer> localDeviceIdsOf(BareJid localUser) {
|
||||
SortedSet<Integer> deviceIds = new TreeSet<>();
|
||||
|
@ -128,6 +122,12 @@ public abstract class FileBasedOmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigP
|
|||
return deviceIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date) {
|
||||
File lastMessageReceived = hierarchy.getLastMessageReceivedDatePath(userDevice, contactsDevice);
|
||||
writeLong(lastMessageReceived, date.getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice 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;
|
||||
}
|
||||
|
||||
@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
|
||||
public void setDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice, Date date) {
|
||||
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 PRE_KEYS = "preKeys";
|
||||
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 LAST_SIGNED_PRE_KEY_RENEWAL = "lastSignedPreKeyRenewal";
|
||||
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);
|
||||
}
|
||||
|
||||
File getLastDeviceIdPublicationDatePath(OmemoDevice userDevice, OmemoDevice device) {
|
||||
return new File(getContactsDir(userDevice, device), LAST_DEVICEID_PUBLICATION_DATE);
|
||||
}
|
||||
|
||||
File getSignedPreKeysDirectory(OmemoDevice userDevice) {
|
||||
return createDirectory(getUserDeviceDirectory(userDevice), SIGNED_PRE_KEYS);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PEP_NODE_DEVICE_
|
|||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -245,6 +246,10 @@ public final class OmemoManager extends Manager {
|
|||
throw new SmackException.NotLoggedInException();
|
||||
}
|
||||
|
||||
if (getTrustCallback() == null) {
|
||||
throw new IllegalStateException("No TrustCallback set.");
|
||||
}
|
||||
|
||||
getOmemoService().init(new LoggedInOmemoManager(this));
|
||||
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);
|
||||
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
|
@ -386,16 +386,25 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
|||
// Ignore stale devices
|
||||
if (OmemoConfiguration.getIgnoreStaleDevices()) {
|
||||
|
||||
Date lastActivity = getOmemoStoreBackend().getDateOfLastReceivedMessage(userDevice, contactsDevice);
|
||||
if (lastActivity == null) {
|
||||
lastActivity = new Date();
|
||||
getOmemoStoreBackend().setDateOfLastReceivedMessage(userDevice, contactsDevice, lastActivity);
|
||||
Date lastMessageDate = getOmemoStoreBackend().getDateOfLastReceivedMessage(userDevice, contactsDevice);
|
||||
if (lastMessageDate == null) {
|
||||
lastMessageDate = new Date();
|
||||
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 "
|
||||
+ lastActivity + "). Ignore it.");
|
||||
skippedRecipients.put(contactsDevice, new StaleDeviceException(contactsDevice, lastActivity));
|
||||
+ lastMessageDate + ", last publication of deviceId: " + lastPublicationDate + "). Ignore it.");
|
||||
skippedRecipients.put(contactsDevice, new StaleDeviceException(contactsDevice, lastMessageDate, lastPublicationDate));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -860,6 +869,15 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
|||
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) {
|
||||
Set<OmemoDevice> undecidedDevices = new HashSet<>();
|
||||
|
||||
|
@ -883,6 +901,15 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
|||
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) {
|
||||
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()) {
|
||||
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);
|
||||
if (lastMessageReceived == null) {
|
||||
lastMessageReceived = new Date();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,11 +108,19 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
|
|||
cached = new OmemoCachedDeviceList();
|
||||
}
|
||||
|
||||
if (list != null) {
|
||||
cached.merge(list.getDeviceIds());
|
||||
storeCachedDeviceList(userDevice, contact, cached);
|
||||
if (list == null) {
|
||||
return 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -24,17 +24,42 @@ public class StaleDeviceException extends Exception {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
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.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() {
|
||||
return device;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue