Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runfix: Allow opening device preferences after enrollment #16542

Merged
merged 7 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/script/E2EIdentity/DelayTimer/delay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import {EnrollmentConfig} from '../E2EIdentityEnrollment';
import {MLSStatuses, WireIdentity} from '../E2EIdentityVerification';
import {MLSStatuses, WireIdentity, isFreshMLSSelfClient} from '../E2EIdentityVerification';

/* eslint-disable no-magic-numbers */

Expand Down Expand Up @@ -54,8 +54,14 @@ export function getDelayTime(gracePeriodInMs: number): number {
return 0;
}

export function shouldEnableSoftLock(enrollmentConfig: EnrollmentConfig, identity?: WireIdentity): boolean {
if (!enrollmentConfig.timer.isSnoozeTimeAvailable() || enrollmentConfig.isFreshMLSSelfClient) {
export async function shouldEnableSoftLock(
enrollmentConfig: EnrollmentConfig,
identity?: WireIdentity,
): Promise<boolean> {
if (await isFreshMLSSelfClient()) {
return true;
}
if (!enrollmentConfig.timer.isSnoozeTimeAvailable()) {
// The user has used up the entire grace period or has a fresh new client, he now needs to enroll
return true;
}
Expand Down
17 changes: 11 additions & 6 deletions src/script/E2EIdentity/E2EIdentityEnrollment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ jest.mock('./E2EIdentityVerification', () => ({
hasActiveCertificate: jest.fn().mockResolvedValue(false),
getActiveWireIdentity: jest.fn().mockResolvedValue({certificate: 'certificate data'}),
isE2EIEnabled: jest.fn().mockReturnValue(true),
isFreshMLSSelfClient: jest.fn().mockResolvedValue(false),
}));

// These values should lead to renewalPromptTime being less than the mocked current time
Expand Down Expand Up @@ -135,8 +136,8 @@ describe('E2EIHandler', () => {
jest.spyOn(container.resolve(Core), 'enrollE2EI').mockResolvedValueOnce(true);

const instance = await E2EIHandler.getInstance().initialize(params);
await instance['enroll']();

void instance['enroll']();
await wait(1);
expect(instance['currentStep']).toBe(E2EIHandlerStep.SUCCESS);
});

Expand All @@ -146,7 +147,8 @@ describe('E2EIHandler', () => {
jest.spyOn(container.resolve(UserState), 'self').mockImplementationOnce(() => user);

const instance = await E2EIHandler.getInstance().initialize(params);
await instance['enroll']();
void instance['enroll']();
await wait(1);
expect(instance['currentStep']).toBe(E2EIHandlerStep.ERROR);
});

Expand All @@ -169,7 +171,8 @@ describe('E2EIHandler', () => {

it('should display loading message when enroled', async () => {
const handler = await E2EIHandler.getInstance().initialize(params);
await handler['enroll']();
void handler['enroll']();
await wait(1);
expect(getModalOptions).toHaveBeenCalledWith(
expect.objectContaining({
type: ModalType.LOADING,
Expand All @@ -182,7 +185,8 @@ describe('E2EIHandler', () => {

const handler = await E2EIHandler.getInstance().initialize(params);
handler['showLoadingMessage'] = jest.fn();
await handler['enroll']();
void handler['enroll']();
await wait(1);
expect(getModalOptions).toHaveBeenCalledWith(
expect.objectContaining({
type: ModalType.SUCCESS,
Expand All @@ -195,7 +199,8 @@ describe('E2EIHandler', () => {

const handler = await E2EIHandler.getInstance().initialize(params);
handler['showLoadingMessage'] = jest.fn();
await handler['enroll']();
void handler['enroll']();
await wait(1);
expect(getModalOptions).toHaveBeenCalledWith(
expect.objectContaining({
type: ModalType.ERROR,
Expand Down
134 changes: 69 additions & 65 deletions src/script/E2EIdentity/E2EIdentityEnrollment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export type EnrollmentConfig = {
timer: DelayTimerService;
discoveryUrl: string;
gracePeriodInMs: number;
isFreshMLSSelfClient?: boolean;
};

const historyTimeMS = 28 * TimeInMillis.DAY; //HT
Expand Down Expand Up @@ -122,7 +121,7 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
E2EIHandler.instance = null;
}

public async initialize({discoveryUrl, gracePeriodInSeconds, isFreshMLSSelfClient = false}: E2EIHandlerParams) {
public async initialize({discoveryUrl, gracePeriodInSeconds}: E2EIHandlerParams) {
if (isE2EIEnabled()) {
const gracePeriodInMs = gracePeriodInSeconds * TIME_IN_MILLIS.SECOND;
this.config = {
Expand All @@ -133,7 +132,6 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
gracePeriodExpiredCallback: () => null,
delayPeriodExpiredCallback: () => null,
}),
isFreshMLSSelfClient,
};
}
return this;
Expand All @@ -145,14 +143,7 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
// If the client already has a certificate, we don't need to start the enrollment
return;
}
this.showE2EINotificationMessage();
return new Promise<void>(resolve => {
const handleSuccess = () => {
this.off('identityUpdated', handleSuccess);
resolve();
};
this.on('identityUpdated', handleSuccess);
});
return this.showE2EINotificationMessage(ModalType.ENROLL);
}

public async attemptRenewal(): Promise<void> {
Expand Down Expand Up @@ -312,10 +303,11 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
setTimeout(removeCurrentModal, 0);

this.currentStep = E2EIHandlerStep.SUCCESS;
this.showSuccessMessage(isCertificateRenewal);

// clear the oidc service progress/data and successful enrolment
await this.cleanUp(false);

await this.showSuccessMessage(isCertificateRenewal);
this.emit('identityUpdated', {enrollmentConfig: this.config!});
} catch (error) {
this.currentStep = E2EIHandlerStep.ERROR;

Expand Down Expand Up @@ -344,19 +336,21 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
return;
}

const {modalOptions, modalType} = getModalOptions({
type: ModalType.SUCCESS,
hideSecondary: false,
hideClose: false,
extraParams: {
isRenewal: isCertificateRenewal,
},
primaryActionFn: () => this.emit('identityUpdated', {enrollmentConfig: this.config!}),
secondaryActionFn: () => {
amplify.publish(WebAppEvents.PREFERENCES.MANAGE_DEVICES);
},
return new Promise<void>(resolve => {
const {modalOptions, modalType} = getModalOptions({
type: ModalType.SUCCESS,
hideClose: false,
extraParams: {
isRenewal: isCertificateRenewal,
},
primaryActionFn: resolve,
secondaryActionFn: () => {
amplify.publish(WebAppEvents.PREFERENCES.MANAGE_DEVICES);
resolve();
},
});
PrimaryModal.show(modalType, modalOptions);
});
PrimaryModal.show(modalType, modalOptions);
}

private async showErrorMessage(): Promise<void> {
Expand All @@ -371,22 +365,26 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
// Clear the e2e identity progress
this.coreE2EIService.clearAllProgress();

const isSoftLockEnabled = shouldEnableSoftLock(this.config!);
const isSoftLockEnabled = await shouldEnableSoftLock(this.config!);

const {modalOptions, modalType} = getModalOptions({
type: ModalType.ERROR,
hideClose: true,
hideSecondary: isSoftLockEnabled,
primaryActionFn: () => {
this.currentStep = E2EIHandlerStep.INITIALIZED;
void this.enroll();
},
secondaryActionFn: () => {
this.showE2EINotificationMessage();
},
});
return new Promise<void>(resolve => {
const {modalOptions, modalType} = getModalOptions({
type: ModalType.ERROR,
hideClose: true,
hideSecondary: isSoftLockEnabled,
primaryActionFn: async () => {
this.currentStep = E2EIHandlerStep.INITIALIZED;
await this.enroll();
resolve();
},
secondaryActionFn: async () => {
await this.showE2EINotificationMessage(ModalType.ENROLL);
resolve();
},
});

PrimaryModal.show(modalType, modalOptions);
PrimaryModal.show(modalType, modalOptions);
});
}

private shouldShowNotification(): boolean {
Expand All @@ -403,35 +401,43 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
this.config?.timer.updateParams({
gracePeriodInMS: this.config.gracePeriodInMs,
gracePeriodExpiredCallback: () => {
this.showE2EINotificationMessage();
this.showE2EINotificationMessage(ModalType.ENROLL);
},
delayPeriodExpiredCallback: () => {
this.showE2EINotificationMessage();
this.showE2EINotificationMessage(ModalType.ENROLL);
},
});
this.currentStep = E2EIHandlerStep.INITIALIZED;
}
}

private async showModal(modalType: ModalType = ModalType.ENROLL, hideSecondary = false): Promise<void> {
// Check if config is defined and timer is available
const isSoftLockEnabled = shouldEnableSoftLock(this.config!);
private async showEnrollmentModal(modalType: ModalType.ENROLL | ModalType.CERTIFICATE_RENEWAL): Promise<void> {
// Show the modal with the provided modal type
const disableSnooze = await shouldEnableSoftLock(this.config!);
return new Promise<void>(resolve => {
const {modalOptions, modalType: determinedModalType} = getModalOptions({
hideSecondary: disableSnooze,
primaryActionFn: async () => {
await this.enroll();
resolve();
},
secondaryActionFn: () => {
this.currentStep = E2EIHandlerStep.SNOOZE;
this.config?.timer.delayPrompt();
this.showSnoozeModal();
resolve();
},
type: modalType,
hideClose: true,
});
PrimaryModal.show(determinedModalType, modalOptions);
});
}

private showSnoozeModal() {
// Show the modal with the provided modal type
const {modalOptions, modalType: determinedModalType} = getModalOptions({
hideSecondary: isSoftLockEnabled || hideSecondary,
primaryActionFn: () => {
if (modalType === ModalType.SNOOZE_REMINDER) {
return undefined;
}
return this.enroll();
},
secondaryActionFn: () => {
this.currentStep = E2EIHandlerStep.SNOOZE;
this.config?.timer.delayPrompt();
this.handleE2EIReminderSnooze();
},
type: modalType,
type: ModalType.SNOOZE_REMINDER,
hideClose: true,
extraParams: {
delayTime: formatDelayTime(getDelayTime(this.config!.gracePeriodInMs)),
Expand All @@ -440,16 +446,14 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
PrimaryModal.show(determinedModalType, modalOptions);
}

private handleE2EIReminderSnooze(): void {
void this.showModal(ModalType.SNOOZE_REMINDER, true);
}

public showE2EINotificationMessage(modalType: ModalType = ModalType.ENROLL): void {
public async showE2EINotificationMessage(
modalType: ModalType.CERTIFICATE_RENEWAL | ModalType.ENROLL,
disableSnooze: boolean = false,
): Promise<void> {
// If the user has already started enrolment, don't show the notification. Instead, show the loading modal
// This will occur after the redirect from the oauth provider
if (this.coreE2EIService.isEnrollmentInProgress()) {
void this.enroll();
return;
return this.enroll();
}

// Early return if we shouldn't show the notification
Expand All @@ -461,7 +465,7 @@ export class E2EIHandler extends TypedEventEmitter<Events> {

// If the timer is not active, show the notification modal
if (this.config && !this.config.timer.isDelayTimerActive()) {
void this.showModal(modalType);
return this.showEnrollmentModal(modalType);
}
}
}
9 changes: 5 additions & 4 deletions src/script/hooks/useAppSoftLock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export function useAppSoftLock(callingRepository: CallingRepository, notificatio
const [softLockEnabled, setSoftLockEnabled] = useState(false);

const handleSoftLockActivation = useCallback(
({enrollmentConfig, identity}: {enrollmentConfig: EnrollmentConfig; identity?: WireIdentity}) => {
const isSoftLockEnabled = shouldEnableSoftLock(enrollmentConfig, identity);
async ({enrollmentConfig, identity}: {enrollmentConfig: EnrollmentConfig; identity?: WireIdentity}) => {
const isSoftLockEnabled = await shouldEnableSoftLock(enrollmentConfig, identity);

setSoftLockEnabled(isSoftLockEnabled);
callingRepository.setSoftLock(isSoftLockEnabled);
Expand All @@ -44,10 +44,11 @@ export function useAppSoftLock(callingRepository: CallingRepository, notificatio
if (!e2eiEnabled) {
return () => {};
}
const e2eiHandler = E2EIHandler.getInstance();

E2EIHandler.getInstance().on('identityUpdated', handleSoftLockActivation);
e2eiHandler.on('identityUpdated', handleSoftLockActivation);
return () => {
E2EIHandler.getInstance().off('identityUpdated', handleSoftLockActivation);
e2eiHandler.off('identityUpdated', handleSoftLockActivation);
};
}, [e2eiEnabled, handleSoftLockActivation]);

Expand Down
Loading