From 24464a8859915c060bb25d8c0798d0d439845686 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Fri, 19 Apr 2024 16:07:46 -0300 Subject: [PATCH] Refactor the logic on RoomView and apply filters on ShareListView and forward message --- app/lib/encryption/encryption.ts | 20 +++++++++++ app/lib/methods/search.ts | 16 +++++++-- app/views/RoomView/index.tsx | 52 ++++++++++++++-------------- app/views/ShareListView/index.tsx | 57 ++++++++++++++++++++----------- 4 files changed, 99 insertions(+), 46 deletions(-) diff --git a/app/lib/encryption/encryption.ts b/app/lib/encryption/encryption.ts index c51aaa517..06f82d490 100644 --- a/app/lib/encryption/encryption.ts +++ b/app/lib/encryption/encryption.ts @@ -501,6 +501,26 @@ class Encryption { // Decrypt multiple subscriptions decryptSubscriptions = (subscriptions: ISubscription[]) => Promise.all(subscriptions.map(s => this.decryptSubscription(s))); + + // Missing room encryption key + isMissingRoomE2EEKey = ({ + encryptionEnabled, + roomEncrypted, + E2EKey + }: { + encryptionEnabled: boolean; + roomEncrypted: TSubscriptionModel['encrypted']; + E2EKey: TSubscriptionModel['E2EKey']; + }) => (encryptionEnabled && roomEncrypted && !E2EKey) ?? false; + + // Encrypted room, but user session is not encrypted + isE2EEDisabledEncryptedRoom = ({ + encryptionEnabled, + roomEncrypted + }: { + encryptionEnabled: boolean; + roomEncrypted: TSubscriptionModel['encrypted']; + }) => (!encryptionEnabled && roomEncrypted) ?? false; } const encryption = new Encryption(); diff --git a/app/lib/methods/search.ts b/app/lib/methods/search.ts index 5d5b22b1a..b8b65b039 100644 --- a/app/lib/methods/search.ts +++ b/app/lib/methods/search.ts @@ -6,6 +6,7 @@ import { store as reduxStore } from '../store/auxStore'; import { spotlight } from '../services/restApi'; import { ISearch, ISearchLocal, IUserMessage, SubscriptionType, TSubscriptionModel } from '../../definitions'; import { isGroupChat, isReadOnly } from './helpers'; +import { Encryption } from '../encryption'; export type TSearch = ISearchLocal | IUserMessage | ISearch; @@ -46,10 +47,21 @@ export const localSearchSubscription = async ({ if (filterMessagingAllowed) { const username = reduxStore.getState().login.user.username as string; + const encryptionEnabled = reduxStore.getState().encryption.enabled as boolean; const filteredSubscriptions = await Promise.all( subscriptions.map(async item => { - const isItemReadOnly = await isReadOnly(item, username); - return isItemReadOnly ? null : item; + if (await isReadOnly(item, username)) { + return null; + } + + if (Encryption.isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: item.encrypted, E2EKey: item.E2EKey })) { + return null; + } + if (Encryption.isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: item.encrypted })) { + return null; + } + + return item; }) ); subscriptions = filteredSubscriptions.filter(item => item !== null) as TSubscriptionModel[]; diff --git a/app/views/RoomView/index.tsx b/app/views/RoomView/index.tsx index 66cda7617..8d82256ec 100644 --- a/app/views/RoomView/index.tsx +++ b/app/views/RoomView/index.tsx @@ -98,6 +98,7 @@ import AudioManager from '../../lib/methods/AudioManager'; import { IListContainerRef, TListRef } from './List/definitions'; import { getMessageById } from '../../lib/database/services/Message'; import { getThreadById } from '../../lib/database/services/Thread'; +import { Encryption } from '../../lib/encryption'; import { clearInAppFeedback, removeInAppFeedback } from '../../actions/inAppFeedback'; import UserPreferences from '../../lib/methods/userPreferences'; import { IRoomViewProps, IRoomViewState } from './definitions'; @@ -414,17 +415,19 @@ class RoomView extends React.Component { return hideSystemMessages ?? []; } - get missingRoomE2EEKey() { + hasE2EEWarning = () => { const { room } = this.state; const { encryptionEnabled } = this.props; - return (encryptionEnabled && 'encrypted' in room && room.encrypted && 'E2EKey' in room && !room.E2EKey) ?? false; - } - - get e2eeDisabledEncryptedRoom() { - const { room } = this.state; - const { encryptionEnabled } = this.props; - return (!encryptionEnabled && 'encrypted' in room && room.encrypted) ?? false; - } + if ('encrypted' in room) { + if (Encryption.isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: room.encrypted, E2EKey: room.E2EKey })) { + return true; + } + if (Encryption.isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: room.encrypted })) { + return true; + } + } + return false; + }; setHeader = () => { const { room, unreadsCount, roomUserId, joined, canForwardGuest, canReturnQueue, canPlaceLivechatOnHold } = this.state; @@ -513,7 +516,7 @@ class RoomView extends React.Component { onPress={this.goRoomActionsView} testID={`room-view-title-${title}`} sourceType={sourceType} - disabled={this.missingRoomE2EEKey || this.e2eeDisabledEncryptedRoom || !!tmid} + disabled={this.hasE2EEWarning() || !!tmid} /> ), headerRight: () => ( @@ -531,7 +534,7 @@ class RoomView extends React.Component { showActionSheet={this.showActionSheet} departmentId={departmentId} notificationsDisabled={iSubRoom?.disableNotifications} - disabled={this.missingRoomE2EEKey || this.e2eeDisabledEncryptedRoom} + disabled={this.hasE2EEWarning()} /> ) }); @@ -1389,8 +1392,7 @@ class RoomView extends React.Component { + enabled={!loading}> {I18n.t('Resume')} @@ -1405,8 +1407,7 @@ class RoomView extends React.Component { + enabled={!loading}> {I18n.t(this.isOmnichannel ? 'Take_it' : 'Join')} @@ -1460,7 +1461,7 @@ class RoomView extends React.Component { render() { console.count(`${this.constructor.name}.render calls`); const { room, loading, action, selectedMessages } = this.state; - const { user, baseUrl, theme, width, serverVersion, navigation } = this.props; + const { user, baseUrl, theme, width, serverVersion, navigation, encryptionEnabled } = this.props; const { rid, t } = room; let bannerClosed; let announcement; @@ -1468,14 +1469,16 @@ class RoomView extends React.Component { ({ bannerClosed, announcement } = room); } - // Missing room encryption key - if (this.missingRoomE2EEKey) { - return ; - } + if ('encrypted' in room) { + // Missing room encryption key + if (Encryption.isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: room.encrypted, E2EKey: room.E2EKey })) { + return ; + } - // Encrypted room, but user session is not encrypted - if (this.e2eeDisabledEncryptedRoom) { - return ; + // Encrypted room, but user session is not encrypted + if (Encryption.isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: room.encrypted })) { + return ; + } } return ( @@ -1493,8 +1496,7 @@ class RoomView extends React.Component { onSendMessage: this.handleSendMessage, setQuotesAndText: this.setQuotesAndText, getText: this.getText - }} - > + }}> diff --git a/app/views/ShareListView/index.tsx b/app/views/ShareListView/index.tsx index aeebf06cf..dd04c4233 100644 --- a/app/views/ShareListView/index.tsx +++ b/app/views/ShareListView/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Dispatch } from 'redux'; import { StackNavigationProp } from '@react-navigation/stack'; import { BackHandler, FlatList, Keyboard, ScrollView, Text, View } from 'react-native'; import ShareExtension from 'rn-extensions-share'; @@ -20,11 +21,13 @@ import { animateNextTransition } from '../../lib/methods/helpers/layoutAnimation import { TSupportedThemes, withTheme } from '../../theme'; import SafeAreaView from '../../containers/SafeAreaView'; import { sanitizeLikeString } from '../../lib/database/utils'; +import { Encryption } from '../../lib/encryption'; import styles from './styles'; import ShareListHeader from './Header'; -import { TServerModel, TSubscriptionModel } from '../../definitions'; +import { IApplicationState, TServerModel, TSubscriptionModel } from '../../definitions'; import { ShareInsideStackParamList } from '../../definitions/navigationTypes'; import { getRoomAvatar, isAndroid, isIOS, askAndroidMediaPermissions } from '../../lib/methods/helpers'; +import { encryptionInit } from '../../actions/encryption'; interface IDataFromShare { value: string; @@ -61,6 +64,8 @@ interface IShareListViewProps extends INavigationOption { token: string; userId: string; theme: TSupportedThemes; + encryptionEnabled: boolean; + dispatch: Dispatch; } const getItemLayout = (data: any, index: number) => ({ length: data.length, offset: ROW_HEIGHT * index, index }); @@ -97,8 +102,9 @@ class ShareListView extends React.Component { } async componentDidMount() { - const { server } = this.props; + const { server, dispatch } = this.props; try { + dispatch(encryptionInit()); const data = (await ShareExtension.data()) as IDataFromShare[]; if (isAndroid) { await this.askForPermission(data); @@ -217,6 +223,7 @@ class ShareListView extends React.Component { }; query = async (text?: string) => { + const { encryptionEnabled } = this.props; const db = database.active; const defaultWhereClause = [ Q.where('archived', false), @@ -234,19 +241,30 @@ class ShareListView extends React.Component { .query(...defaultWhereClause) .fetch()) as TSubscriptionModel[]; - return data.map(item => ({ - rid: item.rid, - t: item.t, - name: item.name, - fname: item.fname, - blocked: item.blocked, - blocker: item.blocker, - prid: item.prid, - uids: item.uids, - usernames: item.usernames, - topic: item.topic, - teamMain: item.teamMain - })); + return data + .map(item => { + if (Encryption.isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: item.encrypted, E2EKey: item.E2EKey })) { + return null; + } + if (Encryption.isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: item.encrypted })) { + return null; + } + + return { + rid: item.rid, + t: item.t, + name: item.name, + fname: item.fname, + blocked: item.blocked, + blocker: item.blocker, + prid: item.prid, + uids: item.uids, + usernames: item.usernames, + topic: item.topic, + teamMain: item.teamMain + }; + }) + .filter(item => !!item); }; getSubscriptions = async (server: string) => { @@ -465,10 +483,11 @@ class ShareListView extends React.Component { }; } -const mapStateToProps = ({ share }: any) => ({ - userId: share.user && share.user.id, - token: share.user && share.user.token, - server: share.server.server +const mapStateToProps = ({ share, encryption }: IApplicationState) => ({ + userId: share.user && (share.user.id as string), + token: share.user && (share.user.token as string), + server: share.server.server as string, + encryptionEnabled: encryption.enabled }); export default connect(mapStateToProps)(withTheme(ShareListView));