Lazily fetch profiles when modifying groups

This commit is contained in:
Fedor Indutny 2022-07-11 11:50:14 -07:00 committed by GitHub
parent 712c9597c5
commit 07cc399550
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 21 deletions

View file

@ -1472,12 +1472,43 @@ export async function modifyGroupV2({
let refreshedCredentials = false; let refreshedCredentials = false;
const profileFetchQueue = new PQueue({
concurrency: 3,
});
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) { for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
log.info(`modifyGroupV2/${logId}: Starting attempt ${attempt}`); log.info(`modifyGroupV2/${logId}: Starting attempt ${attempt}`);
try { try {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await window.waitForEmptyEventQueue(); await window.waitForEmptyEventQueue();
// Fetch profiles for contacts that do not have credentials (or have
// expired credentials)
{
const membersMissingCredentials = usingCredentialsFrom.filter(member =>
member.hasProfileKeyCredentialExpired()
);
const logIds = membersMissingCredentials.map(member =>
member.idForLogging()
);
if (logIds.length !== 0) {
log.info(`modifyGroupV2/${logId}: Fetching profiles for ${logIds}`);
}
for (const member of membersMissingCredentials) {
member.set({
profileKeyCredential: null,
profileKeyCredentialExpiration: null,
});
}
// eslint-disable-next-line no-await-in-loop
await profileFetchQueue.addAll(
membersMissingCredentials.map(member => () => member.getProfiles())
);
}
log.info(`modifyGroupV2/${logId}: Queuing attempt ${attempt}`); log.info(`modifyGroupV2/${logId}: Queuing attempt ${attempt}`);
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
@ -1557,10 +1588,12 @@ export async function modifyGroupV2({
const logIds = usingCredentialsFrom.map(member => const logIds = usingCredentialsFrom.map(member =>
member.idForLogging() member.idForLogging()
); );
if (logIds.length !== 0) {
log.warn( log.warn(
`modifyGroupV2/${logId}: Profile key credentials were not ` + `modifyGroupV2/${logId}: Profile key credentials were not ` +
`up-to-date. Updating profiles for ${logIds} and retrying` `up-to-date. Updating profiles for ${logIds} and retrying`
); );
}
for (const member of usingCredentialsFrom) { for (const member of usingCredentialsFrom) {
member.set({ member.set({
@ -1569,9 +1602,6 @@ export async function modifyGroupV2({
}); });
} }
const profileFetchQueue = new PQueue({
concurrency: 3,
});
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await profileFetchQueue.addAll( await profileFetchQueue.addAll(
usingCredentialsFrom.map(member => () => member.getProfiles()) usingCredentialsFrom.map(member => () => member.getProfiles())
@ -1741,6 +1771,17 @@ export async function createGroupV2({
const ourACI = window.storage.user.getCheckedUuid(UUIDKind.ACI).toString(); const ourACI = window.storage.user.getCheckedUuid(UUIDKind.ACI).toString();
const ourConversation =
window.ConversationController.getOurConversationOrThrow();
if (ourConversation.hasProfileKeyCredentialExpired()) {
log.info(`createGroupV2/${logId}: fetching our own credentials`);
ourConversation.set({
profileKeyCredential: null,
profileKeyCredentialExpiration: null,
});
await ourConversation.getProfiles();
}
const membersV2: Array<GroupV2MemberType> = [ const membersV2: Array<GroupV2MemberType> = [
{ {
uuid: ourACI, uuid: ourACI,
@ -1770,7 +1811,7 @@ export async function createGroupV2({
} }
// Refresh our local data to be sure // Refresh our local data to be sure
if (!contact.get('profileKey') || !contact.get('profileKeyCredential')) { if (contact.hasProfileKeyCredentialExpired()) {
await contact.getProfiles(); await contact.getProfiles();
} }

View file

@ -2056,6 +2056,8 @@ export class ConversationModel extends window.Backbone
UUIDKind.ACI UUIDKind.ACI
); );
const ourPNI = window.textsecure.storage.user.getUuid(UUIDKind.PNI); const ourPNI = window.textsecure.storage.user.getUuid(UUIDKind.PNI);
const ourConversation =
window.ConversationController.getOurConversationOrThrow();
if ( if (
isGroupV1(this.attributes) || isGroupV1(this.attributes) ||
@ -2068,7 +2070,7 @@ export class ConversationModel extends window.Backbone
) { ) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'promotePendingMember', name: 'promotePendingMember',
usingCredentialsFrom: [], usingCredentialsFrom: [ourConversation],
createGroupChange: () => this.promotePendingMember(UUIDKind.ACI), createGroupChange: () => this.promotePendingMember(UUIDKind.ACI),
}); });
} else if ( } else if (
@ -2078,7 +2080,7 @@ export class ConversationModel extends window.Backbone
) { ) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'promotePendingMember', name: 'promotePendingMember',
usingCredentialsFrom: [], usingCredentialsFrom: [ourConversation],
createGroupChange: () => this.promotePendingMember(UUIDKind.PNI), createGroupChange: () => this.promotePendingMember(UUIDKind.PNI),
}); });
} else if (isGroupV2(this.attributes) && this.isMember(ourACI)) { } else if (isGroupV2(this.attributes) && this.isMember(ourACI)) {
@ -2170,18 +2172,20 @@ export class ConversationModel extends window.Backbone
approvalRequired: boolean; approvalRequired: boolean;
}): Promise<void> { }): Promise<void> {
const ourACI = window.textsecure.storage.user.getCheckedUuid(); const ourACI = window.textsecure.storage.user.getCheckedUuid();
const ourConversation =
window.ConversationController.getOurConversationOrThrow();
try { try {
if (approvalRequired) { if (approvalRequired) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'requestToJoin', name: 'requestToJoin',
usingCredentialsFrom: [], usingCredentialsFrom: [ourConversation],
inviteLinkPassword, inviteLinkPassword,
createGroupChange: () => this.addPendingApprovalRequest(), createGroupChange: () => this.addPendingApprovalRequest(),
}); });
} else { } else {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'joinGroup', name: 'joinGroup',
usingCredentialsFrom: [], usingCredentialsFrom: [ourConversation],
inviteLinkPassword, inviteLinkPassword,
createGroupChange: () => this.addMember(ourACI), createGroupChange: () => this.addMember(ourACI),
}); });
@ -2284,6 +2288,8 @@ export class ConversationModel extends window.Backbone
const ourACI = window.textsecure.storage.user.getCheckedUuid(UUIDKind.ACI); const ourACI = window.textsecure.storage.user.getCheckedUuid(UUIDKind.ACI);
const ourPNI = window.textsecure.storage.user.getUuid(UUIDKind.PNI); const ourPNI = window.textsecure.storage.user.getUuid(UUIDKind.PNI);
const ourConversation =
window.ConversationController.getOurConversationOrThrow();
if (this.isMemberPending(ourACI)) { if (this.isMemberPending(ourACI)) {
await this.modifyGroupV2({ await this.modifyGroupV2({
@ -2294,7 +2300,7 @@ export class ConversationModel extends window.Backbone
} else if (this.isMember(ourACI)) { } else if (this.isMember(ourACI)) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'delete', name: 'delete',
usingCredentialsFrom: [], usingCredentialsFrom: [ourConversation],
createGroupChange: () => this.removeMember(ourACI), createGroupChange: () => this.removeMember(ourACI),
}); });
// Keep PNI in pending if ACI was a member. // Keep PNI in pending if ACI was a member.
@ -2418,9 +2424,7 @@ export class ConversationModel extends window.Backbone
}); });
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'removePendingMember', name: 'removePendingMember',
usingCredentialsFrom: conversationIds usingCredentialsFrom: [],
.map(id => window.ConversationController.get(id))
.filter(isNotNil),
createGroupChange: () => this.removePendingMember(uuids), createGroupChange: () => this.removePendingMember(uuids),
extraConversationsForSend: conversationIds, extraConversationsForSend: conversationIds,
}); });
@ -2444,14 +2448,14 @@ export class ConversationModel extends window.Backbone
if (this.isMemberRequestingToJoin(uuid)) { if (this.isMemberRequestingToJoin(uuid)) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'denyPendingApprovalRequest', name: 'denyPendingApprovalRequest',
usingCredentialsFrom: [pendingMember], usingCredentialsFrom: [],
createGroupChange: () => this.denyPendingApprovalRequest(uuid), createGroupChange: () => this.denyPendingApprovalRequest(uuid),
extraConversationsForSend: [conversationId], extraConversationsForSend: [conversationId],
}); });
} else if (this.isMemberPending(uuid)) { } else if (this.isMemberPending(uuid)) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'removePendingMember', name: 'removePendingMember',
usingCredentialsFrom: [pendingMember], usingCredentialsFrom: [],
createGroupChange: () => this.removePendingMember([uuid]), createGroupChange: () => this.removePendingMember([uuid]),
extraConversationsForSend: [conversationId], extraConversationsForSend: [conversationId],
}); });
@ -2476,14 +2480,14 @@ export class ConversationModel extends window.Backbone
if (this.isMemberRequestingToJoin(uuid)) { if (this.isMemberRequestingToJoin(uuid)) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'denyPendingApprovalRequest', name: 'denyPendingApprovalRequest',
usingCredentialsFrom: [pendingMember], usingCredentialsFrom: [],
createGroupChange: () => this.denyPendingApprovalRequest(uuid), createGroupChange: () => this.denyPendingApprovalRequest(uuid),
extraConversationsForSend: [conversationId], extraConversationsForSend: [conversationId],
}); });
} else if (this.isMemberPending(uuid)) { } else if (this.isMemberPending(uuid)) {
await this.modifyGroupV2({ await this.modifyGroupV2({
name: 'removePendingMember', name: 'removePendingMember',
usingCredentialsFrom: [pendingMember], usingCredentialsFrom: [],
createGroupChange: () => this.removePendingMember([uuid]), createGroupChange: () => this.removePendingMember([uuid]),
extraConversationsForSend: [conversationId], extraConversationsForSend: [conversationId],
}); });
@ -4783,13 +4787,18 @@ export class ConversationModel extends window.Backbone
} }
hasProfileKeyCredentialExpired(): boolean { hasProfileKeyCredentialExpired(): boolean {
const profileKey = this.get('profileKey');
if (!profileKey) {
return false;
}
const profileKeyCredential = this.get('profileKeyCredential'); const profileKeyCredential = this.get('profileKeyCredential');
const profileKeyCredentialExpiration = this.get( const profileKeyCredentialExpiration = this.get(
'profileKeyCredentialExpiration' 'profileKeyCredentialExpiration'
); );
if (!profileKeyCredential) { if (!profileKeyCredential) {
return false; return true;
} }
if (!isNumber(profileKeyCredentialExpiration)) { if (!isNumber(profileKeyCredentialExpiration)) {