From c6b7f4f0bebc67fc8452e7a44c0548242473a7b6 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 20 Oct 2020 10:12:10 +0300 Subject: [PATCH] Brought back and refactored run on AWS button. --- .../pages/RunMonkeyPage/AWSRunButton.js | 75 ++++++++++++ .../pages/RunMonkeyPage/AWSRunInstances.js | 108 ++++++++++++++++++ .../RunMonkeyPage}/AwsRunTable.js | 0 .../pages/RunMonkeyPage/RunOptions.js | 2 + .../monkey_island/cc/ui/src/styles/Main.scss | 1 + .../cc/ui/src/styles/components/Buttons.scss | 6 + 6 files changed, 192 insertions(+) create mode 100644 monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunButton.js create mode 100644 monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunInstances.js rename monkey/monkey_island/cc/ui/src/components/{run-monkey => pages/RunMonkeyPage}/AwsRunTable.js (100%) create mode 100644 monkey/monkey_island/cc/ui/src/styles/components/Buttons.scss diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunButton.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunButton.js new file mode 100644 index 000000000..f176ba0b5 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunButton.js @@ -0,0 +1,75 @@ +import React, {useEffect, useState} from 'react'; +import AuthComponent from '../../AuthComponent'; +import '../../../styles/components/RunOnIslandButton.scss'; +import {faCloud} from '@fortawesome/free-solid-svg-icons'; +import AWSRunInstances from './AWSRunInstances'; +import NextSelectionButton from '../../ui-components/inline-selection/NextSelectionButton'; +import {Alert, Button} from 'react-bootstrap'; + + +function AWSRunButton(props) { + + const authComponent = new AuthComponent({}); + + const [isOnAWS, setIsOnAWS] = useState(false); + const [AWSInstances, setAWSInstances] = useState([]); + const [awsMachineCollectionError, setAwsMachineCollectionError] = useState(''); + + useEffect(() => { + checkIsOnAWS(); + }, []); + + function checkIsOnAWS() { + authComponent.authFetch('/api/remote-monkey?action=list_aws') + .then(res => res.json()) + .then(res => { + let isAws = res['is_aws']; + + if (isAws) { + // On AWS! + // Checks if there was an error while collecting the aws machines. + let isErrorWhileCollectingAwsMachines = (res['error'] != null); + if (isErrorWhileCollectingAwsMachines) { + // There was an error. Finish loading, and display error message. + setIsOnAWS(true); + setAwsMachineCollectionError(res['error']); + } else { + // No error! Finish loading and display machines for user + setIsOnAWS(true); + setAWSInstances(res['instances']); + } + } + }); + } + + function getAWSButton() { + return { + props.setComponent(AWSRunInstances, + {AWSInstances: AWSInstances, setComponent: props.setComponent}) + }}/> + } + + function getErrorDisplay() { + return ( + Detected ability to run on different AWS instances. + To enable this feature, follow the   + and refresh the page. Error received while trying to list AWS instances: {awsMachineCollectionError} + ); + } + + let displayed = ''; + if (awsMachineCollectionError !== '') { + displayed = getErrorDisplay(); + } else if (isOnAWS) { + displayed = getAWSButton(); + } + return displayed; +} + +export default AWSRunButton; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunInstances.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunInstances.js new file mode 100644 index 000000000..4cc4f4e88 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AWSRunInstances.js @@ -0,0 +1,108 @@ +import React, {useEffect, useState} from 'react'; +import {Button, Nav} from 'react-bootstrap'; + +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faSync} from '@fortawesome/free-solid-svg-icons/faSync'; +import '../../../styles/components/RunOnIslandButton.scss'; +import {faInfoCircle} from '@fortawesome/free-solid-svg-icons/faInfoCircle'; +import AwsRunTable from './AwsRunTable'; +import AuthComponent from '../../AuthComponent'; + + +function AWSRunInstances(props) { + + const authComponent = new AuthComponent({}); + + let awsTable = null + let [allIPs, setAllIPs] = useState([]); + let [selectedIp, setSelectedIp] = useState(null); + let [AWSClicked, setAWSClicked] = useState(false); + + useEffect(() => { + getIps(); + }, [allIPs]); + + function getIps() { + this.authFetch('/api') + .then(res => res.json()) + .then(res => { + setAllIPs(res['ip_addresses']); + setSelectedIp(res['ip_addresses'][0]); + }); + } + + function runOnAws() { + setAWSClicked(true); + let instances = awsTable.state.selection.map(x => instanceIdToInstance(x)); + + authComponent.authFetch('/api/remote-monkey', + { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({type: 'aws', instances: instances, island_ip: selectedIp}) + }).then(res => res.json()) + .then(res => { + let result = res['result']; + + // update existing state, not run-over + let prevRes = awsTable.state.result; + for (let key in result) { + if (result.hasOwnProperty(key)) { + prevRes[key] = result[key]; + } + } + awsTable.setState({ + result: prevRes, + selection: [], + selectAll: false + }); + setAWSClicked(false); + }); + } + + function instanceIdToInstance(instance_id) { + let instance = props.AWSInstances.find( + function (inst) { + return inst['instance_id'] === instance_id; + }); + + return {'instance_id': instance_id, 'os': instance['os']} + } + + return ( +
+
+

+ + Not sure what this is? Not seeing your AWS EC2 instances? Read the documentation! +

+
+ { + allIPs.length > 1 ? + + :
+ } + (awsTable = r)} + /> +
+ +
+
+ ); +} + +export default AWSRunInstances; diff --git a/monkey/monkey_island/cc/ui/src/components/run-monkey/AwsRunTable.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AwsRunTable.js similarity index 100% rename from monkey/monkey_island/cc/ui/src/components/run-monkey/AwsRunTable.js rename to monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/AwsRunTable.js diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js index a9fe1f8cf..e7c14c217 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js @@ -7,6 +7,7 @@ import InlineSelection from '../../ui-components/inline-selection/InlineSelectio import {cloneDeep} from 'lodash'; import {faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons'; import RunOnIslandButton from './RunOnIslandButton'; +import AWSRunButton from './AWSRunButton'; function RunOptions(props) { @@ -61,6 +62,7 @@ function RunOptions(props) { setComponent(LocalManualRunOptions, {ips: ips, setComponent: setComponent}) }}/> + ); } diff --git a/monkey/monkey_island/cc/ui/src/styles/Main.scss b/monkey/monkey_island/cc/ui/src/styles/Main.scss index 616217e52..4e8419c82 100644 --- a/monkey/monkey_island/cc/ui/src/styles/Main.scss +++ b/monkey/monkey_island/cc/ui/src/styles/Main.scss @@ -17,6 +17,7 @@ @import 'components/inline-selection/BackButton'; @import 'components/inline-selection/CommandDisplay'; @import 'components/Icons'; +@import 'components/Buttons'; // Define custom elements after bootstrap import diff --git a/monkey/monkey_island/cc/ui/src/styles/components/Buttons.scss b/monkey/monkey_island/cc/ui/src/styles/components/Buttons.scss new file mode 100644 index 000000000..43bdc92fc --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/styles/components/Buttons.scss @@ -0,0 +1,6 @@ +a.inline-link { + position: relative; + top: -1px; + margin: 0; + padding: 0; +}