diff --git a/monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx b/monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx new file mode 100644 index 000000000..842fa6333 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/IslandHttpClient.tsx @@ -0,0 +1,31 @@ +import AuthComponent from "./AuthComponent"; +import React from "react"; + +export class Response{ + body: any + status: number + + constructor(body: any, status: number) { + this.body = body + this.status = status + } +} + +class IslandHttpClient extends AuthComponent { + post(endpoint: string, contents: any): Promise{ + return this.authFetch(endpoint, + { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify(contents) + }) + .then(res => new Response(res.json(), res.status)); + } + + get(endpoint: string): Promise{ + return this.authFetch(endpoint) + .then(res => new Response(res.json(), res.status)); + } +} + +export default new IslandHttpClient(); diff --git a/monkey/monkey_island/cc/ui/src/components/Main.tsx b/monkey/monkey_island/cc/ui/src/components/Main.tsx index 2c8659bc1..0727b3e70 100644 --- a/monkey/monkey_island/cc/ui/src/components/Main.tsx +++ b/monkey/monkey_island/cc/ui/src/components/Main.tsx @@ -12,6 +12,7 @@ import LicensePage from './pages/LicensePage'; import AuthComponent from './AuthComponent'; import LoginPageComponent from './pages/LoginPage'; import RegisterPageComponent from './pages/RegisterPage'; +import LandingPage from "./pages/LandingPage"; import Notifier from 'react-desktop-notification'; import NotFoundPage from './pages/NotFoundPage'; import GettingStartedPage from './pages/GettingStartedPage'; @@ -24,10 +25,10 @@ import 'react-toggle/style.css'; import 'react-table/react-table.css'; import {StandardLayoutComponent} from './layouts/StandardLayoutComponent'; import LoadingScreen from './ui-components/LoadingScreen'; -import LandingPageComponent from "./pages/LandingPage"; import {DisabledSidebarLayoutComponent} from "./layouts/DisabledSidebarLayoutComponent"; import {CompletedSteps} from "./side-menu/CompletedSteps"; import Timeout = NodeJS.Timeout; +import IslandHttpClient from "./IslandHttpClient"; let notificationIcon = require('../images/notification-logo-512x512.png'); @@ -35,6 +36,11 @@ let notificationIcon = require('../images/notification-logo-512x512.png'); const reportZeroTrustRoute = '/report/zeroTrust'; +const Routes = { + LandingPage: '/landing-page', + GettingStartedPage: '/' +} + class AppComponent extends AuthComponent { private interval: Timeout; @@ -43,7 +49,7 @@ class AppComponent extends AuthComponent { let completedSteps = new CompletedSteps(false); this.state = { completedSteps: completedSteps, - islandMode: undefined, + islandMode: null, noAuthLoginAttempted: undefined }; this.interval = undefined; @@ -70,35 +76,38 @@ class AppComponent extends AuthComponent { }) } - this.checkMode(); - if (res) { - this.authFetch('/api') - .then(res => res.json()) - .then(res => { - // This check is used to prevent unnecessary re-rendering - let isChanged = false; - for (let step in this.state.completedSteps) { - if (this.state.completedSteps[step] !== res['completed_steps'][step]) { - isChanged = true; - break; - } + this.checkMode() + .then(() => { + if(this.state.islandMode === null) { + return } - if (isChanged) { - this.setState({completedSteps: res['completed_steps']}); - this.showInfectionDoneNotification(); - } - }); + this.authFetch('/api') + .then(res => res.json()) + .then(res => { + // This check is used to prevent unnecessary re-rendering + let isChanged = false; + for (let step in this.state.completedSteps) { + if (this.state.completedSteps[step] !== res['completed_steps'][step]) { + isChanged = true; + break; + } + } + if (isChanged) { + this.setState({completedSteps: res['completed_steps']}); + this.showInfectionDoneNotification(); + } + });} + ) + } }); }; checkMode = () => { - // TODO change to fetch the mode from UI - this.authFetch('/api') - .then(res => res.json()) + return IslandHttpClient.get('/api/island-mode') .then(res => { - this.setState({IslandMode: undefined}) + this.setState({islandMode: res.body.mode}); }); } @@ -106,8 +115,10 @@ class AppComponent extends AuthComponent { let render_func = () => { switch (this.state.isLoggedIn) { case true: - if(this.state.islandMode === undefined){ - return this.getLandingPage(); + if (this.state.islandMode === null && route_path !== Routes.LandingPage) { + return + } else if(route_path === Routes.LandingPage && this.state.islandMode !== null){ + return } return page_component; case false: @@ -131,12 +142,6 @@ class AppComponent extends AuthComponent { } }; - getLandingPage() { - return - } - redirectTo = (userPath, targetPath) => { let pathQuery = new RegExp(userPath + '[/]?$', 'g'); if (window.location.pathname.match(pathQuery)) { @@ -160,7 +165,11 @@ class AppComponent extends AuthComponent { ()}/> ()}/> - {this.renderRoute('/', + {this.renderRoute(Routes.LandingPage, + )} + {this.renderRoute(Routes.GettingStartedPage, ( diff --git a/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx b/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx index d6f5136c1..e25717b7f 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx +++ b/monkey/monkey_island/cc/ui/src/components/pages/LandingPage.tsx @@ -4,63 +4,72 @@ import {Link} from 'react-router-dom'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faFileCode, faLightbulb} from '@fortawesome/free-solid-svg-icons'; import '../../styles/pages/LandingPage.scss'; -import AuthComponent from '../AuthComponent'; +import IslandHttpClient from "../IslandHttpClient"; -class LandingPageComponent extends AuthComponent { - constructor(props) { - super(props); - } +const LandingPageComponent = (props) => { - render() { + return ( + +

Welcome to the Monkey Island Server

+
+ +
+
+ + ); + + function ScenarioButtons() { return ( - -

Welcome to the Monkey Island Server

-
- -
+
+

Choose a scenario:

+
+ +
+ { + setScenario('ransomware') + }}> +

Ransomware

+

Simulate ransomware infection in the network.

+ +
+
+ { + setScenario('advanced') + }}> +

Custom

+

Fine tune the simulation to your needs.

+ +
+
+
- +
); } -} -function ScenarioButtons() { - return ( -
-

Choose a scenario:

-
- -
- -

Ransomware

-

Simulate ransomware infection in the network.

- -
-
- -

Custom

-

Fine tune the simulation to your needs.

- -
-
- -
-
- ); + function setScenario(scenario: string) { + IslandHttpClient.post('/api/island-mode', {'mode': scenario}); + props.onStatusChange(); + } } function MonkeyInfo() { - return ( - <> -

What is Infection Monkey?

- Infection Monkey is an open-source security tool for testing a data center's resiliency to perimeter - breaches and internal server infections. The Monkey uses various methods to propagate across a data center - and reports to this Monkey Island Command and Control server. - - ); + return ( + <> +

What is Infection Monkey?

+ Infection Monkey is an open-source security tool for testing a data center's resiliency to + perimeter + breaches and internal server infections. The Monkey uses various methods to propagate across a data center + and reports to this Monkey Island Command and Control server. + + ); } export default LandingPageComponent;