From 0836691020370a127a2847cd38f16cc6356e8779 Mon Sep 17 00:00:00 2001 From: Fidel Coria Date: Tue, 22 Dec 2020 15:44:42 -0600 Subject: [PATCH] Revert "eliminate racey code" This reverts commit 907fac9d9272444a40ff46a979de2e47b4088b71. --- packages/core-api/src/lib/loginPopup.test.ts | 80 ++++++++++++++++++++ packages/core-api/src/lib/loginPopup.ts | 18 +++++ 2 files changed, 98 insertions(+) diff --git a/packages/core-api/src/lib/loginPopup.test.ts b/packages/core-api/src/lib/loginPopup.test.ts index f645b75af7..98541c268e 100644 --- a/packages/core-api/src/lib/loginPopup.test.ts +++ b/packages/core-api/src/lib/loginPopup.test.ts @@ -135,4 +135,84 @@ describe('showLoginPopup', () => { expect(addEventListenerSpy).toBeCalledTimes(1); expect(removeEventListenerSpy).toBeCalledTimes(1); }); + + it('should fail if popup is closed', async () => { + const openSpy = jest + .spyOn(window, 'open') + .mockReturnValue({ closed: false } as Window); + const addEventListenerSpy = jest.spyOn(window, 'addEventListener'); + const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener'); + const popupMock = { closed: false }; + + openSpy.mockReturnValue(popupMock as Window); + + const payloadPromise = showLoginPopup({ + url: 'url', + name: 'name', + origin: 'origin', + }); + + expect(openSpy).toBeCalledTimes(1); + expect(addEventListenerSpy).toBeCalledTimes(1); + expect(removeEventListenerSpy).toBeCalledTimes(0); + + const listener = addEventListenerSpy.mock.calls[0][1] as EventListener; + listener({ + source: popupMock, + origin: 'origin', + data: { + type: 'config_info', + targetOrigin: 'http://localhost', + }, + } as MessageEvent); + + setTimeout(() => { + popupMock.closed = true; + }, 150); + await expect(payloadPromise).rejects.toThrow( + 'Login failed, popup was closed', + ); + + expect(openSpy).toBeCalledTimes(1); + expect(addEventListenerSpy).toBeCalledTimes(1); + expect(removeEventListenerSpy).toBeCalledTimes(1); + }); + + it('should indicate if origin does not match', async () => { + const openSpy = jest + .spyOn(window, 'open') + .mockReturnValue({ closed: false } as Window); + const addEventListenerSpy = jest.spyOn(window, 'addEventListener'); + const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener'); + const popupMock = { closed: false }; + + openSpy.mockReturnValue(popupMock as Window); + + const payloadPromise = showLoginPopup({ + url: 'url', + name: 'name', + origin: 'origin', + }); + + const listener = addEventListenerSpy.mock.calls[0][1] as EventListener; + listener({ + source: popupMock, + origin: 'origin', + data: { + type: 'config_info', + targetOrigin: 'http://differenthost', + }, + } as MessageEvent); + + setTimeout(() => { + popupMock.closed = true; + }, 150); + await expect(payloadPromise).rejects.toThrow( + 'Login failed, Incorrect app origin, expected http://differenthost', + ); + + expect(openSpy).toBeCalledTimes(1); + expect(addEventListenerSpy).toBeCalledTimes(1); + expect(removeEventListenerSpy).toBeCalledTimes(1); + }); }); diff --git a/packages/core-api/src/lib/loginPopup.ts b/packages/core-api/src/lib/loginPopup.ts index 1741d845e8..2e14447882 100644 --- a/packages/core-api/src/lib/loginPopup.ts +++ b/packages/core-api/src/lib/loginPopup.ts @@ -79,6 +79,8 @@ export function showLoginPopup(options: LoginPopupOptions): Promise { `menubar=no,location=no,resizable=no,scrollbars=no,status=no,width=${width},height=${height},top=${top},left=${left}`, ); + let targetOrigin = ''; + if (!popup || typeof popup.closed === 'undefined' || popup.closed) { reject(new Error('Failed to open auth popup.')); return; @@ -94,6 +96,7 @@ export function showLoginPopup(options: LoginPopupOptions): Promise { const { data } = event; if (data.type === 'config_info') { + targetOrigin = data.targetOrigin; return; } @@ -114,8 +117,23 @@ export function showLoginPopup(options: LoginPopupOptions): Promise { done(); }; + const intervalId = setInterval(() => { + if (popup.closed) { + const errMessage = `Login failed, ${ + targetOrigin !== window.location.origin + ? `Incorrect app origin, expected ${targetOrigin}` + : 'popup was closed' + }`; + const error = new Error(errMessage); + error.name = 'PopupClosedError'; + reject(error); + done(); + } + }, 100); + function done() { window.removeEventListener('message', messageListener); + clearInterval(intervalId); } window.addEventListener('message', messageListener);