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