X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/ea633efc9c113918c84994f75ed72116f708dada..795b73df87e411f0cb028426f0f5dc94b2981e42:/lib/src/main/java/org/asamk/signal/manager/Manager.java diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 889bafb0..08789d95 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -121,6 +121,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage import org.whispersystems.signalservice.api.profiles.ProfileAndCredential; import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import org.whispersystems.signalservice.api.push.exceptions.ConflictException; import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; import org.whispersystems.signalservice.api.util.DeviceNameUtil; @@ -330,6 +331,17 @@ public class Manager implements Closeable { } public void checkAccountState() throws IOException { + if (account.getLastReceiveTimestamp() == 0) { + logger.warn("The Signal protocol expects that incoming messages are regularly received."); + } else { + var diffInMilliseconds = System.currentTimeMillis() - account.getLastReceiveTimestamp(); + long days = TimeUnit.DAYS.convert(diffInMilliseconds, TimeUnit.MILLISECONDS); + if (days > 7) { + logger.warn( + "Messages have been last received {} days ago. The Signal protocol expects that incoming messages are regularly received.", + days); + } + } if (accountManager.getPreKeysCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) { refreshPreKeys(); } @@ -574,7 +586,7 @@ public class Manager implements Closeable { ) { var profile = account.getProfileStore().getProfile(recipientId); - var now = new Date().getTime(); + var now = System.currentTimeMillis(); // Profiles are cached for 24h before retrieving them again, unless forced if (!force && profile != null && now - profile.getLastUpdateTimestamp() < 24 * 60 * 60 * 1000) { return profile; @@ -600,7 +612,7 @@ public class Manager implements Closeable { var profileKey = account.getProfileStore().getProfileKey(recipientId); if (profileKey == null) { - profile = new Profile(new Date().getTime(), + profile = new Profile(System.currentTimeMillis(), null, null, null, @@ -641,7 +653,7 @@ public class Manager implements Closeable { } } catch (InvalidKeyException ignored) { logger.warn("Got invalid identity key in profile for {}", - resolveSignalServiceAddress(recipientId).getLegacyIdentifier()); + resolveSignalServiceAddress(recipientId).getIdentifier()); } return profileAndCredential; } @@ -889,19 +901,37 @@ public class Manager implements Closeable { var group = getGroupForUpdating(groupId); if (group instanceof GroupInfoV2) { - return updateGroupV2((GroupInfoV2) group, - name, - description, - members, - removeMembers, - admins, - removeAdmins, - resetGroupLink, - groupLinkState, - addMemberPermission, - editDetailsPermission, - avatarFile, - expirationTimer); + try { + return updateGroupV2((GroupInfoV2) group, + name, + description, + members, + removeMembers, + admins, + removeAdmins, + resetGroupLink, + groupLinkState, + addMemberPermission, + editDetailsPermission, + avatarFile, + expirationTimer); + } catch (ConflictException e) { + // Detected conflicting update, refreshing group and trying again + group = getGroup(groupId, true); + return updateGroupV2((GroupInfoV2) group, + name, + description, + members, + removeMembers, + admins, + removeAdmins, + resetGroupLink, + groupLinkState, + addMemberPermission, + editDetailsPermission, + avatarFile, + expirationTimer); + } } final var gv1 = (GroupInfoV1) group; @@ -1060,7 +1090,7 @@ public class Manager implements Closeable { result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); } - if (result == null || name != null || description != null || avatarFile != null) { + if (name != null || description != null || avatarFile != null) { var groupGroupChangePair = groupV2Helper.updateGroup(group, name, description, avatarFile); if (avatarFile != null) { avatarStore.storeGroupAvatar(group.getGroupId(), @@ -1982,6 +2012,7 @@ public class Manager implements Closeable { SignalServiceContent content = null; Exception exception = null; final CachedMessage[] cachedMessage = {null}; + account.setLastReceiveTimestamp(System.currentTimeMillis()); try { var result = messagePipe.readOrEmpty(timeout, unit, envelope1 -> { final var recipientId = envelope1.hasSource() @@ -2209,7 +2240,16 @@ public class Manager implements Closeable { try (var attachmentAsStream = retrieveAttachmentAsStream(groupsMessage.asPointer(), tmpFile)) { var s = new DeviceGroupsInputStream(attachmentAsStream); DeviceGroup g; - while ((g = s.read()) != null) { + while (true) { + try { + g = s.read(); + } catch (IOException e) { + logger.warn("Sync groups contained invalid group, ignoring: {}", e.getMessage()); + continue; + } + if (g == null) { + break; + } var syncGroup = account.getGroupStore().getOrCreateGroupV1(GroupId.v1(g.getId())); if (syncGroup != null) { if (g.getName().isPresent()) { @@ -2280,7 +2320,17 @@ public class Manager implements Closeable { .asPointer(), tmpFile)) { var s = new DeviceContactsInputStream(attachmentAsStream); DeviceContact c; - while ((c = s.read()) != null) { + while (true) { + try { + c = s.read(); + } catch (IOException e) { + logger.warn("Sync contacts contained invalid contact, ignoring: {}", + e.getMessage()); + continue; + } + if (c == null) { + break; + } if (c.getAddress().matches(account.getSelfAddress()) && c.getProfileKey().isPresent()) { account.setProfileKey(c.getProfileKey().get()); } @@ -2691,8 +2741,12 @@ public class Manager implements Closeable { } public GroupInfo getGroup(GroupId groupId) { + return getGroup(groupId, false); + } + + public GroupInfo getGroup(GroupId groupId, boolean forceUpdate) { final var group = account.getGroupStore().getGroup(groupId); - if (group instanceof GroupInfoV2 && ((GroupInfoV2) group).getGroup() == null) { + if (group instanceof GroupInfoV2 && (forceUpdate || ((GroupInfoV2) group).getGroup() == null)) { final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(((GroupInfoV2) group).getMasterKey()); ((GroupInfoV2) group).setGroup(groupV2Helper.getDecryptedGroup(groupSecretParams), this::resolveRecipient); account.getGroupStore().updateGroup(group);