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:
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue