Remove isPrivate, isMe, isGroupV1, isGroupV2 from model

This commit is contained in:
Josh Perez 2021-06-07 12:39:13 -04:00 committed by GitHub
parent eaf4036fc8
commit d4875fd8f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 377 additions and 267 deletions

View File

@ -13,6 +13,10 @@ import { SendOptionsType, CallbackResultType } from './textsecure/SendMessage';
import { ConversationModel } from './models/conversations';
import { maybeDeriveGroupV2Id } from './groups';
import { assert } from './util/assert';
import { isGroupV1, isGroupV2 } from './util/whatTypeOfConversation';
import { deprecated } from './util/deprecated';
import { getSendOptions } from './util/getSendOptions';
import { handleMessageSend } from './util/handleMessageSend';
const MAX_MESSAGE_BODY_LENGTH = 64 * 1024;
@ -237,7 +241,7 @@ export class ConversationController {
}
try {
if (conversation.isGroupV1()) {
if (isGroupV1(conversation.attributes)) {
await maybeDeriveGroupV2Id(conversation);
}
await saveConversation(conversation.attributes);
@ -556,7 +560,7 @@ export class ConversationController {
}
let groupV2Id: undefined | string;
if (conversation.isGroupV1()) {
if (isGroupV1(conversation.attributes)) {
// eslint-disable-next-line no-await-in-loop
await maybeDeriveGroupV2Id(conversation);
groupV2Id = conversation.get('derivedGroupV2Id');
@ -564,7 +568,7 @@ export class ConversationController {
groupV2Id,
'checkForConflicts: expected the group V2 ID to have been derived, but it was falsy'
);
} else if (conversation.isGroupV2()) {
} else if (isGroupV2(conversation.attributes)) {
groupV2Id = conversation.get('groupId');
}
@ -573,7 +577,7 @@ export class ConversationController {
if (!existing) {
byGroupV2Id[groupV2Id] = conversation;
} else {
const logParenthetical = conversation.isGroupV1()
const logParenthetical = isGroupV1(conversation.attributes)
? ' (derived from a GV1 group ID)'
: '';
window.log.warn(
@ -581,7 +585,10 @@ export class ConversationController {
);
// Prefer the GV2 group.
if (conversation.isGroupV2() && !existing.isGroupV2()) {
if (
isGroupV2(conversation.attributes) &&
!isGroupV2(existing.attributes)
) {
// eslint-disable-next-line no-await-in-loop
await this.combineConversations(conversation, existing);
byGroupV2Id[groupV2Id] = conversation;
@ -730,16 +737,14 @@ export class ConversationController {
) => Promise<CallbackResultType | void | null>;
sendOptions: SendOptionsType | undefined;
}> {
deprecated('prepareForSend');
// id is any valid conversation identifier
const conversation = this.get(id);
const sendOptions = conversation
? await conversation.getSendOptions(options)
? await getSendOptions(conversation.attributes, options)
: undefined;
const wrap = conversation
? conversation.wrapSend.bind(conversation)
: async (promise: Promise<CallbackResultType | void | null>) => promise;
return { wrap, sendOptions };
return { wrap: handleMessageSend, sendOptions };
}
async getAllGroupsInvolvingId(

View File

@ -43,6 +43,7 @@ import {
UnprocessedType,
UnprocessedUpdateType,
} from './textsecure/Types.d';
import { getSendOptions } from './util/getSendOptions';
const TIMESTAMP_THRESHOLD = 5 * 1000; // 5 seconds
@ -1230,7 +1231,7 @@ export class SignalProtocolStore extends EventsMixin {
await this.archiveSession(id);
// Send a null message with newly-created session
const sendOptions = await conversation.getSendOptions();
const sendOptions = await getSendOptions(conversation.attributes);
await window.textsecure.messaging.sendNullMessage({ uuid }, sendOptions);
} catch (error) {
// If we failed to do the session reset, then we'll allow another attempt sooner

View File

@ -35,6 +35,8 @@ import {
} from './textsecure/MessageReceiver';
import { connectToServerWithStoredCredentials } from './util/connectToServerWithStoredCredentials';
import * as universalExpireTimer from './util/universalExpireTimer';
import { isDirectConversation, isGroupV2 } from './util/whatTypeOfConversation';
import { getSendOptions } from './util/getSendOptions';
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
@ -1955,7 +1957,7 @@ export async function startApp(): Promise<void> {
.getConversations()
.filter(c =>
Boolean(
c.isPrivate() &&
isDirectConversation(c.attributes) &&
c.get('e164') &&
!c.get('uuid') &&
!c.isEverUnregistered()
@ -2502,7 +2504,10 @@ export async function startApp(): Promise<void> {
}
// We drop typing notifications in groups we're not a part of
if (!conversation.isPrivate() && !conversation.hasMember(ourId)) {
if (
!isDirectConversation(conversation.attributes) &&
!conversation.hasMember(ourId)
) {
window.log.warn(
`Received typing indicator for group ${conversation.idForLogging()}, which we're not a part of. Dropping.`
);
@ -2703,7 +2708,7 @@ export async function startApp(): Promise<void> {
id,
'group'
);
if (conversation.isGroupV2()) {
if (isGroupV2(conversation.attributes)) {
window.log.warn(
'Got group sync for v2 group: ',
conversation.idForLogging()
@ -3578,7 +3583,7 @@ export async function startApp(): Promise<void> {
);
const plaintext = PlaintextContent.from(message);
const options = await conversation.getSendOptions();
const options = await getSendOptions(conversation.attributes);
const result = await window.textsecure.messaging.sendRetryRequest({
plaintext,
options,

View File

@ -79,6 +79,13 @@ import { CURRENT_SCHEMA_VERSION as MAX_MESSAGE_SCHEMA } from '../js/modules/type
import { ConversationModel } from './models/conversations';
import { getGroupSizeHardLimit } from './groups/limits';
import { ourProfileKeyService } from './services/ourProfileKey';
import {
isGroupV1 as getIsGroupV1,
isGroupV2 as getIsGroupV2,
isMe,
} from './util/whatTypeOfConversation';
import { handleMessageSend } from './util/handleMessageSend';
import { getSendOptions } from './util/getSendOptions';
export { joinViaLink } from './groups/joinViaLink';
@ -1231,7 +1238,7 @@ export async function modifyGroupV2({
}): Promise<void> {
const idLog = `${name}/${conversation.idForLogging()}`;
if (!conversation.isGroupV2()) {
if (!getIsGroupV2(conversation.attributes)) {
throw new Error(
`modifyGroupV2/${idLog}: Called for non-GroupV2 conversation`
);
@ -1297,13 +1304,13 @@ export async function modifyGroupV2({
? await ourProfileKeyService.get()
: undefined;
const sendOptions = await conversation.getSendOptions();
const sendOptions = await getSendOptions(conversation.attributes);
const timestamp = Date.now();
const {
ContentHint,
} = window.textsecure.protobuf.UnidentifiedSenderMessage.Message;
const promise = conversation.wrapSend(
const promise = handleMessageSend(
window.Signal.Util.sendToGroup(
{
groupV2: conversation.getGroupV2Info({
@ -1676,7 +1683,7 @@ export async function createGroupV2({
const {
ContentHint,
} = window.textsecure.protobuf.UnidentifiedSenderMessage.Message;
const sendOptions = await conversation.getSendOptions();
const sendOptions = await getSendOptions(conversation.attributes);
await wrapWithSyncMessageSend({
conversation,
@ -1729,7 +1736,7 @@ export async function hasV1GroupBeenMigrated(
conversation: ConversationModel
): Promise<boolean> {
const logId = conversation.idForLogging();
const isGroupV1 = conversation.isGroupV1();
const isGroupV1 = getIsGroupV1(conversation.attributes);
if (!isGroupV1) {
window.log.warn(
`checkForGV2Existence/${logId}: Called for non-GroupV1 conversation!`
@ -1766,7 +1773,7 @@ export async function hasV1GroupBeenMigrated(
export async function maybeDeriveGroupV2Id(
conversation: ConversationModel
): Promise<boolean> {
const isGroupV1 = conversation.isGroupV1();
const isGroupV1 = getIsGroupV1(conversation.attributes);
const groupV1Id = conversation.get('groupId');
const derived = conversation.get('derivedGroupV2Id');
@ -1797,7 +1804,7 @@ type MigratePropsType = {
export async function isGroupEligibleToMigrate(
conversation: ConversationModel
): Promise<boolean> {
if (!conversation.isGroupV1()) {
if (!getIsGroupV1(conversation.attributes)) {
return false;
}
@ -1860,7 +1867,7 @@ export async function getGroupMigrationMembers(
`getGroupMigrationMembers/${logId}: membersV2 - missing local contact for ${e164}, skipping.`
);
}
if (!contact.isMe() && window.GV2_MIGRATION_DISABLE_ADD) {
if (!isMe(contact.attributes) && window.GV2_MIGRATION_DISABLE_ADD) {
window.log.warn(
`getGroupMigrationMembers/${logId}: membersV2 - skipping ${e164} due to GV2_MIGRATION_DISABLE_ADD flag`
);
@ -1947,7 +1954,7 @@ export async function getGroupMigrationMembers(
return null;
}
if (!contact.isMe() && window.GV2_MIGRATION_DISABLE_INVITE) {
if (!isMe(contact.attributes) && window.GV2_MIGRATION_DISABLE_INVITE) {
window.log.warn(
`getGroupMigrationMembers/${logId}: pendingMembersV2 - skipping ${e164} due to GV2_MIGRATION_DISABLE_INVITE flag`
);
@ -2173,7 +2180,7 @@ export async function initiateMigrationToGroupV2(
});
} catch (error) {
const logId = conversation.idForLogging();
if (!conversation.isGroupV1()) {
if (!getIsGroupV1(conversation.attributes)) {
throw error;
}
@ -2203,7 +2210,7 @@ export async function initiateMigrationToGroupV2(
const {
ContentHint,
} = window.textsecure.protobuf.UnidentifiedSenderMessage.Message;
const sendOptions = await conversation.getSendOptions();
const sendOptions = await getSendOptions(conversation.attributes);
await wrapWithSyncMessageSend({
conversation,
@ -2361,7 +2368,7 @@ export async function joinGroupV2ViaLinkAndMigrate({
inviteLinkPassword: string;
revision: number;
}): Promise<void> {
const isGroupV1 = conversation.isGroupV1();
const isGroupV1 = getIsGroupV1(conversation.attributes);
const previousGroupV1Id = conversation.get('groupId');
if (!isGroupV1 || !previousGroupV1Id) {
@ -2451,7 +2458,7 @@ export async function respondToGroupV2Migration({
// Ensure we have the credentials we need before attempting GroupsV2 operations
await maybeFetchNewCredentials();
const isGroupV1 = conversation.isGroupV1();
const isGroupV1 = getIsGroupV1(conversation.attributes);
const previousGroupV1Id = conversation.get('groupId');
if (!isGroupV1 || !previousGroupV1Id) {

View File

@ -13,6 +13,7 @@ import {
} from '../groups';
import { arrayBufferToBase64, base64ToArrayBuffer } from '../Crypto';
import { longRunningTaskWrapper } from '../util/longRunningTaskWrapper';
import { isGroupV1 } from '../util/whatTypeOfConversation';
import type { GroupJoinInfoClass } from '../textsecure.d';
import type { ConversationAttributesType } from '../model-types.d';
@ -285,7 +286,7 @@ export async function joinViaLink(hash: string): Promise<void> {
);
}
if (targetConversation.isGroupV1()) {
if (isGroupV1(targetConversation.attributes)) {
await targetConversation.joinGroupV2ViaLinkAndMigrate({
approvalRequired,
inviteLinkPassword,

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,14 @@ import { MIMEType } from '../types/MIME';
import { LinkPreviewType } from '../types/message/LinkPreviews';
import { ourProfileKeyService } from '../services/ourProfileKey';
import { markRead, setToExpire } from '../services/MessageUpdater';
import {
isDirectConversation,
isGroupV1,
isGroupV2,
isMe,
} from '../util/whatTypeOfConversation';
import { handleMessageSend } from '../util/handleMessageSend';
import { getSendOptions } from '../util/getSendOptions';
/* eslint-disable camelcase */
/* eslint-disable more/no-then */
@ -744,7 +752,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
getPropsForSafetyNumberNotification(): SafetyNumberNotificationProps {
const conversation = this.getConversation();
const isGroup = Boolean(conversation && !conversation.isPrivate());
const isGroup = Boolean(
conversation && !isDirectConversation(conversation.attributes)
);
const identifier = this.get('key_changed');
const contact = this.findAndFormatContact(identifier);
@ -981,7 +991,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
: undefined;
const conversation = this.getConversation();
const isGroup = conversation && !conversation.isPrivate();
const isGroup =
conversation && !isDirectConversation(conversation.attributes);
const sticker = this.get('sticker');
const isTapToView = this.isTapToView();
@ -1316,7 +1327,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
let authorTitle: string;
let isFromMe: boolean;
if (contact && contact.isPrivate()) {
if (contact && isDirectConversation(contact.attributes)) {
const contactPhoneNumber = contact.get('e164');
authorId = contact.id;
@ -1328,7 +1339,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
: undefined;
authorProfileName = contact.getProfileName();
authorTitle = contact.getTitle();
isFromMe = contact.isMe();
isFromMe = isMe(contact.attributes);
} else {
window.log.warn(
'getPropsForQuote: contact was missing. This may indicate a bookkeeping error or bad data from another client. Returning a placeholder contact.'
@ -1529,7 +1540,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
return { text: '' };
}
if (fromContact.isMe()) {
if (isMe(fromContact.attributes)) {
messages.push(window.i18n('youUpdatedTheGroup'));
} else {
messages.push(window.i18n('updatedTheGroup', [fromContact.getTitle()]));
@ -1540,7 +1551,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
window.ConversationController.getOrCreate(item, 'private')
);
const joinedWithoutMe = joinedContacts.filter(
contact => !contact.isMe()
contact => !isMe(contact.attributes)
);
if (joinedContacts.length > 1) {
@ -1558,7 +1569,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
groupUpdate.joined[0],
'private'
);
if (joinedContact.isMe()) {
if (isMe(joinedContact.attributes)) {
messages.push(window.i18n('youJoinedTheGroup'));
} else {
messages.push(
@ -2282,13 +2293,13 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
let promise;
const options = await conversation.getSendOptions();
const options = await getSendOptions(conversation.attributes);
const {
ContentHint,
} = window.textsecure.protobuf.UnidentifiedSenderMessage.Message;
if (conversation.isPrivate()) {
if (isDirectConversation(conversation.attributes)) {
const [identifier] = recipients;
promise = window.textsecure.messaging.sendMessageToIdentifier(
identifier,
@ -2351,7 +2362,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
);
}
return this.send(conversation.wrapSend(promise));
return this.send(handleMessageSend(promise));
}
// eslint-disable-next-line class-methods-use-this
@ -2534,7 +2545,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
sendOptions,
} = await window.ConversationController.prepareForSend(identifier);
const group =
groupId && parentConversation?.isGroupV1()
groupId && isGroupV1(parentConversation?.attributes)
? {
id: groupId,
type: window.textsecure.protobuf.GroupContext.Type.DELIVER,
@ -2576,7 +2587,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
[identifier],
contentMessage,
ContentHint.RESENDABLE,
groupId && parentConversation?.isGroupV2() ? groupId : undefined,
groupId && isGroupV2(parentConversation?.attributes)
? groupId
: undefined,
sendOptions
);
@ -2767,7 +2780,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
retryOptions: options,
});
const sendOptions = await conv.getSendOptions();
const sendOptions = await getSendOptions(conv.attributes);
// We don't have to check `sent_to` here, because:
//
@ -2776,11 +2789,11 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// in a single request to the server. So partial success is not
// possible.
await this.send(
conv.wrapSend(
handleMessageSend(
// TODO: DESKTOP-724
// resetSession returns `Array<void>` which is incompatible with the
// expected promise return values. `[]` is truthy and wrapSend assumes
// it's a valid callback result type
// expected promise return values. `[]` is truthy and handleMessageSend
// assumes it's a valid callback result type
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.textsecure.messaging.resetSession(
@ -3601,7 +3614,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// GroupV2
if (initialMessage.groupV2) {
if (conversation.isGroupV1()) {
if (isGroupV1(conversation.attributes)) {
// If we received a GroupV2 message in a GroupV1 group, we migrate!
const { revision, groupChange } = initialMessage.groupV2;
@ -3660,7 +3673,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
e164: source,
uuid: sourceUuid,
})!;
const isGroupV2 = Boolean(initialMessage.groupV2);
const hasGroupV2Prop = Boolean(initialMessage.groupV2);
const isV1GroupUpdate =
initialMessage.group &&
initialMessage.group.type !==
@ -3670,8 +3683,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// after applying the message's associated group changes.
if (
type === 'incoming' &&
!conversation.isPrivate() &&
isGroupV2 &&
!isDirectConversation(conversation.attributes) &&
hasGroupV2Prop &&
(conversation.get('left') ||
!conversation.hasMember(ourConversationId) ||
!conversation.hasMember(senderId))
@ -3690,8 +3703,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// messages. We detect that via a missing 'members' field.
if (
type === 'incoming' &&
!conversation.isPrivate() &&
!isGroupV2 &&
!isDirectConversation(conversation.attributes) &&
!hasGroupV2Prop &&
!isV1GroupUpdate &&
conversation.get('members') &&
(conversation.get('left') || !conversation.hasMember(ourConversationId))
@ -3705,7 +3718,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// Because GroupV1 messages can now be multiplexed into GroupV2 conversations, we
// drop GroupV1 updates in GroupV2 groups.
if (isV1GroupUpdate && conversation.isGroupV2()) {
if (isV1GroupUpdate && isGroupV2(conversation.attributes)) {
window.log.warn(
`Received GroupV1 update in GroupV2 conversation ${conversation.idForLogging()}. Dropping.`
);
@ -3793,7 +3806,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
};
// GroupV1
if (!isGroupV2 && dataMessage.group) {
if (!hasGroupV2Prop && dataMessage.group) {
const pendingGroupUpdate = [];
const memberConversations: Array<ConversationModel> = await Promise.all(
dataMessage.group.membersE164.map((e164: string) =>
@ -3920,7 +3933,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
return;
}
if (sender.isMe()) {
if (isMe(sender.attributes)) {
attributes.left = true;
pendingGroupUpdate.push(['left', 'You']);
} else {
@ -3962,7 +3975,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
message.set({ expireTimer: dataMessage.expireTimer });
}
if (!isGroupV2) {
if (!hasGroupV2Prop) {
if (message.isExpirationTimerUpdate()) {
message.set({
expirationTimerUpdate: {
@ -4023,7 +4036,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
sourceUuid === window.textsecure.storage.user.getUuid()
) {
conversation.set({ profileSharing: true });
} else if (conversation.isPrivate()) {
} else if (isDirectConversation(conversation.attributes)) {
conversation.setProfileKey(profileKey);
} else {
const localId = window.ConversationController.ensureContactIds({
@ -4214,7 +4227,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
// A sync'd message to ourself is automatically considered read/delivered
if (isFirstRun && conversation.isMe()) {
if (isFirstRun && isMe(conversation.attributes)) {
message.set({
read_by: conversation.getRecipients(),
delivered_to: conversation.getRecipients(),

View File

@ -69,6 +69,7 @@ import {
REQUESTED_VIDEO_FRAMERATE,
} from '../calling/constants';
import { notify } from './notify';
import { getSendOptions } from '../util/getSendOptions';
const RINGRTC_HTTP_METHOD_TO_OUR_HTTP_METHOD: Map<
HttpMethod,
@ -783,7 +784,7 @@ export class CallingClass {
}
const groupV2 = conversation.getGroupV2Info();
const sendOptions = await conversation.getSendOptions();
const sendOptions = await getSendOptions(conversation.attributes);
if (!groupV2) {
window.log.error(
'Unable to send group call update message for conversation that lacks groupV2 info'
@ -1408,7 +1409,7 @@ export class CallingClass {
): Promise<boolean> {
const conversation = window.ConversationController.get(remoteUserId);
const sendOptions = conversation
? await conversation.getSendOptions()
? await getSendOptions(conversation.attributes)
: undefined;
if (!window.textsecure.messaging) {

View File

@ -35,6 +35,10 @@ import { sleep } from '../util/sleep';
import { isMoreRecentThan } from '../util/timestamp';
import { isStorageWriteFeatureEnabled } from '../storage/isFeatureEnabled';
import { ourProfileKeyService } from './ourProfileKey';
import {
ConversationTypes,
typeofConversation,
} from '../util/whatTypeOfConversation';
const {
eraseStorageServiceStateFromConversations,
@ -152,22 +156,24 @@ async function generateManifest(
const identifier = new window.textsecure.protobuf.ManifestRecord.Identifier();
let storageRecord;
if (conversation.isMe()) {
const conversationType = typeofConversation(conversation.attributes);
if (conversationType === ConversationTypes.Me) {
storageRecord = new window.textsecure.protobuf.StorageRecord();
// eslint-disable-next-line no-await-in-loop
storageRecord.account = await toAccountRecord(conversation);
identifier.type = ITEM_TYPE.ACCOUNT;
} else if (conversation.isPrivate()) {
} else if (conversationType === ConversationTypes.Direct) {
storageRecord = new window.textsecure.protobuf.StorageRecord();
// eslint-disable-next-line no-await-in-loop
storageRecord.contact = await toContactRecord(conversation);
identifier.type = ITEM_TYPE.CONTACT;
} else if (conversation.isGroupV2()) {
} else if (conversationType === ConversationTypes.GroupV2) {
storageRecord = new window.textsecure.protobuf.StorageRecord();
// eslint-disable-next-line no-await-in-loop
storageRecord.groupV2 = await toGroupV2Record(conversation);
identifier.type = ITEM_TYPE.GROUPV2;
} else if (conversation.isGroupV1()) {
} else if (conversationType === ConversationTypes.GroupV1) {
storageRecord = new window.textsecure.protobuf.StorageRecord();
// eslint-disable-next-line no-await-in-loop
storageRecord.groupV1 = await toGroupV1Record(conversation);

View File

@ -43,6 +43,7 @@ import {
set as setUniversalExpireTimer,
} from '../util/universalExpireTimer';
import { ourProfileKeyService } from './ourProfileKey';
import { isGroupV1, isGroupV2 } from '../util/whatTypeOfConversation';
const { updateConversation } = dataInterface;
@ -241,7 +242,7 @@ export async function toAccountRecord(
uuid: pinnedConversation.get('uuid'),
e164: pinnedConversation.get('e164'),
};
} else if (pinnedConversation.isGroupV1()) {
} else if (isGroupV1(pinnedConversation.attributes)) {
pinnedConversationRecord.identifier = 'legacyGroupId';
const groupId = pinnedConversation.get('groupId');
if (!groupId) {
@ -252,7 +253,7 @@ export async function toAccountRecord(
pinnedConversationRecord.legacyGroupId = fromEncodedBinaryToArrayBuffer(
groupId
);
} else if (pinnedConversation.isGroupV2()) {
} else if (isGroupV2(pinnedConversation.attributes)) {
pinnedConversationRecord.identifier = 'groupMasterKey';
const masterKey = pinnedConversation.get('masterKey');
if (!masterKey) {
@ -508,7 +509,7 @@ export async function mergeGroupV1Record(
// where the binary representation of its ID matches a v2 record in memory.
// Here we ensure that the record we're about to process is GV1 otherwise
// we drop the update.
if (conversation && !conversation.isGroupV1()) {
if (conversation && !isGroupV1(conversation.attributes)) {
throw new Error(
`Record has group type mismatch ${conversation.idForLogging()}`
);
@ -565,7 +566,7 @@ export async function mergeGroupV1Record(
let hasPendingChanges: boolean;
if (conversation.isGroupV1()) {
if (isGroupV1(conversation.attributes)) {
addUnknownFields(groupV1Record, conversation);
hasPendingChanges = doesRecordHavePendingChanges(
@ -684,7 +685,7 @@ export async function mergeGroupV2Record(
const isFirstSync = !window.storage.get('storageFetchComplete');
const dropInitialJoinMessage = isFirstSync;
if (conversation.isGroupV1()) {
if (isGroupV1(conversation.attributes)) {
// If we found a GroupV1 conversation from this incoming GroupV2 record, we need to
// migrate it!

11
ts/util/deprecated.ts Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { getEnvironment, Environment } from '../environment';
import * as log from '../logging/log';
export function deprecated(message?: string): void {
if (getEnvironment() === Environment.Development) {
log.error(new Error(`This method is deprecated: ${message}`));
}
}

View File

@ -40,9 +40,10 @@ export async function getSendOptions(
if (!conversation) {
return;
}
const {
sendMetadata: conversationSendMetadata,
} = await conversation.getSendOptions(options);
const { sendMetadata: conversationSendMetadata } = await getSendOptions(
conversation.attributes,
options
);
Object.assign(sendMetadata, conversationSendMetadata || {});
})
);

View File

@ -38,6 +38,7 @@ import {
import { ContentClass } from '../textsecure.d';
import { assert } from './assert';
import { isGroupV2 } from './whatTypeOfConversation';
const ERROR_EXPIRED_OR_MISSING_DEVICES = 409;
const ERROR_STALE_DEVICES = 410;
@ -116,7 +117,7 @@ export async function sendContentMessageToGroup({
if (
ourConversation?.get('capabilities')?.senderKey &&
conversation.isGroupV2()
isGroupV2(conversation.attributes)
) {
try {
return await sendToGroupViaSenderKey({
@ -138,7 +139,7 @@ export async function sendContentMessageToGroup({
}
}
const groupId = conversation.isGroupV2()
const groupId = isGroupV2(conversation.attributes)
? conversation.get('groupId')
: undefined;
return window.textsecure.messaging.sendGroupProto(
@ -191,7 +192,7 @@ export async function sendToGroupViaSenderKey(options: {
}
const groupId = conversation.get('groupId');
if (!groupId || !conversation.isGroupV2()) {
if (!groupId || !isGroupV2(conversation.attributes)) {
throw new Error(
`sendToGroupViaSenderKey/${logId}: Missing groupId or group is not GV2`
);

View File

@ -2,11 +2,12 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { ConversationModel } from '../models/conversations';
import { isMe } from './whatTypeOfConversation';
export async function shouldRespondWithProfileKey(
sender: ConversationModel
): Promise<boolean> {
if (sender.isMe() || !sender.getAccepted() || sender.isBlocked()) {
if (isMe(sender.attributes) || !sender.getAccepted() || sender.isBlocked()) {
return false;
}

View File

@ -2,6 +2,14 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { ConversationAttributesType } from '../model-types.d';
import { base64ToArrayBuffer, fromEncodedBinaryToArrayBuffer } from '../Crypto';
export enum ConversationTypes {
Me = 'Me',
Direct = 'Direct',
GroupV1 = 'GroupV1',
GroupV2 = 'GroupV2',
}
export function isDirectConversation(
conversationAttrs: ConversationAttributesType
@ -15,3 +23,56 @@ export function isMe(conversationAttrs: ConversationAttributesType): boolean {
const ourUuid = window.textsecure.storage.user.getUuid();
return Boolean((e164 && e164 === ourNumber) || (uuid && uuid === ourUuid));
}
export function isGroupV1(
conversationAttrs: ConversationAttributesType
): boolean {
const { groupId } = conversationAttrs;
if (!groupId) {
return false;
}
const buffer = fromEncodedBinaryToArrayBuffer(groupId);
return buffer.byteLength === window.Signal.Groups.ID_V1_LENGTH;
}
export function isGroupV2(
conversationAttrs: ConversationAttributesType
): boolean {
const { groupId, groupVersion = 0 } = conversationAttrs;
if (!groupId) {
return false;
}
try {
return (
groupVersion === 2 &&
base64ToArrayBuffer(groupId).byteLength === window.Signal.Groups.ID_LENGTH
);
} catch (error) {
window.log.error('isGroupV2: Failed to process groupId in base64!');
return false;
}
}
export function typeofConversation(
conversationAttrs: ConversationAttributesType
): ConversationTypes | undefined {
if (isMe(conversationAttrs)) {
return ConversationTypes.Me;
}
if (isDirectConversation(conversationAttrs)) {
return ConversationTypes.Direct;
}
if (isGroupV2(conversationAttrs)) {
return ConversationTypes.GroupV2;
}
if (isGroupV1(conversationAttrs)) {
return ConversationTypes.GroupV1;
}
return undefined;
}

View File

@ -15,6 +15,12 @@ import { maybeParseUrl } from '../util/url';
import { addReportSpamJob } from '../jobs/helpers/addReportSpamJob';
import { reportSpamJobQueue } from '../jobs/reportSpamJobQueue';
import { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions';
import {
isDirectConversation,
isGroupV1,
isGroupV2,
isMe,
} from '../util/whatTypeOfConversation';
type GetLinkPreviewImageResult = {
data: ArrayBuffer;
@ -486,7 +492,7 @@ Whisper.ConversationView = Whisper.View.extend({
onResetSession: () => this.endSession(),
onSearchInConversation: () => {
const { searchInConversation } = window.reduxActions.search;
const name = this.model.isMe()
const name = isMe(this.model.attributes)
? window.i18n('noteToSelf')
: this.model.getTitle();
searchInConversation(this.model.id, name);
@ -1281,7 +1287,7 @@ Whisper.ConversationView = Whisper.View.extend({
async startMigrationToGV2(): Promise<void> {
const logId = this.model.idForLogging();
if (!this.model.isGroupV1()) {
if (!isGroupV1(this.model.attributes)) {
throw new Error(
`startMigrationToGV2/${logId}: Cannot start, not a GroupV1 group`
);
@ -2682,7 +2688,7 @@ Whisper.ConversationView = Whisper.View.extend({
let model = providedMembers || this.model.contactCollection;
if (!providedMembers && this.model.isGroupV2()) {
if (!providedMembers && isGroupV2(this.model.attributes)) {
model = new Whisper.GroupConversationCollection(
this.model.get('membersV2').map(({ conversationId, role }: any) => ({
conversation: window.ConversationController.get(conversationId),
@ -2738,7 +2744,7 @@ Whisper.ConversationView = Whisper.View.extend({
showSafetyNumber(id: any) {
let conversation;
if (!id && this.model.isPrivate()) {
if (!id && isDirectConversation(this.model.attributes)) {
// eslint-disable-next-line prefer-destructuring
conversation = this.model;
} else {
@ -3786,19 +3792,22 @@ Whisper.ConversationView = Whisper.View.extend({
ToastView = Whisper.InvalidConversationToast;
}
if (
this.model.isPrivate() &&
isDirectConversation(this.model.attributes) &&
(window.storage.isBlocked(this.model.get('e164')) ||
window.storage.isUuidBlocked(this.model.get('uuid')))
) {
ToastView = Whisper.BlockedToast;
}
if (
!this.model.isPrivate() &&
!isDirectConversation(this.model.attributes) &&
window.storage.isGroupBlocked(this.model.get('groupId'))
) {
ToastView = Whisper.BlockedGroupToast;
}
if (!this.model.isPrivate() && this.model.get('left')) {
if (
!isDirectConversation(this.model.attributes) &&
this.model.get('left')
) {
ToastView = Whisper.LeftGroupToast;
}
if (messageText && messageText.length > MAX_MESSAGE_BODY_LENGTH) {