X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/7170a68571f2d612f908e5293c15850ba726f35d..1ce1ae91be709eba4ce01142596336bf98c13bb4:/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 28e06bbe..0f75f909 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -25,7 +25,9 @@ import org.asamk.signal.manager.groups.GroupIdV1; import org.asamk.signal.manager.groups.GroupInviteLinkUrl; import org.asamk.signal.manager.groups.GroupLinkState; import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupPermission; import org.asamk.signal.manager.groups.GroupUtils; +import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.helper.GroupV2Helper; import org.asamk.signal.manager.helper.PinHelper; @@ -328,6 +330,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(); } @@ -572,7 +585,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; @@ -598,7 +611,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, @@ -639,7 +652,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; } @@ -762,7 +775,9 @@ public class Manager implements Closeable { return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfRecipientId())); } - public Pair> sendQuitGroupMessage(GroupId groupId) throws GroupNotFoundException, IOException, NotAGroupMemberException { + public Pair> sendQuitGroupMessage( + GroupId groupId, Set groupAdmins + ) throws GroupNotFoundException, IOException, NotAGroupMemberException, InvalidNumberException, LastGroupAdminException { SignalServiceDataMessage.Builder messageBuilder; final var g = getGroupForUpdating(groupId); @@ -774,7 +789,18 @@ public class Manager implements Closeable { account.getGroupStore().updateGroup(groupInfoV1); } else { final var groupInfoV2 = (GroupInfoV2) g; - final var groupGroupChangePair = groupV2Helper.leaveGroup(groupInfoV2); + final var currentAdmins = g.getAdminMembers(); + final var newAdmins = getSignalServiceAddresses(groupAdmins); + newAdmins.removeAll(currentAdmins); + newAdmins.retainAll(g.getMembers()); + if (currentAdmins.contains(getSelfRecipientId()) + && currentAdmins.size() == 1 + && g.getMembers().size() > 1 + && newAdmins.size() == 0) { + // Last admin can't leave the group, unless she's also the last member + throw new LastGroupAdminException(g.getGroupId(), g.getTitle()); + } + final var groupGroupChangePair = groupV2Helper.leaveGroup(groupInfoV2, newAdmins); groupInfoV2.setGroup(groupGroupChangePair.first(), this::resolveRecipient); messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupGroupChangePair.second().toByteArray()); account.getGroupStore().updateGroup(groupInfoV2); @@ -836,6 +862,8 @@ public class Manager implements Closeable { List removeAdmins, boolean resetGroupLink, GroupLinkState groupLinkState, + GroupPermission addMemberPermission, + GroupPermission editDetailsPermission, File avatarFile, Integer expirationTimer ) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException { @@ -848,6 +876,8 @@ public class Manager implements Closeable { removeAdmins == null ? null : getSignalServiceAddresses(removeAdmins), resetGroupLink, groupLinkState, + addMemberPermission, + editDetailsPermission, avatarFile, expirationTimer); } @@ -862,8 +892,10 @@ public class Manager implements Closeable { final Set removeAdmins, final boolean resetGroupLink, final GroupLinkState groupLinkState, + final GroupPermission addMemberPermission, + final GroupPermission editDetailsPermission, final File avatarFile, - Integer expirationTimer + final Integer expirationTimer ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException { var group = getGroupForUpdating(groupId); @@ -877,6 +909,8 @@ public class Manager implements Closeable { removeAdmins, resetGroupLink, groupLinkState, + addMemberPermission, + editDetailsPermission, avatarFile, expirationTimer); } @@ -948,6 +982,8 @@ public class Manager implements Closeable { final Set removeAdmins, final boolean resetGroupLink, final GroupLinkState groupLinkState, + final GroupPermission addMemberPermission, + final GroupPermission editDetailsPermission, final File avatarFile, Integer expirationTimer ) throws IOException { @@ -1020,12 +1056,22 @@ public class Manager implements Closeable { result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); } + if (addMemberPermission != null) { + var groupGroupChangePair = groupV2Helper.setAddMemberPermission(group, addMemberPermission); + result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); + } + + if (editDetailsPermission != null) { + var groupGroupChangePair = groupV2Helper.setEditDetailsPermission(group, editDetailsPermission); + result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); + } + if (expirationTimer != null) { var groupGroupChangePair = groupV2Helper.setMessageExpirationTimer(group, expirationTimer); 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(), @@ -1947,6 +1993,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()