Remove GroupContext proto

Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
Josh Perez 2023-04-14 20:52:50 -04:00 committed by GitHub
parent 9bfbee464b
commit 68ae25f5cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 74 additions and 713 deletions

View file

@ -2,7 +2,6 @@
// SPDX-License-Identifier: AGPL-3.0-only
import {
difference,
isEmpty,
isEqual,
isNumber,
@ -14,11 +13,9 @@ import {
partition,
pick,
union,
without,
} from 'lodash';
import type {
CustomError,
GroupV1Update,
MessageAttributesType,
MessageReactionType,
QuotedMessageType,
@ -85,7 +82,6 @@ import {
isDirectConversation,
isGroup,
isGroupV1,
isGroupV2,
isMe,
} from '../util/whatTypeOfConversation';
import { handleMessageSend } from '../util/handleMessageSend';
@ -145,11 +141,9 @@ import { notificationService } from '../services/notifications';
import type { LinkPreviewType } from '../types/message/LinkPreviews';
import * as log from '../logging/log';
import * as Bytes from '../Bytes';
import { computeHash } from '../Crypto';
import { cleanupMessage, deleteMessageData } from '../util/cleanup';
import {
getContact,
getContactId,
getSource,
getSourceUuid,
isCustomError,
@ -173,7 +167,6 @@ import { SeenStatus } from '../MessageSeenStatus';
import { isNewReactionReplacingPrevious } from '../reactions/util';
import { parseBoostBadgeListFromServer } from '../badges/parseBadgesFromServer';
import { GiftBadgeStates } from '../components/conversation/Message';
import { downloadAttachment } from '../util/downloadAttachment';
import type { StickerWithHydratedData } from '../types/Stickers';
import { getStringForConversationMerge } from '../util/getStringForConversationMerge';
import {
@ -2139,7 +2132,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const sourceUuid = message.get('sourceUuid');
const type = message.get('type');
const conversationId = message.get('conversationId');
const GROUP_TYPES = Proto.GroupContext.Type;
const fromContact = getContact(this.attributes);
if (fromContact) {
@ -2352,9 +2344,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
reason: 'handleDataMessage',
})!;
const hasGroupV2Prop = Boolean(initialMessage.groupV2);
const isV1GroupUpdate =
initialMessage.group &&
initialMessage.group.type !== Proto.GroupContext.Type.DELIVER;
// Drop if from blocked user. Only GroupV2 messages should need to be dropped here.
const isBlocked =
@ -2397,7 +2386,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
type === 'incoming' &&
!isDirectConversation(conversation.attributes) &&
!hasGroupV2Prop &&
!isV1GroupUpdate &&
conversation.get('members') &&
!areWeMember
) {
@ -2408,16 +2396,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
return;
}
// Because GroupV1 messages can now be multiplexed into GroupV2 conversations, we
// drop GroupV1 updates in GroupV2 groups.
if (isV1GroupUpdate && isGroupV2(conversation.attributes)) {
log.warn(
`Received GroupV1 update in GroupV2 conversation ${conversation.idForLogging()}. Dropping.`
);
confirm();
return;
}
// Drop incoming messages to announcement only groups where sender is not admin
if (
conversation.get('announcementsOnly') &&
@ -2615,160 +2593,10 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
if (isSupported) {
let attributes = {
const attributes = {
...conversation.attributes,
};
// GroupV1
if (!hasGroupV2Prop && initialMessage.group) {
const pendingGroupUpdate: GroupV1Update = {};
const memberConversations: Array<ConversationModel> =
await Promise.all(
initialMessage.group.membersE164.map((e164: string) =>
window.ConversationController.getOrCreateAndWait(
e164,
'private'
)
)
);
const members = memberConversations.map(c => c.get('id'));
attributes = {
...attributes,
type: 'group',
groupId: initialMessage.group.id,
};
if (initialMessage.group.type === GROUP_TYPES.UPDATE) {
attributes = {
...attributes,
name: initialMessage.group.name,
members: union(members, conversation.get('members')),
};
if (initialMessage.group.name !== conversation.get('name')) {
pendingGroupUpdate.name = initialMessage.group.name;
}
const avatarAttachment = initialMessage.group.avatar;
let downloadedAvatar;
let hash;
if (avatarAttachment) {
try {
downloadedAvatar = await downloadAttachment(avatarAttachment);
if (downloadedAvatar) {
const loadedAttachment =
await window.Signal.Migrations.loadAttachmentData(
downloadedAvatar
);
hash = computeHash(loadedAttachment.data);
}
} catch (err) {
log.info(`${idLog}: group avatar download failed`);
}
}
const existingAvatar = conversation.get('avatar');
if (
// Avatar added
(!existingAvatar && avatarAttachment) ||
// Avatar changed
(existingAvatar && existingAvatar.hash !== hash) ||
// Avatar removed
(existingAvatar && !avatarAttachment)
) {
// Removes existing avatar from disk
if (existingAvatar && existingAvatar.path) {
await window.Signal.Migrations.deleteAttachmentData(
existingAvatar.path
);
}
let avatar = null;
if (downloadedAvatar && avatarAttachment != null) {
const onDiskAttachment =
await Attachment.migrateDataToFileSystem(downloadedAvatar, {
writeNewAttachmentData:
window.Signal.Migrations.writeNewAttachmentData,
logger: log,
});
avatar = {
...onDiskAttachment,
hash,
};
}
if (!avatar) {
attributes.avatar = avatar;
} else {
const { url, path } = avatar;
strictAssert(url, 'Avatar needs url');
strictAssert(path, 'Avatar needs path');
attributes.avatar = {
url,
path,
...avatar,
};
}
pendingGroupUpdate.avatarUpdated = true;
} else {
log.info(
`${idLog}: Group avatar hash matched; not replacing group avatar`
);
}
const differentMembers = difference(
members,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
conversation.get('members')!
);
if (differentMembers.length > 0) {
// Because GroupV1 groups are based on e164 only
const maybeE164s = map(differentMembers, id =>
window.ConversationController.get(id)?.get('e164')
);
const e164s = filter(maybeE164s, isNotNil);
pendingGroupUpdate.joined = [...e164s];
}
if (conversation.get('left')) {
log.warn('re-added to a left group');
attributes.left = false;
conversation.set({ addedBy: getContactId(message.attributes) });
}
} else if (initialMessage.group.type === GROUP_TYPES.QUIT) {
const inGroup = Boolean(
sender &&
(conversation.get('members') || []).includes(sender.id)
);
if (!inGroup) {
const senderString = sender ? sender.idForLogging() : null;
log.info(
`${idLog}: Got 'left' message from someone not in group: ${senderString}. Dropping.`
);
return;
}
if (isMe(sender.attributes)) {
attributes.left = true;
pendingGroupUpdate.left = 'You';
} else {
pendingGroupUpdate.left = sender.get('id');
}
attributes.members = without(
conversation.get('members'),
sender.get('id')
);
}
if (!isEmpty(pendingGroupUpdate)) {
message.set('group_update', pendingGroupUpdate);
}
}
// Drop empty messages after. This needs to happen after the initial
// message.set call and after GroupV1 processing to make sure all possible
// properties are set before we determine that a message is empty.