Fix GSE for delivery receipts in inactive groups

Co-authored-by: Jamie Kyle <113370520+jamiebuilds-signal@users.noreply.github.com>
This commit is contained in:
automated-signal 2024-10-21 18:31:09 -05:00 committed by GitHub
parent 08e8a7c6e9
commit 80367143cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 33 additions and 36 deletions

View file

@ -458,7 +458,9 @@ async function doGetProfile(
c: ConversationModel,
groupId: string | null
): Promise<void> {
const logId = `getProfile(${c.idForLogging()})`;
const logId = groupId
? `getProfile(${c.idForLogging()} in groupv2(${groupId}))`
: `getProfile(${c.idForLogging()})`;
const { messaging } = window.textsecure;
strictAssert(
messaging,

View file

@ -30,7 +30,7 @@ import { isTestOrMockEnvironment } from '../environment';
import { isAlpha } from './version';
import { parseStrict } from './schemas';
import { DataReader } from '../sql/Client';
import { maybeUpdateGroup } from '../groups';
import { waitThenMaybeUpdateGroup } from '../groups';
import { isGroupV2 } from './whatTypeOfConversation';
export function decodeGroupSendEndorsementResponse({
@ -139,6 +139,7 @@ export function isValidGroupSendEndorsementsExpiration(
}
export class GroupSendEndorsementState {
#logId: string;
#combinedEndorsement: GroupSendCombinedEndorsementRecord;
#memberEndorsements = new Map<
ServiceIdString,
@ -153,6 +154,7 @@ export class GroupSendEndorsementState {
data: GroupSendEndorsementsData,
groupSecretParamsBase64: string
) {
this.#logId = `GroupSendEndorsementState/groupv2(${data.combinedEndorsement.groupId})`;
this.#combinedEndorsement = data.combinedEndorsement;
this.#groupSecretParamsBase64 = groupSecretParamsBase64;
this.#ourAci = window.textsecure.storage.user.getCheckedAci();
@ -194,7 +196,7 @@ export class GroupSendEndorsementState {
strictAssert(
isValidGroupSendEndorsementsExpiration(expiration.getTime()),
'Cannot build token with invalid expiration'
`${this.#logId}: toToken: Cannot build token with invalid expiration`
);
const fullToken = endorsement.toFullToken(groupSecretParams, expiration);
@ -218,7 +220,7 @@ export class GroupSendEndorsementState {
const memberEndorsement = this.#memberEndorsements.get(serviceId);
strictAssert(
memberEndorsement,
'subtractMemberEndorsements: Missing endorsement'
`${this.#logId}: getMemberEndorsement: Missing endorsement for ${serviceId}`
);
return this.#toEndorsement(memberEndorsement.endorsement);
}
@ -231,7 +233,7 @@ export class GroupSendEndorsementState {
): GroupSendEndorsement {
strictAssert(
!otherMembersServiceIds.has(this.#ourAci),
'subtractMemberEndorsements: Cannot subtract our own aci from the combined endorsement'
`${this.#logId}: subtractMemberEndorsements: Cannot subtract our own aci from the combined endorsement`
);
return this.#getCombinedEndorsement(includesOurs).byRemoving(
this.#combineMemberEndorsements(otherMembersServiceIds)
@ -253,7 +255,7 @@ export class GroupSendEndorsementState {
#buildToken(serviceIds: Set<ServiceIdString>): GroupSendEndorsement {
const sendCount = serviceIds.size;
const memberCount = this.#memberEndorsements.size;
const logId = `GroupSendEndorsementState.buildToken(${sendCount} of ${memberCount})`;
const logId = `${this.#logId}: buildToken(${sendCount} of ${memberCount})`;
// Fast path sending to one person
if (serviceIds.size === 1) {
@ -351,6 +353,12 @@ export async function maybeCreateGroupSendEndorsementState(
if (data == null) {
const ourAci = window.textsecure.storage.user.getCheckedAci();
if (conversation.isMember(ourAci)) {
if (!alreadyRefreshedGroupState) {
log.info(`${logId}: Missing endorsements for group, refreshing group`);
await waitThenMaybeUpdateGroup({ conversation, force: true });
return { state: null, didRefreshGroupState: true };
}
onFailedToSendWithEndorsements(
new Error(`${logId}: Missing all endorsements for group`)
);
@ -374,7 +382,7 @@ export async function maybeCreateGroupSendEndorsementState(
log.info(
`${logId}: Endorsements close to expiration (${groupSendEndorsementState.getExpiration().getTime()}, ${Date.now()}), refreshing group`
);
await maybeUpdateGroup({ conversation });
await waitThenMaybeUpdateGroup({ conversation, force: true });
return { state: null, didRefreshGroupState: true };
}

View file

@ -296,22 +296,20 @@ export async function sendToGroupViaSenderKey(
} = options;
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
const logId = sendTarget.idForLogging();
const logId = `sendToGroupViaSenderKey/${sendTarget.idForLogging()}`;
log.info(
`sendToGroupViaSenderKey/${logId}: Starting ${timestamp}, recursion count ${recursion.count}, reason: ${recursion.reason}...`
`${logId}: Starting ${timestamp}, recursion count ${recursion.count}, reason: ${recursion.reason}...`
);
if (recursion.count > MAX_RECURSION) {
throw new Error(
`sendToGroupViaSenderKey/${logId}: Too much recursion! Count is at ${recursion.count}`
`${logId}: Too much recursion! Count is at ${recursion.count}`
);
}
const groupId = sendTarget.getGroupId();
if (!sendTarget.isValid()) {
throw new Error(
`sendToGroupViaSenderKey/${logId}: sendTarget is not valid!`
);
throw new Error(`${logId}: sendTarget is not valid!`);
}
if (
@ -319,9 +317,7 @@ export async function sendToGroupViaSenderKey(
contentHint !== ContentHint.RESENDABLE &&
contentHint !== ContentHint.IMPLICIT
) {
throw new Error(
`sendToGroupViaSenderKey/${logId}: Invalid contentHint ${contentHint}`
);
throw new Error(`${logId}: Invalid contentHint ${contentHint}`);
}
strictAssert(
@ -334,9 +330,7 @@ export async function sendToGroupViaSenderKey(
const senderKeyInfo = sendTarget.getSenderKeyInfo();
if (!senderKeyInfo) {
log.info(
`sendToGroupViaSenderKey/${logId}: Adding initial sender key info`
);
log.info(`${logId}: Adding initial sender key info`);
await sendTarget.saveSenderKeyInfo({
createdAtDate: Date.now(),
distributionId: generateUuid(),
@ -350,9 +344,7 @@ export async function sendToGroupViaSenderKey(
const EXPIRE_DURATION = getSenderKeyExpireDuration();
if (isOlderThan(senderKeyInfo.createdAtDate, EXPIRE_DURATION)) {
const { createdAtDate } = senderKeyInfo;
log.info(
`sendToGroupViaSenderKey/${logId}: Resetting sender key; ${createdAtDate} is too old`
);
log.info(`${logId}: Resetting sender key; ${createdAtDate} is too old`);
await resetSenderKey(sendTarget);
// Restart here because we updated senderKeyInfo
@ -419,7 +411,7 @@ export async function sendToGroupViaSenderKey(
const senderKeyRecipients = getServiceIdsFromDevices(devicesForSenderKey);
const normalSendRecipients = getServiceIdsFromDevices(devicesForNormalSend);
log.info(
`sendToGroupViaSenderKey/${logId}:` +
`${logId}:` +
` ${senderKeyRecipients.length} accounts for sender key (${devicesForSenderKey.length} devices),` +
` ${normalSendRecipients.length} accounts for normal send (${devicesForNormalSend.length} devices)`
);
@ -427,7 +419,7 @@ export async function sendToGroupViaSenderKey(
// 5. Ensure we have enough recipients
if (senderKeyRecipients.length < 2) {
throw new Error(
`sendToGroupViaSenderKey/${logId}: Not enough recipients for Sender Key message. Failing over.`
`${logId}: Not enough recipients for Sender Key message. Failing over.`
);
}
@ -460,7 +452,7 @@ export async function sendToGroupViaSenderKey(
// have our sender key before we send sender key messages to them.
if (newToMemberServiceIds.length > 0) {
log.info(
`sendToGroupViaSenderKey/${logId}: Sending sender key to ${
`${logId}: Sending sender key to ${
newToMemberServiceIds.length
} members: ${JSON.stringify(newToMemberServiceIds)}`
);
@ -583,7 +575,7 @@ export async function sendToGroupViaSenderKey(
);
} else {
log.error(
`sendToGroupViaSenderKey/${logId}: Server returned unexpected 200 response ${JSON.stringify(
`${logId}: Server returned unexpected 200 response ${JSON.stringify(
parsed.error.flatten()
)}`
);
@ -637,7 +629,7 @@ export async function sendToGroupViaSenderKey(
const brokenAccount = window.ConversationController.get(name);
if (brokenAccount) {
log.warn(
`sendToGroupViaSenderKey/${logId}: Disabling sealed sender for ${brokenAccount.idForLogging()}`
`${logId}: Disabling sealed sender for ${brokenAccount.idForLogging()}`
);
brokenAccount.set({ sealedSender: SEALED_SENDER.DISABLED });
await DataWriter.updateConversation(brokenAccount.attributes);
@ -652,7 +644,7 @@ export async function sendToGroupViaSenderKey(
}
log.error(
`sendToGroupViaSenderKey/${logId}: Returned unexpected error code: ${
`${logId}: Returned unexpected error code: ${
error.code
}, error class: ${typeof error}`
);
@ -1381,11 +1373,8 @@ async function fetchKeysForServiceId(
devices: Array<number> | null,
groupSendEndorsementState: GroupSendEndorsementState | null
): Promise<void> {
log.info(
`fetchKeysForServiceId: Fetching ${
devices || 'all'
} devices for ${serviceId}`
);
const logId = `fetchKeysForServiceId/${serviceId}`;
log.info(`${logId}: Fetching ${devices || 'all'} devices`);
if (!window.textsecure?.messaging?.server) {
throw new Error('fetchKeysForServiceId: No server available!');
@ -1442,9 +1431,7 @@ async function fetchKeysForServiceId(
onFailedToSendWithEndorsements(error as Error);
}
log.error(
`fetchKeysForServiceId: Error fetching ${
devices || 'all'
} devices for ${serviceId}`,
`${logId}: Error fetching ${devices || 'all'} devices`,
Errors.toLogFormat(error)
);
throw error;