import React from 'react'; import { Anchor, Text } from '@mantine/core'; import { VisynLoginForm } from './VisynLoginForm'; import { IUserStore, userSession } from '../../security'; import { LoginUtils } from '../../security/LoginUtils'; interface IUserStoreRenderProps { setError(error: string | null): void; store: T; } export const UserStoreUIMap: Map React.ReactElement> = new Map(); export function DefaultLoginForm({ setError, store }: IUserStoreRenderProps) { return ( { setError(null); return LoginUtils.login(username, password) .then(() => { setError(null); }) .catch((e) => { if (e.response && e.response.status !== 401) { // 401 = Unauthorized // server error setError('not_reachable'); } else { setError('Username or password incorrect. Please try again.'); } }); }} /> ); } UserStoreUIMap.set('DefaultLoginForm', DefaultLoginForm); export function AutoLoginForm({ setError, store }: IUserStoreRenderProps) { const [loginInProgress, setLoginInProgress] = React.useState(false); const POLL_INTERVAL = 500; const MAX_POLL_TIME = 5 * 60 * 1000; // 5 minutes in milliseconds const HOSTNAME = window.location.hostname; const pollQueryStringChange = async (popup: Window): Promise => { // Keep track of polling iterations to avoid endless loops. let tries = 0; const maxTries = MAX_POLL_TIME / POLL_INTERVAL; // eslint-disable-next-line no-constant-condition while (true) { if (popup.closed) { setError('Popup was closed before a successful login.'); } try { if (popup.window.location.hostname === HOSTNAME) { // eslint-disable-next-line no-await-in-loop, no-promise-executor-return await new Promise((resolve) => setTimeout(resolve, 1000)); // eslint-disable-next-line no-await-in-loop const user = await LoginUtils.loggedInAs().catch(() => { // ignore not yet logged in }); if (user) { userSession.login(user); } else { setError('Could not login in, try refreshing the page.'); } break; } } catch (e) { console.error(`Checking window for token failed: `, e); } // User is not logged in yet, waiting for POLL_INTERVAL // eslint-disable-next-line no-await-in-loop await new Promise((resolve) => { setTimeout(resolve, POLL_INTERVAL); }); tries++; if (tries > maxTries) { setError(`Login timed out after ${MAX_POLL_TIME} milliseconds.`); } } }; const login = async () => { if (!loginInProgress) { // Only allow a single concurrent login access setLoginInProgress(true); let popup: Window | null = null; try { // Add timestamp to avoid no proper reloading due to cache hits. const authUrl = `${window.location.origin}?timestamp=${new Date().getTime()}`; popup = window.open( authUrl, 'Authorization', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no,width=600,height=600', ); if (!popup) { setError('Could not open login popup.'); return null; } // Polling until we are actually logged in await pollQueryStringChange(popup); } catch (e) { console.error('An error occurred while communicating with the OAuth provider', e); return null; } finally { setLoginInProgress(false); popup?.close(); } } return undefined; }; return ( You will be automatically logged in as soon as you visit the application. If your access is expired, click{' '} { e.preventDefault(); e.stopPropagation(); login(); }} > here {' '} to open a login window or refresh the page. ); } UserStoreUIMap.set('AutoLoginForm', AutoLoginForm);