diff --git a/monkey/monkey_island/cc/ui/src/components/attack/ConfigMatrixComponent.js b/monkey/monkey_island/cc/ui/src/components/attack/ConfigMatrixComponent.js deleted file mode 100644 index ff9a11766..000000000 --- a/monkey/monkey_island/cc/ui/src/components/attack/ConfigMatrixComponent.js +++ /dev/null @@ -1,123 +0,0 @@ -import React from 'react'; -import Checkbox from '../ui-components/Checkbox' -import Tooltip from 'react-tooltip-lite' -import AuthComponent from '../AuthComponent'; -import ReactTable from 'react-table'; -import 'filepond/dist/filepond.min.css'; -import '../../styles/components/Tooltip.scss'; -import {Col} from 'react-bootstrap'; - -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCircle as faCircle } from '@fortawesome/free-solid-svg-icons/faCircle'; -import { faCircle as faCircleThin } from '@fortawesome/free-regular-svg-icons/faCircle'; - -class ConfigMatrixComponent extends AuthComponent { - constructor(props) { - super(props); - this.state = {lastAction: 'none'} - } - - // Finds which attack type has most techniques and returns that number - static findMaxTechniques(data) { - let maxLen = 0; - data.forEach(function (techType) { - if (Object.keys(techType.properties).length > maxLen) { - maxLen = Object.keys(techType.properties).length - } - }); - return maxLen - } - - // Parses ATT&CK config schema into data suitable for react-table (ATT&CK matrix) - static parseTechniques(data, maxLen) { - let techniques = []; - // Create rows with attack techniques - for (let i = 0; i < maxLen; i++) { - let row = {}; - data.forEach(function (techType) { - let rowColumn = {}; - rowColumn.techName = techType.title; - - if (i <= Object.keys(techType.properties).length) { - rowColumn.technique = Object.values(techType.properties)[i]; - if (rowColumn.technique) { - rowColumn.technique.name = Object.keys(techType.properties)[i]; - } - } else { - rowColumn.technique = null; - } - row[rowColumn.techName] = rowColumn; - }); - techniques.push(row) - } - return techniques; - } - - getColumns(matrixData) { - return Object.keys(matrixData[0]).map((key) => { - return { - Header: key, - id: key, - accessor: x => this.renderTechnique(x[key].technique), - style: {'whiteSpace': 'unset'} - }; - }); - } - - renderTechnique(technique) { - if (technique == null) { - return (
) - } else { - return ( - - {technique.title} - - ) - } - } - - getTableData = (config) => { - let configCopy = JSON.parse(JSON.stringify(config)); - let maxTechniques = ConfigMatrixComponent.findMaxTechniques(Object.values(configCopy)); - let matrixTableData = ConfigMatrixComponent.parseTechniques(Object.values(configCopy), maxTechniques); - let columns = this.getColumns(matrixTableData); - return {'columns': columns, 'matrixTableData': matrixTableData, 'maxTechniques': maxTechniques} - }; - - renderLegend = () => { - return ( - ) - }; - - render() { - let tableData = this.getTableData(this.props.configuration); - return ( -
- {this.renderLegend()} -
- -
-
); - } -} - -export default ConfigMatrixComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js index 7701959cf..f6057dd6e 100644 --- a/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js +++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/ConfigurationTabs.js @@ -1,5 +1,4 @@ const CONFIGURATION_TABS = { - ATTACK: 'attack', BASIC: 'basic', BASIC_NETWORK: 'basic_network', RANSOMWARE: 'ransomware', @@ -8,7 +7,6 @@ const CONFIGURATION_TABS = { }; const advancedModeConfigTabs = [ - CONFIGURATION_TABS.ATTACK, CONFIGURATION_TABS.BASIC, CONFIGURATION_TABS.BASIC_NETWORK, CONFIGURATION_TABS.RANSOMWARE, diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index f23df62e6..4650aec07 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -2,7 +2,6 @@ import React from 'react'; import Form from 'react-jsonschema-form-bs4'; import {Button, Col, Modal, Nav} from 'react-bootstrap'; import AuthComponent from '../AuthComponent'; -import ConfigMatrixComponent from '../attack/ConfigMatrixComponent'; import UiSchema from '../configuration-components/UiSchema'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'; @@ -20,7 +19,6 @@ import applyUiSchemaManipulators from '../configuration-components/UISchemaManip import HtmlFieldDescription from '../configuration-components/HtmlFieldDescription.js'; import CONFIGURATION_TABS_PER_MODE from '../configuration-components/ConfigurationTabs.js'; -const ATTACK_URL = '/api/attack'; const CONFIG_URL = '/api/configuration/island'; export const API_PBA_LINUX = '/api/fileUpload/PBAlinux'; export const API_PBA_WINDOWS = '/api/fileUpload/PBAwindows'; @@ -30,11 +28,9 @@ class ConfigurePageComponent extends AuthComponent { constructor(props) { super(props); this.initialConfig = {}; - this.initialAttackConfig = {}; this.currentSection = this.getSectionsOrder()[0]; this.state = { - attackConfig: {}, configuration: {}, currentFormData: {}, importCandidateConfig: null, @@ -42,7 +38,7 @@ class ConfigurePageComponent extends AuthComponent { schema: {}, sections: [], selectedSection: this.currentSection, - showAttackAlert: false, + showUnsubmittedConfigWarning: false, showUnsafeOptionsConfirmation: false, showUnsafeAttackOptionsWarning: false, showConfigExportModal: false, @@ -64,39 +60,26 @@ class ConfigurePageComponent extends AuthComponent { setInitialConfig(config) { // Sets a reference to know if config was changed - config['attack'] = {} this.initialConfig = JSON.parse(JSON.stringify(config)); } - setInitialAttackConfig(attackConfig) { - // Sets a reference to know if attack config was changed - this.initialAttackConfig = JSON.parse(JSON.stringify(attackConfig)); - } - componentDidMount = () => { - let urls = [CONFIG_URL, ATTACK_URL]; + let urls = [CONFIG_URL]; // ??? Why fetch config here and not in `render()`? Promise.all(urls.map(url => this.authFetch(url).then(res => res.json()))) .then(data => { let sections = []; - let attackConfig = data[1]; let monkeyConfig = data[0]; this.setInitialConfig(monkeyConfig.configuration); - this.setInitialAttackConfig(attackConfig.configuration); for (let sectionKey of this.getSectionsOrder()) { - if (sectionKey === 'attack') { - sections.push({key: sectionKey, title: 'ATT&CK'}) - } else { - sections.push({ - key: sectionKey, - title: monkeyConfig.schema.properties[sectionKey].title - }); - } + sections.push({ + key: sectionKey, + title: monkeyConfig.schema.properties[sectionKey].title + }); } this.setState({ schema: monkeyConfig.schema, configuration: monkeyConfig.configuration, - attackConfig: attackConfig.configuration, sections: sections, currentFormData: monkeyConfig.configuration[this.state.selectedSection] }) @@ -130,42 +113,13 @@ class ConfigurePageComponent extends AuthComponent { }; onSubmit = () => { - if (this.state.selectedSection === 'attack') { - this.matrixSubmit(); - } else { - this.attemptConfigSubmit(); - } + this.attemptConfigSubmit(); }; canSafelySubmitConfig(config) { return !isUnsafeOptionSelected(this.state.schema, config); } - matrixSubmit = () => { - // Submit attack matrix - this.authFetch(ATTACK_URL, - { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(this.state.attackConfig) - }) - .then(res => { - if (!res.ok) { - throw Error() - } - return res; - }) - .then(() => { - this.setInitialAttackConfig(this.state.attackConfig); - }) - .then(() => this.updateConfig(this.checkAndShowUnsafeAttackWarning)) - .then(() => this.setState({lastAction: 'saved'})) - .catch(error => { - console.log('Bad configuration: ' + error.toString()); - this.setState({lastAction: 'invalid_configuration'}); - }); - }; - checkAndShowUnsafeAttackWarning = () => { if (isUnsafeOptionSelected(this.state.schema, this.state.configuration)) { this.setState({showUnsafeAttackOptionsWarning: true}); @@ -201,38 +155,8 @@ class ConfigurePageComponent extends AuthComponent { }); } - // Alters attack configuration when user toggles technique - attackTechniqueChange = (technique, value, mapped = false) => { - // Change value in attack configuration - // Go trough each column in matrix, searching for technique - Object.entries(this.state.attackConfig).forEach(techType => { - if (Object.prototype.hasOwnProperty.call(techType[1].properties, technique)) { - let tempMatrix = this.state.attackConfig; - tempMatrix[techType[0]].properties[technique].value = value; - this.setState({attackConfig: tempMatrix}); - - // Toggle all mapped techniques - if (!mapped) { - // Loop trough each column and each row - Object.entries(this.state.attackConfig).forEach(otherType => { - Object.entries(otherType[1].properties).forEach(otherTech => { - // If this technique depends on a technique that was changed - if (Object.prototype.hasOwnProperty.call(otherTech[1], 'depends_on') && - otherTech[1]['depends_on'].includes(technique)) { - this.attackTechniqueChange(otherTech[0], value, true) - } - }) - }); - } - } - }); - }; - onChange = ({formData}) => { let configuration = this.state.configuration; - if (this.state.selectedSection === 'attack'){ - formData = {}; - } configuration[this.state.selectedSection] = formData; this.setState({currentFormData: formData, configuration: configuration}); }; @@ -270,8 +194,8 @@ class ConfigurePageComponent extends AuthComponent { } renderAttackAlertModal = () => { - return ( { - this.setState({showAttackAlert: false}) + return ( { + this.setState({showUnsubmittedConfigWarning: false}) }}>

@@ -286,7 +210,7 @@ class ConfigurePageComponent extends AuthComponent { size='lg' style={{margin: '5px'}} onClick={() => { - this.setState({showAttackAlert: false}) + this.setState({showUnsubmittedConfigWarning: false}) }}> Cancel @@ -330,16 +254,13 @@ class ConfigurePageComponent extends AuthComponent { return true; } - userChangedMatrix() { - return (JSON.stringify(this.state.attackConfig) !== JSON.stringify(this.initialAttackConfig)) - } - setSelectedSection = (key) => { - if ((key === 'attack' && this.userChangedConfig()) || - (this.currentSection === 'attack' && this.userChangedMatrix())) { - this.setState({showAttackAlert: true}); - return; - } + + // TODO: Fix https://github.com/guardicore/monkey/issues/1621 + //if ( key === 'basic' & this.userChangedConfig()) { + // this.setState({showUnsubmittedConfigWarning: true}); + // return; + //} this.updateConfigSection(); this.currentSection = key; @@ -358,7 +279,6 @@ class ConfigurePageComponent extends AuthComponent { }) .then(res => res.json()) .then(res => { - res.configuration['attack'] = {} this.setState({ lastAction: 'reset', schema: res.schema, @@ -372,16 +292,6 @@ class ConfigurePageComponent extends AuthComponent { this.removePBAfile(API_PBA_WINDOWS, this.setPbaFilenameWindows) this.removePBAfile(API_PBA_LINUX, this.setPbaFilenameLinux) }); - this.authFetch(ATTACK_URL, { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify('reset_attack_matrix') - }) - .then(res => res.json()) - .then(res => { - this.setState({attackConfig: res.configuration}); - this.setInitialAttackConfig(res.configuration); - }) }; removePBAfile(apiEndpoint, setFilenameFnc) { @@ -421,13 +331,6 @@ class ConfigurePageComponent extends AuthComponent { })); } - renderMatrix = () => { - return () - }; - renderConfigContent = (displayedSchema) => { let formProperties = {}; formProperties['schema'] = displayedSchema @@ -497,15 +400,13 @@ class ConfigurePageComponent extends AuthComponent { render() { let displayedSchema = {}; - if (Object.prototype.hasOwnProperty.call(this.state.schema, 'properties') && this.state.selectedSection !== 'attack') { + if (Object.prototype.hasOwnProperty.call(this.state.schema, 'properties')) { displayedSchema = this.state.schema['properties'][this.state.selectedSection]; displayedSchema['definitions'] = this.state.schema['definitions']; } let content = ''; - if (this.state.selectedSection === 'attack' && Object.entries(this.state.attackConfig).length !== 0) { - content = this.renderMatrix() - } else if (this.state.selectedSection !== 'attack' && Object.entries(this.state.configuration).length !== 0) { + if (Object.entries(this.state.configuration).length !== 0) { content = this.renderConfigContent(displayedSchema) } return (