Skip to content

Commit c42e669

Browse files
runfix: fresh client snoozable after oidc failure [WPB-8878] (#17407) (#17408)
* runfix: fresh client snoozable after oidc failure * test: enrollment error with and without snooze option * docs: add comment to snooze param when client is fresh Co-authored-by: Patryk Górka <[email protected]>
1 parent 93e5069 commit c42e669

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

src/script/E2EIdentity/E2EIdentityEnrollment.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,85 @@ describe('E2EIHandler', () => {
222222
return enrollPromise;
223223
});
224224

225+
it('shows the error modal without the snooze option after enrollment failed and the client is fresh', async () => {
226+
jest.spyOn(coreMock.service!.e2eIdentity!, 'isFreshMLSSelfClient').mockResolvedValue(true);
227+
jest.spyOn(coreMock.service!.e2eIdentity!, 'isEnrollmentInProgress').mockResolvedValue(true);
228+
jest.spyOn(coreMock, 'enrollE2EI').mockRejectedValue(new Error('OIDC Error'));
229+
230+
const handler = E2EIHandler.getInstance();
231+
232+
// mock window search params (code, session_state, state)
233+
const searchParams = new URLSearchParams();
234+
searchParams.append('code', 'CODE');
235+
searchParams.append('session_state', 'SESSION_STATE');
236+
searchParams.append('state', 'STATE');
237+
238+
Object.defineProperty(window, 'location', {
239+
value: {
240+
search: searchParams.toString(),
241+
},
242+
writable: true,
243+
});
244+
245+
const enrollPromise = handler.initialize(params);
246+
247+
await waitFor(() => {
248+
expect(modalMock).toHaveBeenCalledWith(
249+
PrimaryModalType.ACKNOWLEDGE,
250+
expect.objectContaining({text: expect.objectContaining({title: 'acme.error.headline'})}),
251+
);
252+
expect(modalMock).not.toHaveBeenCalledWith(
253+
PrimaryModalType.CONFIRM,
254+
expect.objectContaining({secondaryAction: expect.objectContaining({text: 'acme.error.button.secondary'})}),
255+
);
256+
});
257+
258+
jest.spyOn(handler, 'enroll').mockImplementation(() => Promise.resolve());
259+
260+
modalMock.mock.lastCall?.[1].primaryAction?.action?.();
261+
262+
return enrollPromise;
263+
});
264+
265+
it('shows the error modal with the snooze option after enrollment failed and the client is an e2ei client already', async () => {
266+
jest.spyOn(coreMock.service!.e2eIdentity!, 'isFreshMLSSelfClient').mockResolvedValue(false);
267+
jest.spyOn(coreMock.service!.e2eIdentity!, 'isEnrollmentInProgress').mockResolvedValue(true);
268+
jest.spyOn(coreMock, 'enrollE2EI').mockRejectedValue(new Error('OIDC Error'));
269+
270+
const handler = E2EIHandler.getInstance();
271+
272+
// mock window search params (code, session_state, state)
273+
const searchParams = new URLSearchParams();
274+
searchParams.append('code', 'CODE');
275+
searchParams.append('session_state', 'SESSION_STATE');
276+
searchParams.append('state', 'STATE');
277+
278+
Object.defineProperty(window, 'location', {
279+
value: {
280+
search: searchParams.toString(),
281+
},
282+
writable: true,
283+
});
284+
285+
const enrollPromise = handler.initialize(params);
286+
287+
await waitFor(() => {
288+
expect(modalMock).toHaveBeenCalledWith(
289+
PrimaryModalType.CONFIRM,
290+
expect.objectContaining({
291+
text: expect.objectContaining({title: 'acme.error.headline'}),
292+
secondaryAction: expect.objectContaining({text: 'acme.error.button.secondary'}),
293+
}),
294+
);
295+
});
296+
297+
jest.spyOn(handler, 'enroll').mockImplementation(() => Promise.resolve());
298+
299+
modalMock.mock.lastCall?.[1].primaryAction?.action?.();
300+
301+
return enrollPromise;
302+
});
303+
225304
it('registers a renew timer when device is enrolled', async () => {
226305
const conversationState = container.resolve(ConversationState);
227306
jest.spyOn(conversationState, 'getSelfMLSConversation').mockReturnValue(new Conversation() as any);

src/script/E2EIdentity/E2EIdentityEnrollment.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,19 @@ export class E2EIHandler extends TypedEventEmitter<Events> {
142142

143143
await this.coreE2EIService.initialize(discoveryUrl);
144144

145+
const isFreshClient = await isFreshMLSSelfClient();
146+
145147
if (await this.coreE2EIService.isEnrollmentInProgress()) {
146148
// If we have an enrollment in progress, we can just finish it (meaning we are coming back from an idp redirect)
147149
if (this.wasJustRedirected()) {
148-
await this.enroll();
150+
// We should not allow to snooze the enorollment if the client is still fresh and the user is coming back from an idp redirect
151+
await this.enroll(!isFreshClient);
149152
} else {
150153
// 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
151154
await this.coreE2EIService.clearAllProgress();
152155
await this.startEnrollment(ModalType.ENROLL, false);
153156
}
154-
} else if (await isFreshMLSSelfClient()) {
157+
} else if (isFreshClient) {
155158
// When the user logs in to a new device in an environment that has e2ei enabled, they should be forced to enroll
156159
await this.startEnrollment(ModalType.ENROLL, false);
157160
}

0 commit comments

Comments
 (0)