From f814b6ee47e7f10789442318c3351fe154dd81ef Mon Sep 17 00:00:00 2001 From: Thomas Belin Date: Tue, 27 Feb 2024 14:26:40 +0100 Subject: [PATCH] runfix: Fix grace period computation for verified devices (#16930) --- .../E2EIdentity/E2EIdentityEnrollment.ts | 8 +-- ...bleTimerStorage.ts => Enrollment.store.ts} | 2 +- .../EnrollmentTimer/EnrollmentTimer.test.ts | 65 +++++++++++++++++++ .../EnrollmentTimer.ts} | 8 +-- .../E2EIdentity/EnrollmentTimer/index.ts | 20 ++++++ 5 files changed, 94 insertions(+), 9 deletions(-) rename src/script/E2EIdentity/{SnoozableTimer/SnoozableTimerStorage.ts => Enrollment.store.ts} (96%) create mode 100644 src/script/E2EIdentity/EnrollmentTimer/EnrollmentTimer.test.ts rename src/script/E2EIdentity/{SnoozableTimer/delay.ts => EnrollmentTimer/EnrollmentTimer.ts} (94%) create mode 100644 src/script/E2EIdentity/EnrollmentTimer/index.ts diff --git a/src/script/E2EIdentity/E2EIdentityEnrollment.ts b/src/script/E2EIdentity/E2EIdentityEnrollment.ts index 69a34250bd2..95ec33943ff 100644 --- a/src/script/E2EIdentity/E2EIdentityEnrollment.ts +++ b/src/script/E2EIdentity/E2EIdentityEnrollment.ts @@ -32,11 +32,11 @@ import {formatDelayTime, TIME_IN_MILLIS} from 'Util/TimeUtil'; import {removeUrlParameters} from 'Util/UrlUtil'; import {hasActiveCertificate, getActiveWireIdentity, isFreshMLSSelfClient} from './E2EIdentityVerification'; +import {EnrollmentStore} from './Enrollment.store'; +import {getEnrollmentTimer} from './EnrollmentTimer'; import {getModalOptions, ModalType} from './Modals'; import {OIDCService} from './OIDCService'; import {OIDCServiceStore} from './OIDCService/OIDCServiceStorage'; -import {getEnrollmentTimer} from './SnoozableTimer/delay'; -import {SnoozableTimerStore} from './SnoozableTimer/SnoozableTimerStorage'; const {TaskScheduler} = util; interface E2EIHandlerParams { @@ -142,8 +142,8 @@ export class E2EIHandler extends TypedEventEmitter { */ public async startTimers() { // We store the first time the user was prompted with the enrollment modal - const e2eActivatedAt = SnoozableTimerStore.get.e2eiActivatedAt() || Date.now(); - SnoozableTimerStore.store.e2eiActivatedAt(e2eActivatedAt); + const e2eActivatedAt = EnrollmentStore.get.e2eiActivatedAt() || Date.now(); + EnrollmentStore.store.e2eiActivatedAt(e2eActivatedAt); const timerKey = 'enrollmentTimer'; const identity = await getActiveWireIdentity(); diff --git a/src/script/E2EIdentity/SnoozableTimer/SnoozableTimerStorage.ts b/src/script/E2EIdentity/Enrollment.store.ts similarity index 96% rename from src/script/E2EIdentity/SnoozableTimer/SnoozableTimerStorage.ts rename to src/script/E2EIdentity/Enrollment.store.ts index 47c9a891443..ca1a1de8eb7 100644 --- a/src/script/E2EIdentity/SnoozableTimer/SnoozableTimerStorage.ts +++ b/src/script/E2EIdentity/Enrollment.store.ts @@ -19,7 +19,7 @@ const e2eActivatedAtKey = 'e2eActivatedAt'; -export const SnoozableTimerStore = { +export const EnrollmentStore = { store: { e2eiActivatedAt: (time: number) => localStorage.setItem(e2eActivatedAtKey, String(time)), }, diff --git a/src/script/E2EIdentity/EnrollmentTimer/EnrollmentTimer.test.ts b/src/script/E2EIdentity/EnrollmentTimer/EnrollmentTimer.test.ts new file mode 100644 index 00000000000..b2ab5d669c4 --- /dev/null +++ b/src/script/E2EIdentity/EnrollmentTimer/EnrollmentTimer.test.ts @@ -0,0 +1,65 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {getEnrollmentTimer, messageRetentionTime} from './EnrollmentTimer'; + +import {MLSStatuses} from '../E2EIdentityVerification'; + +describe('e2ei delays', () => { + const gracePeriod = 3600; + beforeEach(() => { + jest.useFakeTimers(); + jest.setSystemTime(0); + }); + + it('should return an immediate delay if the identity is expired', () => { + const delay = getEnrollmentTimer({status: MLSStatuses.EXPIRED} as any, Date.now(), gracePeriod); + + expect(delay).toEqual({firingDate: Date.now(), isSnoozable: false}); + }); + + it('should return a snoozable timer if device is new and still in the grace period', () => { + const {firingDate, isSnoozable} = getEnrollmentTimer(undefined, Date.now(), gracePeriod); + + expect(isSnoozable).toBeTruthy(); + expect(firingDate).toBeLessThanOrEqual(gracePeriod); + }); + + it('should return a snoozable timer if device is certified and still in the grace period', () => { + const {firingDate, isSnoozable} = getEnrollmentTimer( + {certificate: ' ', notAfter: Date.now() + messageRetentionTime + gracePeriod + 1000} as any, + Date.now(), + gracePeriod, + ); + + expect(isSnoozable).toBeTruthy(); + expect(firingDate).toBeLessThanOrEqual(gracePeriod); + }); + + it('should return a non snoozable timer if device is certified about to expired', () => { + const {firingDate, isSnoozable} = getEnrollmentTimer( + {certificate: ' ', notAfter: Date.now() + gracePeriod + 1000} as any, + Date.now(), + gracePeriod, + ); + + expect(isSnoozable).toBeFalsy(); + expect(firingDate).toBeLessThanOrEqual(gracePeriod); + }); +}); diff --git a/src/script/E2EIdentity/SnoozableTimer/delay.ts b/src/script/E2EIdentity/EnrollmentTimer/EnrollmentTimer.ts similarity index 94% rename from src/script/E2EIdentity/SnoozableTimer/delay.ts rename to src/script/E2EIdentity/EnrollmentTimer/EnrollmentTimer.ts index 7f457f16b79..36df081e942 100644 --- a/src/script/E2EIdentity/SnoozableTimer/delay.ts +++ b/src/script/E2EIdentity/EnrollmentTimer/EnrollmentTimer.ts @@ -30,7 +30,7 @@ export const FOUR_HOURS = TimeInMillis.HOUR * 4; export const ONE_DAY = TimeInMillis.DAY; // message retention time on backend (hardcoded to 28 days) -const messageRetentionTime = 28 * TimeInMillis.DAY; +export const messageRetentionTime = 28 * TimeInMillis.DAY; /** * Will return a suitable snooze time based on the grace period @@ -40,7 +40,7 @@ function getNextTick(expiryDate: number, gracePeriodDuration: number, isFirstEnr const leftoverTimer = expiryDate - Date.now(); // First a first enrollment we only consider the grace period. For enrolled devices we also consider the backend message retention time - const extraDelay = isFirstEnrollment ? 0 : randomInt(TimeInMillis.DAY) - messageRetentionTime; + const extraDelay = isFirstEnrollment ? 0 : randomInt(TimeInMillis.DAY) + messageRetentionTime; const gracePeriod = Math.max(0, Math.min(gracePeriodDuration, leftoverTimer - extraDelay)); if (gracePeriod <= 0) { @@ -61,7 +61,7 @@ function getNextTick(expiryDate: number, gracePeriodDuration: number, isFirstEnr export function getEnrollmentTimer( identity: WireIdentity | undefined, - deviceCreatedAt: number, + e2eiActivatedAt: number, teamGracePeriodDuration: number, ) { if (identity?.status === MLSStatuses.EXPIRED) { @@ -70,7 +70,7 @@ export function getEnrollmentTimer( const isFirstEnrollment = !identity?.certificate; const expiryDate = isFirstEnrollment - ? deviceCreatedAt + teamGracePeriodDuration + ? e2eiActivatedAt + teamGracePeriodDuration : Number(identity.notAfter) * TimeInMillis.SECOND; const nextTick = getNextTick(expiryDate, teamGracePeriodDuration, isFirstEnrollment); diff --git a/src/script/E2EIdentity/EnrollmentTimer/index.ts b/src/script/E2EIdentity/EnrollmentTimer/index.ts new file mode 100644 index 00000000000..d17ea105798 --- /dev/null +++ b/src/script/E2EIdentity/EnrollmentTimer/index.ts @@ -0,0 +1,20 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +export * from './EnrollmentTimer';