diff --git a/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts b/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts index 28e37299f4c..76b416f85a7 100644 --- a/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts +++ b/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts @@ -151,6 +151,20 @@ describe('E2EIHandler', () => { it('continues in progress enrollment', async () => { jest.spyOn(coreMock.service!.e2eIdentity!, 'isEnrollmentInProgress').mockResolvedValue(true); + + // mock window search params (code, session_state, state) + const searchParams = new URLSearchParams(); + searchParams.append('code', 'CODE'); + searchParams.append('session_state', 'SESSION_STATE'); + searchParams.append('state', 'STATE'); + + Object.defineProperty(window, 'location', { + value: { + search: searchParams.toString(), + }, + writable: true, + }); + const enrollPromise = E2EIHandler.getInstance().initialize(params); await waitFor(() => { expect(modalMock).toHaveBeenCalledWith( @@ -172,6 +186,42 @@ describe('E2EIHandler', () => { return enrollPromise; }); + it('starts from scratch if returned to app without auth params', async () => { + jest.spyOn(coreMock.service!.e2eIdentity!, 'isEnrollmentInProgress').mockResolvedValue(true); + + // mock window search params (code, session_state, state) + Object.defineProperty(window, 'location', { + value: { + search: '', + }, + writable: true, + }); + + const enrollPromise = E2EIHandler.getInstance().initialize(params); + + await waitFor(() => { + expect(modalMock).toHaveBeenCalledWith( + PrimaryModalType.ACKNOWLEDGE, + expect.objectContaining({text: expect.objectContaining({title: 'acme.settingsChanged.headline.alt'})}), + ); + }); + + // Trigger the user clicking the get certificate button + modalMock.mock.lastCall?.[1].primaryAction?.action?.(); + + await waitFor(() => { + expect(modalMock).toHaveBeenCalledWith( + PrimaryModalType.ACKNOWLEDGE, + expect.objectContaining({text: expect.objectContaining({title: 'acme.done.headline'})}), + ); + }); + + // Trigger the user clicking the OK button after successful enrollment + modalMock.mock.lastCall?.[1].primaryAction?.action?.(); + + return enrollPromise; + }); + it('registers a renew timer when device is enrolled', async () => { const conversationState = container.resolve(ConversationState); jest.spyOn(conversationState, 'getSelfMLSConversation').mockReturnValue(new Conversation() as any); diff --git a/src/script/E2EIdentity/E2EIdentityEnrollment.ts b/src/script/E2EIdentity/E2EIdentityEnrollment.ts index 7935ba31c7b..e2718f60b77 100644 --- a/src/script/E2EIdentity/E2EIdentityEnrollment.ts +++ b/src/script/E2EIdentity/E2EIdentityEnrollment.ts @@ -19,6 +19,7 @@ import {LowPrecisionTaskScheduler} from '@wireapp/core/lib/util/LowPrecisionTaskScheduler'; import {amplify} from 'amplify'; +import {SigninResponse} from 'oidc-client-ts'; import {container} from 'tsyringe'; import {TypedEventEmitter} from '@wireapp/commons'; @@ -143,7 +144,13 @@ export class E2EIHandler extends TypedEventEmitter { if (await this.coreE2EIService.isEnrollmentInProgress()) { // If we have an enrollment in progress, we can just finish it (meaning we are coming back from an idp redirect) - await this.enroll(); + if (this.wasJustRedirected()) { + await this.enroll(); + } else { + // If we have an enrollment in progress but we are not coming back from an idp redirect, we need to clear the progress and start over + await this.coreE2EIService.clearAllProgress(); + await this.startEnrollment(ModalType.ENROLL, false); + } } else if (await isFreshMLSSelfClient()) { // When the user logs in to a new device in an environment that has e2ei enabled, they should be forced to enroll await this.startEnrollment(ModalType.ENROLL, false); @@ -151,6 +158,14 @@ export class E2EIHandler extends TypedEventEmitter { return this; } + public wasJustRedirected() { + const searchParams = new URLSearchParams(window.location.search); + + const {state, session_state, code} = new SigninResponse(searchParams); + + return !!state && !!session_state && !!code; + } + /** * Will initiate the timer that will regularly prompt the user to enroll (or to renew the certificate if it is about to expire) * @returns the delay under which the next enrollment/renewal modal will be prompted