Store profile keys from group requesting members (#2031)

When filling or updating a V2 group, profile keys were copied from
DecryptedGroup.members into the local profile store but not from
requestingMembers. Admins who never had a prior session with a user in
the join queue then lacked profile keys and could not decrypt profiles
(e.g. for listContacts).

Also process DecryptedRequestingMember entries the same way as full
members, using DecryptedMember / DecryptedRequestingMember types so the
lib module does not require a direct protobuf dependency.

Made-with: Cursor
This commit is contained in:
Patrick Dattilio 2026-04-27 10:25:47 -04:00 committed by GitHub
parent 9b09df5f17
commit c9e2504349
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -38,6 +38,8 @@ import org.signal.storageservice.storage.protos.groups.GroupChangeResponse;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupJoinInfo;
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedRequestingMember;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupChangeLog;
@ -557,17 +559,44 @@ public class GroupHelper {
private void storeProfileKeysFromMembers(final DecryptedGroup group) {
for (var member : group.members) {
final var serviceId = ServiceId.parseOrThrow(member.aciBytes);
final var recipientId = account.getRecipientResolver().resolveRecipient(serviceId);
final var profileStore = account.getProfileStore();
if (profileStore.getProfileKey(recipientId) != null) {
// We already have a profile key, not updating it from a non-authoritative source
continue;
}
try {
profileStore.storeProfileKey(recipientId, new ProfileKey(member.profileKey.toByteArray()));
} catch (InvalidInputException ignored) {
}
storeProfileKeyForDecryptedMemberIfMissing(member);
}
for (var member : group.requestingMembers) {
storeProfileKeyForDecryptedRequestingMemberIfMissing(member);
}
}
private void storeProfileKeyForDecryptedMemberIfMissing(final DecryptedMember member) {
if (member == null) {
return;
}
final var serviceId = ServiceId.parseOrThrow(member.aciBytes);
final var recipientId = account.getRecipientResolver().resolveRecipient(serviceId);
final var profileStore = account.getProfileStore();
if (profileStore.getProfileKey(recipientId) != null) {
// We already have a profile key, not updating it from a non-authoritative source
return;
}
try {
profileStore.storeProfileKey(recipientId, new ProfileKey(member.profileKey.toByteArray()));
} catch (InvalidInputException ignored) {
}
}
private void storeProfileKeyForDecryptedRequestingMemberIfMissing(final DecryptedRequestingMember member) {
if (member == null) {
return;
}
final var serviceId = ServiceId.parseOrThrow(member.aciBytes);
final var recipientId = account.getRecipientResolver().resolveRecipient(serviceId);
final var profileStore = account.getProfileStore();
if (profileStore.getProfileKey(recipientId) != null) {
// We already have a profile key, not updating it from a non-authoritative source
return;
}
try {
profileStore.storeProfileKey(recipientId, new ProfileKey(member.profileKey.toByteArray()));
} catch (InvalidInputException ignored) {
}
}