Files
Desktop/ts/util/isConversationAccepted.preload.ts
Fedor Indutny 44076ece79 Rename files
2025-10-16 23:45:44 -07:00

120 lines
3.4 KiB
TypeScript

// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ConversationAttributesType } from '../model-types.d.ts';
import { SignalService as Proto } from '../protobuf/index.std.js';
import { isDirectConversation, isMe } from './whatTypeOfConversation.dom.js';
import { isInSystemContacts } from './isInSystemContacts.std.js';
import { createLogger } from '../logging/log.std.js';
import { itemStorage } from '../textsecure/Storage.preload.js';
export type IsConversationAcceptedOptionsType = {
ignoreEmptyConvo: boolean;
};
const log = createLogger('isConversationAccepted');
/**
* Determine if this conversation should be considered "accepted" in terms
* of message requests
*/
export function isConversationAccepted(
conversationAttrs: ConversationAttributesType,
{ ignoreEmptyConvo }: IsConversationAcceptedOptionsType = {
ignoreEmptyConvo: false,
}
): boolean {
if (isMe(conversationAttrs)) {
return true;
}
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
const { messageRequestResponseType, removalStage } = conversationAttrs;
if (removalStage !== undefined) {
return false;
}
if (messageRequestResponseType === messageRequestEnum.ACCEPT) {
return true;
}
const {
sentMessageCount,
messageCount,
messageCountBeforeMessageRequests,
pendingAdminApprovalV2,
profileSharing,
} = conversationAttrs;
const ourAci = itemStorage.user.getAci();
const hasRequestedToJoin =
Boolean(ourAci) &&
(pendingAdminApprovalV2 || []).some(item => item.aci === ourAci);
if (hasRequestedToJoin) {
return true;
}
const hasSentMessages = (sentMessageCount || 0) > 0;
const hasMessagesBeforeMessageRequests =
(messageCountBeforeMessageRequests || 0) > 0;
const hasNoMessages = (messageCount || 0) === 0;
// We don't want to show the message request UI in an empty conversation.
const isEmptyPrivateConvo =
hasNoMessages &&
isDirectConversation(conversationAttrs) &&
!ignoreEmptyConvo;
const isEmptyWhitelistedGroup =
hasNoMessages &&
!isDirectConversation(conversationAttrs) &&
Boolean(profileSharing);
return (
isFromOrAddedByTrustedContact(conversationAttrs) ||
hasSentMessages ||
hasMessagesBeforeMessageRequests ||
// an empty group is the scenario where we need to rely on
// whether the profile has already been shared or not
isEmptyPrivateConvo ||
isEmptyWhitelistedGroup
);
}
// Is this someone me, a system contact, or are we sharing our profile with them?
export function isTrustedContact(
conversationAttrs: ConversationAttributesType
): boolean {
if (!isDirectConversation(conversationAttrs)) {
log.error('isTrustedContact should only be called for direct convos');
return false;
}
return (
isMe(conversationAttrs) ||
isInSystemContacts(conversationAttrs) ||
Boolean(conversationAttrs.profileSharing)
);
}
// Is this person (or the person who added us to this group) a trusted contact?
function isFromOrAddedByTrustedContact(
conversationAttrs: ConversationAttributesType
): boolean {
if (isDirectConversation(conversationAttrs)) {
return isTrustedContact(conversationAttrs);
}
const { addedBy } = conversationAttrs;
if (!addedBy) {
return false;
}
const addedByContact = window.ConversationController.get(addedBy);
if (!addedByContact) {
return false;
}
return isTrustedContact(addedByContact.attributes);
}