diff --git a/monkey/monkey_island/cc/resources/agent_configuration.py b/monkey/monkey_island/cc/resources/agent_configuration.py
index 0f9279bba..47be16abc 100644
--- a/monkey/monkey_island/cc/resources/agent_configuration.py
+++ b/monkey/monkey_island/cc/resources/agent_configuration.py
@@ -24,7 +24,7 @@ class AgentConfiguration(AbstractResource):
@jwt_required
def post(self):
try:
- configuration_object = AgentConfigurationObject.from_json(request.data)
+ configuration_object = AgentConfigurationObject.from_mapping(request.json)
self._agent_configuration_repository.store_configuration(configuration_object)
return make_response({}, 200)
except (InvalidConfigurationError, json.JSONDecodeError) as err:
diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/ExportConfigModal.tsx b/monkey/monkey_island/cc/ui/src/components/configuration-components/ExportConfigModal.tsx
index 469d91ec3..ef11dd67f 100644
--- a/monkey/monkey_island/cc/ui/src/components/configuration-components/ExportConfigModal.tsx
+++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/ExportConfigModal.tsx
@@ -4,6 +4,7 @@ import React, {useState} from 'react';
import FileSaver from 'file-saver';
import '../../styles/components/configuration-components/ExportConfigModal.scss';
import {encryptText} from '../utils/PasswordBasedEncryptor';
+import {reformatConfig} from './ReformatHook';
type Props = {
@@ -21,7 +22,7 @@ const ConfigExportModal = (props: Props) => {
}
function onSubmit() {
- let config = props.configuration;
+ let config = reformatConfig(props.configuration, true);
let config_export = {'metadata': {}, 'contents': null};
if (radioValue === 'password') {
diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/ImportConfigModal.tsx b/monkey/monkey_island/cc/ui/src/components/configuration-components/ImportConfigModal.tsx
index a60a25c0f..cce66a521 100644
--- a/monkey/monkey_island/cc/ui/src/components/configuration-components/ImportConfigModal.tsx
+++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/ImportConfigModal.tsx
@@ -20,8 +20,7 @@ type Props = {
const ConfigImportModal = (props: Props) => {
- // TODO: change this endpoint to the new configuration import endpoint
- const configImportEndpoint = '/api/configuration/import';
+ const configImportEndpoint = '/api/agent-configuration';
const [uploadStatus, setUploadStatus] = useState(UploadStatuses.clean);
const [configContents, setConfigContents] = useState(null);
@@ -71,18 +70,15 @@ const ConfigImportModal = (props: Props) => {
{
method: 'POST',
headers: {'Content-Type': 'application/json'},
- body: JSON.stringify({
- config: configContents,
- })
+ body: JSON.stringify(configContents)
}
- ).then(res => res.json())
- .then(res => {
- if (res['import_status'] === 'invalid_configuration') {
- setUploadStatus(UploadStatuses.error);
- setErrorMessage(res['message']);
- } else if (res['import_status'] === 'imported') {
+ ).then(res => {
+ if (res.ok) {
resetState();
props.onClose(true);
+ } else {
+ setUploadStatus(UploadStatuses.error);
+ setErrorMessage("Configuration file is corrupt or in an outdated format.");
}
})
}
diff --git a/monkey/monkey_island/cc/ui/src/components/configuration-components/ReformatHook.js b/monkey/monkey_island/cc/ui/src/components/configuration-components/ReformatHook.js
new file mode 100644
index 000000000..322882194
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/components/configuration-components/ReformatHook.js
@@ -0,0 +1,8 @@
+export function reformatConfig(config, reverse = false) {
+ if (reverse) {
+ config['payloads'] = [{'name': 'ransomware', 'options': config['payloads']}]
+ } else {
+ config['payloads'] = config['payloads'][0]['options'];
+ }
+ return config;
+ }
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 8bcad002b..154eff52c 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/ConfigurePage.js
@@ -1,6 +1,6 @@
import React from 'react';
import Form from 'react-jsonschema-form-bs4';
-import {Button, Col, Modal, Nav} from 'react-bootstrap';
+import {Col, Nav} from 'react-bootstrap';
import AuthComponent from '../AuthComponent';
import UiSchema from '../configuration-components/UiSchema';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
@@ -10,7 +10,6 @@ import {formValidationFormats} from '../configuration-components/ValidationForma
import transformErrors from '../configuration-components/ValidationErrorMessages';
import UnsafeConfigOptionsConfirmationModal
from '../configuration-components/UnsafeConfigOptionsConfirmationModal.js';
-import UnsafeOptionsWarningModal from '../configuration-components/UnsafeOptionsWarningModal.js';
import isUnsafeOptionSelected from '../utils/SafeOptionValidator.js';
import ConfigExportModal from '../configuration-components/ExportConfigModal';
import ConfigImportModal from '../configuration-components/ImportConfigModal';
@@ -18,8 +17,10 @@ import applyUiSchemaManipulators from '../configuration-components/UISchemaManip
import HtmlFieldDescription from '../configuration-components/HtmlFieldDescription.js';
import CONFIGURATION_TABS_PER_MODE from '../configuration-components/ConfigurationTabs.js';
import {SCHEMA} from '../../services/configuration/config_schema.js';
+import {reformatConfig} from '../configuration-components/ReformatHook';
-const CONFIG_URL = '/api/configuration/island';
+const CONFIG_URL = '/api/agent-configuration';
+const RESET_URL = '/api/reset-agent-configuration';
export const API_PBA_LINUX = '/api/file-upload/PBAlinux';
export const API_PBA_WINDOWS = '/api/file-upload/PBAwindows';
@@ -42,9 +43,7 @@ class ConfigurePageComponent extends AuthComponent {
schema: {},
sections: [],
selectedSection: this.currentSection,
- showUnsubmittedConfigWarning: false,
showUnsafeOptionsConfirmation: false,
- showUnsafeAttackOptionsWarning: false,
showConfigExportModal: false,
showConfigImportModal: false
};
@@ -57,8 +56,13 @@ class ConfigurePageComponent extends AuthComponent {
}
}
+ resetLastAction = () => {
+ this.setState({lastAction: 'none'});
+ }
+
getSectionsOrder() {
- let islandMode = this.props.islandMode !== 'unset' ? this.props.islandMode : 'advanced'
+ let islandModeSet = (this.props.islandMode !== 'unset' && this.props.islandMode !== undefined)
+ let islandMode = islandModeSet ? this.props.islandMode : 'advanced'
return CONFIGURATION_TABS_PER_MODE[islandMode];
}
@@ -68,14 +72,10 @@ class ConfigurePageComponent extends AuthComponent {
}
componentDidMount = () => {
- let urls = ['/api/agent-configuration'];
- // ??? Why fetch config here and not in `render()`?
- Promise.all(urls.map(url => this.authFetch(url).then(res => res.json())))
- .then(data => {
+ this.authFetch(CONFIG_URL).then(res => res.json())
+ .then(monkeyConfig => {
let sections = [];
- let monkeyConfig = data[0];
- // TODO: Fix when we add plugins
- monkeyConfig['payloads'] = monkeyConfig['payloads'][0]['options'];
+ monkeyConfig = reformatConfig(monkeyConfig);
this.setInitialConfig(monkeyConfig);
for (let sectionKey of this.getSectionsOrder()) {
@@ -108,17 +108,16 @@ class ConfigurePageComponent extends AuthComponent {
}
}
- onUnsafeAttackContinueClick = () => {
- this.setState({showUnsafeAttackOptionsWarning: false});
- }
-
- updateConfig = (callback = null) => {
+ updateConfig = () => {
this.authFetch(CONFIG_URL)
.then(res => res.json())
.then(data => {
- this.setInitialConfig(data.configuration);
- this.setState({configuration: data.configuration,
- currentFormData: data.configuration[this.state.selectedSection]}, callback);
+ data = reformatConfig(data);
+ this.setInitialConfig(data);
+ this.setState({
+ configuration: data,
+ currentFormData: data[this.state.selectedSection]
+ });
})
};
@@ -134,7 +133,7 @@ class ConfigurePageComponent extends AuthComponent {
await this.updateConfigSection();
if (this.canSafelySubmitConfig(this.state.configuration)) {
this.configSubmit();
- if(this.state.lastAction === configExportAction){
+ if (this.state.lastAction === configExportAction) {
this.setState({showConfigExportModal: true})
}
} else {
@@ -145,18 +144,16 @@ class ConfigurePageComponent extends AuthComponent {
configSubmit() {
return this.sendConfig()
.then(res => res.json())
- .then(res => {
+ .then(() => {
this.setState({
- lastAction: configSaveAction,
- schema: res.schema,
- configuration: res.configuration
+ lastAction: configSaveAction
});
- this.setInitialConfig(res.configuration);
+ this.setInitialConfig(this.state.configuration);
this.props.onStatusChange();
}).catch(error => {
- console.log('Bad configuration: ' + error.toString());
- this.setState({lastAction: 'invalid_configuration'});
- });
+ console.log('Bad configuration: ' + error.toString());
+ this.setState({lastAction: 'invalid_configuration'});
+ });
}
onChange = ({formData}) => {
@@ -189,42 +186,18 @@ class ConfigurePageComponent extends AuthComponent {
}
onClose = (importSuccessful) => {
- if(importSuccessful === true){
+ if (importSuccessful === true) {
this.updateConfig();
- this.setState({lastAction: 'import_success',
- showConfigImportModal: false});
+ this.setState({
+ lastAction: 'import_success',
+ showConfigImportModal: false
+ });
} else {
this.setState({showConfigImportModal: false});
}
}
- renderAttackAlertModal = () => {
- return (
- You have unsubmitted changes. Submit them before proceeding.
-
-
-