mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2025-12-24 20:26:24 +00:00
120 lines
3.0 KiB
TypeScript
120 lines
3.0 KiB
TypeScript
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import type {
|
|
ReadonlyMessageAttributesType,
|
|
ConversationAttributesType,
|
|
} from '../model-types.d.ts';
|
|
import { type AciString } from '../types/ServiceId.std.js';
|
|
import type { ProcessedStoryContext } from '../textsecure/Types.d.ts';
|
|
import { createLogger } from '../logging/log.std.js';
|
|
import { getAuthorId } from '../messages/sources.preload.js';
|
|
import { itemStorage } from '../textsecure/Storage.preload.js';
|
|
import { isDirectConversation } from './whatTypeOfConversation.dom.js';
|
|
|
|
const log = createLogger('findStoryMessage');
|
|
|
|
export type FindStoryMessageOptionsType = Readonly<{
|
|
conversation: ConversationAttributesType;
|
|
senderId: string;
|
|
storyContext?: ProcessedStoryContext;
|
|
}>;
|
|
|
|
export async function findStoryMessage({
|
|
conversation,
|
|
senderId,
|
|
storyContext,
|
|
}: FindStoryMessageOptionsType): Promise<
|
|
ReadonlyMessageAttributesType | undefined
|
|
> {
|
|
if (!storyContext) {
|
|
return undefined;
|
|
}
|
|
|
|
const { authorAci, sentTimestamp: sentAt } = storyContext;
|
|
|
|
if (!sentAt) {
|
|
return undefined;
|
|
}
|
|
|
|
if (authorAci == null) {
|
|
return undefined;
|
|
}
|
|
|
|
const ourConversationId =
|
|
window.ConversationController.getOurConversationIdOrThrow();
|
|
const ourAci = itemStorage.user.getCheckedAci();
|
|
|
|
const found = await window.MessageCache.findBySentAt(
|
|
sentAt,
|
|
({ attributes: candidate }) => {
|
|
if (
|
|
!isStoryAMatch(
|
|
candidate,
|
|
conversation.id,
|
|
ourConversationId,
|
|
authorAci,
|
|
sentAt
|
|
)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
const sendStateByConversationId =
|
|
candidate.sendStateByConversationId || {};
|
|
const sendState = sendStateByConversationId[senderId];
|
|
|
|
const storyQuoteIsFromSelf = candidate.sourceServiceId === ourAci;
|
|
|
|
if (!storyQuoteIsFromSelf) {
|
|
return true;
|
|
}
|
|
|
|
// The sender is not a recipient for this story
|
|
if (sendState === undefined) {
|
|
return false;
|
|
}
|
|
|
|
// Group replies are always allowed
|
|
if (!isDirectConversation(conversation)) {
|
|
return true;
|
|
}
|
|
|
|
// For 1:1 stories, we need to check if they can be replied to
|
|
return sendState.isAllowedToReplyToStory !== false;
|
|
}
|
|
);
|
|
|
|
if (found == null) {
|
|
log.info('findStoryMessages: message not found', sentAt);
|
|
return undefined;
|
|
}
|
|
|
|
return found.attributes;
|
|
}
|
|
|
|
function isStoryAMatch(
|
|
message: ReadonlyMessageAttributesType | null | undefined,
|
|
conversationId: string,
|
|
ourConversationId: string,
|
|
authorAci: AciString,
|
|
sentTimestamp: number
|
|
): boolean {
|
|
if (!message) {
|
|
return false;
|
|
}
|
|
|
|
const authorConversation = window.ConversationController.lookupOrCreate({
|
|
e164: undefined,
|
|
serviceId: authorAci,
|
|
reason: 'isStoryAMatch',
|
|
});
|
|
|
|
return (
|
|
message.sent_at === sentTimestamp &&
|
|
getAuthorId(message) === authorConversation?.id &&
|
|
(message.conversationId === conversationId ||
|
|
message.conversationId === ourConversationId)
|
|
);
|
|
}
|