Remove processing of inbound GV1 messages.

fork-5.53.8
Greyson Parrelli 2022-07-29 10:07:12 -04:00
rodzic 5140353722
commit df3399bde5
22 zmienionych plików z 92 dodań i 1054 usunięć

Wyświetl plik

@ -157,7 +157,6 @@ final class GroupManagerV1 {
Recipient recipient = Recipient.resolved(member);
if (recipient.hasE164()) {
e164Members.add(recipient.requireE164());
uuidMembers.add(GroupV1MessageProcessor.createMember(recipient.requireE164()));
}
}
@ -216,6 +215,6 @@ final class GroupManagerV1 {
return Optional.empty();
}
return Optional.of(GroupUtil.createGroupV1LeaveMessage(groupId, groupRecipient));
return Optional.empty();
}
}

Wyświetl plik

@ -1,309 +0,0 @@
package org.thoughtcrime.securesms.groups;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import com.google.protobuf.ByteString;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.MessageDatabase;
import org.thoughtcrime.securesms.database.MessageDatabase.InsertResult;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.AvatarGroupsV1DownloadJob;
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.notifications.v2.ConversationId;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sms.IncomingGroupUpdateMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
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;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
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.GroupContext;
public final class GroupV1MessageProcessor {
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)
throws BadGroupIdException
{
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 = SignalDatabase.groups();
SignalServiceGroup group = groupV1.get();
GroupId id = GroupId.v1(group.getGroupId());
Optional<GroupRecord> 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);
} 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, 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)
{
GroupDatabase database = SignalDatabase.groups();
GroupId.V1 id = GroupId.v1orThrow(group.getGroupId());
GroupContext.Builder builder = createGroupContext(group);
builder.setType(GroupContext.Type.UPDATE);
SignalServiceAttachment avatar = group.getAvatar().orElse(null);
List<RecipientId> members = new LinkedList<>();
if (group.getMembers().isPresent()) {
for (SignalServiceAddress member : group.getMembers().get()) {
members.add(Recipient.externalGV1Member(member).getId());
}
}
database.create(id, group.getName().orElse(null), members,
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null);
Recipient sender = Recipient.externalPush(content.getSender());
if (sender.isSystemContact() || sender.isProfileSharing()) {
Log.i(TAG, "Auto-enabling profile sharing because 'adder' is trusted. contact: " + sender.isSystemContact() + ", profileSharing: " + sender.isProfileSharing());
SignalDatabase.recipients().setProfileSharing(Recipient.externalGroupExact(id).getId(), true);
}
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 = SignalDatabase.groups();
GroupId.V1 id = GroupId.v1orThrow(group.getGroupId());
Set<RecipientId> recordMembers = new HashSet<>(groupRecord.getMembers());
Set<RecipientId> messageMembers = new HashSet<>();
if (group.getMembers().isPresent()) {
for (SignalServiceAddress messageMember : group.getMembers().get()) {
messageMembers.add(Recipient.externalGV1Member(messageMember).getId());
}
}
Set<RecipientId> addedMembers = new HashSet<>(messageMembers);
addedMembers.removeAll(recordMembers);
Set<RecipientId> missingMembers = new HashSet<>(recordMembers);
missingMembers.removeAll(messageMembers);
GroupContext.Builder builder = createGroupContext(group);
builder.setType(GroupContext.Type.UPDATE);
if (addedMembers.size() > 0) {
Set<RecipientId> unionMembers = new HashSet<>(recordMembers);
unionMembers.addAll(messageMembers);
database.updateMembers(id, new LinkedList<>(unionMembers));
builder.clearMembers();
builder.clearMembersE164();
for (RecipientId addedMember : addedMembers) {
Recipient recipient = Recipient.resolved(addedMember);
if (recipient.getE164().isPresent()) {
builder.addMembersE164(recipient.requireE164());
builder.addMembers(createMember(recipient.requireE164()));
}
}
} else {
builder.clearMembers();
builder.clearMembersE164();
}
if (missingMembers.size() > 0) {
// TODO We should tell added and missing about each-other.
}
if (group.getName().isPresent() || group.getAvatar().isPresent()) {
SignalServiceAttachment avatar = group.getAvatar().orElse(null);
database.update(id, group.getName().orElse(null), avatar != null ? avatar.asPointer() : null);
}
if (group.getName().isPresent() && group.getName().get().equals(groupRecord.getTitle())) {
builder.clearName();
}
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 GroupRecord record)
{
Recipient sender = Recipient.externalPush(content.getSender());
if (record.getMembers().contains(sender.getId())) {
ApplicationDependencies.getJobManager().add(new PushGroupUpdateJob(sender.getId(), record.getId()));
}
return null;
}
private static Long handleGroupLeave(@NonNull Context context,
@NonNull SignalServiceContent content,
@NonNull SignalServiceGroup group,
@NonNull GroupRecord record,
boolean outgoing)
{
GroupDatabase database = SignalDatabase.groups();
GroupId id = GroupId.v1orThrow(group.getGroupId());
List<RecipientId> members = record.getMembers();
GroupContext.Builder builder = createGroupContext(group);
builder.setType(GroupContext.Type.QUIT);
RecipientId senderId = RecipientId.from(content.getSender());
if (members.contains(senderId)) {
database.remove(id, senderId);
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()) {
ApplicationDependencies.getJobManager()
.add(new AvatarGroupsV1DownloadJob(GroupId.v1orThrow(group.getGroupId())));
}
try {
if (outgoing) {
MessageDatabase mmsDatabase = SignalDatabase.mms();
RecipientId recipientId = SignalDatabase.recipients().getOrInsertFromGroupId(GroupId.v1orThrow(group.getGroupId()));
Recipient recipient = Recipient.resolved(recipientId);
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(recipient, storage, null, content.getTimestamp(), 0, false, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
mmsDatabase.markAsSent(messageId, true);
return threadId;
} else {
MessageDatabase smsDatabase = SignalDatabase.sms();
String body = Base64.encodeBytes(storage.toByteArray());
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalPush(content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), content.getServerReceivedTimestamp(), System.currentTimeMillis(), body, Optional.of(GroupId.v1orThrow(group.getGroupId())), 0, content.isNeedsReceipt(), content.getServerUuid());
IncomingGroupUpdateMessage groupMessage = new IncomingGroupUpdateMessage(incoming, storage, body);
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
if (insertResult.isPresent()) {
ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(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() &&
group.getAvatar().get().asPointer().getRemoteId().getV2().isPresent())
{
builder.setAvatar(AttachmentPointer.newBuilder()
.setCdnId(group.getAvatar().get().asPointer().getRemoteId().getV2().get())
.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.addAllMembersE164(Stream.of(group.getMembers().get())
.filter(a -> a.getNumber().isPresent())
.map(a -> a.getNumber().get())
.toList());
builder.addAllMembers(Stream.of(group.getMembers().get())
.filter(address -> address.getNumber().isPresent())
.map(address -> address.getNumber().get())
.map(GroupV1MessageProcessor::createMember)
.toList());
}
return builder;
}
public static GroupContext.Member createMember(@NonNull String e164) {
GroupContext.Member.Builder member = GroupContext.Member.newBuilder();
member.setE164(e164);
return member.build();
}
}

Wyświetl plik

@ -124,7 +124,7 @@ public final class GroupsV1MigrationUtil {
break;
case NOT_A_MEMBER:
Log.w(TAG, "The migrated group already exists, but we are not a member. Doing a local leave.");
handleLeftBehind(context, gv1Id, groupRecipient, threadId);
handleLeftBehind(gv1Id);
return;
case FULL_OR_PENDING_MEMBER:
Log.w(TAG, "The migrated group already exists, and we're in it. Continuing on.");
@ -177,7 +177,7 @@ public final class GroupsV1MigrationUtil {
throw new IOException("[Local] The group should exist already!");
} catch (GroupNotAMemberException e) {
Log.w(TAG, "[Local] We are not in the group. Doing a local leave.");
handleLeftBehind(context, gv1Id, groupRecipient, threadId);
handleLeftBehind(gv1Id);
return null;
}
@ -195,15 +195,7 @@ public final class GroupsV1MigrationUtil {
}
}
private static void handleLeftBehind(@NonNull Context context, @NonNull GroupId.V1 gv1Id, @NonNull Recipient groupRecipient, long threadId) {
OutgoingMediaMessage leaveMessage = GroupUtil.createGroupV1LeaveMessage(gv1Id, groupRecipient);
try {
long id = SignalDatabase.mms().insertMessageOutbox(leaveMessage, threadId, false, null);
SignalDatabase.mms().markAsSent(id, true);
} catch (MmsException e) {
Log.w(TAG, "Failed to insert group leave message!", e);
}
private static void handleLeftBehind(@NonNull GroupId.V1 gv1Id) {
SignalDatabase.groups().setActive(gv1Id, false);
SignalDatabase.groups().remove(gv1Id, Recipient.self().getId());
}

Wyświetl plik

@ -56,14 +56,11 @@ public class PushProcessMessageQueueJobMigration extends JobMigration {
if (content != null && content.getDataMessage().isPresent() && content.getDataMessage().get().getGroupContext().isPresent()) {
Log.i(TAG, "Migrating a group message.");
try {
GroupId groupId = GroupUtil.idFromGroupContext(content.getDataMessage().get().getGroupContext().get());
Recipient recipient = Recipient.externalGroupExact(groupId);
suffix = recipient.getId().toQueueKey();
} catch (BadGroupIdException e) {
Log.w(TAG, "Bad groupId! Using default queue.");
}
GroupId groupId = GroupId.v2(content.getDataMessage().get().getGroupContext().get().getMasterKey());
Recipient recipient = Recipient.externalGroupExact(groupId);
suffix = recipient.getId().toQueueKey();
} else if (content != null) {
Log.i(TAG, "Migrating an individual message.");
suffix = RecipientId.from(content.getSender()).toQueueKey();

Wyświetl plik

@ -142,7 +142,6 @@ public final class JobManagerFactories {
put(PushDistributionListSendJob.KEY, new PushDistributionListSendJob.Factory());
put(PushGroupSendJob.KEY, new PushGroupSendJob.Factory());
put(PushGroupSilentUpdateSendJob.KEY, new PushGroupSilentUpdateSendJob.Factory());
put(PushGroupUpdateJob.KEY, new PushGroupUpdateJob.Factory());
put(PushMediaSendJob.KEY, new PushMediaSendJob.Factory());
put(PushNotificationReceiveJob.KEY, new PushNotificationReceiveJob.Factory());
put(PushProcessEarlyMessagesJob.KEY, new PushProcessEarlyMessagesJob.Factory());
@ -156,7 +155,6 @@ public final class JobManagerFactories {
put(RemoteConfigRefreshJob.KEY, new RemoteConfigRefreshJob.Factory());
put(RemoteDeleteSendJob.KEY, new RemoteDeleteSendJob.Factory());
put(ReportSpamJob.KEY, new ReportSpamJob.Factory());
put(RequestGroupInfoJob.KEY, new RequestGroupInfoJob.Factory());
put(ResendMessageJob.KEY, new ResendMessageJob.Factory());
put(ResumableUploadSpecJob.KEY, new ResumableUploadSpecJob.Factory());
put(RequestGroupV2InfoWorkerJob.KEY, new RequestGroupV2InfoWorkerJob.Factory());
@ -240,6 +238,8 @@ public final class JobManagerFactories {
put("StorageSyncJob", new StorageSyncJob.Factory());
put("WakeGroupV2Job", new FailingJob.Factory());
put("LeaveGroupJob", new FailingJob.Factory());
put("PushGroupUpdateJob", new FailingJob.Factory());
put("RequestGroupInfoJob", new FailingJob.Factory());
}};
}

Wyświetl plik

@ -1,163 +0,0 @@
package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import org.thoughtcrime.securesms.database.SignalDatabase;
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.impl.NetworkConstraint;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents;
import org.whispersystems.signalservice.api.crypto.ContentHint;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
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.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
public class PushGroupUpdateJob extends BaseJob {
public static final String KEY = "PushGroupUpdateJob";
private static final String TAG = Log.tag(PushGroupUpdateJob.class);
private static final String KEY_SOURCE = "source";
private static final String KEY_GROUP_ID = "group_id";
private final RecipientId source;
private final GroupId groupId;
public PushGroupUpdateJob(@NonNull RecipientId source, @NonNull GroupId groupId) {
this(new Job.Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(Parameters.UNLIMITED)
.build(),
source,
groupId);
}
private PushGroupUpdateJob(@NonNull Job.Parameters parameters, RecipientId source, @NonNull GroupId groupId) {
super(parameters);
this.source = source;
this.groupId = groupId;
}
@Override
public @NonNull Data serialize() {
return new Data.Builder().putString(KEY_SOURCE, source.serialize())
.putString(KEY_GROUP_ID, groupId.toString())
.build();
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}
Recipient sourceRecipient = Recipient.resolved(source);
if (sourceRecipient.isUnregistered()) {
Log.w(TAG, sourceRecipient.getId() + " not registered!");
return;
}
GroupDatabase groupDatabase = SignalDatabase.groups();
Optional<GroupRecord> record = groupDatabase.getGroup(groupId);
SignalServiceAttachment avatar = null;
if (record == null || !record.isPresent()) {
Log.w(TAG, "No information for group record info request: " + groupId.toString());
return;
}
if (AvatarHelper.hasAvatar(context, record.get().getRecipientId())) {
avatar = SignalServiceAttachmentStream.newStreamBuilder()
.withContentType("image/jpeg")
.withStream(AvatarHelper.getAvatar(context, record.get().getRecipientId()))
.withLength(AvatarHelper.getAvatarLength(context, record.get().getRecipientId()))
.build();
}
List<SignalServiceAddress> members = new LinkedList<>();
for (RecipientId member : record.get().getMembers()) {
Recipient recipient = Recipient.resolved(member);
if (recipient.isMaybeRegistered()) {
members.add(RecipientUtil.toSignalServiceAddress(context, recipient));
}
}
SignalServiceGroup groupContext = SignalServiceGroup.newBuilder(Type.UPDATE)
.withAvatar(avatar)
.withId(groupId.getDecodedId())
.withMembers(members)
.withName(record.get().getTitle())
.build();
RecipientId groupRecipientId = SignalDatabase.recipients().getOrInsertFromGroupId(groupId);
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder()
.asGroupMessage(groupContext)
.withTimestamp(System.currentTimeMillis())
.withExpiration(groupRecipient.getExpiresInSeconds())
.build();
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
messageSender.sendDataMessage(RecipientUtil.toSignalServiceAddress(context, sourceRecipient),
UnidentifiedAccessUtil.getAccessFor(context, sourceRecipient),
ContentHint.DEFAULT,
message,
IndividualSendEvents.EMPTY);
}
@Override
public boolean onShouldRetry(@NonNull Exception e) {
Log.w(TAG, e);
return e instanceof PushNetworkException;
}
@Override
public void onFailure() {
}
public static final class Factory implements Job.Factory<PushGroupUpdateJob> {
@Override
public @NonNull PushGroupUpdateJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
return new PushGroupUpdateJob(parameters,
RecipientId.from(data.getString(KEY_SOURCE)),
GroupId.parseOrThrow(data.getString(KEY_GROUP_ID)));
}
}
}

Wyświetl plik

@ -24,7 +24,7 @@ import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.whispersystems.signalservice.api.groupsv2.NoCredentialForRedemptionTimeException;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.IOException;
@ -120,27 +120,23 @@ public final class PushProcessMessageJob extends BaseJob {
.setMaxAttempts(Parameters.UNLIMITED);
if (content != null) {
SignalServiceGroupContext signalServiceGroupContext = GroupUtil.getGroupContextIfPresent(content);
SignalServiceGroupV2 signalServiceGroupContext = GroupUtil.getGroupContextIfPresent(content);
if (signalServiceGroupContext != null) {
try {
GroupId groupId = GroupUtil.idFromGroupContext(signalServiceGroupContext);
GroupId groupId = GroupId.v2(signalServiceGroupContext.getMasterKey());
queueName = getQueueName(Recipient.externalPossiblyMigratedGroup(groupId).getId());
queueName = getQueueName(Recipient.externalPossiblyMigratedGroup(groupId).getId());
if (groupId.isV2()) {
int localRevision = SignalDatabase.groups().getGroupV2Revision(groupId.requireV2());
if (groupId.isV2()) {
int localRevision = SignalDatabase.groups().getGroupV2Revision(groupId.requireV2());
if (signalServiceGroupContext.getGroupV2().get().getRevision() > localRevision ||
SignalDatabase.groups().getGroupV1ByExpectedV2(groupId.requireV2()).isPresent())
{
Log.i(TAG, "Adding network constraint to group-related job.");
builder.addConstraint(NetworkConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(30));
}
if (signalServiceGroupContext.getRevision() > localRevision ||
SignalDatabase.groups().getGroupV1ByExpectedV2(groupId.requireV2()).isPresent())
{
Log.i(TAG, "Adding network constraint to group-related job.");
builder.addConstraint(NetworkConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(30));
}
} catch (BadGroupIdException e) {
Log.w(TAG, "Bad groupId! Using default queue. ID: " + content.getTimestamp());
}
} else if (content.getSyncMessage().isPresent() && content.getSyncMessage().get().getSent().isPresent() && content.getSyncMessage().get().getSent().get().getDestination().isPresent()) {
queueName = getQueueName(RecipientId.from(content.getSyncMessage().get().getSent().get().getDestination().get()));

Wyświetl plik

@ -1,122 +0,0 @@
package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
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.impl.NetworkConstraint;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents;
import org.whispersystems.signalservice.api.crypto.ContentHint;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
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.push.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class RequestGroupInfoJob extends BaseJob {
public static final String KEY = "RequestGroupInfoJob";
@SuppressWarnings("unused")
private static final String TAG = Log.tag(RequestGroupInfoJob.class);
private static final String KEY_SOURCE = "source";
private static final String KEY_GROUP_ID = "group_id";
private final RecipientId source;
private final GroupId groupId;
public RequestGroupInfoJob(@NonNull RecipientId source, @NonNull GroupId groupId) {
this(new Job.Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(Parameters.UNLIMITED)
.build(),
source,
groupId);
}
private RequestGroupInfoJob(@NonNull Job.Parameters parameters, @NonNull RecipientId source, @NonNull GroupId groupId) {
super(parameters);
this.source = source;
this.groupId = groupId;
}
@Override
public @NonNull Data serialize() {
return new Data.Builder().putString(KEY_SOURCE, source.serialize())
.putString(KEY_GROUP_ID, groupId.toString())
.build();
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@Override
public void onRun() throws IOException, UntrustedIdentityException {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}
SignalServiceGroup group = SignalServiceGroup.newBuilder(Type.REQUEST_INFO)
.withId(groupId.getDecodedId())
.build();
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder()
.asGroupMessage(group)
.withTimestamp(System.currentTimeMillis())
.build();
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
Recipient recipient = Recipient.resolved(source);
if (recipient.isUnregistered()) {
Log.w(TAG, recipient.getId() + " is unregistered!");
return;
}
messageSender.sendDataMessage(RecipientUtil.toSignalServiceAddress(context, recipient),
UnidentifiedAccessUtil.getAccessFor(context, recipient),
ContentHint.IMPLICIT,
message,
IndividualSendEvents.EMPTY);
}
@Override
public boolean onShouldRetry(@NonNull Exception e) {
if (e instanceof ServerRejectedException) return false;
return e instanceof PushNetworkException;
}
@Override
public void onFailure() {
}
public static final class Factory implements Job.Factory<RequestGroupInfoJob> {
@Override
public @NonNull RequestGroupInfoJob create(@NonNull Parameters parameters, @NonNull Data data) {
return new RequestGroupInfoJob(parameters,
RecipientId.from(data.getString(KEY_SOURCE)),
GroupId.parseOrThrow(data.getString(KEY_GROUP_ID)));
}
}
}

Wyświetl plik

@ -30,7 +30,7 @@ import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import java.io.Closeable;
import java.io.IOException;
@ -177,24 +177,19 @@ public class IncomingMessageProcessor {
}
private boolean needsToEnqueueProcessing(@NonNull DecryptionResult result) {
SignalServiceGroupContext groupContext = GroupUtil.getGroupContextIfPresent(result.getContent());
SignalServiceGroupV2 groupContext = GroupUtil.getGroupContextIfPresent(result.getContent());
if (groupContext != null) {
try {
GroupId groupId = GroupUtil.idFromGroupContext(groupContext);
GroupId groupId = GroupId.v2(groupContext.getMasterKey());
if (groupId.isV2()) {
String queueName = PushProcessMessageJob.getQueueName(Recipient.externalPossiblyMigratedGroup(groupId).getId());
GroupDatabase groupDatabase = SignalDatabase.groups();
if (groupId.isV2()) {
String queueName = PushProcessMessageJob.getQueueName(Recipient.externalPossiblyMigratedGroup(groupId).getId());
GroupDatabase groupDatabase = SignalDatabase.groups();
return !jobManager.isQueueEmpty(queueName) ||
groupContext.getGroupV2().get().getRevision() > groupDatabase.getGroupV2Revision(groupId.requireV2()) ||
groupDatabase.getGroupV1ByExpectedV2(groupId.requireV2()).isPresent();
} else {
return false;
}
} catch (BadGroupIdException e) {
Log.w(TAG, "Bad group ID!");
return !jobManager.isQueueEmpty(queueName) ||
groupContext.getRevision() > groupDatabase.getGroupV2Revision(groupId.requireV2()) ||
groupDatabase.getGroupV1ByExpectedV2(groupId.requireV2()).isPresent();
} else {
return false;
}
} else if (result.getContent() != null) {

Wyświetl plik

@ -69,7 +69,6 @@ import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
import org.thoughtcrime.securesms.groups.GroupV1MessageProcessor;
import org.thoughtcrime.securesms.groups.GroupsV1MigrationUtil;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
@ -92,7 +91,6 @@ import org.thoughtcrime.securesms.jobs.PushProcessEarlyMessagesJob;
import org.thoughtcrime.securesms.jobs.PushProcessMessageJob;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob;
import org.thoughtcrime.securesms.jobs.ResendMessageJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
@ -142,8 +140,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.api.messages.SignalServicePreview;
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
@ -283,7 +279,7 @@ public final class MessageContentProcessor {
boolean isGv2Message = groupId.isPresent() && groupId.get().isV2();
if (isGv2Message) {
if (handleGv2PreProcessing(groupId.orElse(null).requireV2(), content, content.getDataMessage().get().getGroupContext().get().getGroupV2().get(), senderRecipient)) {
if (handleGv2PreProcessing(groupId.orElse(null).requireV2(), content, content.getDataMessage().get().getGroupContext().get(), senderRecipient)) {
return;
}
}
@ -292,7 +288,6 @@ public final class MessageContentProcessor {
if (isInvalidMessage(message)) handleInvalidMessage(content.getSender(), content.getSenderDevice(), groupId, content.getTimestamp(), smsMessageId);
else if (message.isEndSession()) messageId = handleEndSessionMessage(content, smsMessageId, senderRecipient);
else if (message.isGroupV1Update()) handleGroupV1Message(content, message, smsMessageId, groupId.get().requireV1(), senderRecipient, threadRecipient, receivedTime);
else if (message.isExpirationUpdate()) messageId = handleExpirationUpdate(content, message, smsMessageId, groupId, senderRecipient, threadRecipient, receivedTime, false);
else if (message.getReaction().isPresent() && message.getStoryContext().isPresent()) messageId = handleStoryReaction(content, message, senderRecipient);
else if (message.getReaction().isPresent()) messageId = handleReaction(content, message, senderRecipient);
@ -516,20 +511,6 @@ public final class MessageContentProcessor {
return false;
}
private static @Nullable SignalServiceGroupContext getGroupContextIfPresent(@NonNull SignalServiceContent content) {
if (content.getDataMessage().isPresent() && content.getDataMessage().get().getGroupContext().isPresent()) {
return content.getDataMessage().get().getGroupContext().get();
} else if (content.getSyncMessage().isPresent() &&
content.getSyncMessage().get().getSent().isPresent() &&
content.getSyncMessage().get().getSent().get().getDataMessage().get().getGroupContext().isPresent())
{
return content.getSyncMessage().get().getSent().get().getDataMessage().get().getGroupContext().get();
} else {
return null;
}
}
/**
* Attempts to update the group to the revision mentioned in the message.
* If the local version is at least the revision in the message it will not query the server.
@ -790,51 +771,20 @@ public final class MessageContentProcessor {
return threadId;
}
private void handleGroupV1Message(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId,
@NonNull GroupId.V1 groupId,
@NonNull Recipient senderRecipient,
@NonNull Recipient threadRecipient,
long receivedTime)
throws StorageFailedException, BadGroupIdException
{
log(content.getTimestamp(), "GroupV1 message.");
GroupV1MessageProcessor.process(context, content, message, false);
handlePossibleExpirationUpdate(content, message, Optional.of(groupId), senderRecipient, threadRecipient, receivedTime);
if (smsMessageId.isPresent()) {
SignalDatabase.sms().deleteMessage(smsMessageId.get());
}
}
private void handleUnknownGroupMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceGroupContext group,
@NonNull SignalServiceGroupV2 group,
@NonNull Recipient senderRecipient)
throws BadGroupIdException
{
log(content.getTimestamp(), "Unknown group message.");
if (group.getGroupV1().isPresent()) {
SignalServiceGroup groupV1 = group.getGroupV1().get();
if (groupV1.getType() != SignalServiceGroup.Type.REQUEST_INFO) {
ApplicationDependencies.getJobManager().add(new RequestGroupInfoJob(senderRecipient.getId(), GroupId.v1(groupV1.getGroupId())));
} else {
warn(content.getTimestamp(), "Received a REQUEST_INFO message for a group we don't know about. Ignoring.");
}
} else if (group.getGroupV2().isPresent()) {
warn(content.getTimestamp(), "Received a GV2 message for a group we have no knowledge of -- attempting to fix this state.");
ServiceId authServiceId = ServiceId.parseOrNull(content.getDestinationUuid());
if (authServiceId == null) {
warn(content.getTimestamp(), "Group message missing destination uuid, defaulting to ACI");
authServiceId = SignalStore.account().requireAci();
}
SignalDatabase.groups().fixMissingMasterKey(authServiceId, group.getGroupV2().get().getMasterKey());
} else {
warn(content.getTimestamp(), "Received a message for a group we don't know about without a group context. Ignoring.");
warn(content.getTimestamp(), "Received a GV2 message for a group we have no knowledge of -- attempting to fix this state.");
ServiceId authServiceId = ServiceId.parseOrNull(content.getDestinationUuid());
if (authServiceId == null) {
warn(content.getTimestamp(), "Group message missing destination uuid, defaulting to ACI");
authServiceId = SignalStore.account().requireAci();
}
SignalDatabase.groups().fixMissingMasterKey(authServiceId, group.getMasterKey());
}
/**
@ -876,8 +826,8 @@ public final class MessageContentProcessor {
return null;
}
int expiresInSeconds = message.getExpiresInSeconds();
Optional<SignalServiceGroupContext> groupContext = message.getGroupContext();
int expiresInSeconds = message.getExpiresInSeconds();
Optional<SignalServiceGroupV2> groupContext = message.getGroupContext();
if (threadRecipient.getExpiresInSeconds() == expiresInSeconds) {
log(String.valueOf(content.getTimestamp()), "No change in message expiry for group. Ignoring.");
@ -1212,8 +1162,8 @@ public final class MessageContentProcessor {
SignalServiceDataMessage dataMessage = message.getDataMessage().get();
if (dataMessage.isGroupV2Message()) {
GroupId.V2 groupId = GroupId.v2(dataMessage.getGroupContext().get().getGroupV2().get().getMasterKey());
if (handleGv2PreProcessing(groupId, content, dataMessage.getGroupContext().get().getGroupV2().get(), senderRecipient)) {
GroupId.V2 groupId = GroupId.v2(dataMessage.getGroupContext().get().getMasterKey());
if (handleGv2PreProcessing(groupId, content, dataMessage.getGroupContext().get(), senderRecipient)) {
return;
}
}
@ -1224,9 +1174,6 @@ public final class MessageContentProcessor {
handleGroupRecipientUpdate(message, content.getTimestamp());
} else if (dataMessage.isEndSession()) {
threadId = handleSynchronizeSentEndSessionMessage(message, content.getTimestamp());
} else if (dataMessage.isGroupV1Update()) {
Long gv1ThreadId = GroupV1MessageProcessor.process(context, content, dataMessage, true);
threadId = gv1ThreadId == null ? -1 : gv1ThreadId;
} else if (dataMessage.isGroupV2Update()) {
handleSynchronizeSentGv2Update(content, message);
threadId = SignalDatabase.threads().getOrCreateThreadIdFor(getSyncMessageDestination(message));
@ -1249,7 +1196,7 @@ public final class MessageContentProcessor {
threadId = handleSynchronizeSentTextMessage(message, content.getTimestamp());
}
if (dataMessage.getGroupContext().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.idFromGroupContext(dataMessage.getGroupContext().get()))) {
if (dataMessage.getGroupContext().isPresent() && groupDatabase.isUnknownGroup(GroupId.v2(dataMessage.getGroupContext().get().getMasterKey()))) {
handleUnknownGroupMessage(content, dataMessage.getGroupContext().get(), senderRecipient);
}
@ -1284,7 +1231,7 @@ public final class MessageContentProcessor {
log(content.getTimestamp(), "Synchronize sent GV2 update for message with timestamp " + message.getTimestamp());
SignalServiceDataMessage dataMessage = message.getDataMessage().get();
SignalServiceGroupV2 signalServiceGroupV2 = dataMessage.getGroupContext().get().getGroupV2().get();
SignalServiceGroupV2 signalServiceGroupV2 = dataMessage.getGroupContext().get();
GroupId.V2 groupIdV2 = GroupId.v2(signalServiceGroupV2.getMasterKey());
if (!updateGv2GroupFromServerOrP2PChange(content, signalServiceGroupV2)) {
@ -3012,9 +2959,7 @@ public final class MessageContentProcessor {
return database.insertMessageInbox(textMessage);
}
private Recipient getSyncMessageDestination(@NonNull SentTranscriptMessage message)
throws BadGroupIdException
{
private Recipient getSyncMessageDestination(@NonNull SentTranscriptMessage message) {
return getGroupRecipient(message.getDataMessage().get().getGroupContext()).orElseGet(() -> Recipient.externalPush(message.getDestination().get()));
}
@ -3023,13 +2968,12 @@ public final class MessageContentProcessor {
return getGroupRecipient(message != null ? message.getGroupContext() : Optional.empty()).orElseGet(() -> Recipient.externalPush(content.getSender()));
}
private Optional<Recipient> getGroupRecipient(Optional<SignalServiceGroupContext> message)
throws BadGroupIdException
{
private Optional<Recipient> getGroupRecipient(Optional<SignalServiceGroupV2> message) {
if (message.isPresent()) {
return Optional.of(Recipient.externalPossiblyMigratedGroup(GroupUtil.idFromGroupContext(message.get())));
return Optional.of(Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.get().getMasterKey())));
} else {
return Optional.empty();
}
return Optional.empty();
}
private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient senderRecipient, @NonNull Recipient conversationRecipient, int device) {
@ -3053,15 +2997,6 @@ public final class MessageContentProcessor {
GroupDatabase groupDatabase = SignalDatabase.groups();
Optional<GroupId> groupId = GroupUtil.idFromGroupContext(message.getGroupContext());
if (groupId.isPresent() &&
groupId.get().isV1() &&
message.isGroupV1Update() &&
groupDatabase.groupExists(groupId.get().requireV1().deriveV2MigrationGroupId()))
{
warn(String.valueOf(content.getTimestamp()), "Ignoring V1 update for a group we've already migrated to V2.");
return true;
}
if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) {
return sender.isBlocked();
}
@ -3070,11 +3005,10 @@ public final class MessageContentProcessor {
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getSticker().isPresent();
boolean isExpireMessage = message.isExpirationUpdate();
boolean isGv2Update = message.isGroupV2Update();
boolean isContentMessage = !message.isGroupV1Update() && !isGv2Update && !isExpireMessage && (isTextMessage || isMediaMessage);
boolean isContentMessage = !isGv2Update && !isExpireMessage && (isTextMessage || isMediaMessage);
boolean isGroupActive = groupId.isPresent() && groupDatabase.isActive(groupId.get());
boolean isLeaveMessage = message.getGroupContext().isPresent() && message.getGroupContext().get().getGroupV1Type() == SignalServiceGroup.Type.QUIT;
return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage && !isGv2Update);
return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isGv2Update);
} else {
return sender.isBlocked();
}

Wyświetl plik

@ -207,15 +207,7 @@ public final class MessageDecryptionUtil {
if (sender == null) throw new NoSenderException();
GroupId groupId = null;
if (e.getGroup().isPresent()) {
try {
groupId = GroupUtil.idFromGroupContext(e.getGroup().get());
} catch (BadGroupIdException ex) {
Log.w(TAG, "Bad group id found in unsupported data message", ex);
}
}
GroupId groupId = e.getGroup().isPresent() ? GroupId.v2(e.getGroup().get().getMasterKey()) : null;
return new ExceptionMetadata(sender, e.getSenderDevice(), groupId);
}

Wyświetl plik

@ -11,9 +11,8 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.GroupUtil
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2
import java.util.Optional
class IncomingMediaMessage(
@ -96,7 +95,7 @@ class IncomingMediaMessage(
viewOnce: Boolean,
unidentified: Boolean,
body: Optional<String>,
group: Optional<SignalServiceGroupContext>,
group: Optional<SignalServiceGroupV2>,
attachments: Optional<List<SignalServiceAttachment>>,
quote: Optional<QuoteModel>,
sharedContacts: Optional<List<Contact>>,
@ -107,7 +106,7 @@ class IncomingMediaMessage(
giftBadge: GiftBadge?
) : this(
from = from,
groupId = if (group.isPresent) GroupUtil.idFromGroupContextOrThrow(group.get()) else null,
groupId = if (group.isPresent) GroupId.v2(group.get().masterKey) else null,
body = body.orElse(null),
isPushMessage = true,
storyType = storyType,

Wyświetl plik

@ -6,31 +6,23 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.google.protobuf.ByteString;
import org.signal.core.util.StringUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.groups.BadGroupIdException;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@ -44,7 +36,7 @@ public final class GroupUtil {
/**
* @return The group context present on the content if one exists, otherwise null.
*/
public static @Nullable SignalServiceGroupContext getGroupContextIfPresent(@Nullable SignalServiceContent content) {
public static @Nullable SignalServiceGroupV2 getGroupContextIfPresent(@Nullable SignalServiceContent content) {
if (content == null) {
return null;
} else if (content.getDataMessage().isPresent() && content.getDataMessage().get().getGroupContext().isPresent()) {
@ -56,11 +48,7 @@ public final class GroupUtil {
{
return content.getSyncMessage().get().getSent().get().getDataMessage().get().getGroupContext().get();
} else if (content.getStoryMessage().isPresent() && content.getStoryMessage().get().getGroupContext().isPresent()) {
try {
return SignalServiceGroupContext.create(null, content.getStoryMessage().get().getGroupContext().get());
} catch (InvalidMessageException e) {
throw new AssertionError(e);
}
return content.getStoryMessage().get().getGroupContext().get();
} else {
return null;
}
@ -69,36 +57,12 @@ public final class GroupUtil {
/**
* Result may be a v1 or v2 GroupId.
*/
public static @NonNull GroupId idFromGroupContext(@NonNull SignalServiceGroupContext groupContext)
throws BadGroupIdException
{
if (groupContext.getGroupV1().isPresent()) {
return GroupId.v1(groupContext.getGroupV1().get().getGroupId());
} else if (groupContext.getGroupV2().isPresent()) {
return GroupId.v2(groupContext.getGroupV2().get().getMasterKey());
} else {
throw new AssertionError();
}
}
public static @NonNull GroupId idFromGroupContextOrThrow(@NonNull SignalServiceGroupContext groupContext) {
try {
return idFromGroupContext(groupContext);
} catch (BadGroupIdException e) {
throw new AssertionError(e);
}
}
/**
* Result may be a v1 or v2 GroupId.
*/
public static @NonNull Optional<GroupId> idFromGroupContext(@NonNull Optional<SignalServiceGroupContext> groupContext)
throws BadGroupIdException
{
public static @NonNull Optional<GroupId> idFromGroupContext(@NonNull Optional<SignalServiceGroupV2> groupContext) {
if (groupContext.isPresent()) {
return Optional.of(idFromGroupContext(groupContext.get()));
return Optional.of(GroupId.v2(groupContext.get().getMasterKey()));
} else {
return Optional.empty();
}
return Optional.empty();
}
public static @NonNull GroupMasterKey requireMasterKey(@NonNull byte[] masterKey) {
@ -129,36 +93,14 @@ public final class GroupUtil {
@NonNull GroupId.Push groupId)
{
if (groupId.isV2()) {
GroupDatabase groupDatabase = SignalDatabase.groups();
GroupDatabase.GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
GroupDatabase.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
SignalServiceGroupV2 group = SignalServiceGroupV2.newBuilder(v2GroupProperties.getGroupMasterKey())
.withRevision(v2GroupProperties.getGroupRevision())
.build();
dataMessageBuilder.asGroupMessage(group);
} else {
dataMessageBuilder.asGroupMessage(new SignalServiceGroup(groupId.getDecodedId()));
}
}
public static OutgoingGroupUpdateMessage createGroupV1LeaveMessage(@NonNull GroupId.V1 groupId,
@NonNull Recipient groupRecipient)
{
GroupContext groupContext = GroupContext.newBuilder()
.setId(ByteString.copyFrom(groupId.getDecodedId()))
.setType(GroupContext.Type.QUIT)
.build();
return new OutgoingGroupUpdateMessage(groupRecipient,
groupContext,
null,
System.currentTimeMillis(),
0,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList());
GroupDatabase groupDatabase = SignalDatabase.groups();
GroupDatabase.GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
GroupDatabase.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
SignalServiceGroupV2 group = SignalServiceGroupV2.newBuilder(v2GroupProperties.getGroupMasterKey())
.withRevision(v2GroupProperties.getGroupRevision())
.build();
dataMessageBuilder.asGroupMessage(group);
}
}
public static class GroupDescription {

Wyświetl plik

@ -10,7 +10,6 @@ import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData;
import org.thoughtcrime.securesms.jobs.FailingJob;
import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob;
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -29,35 +28,6 @@ public class RecipientIdFollowUpJobMigrationTest {
@Mock
private MockedStatic<Job.Parameters> jobParametersMockedStatic;
@Test
public void migrate_requestGroupInfoJob_good() throws Exception {
JobData testData = new JobData("RequestGroupInfoJob", null, new Data.Builder().putString("source", "1")
.putString("group_id", "__textsecure_group__!abcdef0123456789abcdef0123456789")
.build());
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
JobData converted = subject.migrate(testData);
assertEquals("RequestGroupInfoJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("source"));
assertEquals("__textsecure_group__!abcdef0123456789abcdef0123456789", converted.getData().getString("group_id"));
new RequestGroupInfoJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_requestGroupInfoJob_bad() throws Exception {
JobData testData = new JobData("RequestGroupInfoJob", null, new Data.Builder().putString("source", "1")
.build());
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
JobData converted = subject.migrate(testData);
assertEquals("FailingJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
new FailingJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_sendDeliveryReceiptJob_good() throws Exception {
JobData testData = new JobData("SendDeliveryReceiptJob", null, new Data.Builder().putString("recipient", "1")

Wyświetl plik

@ -19,10 +19,8 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob;
import org.thoughtcrime.securesms.jobs.PushGroupSendJob;
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
import org.thoughtcrime.securesms.jobs.PushMediaSendJob;
import org.thoughtcrime.securesms.jobs.PushTextSendJob;
import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob;
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
import org.thoughtcrime.securesms.jobs.SmsSendJob;
@ -83,24 +81,6 @@ public class RecipientIdJobMigrationTest {
new MultiDeviceViewOnceOpenJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_requestGroupInfoJob() throws Exception {
JobData testData = new JobData("RequestGroupInfoJob", null, new Data.Builder().putString("source", "+16101234567")
.putString("group_id", "__textsecure_group__!abcdef0123456789abcdef0123456789")
.build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("RequestGroupInfoJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("source"));
assertEquals("__textsecure_group__!abcdef0123456789abcdef0123456789", converted.getData().getString("group_id"));
new RequestGroupInfoJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_sendDeliveryReceiptJob() throws Exception {
JobData testData = new JobData("SendDeliveryReceiptJob", null, new Data.Builder().putString("address", "+16101234567")
@ -180,24 +160,6 @@ public class RecipientIdJobMigrationTest {
new PushGroupSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_pushGroupUpdateJob() throws Exception {
JobData testData = new JobData("PushGroupUpdateJob", null, new Data.Builder().putString("source", "+16101234567")
.putString("group_id", "__textsecure_group__!abcdef0123456789abcdef0123456789")
.build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("PushGroupUpdateJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("source"));
assertEquals("__textsecure_group__!abcdef0123456789abcdef0123456789", converted.getData().getString("group_id"));
new PushGroupUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_directoryRefreshJob_null() throws Exception {
JobData testData = new JobData("DirectoryRefreshJob", "DirectoryRefreshJob", new Data.Builder().putString("address", null).putBoolean("notify_of_new_users", true).build());

Wyświetl plik

@ -36,8 +36,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.api.messages.SignalServicePreview;
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
@ -102,7 +100,6 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Attach
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.CallMessage;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Content;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMessage;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.NullMessage;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Preview;
@ -834,14 +831,7 @@ public class SignalServiceMessageSender {
}
if (message.getGroupContext().isPresent()) {
SignalServiceGroupContext groupContext = message.getGroupContext().get();
if (groupContext.getGroupV1().isPresent()) {
builder.setGroup(createGroupContent(groupContext.getGroupV1().get()));
}
if (groupContext.getGroupV2().isPresent()) {
builder.setGroupV2(createGroupContent(groupContext.getGroupV2().get()));
}
builder.setGroupV2(createGroupContent(message.getGroupContext().get()));
}
if (message.isEndSession()) {
@ -1473,47 +1463,6 @@ public class SignalServiceMessageSender {
return builder;
}
private GroupContext createGroupContent(SignalServiceGroup group) throws IOException {
GroupContext.Builder builder = GroupContext.newBuilder();
builder.setId(ByteString.copyFrom(group.getGroupId()));
if (group.getType() != SignalServiceGroup.Type.DELIVER) {
if (group.getType() == SignalServiceGroup.Type.UPDATE) builder.setType(GroupContext.Type.UPDATE);
else if (group.getType() == SignalServiceGroup.Type.QUIT) builder.setType(GroupContext.Type.QUIT);
else if (group.getType() == SignalServiceGroup.Type.REQUEST_INFO) builder.setType(GroupContext.Type.REQUEST_INFO);
else throw new AssertionError("Unknown type: " + group.getType());
if (group.getName().isPresent()) {
builder.setName(group.getName().get());
}
if (group.getMembers().isPresent()) {
for (SignalServiceAddress address : group.getMembers().get()) {
if (address.getNumber().isPresent()) {
builder.addMembersE164(address.getNumber().get());
GroupContext.Member.Builder memberBuilder = GroupContext.Member.newBuilder();
memberBuilder.setE164(address.getNumber().get());
builder.addMembers(memberBuilder.build());
}
}
}
if (group.getAvatar().isPresent()) {
if (group.getAvatar().get().isStream()) {
builder.setAvatar(createAttachmentPointer(group.getAvatar().get().asStream()));
} else {
builder.setAvatar(createAttachmentPointer(group.getAvatar().get().asPointer()));
}
}
} else {
builder.setType(GroupContext.Type.DELIVER);
}
return builder.build();
}
private static GroupContextV2 createGroupContent(SignalServiceGroupV2 group) {
GroupContextV2.Builder builder = GroupContextV2.newBuilder()
.setMasterKey(ByteString.copyFrom(group.getMasterKey().serialize()))

Wyświetl plik

@ -594,15 +594,8 @@ public final class SignalServiceContent {
SignalServiceProtos.DataMessage content)
throws UnsupportedDataMessageException, InvalidMessageStructureException
{
SignalServiceGroupV2 groupInfoV2 = createGroupV2Info(content);
Optional<SignalServiceGroupContext> groupContext;
try {
groupContext = SignalServiceGroupContext.createOptional(null, groupInfoV2);
} catch (InvalidMessageException e) {
throw new InvalidMessageStructureException(e);
}
SignalServiceGroupV2 groupInfoV2 = createGroupV2Info(content);
Optional<SignalServiceGroupV2> groupContext = Optional.ofNullable(groupInfoV2);
List<SignalServiceAttachment> attachments = new LinkedList<>();
boolean endSession = ((content.getFlags() & SignalServiceProtos.DataMessage.Flags.END_SESSION_VALUE ) != 0);
@ -649,7 +642,6 @@ public final class SignalServiceContent {
}
return new SignalServiceDataMessage(metadata.getTimestamp(),
null,
groupInfoV2,
attachments,
content.hasBody() ? content.getBody() : null,

Wyświetl plik

@ -27,7 +27,7 @@ public class SignalServiceDataMessage {
private final long timestamp;
private final Optional<List<SignalServiceAttachment>> attachments;
private final Optional<String> body;
private final Optional<SignalServiceGroupContext> group;
private final Optional<SignalServiceGroupV2> group;
private final Optional<byte[]> profileKey;
private final boolean endSession;
private final boolean expirationUpdate;
@ -50,7 +50,6 @@ public class SignalServiceDataMessage {
* Construct a SignalServiceDataMessage.
*
* @param timestamp The sent timestamp.
* @param group The group information (or null if none).
* @param groupV2 The group information (or null if none).
* @param attachments The attachments (or null if none).
* @param body The message contents.
@ -58,7 +57,6 @@ public class SignalServiceDataMessage {
* @param expiresInSeconds Number of seconds in which the message should disappear after being seen.
*/
SignalServiceDataMessage(long timestamp,
SignalServiceGroup group,
SignalServiceGroupV2 groupV2,
List<SignalServiceAttachment> attachments,
String body,
@ -80,12 +78,7 @@ public class SignalServiceDataMessage {
StoryContext storyContext,
GiftBadge giftBadge)
{
try {
this.group = SignalServiceGroupContext.createOptional(group, groupV2);
} catch (InvalidMessageException e) {
throw new AssertionError(e);
}
this.group = Optional.ofNullable(groupV2);
this.timestamp = timestamp;
this.body = OptionalUtil.absentIfEmpty(body);
this.endSession = endSession;
@ -156,7 +149,7 @@ public class SignalServiceDataMessage {
/**
* @return The message group context (if any).
*/
public Optional<SignalServiceGroupContext> getGroupContext() {
public Optional<SignalServiceGroupV2> getGroupContext() {
return group;
}
@ -172,20 +165,13 @@ public class SignalServiceDataMessage {
return profileKeyUpdate;
}
public boolean isGroupV1Update() {
return group.isPresent() &&
group.get().getGroupV1().isPresent() &&
group.get().getGroupV1().get().getType() != SignalServiceGroup.Type.DELIVER;
}
public boolean isGroupV2Message() {
return group.isPresent() &&
group.get().getGroupV2().isPresent();
return group.isPresent();
}
public boolean isGroupV2Update() {
return isGroupV2Message() &&
group.get().getGroupV2().get().hasSignedGroupChange() &&
return group.isPresent() &&
group.get().hasSignedGroupChange() &&
!hasRenderableContent();
}
@ -265,8 +251,8 @@ public class SignalServiceDataMessage {
public Optional<byte[]> getGroupId() {
byte[] groupId = null;
if (getGroupContext().isPresent() && getGroupContext().get().getGroupV2().isPresent()) {
SignalServiceGroupV2 gv2 = getGroupContext().get().getGroupV2().get();
if (getGroupContext().isPresent() && getGroupContext().isPresent()) {
SignalServiceGroupV2 gv2 = getGroupContext().get();
groupId = GroupSecretParams.deriveFromMasterKey(gv2.getMasterKey())
.getPublicParams()
.getGroupIdentifier()
@ -284,7 +270,6 @@ public class SignalServiceDataMessage {
private List<Mention> mentions = new LinkedList<>();
private long timestamp;
private SignalServiceGroup group;
private SignalServiceGroupV2 groupV2;
private String body;
private boolean endSession;
@ -309,18 +294,7 @@ public class SignalServiceDataMessage {
return this;
}
public Builder asGroupMessage(SignalServiceGroup group) {
if (this.groupV2 != null) {
throw new AssertionError("Can not contain both V1 and V2 group contexts.");
}
this.group = group;
return this;
}
public Builder asGroupMessage(SignalServiceGroupV2 group) {
if (this.group != null) {
throw new AssertionError("Can not contain both V1 and V2 group contexts.");
}
this.groupV2 = group;
return this;
}
@ -440,7 +414,7 @@ public class SignalServiceDataMessage {
public SignalServiceDataMessage build() {
if (timestamp == 0) timestamp = System.currentTimeMillis();
return new SignalServiceDataMessage(timestamp, group, groupV2, attachments, body, endSession,
return new SignalServiceDataMessage(timestamp, groupV2, attachments, body, endSession,
expiresInSeconds, expirationUpdate, profileKey,
profileKeyUpdate, quote, sharedContacts, previews,
mentions, sticker, viewOnce, reaction, remoteDelete,

Wyświetl plik

@ -1,61 +0,0 @@
package org.whispersystems.signalservice.api.messages;
import org.signal.libsignal.protocol.InvalidMessageException;
import java.util.Optional;
public final class SignalServiceGroupContext {
private final Optional<SignalServiceGroup> groupV1;
private final Optional<SignalServiceGroupV2> groupV2;
private SignalServiceGroupContext(SignalServiceGroup groupV1) {
this.groupV1 = Optional.of(groupV1);
this.groupV2 = Optional.empty();
}
private SignalServiceGroupContext(SignalServiceGroupV2 groupV2) {
this.groupV1 = Optional.empty();
this.groupV2 = Optional.of(groupV2);
}
public Optional<SignalServiceGroup> getGroupV1() {
return groupV1;
}
public Optional<SignalServiceGroupV2> getGroupV2() {
return groupV2;
}
static Optional<SignalServiceGroupContext> createOptional(SignalServiceGroup groupV1, SignalServiceGroupV2 groupV2)
throws InvalidMessageException
{
return Optional.ofNullable(create(groupV1, groupV2));
}
public static SignalServiceGroupContext create(SignalServiceGroup groupV1, SignalServiceGroupV2 groupV2)
throws InvalidMessageException
{
if (groupV1 == null && groupV2 == null) {
return null;
}
if (groupV1 != null && groupV2 != null) {
throw new InvalidMessageException("Message cannot have both V1 and V2 group contexts.");
}
if (groupV1 != null) {
return new SignalServiceGroupContext(groupV1);
} else {
return new SignalServiceGroupContext(groupV2);
}
}
public SignalServiceGroup.Type getGroupV1Type() {
if (groupV1.isPresent()) {
return groupV1.get().getType();
}
return null;
}
}

Wyświetl plik

@ -1,7 +1,7 @@
package org.whispersystems.signalservice.internal.push;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import java.util.Optional;
@ -12,14 +12,14 @@ import java.util.Optional;
*/
public abstract class UnsupportedDataMessageException extends Exception {
private final String sender;
private final int senderDevice;
private final Optional<SignalServiceGroupContext> group;
private final String sender;
private final int senderDevice;
private final Optional<SignalServiceGroupV2> group;
protected UnsupportedDataMessageException(String message,
String sender,
int senderDevice,
Optional<SignalServiceGroupContext> group)
Optional<SignalServiceGroupV2> group)
{
super(message);
this.sender = sender;
@ -35,7 +35,7 @@ public abstract class UnsupportedDataMessageException extends Exception {
return senderDevice;
}
public Optional<SignalServiceGroupContext> getGroup() {
public Optional<SignalServiceGroupV2> getGroup() {
return group;
}
}

Wyświetl plik

@ -1,7 +1,7 @@
package org.whispersystems.signalservice.internal.push;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import java.util.Optional;
@ -16,7 +16,7 @@ public final class UnsupportedDataMessageProtocolVersionException extends Unsupp
int requiredVersion,
String sender,
int senderDevice,
Optional<SignalServiceGroupContext> group) {
Optional<SignalServiceGroupV2> group) {
super("Required version: " + requiredVersion + ", Our version: " + currentVersion, sender, senderDevice, group);
this.requiredVersion = requiredVersion;
}

Wyświetl plik

@ -313,7 +313,7 @@ message DataMessage {
optional string body = 1;
repeated AttachmentPointer attachments = 2;
optional GroupContext group = 3;
reserved /*groupV1*/ 3;
optional GroupContextV2 groupV2 = 15;
optional uint32 flags = 4;
optional uint32 expireTimer = 5;