|
|
|
import { getMessageQueue } from '../../..';
|
|
|
|
import { SignalService } from '../../../../protobuf';
|
|
|
|
import { SnodeNamespaces } from '../../../apis/snode_api/namespaces';
|
|
|
|
import { getConversationController } from '../../../conversations';
|
|
|
|
import { DisappearingMessages } from '../../../disappearing_messages';
|
|
|
|
import { PubKey } from '../../../types';
|
|
|
|
import { UserUtils } from '../../../utils';
|
|
|
|
import { ExpirableMessage, ExpirableMessageParams } from '../ExpirableMessage';
|
|
|
|
|
|
|
|
interface DataExtractionNotificationMessageParams extends ExpirableMessageParams {
|
|
|
|
referencedAttachmentTimestamp: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class DataExtractionNotificationMessage extends ExpirableMessage {
|
|
|
|
public readonly referencedAttachmentTimestamp: number;
|
|
|
|
|
|
|
|
constructor(params: DataExtractionNotificationMessageParams) {
|
|
|
|
super(params);
|
|
|
|
this.referencedAttachmentTimestamp = params.referencedAttachmentTimestamp;
|
|
|
|
// this does not make any sense
|
|
|
|
if (!this.referencedAttachmentTimestamp) {
|
|
|
|
throw new Error('referencedAttachmentTimestamp must be set');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public contentProto(): SignalService.Content {
|
|
|
|
const content = super.contentProto();
|
|
|
|
content.dataExtractionNotification = this.dataExtractionProto();
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected dataExtractionProto(): SignalService.DataExtractionNotification {
|
|
|
|
const ACTION_ENUM = SignalService.DataExtractionNotification.Type;
|
|
|
|
|
|
|
|
const action = ACTION_ENUM.MEDIA_SAVED; // we cannot know when user screenshots, so it can only be a media saved on desktop
|
|
|
|
|
|
|
|
return new SignalService.DataExtractionNotification({
|
|
|
|
type: action,
|
|
|
|
timestamp: this.referencedAttachmentTimestamp,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Currently only enabled for private chats
|
|
|
|
*/
|
|
|
|
export const sendDataExtractionNotification = async (
|
|
|
|
conversationId: string,
|
|
|
|
attachmentSender: string,
|
|
|
|
referencedAttachmentTimestamp: number
|
|
|
|
) => {
|
|
|
|
const convo = getConversationController().get(conversationId);
|
|
|
|
if (!convo || !convo.isPrivate() || convo.isMe() || UserUtils.isUsFromCache(attachmentSender)) {
|
|
|
|
window.log.warn('Not sending saving attachment notification for', attachmentSender);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const { expirationType, expireTimer } = DisappearingMessages.forcedDeleteAfterReadMsgSetting(
|
|
|
|
convo
|
|
|
|
);
|
|
|
|
// DataExtractionNotification are expiring with a forced DaR timer if a DaS is set.
|
|
|
|
// It's because we want the DataExtractionNotification to stay in the swarm as much as possible,
|
|
|
|
// but also expire on the recipient's side (and synced) once read.
|
|
|
|
const dataExtractionNotificationMessage = new DataExtractionNotificationMessage({
|
|
|
|
referencedAttachmentTimestamp,
|
|
|
|
timestamp: Date.now(),
|
|
|
|
expirationType,
|
|
|
|
expireTimer,
|
|
|
|
});
|
|
|
|
|
|
|
|
const pubkey = PubKey.cast(conversationId);
|
|
|
|
window.log.info(
|
|
|
|
`Sending DataExtractionNotification to ${conversationId} about attachment: ${referencedAttachmentTimestamp}`
|
|
|
|
);
|
|
|
|
|
|
|
|
try {
|
|
|
|
await getMessageQueue().sendToPubKey(
|
|
|
|
pubkey,
|
|
|
|
dataExtractionNotificationMessage,
|
|
|
|
SnodeNamespaces.UserMessages
|
|
|
|
);
|
|
|
|
} catch (e) {
|
|
|
|
window.log.warn('failed to send data extraction notification', e);
|
|
|
|
}
|
|
|
|
};
|