Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / components / containers / login / ssoExternalLogin.ts
blobc7b6b730f30bfb20919c5e503c81150f22ecc0b3
1 import { MINUTE } from '@proton/shared/lib/constants';
2 import { getHostname } from '@proton/shared/lib/helpers/url';
4 export class ExternalSSOError extends Error {}
6 export const handleExternalSSOLogin = ({
7     token,
8     signal,
9     finalRedirectBaseUrl,
10 }: {
11     token: string;
12     signal: AbortSignal;
13     finalRedirectBaseUrl?: string;
14 }) => {
15     if (!token) {
16         throw new Error('Unexpected response');
17     }
19     const url = new URL(`${window.location.origin}/api/auth/sso/${token}`);
21     if (finalRedirectBaseUrl) {
22         url.searchParams.set('FinalRedirectBaseUrl', finalRedirectBaseUrl);
23     }
25     const handleMessage = (event: MessageEvent) => {
26         if (event.data.action === 'sso' && event.data.payload) {
27             const uid: string = event.data.payload.uid;
28             const token: string = event.data.payload.token;
29             return {
30                 action: 'resolve' as const,
31                 payload: { uid, token },
32             };
33         }
34     };
36     const tab = window.open(url);
38     if (!tab) {
39         throw new ExternalSSOError('Unable to open tab');
40     }
42     return new Promise<{ uid: string; token: string }>((resolve, reject) => {
43         let openHandle: ReturnType<typeof setInterval> | undefined = undefined;
44         let timeoutHandle: ReturnType<typeof setTimeout> | undefined = undefined;
45         let reset: () => void;
47         const assertOpen = () => {
48             if (!tab || tab.closed) {
49                 reset();
50                 reject(new ExternalSSOError('Process closed'));
51             }
52         };
54         const onMessage = (event: MessageEvent) => {
55             if (event.source !== tab && getHostname(event.origin) !== window.location.origin) {
56                 return;
57             }
59             const result = handleMessage(event);
60             if (!result) {
61                 return;
62             }
64             if (result.action === 'resolve') {
65                 resolve(result.payload);
66             } else if (result.action === 'reject') {
67                 reject(result.payload);
68             }
70             reset();
71             tab?.close?.();
72         };
74         const abort = () => {
75             reset();
76             tab?.close?.();
77             reject(new ExternalSSOError('Process aborted'));
78         };
80         reset = () => {
81             clearTimeout(timeoutHandle);
82             clearInterval(openHandle);
83             window.removeEventListener('message', onMessage, false);
84             signal.removeEventListener('abort', abort);
85         };
87         signal.addEventListener('abort', abort);
88         window.addEventListener('message', onMessage, false);
89         openHandle = setInterval(() => {
90             assertOpen();
91         }, 2500);
92         timeoutHandle = setTimeout(() => {
93             abort();
94         }, 10 * MINUTE);
95     });