From 6a776b56f6d62f14dfd0ff31472c1a2da93f8d67 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 19 Jan 2021 11:25:03 +1100 Subject: [PATCH] fix ban of users on open group --- js/background.js | 1 + js/models/conversations.js | 5 +++++ js/modules/signal.js | 4 ---- ts/components/conversation/Message.tsx | 5 +++-- ts/components/session/SessionInboxView.tsx | 1 + .../session/conversation/SessionConversation.tsx | 5 ++++- .../session/conversation/SessionMessagesList.tsx | 12 +++++++++++- ts/state/ducks/conversations.ts | 1 + ts/state/ducks/user.ts | 4 ++++ ts/state/reducer.ts | 1 + ts/state/selectors/user.ts | 5 +++++ ts/state/smart/SessionConversation.tsx | 3 +++ 12 files changed, 39 insertions(+), 8 deletions(-) diff --git a/js/background.js b/js/background.js index 409f81787..a6cb232d1 100644 --- a/js/background.js +++ b/js/background.js @@ -132,6 +132,7 @@ const user = { regionCode: window.storage.get('regionCode'), ourNumber: textsecure.storage.user.getNumber(), + ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'), isSecondaryDevice: !!textsecure.storage.get('isSecondaryDevice'), }; Whisper.events.trigger('userChanged', user); diff --git a/js/models/conversations.js b/js/models/conversations.js index 56f78dab6..c1d171cea 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -462,6 +462,10 @@ const regionCode = storage.get('regionCode'); const typingKeys = Object.keys(this.contactTypingTimers || {}); + const groupAdmins = this.isPublic() + ? this.get('moderators') + : this.get('groupAdmins'); + const result = { id: this.id, isArchived: this.get('isArchived'), @@ -494,6 +498,7 @@ hasNickname: !!this.getNickname(), isKickedFromGroup: !!this.get('isKickedFromGroup'), left: !!this.get('left'), + groupAdmins, onClick: () => this.trigger('select', this), onBlockContact: () => this.block(), diff --git a/js/modules/signal.js b/js/modules/signal.js index 37077fe55..4ce3b450a 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -32,9 +32,6 @@ const { UserDetailsDialog } = require('../../ts/components/UserDetailsDialog'); const { DevicePairingDialog, } = require('../../ts/components/DevicePairingDialog'); -const { - SessionConversation, -} = require('../../ts/components/session/conversation/SessionConversation'); const { SessionModal } = require('../../ts/components/session/SessionModal'); const { SessionSeedModal, @@ -244,7 +241,6 @@ exports.setup = (options = {}) => { AddModeratorsDialog, RemoveModeratorsDialog, GroupInvitation, - SessionConversation, SessionConfirm, SessionModal, SessionSeedModal, diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index bffabcc34..3e9f72df4 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -53,6 +53,7 @@ export interface Props { disableMenu?: boolean; isDeletable: boolean; isModerator?: boolean; + weAreModerator?: boolean; text?: string; bodyPending?: boolean; id: string; @@ -691,7 +692,7 @@ class MessageInner extends React.PureComponent { onRetrySend, onShowDetail, isPublic, - isModerator, + weAreModerator, onBanUser, } = this.props; @@ -759,7 +760,7 @@ class MessageInner extends React.PureComponent { ) : null} - {isModerator && isPublic ? ( + {weAreModerator && isPublic ? ( {window.i18n('banUser')} ) : null} diff --git a/ts/components/session/SessionInboxView.tsx b/ts/components/session/SessionInboxView.tsx index 392a02d07..b3d8d2ed0 100644 --- a/ts/components/session/SessionInboxView.tsx +++ b/ts/components/session/SessionInboxView.tsx @@ -200,6 +200,7 @@ export class SessionInboxView extends React.Component { }, user: { regionCode: window.storage.get('regionCode'), + ourPrimary: window.storage.get('primaryDevicePubKey'), ourNumber: window.storage.get('primaryDevicePubKey') || window.textsecure.storage.user.getNumber(), diff --git a/ts/components/session/conversation/SessionConversation.tsx b/ts/components/session/conversation/SessionConversation.tsx index 33fe02905..85ba665ab 100644 --- a/ts/components/session/conversation/SessionConversation.tsx +++ b/ts/components/session/conversation/SessionConversation.tsx @@ -32,6 +32,7 @@ import { getMessageById } from '../../../../js/modules/data'; import { pushUnblockToSend } from '../../../session/utils/Toast'; import { MessageDetail } from '../../conversation/MessageDetail'; import { ConversationController } from '../../../session/conversations'; +import { PubKey } from '../../../session/types'; interface State { // Message sending progress @@ -70,6 +71,7 @@ interface State { } interface Props { + ourPrimary: string; conversationKey: string; conversation: ConversationType; theme: DefaultTheme; @@ -522,11 +524,12 @@ export class SessionConversation extends React.Component { } public getMessagesListProps() { - const { conversation, messages, actions } = this.props; + const { conversation, ourPrimary, messages, actions } = this.props; const { quotedMessageTimestamp, selectedMessages } = this.state; return { selectedMessages, + ourPrimary, conversationKey: conversation.id, messages, resetSelection: this.resetSelection, diff --git a/ts/components/session/conversation/SessionMessagesList.tsx b/ts/components/session/conversation/SessionMessagesList.tsx index adcae6bdd..6f7435bab 100644 --- a/ts/components/session/conversation/SessionMessagesList.tsx +++ b/ts/components/session/conversation/SessionMessagesList.tsx @@ -18,6 +18,7 @@ import { VerificationNotification } from '../../conversation/VerificationNotific import { ToastUtils } from '../../../session/utils'; import { TypingBubble } from '../../conversation/TypingBubble'; import { ConversationController } from '../../../session/conversations'; +import { PubKey } from '../../../session/types'; interface State { showScrollButton: boolean; @@ -29,6 +30,7 @@ interface Props { conversationKey: string; messages: Array; conversation: ConversationType; + ourPrimary: string; messageContainerRef: React.RefObject; selectMessage: (messageId: string) => void; deleteMessage: (messageId: string) => void; @@ -202,7 +204,8 @@ export class SessionMessagesList extends React.Component { } private renderMessages(messages: Array) { - const multiSelectMode = Boolean(this.props.selectedMessages.length); + const { conversation, ourPrimary, selectedMessages } = this.props; + const multiSelectMode = Boolean(selectedMessages.length); let currentMessageIndex = 0; const displayUnreadBannerIndex = this.displayUnreadBannerIndex(messages); @@ -294,6 +297,13 @@ export class SessionMessagesList extends React.Component { ); } + // allow moderators feature on messages (like banning a user) + if (messageProps.isPublic) { + messageProps.weAreModerator = conversation.groupAdmins?.includes( + ourPrimary + ); + } + // firstMessageOfSeries tells us to render the avatar only for the first message // in a series of messages from the same user return ( diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index c39307797..b70893c31 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -79,6 +79,7 @@ export type ConversationType = { isKickedFromGroup: boolean; left: boolean; avatarPath?: string; // absolute filepath to the avatar + groupAdmins?: Array; // admins for closed groups and moderators for open groups }; export type ConversationLookupType = { [key: string]: ConversationType; diff --git a/ts/state/ducks/user.ts b/ts/state/ducks/user.ts index c49cf6386..fd5d06f3b 100644 --- a/ts/state/ducks/user.ts +++ b/ts/state/ducks/user.ts @@ -4,6 +4,7 @@ import { LocalizerType } from '../../types/Util'; export type UserStateType = { ourNumber: string; + ourPrimary: string; regionCode: string; isSecondaryDevice: boolean; i18n: LocalizerType; @@ -15,6 +16,7 @@ type UserChangedActionType = { type: 'USER_CHANGED'; payload: { ourNumber: string; + ourPrimary: string; regionCode: string; isSecondaryDevice: boolean; }; @@ -30,6 +32,7 @@ export const actions = { function userChanged(attributes: { ourNumber: string; + ourPrimary: string; regionCode: string; isSecondaryDevice: boolean; }): UserChangedActionType { @@ -44,6 +47,7 @@ function userChanged(attributes: { function getEmptyState(): UserStateType { return { ourNumber: 'missing', + ourPrimary: 'missing', regionCode: 'missing', isSecondaryDevice: false, i18n: () => 'missing', diff --git a/ts/state/reducer.ts b/ts/state/reducer.ts index f6b07979b..aa7429963 100644 --- a/ts/state/reducer.ts +++ b/ts/state/reducer.ts @@ -8,6 +8,7 @@ import { import { reducer as user, UserStateType } from './ducks/user'; import { reducer as theme, ThemeStateType } from './ducks/theme'; import { reducer as section, SectionStateType } from './ducks/section'; +import { PubKey } from '../session/types'; export type StateType = { search: SearchStateType; diff --git a/ts/state/selectors/user.ts b/ts/state/selectors/user.ts index 6963ad8a3..2535d9570 100644 --- a/ts/state/selectors/user.ts +++ b/ts/state/selectors/user.ts @@ -26,3 +26,8 @@ export const getIsSecondaryDevice = createSelector( getUser, (state: UserStateType): boolean => state.isSecondaryDevice ); + +export const getPrimaryPubkey = createSelector( + getUser, + (state: UserStateType): string => state.ourPrimary +); diff --git a/ts/state/smart/SessionConversation.tsx b/ts/state/smart/SessionConversation.tsx index 3a43e6bf6..4753306a2 100644 --- a/ts/state/smart/SessionConversation.tsx +++ b/ts/state/smart/SessionConversation.tsx @@ -2,9 +2,11 @@ import { connect } from 'react-redux'; import { mapDispatchToProps } from '../actions'; import { SessionConversation } from '../../components/session/conversation/SessionConversation'; import { StateType } from '../reducer'; +import { getPrimaryPubkey } from '../selectors/user'; const mapStateToProps = (state: StateType) => { const conversationKey = state.conversations.selectedConversation; + const ourPrimary = getPrimaryPubkey(state); const conversation = (conversationKey && state.conversations.conversationLookup[conversationKey]) || @@ -14,6 +16,7 @@ const mapStateToProps = (state: StateType) => { conversationKey, theme: state.theme, messages: state.conversations.messages, + ourPrimary, }; };