From 1008e61adeb3179b9a48fb86f76283e9aa24124f Mon Sep 17 00:00:00 2001 From: Thomas Belin Date: Thu, 18 Jan 2024 16:41:02 +0100 Subject: [PATCH] refactor: Single source of truth to know if e2ei should be enabled (#16552) --- .../E2EIdentity/E2EIdentityEnrollment.ts | 49 ++++++++----------- .../E2EIdentity/E2EIdentityVerification.ts | 7 +-- src/script/components/InputBar/InputBar.tsx | 3 +- src/script/hooks/useAppSoftLock.test.ts | 13 ++--- src/script/hooks/useAppSoftLock.ts | 10 ++-- src/script/hooks/useDeviceIdentities.ts | 4 +- .../Features/E2EIdentity.ts | 6 +++ src/script/service/CoreSingleton.ts | 3 +- src/script/view_model/CallingViewModel.ts | 3 +- 9 files changed, 44 insertions(+), 54 deletions(-) diff --git a/src/script/E2EIdentity/E2EIdentityEnrollment.ts b/src/script/E2EIdentity/E2EIdentityEnrollment.ts index 770f380080a..442f307bea6 100644 --- a/src/script/E2EIdentity/E2EIdentityEnrollment.ts +++ b/src/script/E2EIdentity/E2EIdentityEnrollment.ts @@ -33,23 +33,14 @@ import {getCertificateDetails} from 'Util/certificateDetails'; import {getLogger} from 'Util/Logger'; import {formatDelayTime, TIME_IN_MILLIS} from 'Util/TimeUtil'; import {removeUrlParameters} from 'Util/UrlUtil'; -import {supportsMLS} from 'Util/util'; - -import { - hasActiveCertificate, - isE2EIEnabled, - getActiveWireIdentity, - MLSStatuses, - WireIdentity, -} from './E2EIdentityVerification'; + +import {hasActiveCertificate, getActiveWireIdentity, MLSStatuses, WireIdentity} from './E2EIdentityVerification'; import {getModalOptions, ModalType} from './Modals'; import {OIDCService} from './OIDCService'; import {OIDCServiceStore} from './OIDCService/OIDCServiceStorage'; import {getSnoozeTime, shouldEnableSoftLock} from './SnoozableTimer/delay'; import {SnoozableTimer} from './SnoozableTimer/SnoozableTimer'; -import {Config} from '../Config'; - export enum E2EIHandlerStep { UNINITIALIZED = 'uninitialized', INITIALIZED = 'initialized', @@ -121,20 +112,26 @@ export class E2EIHandler extends TypedEventEmitter { E2EIHandler.instance = null; } + /** + * Returns true if the current instance has been configured with team settings params + * @returns + */ + public isE2EIEnabled() { + return this.currentStep !== E2EIHandlerStep.UNINITIALIZED; + } + public initialize({discoveryUrl, gracePeriodInSeconds}: E2EIHandlerParams) { - if (isE2EIEnabled()) { - const gracePeriodInMs = gracePeriodInSeconds * TIME_IN_MILLIS.SECOND; - this.config = { - discoveryUrl, - gracePeriodInMs, - timer: new SnoozableTimer({ - gracePeriodInMS: gracePeriodInMs, - onGracePeriodExpired: () => this.startEnrollment(ModalType.ENROLL), - onSnoozeExpired: () => this.startEnrollment(ModalType.ENROLL), - }), - }; - this.currentStep = E2EIHandlerStep.INITIALIZED; - } + const gracePeriodInMs = gracePeriodInSeconds * TIME_IN_MILLIS.SECOND; + this.config = { + discoveryUrl, + gracePeriodInMs, + timer: new SnoozableTimer({ + gracePeriodInMS: gracePeriodInMs, + onGracePeriodExpired: () => this.startEnrollment(ModalType.ENROLL), + onSnoozeExpired: () => this.startEnrollment(ModalType.ENROLL), + }), + }; + this.currentStep = E2EIHandlerStep.INITIALIZED; return this; } @@ -230,10 +227,6 @@ export class E2EIHandler extends TypedEventEmitter { return renewalDate; } - get isE2EIEnabled(): boolean { - return supportsMLS() && Config.getConfig().FEATURE.ENABLE_E2EI; - } - private async storeRedirectTargetAndRedirect( targetURL: string, keyAuth: KeyAuth, diff --git a/src/script/E2EIdentity/E2EIdentityVerification.ts b/src/script/E2EIdentity/E2EIdentityVerification.ts index d960834c734..0ae7ced8b82 100644 --- a/src/script/E2EIdentity/E2EIdentityVerification.ts +++ b/src/script/E2EIdentity/E2EIdentityVerification.ts @@ -22,11 +22,10 @@ import {DeviceIdentity} from '@wireapp/core/lib/messagingProtocols/mls'; import {container} from 'tsyringe'; import {Core} from 'src/script/service/CoreSingleton'; -import {base64ToArray, supportsMLS} from 'Util/util'; +import {base64ToArray} from 'Util/util'; import {mapMLSStatus} from './certificateDetails'; -import {Config} from '../Config'; import {ConversationState} from '../conversation/ConversationState'; export enum MLSStatuses { @@ -49,10 +48,6 @@ export function getE2EIdentityService() { return e2eIdentityService; } -export function isE2EIEnabled(): boolean { - return supportsMLS() && Config.getConfig().FEATURE.ENABLE_E2EI; -} - export async function getUsersIdentities(groupId: string, userIds: QualifiedId[]) { const userVerifications = await getE2EIdentityService().getUsersIdentities(groupId, userIds); diff --git a/src/script/components/InputBar/InputBar.tsx b/src/script/components/InputBar/InputBar.tsx index 02d3d29bfc3..a62ab77bd26 100644 --- a/src/script/components/InputBar/InputBar.tsx +++ b/src/script/components/InputBar/InputBar.tsx @@ -58,7 +58,6 @@ import {loadDraftState, saveDraftState} from './util/DraftStateUtil'; import {Config} from '../../Config'; import {ConversationVerificationState} from '../../conversation/ConversationVerificationState'; import {MessageRepository, OutgoingQuote} from '../../conversation/MessageRepository'; -import {isE2EIEnabled} from '../../E2EIdentity'; import {Conversation} from '../../entity/Conversation'; import {ContentMessage} from '../../entity/message/ContentMessage'; import {User} from '../../entity/User'; @@ -353,7 +352,7 @@ export const InputBar = ({ const handleSendMessage = () => { const isE2EIDegraded = conversation.mlsVerificationState() === ConversationVerificationState.DEGRADED; - if (isE2EIEnabled() && isE2EIDegraded) { + if (isE2EIDegraded) { PrimaryModal.show(PrimaryModal.type.CONFIRM, { primaryAction: { action: () => { diff --git a/src/script/hooks/useAppSoftLock.test.ts b/src/script/hooks/useAppSoftLock.test.ts index 48d34982e9d..ee18a61f265 100644 --- a/src/script/hooks/useAppSoftLock.test.ts +++ b/src/script/hooks/useAppSoftLock.test.ts @@ -22,12 +22,11 @@ import {renderHook, waitFor} from '@testing-library/react'; import {useAppSoftLock} from './useAppSoftLock'; import {CallingRepository} from '../calling/CallingRepository'; -import {E2EIHandler, isE2EIEnabled} from '../E2EIdentity'; +import {E2EIHandler} from '../E2EIdentity'; import {isFreshMLSSelfClient} from '../E2EIdentity/E2EIdentityVerification'; import {NotificationRepository} from '../notification/NotificationRepository'; const isFreshMLSSelfClientMock = isFreshMLSSelfClient as jest.MockedFn; -const isE2EIEnabledMock = isE2EIEnabled as jest.MockedFn; const E2EIHandlerMock = E2EIHandler as jest.Mocked; jest.mock('../E2EIdentity/E2EIdentityVerification', () => ({ @@ -35,7 +34,6 @@ jest.mock('../E2EIdentity/E2EIdentityVerification', () => ({ })); jest.mock('../E2EIdentity', () => ({ - isE2EIEnabled: jest.fn(), E2EIHandler: { getInstance: jest.fn(), }, @@ -50,6 +48,9 @@ describe('useAppSoftLock', () => { }); it('should not do anything if e2ei is not enabled', () => { + E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => false), + } as any); const {result} = renderHook(() => useAppSoftLock(callingRepository, notificationRepository)); expect(result.current).toEqual({softLockEnabled: false}); expect(callingRepository.setSoftLock).not.toHaveBeenCalledWith(true); @@ -57,8 +58,8 @@ describe('useAppSoftLock', () => { }); it('should set soft lock to true if the user has used up the entire grace period', async () => { - isE2EIEnabledMock.mockReturnValue(true); E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => true), on: jest.fn((eventName, callback) => callback({enrollmentConfig: {timer: {isSnoozeTimeAvailable: () => false}}})), off: jest.fn(), } as any); @@ -73,9 +74,9 @@ describe('useAppSoftLock', () => { }); it('should set softLock if the device is a fresh new device', async () => { - isE2EIEnabledMock.mockReturnValue(true); isFreshMLSSelfClientMock.mockResolvedValue(true); E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => true), on: jest.fn((eventName, callback) => callback({enrollmentConfig: {timer: {isSnoozeTimeAvailable: () => true}}})), off: jest.fn(), } as any); @@ -90,8 +91,8 @@ describe('useAppSoftLock', () => { }); it('should not set softLock if the device is an old device and the grace period is not expireds', async () => { - isE2EIEnabledMock.mockReturnValue(true); E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => true), on: jest.fn((eventName, callback) => callback({enrollmentConfig: {timer: {isSnoozeTimeAvailable: () => true}, isFreshMLSSelfClient: false}}), ), diff --git a/src/script/hooks/useAppSoftLock.ts b/src/script/hooks/useAppSoftLock.ts index 89e9bfcd95a..8a4019c106d 100644 --- a/src/script/hooks/useAppSoftLock.ts +++ b/src/script/hooks/useAppSoftLock.ts @@ -20,13 +20,11 @@ import {useCallback, useEffect, useState} from 'react'; import {CallingRepository} from '../calling/CallingRepository'; -import {E2EIHandler, EnrollmentConfig, isE2EIEnabled, WireIdentity} from '../E2EIdentity'; +import {E2EIHandler, EnrollmentConfig, WireIdentity} from '../E2EIdentity'; import {shouldEnableSoftLock} from '../E2EIdentity/SnoozableTimer/delay'; import {NotificationRepository} from '../notification/NotificationRepository'; export function useAppSoftLock(callingRepository: CallingRepository, notificationRepository: NotificationRepository) { - const e2eiEnabled = isE2EIEnabled(); - const [softLockEnabled, setSoftLockEnabled] = useState(false); const handleSoftLockActivation = useCallback( @@ -41,16 +39,16 @@ export function useAppSoftLock(callingRepository: CallingRepository, notificatio ); useEffect(() => { - if (!e2eiEnabled) { + const e2eiHandler = E2EIHandler.getInstance(); + if (!e2eiHandler.isE2EIEnabled()) { return () => {}; } - const e2eiHandler = E2EIHandler.getInstance(); e2eiHandler.on('identityUpdated', handleSoftLockActivation); return () => { e2eiHandler.off('identityUpdated', handleSoftLockActivation); }; - }, [e2eiEnabled, handleSoftLockActivation]); + }, [handleSoftLockActivation]); return {softLockEnabled}; } diff --git a/src/script/hooks/useDeviceIdentities.ts b/src/script/hooks/useDeviceIdentities.ts index 2b0459acdb3..006ca06f060 100644 --- a/src/script/hooks/useDeviceIdentities.ts +++ b/src/script/hooks/useDeviceIdentities.ts @@ -21,13 +21,13 @@ import {useCallback, useEffect, useState} from 'react'; import {QualifiedId} from '@wireapp/api-client/lib/user'; -import {E2EIHandler, getUsersIdentities, isE2EIEnabled, MLSStatuses, WireIdentity} from '../E2EIdentity'; +import {E2EIHandler, getUsersIdentities, MLSStatuses, WireIdentity} from '../E2EIdentity'; export const useUserIdentity = (userId: QualifiedId, groupId?: string, updateAfterEnrollment?: boolean) => { const [deviceIdentities, setDeviceIdentities] = useState(); const refreshDeviceIdentities = useCallback(async () => { - if (!isE2EIEnabled() || !groupId) { + if (!E2EIHandler.getInstance().isE2EIEnabled() || !groupId) { return; } const userIdentities = await getUsersIdentities(groupId, [userId]); diff --git a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts index 2fbcc30d90b..aaa2fc418f5 100644 --- a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts +++ b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts @@ -19,8 +19,10 @@ import {FeatureStatus, FEATURE_KEY, FeatureList} from '@wireapp/api-client/lib/team'; +import {Config} from 'src/script/Config'; import {E2EIHandler} from 'src/script/E2EIdentity'; import {Logger} from 'Util/Logger'; +import {supportsMLS} from 'Util/util'; import {hasE2EIVerificationExpiration, hasMLSDefaultProtocol} from '../../../../../guards/Protocol'; @@ -32,6 +34,10 @@ export const configureE2EI = (logger: Logger, config: FeatureList): undefined | return undefined; } + if (!supportsMLS() && Config.getConfig().FEATURE.ENABLE_E2EI) { + return undefined; + } + // Check if E2EIdentity feature is enabled if (e2eiConfig?.status === FeatureStatus.ENABLED) { // Check if MLS feature is enabled diff --git a/src/script/service/CoreSingleton.ts b/src/script/service/CoreSingleton.ts index 06c44ea32a5..56d5f4e6f47 100644 --- a/src/script/service/CoreSingleton.ts +++ b/src/script/service/CoreSingleton.ts @@ -28,7 +28,6 @@ import {createStorageEngine, DatabaseTypes} from './StoreEngineProvider'; import {SystemCrypto, wrapSystemCrypto} from './utils/systemCryptoWrapper'; import {Config} from '../Config'; -import {isE2EIEnabled} from '../E2EIdentity'; declare global { interface Window { @@ -63,7 +62,7 @@ export class Core extends Account { ? { keyingMaterialUpdateThreshold: Config.getConfig().FEATURE.MLS_CONFIG_KEYING_MATERIAL_UPDATE_THRESHOLD, cipherSuite: Config.getConfig().FEATURE.MLS_CONFIG_DEFAULT_CIPHERSUITE, - useE2EI: isE2EIEnabled(), + useE2EI: Config.getConfig().FEATURE.ENABLE_E2EI, } : undefined, } diff --git a/src/script/view_model/CallingViewModel.ts b/src/script/view_model/CallingViewModel.ts index 829a5997945..8e0037fdb02 100644 --- a/src/script/view_model/CallingViewModel.ts +++ b/src/script/view_model/CallingViewModel.ts @@ -42,7 +42,6 @@ import {PrimaryModal} from '../components/Modals/PrimaryModal'; import {Config} from '../Config'; import {ConversationState} from '../conversation/ConversationState'; import {ConversationVerificationState} from '../conversation/ConversationVerificationState'; -import {isE2EIEnabled} from '../E2EIdentity'; import type {Conversation} from '../entity/Conversation'; import type {User} from '../entity/User'; import type {ElectronDesktopCapturerSource, MediaDevicesHandler} from '../media/MediaDevicesHandler'; @@ -257,7 +256,7 @@ export class CallingViewModel { const memberCount = conversationEntity.participating_user_ets().length; const isE2EIDegraded = conversationEntity.mlsVerificationState() === ConversationVerificationState.DEGRADED; - if (isE2EIEnabled() && isE2EIDegraded) { + if (isE2EIDegraded) { showE2EICallModal(conversationEntity, callType); } else if (memberCount > MAX_USERS_TO_CALL_WITHOUT_CONFIRM) { showMaxUsersToCallModalWithoutConfirm(conversationEntity, callType);