Profile name spoofing dialog

This commit is contained in:
Evan Hahn 2021-04-21 11:31:12 -05:00 committed by Scott Nonnenberg
parent 814255c10e
commit e7ef3de6d0
21 changed files with 893 additions and 15 deletions

View file

@ -5,13 +5,18 @@ import { pick } from 'lodash';
import React from 'react';
import { connect } from 'react-redux';
import { mapDispatchToProps } from '../actions';
import { Timeline } from '../../components/conversation/Timeline';
import {
Timeline,
WarningType as TimelineWarningType,
} from '../../components/conversation/Timeline';
import { StateType } from '../reducer';
import { ConversationType } from '../ducks/conversations';
import { getIntl } from '../selectors/user';
import {
getConversationMessagesSelector,
getConversationSelector,
getConversationsByTitleSelector,
getInvitedContactsForNewlyCreatedGroup,
getSelectedMessage,
} from '../selectors/conversations';
@ -24,6 +29,8 @@ import { SmartTimelineLoadingRow } from './TimelineLoadingRow';
import { renderAudioAttachment } from './renderAudioAttachment';
import { renderEmojiPicker } from './renderEmojiPicker';
import { assert } from '../../util/assert';
// Workaround: A react component's required properties are filtering up through connect()
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31363
/* eslint-disable @typescript-eslint/no-explicit-any */
@ -80,6 +87,60 @@ function renderTypingBubble(id: string): JSX.Element {
return <FilteredSmartTypingBubble id={id} />;
}
const getWarning = (
conversation: Readonly<ConversationType>,
state: Readonly<StateType>
): undefined | TimelineWarningType => {
if (
conversation.type === 'direct' &&
!conversation.acceptedMessageRequest &&
!conversation.isBlocked
) {
const getConversationsWithTitle = getConversationsByTitleSelector(state);
const conversationsWithSameTitle = getConversationsWithTitle(
conversation.title
);
assert(
conversationsWithSameTitle.length,
'Expected at least 1 conversation with the same title (this one)'
);
const safeConversation = conversationsWithSameTitle.find(
otherConversation =>
otherConversation.acceptedMessageRequest &&
otherConversation.type === 'direct' &&
otherConversation.id !== conversation.id
);
return safeConversation ? { safeConversation } : undefined;
}
return undefined;
};
const getContactSpoofingReview = (
selectedConversationId: string,
state: Readonly<StateType>
):
| undefined
| {
possiblyUnsafeConversation: ConversationType;
safeConversation: ConversationType;
} => {
const { contactSpoofingReview } = state.conversations;
if (!contactSpoofingReview) {
return undefined;
}
const conversationSelector = getConversationSelector(state);
return {
possiblyUnsafeConversation: conversationSelector(selectedConversationId),
safeConversation: conversationSelector(
contactSpoofingReview.safeConversationId
),
};
};
const mapStateToProps = (state: StateType, props: ExternalProps) => {
const { id, ...actions } = props;
@ -99,6 +160,10 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => {
state
),
selectedMessageId: selectedMessage ? selectedMessage.id : undefined,
warning: getWarning(conversation, state),
contactSpoofingReview: getContactSpoofingReview(id, state),
i18n: getIntl(state),
renderItem,
renderLastSeenIndicator,