diff --git a/docs/content/usage/integrations/aws-run-on-ec2-machine.md b/docs/content/usage/integrations/aws-run-on-ec2-machine.md index 0183dc241..e30a8b554 100644 --- a/docs/content/usage/integrations/aws-run-on-ec2-machine.md +++ b/docs/content/usage/integrations/aws-run-on-ec2-machine.md @@ -54,16 +54,15 @@ See [Amazon's documentation about working with SSM agents](https://docs.aws.amaz ### Running the monkey -When you run the monkey island on an AWS instance, the island detects it's running on AWS and present the following option in the _"Run Monkey"_ page, like so: +When you run the Monkey Island on an AWS instance, the island detects it's running on AWS and present the following option in the _"Run Monkey"_ page, like so: ![Running a Monkey on EC2 Instance](/images/usage/integrations/monkey-island-aws-screenshot-1.png "Running a Monkey on EC2 Instance") -And then you can choose one of the available instances as "patient zero" like so: +After you click on "AWS run" you can choose one of the available instances as "patient zero" like so: -1. Click on "Run on AWS" -2. Choose the relevant Network Interface -3. Select the machines you'd like to run the Monkey on -4. Click "Run on Selected Machines", and watch the monkey go! 🐒 +1. Choose the relevant Network Interface +2. Select the machines you'd like to run the Monkey on +3. Click "Run on Selected Machines", and watch the monkey go! 🐒 ![Running a Monkey on EC2 Instance](/images/usage/integrations/monkey-island-aws-screenshot-2.png "Running a Monkey on EC2 Instance") diff --git a/docs/static/images/usage/integrations/monkey-island-aws-screenshot-1.png b/docs/static/images/usage/integrations/monkey-island-aws-screenshot-1.png index 0b1af5fae..ba61e2b7c 100644 Binary files a/docs/static/images/usage/integrations/monkey-island-aws-screenshot-1.png and b/docs/static/images/usage/integrations/monkey-island-aws-screenshot-1.png differ diff --git a/docs/static/images/usage/integrations/monkey-island-aws-screenshot-2.png b/docs/static/images/usage/integrations/monkey-island-aws-screenshot-2.png index f6442e82b..ad9f6ed81 100644 Binary files a/docs/static/images/usage/integrations/monkey-island-aws-screenshot-2.png and b/docs/static/images/usage/integrations/monkey-island-aws-screenshot-2.png differ diff --git a/monkey/monkey_island/cc/ui/.eslintrc b/monkey/monkey_island/cc/ui/.eslintrc index 2cd52bb98..afc7f2b7a 100644 --- a/monkey/monkey_island/cc/ui/.eslintrc +++ b/monkey/monkey_island/cc/ui/.eslintrc @@ -35,7 +35,8 @@ "comma-dangle": 1, "quotes": [ 1, - "single" + "single", + {"allowTemplateLiterals": true} ], "no-undef": 1, "global-strict": 0, diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/LocalManualRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunManually/LocalManualRunOptions.js similarity index 74% rename from monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/LocalManualRunOptions.js rename to monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunManually/LocalManualRunOptions.js index b28285a18..bd396e256 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/LocalManualRunOptions.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunManually/LocalManualRunOptions.js @@ -1,12 +1,12 @@ import React, {useEffect, useState} from 'react'; -import InlineSelection from '../../ui-components/inline-selection/InlineSelection'; -import DropdownSelect from '../../ui-components/DropdownSelect'; -import {OS_TYPES} from './OsTypes'; -import GenerateLocalWindowsCmd from './commands/local_windows_cmd'; -import GenerateLocalWindowsPowershell from './commands/local_windows_powershell'; -import GenerateLocalLinuxWget from './commands/local_linux_wget'; -import GenerateLocalLinuxCurl from './commands/local_linux_curl'; -import CommandDisplay from './CommandDisplay'; +import InlineSelection from '../../../ui-components/inline-selection/InlineSelection'; +import DropdownSelect from '../../../ui-components/DropdownSelect'; +import {OS_TYPES} from '../utils/OsTypes'; +import GenerateLocalWindowsCmd from '../commands/local_windows_cmd'; +import GenerateLocalWindowsPowershell from '../commands/local_windows_powershell'; +import GenerateLocalLinuxWget from '../commands/local_linux_wget'; +import GenerateLocalLinuxCurl from '../commands/local_linux_curl'; +import CommandDisplay from '../utils/CommandDisplay'; const LocalManualRunOptions = (props) => { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSInstanceTable.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSInstanceTable.js new file mode 100644 index 000000000..cf792f7b8 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSInstanceTable.js @@ -0,0 +1,119 @@ +import React, {useState} from 'react'; +import ReactTable from 'react-table' +import checkboxHOC from 'react-table/lib/hoc/selectTable'; +import PropTypes from 'prop-types'; + + +const CheckboxTable = checkboxHOC(ReactTable); + +const columns = [ + { + Header: 'Machines', + columns: [ + {Header: 'Machine', accessor: 'name'}, + {Header: 'Instance ID', accessor: 'instance_id'}, + {Header: 'IP Address', accessor: 'ip_address'}, + {Header: 'OS', accessor: 'os'} + ] + } +]; + +const pageSize = 10; + +function AWSInstanceTable(props) { + + const [allToggled, setAllToggled] = useState(false); + let checkboxTable = null; + + function toggleSelection(key) { + key = key.replace('select-', ''); + // start off with the existing state + let modifiedSelection = [...props.selection]; + const keyIndex = modifiedSelection.indexOf(key); + // check to see if the key exists + if (keyIndex >= 0) { + // it does exist so we will remove it using destructing + modifiedSelection = [ + ...modifiedSelection.slice(0, keyIndex), + ...modifiedSelection.slice(keyIndex + 1) + ]; + } else { + // it does not exist so add it + modifiedSelection.push(key); + } + // update the state + props.setSelection(modifiedSelection); + } + + function isSelected(key) { + return props.selection.includes(key); + } + + function toggleAll() { + const selectAll = !allToggled; + const selection = []; + if (selectAll) { + // we need to get at the internals of ReactTable + const wrappedInstance = checkboxTable.getWrappedInstance(); + // the 'sortedData' property contains the currently accessible records based on the filter and sort + const currentRecords = wrappedInstance.getResolvedState().sortedData; + // we just push all the IDs onto the selection array + currentRecords.forEach(item => { + selection.push(item._original.instance_id); + }); + } + setAllToggled(selectAll); + props.setSelection(selection); + } + + function getTrProps(_, r) { + let color = 'inherit'; + if (r) { + let instId = r.original.instance_id; + if (isSelected(instId)) { + color = '#ffed9f'; + } else if (Object.prototype.hasOwnProperty.call(props.results, instId)) { + color = props.results[instId] ? '#00f01b' : '#f00000' + } + } + + return { + style: {backgroundColor: color} + }; + } + + return ( +
+ (checkboxTable = r)} + keyField="instance_id" + columns={columns} + data={props.data} + showPagination={true} + defaultPageSize={pageSize} + className="-highlight" + selectType="checkbox" + toggleSelection={toggleSelection} + isSelected={isSelected} + toggleAll={toggleAll} + selectAll={allToggled} + getTrProps={getTrProps} + /> +
+ ); + +} + +AWSInstanceTable.propTypes = { + data: PropTypes.arrayOf(PropTypes.exact({ + instance_id: PropTypes.string, + name: PropTypes.string, + os: PropTypes.string, + ip_address: PropTypes.string + })), + results: PropTypes.arrayOf(PropTypes.string), + selection: PropTypes.arrayOf(PropTypes.string), + setSelection: PropTypes.func +} + +export default AWSInstanceTable; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunButton.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunButton.js new file mode 100644 index 000000000..3903d2a8e --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunButton.js @@ -0,0 +1,80 @@ +import React, {useEffect, useState} from 'react'; +import AuthComponent from '../../../AuthComponent'; +import '../../../../styles/components/RunOnIslandButton.scss'; +import {faCloud} from '@fortawesome/free-solid-svg-icons'; +import AWSRunOptions from './AWSRunOptions'; +import NextSelectionButton from '../../../ui-components/inline-selection/NextSelectionButton'; +import {Alert, Button} from 'react-bootstrap'; +import LoadingIcon from '../../../ui-components/LoadingIcon'; + + +function AWSRunButton(props) { + + const authComponent = new AuthComponent({}); + + const [isOnAWS, setIsOnAWS] = useState(false); + const [AWSInstances, setAWSInstances] = useState([]); + const [awsMachineCollectionError, setAwsMachineCollectionError] = useState(''); + const [componentLoading, setComponentLoading] = useState(true); + + useEffect(() => { + checkIsOnAWS(); + }, []); + + function checkIsOnAWS() { + authComponent.authFetch('/api/remote-monkey?action=list_aws') + .then(res => res.json()) + .then(res => { + let isAws = res['is_aws']; + setComponentLoading(false); + 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(AWSRunOptions, + {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 (componentLoading) { + displayed = LoadingIcon(); + } + 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/RunOnAWS/AWSRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunOptions.js new file mode 100644 index 000000000..eba4cf0f3 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnAWS/AWSRunOptions.js @@ -0,0 +1,117 @@ +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 {faInfoCircle} from '@fortawesome/free-solid-svg-icons/faInfoCircle'; +import AwsRunTable from './AWSInstanceTable'; +import AuthComponent from '../../../AuthComponent'; +import InlineSelection from '../../../ui-components/inline-selection/InlineSelection'; + + +const AWSRunOptions = (props) => { + return InlineSelection(getContents, { + ...props, + onBackButtonClick: () => {props.setComponent()} + }) +} + + +const getContents = (props) => { + + const authComponent = new AuthComponent({}); + + let [allIPs, setAllIPs] = useState([]); + let [selectedIp, setSelectedIp] = useState(null); + let [AWSClicked, setAWSClicked] = useState(false); + let [runResults, setRunResults] = useState([]); + let [selectedInstances, setSelectedInstances] = useState([]); + + useEffect(() => { + getIps(); + }, []); + + function getIps() { + authComponent.authFetch('/api') + .then(res => res.json()) + .then(res => { + setAllIPs(res['ip_addresses']); + setSelectedIp(res['ip_addresses'][0]); + }); + } + + function runOnAws() { + setAWSClicked(true); + let instances = selectedInstances.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 = result; + for (let key in result) { + if (result.hasOwnProperty(key)) { + prevRes[key] = result[key]; + } + } + setRunResults(prevRes); + setSelectedInstances([]); + 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 ? + + :
+ } + +
+ +
+
+ ); +} + +export default AWSRunOptions; 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..379aa647d 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 @@ -1,12 +1,13 @@ import React, {useEffect, useState} from 'react'; import NextSelectionButton from '../../ui-components/inline-selection/NextSelectionButton'; -import LocalManualRunOptions from './LocalManualRunOptions'; +import LocalManualRunOptions from './RunManually/LocalManualRunOptions'; import AuthComponent from '../../AuthComponent'; import {faLaptopCode} from '@fortawesome/free-solid-svg-icons/faLaptopCode'; import InlineSelection from '../../ui-components/inline-selection/InlineSelection'; import {cloneDeep} from 'lodash'; import {faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons'; import RunOnIslandButton from './RunOnIslandButton'; +import AWSRunButton from './RunOnAWS/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/components/pages/RunMonkeyPage/commands/local_linux_curl.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js index fb0171bfd..2f0d5a5d0 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js @@ -1,4 +1,4 @@ -import {OS_TYPES} from '../OsTypes'; +import {OS_TYPES} from '../utils/OsTypes'; export default function generateLocalLinuxCurl(ip, osType) { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js index 766822ee1..b1d2a5a30 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js @@ -1,4 +1,4 @@ -import {OS_TYPES} from '../OsTypes'; +import {OS_TYPES} from '../utils/OsTypes'; export default function generateLocalLinuxWget(ip, osType) { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_cmd.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_cmd.js index 74afbe512..1cb9c2979 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_cmd.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_cmd.js @@ -1,4 +1,4 @@ -import {OS_TYPES} from '../OsTypes'; +import {OS_TYPES} from '../utils/OsTypes'; export default function generateLocalWindowsCmd(ip, osType) { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js index 1ebd1f4ac..97d95fb63 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js @@ -1,4 +1,4 @@ -import {OS_TYPES} from '../OsTypes'; +import {OS_TYPES} from '../utils/OsTypes'; export default function generateLocalWindowsPowershell(ip, osType) { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandDisplay.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/CommandDisplay.js similarity index 100% rename from monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandDisplay.js rename to monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/CommandDisplay.js diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/InterfaceSelection.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/InterfaceSelection.js similarity index 65% rename from monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/InterfaceSelection.js rename to monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/InterfaceSelection.js index 6e74fb4a0..728d1958b 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/InterfaceSelection.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/InterfaceSelection.js @@ -1,6 +1,6 @@ import React from 'react'; -import InlineSelection from '../../ui-components/inline-selection/InlineSelection'; -import LocalManualRunOptions from './LocalManualRunOptions'; +import InlineSelection from '../../../ui-components/inline-selection/InlineSelection'; +import LocalManualRunOptions from '../RunManually/LocalManualRunOptions'; function InterfaceSelection(props) { return InlineSelection(getContents, props, LocalManualRunOptions) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/OsTypes.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/OsTypes.js similarity index 100% rename from monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/OsTypes.js rename to monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/OsTypes.js diff --git a/monkey/monkey_island/cc/ui/src/components/run-monkey/AwsRunTable.js b/monkey/monkey_island/cc/ui/src/components/run-monkey/AwsRunTable.js deleted file mode 100644 index 8c7ccf490..000000000 --- a/monkey/monkey_island/cc/ui/src/components/run-monkey/AwsRunTable.js +++ /dev/null @@ -1,109 +0,0 @@ -import React from 'react'; -import ReactTable from 'react-table' -import checkboxHOC from 'react-table/lib/hoc/selectTable'; - -const CheckboxTable = checkboxHOC(ReactTable); - -const columns = [ - { - Header: 'Machines', - columns: [ - {Header: 'Machine', accessor: 'name'}, - {Header: 'Instance ID', accessor: 'instance_id'}, - {Header: 'IP Address', accessor: 'ip_address'}, - {Header: 'OS', accessor: 'os'} - ] - } -]; - -const pageSize = 10; - -class AwsRunTableComponent extends React.Component { - constructor(props) { - super(props); - this.state = { - selection: [], - selectAll: false, - result: {} - } - } - - toggleSelection = (key) => { - // start off with the existing state - let selection = [...this.state.selection]; - const keyIndex = selection.indexOf(key); - // check to see if the key exists - if (keyIndex >= 0) { - // it does exist so we will remove it using destructing - selection = [ - ...selection.slice(0, keyIndex), - ...selection.slice(keyIndex + 1) - ]; - } else { - // it does not exist so add it - selection.push(key); - } - // update the state - this.setState({selection}); - }; - - isSelected = key => { - return this.state.selection.includes(key); - }; - - toggleAll = () => { - const selectAll = !this.state.selectAll; - const selection = []; - if (selectAll) { - // we need to get at the internals of ReactTable - const wrappedInstance = this.checkboxTable.getWrappedInstance(); - // the 'sortedData' property contains the currently accessible records based on the filter and sort - const currentRecords = wrappedInstance.getResolvedState().sortedData; - // we just push all the IDs onto the selection array - currentRecords.forEach(item => { - selection.push(item._original.instance_id); - }); - } - this.setState({selectAll, selection}); - }; - - getTrProps = (_, r) => { - let color = 'inherit'; - if (r) { - let instId = r.original.instance_id; - if (this.isSelected(instId)) { - color = '#ffed9f'; - } else if (Object.prototype.hasOwnProperty.call(this.state.result, instId)) { - color = this.state.result[instId] ? '#00f01b' : '#f00000' - } - } - - return { - style: {backgroundColor: color} - }; - }; - - render() { - return ( -
- (this.checkboxTable = r)} - keyField="instance_id" - columns={columns} - data={this.props.data} - showPagination={true} - defaultPageSize={pageSize} - className="-highlight" - selectType="checkbox" - toggleSelection={this.toggleSelection} - isSelected={this.isSelected} - toggleAll={this.toggleAll} - selectAll={this.state.selectAll} - getTrProps={this.getTrProps} - /> -
- ); - } -} - -export default AwsRunTableComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/LoadingIcon.js b/monkey/monkey_island/cc/ui/src/components/ui-components/LoadingIcon.js new file mode 100644 index 000000000..465ec7044 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/LoadingIcon.js @@ -0,0 +1,9 @@ +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faSync} from '@fortawesome/free-solid-svg-icons'; +import React from 'react'; + +function LoadingIcon() { + return +} + +export default LoadingIcon; 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; +} diff --git a/monkey/monkey_island/cc/ui/src/styles/components/Icons.scss b/monkey/monkey_island/cc/ui/src/styles/components/Icons.scss index ed75d8a9d..7f8eadf05 100644 --- a/monkey/monkey_island/cc/ui/src/styles/components/Icons.scss +++ b/monkey/monkey_island/cc/ui/src/styles/components/Icons.scss @@ -1,3 +1,10 @@ +.loading-icon { + color: $monkey-yellow; + font-size: 20px; + margin-left: 50%; + margin-right: 50%; +} + .spinning-icon { animation: spin-animation 0.5s infinite; display: inline-block; diff --git a/monkey/monkey_island/cc/ui/src/styles/pages/MonkeyRunPage.scss b/monkey/monkey_island/cc/ui/src/styles/pages/MonkeyRunPage.scss index 56f6cdb15..5114d0e21 100644 --- a/monkey/monkey_island/cc/ui/src/styles/pages/MonkeyRunPage.scss +++ b/monkey/monkey_island/cc/ui/src/styles/pages/MonkeyRunPage.scss @@ -14,3 +14,8 @@ div.run-on-os-buttons > .nav-item > .nav-link:hover{ color: $monkey-white; background-color: $monkey-alt; } + +.aws-run-button-container { + margin-top: 2em; + text-align: center; +} diff --git a/monkey/monkey_island/cc/ui/webpack.config.js b/monkey/monkey_island/cc/ui/webpack.config.js index 08c2a77f3..975e914ce 100644 --- a/monkey/monkey_island/cc/ui/webpack.config.js +++ b/monkey/monkey_island/cc/ui/webpack.config.js @@ -71,6 +71,7 @@ module.exports = { publicPath: '/' }, devServer: { + host: '0.0.0.0', proxy: { '/api': { target: 'https://localhost:5000',