Use the profile key from the latest group change

This commit is contained in:
Fedor Indutny 2023-10-02 22:19:55 +02:00 committed by GitHub
parent 69c0cad14c
commit 1efc9274ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -24,6 +24,7 @@ import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64';
import { assertDev, strictAssert } from './util/assert'; import { assertDev, strictAssert } from './util/assert';
import { isMoreRecentThan } from './util/timestamp'; import { isMoreRecentThan } from './util/timestamp';
import { MINUTE, DurationInSeconds, SECOND } from './util/durations'; import { MINUTE, DurationInSeconds, SECOND } from './util/durations';
import { drop } from './util/drop';
import { dropNull } from './util/dropNull'; import { dropNull } from './util/dropNull';
import type { import type {
ConversationAttributesType, ConversationAttributesType,
@ -267,16 +268,12 @@ if (!isNumber(MAX_MESSAGE_SCHEMA)) {
); );
} }
type MemberType = {
profileKey: string;
aci: ServiceIdString;
};
type UpdatesResultType = { type UpdatesResultType = {
// The array of new messages to be added into the message timeline // The array of new messages to be added into the message timeline
groupChangeMessages: Array<GroupChangeMessageType>; groupChangeMessages: Array<GroupChangeMessageType>;
// The set of members in the group, and we largely just pull profile keys for each, // The map of members in the group, and we largely just pull profile keys for each,
// because the group membership is updated in newAttributes // because the group membership is updated in newAttributes
members: Array<MemberType>; newProfileKeys: Map<AciString, string>;
// To be merged into the conversation model // To be merged into the conversation model
newAttributes: ConversationAttributesType; newAttributes: ConversationAttributesType;
}; };
@ -2442,7 +2439,7 @@ export async function initiateMigrationToGroupV2(
updates: { updates: {
newAttributes, newAttributes,
groupChangeMessages, groupChangeMessages,
members: [], newProfileKeys: new Map(),
}, },
}); });
@ -2645,7 +2642,7 @@ export async function joinGroupV2ViaLinkAndMigrate({
updates: { updates: {
newAttributes, newAttributes,
groupChangeMessages, groupChangeMessages,
members: [], newProfileKeys: new Map(),
}, },
}); });
@ -2806,7 +2803,7 @@ export async function respondToGroupV2Migration({
seenStatus: SeenStatus.Unseen, seenStatus: SeenStatus.Unseen,
}, },
], ],
members: [], newProfileKeys: new Map(),
}, },
}); });
return; return;
@ -2828,7 +2825,7 @@ export async function respondToGroupV2Migration({
seenStatus: SeenStatus.Seen, seenStatus: SeenStatus.Seen,
}, },
], ],
members: [], newProfileKeys: new Map(),
}, },
}); });
return; return;
@ -2899,7 +2896,7 @@ export async function respondToGroupV2Migration({
updates: { updates: {
newAttributes, newAttributes,
groupChangeMessages, groupChangeMessages,
members: profileKeysToMembers(newProfileKeys), newProfileKeys: profileKeysToMap(newProfileKeys),
}, },
}); });
@ -3035,7 +3032,7 @@ async function updateGroup(
): Promise<void> { ): Promise<void> {
const logId = conversation.idForLogging(); const logId = conversation.idForLogging();
const { newAttributes, groupChangeMessages, members } = updates; const { newAttributes, groupChangeMessages, newProfileKeys } = updates;
const ourAci = window.textsecure.storage.user.getCheckedAci(); const ourAci = window.textsecure.storage.user.getCheckedAci();
const ourPni = window.textsecure.storage.user.getPni(); const ourPni = window.textsecure.storage.user.getPni();
@ -3105,22 +3102,19 @@ async function updateGroup(
const contactsWithoutProfileKey = new Array<ConversationModel>(); const contactsWithoutProfileKey = new Array<ConversationModel>();
// Capture profile key for each member in the group, if we don't have it yet // Capture profile key for each member in the group, if we don't have it yet
members.forEach(member => { for (const [aci, profileKey] of newProfileKeys) {
const contact = window.ConversationController.getOrCreate( const contact = window.ConversationController.getOrCreate(aci, 'private');
member.aci,
'private'
);
if ( if (
!isMe(contact.attributes) && !isMe(contact.attributes) &&
member.profileKey && profileKey &&
member.profileKey.length > 0 && profileKey.length > 0 &&
contact.get('profileKey') !== member.profileKey contact.get('profileKey') !== profileKey
) { ) {
contactsWithoutProfileKey.push(contact); contactsWithoutProfileKey.push(contact);
void contact.setProfileKey(member.profileKey); drop(contact.setProfileKey(profileKey));
}
} }
});
let profileFetches: Promise<Array<void>> | undefined; let profileFetches: Promise<Array<void>> | undefined;
if (contactsWithoutProfileKey.length !== 0) { if (contactsWithoutProfileKey.length !== 0) {
@ -3469,7 +3463,7 @@ async function getGroupUpdates({
return { return {
newAttributes: group, newAttributes: group,
groupChangeMessages: [], groupChangeMessages: [],
members: [], newProfileKeys: new Map(),
}; };
} }
} }
@ -3563,7 +3557,7 @@ async function getGroupUpdates({
return { return {
newAttributes: group, newAttributes: group,
groupChangeMessages: [], groupChangeMessages: [],
members: [], newProfileKeys: new Map(),
}; };
} }
@ -3637,7 +3631,7 @@ async function updateGroupViaPreJoinInfo({
current: newAttributes, current: newAttributes,
dropInitialJoinMessage: false, dropInitialJoinMessage: false,
}), }),
members: [], newProfileKeys: new Map(),
}; };
} }
@ -3687,7 +3681,7 @@ async function updateGroupViaState({
current: newAttributes, current: newAttributes,
dropInitialJoinMessage, dropInitialJoinMessage,
}), }),
members: profileKeysToMembers(newProfileKeys), newProfileKeys: profileKeysToMap(newProfileKeys),
}; };
} }
@ -3721,7 +3715,7 @@ async function updateGroupViaSingleChange({
); );
const { const {
newAttributes, newAttributes,
members, newProfileKeys,
groupChangeMessages: catchupMessages, groupChangeMessages: catchupMessages,
} = await updateGroupViaLogs({ } = await updateGroupViaLogs({
group: singleChangeResult.newAttributes, group: singleChangeResult.newAttributes,
@ -3756,7 +3750,10 @@ async function updateGroupViaSingleChange({
// keep the final group attributes generated, as well as any new members. // keep the final group attributes generated, as well as any new members.
return { return {
groupChangeMessages, groupChangeMessages,
members: [...singleChangeResult.members, ...members], newProfileKeys: new Map([
...singleChangeResult.newProfileKeys,
...newProfileKeys,
]),
newAttributes, newAttributes,
}; };
} }
@ -3886,7 +3883,7 @@ async function generateLeftGroupChanges(
current: newAttributes, current: newAttributes,
old: group, old: group,
}), }),
members: [], newProfileKeys: new Map(),
}; };
} }
@ -3929,7 +3926,7 @@ async function integrateGroupChanges({
const logId = idForLogging(group.groupId); const logId = idForLogging(group.groupId);
let attributes = group; let attributes = group;
const finalMessages: Array<Array<GroupChangeMessageType>> = []; const finalMessages: Array<Array<GroupChangeMessageType>> = [];
const finalMembers: Array<Array<MemberType>> = []; const finalNewProfileKeys = new Map<AciString, string>();
const imax = changes.length; const imax = changes.length;
for (let i = 0; i < imax; i += 1) { for (let i = 0; i < imax; i += 1) {
@ -3956,7 +3953,7 @@ async function integrateGroupChanges({
const { const {
newAttributes, newAttributes,
groupChangeMessages, groupChangeMessages,
members, newProfileKeys,
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
} = await integrateGroupChange({ } = await integrateGroupChange({
group: attributes, group: attributes,
@ -3967,7 +3964,9 @@ async function integrateGroupChanges({
attributes = newAttributes; attributes = newAttributes;
finalMessages.push(groupChangeMessages); finalMessages.push(groupChangeMessages);
finalMembers.push(members); for (const [aci, profileKey] of newProfileKeys) {
finalNewProfileKeys.set(aci, profileKey);
}
} catch (error) { } catch (error) {
log.error( log.error(
`integrateGroupChanges/${logId}: Failed to apply change log, continuing to apply remaining change logs.`, `integrateGroupChanges/${logId}: Failed to apply change log, continuing to apply remaining change logs.`,
@ -4000,14 +3999,14 @@ async function integrateGroupChanges({
return { return {
newAttributes: attributes, newAttributes: attributes,
groupChangeMessages, groupChangeMessages,
members: flatten(finalMembers), newProfileKeys: finalNewProfileKeys,
}; };
} }
return { return {
newAttributes: attributes, newAttributes: attributes,
groupChangeMessages: flatten(finalMessages), groupChangeMessages: flatten(finalMessages),
members: flatten(finalMembers), newProfileKeys: finalNewProfileKeys,
}; };
} }
@ -4067,7 +4066,7 @@ async function integrateGroupChange({
return { return {
newAttributes: group, newAttributes: group,
groupChangeMessages: [], groupChangeMessages: [],
members: [], newProfileKeys: new Map(),
}; };
} }
@ -4099,7 +4098,7 @@ async function integrateGroupChange({
return { return {
newAttributes: group, newAttributes: group,
groupChangeMessages: [], groupChangeMessages: [],
members: [], newProfileKeys: new Map(),
}; };
} }
if (groupChangeActions.version === group.revision) { if (groupChangeActions.version === group.revision) {
@ -4115,7 +4114,7 @@ async function integrateGroupChange({
let attributes = group; let attributes = group;
const aggregatedChangeMessages = []; const aggregatedChangeMessages = [];
const aggregatedMembers = []; const finalNewProfileKeys = new Map<AciString, string>();
const canApplyChange = const canApplyChange =
groupChange && groupChange &&
@ -4153,7 +4152,9 @@ async function integrateGroupChange({
attributes = newAttributes; attributes = newAttributes;
aggregatedChangeMessages.push(groupChangeMessages); aggregatedChangeMessages.push(groupChangeMessages);
aggregatedMembers.push(profileKeysToMembers(newProfileKeys)); for (const [aci, profileKey] of profileKeysToMap(newProfileKeys)) {
finalNewProfileKeys.set(aci, profileKey);
}
} }
// Apply the group state afterwards to verify that we didn't miss anything // Apply the group state afterwards to verify that we didn't miss anything
@ -4177,8 +4178,11 @@ async function integrateGroupChange({
logId logId
); );
const { newAttributes, newProfileKeys, otherChanges } = const {
await applyGroupState({ newAttributes,
newProfileKeys: newProfileKeysList,
otherChanges,
} = await applyGroupState({
group: attributes, group: attributes,
groupState: decryptedGroupState, groupState: decryptedGroupState,
sourceServiceId: isFirstFetch ? sourceServiceId : undefined, sourceServiceId: isFirstFetch ? sourceServiceId : undefined,
@ -4190,12 +4194,12 @@ async function integrateGroupChange({
sourceServiceId: isFirstFetch ? sourceServiceId : undefined, sourceServiceId: isFirstFetch ? sourceServiceId : undefined,
}); });
const newMembers = profileKeysToMembers(newProfileKeys); const newProfileKeys = profileKeysToMap(newProfileKeysList);
if ( if (
canApplyChange && canApplyChange &&
(groupChangeMessages.length !== 0 || (groupChangeMessages.length !== 0 ||
newMembers.length !== 0 || newProfileKeys.size !== 0 ||
otherChanges) otherChanges)
) { ) {
assertDev( assertDev(
@ -4207,14 +4211,16 @@ async function integrateGroupChange({
`integrateGroupChange/${logId}: local state was different from ` + `integrateGroupChange/${logId}: local state was different from ` +
'the remote final state. ' + 'the remote final state. ' +
`Got ${groupChangeMessages.length} change messages, ` + `Got ${groupChangeMessages.length} change messages, ` +
`${newMembers.length} updated members, and ` + `${newProfileKeys.size} updated members, and ` +
`otherChanges=${otherChanges}` `otherChanges=${otherChanges}`
); );
} }
attributes = newAttributes; attributes = newAttributes;
aggregatedChangeMessages.push(groupChangeMessages); aggregatedChangeMessages.push(groupChangeMessages);
aggregatedMembers.push(newMembers); for (const [aci, profileKey] of newProfileKeys) {
finalNewProfileKeys.set(aci, profileKey);
}
} else { } else {
strictAssert( strictAssert(
canApplyChange, canApplyChange,
@ -4225,7 +4231,7 @@ async function integrateGroupChange({
return { return {
newAttributes: attributes, newAttributes: attributes,
groupChangeMessages: aggregatedChangeMessages.flat(), groupChangeMessages: aggregatedChangeMessages.flat(),
members: aggregatedMembers.flat(), newProfileKeys: finalNewProfileKeys,
}; };
} }
@ -4774,11 +4780,12 @@ function extractDiffs({
return result; return result;
} }
function profileKeysToMembers(items: ReadonlyArray<GroupChangeMemberType>) { function profileKeysToMap(items: ReadonlyArray<GroupChangeMemberType>) {
return items.map(item => ({ const map = new Map<AciString, string>();
profileKey: Bytes.toBase64(item.profileKey), for (const { aci, profileKey } of items) {
aci: item.aci, map.set(aci, Bytes.toBase64(profileKey));
})); }
return map;
} }
type GroupChangeMemberType = { type GroupChangeMemberType = {