Skip to content

Commit

Permalink
GV2 group context proto.
Browse files Browse the repository at this point in the history
  • Loading branch information
alan-signal authored and greyson-signal committed Mar 27, 2020
1 parent 20d1a93 commit 640c82d
Show file tree
Hide file tree
Showing 15 changed files with 351 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;

import java.util.Collections;
Expand All @@ -46,22 +47,29 @@
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;

public class GroupMessageProcessor {
public final class GroupV1MessageProcessor {

private static final String TAG = GroupMessageProcessor.class.getSimpleName();
private static final String TAG = Log.tag(GroupV1MessageProcessor.class);

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) {
SignalServiceGroupContext signalServiceGroupContext = message.getGroupContext().get();
Optional<SignalServiceGroup> groupV1 = signalServiceGroupContext.getGroupV1();

if (signalServiceGroupContext.getGroupV2().isPresent()) {
throw new AssertionError("Cannot process GV2");
}

if (!groupV1.isPresent() || groupV1.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();
SignalServiceGroup group = groupV1.get();
GroupId id = GroupId.v1(group.getGroupId());
Optional<GroupRecord> record = database.getGroup(id);

Expand Down Expand Up @@ -278,7 +286,7 @@ private static GroupContext.Builder createGroupContext(SignalServiceGroup group)
.map(a -> a.getNumber().get())
.toList());
builder.addAllMembers(Stream.of(group.getMembers().get())
.map(GroupMessageProcessor::createMember)
.map(GroupV1MessageProcessor::createMember)
.toList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private static GroupActionResult sendGroupUpdate(@NonNull Context cont

for (RecipientId member : members) {
Recipient recipient = Recipient.resolved(member);
uuidMembers.add(GroupMessageProcessor.createMember(RecipientUtil.toSignalServiceAddress(context, recipient)));
uuidMembers.add(GroupV1MessageProcessor.createMember(RecipientUtil.toSignalServiceAddress(context, recipient)));
}

GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.PushDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.util.guava.Optional;
Expand Down Expand Up @@ -233,7 +233,7 @@ private static PushProcessMessageJob.ExceptionMetadata toExceptionMetadata(@NonN

return new PushProcessMessageJob.ExceptionMetadata(sender,
e.getSenderDevice(),
e.getGroup().transform(g -> GroupId.v1(g.getGroupId())).orNull());
e.getGroup().transform(GroupUtil::idFromGroupContext).orNull());
}

private static PushProcessMessageJob.ExceptionMetadata toExceptionMetadata(@NonNull ProtocolException e) throws NoSenderException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
import org.thoughtcrime.securesms.groups.GroupV1MessageProcessor;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobManager;
Expand Down Expand Up @@ -75,6 +75,7 @@
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
Expand All @@ -86,6 +87,7 @@
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
Expand Down Expand Up @@ -263,17 +265,24 @@ private void handleMessage(@NonNull byte[] plaintextDataBuffer, @NonNull Optiona
if (content.getDataMessage().isPresent()) {
SignalServiceDataMessage message = content.getDataMessage().get();
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent() || message.getSticker().isPresent();
Optional<GroupId> groupId = GroupUtil.idFromGroupContext(message.getGroupContext());
boolean isGv2Message = groupId.isPresent() && groupId.get().isV2();

if (isInvalidMessage(message)) handleInvalidMessage(content.getSender(), content.getSenderDevice(), toEncodedId(message.getGroupInfo()), content.getTimestamp(), smsMessageId);
if (isGv2Message) {
Log.w(TAG, "Ignoring GV2 message.");
return;
}

if (isInvalidMessage(message)) handleInvalidMessage(content.getSender(), content.getSenderDevice(), groupId, content.getTimestamp(), smsMessageId);
else if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId);
else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId);
else if (message.isGroupV1Update()) handleGroupV1Message(content, message, smsMessageId);
else if (message.isExpirationUpdate()) handleExpirationUpdate(content, message, smsMessageId);
else if (message.getReaction().isPresent()) handleReaction(content, message);
else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId);
else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId);
else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId, groupId);

if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupId.v1(message.getGroupInfo().get().getGroupId()))) {
handleUnknownGroupMessage(content, message.getGroupInfo().get());
if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) {
handleUnknownGroupMessage(content, message.getGroupContext().get());
}

if (message.getProfileKey().isPresent()) {
Expand Down Expand Up @@ -327,10 +336,6 @@ private void handleMessage(@NonNull byte[] plaintextDataBuffer, @NonNull Optiona
}
}

private static @NonNull Optional<GroupId> toEncodedId(@NonNull Optional<SignalServiceGroup> groupInfo) {
return groupInfo.transform(g -> GroupId.v1(g.getGroupId()));
}

private void handleExceptionMessage(@NonNull ExceptionMetadata e, @NonNull Optional<Long> smsMessageId) {
switch (messageState) {

Expand Down Expand Up @@ -415,7 +420,7 @@ private void handleCallIceUpdateMessage(@NonNull SignalServiceContent content,
{
Log.i(TAG, "handleCallIceUpdateMessage... " + messages.size());

ArrayList<IceCandidateParcel> iceCandidates = new ArrayList(messages.size());
ArrayList<IceCandidateParcel> iceCandidates = new ArrayList<>(messages.size());
long callId = -1;
for (IceUpdateMessage iceMessage : messages) {
iceCandidates.add(new IceCandidateParcel(iceMessage));
Expand Down Expand Up @@ -526,12 +531,12 @@ private long handleSynchronizeSentEndSessionMessage(@NonNull SentTranscriptMessa
return threadId;
}

private void handleGroupMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId)
private void handleGroupV1Message(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId)
throws StorageFailedException
{
GroupMessageProcessor.process(context, content, message, false);
GroupV1MessageProcessor.process(context, content, message, false);

if (message.getExpiresInSeconds() != 0 && message.getExpiresInSeconds() != getMessageDestination(content, message).getExpireMessages()) {
handleExpirationUpdate(content, message, Optional.absent());
Expand All @@ -543,12 +548,17 @@ private void handleGroupMessage(@NonNull SignalServiceContent content,
}

private void handleUnknownGroupMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceGroup group)
@NonNull SignalServiceGroupContext group)
{
if (group.getType() != SignalServiceGroup.Type.REQUEST_INFO) {
ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(Recipient.externalPush(context, content.getSender()).getId(), GroupId.v1(group.getGroupId())));
if (group.getGroupV1().isPresent()) {
SignalServiceGroup groupV1 = group.getGroupV1().get();
if (groupV1.getType() != SignalServiceGroup.Type.REQUEST_INFO) {
ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(Recipient.externalPush(context, content.getSender()).getId(), GroupId.v1(groupV1.getGroupId())));
} else {
Log.w(TAG, "Received a REQUEST_INFO message for a group we don't know about. Ignoring.");
}
} else {
Log.w(TAG, "Received a REQUEST_INFO message for a group we don't know about. Ignoring.");
Log.w(TAG, "Received a message for a group we don't know about without a GV1 context. Ignoring.");
}
}

Expand All @@ -567,7 +577,7 @@ private void handleExpirationUpdate(@NonNull SignalServiceContent content,
false,
content.isNeedsReceipt(),
Optional.absent(),
message.getGroupInfo(),
message.getGroupContext(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Expand Down Expand Up @@ -729,8 +739,8 @@ private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content,
handleGroupRecipientUpdate(message);
} else if (message.getMessage().isEndSession()) {
threadId = handleSynchronizeSentEndSessionMessage(message);
} else if (message.getMessage().isGroupUpdate()) {
threadId = GroupMessageProcessor.process(context, content, message.getMessage(), true);
} else if (message.getMessage().isGroupV1Update()) {
threadId = GroupV1MessageProcessor.process(context, content, message.getMessage(), true);
} else if (message.getMessage().isExpirationUpdate()) {
threadId = handleSynchronizeSentExpirationUpdate(message);
} else if (message.getMessage().getReaction().isPresent()) {
Expand All @@ -743,8 +753,8 @@ private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content,
threadId = handleSynchronizeSentTextMessage(message);
}

if (message.getMessage().getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupId.v1(message.getMessage().getGroupInfo().get().getGroupId()))) {
handleUnknownGroupMessage(content, message.getMessage().getGroupInfo().get());
if (message.getMessage().getGroupContext().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.idFromGroupContext(message.getMessage().getGroupContext().get()))) {
handleUnknownGroupMessage(content, message.getMessage().getGroupContext().get());
}

if (message.getMessage().getProfileKey().isPresent()) {
Expand Down Expand Up @@ -854,7 +864,7 @@ private void handleMediaMessage(@NonNull SignalServiceContent content,
message.isViewOnce(),
content.isNeedsReceipt(),
message.getBody(),
message.getGroupInfo(),
message.getGroupContext(),
message.getAttachments(),
quote,
sharedContacts,
Expand Down Expand Up @@ -1040,7 +1050,8 @@ private void updateGroupReceiptStatus(@NonNull SentTranscriptMessage message, lo

private void handleTextMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId)
@NonNull Optional<Long> smsMessageId,
@NonNull Optional<GroupId> groupId)
throws StorageFailedException
{
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
Expand All @@ -1053,15 +1064,15 @@ private void handleTextMessage(@NonNull SignalServiceContent content,

Long threadId;

if (smsMessageId.isPresent() && !message.getGroupInfo().isPresent()) {
if (smsMessageId.isPresent() && !message.getGroupContext().isPresent()) {
threadId = database.updateBundleMessageBody(smsMessageId.get(), body).second;
} else {
notifyTypingStoppedFromIncomingMessage(recipient, content.getSender(), content.getSenderDevice());

IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.externalPush(context, content.getSender()).getId(),
content.getSenderDevice(),
message.getTimestamp(), body,
toEncodedId(message.getGroupInfo()),
groupId,
message.getExpiresInSeconds() * 1000L,
content.isNeedsReceipt());

Expand Down Expand Up @@ -1488,20 +1499,20 @@ private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int sen
return database.insertMessageInbox(textMessage);
}

private Recipient getSyncMessageDestination(SentTranscriptMessage message) {
if (message.getMessage().getGroupInfo().isPresent()) {
return Recipient.externalGroup(context, GroupId.v1(message.getMessage().getGroupInfo().get().getGroupId()));
} else {
return Recipient.externalPush(context, message.getDestination().get());
}
private Recipient getSyncMessageDestination(@NonNull SentTranscriptMessage message) {
return getGroupRecipient(message.getMessage().getGroupContext())
.or(() -> Recipient.externalPush(context, message.getDestination().get()));
}

private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
if (message.getGroupInfo().isPresent()) {
return Recipient.externalGroup(context, GroupId.v1(message.getGroupInfo().get().getGroupId()));
} else {
return Recipient.externalPush(context, content.getSender());
}
private Recipient getMessageDestination(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message)
{
return getGroupRecipient(message.getGroupContext())
.or(() -> Recipient.externalPush(context, content.getSender()));
}

private Optional<Recipient> getGroupRecipient(Optional<SignalServiceGroupContext> message) {
return message.transform(groupContext -> Recipient.externalGroup(context, GroupUtil.idFromGroupContext(groupContext)));
}

private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient conversationRecipient, @NonNull SignalServiceAddress sender, int device) {
Expand Down Expand Up @@ -1530,8 +1541,7 @@ private boolean shouldIgnore(@Nullable SignalServiceContent content) {
return true;
} else if (conversation.isGroup()) {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
Optional<GroupId> groupId = message.getGroupInfo().isPresent() ? Optional.of(GroupId.v1(message.getGroupInfo().get().getGroupId()))
: Optional.absent();
Optional<GroupId> groupId = message.getGroupContext().transform(GroupUtil::idFromGroupContext);

if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) {
return false;
Expand All @@ -1540,9 +1550,9 @@ private boolean shouldIgnore(@Nullable SignalServiceContent content) {
boolean isTextMessage = message.getBody().isPresent();
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent();
boolean isExpireMessage = message.isExpirationUpdate();
boolean isContentMessage = !message.isGroupUpdate() && !isExpireMessage && (isTextMessage || isMediaMessage);
boolean isContentMessage = !message.isGroupV1Update() && !isExpireMessage && (isTextMessage || isMediaMessage);
boolean isGroupActive = groupId.isPresent() && groupDatabase.isActive(groupId.get());
boolean isLeaveMessage = message.getGroupInfo().isPresent() && message.getGroupInfo().get().getType() == SignalServiceGroup.Type.QUIT;
boolean isLeaveMessage = message.getGroupContext().isPresent() && message.getGroupContext().get().getGroupV1Type() == SignalServiceGroup.Type.QUIT;

return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage);
} else {
Expand Down

0 comments on commit 640c82d

Please sign in to comment.