diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 2c778e61b..f2c0e9ce1 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -124,7 +124,11 @@ def init_api_resources(api): api.add_resource(Node, '/api/netmap/node', '/api/netmap/node/') # report_type: zero_trust or general - api.add_resource(Report, '/api/report/') + api.add_resource( + Report, + '/api/report/', + '/api/report//') + api.add_resource(TelemetryFeed, '/api/telemetry-feed', '/api/telemetry-feed/') api.add_resource(Log, '/api/log', '/api/log/') api.add_resource(IslandLog, '/api/log/island/download', '/api/log/island/download/') diff --git a/monkey/monkey_island/cc/resources/reporting/report.py b/monkey/monkey_island/cc/resources/reporting/report.py index 3fe8f0fd9..8ae1d8769 100644 --- a/monkey/monkey_island/cc/resources/reporting/report.py +++ b/monkey/monkey_island/cc/resources/reporting/report.py @@ -10,50 +10,129 @@ ZERO_TRUST_REPORT_TYPE = "zero_trust" GENERAL_REPORT_TYPE = "general" REPORT_TYPES = [GENERAL_REPORT_TYPE, ZERO_TRUST_REPORT_TYPE] +REPORT_DATA_PILLARS = "pillars" +REPORT_DATA_FINDINGS = "findings" +REPORT_DATA_TEST_STATUS = "tests" + __author__ = ["itay.mizeretz", "shay.nehmad"] class Report(flask_restful.Resource): @jwt_required() - def get(self, report_type): + def get(self, report_type=GENERAL_REPORT_TYPE, report_data=None): if report_type == GENERAL_REPORT_TYPE: return ReportService.get_report() elif report_type == ZERO_TRUST_REPORT_TYPE: - fakedict = { - "are_all_monkeys_done": False, - "findings": [ - { - "test": "Monkey 8 found a machine with no AV software active.", - "conclusive": False, - "pillars": ["Devices"], - "events": [ - { - "timestamp": "2019-08-01 14:48:46.112000", - "title": "Monkey performed an action", - "type": "MonkeyAction", - "message": "log1" - }, { - "timestamp": "2019-08-01 14:48:42.112000", - "title": "Analysis", - "type": "IslandAction", - "message": "log2" - }] - }, - { - "test": "Monkey 6 successfully exploited machine XXX with shellshock.", - "conclusive": True, - "pillars": ["Devices", "Networks"], - "events": [ - { - "timestamp": "2019-08-01 14:48:46.112000", - "title": "Analysis", - "type": "MonkeyAction", - "message": "log3" - }] - } - ] - } - return jsonify(fakedict) + if report_data == REPORT_DATA_FINDINGS: + return jsonify(get_all_findings()) + elif report_data == REPORT_DATA_PILLARS: + return jsonify(get_pillars_grades()) + elif report_data == REPORT_DATA_TEST_STATUS: + return jsonify(get_tests_status()) flask_restful.abort(httplib.NOT_FOUND) + + +def get_all_findings(): + return [ + { + "test": "Monkey 8 found a machine with no AV software active.", + "conclusive": False, + "pillars": ["Devices"], + "events": [ + { + "timestamp": "2019-08-01 14:48:46.112000", + "title": "Monkey performed an action", + "type": "MonkeyAction", + "message": "log1" + }, { + "timestamp": "2019-08-01 14:48:42.112000", + "title": "Analysis", + "type": "IslandAction", + "message": "log2" + }] + }, + { + "test": "Monkey 6 successfully exploited machine XXX with shellshock.", + "conclusive": True, + "pillars": ["Devices", "Networks"], + "events": [ + { + "timestamp": "2019-08-01 14:48:46.112000", + "title": "Analysis", + "type": "MonkeyAction", + "message": "log3" + }] + } + ] + + +def get_tests_status(): + return [ + { + "Test": "Segmentation", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": False # There were results meaning the test was executed. + }, + { + "Exploit": "network", + "Unexecuted": True # There were no results since the test wasn't executed. + }, + ] + + +def get_pillars_grades(): + return [ + { + "Pillar": "data", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": 6 + }, + { + "Pillar": "network", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": 6 + }, + { + "Pillar": "people", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": 6 + }, + { + "Pillar": "workloads", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": 6 + }, + { + "Pillar": "devices", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": 6 + }, + { + "Pillar": "visibility and analytics", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": 6 + }, + { + "Pillar": "automation and analytics", + "Conclusive": 6, + "Inconclusive": 6, + "Positive": 6, + "Unexecuted": 6 + }, + ] diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js index ec90b625f..9d200beac 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js @@ -11,9 +11,6 @@ class ZeroTrustReportPageComponent extends AuthComponent { super(props); this.state = { - report: { - findings: undefined - }, allMonkeysAreDead: false, runStarted: false }; @@ -38,14 +35,16 @@ class ZeroTrustReportPageComponent extends AuthComponent { generateReportContent() { let content; - if (typeof this.state.report.findings === "undefined") { + if (typeof this.state.findings === "undefined") { content = "Still empty"; } else { content =

Pillars Overview

- + +

Test Status

+ TODO

Findings

- +
; } @@ -63,9 +62,15 @@ class ZeroTrustReportPageComponent extends AuthComponent { {content}
THIS IS THE RAW SERVER DATA -
-            {JSON.stringify(this.state.report, undefined, 2)}
-          
+
+ PILLARS: +
{JSON.stringify(this.state.pillars, undefined, 2)}
+
+ TESTS: +
{JSON.stringify(this.state.tests, undefined, 2)}
+
+ FINDINGS: +
{JSON.stringify(this.state.findings, undefined, 2)}
) @@ -76,11 +81,26 @@ class ZeroTrustReportPageComponent extends AuthComponent { } getZeroTrustReportFromServer() { - this.authFetch('/api/report/zero_trust') + let res; + this.authFetch('/api/report/zero_trust/findings') .then(res => res.json()) .then(res => { this.setState({ - report: res + findings: res + }); + }); + this.authFetch('/api/report/zero_trust/tests') + .then(res => res.json()) + .then(res => { + this.setState({ + tests: res + }); + }); + this.authFetch('/api/report/zero_trust/pillars') + .then(res => res.json()) + .then(res => { + this.setState({ + pillars: res }); }); } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/FindingsTable.js b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/FindingsTable.js index 3b7842b26..863d08670 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/FindingsTable.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/FindingsTable.js @@ -63,7 +63,7 @@ const columns = [ const listItems = pillars.map((pillar) =>
  • ); - return
      {listItems}
    + return
      {listItems}
    ; } }, { Header: 'Events', id:"events", @@ -79,19 +79,22 @@ const pageSize = 10; class FindingsTable extends Component { render() { - let defaultPageSize = this.props.findings.length > pageSize ? pageSize : this.props.findings.length; - let showPagination = this.props.findings.length > pageSize; + if (this.props.findings.length > 0) { + let defaultPageSize = this.props.findings.length > pageSize ? pageSize : this.props.findings.length; + let showPagination = this.props.findings.length > pageSize; - return ( -
    - -
    - ); + return ( +
    + +
    + ); + } + else { return (
    BAYAZ
    );} } } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarGrades.js b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarGrades.js index 6afe2dd52..8c3959b00 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarGrades.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarGrades.js @@ -3,37 +3,13 @@ import ZeroTrustPillars from "./ZeroTrustPillars"; export class PillarGrades extends Component { render() { - let pillarsCounters = {}; - for(const pillar in ZeroTrustPillars) { - pillarsCounters[ZeroTrustPillars[pillar]] = { - "conclusive": 0, - "possible": 0 - }; - } - - if (this.props.findings !== null) { - for (const finding of this.props.findings) { - if (typeof finding === 'object' && finding !== null) { - if (finding.hasOwnProperty("pillars") && finding.hasOwnProperty("conclusive")) { - for (const pillar of finding["pillars"]) { - if (finding.conclusive) { - pillarsCounters[pillar]["conclusive"] += 1; - } else { - pillarsCounters[pillar]["possible"] += 1; - } - } - } - } - } - } - return (

    TODO: table with conditional colouring.

    -          {JSON.stringify(pillarsCounters, undefined, 2)}
    +          {JSON.stringify(this.props.pillars, undefined, 2)}
             
    )