Support for single-attachment delete synced across devices

This commit is contained in:
Scott Nonnenberg 2024-06-21 15:35:18 -07:00 committed by GitHub
parent 97229e2e65
commit ac04d02d4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 422 additions and 55 deletions

View file

@ -156,6 +156,7 @@ import { getCallEventForProto } from '../util/callDisposition';
import { checkOurPniIdentityKey } from '../util/checkOurPniIdentityKey';
import { CallLogEvent } from '../types/CallDisposition';
import { CallLinkUpdateSyncType } from '../types/CallLink';
import { bytesToUuid } from '../util/uuidToBytes';
const GROUPV2_ID_LENGTH = 32;
const RETRY_TIMEOUT = 2 * 60 * 1000;
@ -3761,6 +3762,67 @@ export default class MessageReceiver
eventData = eventData.concat(localOnlyConversationDeletes);
}
if (deleteSync.attachmentDeletes?.length) {
const attachmentDeletes: Array<DeleteForMeSyncTarget> =
deleteSync.attachmentDeletes
.map(item => {
const {
clientUuid: targetClientUuid,
conversation: targetConversation,
fallbackDigest: targetFallbackDigest,
fallbackPlaintextHash: targetFallbackPlaintextHash,
targetMessage,
} = item;
const conversation = targetConversation
? processConversationToDelete(targetConversation, logId)
: undefined;
const message = targetMessage
? processMessageToDelete(targetMessage, logId)
: undefined;
if (!conversation) {
log.warn(
`${logId}/handleDeleteForMeSync/attachmentDeletes: No target conversation`
);
return undefined;
}
if (!message) {
log.warn(
`${logId}/handleDeleteForMeSync/attachmentDeletes: No target message`
);
return undefined;
}
const clientUuid = targetClientUuid?.length
? bytesToUuid(targetClientUuid)
: undefined;
const fallbackDigest = targetFallbackDigest?.length
? Bytes.toBase64(targetFallbackDigest)
: undefined;
// TODO: DESKTOP-7204
const fallbackPlaintextHash = targetFallbackPlaintextHash?.length
? Bytes.toHex(targetFallbackPlaintextHash)
: undefined;
if (!clientUuid && !fallbackDigest && !fallbackPlaintextHash) {
log.warn(
`${logId}/handleDeleteForMeSync/attachmentDeletes: Missing clientUuid, fallbackDigest and fallbackPlaintextHash`
);
return undefined;
}
return {
type: 'delete-single-attachment' as const,
conversation,
message,
clientUuid,
fallbackDigest,
fallbackPlaintextHash,
timestamp,
};
})
.filter(isNotNil);
eventData = eventData.concat(attachmentDeletes);
}
if (!eventData.length) {
throw new Error(`${logId}: Nothing found in sync message!`);
}

View file

@ -1534,6 +1534,10 @@ export default class MessageSender {
deleteForMe.localOnlyConversationDeletes.push({
conversation,
});
} else if (item.type === 'delete-single-attachment') {
throw new Error(
"getDeleteForMeSyncMessage: Desktop currently does not support sending 'delete-single-attachment' messages"
);
} else {
throw missingCaseError(item);
}

View file

@ -105,8 +105,9 @@ export type ProcessedEnvelope = Readonly<{
export type ProcessedAttachment = {
cdnId?: string;
cdnKey?: string;
digest?: string;
contentType: MIMEType;
clientUuid?: string;
digest?: string;
key?: string;
size: number;
fileName?: string;

View file

@ -526,10 +526,20 @@ export const deleteLocalConversationSchema = z.object({
conversation: conversationToDeleteSchema,
timestamp: z.number(),
});
export const deleteAttachmentSchema = z.object({
type: z.literal('delete-single-attachment').readonly(),
conversation: conversationToDeleteSchema,
message: messageToDeleteSchema,
clientUuid: z.string().optional(),
fallbackDigest: z.string().optional(),
fallbackPlaintextHash: z.string().optional(),
timestamp: z.number(),
});
export const deleteForMeSyncTargetSchema = z.union([
deleteMessageSchema,
deleteConversationSchema,
deleteLocalConversationSchema,
deleteAttachmentSchema,
]);
export type DeleteForMeSyncTarget = z.infer<typeof deleteForMeSyncTargetSchema>;

View file

@ -31,6 +31,7 @@ import { PaymentEventKind } from '../types/Payment';
import { filterAndClean } from '../types/BodyRange';
import { isAciString } from '../util/isAciString';
import { normalizeAci } from '../util/normalizeAci';
import { bytesToUuid } from '../util/uuidToBytes';
const FLAGS = Proto.DataMessage.Flags;
export const ATTACHMENT_MAX = 32;
@ -52,7 +53,7 @@ export function processAttachment(
const { cdnId } = attachment;
const hasCdnId = Long.isLong(cdnId) ? !cdnId.isZero() : Boolean(cdnId);
const { contentType, digest, key, size } = attachment;
const { clientUuid, contentType, digest, key, size } = attachment;
if (!isNumber(size)) {
throw new Error('Missing size on incoming attachment!');
}
@ -61,6 +62,7 @@ export function processAttachment(
...shallowDropNull(attachment),
cdnId: hasCdnId ? String(cdnId) : undefined,
clientUuid: clientUuid ? bytesToUuid(clientUuid) : undefined,
contentType: contentType
? stringToMIMEType(contentType)
: APPLICATION_OCTET_STREAM,