From dee7d78acbdab09a63d258cfc1d45f578b25618e Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Tue, 23 Feb 2021 10:30:45 +1100 Subject: [PATCH] clean up old groups --- .../securesms/groups/GroupManager.java | 35 -- .../groups/GroupMessageProcessor.java | 318 ------------------ .../securesms/jobs/PushDecryptJob.java | 49 +-- 3 files changed, 1 insertion(+), 401 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java index 0fe3fdeaef..11e36ffec3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManager.java @@ -47,41 +47,6 @@ public class GroupManager { return DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(groupRecipient); } - public static @NonNull GroupActionResult createGroup(@NonNull Context context, - @NonNull Set members, - @Nullable Bitmap avatar, - @Nullable String name, - @NonNull Set admins) - { - GroupDatabase database = DatabaseFactory.getGroupDatabase(context); - String id = GroupUtil.getEncodedClosedGroupID(database.allocateGroupId()); // TODO: The group id is double encoded here 1 - return createGroup(id, context, members, avatar, name, admins); - } - - public static @NonNull GroupActionResult createGroup(@NonNull String id, - @NonNull Context context, - @NonNull Set members, - @Nullable Bitmap avatar, - @Nullable String name, - @NonNull Set admins) - { - final byte[] avatarBytes = BitmapUtil.toByteArray(avatar); - final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); - final String groupId = GroupUtil.getEncodedClosedGroupID(id.getBytes()); // TODO: The group id is double encoded here 2 - final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), false); - final Set
memberAddresses = getMemberAddresses(members); - final Set
adminAddresses = getMemberAddresses(admins); - - String userPublicKey = TextSecurePreferences.getLocalNumber(context); - - memberAddresses.add(Address.fromSerialized(userPublicKey)); - groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(adminAddresses), System.currentTimeMillis()); - - groupDatabase.updateProfilePicture(groupId, avatarBytes); - DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true); - return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses); - } - public static @NonNull GroupActionResult createOpenGroup(@NonNull String id, @NonNull Context context, @Nullable Bitmap avatar, diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java deleted file mode 100644 index b9c18bc41e..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ /dev/null @@ -1,318 +0,0 @@ -package org.thoughtcrime.securesms.groups; - - -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.protobuf.ByteString; - -import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.database.GroupDatabase; -import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult; -import org.thoughtcrime.securesms.database.MmsDatabase; -import org.thoughtcrime.securesms.database.SmsDatabase; -import org.thoughtcrime.securesms.database.ThreadDatabase; -import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.jobs.AvatarDownloadJob; -import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob; -import org.session.libsignal.utilities.logging.Log; -import org.thoughtcrime.securesms.mms.MmsException; -import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; -import org.thoughtcrime.securesms.sms.IncomingGroupMessage; -import org.thoughtcrime.securesms.sms.IncomingTextMessage; - -import org.session.libsession.messaging.threads.Address; -import org.session.libsession.messaging.threads.GroupRecord; -import org.session.libsession.messaging.threads.recipients.Recipient; -import org.session.libsignal.utilities.Base64; -import org.session.libsession.utilities.GroupUtil; -import org.session.libsession.utilities.TextSecurePreferences; -import org.session.libsignal.libsignal.util.guava.Optional; -import org.session.libsignal.service.api.messages.SignalServiceAttachment; -import org.session.libsignal.service.api.messages.SignalServiceContent; -import org.session.libsignal.service.api.messages.SignalServiceDataMessage; -import org.session.libsignal.service.api.messages.SignalServiceGroup; -import org.session.libsignal.service.api.messages.SignalServiceGroup.Type; - -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import static org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer; -import static org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext; - -public class GroupMessageProcessor { - - private static final String TAG = GroupMessageProcessor.class.getSimpleName(); - - public static @Nullable Long process(@NonNull Context context, - @NonNull SignalServiceContent content, - @NonNull SignalServiceDataMessage message, - boolean outgoing) - { - if (!message.getGroupInfo().isPresent() || message.getGroupInfo().get().getGroupId() == null) { - Log.w(TAG, "Received group message with no id! Ignoring..."); - return null; - } - - GroupDatabase database = DatabaseFactory.getGroupDatabase(context); - SignalServiceGroup group = message.getGroupInfo().get(); - String id = GroupUtil.getEncodedId(group); - Optional record = database.getGroup(id); - - if (record.isPresent() && group.getType() == Type.UPDATE) { - return handleGroupUpdate(context, content, group, record.get(), outgoing); - } else if (!record.isPresent() && group.getType() == Type.UPDATE) { - return handleGroupCreate(context, content, group, outgoing, message.getTimestamp()); - } else if (record.isPresent() && group.getType() == Type.QUIT) { - return handleGroupLeave(context, content, group, record.get(), outgoing); - } else if (record.isPresent() && group.getType() == Type.REQUEST_INFO) { - return handleGroupInfoRequest(context, content, group, record.get()); - } else { - Log.w(TAG, "Received unknown type, ignoring..."); - return null; - } - } - - private static @Nullable Long handleGroupCreate(@NonNull Context context, - @NonNull SignalServiceContent content, - @NonNull SignalServiceGroup group, - boolean outgoing, - Long formationTimestamp) - { - GroupDatabase database = DatabaseFactory.getGroupDatabase(context); - String id = GroupUtil.getEncodedId(group); - GroupContext.Builder builder = createGroupContext(group); - builder.setType(GroupContext.Type.UPDATE); - - SignalServiceAttachment avatar = group.getAvatar().orNull(); - List
members = group.getMembers().isPresent() ? new LinkedList<>() : null; - List
admins = group.getAdmins().isPresent() ? new LinkedList<>() : null; - - if (group.getMembers().isPresent()) { - for (String member : group.getMembers().get()) { - members.add(Address.fromExternal(context, member)); - } - } - - // Loki - Parse admins - if (group.getAdmins().isPresent()) { - for (String admin : group.getAdmins().get()) { - admins.add(Address.fromExternal(context, admin)); - } - } - - database.create(id, group.getName().orNull(), members, - avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins, formationTimestamp); - - return storeMessage(context, content, group, builder.build(), outgoing); - } - - private static @Nullable Long handleGroupUpdate(@NonNull Context context, - @NonNull SignalServiceContent content, - @NonNull SignalServiceGroup group, - @NonNull GroupRecord groupRecord, - boolean outgoing) - { - - GroupDatabase database = DatabaseFactory.getGroupDatabase(context); - ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); - String id = GroupUtil.getEncodedId(group); - Address address = Address.fromExternal(context, GroupUtil.getEncodedId(group)); - Recipient recipient = Recipient.from(context, address, false); - - String userPublicKey = TextSecurePreferences.getLocalNumber(context); - - if (content.getSender().equals(userPublicKey)) { - long threadId = threadDatabase.getThreadIdIfExistsFor(recipient); - return threadId == -1 ? null : threadId; - } - - if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) { - // Loki - Only update the group if the group admin sent the message - if (!groupRecord.getAdmins().contains(Address.fromSerialized(content.getSender()))) { - Log.d("Loki", "Received a group update message from a non-admin user for: " + id +"; ignoring."); - return null; - } - - // Loki - Only process update messages if we're part of the group - Address userMasterDeviceAddress = Address.fromSerialized(userPublicKey); - if (!groupRecord.getMembers().contains(userMasterDeviceAddress) && - !group.getMembers().or(Collections.emptyList()).contains(userPublicKey)) { - Log.d("Loki", "Received a group update message from a group we're not a member of: " + id + "; ignoring."); - database.setActive(id, false); - return null; - } - } - - Set
currentMembers = new HashSet<>(groupRecord.getMembers()); - Set
newMembers = new HashSet<>(); - - for (String messageMember : group.getMembers().get()) { - newMembers.add(Address.fromExternal(context, messageMember)); - } - - // Added members are the members who are present in newMembers but not in currentMembers - Set
addedMembers = new HashSet<>(newMembers); - addedMembers.removeAll(currentMembers); - - // Kicked members are members who are present in currentMembers but not in newMembers - Set
removedMembers = new HashSet<>(currentMembers); - removedMembers.removeAll(newMembers); - - GroupContext.Builder builder = createGroupContext(group); - builder.setType(GroupContext.Type.UPDATE); - - // Update our group members if they're different - if (!currentMembers.equals(newMembers)) { - database.updateMembers(id, new LinkedList<>(newMembers)); - } - - // Add any new or removed members to the group context. - // This will allow us later to iterate over them to check if they left or were added for UI purposes. - for (Address addedMember : addedMembers) { - builder.addNewMembers(addedMember.serialize()); - } - - for (Address removedMember : removedMembers) { - builder.addRemovedMembers(removedMember.serialize()); - } - - if (group.getName().isPresent() || group.getAvatar().isPresent()) { - SignalServiceAttachment avatar = group.getAvatar().orNull(); - database.update(id, group.getName().orNull(), avatar != null ? avatar.asPointer() : null); - } - - if (group.getName().isPresent() && group.getName().get().equals(groupRecord.getTitle())) { - builder.clearName(); - } - - // If we were removed then we need to disable the chat - if (removedMembers.contains(Address.fromSerialized(userPublicKey))) { - database.setActive(id, false); - } else { - if (!groupRecord.isActive()) database.setActive(id, true); - } - - return storeMessage(context, content, group, builder.build(), outgoing); - } - - private static Long handleGroupInfoRequest(@NonNull Context context, - @NonNull SignalServiceContent content, - @NonNull SignalServiceGroup group, - @NonNull GroupRecord record) - { - if (record.getMembers().contains(Address.fromSerialized(content.getSender()))) { - ApplicationContext.getInstance(context) - .getJobManager() - .add(new PushGroupUpdateJob(content.getSender(), group.getGroupId())); - } - return null; - } - - private static Long handleGroupLeave(@NonNull Context context, - @NonNull SignalServiceContent content, - @NonNull SignalServiceGroup group, - @NonNull GroupRecord record, - boolean outgoing) - { - GroupDatabase database = DatabaseFactory.getGroupDatabase(context); - String id = GroupUtil.getEncodedId(group); - List
members = record.getMembers(); - - GroupContext.Builder builder = createGroupContext(group); - builder.setType(GroupContext.Type.QUIT); - - if (members.contains(Address.fromExternal(context, content.getSender()))) { - database.removeMember(id, Address.fromExternal(context, content.getSender())); - if (outgoing) database.setActive(id, false); - - return storeMessage(context, content, group, builder.build(), outgoing); - } - - return null; - } - - - private static @Nullable Long storeMessage(@NonNull Context context, - @NonNull SignalServiceContent content, - @NonNull SignalServiceGroup group, - @NonNull GroupContext storage, - boolean outgoing) - { - if (group.getAvatar().isPresent()) { - ApplicationContext.getInstance(context).getJobManager() - .add(new AvatarDownloadJob(GroupUtil.getEncodedId(group))); - } - - try { - if (outgoing) { - MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context); - Address address = Address.fromExternal(context, GroupUtil.getEncodedId(group)); - Recipient recipient = Recipient.from(context, address, false); - OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, 0, null, Collections.emptyList(), Collections.emptyList()); - long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient); - Address senderAddress = Address.fromExternal(context, content.getSender()); - MessageRecord existingMessage = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(content.getTimestamp(), senderAddress); - long messageId; - if (existingMessage != null) { - messageId = existingMessage.getId(); - } else { - messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null); - } - - mmsDatabase.markAsSent(messageId, true); - - return threadId; - } else { - SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); - String body = Base64.encodeBytes(storage.toByteArray()); - IncomingTextMessage incoming = new IncomingTextMessage(Address.fromExternal(context, content.getSender()), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(group), 0, content.isNeedsReceipt()); - IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body); - - Optional insertResult = smsDatabase.insertMessageInbox(groupMessage); - - if (insertResult.isPresent()) { - ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, insertResult.get().getThreadId()); - return insertResult.get().getThreadId(); - } else { - return null; - } - } - } catch (MmsException e) { - Log.w(TAG, e); - } - - return null; - } - - private static GroupContext.Builder createGroupContext(SignalServiceGroup group) { - GroupContext.Builder builder = GroupContext.newBuilder(); - builder.setId(ByteString.copyFrom(group.getGroupId())); - - if (group.getAvatar().isPresent() && group.getAvatar().get().isPointer()) { - builder.setAvatar(AttachmentPointer.newBuilder() - .setId(group.getAvatar().get().asPointer().getId()) - .setKey(ByteString.copyFrom(group.getAvatar().get().asPointer().getKey())) - .setContentType(group.getAvatar().get().getContentType())); - } - - if (group.getName().isPresent()) { - builder.setName(group.getName().get()); - } - - if (group.getMembers().isPresent()) { - builder.addAllMembers(group.getMembers().get()); - } - - if (group.getAdmins().isPresent()) { - builder.addAllAdmins(group.getAdmins().get()); - } - - return builder; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 9a6f3e34e7..d5b8cf030b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -49,7 +49,6 @@ import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.dependencies.InjectableType; -import org.thoughtcrime.securesms.groups.GroupMessageProcessor; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.linkpreview.Link; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; @@ -229,9 +228,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { if (message.getClosedGroupControlMessage().isPresent()) { ClosedGroupsProtocolV2.handleMessage(context, message.getClosedGroupControlMessage().get(), message.getTimestamp(), envelope.getSource(), content.getSender()); } - if (message.isGroupUpdate()) { - handleGroupMessage(content, message, smsMessageId); - } else if (message.isExpirationUpdate()) { + if (message.isExpirationUpdate()) { handleExpirationUpdate(content, message, smsMessageId); } else if (isMediaMessage) { handleMediaMessage(content, message, smsMessageId, Optional.absent()); @@ -279,50 +276,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } } - private void handleEndSessionMessage(@NonNull SignalServiceContent content, - @NonNull Optional smsMessageId) - { - SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); - IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Address.fromSerialized(content.getSender()), - content.getSenderDevice(), - content.getTimestamp(), - "", Optional.absent(), 0, - content.isNeedsReceipt()); - - Long threadId; - - if (!smsMessageId.isPresent()) { - IncomingEndSessionMessage incomingEndSessionMessage = new IncomingEndSessionMessage(incomingTextMessage); - Optional insertResult = smsDatabase.insertMessageInbox(incomingEndSessionMessage); - - if (insertResult.isPresent()) threadId = insertResult.get().getThreadId(); - else threadId = null; - } else { - smsDatabase.markAsEndSession(smsMessageId.get()); - threadId = smsDatabase.getThreadIdForMessage(smsMessageId.get()); - } - - if (threadId != null) { - messageNotifier.updateNotification(context, threadId); - } - } - - private void handleGroupMessage(@NonNull SignalServiceContent content, - @NonNull SignalServiceDataMessage message, - @NonNull Optional smsMessageId) - throws StorageFailedException - { - GroupMessageProcessor.process(context, content, message, false); - - if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getMessageDestination(content, message).getExpireMessages()) { - handleExpirationUpdate(content, message, Optional.absent()); - } - - if (smsMessageId.isPresent()) { - DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get()); - } - } - private void handleUnknownGroupMessage(@NonNull SignalServiceContent content, @NonNull SignalServiceGroup group) {