Untitled
unknown
plain_text
a year ago
14 kB
1
Indexable
Never
import React, { Suspense, useEffect, useState } from 'react'; import './App.scss'; import { Route, Switch, Redirect, useLocation, useHistory } from 'react-router-dom'; import Policies from './access-policies/components/policies/Policies'; import { ThemeProvider, Theme, StyledEngineProvider } from '@mui/material/styles'; import { scaTheme } from './scaTheme'; import Wizard, { WizardMode } from './create-edit-policy/wizard/Wizard'; import { INavBarItem, updateSideNavigation, updateShellURL, GeneralMessageEnum } from '@cyberark/shell-sdk'; import { isInIframe } from './utils/shellUtils'; import IntroPage from './introducation-page/introPage'; import './interceptors/CsrfInterceptor'; import './interceptors/RefreshTokenInterceptor'; import { runMocks } from './mocks/mocker'; import { useDispatch, useSelector } from 'react-redux'; import { MessagesState } from './global-state/reducers/ShowMessagesReducer'; import { ConfigService } from './access-policies/services/ConfigService'; import { setSocketConnectionId, updateAccessMap, updateApplicationConfig, updateCemOnboarding, updateCloudRequestObject, updateOnboardingDone, updatePoliciesTable, } from './global-state/Actions'; import CircularProgress from '@mui/material/CircularProgress'; import { Box } from '@mui/material'; import { hideIntroduction, onHideIntroductionButton } from '@cyberark/shell-sdk/dist/shell-sdk'; import ErrorDialog from './error-handling/error-dialog/ErrorDialog'; import Roles from './cloud-roles/components/CloudRoles'; import ServiceUnavalable from './error-handling/service-unavalable/serviceUnavalable'; import { ErrorBoundary } from 'react-error-boundary'; import { shouldInitShellSDK } from './index'; import RequestForm from './request-form/RequestForm'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; import { PermissionService } from './shared/PermissionService'; import { PoliciesService } from './access-policies/services/PoliciesService'; import { CemAzureOnBoardingData } from './onboarding/azure-onboarding/CemAzureOnBoardingData'; import { CemGcpOnBoardingData } from './onboarding/gcp-onboarding/CemGcpOnBoardingData'; import AzureOnboarding from './onboarding/azure-onboarding/AzureOnboarding'; import SelfService from './self-service/SelfService'; import GcpOnboarding from './onboarding/gcp-onboarding/GcpOnboarding'; import { ApplicationConfig } from './global-state/reducers/ApplicationConfigReducer'; import AccessPolicies from './access-policies/AccessPolicies'; import { SocketService } from 'src/cloud-roles/services/SocketService'; import { UserService } from './access-policies/services/UserService'; import { setUserPermissionsAction } from './global-state/actions/user.actions'; import ProtectedRoute from './shared/hoc/ProtectedRoute'; declare module '@mui/styles/defaultTheme' { // eslint-disable-next-line @typescript-eslint/no-empty-interface interface DefaultTheme extends Theme { config?: string; } } export const navBarItems = [ { label: `Introduction`, url: 'introduction', iconClass: 'cyb-ic-welcome', isRoot: true, } as INavBarItem, { label: `Policies`, url: 'policies', iconClass: 'cyb-ic-policy-list', isRoot: true, } as INavBarItem, { label: `Settings`, url: 'settings', iconClass: 'cyb-ic-settings', isRoot: true, shouldHide: true, } as INavBarItem, { label: `gcp_onboarding`, url: 'gcp_onboarding', iconClass: 'cyb-ic-recuring-access', isRoot: true, shouldHide: true, } as INavBarItem, ]; export const navBarItemsWithoutIntro = [ { label: `Policies`, url: 'policies', iconClass: 'cyb-ic-policy-list', isRoot: true, } as INavBarItem, { label: `Settings`, url: 'settings', iconClass: 'cyb-ic-settings', isRoot: true, shouldHide: true, } as INavBarItem, { label: `gcp_onboarding`, url: 'gcp_onboarding', iconClass: 'cyb-ic-recuring-access', isRoot: true, shouldHide: true, } as INavBarItem, ]; const socketService = new SocketService(); const queryClient = new QueryClient(); const userService = new UserService(); function App() { const location = useLocation(); if (process.env.REACT_APP_MOCK === 'mock') { runMocks(); } const appConfig: ApplicationConfig = useSelector<ApplicationConfig>( (state: any) => state.appConfig.applicationConfig ) as ApplicationConfig; const webSocketFlagEnabled = appConfig.wizardConfig.enableWebSocket; const permissionService = new PermissionService(); const errorMessage = useSelector<MessagesState>((state: any) => state.messages) as MessagesState; const dispatch = useDispatch(); const [loading, setLoading] = React.useState(true); const [fetchUserPermissionsLoading, setFetchUserPermissionsLoading] = useState(true); const history = useHistory(); const [defaultRoute, setDefaultRoute] = useState<string>('/Introduction'); const [showHide, setShowHide] = useState(true); let socket: WebSocket; let pingInterval: any; console.log('----- APP .tsx ---- ', { fetchUserPermissionsLoading }); useEffect(() => { getUserPermissions(); }, []); const getUserPermissions = async () => { try { console.log('getUserPermissions'); const res = await userService.getUserPermissions(); console.log({ res }); dispatch(setUserPermissionsAction(res.data.actions)); setFetchUserPermissionsLoading(false); } catch (e) { console.error(e); setFetchUserPermissionsLoading(false); } }; const updateNavBarItems = (items: INavBarItem[], appConfigData: ApplicationConfig) => { return items.map((item) => { if (item.url === 'settings') { item.shouldHide = !appConfigData.navBarItemsShow.selfService; } return item; }); }; const startPingSending = () => { pingInterval = setInterval(() => { if (!socket) { return; } if (socket.readyState === socket.OPEN) { socket.send('heartbeat'); } }, 1000 * 30); }; window.addEventListener( 'message', (e) => { console.log('event listener was invoked'); try { if (e.origin !== window.location.href) { const data = e.data; if (data.SCARequestPayload) { const esacped = data.SCARequestPayload.replace(/"/g, '"'); console.log('esacped' + esacped); const reqObj = JSON.parse(esacped); dispatch(updateCloudRequestObject(reqObj)); } if (e.data.type === GeneralMessageEnum.GENERAL) { const cemData = e.data.data; switch (cemData.type) { case 'CEM_ONBORADING_DATA': if (window.location.hash.includes('gcp_onboarding')) { dispatch(updateCemOnboarding(new CemGcpOnBoardingData(cemData))); break; } if (window.location.hash.includes('azure_onboarding')) { dispatch(updateCemOnboarding(new CemAzureOnBoardingData(cemData))); break; } break; case 'CEM_ONBOARIDNG_PROCESS_DONE': dispatch(updateOnboardingDone({ onboarding: cemData })); break; case 'ACCESS_MAP_LOADED': dispatch(updateAccessMap({ accessMap: true })); break; } } } } catch (ex) { console.error('error from identity listener ' + ex); } }, false ); const connectWebSocket = (url: string) => { socket = new WebSocket(url); socket.onopen = (event: any) => { console.log('Websocket is connected'); startPingSending(); }; socket.onerror = (error: any) => { console.error('Socket encountered error: ', error.message, 'Closing socket'); socket.close(); }; socket.onmessage = (event: any) => { const dataFromServer = JSON.parse(event.data.toString()); if (dataFromServer.policy_id) { console.log('Message received:', event.data); dispatch(updatePoliciesTable(dataFromServer)); } if (dataFromServer.connection_id) { console.log('Message received connection id:', event.data); dispatch(setSocketConnectionId(dataFromServer)); } }; socket.onclose = (event: any) => { console.error('Socket is closed. Reconnect will be attempted in 1 second.', event.reason); if (pingInterval) { clearInterval(pingInterval); } setTimeout(() => { initWebsocket(); }, 1000); }; }; const initWebsocket = () => { socketService .allocateWebSocket() .then((data) => { try { connectWebSocket(data.data); } catch (error: any) { console.error('Connection to websocket failed, Reconnect will be attempted in 3 second.', error); setTimeout(() => { initWebsocket(); }, 3000); } }) .catch((error) => { console.error('Connection to websocket failed, Reconnect will be attempted in 3 second.', error); setTimeout(() => { initWebsocket(); }, 3000); }); }; useEffect(() => { const confService = new ConfigService(); if (!shouldInitShellSDK()) { setLoading(false); return; } confService .getApplicationConfig() .then((result) => { const data = result.data; if (permissionService.isNoAccess(data.applicationConfig.wizardConfig.scope)) { console.log("Your role isn't allowed to use SCA"); setLoading(false); history.push('/service-unavalable'); } data.applicationConfig.timeoutConfig.default = data.applicationConfig.timeoutConfig.default ? data.applicationConfig.timeoutConfig.default * 1000 : 15000; dispatch(updateApplicationConfig(result.data)); setLoading(false); if (isInIframe()) { updateSideNavigation(updateNavBarItems(navBarItems, data.applicationConfig)); onHideIntroductionButton() .then(() => { updateSideNavigation(updateNavBarItems(navBarItemsWithoutIntro, data.applicationConfig)); setDefaultRoute('/policies'); return history.push('/policies'); }) .catch((error) => { console.error(error); }); } if (data.applicationConfig.wizardConfig.enableWebSocket) { initWebsocket(); } }) .catch((error) => { console.log(error); setLoading(false); history.push('/service-unavalable'); }); }, []); useEffect(() => { if (isInIframe()) { updateShellURL({ pathname: location.pathname, }); } }, [location]); const onHideIntroPage = (appConfigData: ApplicationConfig) => { setShowHide(false); updateSideNavigation(updateNavBarItems(navBarItemsWithoutIntro, appConfigData)); hideIntroduction(); history.push('/policies'); }; useEffect(() => { onHideIntroductionButton() .then(() => { setShowHide(false); }) .catch((error) => { console.error(error); }); }, []); const sharedRotes = () => { return ( <> <Route path="/policies"> <AccessPolicies /> </Route> <Route path="/Introduction"> <IntroPage onHideIntroPage={() => onHideIntroPage(appConfig)} showHide={showHide} /> </Route> <Route path="/settings"> <SelfService /> </Route> <Route path="/gcp_onboarding"> <GcpOnboarding /> </Route> <Route path="/azure_onboarding"> <AzureOnboarding /> </Route> <Route path="/service-unavalable"> <ServiceUnavalable /> </Route> <ProtectedRoute path="/create_policy/:provider" render={(props) => <Wizard {...props.match.params.provider} wizardMode={WizardMode.Create} />} permissions={(match) => [`sca.mgmt.${match.params.provider}.create`]} /> <Route path="/view_policy/:provider/:id" render={(props) => <Wizard {...props.match.params.id} wizardMode={WizardMode.View} />} /> <Route path="/edit_policy/:provider/:id" render={(props) => <Wizard {...props.match.params.id} wizardMode={WizardMode.Edit} />} /> <Route path="/cloud_roles"> <Roles /> </Route> <Route path="/request_form"> <RequestForm /> </Route> <Route exact={true} path="/"> <Redirect to={defaultRoute} /> </Route> </> ); }; const getRoutesForApp = () => { if (isInIframe()) { return <Switch>{sharedRotes()}</Switch>; } else { return ( <Switch> <Route path="/policies"> <AccessPolicies /> </Route> {sharedRotes()} <Redirect from="/" to="policies" /> </Switch> ); } }; const showLoader = loading || fetchUserPermissionsLoading; console.log({ loading, fetchUserPermissionsLoading }); console.log({ showLoader }); if (showLoader) { return ( <Box data-testid="app" sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '800px' }}> <CircularProgress size={150} /> </Box> ); } return ( <QueryClientProvider client={queryClient}> <ReactQueryDevtools initialIsOpen={false} /> <StyledEngineProvider injectFirst={true}> <ThemeProvider theme={scaTheme}> <ErrorBoundary FallbackComponent={ServiceUnavalable} onError={(error) => { console.error(error.message); }} > {errorMessage.showErrorMessage && errorMessage.errorDetails ? ( <ErrorDialog open={errorMessage.showErrorMessage} errorDetails={errorMessage.errorDetails} /> ) : null} <Suspense fallback="loading"> <div className="App" data-testid="app"> <div>{getRoutesForApp()}</div> </div> </Suspense> </ErrorBoundary> </ThemeProvider> </StyledEngineProvider> </QueryClientProvider> ); } export default App;