forked from p15670423/monkey
Refactoring file upload UI -> server to be via filepond
This commit is contained in:
parent
4292fc845b
commit
a51d7da1f9
|
@ -29,6 +29,7 @@ from cc.resources.telemetry import Telemetry
|
||||||
from cc.resources.telemetry_feed import TelemetryFeed
|
from cc.resources.telemetry_feed import TelemetryFeed
|
||||||
from cc.resources.pba_file_download import PBAFileDownload
|
from cc.resources.pba_file_download import PBAFileDownload
|
||||||
from cc.services.config import ConfigService
|
from cc.services.config import ConfigService
|
||||||
|
from cc.resources.file_upload import FileUpload
|
||||||
|
|
||||||
__author__ = 'Barak'
|
__author__ = 'Barak'
|
||||||
|
|
||||||
|
@ -118,6 +119,7 @@ def init_app(mongo_url):
|
||||||
api.add_resource(Log, '/api/log', '/api/log/')
|
api.add_resource(Log, '/api/log', '/api/log/')
|
||||||
api.add_resource(IslandLog, '/api/log/island/download', '/api/log/island/download/')
|
api.add_resource(IslandLog, '/api/log/island/download', '/api/log/island/download/')
|
||||||
api.add_resource(PBAFileDownload, '/api/pba/download/<string:path>')
|
api.add_resource(PBAFileDownload, '/api/pba/download/<string:path>')
|
||||||
|
api.add_resource(FileUpload, '/api/fileUpload/<string:file_type>')
|
||||||
api.add_resource(RemoteRun, '/api/remote-monkey', '/api/remote-monkey/')
|
api.add_resource(RemoteRun, '/api/remote-monkey', '/api/remote-monkey/')
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import flask_restful
|
||||||
|
from flask import request, send_from_directory
|
||||||
|
from cc.services.config import ConfigService
|
||||||
|
import os
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
|
UPLOADS_DIR = "./monkey_island/cc/userUploads"
|
||||||
|
|
||||||
|
|
||||||
|
class FileUpload(flask_restful.Resource):
|
||||||
|
# Used by monkey. can't secure.
|
||||||
|
def get(self, path):
|
||||||
|
return send_from_directory(UPLOADS_DIR, path)
|
||||||
|
|
||||||
|
def post(self, file_type):
|
||||||
|
if file_type == 'PBAlinux':
|
||||||
|
config = ConfigService.get_config()
|
||||||
|
file_info = ConfigService.get_config_value(['monkey', 'behaviour', 'custom_post_breach', 'linux_file_info'])
|
||||||
|
filename = secure_filename(request.files['filepond'].filename)
|
||||||
|
file_path = os.path.join(UPLOADS_DIR, filename)
|
||||||
|
request.files['filepond'].save(file_path)
|
||||||
|
file_size = os.path.getsize(file_path)
|
||||||
|
# config['monkey']['behaviour']['cutom_post_breach']['linux_file_info']['size'] = file_size
|
||||||
|
# config['monkey']['behaviour']['cutom_post_breach']['linux_file_info']['name'] = filename
|
||||||
|
# ConfigService.update_config(config, True)
|
||||||
|
|
||||||
|
|
||||||
|
elif file_type == 'PBAwindows':
|
||||||
|
request.files['filepond'].save("./useless.file")
|
|
@ -70,11 +70,13 @@ class ConfigService:
|
||||||
:param is_initial_config: If True, returns the value of the initial config instead of the current config.
|
:param is_initial_config: If True, returns the value of the initial config instead of the current config.
|
||||||
:param should_decrypt: If True, the value of the config key will be decrypted
|
:param should_decrypt: If True, the value of the config key will be decrypted
|
||||||
(if it's in the list of encrypted config values).
|
(if it's in the list of encrypted config values).
|
||||||
:return: The value of the requested config key.
|
:return: The value of the requested config key or False, if such key doesn't exist.
|
||||||
"""
|
"""
|
||||||
config_key = functools.reduce(lambda x, y: x + '.' + y, config_key_as_arr)
|
config_key = functools.reduce(lambda x, y: x + '.' + y, config_key_as_arr)
|
||||||
config = mongo.db.config.find_one({'name': 'initial' if is_initial_config else 'newconfig'}, {config_key: 1})
|
config = mongo.db.config.find_one({'name': 'initial' if is_initial_config else 'newconfig'}, {config_key: 1})
|
||||||
for config_key_part in config_key_as_arr:
|
for config_key_part in config_key_as_arr:
|
||||||
|
if config_key_part not in config:
|
||||||
|
return False
|
||||||
config = config[config_key_part]
|
config = config[config_key_part]
|
||||||
if should_decrypt:
|
if should_decrypt:
|
||||||
if config_key_as_arr in ENCRYPTED_CONFIG_ARRAYS:
|
if config_key_as_arr in ENCRYPTED_CONFIG_ARRAYS:
|
||||||
|
@ -142,8 +144,6 @@ class ConfigService:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_config(config_json, should_encrypt):
|
def update_config(config_json, should_encrypt):
|
||||||
if 'custom_post_breach' in config_json['monkey']['behaviour']:
|
|
||||||
ConfigService.add_PBA_files(config_json['monkey']['behaviour']['custom_post_breach'])
|
|
||||||
if should_encrypt:
|
if should_encrypt:
|
||||||
try:
|
try:
|
||||||
ConfigService.encrypt_config(config_json)
|
ConfigService.encrypt_config(config_json)
|
||||||
|
@ -211,13 +211,7 @@ class ConfigService:
|
||||||
if instance != {}:
|
if instance != {}:
|
||||||
return
|
return
|
||||||
for property, subschema in properties.iteritems():
|
for property, subschema in properties.iteritems():
|
||||||
main_dict = {}
|
main_dict = ConfigService.r_get_properties(subschema)
|
||||||
for property2, subschema2 in subschema["properties"].iteritems():
|
|
||||||
sub_dict = {}
|
|
||||||
for property3, subschema3 in subschema2["properties"].iteritems():
|
|
||||||
if "default" in subschema3:
|
|
||||||
sub_dict[property3] = subschema3["default"]
|
|
||||||
main_dict[property2] = sub_dict
|
|
||||||
instance.setdefault(property, main_dict)
|
instance.setdefault(property, main_dict)
|
||||||
|
|
||||||
for error in validate_properties(validator, properties, instance, schema):
|
for error in validate_properties(validator, properties, instance, schema):
|
||||||
|
@ -227,6 +221,16 @@ class ConfigService:
|
||||||
validator_class, {"properties": set_defaults},
|
validator_class, {"properties": set_defaults},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def r_get_properties(schema):
|
||||||
|
if "default" in schema:
|
||||||
|
return schema["default"]
|
||||||
|
if "properties" in schema:
|
||||||
|
dict_ = {}
|
||||||
|
for property, subschema in schema["properties"].iteritems():
|
||||||
|
dict_[property] = ConfigService.r_get_properties(subschema)
|
||||||
|
return dict_
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def decrypt_config(config):
|
def decrypt_config(config):
|
||||||
ConfigService._encrypt_or_decrypt_config(config, True)
|
ConfigService._encrypt_or_decrypt_config(config, True)
|
||||||
|
@ -312,12 +316,14 @@ class ConfigService:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove_PBA_files():
|
def remove_PBA_files():
|
||||||
# Remove PBA files
|
if ConfigService.get_config():
|
||||||
current_config = ConfigService.get_config()
|
linux_file_name = ConfigService.get_config_value(
|
||||||
if current_config:
|
['monkey', 'behaviour', 'custom_post_breach', 'linux_file_info', 'name'])
|
||||||
linux_file_name = ConfigService.get_config_value(['monkey', 'behaviour', 'custom_post_breach', 'linux_file_info', 'name'])
|
windows_file_name = ConfigService.get_config_value(
|
||||||
windows_file_name = ConfigService.get_config_value(['monkey', 'behaviour', 'custom_post_breach', 'windows_file_info', 'name'])
|
['monkey', 'behaviour', 'custom_post_breach', 'windows_file_info', 'name'])
|
||||||
|
if linux_file_name:
|
||||||
ConfigService.remove_file(linux_file_name)
|
ConfigService.remove_file(linux_file_name)
|
||||||
|
if windows_file_name:
|
||||||
ConfigService.remove_file(windows_file_name)
|
ConfigService.remove_file(windows_file_name)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -375,8 +375,6 @@ SCHEMA = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": [
|
|
||||||
],
|
|
||||||
"description": "List of actions the Monkey will run post breach"
|
"description": "List of actions the Monkey will run post breach"
|
||||||
},
|
},
|
||||||
"self_delete_in_cleanup": {
|
"self_delete_in_cleanup": {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -68,6 +68,7 @@
|
||||||
"core-js": "^2.5.7",
|
"core-js": "^2.5.7",
|
||||||
"downloadjs": "^1.4.7",
|
"downloadjs": "^1.4.7",
|
||||||
"fetch": "^1.1.0",
|
"fetch": "^1.1.0",
|
||||||
|
"filepond": "^4.2.0",
|
||||||
"js-file-download": "^0.4.4",
|
"js-file-download": "^0.4.4",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"jwt-decode": "^2.2.0",
|
"jwt-decode": "^2.2.0",
|
||||||
|
@ -83,6 +84,7 @@
|
||||||
"react-dimensions": "^1.3.0",
|
"react-dimensions": "^1.3.0",
|
||||||
"react-dom": "^16.5.2",
|
"react-dom": "^16.5.2",
|
||||||
"react-fa": "^5.0.0",
|
"react-fa": "^5.0.0",
|
||||||
|
"react-filepond": "^7.0.1",
|
||||||
"react-graph-vis": "^1.0.2",
|
"react-graph-vis": "^1.0.2",
|
||||||
"react-json-tree": "^0.11.0",
|
"react-json-tree": "^0.11.0",
|
||||||
"react-jsonschema-form": "^1.0.5",
|
"react-jsonschema-form": "^1.0.5",
|
||||||
|
|
|
@ -3,6 +3,8 @@ import Form from 'react-jsonschema-form';
|
||||||
import {Col, Nav, NavItem} from 'react-bootstrap';
|
import {Col, Nav, NavItem} from 'react-bootstrap';
|
||||||
import fileDownload from 'js-file-download';
|
import fileDownload from 'js-file-download';
|
||||||
import AuthComponent from '../AuthComponent';
|
import AuthComponent from '../AuthComponent';
|
||||||
|
import { FilePond, registerPlugin } from 'react-filepond';
|
||||||
|
import 'filepond/dist/filepond.min.css';
|
||||||
|
|
||||||
class ConfigurePageComponent extends AuthComponent {
|
class ConfigurePageComponent extends AuthComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -59,16 +61,6 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
})
|
})
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => {
|
.then(res => {
|
||||||
// Leave PBA files on external configuration
|
|
||||||
if ('linux_file' in this.state.configuration.monkey.behaviour.custom_post_breach){
|
|
||||||
let linux_file = this.state.configuration.monkey.behaviour.custom_post_breach.linux_file;
|
|
||||||
res.configuration.monkey.behaviour.custom_post_breach.windows_file = linux_file;
|
|
||||||
}
|
|
||||||
if ('windows_file' in this.state.configuration.monkey.behaviour.custom_post_breach){
|
|
||||||
let windows_file = this.state.configuration.monkey.behaviour.custom_post_breach.windows_file;
|
|
||||||
res.configuration.monkey.behaviour.custom_post_breach.linux_file = windows_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
lastAction: 'saved',
|
lastAction: 'saved',
|
||||||
schema: res.schema,
|
schema: res.schema,
|
||||||
|
@ -160,6 +152,15 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PBAwindows = () => {
|
||||||
|
return (<FilePond server='/api/fileUpload/PBAwindows'/>)
|
||||||
|
};
|
||||||
|
|
||||||
|
PBAlinux = () => {
|
||||||
|
return (<FilePond server='/api/fileUpload/PBAlinux'/>)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let displayedSchema = {};
|
let displayedSchema = {};
|
||||||
const uiSchema = {
|
const uiSchema = {
|
||||||
|
@ -168,8 +169,14 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
linux: {
|
linux: {
|
||||||
"ui:widget": "textarea"
|
"ui:widget": "textarea"
|
||||||
},
|
},
|
||||||
|
linux_file: {
|
||||||
|
"ui:widget": this.PBAlinux
|
||||||
|
},
|
||||||
windows: {
|
windows: {
|
||||||
"ui:widget": "textarea"
|
"ui:widget": "textarea"
|
||||||
|
},
|
||||||
|
windows_file: {
|
||||||
|
"ui:widget": this.PBAwindows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import ReactDOM from 'react-dom';
|
||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
import App from './components/Main';
|
import App from './components/Main';
|
||||||
import Bootstrap from 'bootstrap/dist/css/bootstrap.css'; // eslint-disable-line no-unused-vars
|
import Bootstrap from 'bootstrap/dist/css/bootstrap.css'; // eslint-disable-line no-unused-vars
|
||||||
|
import { FilePond, registerPlugin } from 'react-filepond';
|
||||||
|
import 'filepond/dist/filepond.min.css';
|
||||||
|
|
||||||
// Render the main component into the dom
|
// Render the main component into the dom
|
||||||
ReactDOM.render(<App />, document.getElementById('app'));
|
ReactDOM.render(<App />, document.getElementById('app'));
|
||||||
|
|
Loading…
Reference in New Issue