diff --git a/monkey_island/cc/ui/package.json b/monkey_island/cc/ui/package.json index 64d7643ce..681a98bb3 100644 --- a/monkey_island/cc/ui/package.json +++ b/monkey_island/cc/ui/package.json @@ -64,6 +64,7 @@ "bootstrap": "^3.3.7", "core-js": "^2.5.1", "fetch": "^1.1.0", + "js-file-download": "^0.4.1", "normalize.css": "^4.0.0", "prop-types": "^15.5.10", "react": "^15.6.1", diff --git a/monkey_island/cc/ui/src/components/pages/ConfigurePage.js b/monkey_island/cc/ui/src/components/pages/ConfigurePage.js index 92d6a5687..3f60ab026 100644 --- a/monkey_island/cc/ui/src/components/pages/ConfigurePage.js +++ b/monkey_island/cc/ui/src/components/pages/ConfigurePage.js @@ -1,6 +1,7 @@ import React from 'react'; import Form from 'react-jsonschema-form'; import {Col, Nav, NavItem} from 'react-bootstrap'; +import fileDownload from 'js-file-download'; class ConfigurePageComponent extends React.Component { constructor(props) { @@ -14,8 +15,7 @@ class ConfigurePageComponent extends React.Component { this.state = { schema: {}, configuration: {}, - saved: false, - reset: false, + lastAction: 'none', sections: [], selectedSection: 'basic', allMonkeysAreDead: true @@ -52,8 +52,7 @@ class ConfigurePageComponent extends React.Component { .then(res => res.json()) .then(res => { this.setState({ - saved: true, - reset: false, + lastAction: 'saved', schema: res.schema, configuration: res.configuration }); @@ -92,8 +91,7 @@ class ConfigurePageComponent extends React.Component { .then(res => res.json()) .then(res => { this.setState({ - reset: true, - saved: false, + lastAction: 'reset', schema: res.schema, configuration: res.configuration }); @@ -101,6 +99,32 @@ class ConfigurePageComponent extends React.Component { }); }; + onReadFile = (event) => { + try { + this.setState({ + configuration: JSON.parse(event.target.result), + selectedSection: 'basic', + lastAction: 'import_success' + }); + this.currentSection = 'basic'; + this.currentFormData = {}; + } catch(SyntaxError) { + this.setState({lastAction: 'import_failure'}); + } + }; + + exportConfig = () => { + this.updateConfigSection(); + fileDownload(JSON.stringify(this.state.configuration, null, 2), 'monkey.conf'); + }; + + importConfig = (event) => { + let reader = new FileReader(); + reader.onload = this.onReadFile; + reader.readAsText(event.target.files[0]); + event.target.value = null; + }; + updateMonkeysRunning = () => { fetch('/api') .then(res => res.json()) @@ -160,22 +184,45 @@ class ConfigurePageComponent extends React.Component { Reset to defaults - { this.state.reset ? -
- - Configuration reset successfully. -
- : ''} - { this.state.saved ? -
- - Configuration saved successfully. -
- : ''} : ''} - +
+ + + +
+
+ { this.state.lastAction === 'reset' ? +
+ + Configuration reset successfully. +
+ : ''} + { this.state.lastAction === 'saved' ? +
+ + Configuration saved successfully. +
+ : ''} + { this.state.lastAction === 'import_failure' ? +
+ + Failed importing configuration. Invalid config file. +
+ : ''} + { this.state.lastAction === 'import_success' ? +
+ + Configuration imported successfully. +
+ : ''} +
);