Reenable header, add disable e2ee on header if needed, disable most of actions on RoomActionsView

This commit is contained in:
Diego Mello 2024-05-09 14:14:19 -03:00
parent 354e15619e
commit 0bea843ffa
11 changed files with 202 additions and 120 deletions

View File

@ -841,5 +841,11 @@
"Your_invite_link_will_never_expire": "Your invite link will never expire.", "Your_invite_link_will_never_expire": "Your invite link will never expire.",
"Your_password_is": "Your password is", "Your_password_is": "Your password is",
"Your_push_was_sent_to_s_devices": "Your push was sent to {{s}} devices", "Your_push_was_sent_to_s_devices": "Your push was sent to {{s}} devices",
"Your_workspace": "Your workspace" "Your_workspace": "Your workspace",
"Enable": "Enable",
"Disable": "Disable",
"Disable_encryption_title": "Disable encryption",
"Enable_encryption_title": "Enable encryption",
"Disable_encryption_description": "Disabling E2EE compromises privacy. You can re-enable it later if needed. Proceed with caution.",
"Enable_encryption_description": "Ensure conversations are kept private"
} }

View File

@ -827,5 +827,11 @@
"Your_invite_link_will_never_expire": "Seu link de convite nunca irá vencer.", "Your_invite_link_will_never_expire": "Seu link de convite nunca irá vencer.",
"Your_password_is": "Sua senha é", "Your_password_is": "Sua senha é",
"Your_push_was_sent_to_s_devices": "A sua notificação foi enviada para {{s}} dispositivos", "Your_push_was_sent_to_s_devices": "A sua notificação foi enviada para {{s}} dispositivos",
"Your_workspace": "Sua workspace" "Your_workspace": "Sua workspace",
"Enable": "Habilitar",
"Disable": "Desabilitar",
"Disable_encryption_title": "Desabilitar criptografia",
"Enable_encryption_title": "Habilitar criptografia",
"Disable_encryption_description": "Desabilitar a criptografia compromete sua privacidade. Você pode reabilitá-la depois se precisar. Continue com cautela.",
"Enable_encryption_description": "Garante a privacidade das suas conversas"
} }

View File

@ -501,26 +501,6 @@ class Encryption {
// Decrypt multiple subscriptions // Decrypt multiple subscriptions
decryptSubscriptions = (subscriptions: ISubscription[]) => Promise.all(subscriptions.map(s => this.decryptSubscription(s))); 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(); const encryption = new Encryption();

View File

@ -0,0 +1,70 @@
import { Alert } from 'react-native';
import { Services } from '../../services';
import database from '../../database';
import { getSubscriptionByRoomId } from '../../database/services/Subscription';
import log from '../../methods/helpers/log';
import I18n from '../../../i18n';
export const toggleRoomE2EE = async (rid: string): Promise<void> => {
const room = await getSubscriptionByRoomId(rid);
if (!room) {
return;
}
const isEncrypted = room.encrypted;
const title = I18n.t(isEncrypted ? 'Disable_encryption_title' : 'Enable_encryption_title');
const message = I18n.t(isEncrypted ? 'Disable_encryption_description' : 'Enable_encryption_description');
const confirmationText = I18n.t(isEncrypted ? 'Disable' : 'Enable');
Alert.alert(
title,
message,
[
{
text: I18n.t('Cancel'),
style: 'cancel'
},
{
text: confirmationText,
style: isEncrypted ? 'destructive' : 'default',
onPress: async () => {
try {
const db = database.active;
// Toggle encrypted value
const encrypted = !room.encrypted;
// Instantly feedback to the user
await db.write(async () => {
await room.update(r => {
r.encrypted = encrypted;
});
});
try {
// Send new room setting value to server
const { result } = await Services.saveRoomSettings(rid, { encrypted });
// If it was saved successfully
if (result) {
return;
}
} catch {
// do nothing
}
// If something goes wrong we go back to the previous value
await db.write(async () => {
await room.update(r => {
r.encrypted = room.encrypted;
});
});
} catch (e) {
log(e);
}
}
}
],
{ cancelable: true }
);
};

View File

@ -3,6 +3,7 @@ import SimpleCrypto from 'react-native-simple-crypto';
import { random } from '../methods/helpers'; import { random } from '../methods/helpers';
import { fromByteArray, toByteArray } from './helpers/base64-js'; import { fromByteArray, toByteArray } from './helpers/base64-js';
import { TSubscriptionModel } from '../../definitions';
const BASE64URI = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; const BASE64URI = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
@ -58,3 +59,41 @@ export const toString = (thing: string | ByteBuffer | Buffer | ArrayBuffer | Uin
return new ByteBuffer.wrap(thing).toString('binary'); return new ByteBuffer.wrap(thing).toString('binary');
}; };
export const randomPassword = (): string => `${random(3)}-${random(3)}-${random(3)}`.toLowerCase(); export const randomPassword = (): string => `${random(3)}-${random(3)}-${random(3)}`.toLowerCase();
// Missing room encryption key
export const isMissingRoomE2EEKey = ({
encryptionEnabled,
roomEncrypted,
E2EKey
}: {
encryptionEnabled: boolean;
roomEncrypted: TSubscriptionModel['encrypted'];
E2EKey: TSubscriptionModel['E2EKey'];
}): boolean => (encryptionEnabled && roomEncrypted && !E2EKey) ?? false;
// Encrypted room, but user session is not encrypted
export const isE2EEDisabledEncryptedRoom = ({
encryptionEnabled,
roomEncrypted
}: {
encryptionEnabled: boolean;
roomEncrypted: TSubscriptionModel['encrypted'];
}): boolean => (!encryptionEnabled && roomEncrypted) ?? false;
export const hasE2EEWarning = ({
encryptionEnabled,
roomEncrypted,
E2EKey
}: {
encryptionEnabled: boolean;
roomEncrypted: TSubscriptionModel['encrypted'];
E2EKey: TSubscriptionModel['E2EKey'];
}): boolean => {
if (isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted, E2EKey })) {
return true;
}
if (isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted })) {
return true;
}
return false;
};

View File

@ -6,7 +6,7 @@ import { store as reduxStore } from '../store/auxStore';
import { spotlight } from '../services/restApi'; import { spotlight } from '../services/restApi';
import { ISearch, ISearchLocal, IUserMessage, SubscriptionType, TSubscriptionModel } from '../../definitions'; import { ISearch, ISearchLocal, IUserMessage, SubscriptionType, TSubscriptionModel } from '../../definitions';
import { isGroupChat, isReadOnly } from './helpers'; import { isGroupChat, isReadOnly } from './helpers';
import { Encryption } from '../encryption'; import { isE2EEDisabledEncryptedRoom, isMissingRoomE2EEKey } from '../encryption/utils';
export type TSearch = ISearchLocal | IUserMessage | ISearch; export type TSearch = ISearchLocal | IUserMessage | ISearch;
@ -54,10 +54,10 @@ export const localSearchSubscription = async ({
return null; return null;
} }
if (Encryption.isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: item.encrypted, E2EKey: item.E2EKey })) { if (isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: item.encrypted, E2EKey: item.E2EKey })) {
return null; return null;
} }
if (Encryption.isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: item.encrypted })) { if (isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: item.encrypted })) {
return null; return null;
} }

View File

@ -3,7 +3,7 @@ import React from 'react';
import * as List from '../../../containers/List'; import * as List from '../../../containers/List';
import { useVideoConf } from '../../../lib/hooks/useVideoConf'; import { useVideoConf } from '../../../lib/hooks/useVideoConf';
export default function CallSection({ rid }: { rid: string }): React.ReactElement | null { export default function CallSection({ rid, disabled }: { rid: string; disabled: boolean }): React.ReactElement | null {
const { callEnabled, showInitCallActionSheet, disabledTooltip } = useVideoConf(rid); const { callEnabled, showInitCallActionSheet, disabledTooltip } = useVideoConf(rid);
if (callEnabled) if (callEnabled)
return ( return (
@ -15,7 +15,7 @@ export default function CallSection({ rid }: { rid: string }): React.ReactElemen
testID='room-actions-call' testID='room-actions-call'
left={() => <List.Icon name='phone' />} left={() => <List.Icon name='phone' />}
showActionIndicator showActionIndicator
disabled={disabledTooltip} disabled={disabledTooltip || disabled}
/> />
<List.Separator /> <List.Separator />
</List.Section> </List.Section>

View File

@ -54,6 +54,8 @@ import { ILivechatTag } from '../../definitions/ILivechatTag';
import CallSection from './components/CallSection'; import CallSection from './components/CallSection';
import { TNavigation } from '../../stacks/stackType'; import { TNavigation } from '../../stacks/stackType';
import Switch from '../../containers/Switch'; import Switch from '../../containers/Switch';
import * as EncryptionUtils from '../../lib/encryption/utils';
import { toggleRoomE2EE } from '../../lib/encryption/helpers/toggleRoomE2EE';
type StackType = ChatsStackParamList & TNavigation; type StackType = ChatsStackParamList & TNavigation;
@ -100,6 +102,7 @@ interface IRoomActionsViewState {
canCreateTeam: boolean; canCreateTeam: boolean;
canAddChannelToTeam: boolean; canAddChannelToTeam: boolean;
canConvertTeam: boolean; canConvertTeam: boolean;
hasE2EEWarning: boolean;
loading: boolean; loading: boolean;
} }
@ -151,13 +154,20 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
canCreateTeam: false, canCreateTeam: false,
canAddChannelToTeam: false, canAddChannelToTeam: false,
canConvertTeam: false, canConvertTeam: false,
hasE2EEWarning: false,
loading: false loading: false
}; };
if (room && room.observe && room.rid) { if (room && room.observe && room.rid) {
const { encryptionEnabled } = this.props;
this.roomObservable = room.observe(); this.roomObservable = room.observe();
this.subscription = this.roomObservable.subscribe(changes => { this.subscription = this.roomObservable.subscribe(changes => {
if (this.mounted) { if (this.mounted) {
this.setState({ room: changes, membersCount: changes.usersCount }); const hasE2EEWarning = EncryptionUtils.hasE2EEWarning({
encryptionEnabled,
E2EKey: room.E2EKey,
roomEncrypted: room.encrypted
});
this.setState({ room: changes, membersCount: changes.usersCount, hasE2EEWarning });
} else { } else {
// @ts-ignore // @ts-ignore
this.state.room = changes; this.state.room = changes;
@ -171,6 +181,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
async componentDidMount() { async componentDidMount() {
this.mounted = true; this.mounted = true;
const { room, member } = this.state; const { room, member } = this.state;
const { encryptionEnabled } = this.props;
if (room.rid) { if (room.rid) {
if (!room.id) { if (!room.id) {
if (room.t === SubscriptionType.OMNICHANNEL) { if (room.t === SubscriptionType.OMNICHANNEL) {
@ -214,6 +225,11 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
const canCreateTeam = await this.canCreateTeam(); const canCreateTeam = await this.canCreateTeam();
const canAddChannelToTeam = await this.canAddChannelToTeam(); const canAddChannelToTeam = await this.canAddChannelToTeam();
const canConvertTeam = await this.canConvertTeam(); const canConvertTeam = await this.canConvertTeam();
const hasE2EEWarning = EncryptionUtils.hasE2EEWarning({
encryptionEnabled,
E2EKey: room.E2EKey,
roomEncrypted: room.encrypted
});
this.setState({ this.setState({
canAutoTranslate, canAutoTranslate,
@ -222,7 +238,8 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
canViewMembers, canViewMembers,
canCreateTeam, canCreateTeam,
canAddChannelToTeam, canAddChannelToTeam,
canConvertTeam canConvertTeam,
hasE2EEWarning
}); });
} }
} }
@ -345,7 +362,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
renderEncryptedSwitch = () => { renderEncryptedSwitch = () => {
const { room, canToggleEncryption, canEdit } = this.state; const { room, canToggleEncryption, canEdit } = this.state;
const { encrypted } = room; const { rid, encrypted } = room;
const { serverVersion } = this.props; const { serverVersion } = this.props;
let hasPermission = false; let hasPermission = false;
if (compareServerVersion(serverVersion, 'lowerThan', '3.11.0')) { if (compareServerVersion(serverVersion, 'lowerThan', '3.11.0')) {
@ -353,7 +370,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
} else { } else {
hasPermission = canToggleEncryption; hasPermission = canToggleEncryption;
} }
return <Switch value={encrypted} onValueChange={this.toggleEncrypted} disabled={!hasPermission} />; return <Switch value={encrypted} onValueChange={() => toggleRoomE2EE(rid)} disabled={!hasPermission} />;
}; };
closeLivechat = async () => { closeLivechat = async () => {
@ -477,49 +494,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
}); });
}; };
toggleEncrypted = async () => {
logEvent(events.RA_TOGGLE_ENCRYPTED);
const { room } = this.state;
const { rid } = room;
const db = database.active;
// Toggle encrypted value
const encrypted = !room.encrypted;
try {
// Instantly feedback to the user
await db.write(async () => {
await room.update(
protectedFunction((r: TSubscriptionModel) => {
r.encrypted = encrypted;
})
);
});
try {
// Send new room setting value to server
const { result } = await Services.saveRoomSettings(rid, { encrypted });
// If it was saved successfully
if (result) {
return;
}
} catch {
// do nothing
}
// If something goes wrong we go back to the previous value
await db.write(async () => {
await room.update(
protectedFunction((r: TSubscriptionModel) => {
r.encrypted = room.encrypted;
})
);
});
} catch (e) {
logEvent(events.RA_TOGGLE_ENCRYPTED_F);
log(e);
}
};
handleShare = () => { handleShare = () => {
logEvent(events.RA_SHARE); logEvent(events.RA_SHARE);
const { room } = this.state; const { room } = this.state;
@ -938,7 +912,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
}; };
teamChannelActions = (t: string, room: ISubscription) => { teamChannelActions = (t: string, room: ISubscription) => {
const { canEdit, canCreateTeam, canAddChannelToTeam } = this.state; const { canEdit, canCreateTeam, canAddChannelToTeam, hasE2EEWarning } = this.state;
const canConvertToTeam = canEdit && canCreateTeam && !room.teamMain; const canConvertToTeam = canEdit && canCreateTeam && !room.teamMain;
const canMoveToTeam = canEdit && canAddChannelToTeam && !room.teamId; const canMoveToTeam = canEdit && canAddChannelToTeam && !room.teamId;
@ -956,6 +930,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-convert-to-team' testID='room-actions-convert-to-team'
left={() => <List.Icon name='teams' />} left={() => <List.Icon name='teams' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -973,6 +948,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-move-to-team' testID='room-actions-move-to-team'
left={() => <List.Icon name='channel-move-to-team' />} left={() => <List.Icon name='channel-move-to-team' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -982,7 +958,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
}; };
teamToChannelActions = (t: string, room: ISubscription) => { teamToChannelActions = (t: string, room: ISubscription) => {
const { canEdit, canConvertTeam, loading } = this.state; const { canEdit, canConvertTeam, loading, hasE2EEWarning } = this.state;
const canConvertTeamToChannel = canEdit && canConvertTeam && !!room?.teamMain; const canConvertTeamToChannel = canEdit && canConvertTeam && !!room?.teamMain;
return ( return (
@ -991,7 +967,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
<> <>
<List.Item <List.Item
title='Convert_to_Channel' title='Convert_to_Channel'
disabled={loading} disabled={loading || hasE2EEWarning}
onPress={() => onPress={() =>
this.onPressTouchable({ this.onPressTouchable({
event: this.convertTeamToChannel event: this.convertTeamToChannel
@ -1086,7 +1062,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
}; };
render() { render() {
const { room, membersCount, canViewMembers, joined, canAutoTranslate } = this.state; const { room, membersCount, canViewMembers, joined, canAutoTranslate, hasE2EEWarning } = this.state;
const { isMasterDetail, navigation } = this.props; const { isMasterDetail, navigation } = this.props;
const { rid, t, prid, teamId } = room; const { rid, t, prid, teamId } = room;
const isGroupChatHandler = isGroupChat(room); const isGroupChatHandler = isGroupChat(room);
@ -1096,7 +1072,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
<StatusBar /> <StatusBar />
<List.Container testID='room-actions-scrollview'> <List.Container testID='room-actions-scrollview'>
{this.renderRoomInfo()} {this.renderRoomInfo()}
<CallSection rid={rid} /> <CallSection rid={rid} disabled={hasE2EEWarning} />
{this.renderE2EEncryption()} {this.renderE2EEncryption()}
<List.Section> <List.Section>
<List.Separator /> <List.Separator />
@ -1132,6 +1108,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-discussions' testID='room-actions-discussions'
left={() => <List.Icon name='discussions' />} left={() => <List.Icon name='discussions' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1158,6 +1135,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-teams' testID='room-actions-teams'
left={() => <List.Icon name='channel-public' />} left={() => <List.Icon name='channel-public' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1187,6 +1165,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-files' testID='room-actions-files'
left={() => <List.Icon name='attach' />} left={() => <List.Icon name='attach' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1205,6 +1184,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-mentioned' testID='room-actions-mentioned'
left={() => <List.Icon name='mention' />} left={() => <List.Icon name='mention' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1223,6 +1203,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-starred' testID='room-actions-starred'
left={() => <List.Icon name='star' />} left={() => <List.Icon name='star' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1240,6 +1221,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-share' testID='room-actions-share'
left={() => <List.Icon name='share' />} left={() => <List.Icon name='share' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1258,6 +1240,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-pinned' testID='room-actions-pinned'
left={() => <List.Icon name='pin' />} left={() => <List.Icon name='pin' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1276,6 +1259,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-auto-translate' testID='room-actions-auto-translate'
left={() => <List.Icon name='language' />} left={() => <List.Icon name='language' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>
@ -1294,6 +1278,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
testID='room-actions-notifications' testID='room-actions-notifications'
left={() => <List.Icon name='notification' />} left={() => <List.Icon name='notification' />}
showActionIndicator showActionIndicator
disabled={hasE2EEWarning}
/> />
<List.Separator /> <List.Separator />
</> </>

View File

@ -22,6 +22,7 @@ import { TNavigation } from '../../stacks/stackType';
import { ChatsStackParamList } from '../../stacks/types'; import { ChatsStackParamList } from '../../stacks/types';
import { HeaderCallButton } from './components'; import { HeaderCallButton } from './components';
import { TColors, TSupportedThemes, withTheme } from '../../theme'; import { TColors, TSupportedThemes, withTheme } from '../../theme';
import { toggleRoomE2EE } from '../../lib/encryption/helpers/toggleRoomE2EE';
interface IRightButtonsProps extends Pick<ISubscription, 't'> { interface IRightButtonsProps extends Pick<ISubscription, 't'> {
userId?: string; userId?: string;
@ -48,7 +49,7 @@ interface IRightButtonsProps extends Pick<ISubscription, 't'> {
colors?: TColors; colors?: TColors;
issuesWithNotifications: boolean; issuesWithNotifications: boolean;
notificationsDisabled?: boolean; notificationsDisabled?: boolean;
disabled: boolean; hasE2EEWarning: boolean;
} }
interface IRigthButtonsState { interface IRigthButtonsState {
@ -97,8 +98,16 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
shouldComponentUpdate(nextProps: IRightButtonsProps, nextState: IRigthButtonsState) { shouldComponentUpdate(nextProps: IRightButtonsProps, nextState: IRigthButtonsState) {
const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state; const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state;
const { teamId, status, joined, omnichannelPermissions, theme, disabled, issuesWithNotifications, notificationsDisabled } = const {
this.props; teamId,
status,
joined,
omnichannelPermissions,
theme,
hasE2EEWarning,
issuesWithNotifications,
notificationsDisabled
} = this.props;
if (nextProps.teamId !== teamId) { if (nextProps.teamId !== teamId) {
return true; return true;
} }
@ -111,9 +120,6 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
if (nextProps.theme !== theme) { if (nextProps.theme !== theme) {
return true; return true;
} }
if (nextProps.disabled !== disabled) {
return true;
}
if (nextState.isFollowingThread !== isFollowingThread) { if (nextState.isFollowingThread !== isFollowingThread) {
return true; return true;
} }
@ -123,6 +129,9 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
if (nextProps.notificationsDisabled !== notificationsDisabled) { if (nextProps.notificationsDisabled !== notificationsDisabled) {
return true; return true;
} }
if (nextProps.hasE2EEWarning !== hasE2EEWarning) {
return true;
}
if (!dequal(nextProps.omnichannelPermissions, omnichannelPermissions)) { if (!dequal(nextProps.omnichannelPermissions, omnichannelPermissions)) {
return true; return true;
} }
@ -366,18 +375,17 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
render() { render() {
const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state; const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state;
const { t, tmid, threadsEnabled, rid, colors, issuesWithNotifications, notificationsDisabled, disabled } = this.props; const { t, tmid, threadsEnabled, rid, colors, issuesWithNotifications, notificationsDisabled, hasE2EEWarning } = this.props;
if (!rid) {
return null;
}
if (t === 'l') { if (t === 'l') {
if (!this.isOmnichannelPreview()) { if (!this.isOmnichannelPreview()) {
return ( return (
<HeaderButton.Container> <HeaderButton.Container>
<HeaderButton.Item <HeaderButton.Item iconName='kebab' onPress={this.showMoreActions} testID='room-view-header-omnichannel-kebab' />
iconName='kebab'
onPress={this.showMoreActions}
testID='room-view-header-omnichannel-kebab'
disabled={disabled}
/>
</HeaderButton.Container> </HeaderButton.Container>
); );
} }
@ -390,33 +398,33 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
iconName={isFollowingThread ? 'notification' : 'notification-disabled'} iconName={isFollowingThread ? 'notification' : 'notification-disabled'}
onPress={this.toggleFollowThread} onPress={this.toggleFollowThread}
testID={isFollowingThread ? 'room-view-header-unfollow' : 'room-view-header-follow'} testID={isFollowingThread ? 'room-view-header-unfollow' : 'room-view-header-follow'}
disabled={disabled}
/> />
</HeaderButton.Container> </HeaderButton.Container>
); );
} }
return ( return (
<HeaderButton.Container> <HeaderButton.Container>
{hasE2EEWarning ? <HeaderButton.Item iconName='encrypted' onPress={() => toggleRoomE2EE(rid)} /> : null}
{issuesWithNotifications || notificationsDisabled ? ( {issuesWithNotifications || notificationsDisabled ? (
<HeaderButton.Item <HeaderButton.Item
color={issuesWithNotifications ? colors!.fontDanger : ''} color={issuesWithNotifications ? colors!.fontDanger : ''}
iconName='notification-disabled' iconName='notification-disabled'
onPress={this.navigateToNotificationOrPushTroubleshoot} onPress={this.navigateToNotificationOrPushTroubleshoot}
testID='room-view-push-troubleshoot' testID='room-view-push-troubleshoot'
disabled={disabled} disabled={hasE2EEWarning}
/> />
) : null} ) : null}
{rid ? <HeaderCallButton rid={rid} disabled={disabled} /> : null} {rid ? <HeaderCallButton rid={rid} disabled={hasE2EEWarning} /> : null}
{threadsEnabled ? ( {threadsEnabled ? (
<HeaderButton.Item <HeaderButton.Item
iconName='threads' iconName='threads'
onPress={this.goThreadsView} onPress={this.goThreadsView}
testID='room-view-header-threads' testID='room-view-header-threads'
badge={() => <HeaderButton.BadgeUnread tunread={tunread} tunreadUser={tunreadUser} tunreadGroup={tunreadGroup} />} badge={() => <HeaderButton.BadgeUnread tunread={tunread} tunreadUser={tunreadUser} tunreadGroup={tunreadGroup} />}
disabled={disabled} disabled={hasE2EEWarning}
/> />
) : null} ) : null}
<HeaderButton.Item iconName='search' onPress={this.goSearchView} testID='room-view-search' disabled={disabled} /> <HeaderButton.Item iconName='search' onPress={this.goSearchView} testID='room-view-search' disabled={hasE2EEWarning} />
</HeaderButton.Container> </HeaderButton.Container>
); );
} }

View File

@ -98,7 +98,7 @@ import AudioManager from '../../lib/methods/AudioManager';
import { IListContainerRef, TListRef } from './List/definitions'; import { IListContainerRef, TListRef } from './List/definitions';
import { getMessageById } from '../../lib/database/services/Message'; import { getMessageById } from '../../lib/database/services/Message';
import { getThreadById } from '../../lib/database/services/Thread'; import { getThreadById } from '../../lib/database/services/Thread';
import { Encryption } from '../../lib/encryption'; import { hasE2EEWarning, isE2EEDisabledEncryptedRoom, isMissingRoomE2EEKey } from '../../lib/encryption/utils';
import { clearInAppFeedback, removeInAppFeedback } from '../../actions/inAppFeedback'; import { clearInAppFeedback, removeInAppFeedback } from '../../actions/inAppFeedback';
import UserPreferences from '../../lib/methods/userPreferences'; import UserPreferences from '../../lib/methods/userPreferences';
import { IRoomViewProps, IRoomViewState } from './definitions'; import { IRoomViewProps, IRoomViewState } from './definitions';
@ -415,23 +415,9 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
return hideSystemMessages ?? []; return hideSystemMessages ?? [];
} }
hasE2EEWarning = () => {
const { room } = this.state;
const { encryptionEnabled } = this.props;
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 = () => { setHeader = () => {
const { room, unreadsCount, roomUserId, joined, canForwardGuest, canReturnQueue, canPlaceLivechatOnHold } = this.state; const { room, unreadsCount, roomUserId, joined, canForwardGuest, canReturnQueue, canPlaceLivechatOnHold } = this.state;
const { navigation, isMasterDetail, theme, baseUrl, user, route } = this.props; const { navigation, isMasterDetail, theme, baseUrl, user, route, encryptionEnabled } = this.props;
const { rid, tmid } = this; const { rid, tmid } = this;
if (!room.rid) { if (!room.rid) {
return; return;
@ -516,7 +502,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
onPress={this.goRoomActionsView} onPress={this.goRoomActionsView}
testID={`room-view-title-${title}`} testID={`room-view-title-${title}`}
sourceType={sourceType} sourceType={sourceType}
disabled={this.hasE2EEWarning() || !!tmid} disabled={!!tmid}
/> />
), ),
headerRight: () => ( headerRight: () => (
@ -534,7 +520,9 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
showActionSheet={this.showActionSheet} showActionSheet={this.showActionSheet}
departmentId={departmentId} departmentId={departmentId}
notificationsDisabled={iSubRoom?.disableNotifications} notificationsDisabled={iSubRoom?.disableNotifications}
disabled={this.hasE2EEWarning()} hasE2EEWarning={
'encrypted' in room && hasE2EEWarning({ encryptionEnabled, E2EKey: room.E2EKey, roomEncrypted: room.encrypted })
}
/> />
) )
}); });
@ -1475,12 +1463,12 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
if ('encrypted' in room) { if ('encrypted' in room) {
// Missing room encryption key // Missing room encryption key
if (Encryption.isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: room.encrypted, E2EKey: room.E2EKey })) { if (isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: room.encrypted, E2EKey: room.E2EKey })) {
return <MissingRoomE2EEKey />; return <MissingRoomE2EEKey />;
} }
// Encrypted room, but user session is not encrypted // Encrypted room, but user session is not encrypted
if (Encryption.isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: room.encrypted })) { if (isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: room.encrypted })) {
return <EncryptedRoom navigation={navigation} roomName={getRoomTitle(room)} />; return <EncryptedRoom navigation={navigation} roomName={getRoomTitle(room)} />;
} }
} }

View File

@ -21,13 +21,13 @@ import { animateNextTransition } from '../../lib/methods/helpers/layoutAnimation
import { TSupportedThemes, withTheme } from '../../theme'; import { TSupportedThemes, withTheme } from '../../theme';
import SafeAreaView from '../../containers/SafeAreaView'; import SafeAreaView from '../../containers/SafeAreaView';
import { sanitizeLikeString } from '../../lib/database/utils'; import { sanitizeLikeString } from '../../lib/database/utils';
import { Encryption } from '../../lib/encryption';
import styles from './styles'; import styles from './styles';
import ShareListHeader from './Header'; import ShareListHeader from './Header';
import { IApplicationState, TServerModel, TSubscriptionModel } from '../../definitions'; import { IApplicationState, TServerModel, TSubscriptionModel } from '../../definitions';
import { ShareInsideStackParamList } from '../../definitions/navigationTypes'; import { ShareInsideStackParamList } from '../../definitions/navigationTypes';
import { getRoomAvatar, isAndroid, isIOS, askAndroidMediaPermissions } from '../../lib/methods/helpers'; import { getRoomAvatar, isAndroid, isIOS, askAndroidMediaPermissions } from '../../lib/methods/helpers';
import { encryptionInit } from '../../actions/encryption'; import { encryptionInit } from '../../actions/encryption';
import { isE2EEDisabledEncryptedRoom, isMissingRoomE2EEKey } from '../../lib/encryption/utils';
interface IDataFromShare { interface IDataFromShare {
value: string; value: string;
@ -246,10 +246,10 @@ class ShareListView extends React.Component<IShareListViewProps, IState> {
return data return data
.map(item => { .map(item => {
if (Encryption.isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: item.encrypted, E2EKey: item.E2EKey })) { if (isMissingRoomE2EEKey({ encryptionEnabled, roomEncrypted: item.encrypted, E2EKey: item.E2EKey })) {
return null; return null;
} }
if (Encryption.isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: item.encrypted })) { if (isE2EEDisabledEncryptedRoom({ encryptionEnabled, roomEncrypted: item.encrypted })) {
return null; return null;
} }