mirror of
https://github.com/oxen-io/session-android.git
synced 2025-05-10 01:46:49 +00:00
Refactor GroupMessageProcessor
This commit is contained in:
parent
439bdac7f4
commit
04e14dd5dd
@ -8,7 +8,6 @@ import android.support.annotation.Nullable;
|
|||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
@ -18,26 +17,23 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
|
|||||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.LokiDeviceLinkUtilities;
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -45,8 +41,6 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import kotlin.Unit;
|
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
@ -104,13 +98,12 @@ public class GroupMessageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should only create the group if we are part of the member list
|
// Loki - Ignore message if needed
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context));
|
if (ClosedGroupsProtocol.shouldIgnoreMessage(context, group)) {
|
||||||
if (members == null || !members.contains(Address.fromSerialized(hexEncodedPublicKey))) {
|
|
||||||
Log.d("Loki - Group Message", "Received a group create message which doesn't include us in the member list. Ignoring.");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loki - Parse admins
|
||||||
if (group.getAdmins().isPresent()) {
|
if (group.getAdmins().isPresent()) {
|
||||||
for (String admin : group.getAdmins().get()) {
|
for (String admin : group.getAdmins().get()) {
|
||||||
admins.add(Address.fromExternal(context, admin));
|
admins.add(Address.fromExternal(context, admin));
|
||||||
@ -121,7 +114,7 @@ public class GroupMessageProcessor {
|
|||||||
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins);
|
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins);
|
||||||
|
|
||||||
if (group.getMembers().isPresent()) {
|
if (group.getMembers().isPresent()) {
|
||||||
establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
ClosedGroupsProtocol.establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||||
@ -137,21 +130,21 @@ public class GroupMessageProcessor {
|
|||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
String id = GroupUtil.getEncodedId(group);
|
String id = GroupUtil.getEncodedId(group);
|
||||||
|
|
||||||
String ourHexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context));
|
String userMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||||
|
|
||||||
if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) {
|
if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) {
|
||||||
// Only update group if the group admin sent the message
|
// Loki - Only update the group if the group admin sent the message
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
|
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
||||||
if (!groupRecord.getAdmins().contains(Address.fromSerialized(hexEncodedPublicKey))) {
|
if (!groupRecord.getAdmins().contains(Address.fromSerialized(masterDevice))) {
|
||||||
Log.d("Loki - Group Message", "Received a group update message from a non-admin user for " + id +". Ignoring.");
|
Log.d("Loki", "Received a group update message from a non-admin user for: " + id +"; ignoring.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should only process update messages if we're in the group
|
// Loki - Only process update messages if we're part of the group
|
||||||
Address ourAddress = Address.fromSerialized(ourHexEncodedPublicKey);
|
Address userMasterDeviceAddress = Address.fromSerialized(userMasterDevice);
|
||||||
if (!groupRecord.getMembers().contains(ourAddress) &&
|
if (!groupRecord.getMembers().contains(userMasterDeviceAddress) &&
|
||||||
!group.getMembers().or(Collections.emptyList()).contains(ourHexEncodedPublicKey)) {
|
!group.getMembers().or(Collections.emptyList()).contains(userMasterDevice)) {
|
||||||
Log.d("Loki - Group Message", "Received a group update message from a group we are not a member of: " + id + "; ignoring.");
|
Log.d("Loki", "Received a group update message from a group we're not a member of: " + id + "; ignoring.");
|
||||||
database.setActive(id, false);
|
database.setActive(id, false);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -180,8 +173,8 @@ public class GroupMessageProcessor {
|
|||||||
database.updateMembers(id, new LinkedList<>(newMembers));
|
database.updateMembers(id, new LinkedList<>(newMembers));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We add any new or removed members to the group context
|
// 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
|
// This will allow us later to iterate over them to check if they left or were added for UI purposes.
|
||||||
for (Address addedMember : addedMembers) {
|
for (Address addedMember : addedMembers) {
|
||||||
builder.addNewMembers(addedMember.serialize());
|
builder.addNewMembers(addedMember.serialize());
|
||||||
}
|
}
|
||||||
@ -200,13 +193,13 @@ public class GroupMessageProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we were removed then we need to disable the chat
|
// If we were removed then we need to disable the chat
|
||||||
if (removedMembers.contains(Address.fromSerialized(ourHexEncodedPublicKey))) {
|
if (removedMembers.contains(Address.fromSerialized(userMasterDevice))) {
|
||||||
database.setActive(id, false);
|
database.setActive(id, false);
|
||||||
} else {
|
} else {
|
||||||
if (!groupRecord.isActive()) database.setActive(id, true);
|
if (!groupRecord.isActive()) database.setActive(id, true);
|
||||||
|
|
||||||
if (group.getMembers().isPresent()) {
|
if (group.getMembers().isPresent()) {
|
||||||
establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
ClosedGroupsProtocol.establishSessionsWithMembersIfNeeded(context, group.getMembers().get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,8 +211,8 @@ public class GroupMessageProcessor {
|
|||||||
@NonNull SignalServiceGroup group,
|
@NonNull SignalServiceGroup group,
|
||||||
@NonNull GroupRecord record)
|
@NonNull GroupRecord record)
|
||||||
{
|
{
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
|
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
||||||
if (record.getMembers().contains(Address.fromSerialized(hexEncodedPublicKey))) {
|
if (record.getMembers().contains(Address.fromSerialized(masterDevice))) {
|
||||||
ApplicationContext.getInstance(context)
|
ApplicationContext.getInstance(context)
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new PushGroupUpdateJob(content.getSender(), group.getGroupId()));
|
.add(new PushGroupUpdateJob(content.getSender(), group.getGroupId()));
|
||||||
@ -240,9 +233,9 @@ public class GroupMessageProcessor {
|
|||||||
GroupContext.Builder builder = createGroupContext(group);
|
GroupContext.Builder builder = createGroupContext(group);
|
||||||
builder.setType(GroupContext.Type.QUIT);
|
builder.setType(GroupContext.Type.QUIT);
|
||||||
|
|
||||||
String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender());
|
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
||||||
if (members.contains(Address.fromExternal(context, hexEncodedPublicKey))) {
|
if (members.contains(Address.fromExternal(context, masterDevice))) {
|
||||||
database.remove(id, Address.fromExternal(context, hexEncodedPublicKey));
|
database.remove(id, Address.fromExternal(context, masterDevice));
|
||||||
if (outgoing) database.setActive(id, false);
|
if (outgoing) database.setActive(id, false);
|
||||||
|
|
||||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||||
@ -322,32 +315,4 @@ public class GroupMessageProcessor {
|
|||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getMasterHexEncodedPublicKey(Context context, String hexEncodedPublicKey) {
|
|
||||||
String ourPublicKey = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
try {
|
|
||||||
String masterHexEncodedPublicKey = hexEncodedPublicKey.equalsIgnoreCase(ourPublicKey)
|
|
||||||
? TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
|
||||||
: PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(hexEncodedPublicKey), 5000).get();
|
|
||||||
return masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : hexEncodedPublicKey;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return hexEncodedPublicKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void establishSessionsWithMembersIfNeeded(Context context, List<String> members) {
|
|
||||||
String ourNumber = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
for (String member : members) {
|
|
||||||
// Make sure we have session with all of the members secondary devices
|
|
||||||
LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(member).success(devices -> {
|
|
||||||
if (devices.contains(ourNumber)) { return Unit.INSTANCE; }
|
|
||||||
for (String device : devices) {
|
|
||||||
SignalProtocolAddress protocolAddress = new SignalProtocolAddress(device, SignalServiceAddress.DEFAULT_DEVICE_ID);
|
|
||||||
boolean haveSession = new TextSecureSessionStore(context).containsSession(protocolAddress);
|
|
||||||
if (!haveSession) { MessageSender.sendBackgroundSessionRequest(context, device); }
|
|
||||||
}
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public abstract class PushReceivedJob extends BaseJob {
|
|||||||
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
|
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d("Loki", "Failed to process envelope: " + e);
|
Log.d("Loki", "Failed to process envelope due to error: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
package org.thoughtcrime.securesms.loki.protocol
|
package org.thoughtcrime.securesms.loki.protocol
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore
|
||||||
import org.thoughtcrime.securesms.database.Address
|
import org.thoughtcrime.securesms.database.Address
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender
|
import org.thoughtcrime.securesms.sms.MessageSender
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil
|
import org.thoughtcrime.securesms.util.GroupUtil
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||||
|
import org.whispersystems.libsignal.SignalProtocolAddress
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup
|
||||||
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
||||||
|
|
||||||
object ClosedGroupsProtocol {
|
object ClosedGroupsProtocol {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun shouldIgnoreMessage(context: Context, group: SignalServiceGroup): Boolean {
|
||||||
|
val members = group.members
|
||||||
|
val masterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
||||||
|
return !members.isPresent || !members.get().contains(masterDevice)
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getDestinations(groupID: String, context: Context): List<Address> {
|
fun getDestinations(groupID: String, context: Context): List<Address> {
|
||||||
if (GroupUtil.isRSSFeed(groupID)) { return listOf() }
|
if (GroupUtil.isRSSFeed(groupID)) { return listOf() }
|
||||||
@ -51,4 +62,26 @@ object ClosedGroupsProtocol {
|
|||||||
groupDatabase.remove(groupID, Address.fromSerialized(publicKeyToUse))
|
groupDatabase.remove(groupID, Address.fromSerialized(publicKeyToUse))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun establishSessionsWithMembersIfNeeded(context: Context, members: List<String>) {
|
||||||
|
val allDevices = members.flatMap { member ->
|
||||||
|
MultiDeviceProtocol.shared.getAllLinkedDevices(member)
|
||||||
|
}.toMutableSet()
|
||||||
|
val masterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
||||||
|
if (masterPublicKey != null && allDevices.contains(masterPublicKey)) {
|
||||||
|
allDevices.remove(masterPublicKey)
|
||||||
|
}
|
||||||
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||||
|
if (userPublicKey != null && allDevices.contains(userPublicKey)) {
|
||||||
|
allDevices.remove(userPublicKey)
|
||||||
|
}
|
||||||
|
for (device in allDevices) {
|
||||||
|
val address = SignalProtocolAddress(device, SignalServiceAddress.DEFAULT_DEVICE_ID)
|
||||||
|
val hasSession = TextSecureSessionStore(context).containsSession(address)
|
||||||
|
if (!hasSession) {
|
||||||
|
MessageSender.sendBackgroundSessionRequest(context, device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user