Formatting + Removed export events button from main page

This commit is contained in:
Shay Nehmad 2019-08-29 19:54:46 +03:00
parent 8136c31476
commit 85401e5d48
6 changed files with 215 additions and 136 deletions

View File

@ -100,7 +100,8 @@ TESTS_MAP = {
TEST_SCHEDULED_EXECUTION: {
TEST_EXPLANATION_KEY: "The Monkey was executed in a scheduled manner.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_INCONCLUSIVE: "Monkey was executed in a scheduled manner. Locate this activity in User-Behavior security software."
STATUS_INCONCLUSIVE: "Monkey was executed in a scheduled manner. Locate this activity in User-Behavior security software.",
STATUS_PASSED: "Monkey failed to execute in a scheduled manner."
},
RECOMMENDATION_KEY: RECOMMENDATION_USER_BEHAVIOUR,
PILLARS_KEY: [PEOPLE, NETWORKS],

View File

@ -77,7 +77,9 @@ class ZeroTrustReportPageComponent extends AuthComponent {
return (
<Fragment>
<div style={{marginBottom: '20px'}}>
<PrintReportButton onClick={() => {print();}} />
<PrintReportButton onClick={() => {
print();
}}/>
</div>
<div className="report-page">
<ReportHeader report_type={ReportTypes.zeroTrust}/>
@ -85,43 +87,14 @@ class ZeroTrustReportPageComponent extends AuthComponent {
{content}
</div>
<div style={{marginTop: '20px'}}>
<PrintReportButton onClick={() => {print();}} />
<PrintReportButton onClick={() => {
print();
}}/>
</div>
</Fragment>
)
}
generateFindingsSection() {
return (<div id="findings-overview">
<h2>Findings</h2>
<p>
Deep-dive into the details of each test, and see the explicit events and exact timestamps in which things
happened in your network. This will enable you to match up with your SOC logs and alerts and to gain deeper
insight as to what exactly happened during this test.
</p>
<FindingsSection pillarsToStatuses={this.state.pillars.pillarsToStatuses} findings={this.state.findings}/>
</div>);
}
generateRecommendationsSection() {
return (<div id="recommendations-overview">
<h2>Recommendations</h2>
<p>
Analyze each zero trust recommendation by pillar, and see if you've followed through with it. See test results
to understand how the monkey tested your adherence to that recommendation.
</p>
{
Object.keys(this.state.recommendations).map((pillar) =>
<SinglePillarRecommendationsStatus
key={pillar}
pillar={pillar}
recommendationsStatus={this.state.recommendations[pillar]}
pillarsToStatuses={this.state.pillars.pillarsToStatuses}/>
)
}
</div>);
}
generateOverviewSection() {
return (<div id="overview-section">
<h2>Summary</h2>
@ -145,13 +118,44 @@ class ZeroTrustReportPageComponent extends AuthComponent {
</Row>
<Row>
<Col xs={12} sm={12} md={12} lg={12}>
<ZeroTrustReportLegend />
<ZeroTrustReportLegend/>
</Col>
</Row>
</Grid>
</div>);
}
generateRecommendationsSection() {
return (<div id="recommendations-overview">
<h2>Recommendations</h2>
<p>
Analyze each zero trust recommendation by pillar, and see if you've followed through with it. See test results
to understand how the monkey tested your adherence to that recommendation.
</p>
{
Object.keys(this.state.recommendations).map((pillar) =>
<SinglePillarRecommendationsStatus
key={pillar}
pillar={pillar}
recommendationsStatus={this.state.recommendations[pillar]}
pillarsToStatuses={this.state.pillars.pillarsToStatuses}/>
)
}
</div>);
}
generateFindingsSection() {
return (<div id="findings-overview">
<h2>Findings</h2>
<p>
Deep-dive into the details of each test, and see the explicit events and exact timestamps in which things
happened in your network. This will enable you to match up with your SOC logs and alerts and to gain deeper
insight as to what exactly happened during this test.
</p>
<FindingsSection pillarsToStatuses={this.state.pillars.pillarsToStatuses} findings={this.state.findings}/>
</div>);
}
stillLoadingDataFromServer() {
return typeof this.state.findings === "undefined" || typeof this.state.pillars === "undefined" || typeof this.state.recommendations === "undefined";
}

View File

@ -26,14 +26,9 @@ export default class EventsButtonsComponent extends Component {
<div>
<EventsModal events={this.props.events} showEvents={this.state.isShow} hideCallback={this.hide} exportFilename={this.props.exportFilename} />
<div className="text-center" style={{"display": "grid"}}>
<Button className="btn btn-info btn-lg" onClick={this.show}>
<Button className="btn btn-primary btn-lg" onClick={this.show}>
Show Events
</Button>
<ExportEventsButton onClick={() => {
const content = JSON.stringify(this.props.events, null, 2);
const blob = new Blob([content], {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(blob, this.props.exportFilename + ".json");
}}/>
</div>
</div>
);

View File

@ -1,14 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types';
import { Popover, OverlayTrigger } from 'react-bootstrap';
import {Popover, OverlayTrigger} from 'react-bootstrap';
import * as d3 from 'd3'
class ArcNode extends React.Component {
handleClick(e_) { this.props.disableHover(this.refs.overlay); }
handleOver(e_) { if(this.props.hover) { this.refs.overlay.show(); } }
handleOut(e_) { if(this.props.hover){ this.refs.overlay.hide(); } }
render() {
let {prefix, index, data} = this.props;
@ -16,31 +11,51 @@ class ArcNode extends React.Component {
let id = prefix + 'Node_' + index;
return (
<g transform={'rotate(180)'} id={data.node.pillar} key={prefix + 'arcGroup' + index}>
<OverlayTrigger ref={'overlay'} key={prefix + 'arcOverlayTrigger' + index} trigger={null} placement={data.popover} overlay={<Popover id={prefix + 'ArcPopover' + index} style={{backgroundColor: data.hex}} title={data.node.pillar}>{data.tooltip}</Popover>} rootClose>
<path
<g transform={'rotate(180)'} id={data.node.pillar} key={prefix + 'arcGroup' + index}>
<OverlayTrigger ref={'overlay'} key={prefix + 'arcOverlayTrigger' + index} trigger={null}
placement={data.popover}
overlay={<Popover id={prefix + 'ArcPopover' + index} style={{backgroundColor: data.hex}}
title={data.node.pillar}>{data.tooltip}</Popover>} rootClose>
<path
id={prefix + 'Node_' + index}
className={'arcNode'}
data-tooltip={data.tooltip}
d={arc()}
fill={data.hex}
onClick={this.handleClick.bind(this)}
onMouseEnter={this.handleOver.bind(this)}
onMouseLeave={this.handleOut.bind(this)}
id={prefix + 'Node_' + index}
className={'arcNode'}
data-tooltip={data.tooltip}
d={arc()}
fill={data.hex}
onClick={this.handleClick.bind(this)}
onMouseEnter={this.handleOver.bind(this)}
onMouseLeave={this.handleOut.bind(this)}
/>
</OverlayTrigger>
<text x={0} dy={data.fontStyle.size * 1.2} fontSize={data.fontStyle.size} fill={'white'} textAnchor='middle'
pointerEvents={'none'}>
<textPath href={'#' + id} startOffset={'26.4%'}>
<tspan fontFamily={'FontAwesome'}>{data.icon + '\u2000'}</tspan>
<tspan>{data.label}</tspan>
</textPath>
</text>
</g>
/>
</OverlayTrigger>
<text x={0} dy={data.fontStyle.size * 1.2} fontSize={data.fontStyle.size} fill={'white'} textAnchor='middle'
pointerEvents={'none'}>
<textPath href={'#' + id} startOffset={'26.4%'}>
<tspan fontFamily={'FontAwesome'}>{data.icon + '\u2000'}</tspan>
<tspan>{data.label}</tspan>
</textPath>
</text>
</g>
);
}
handleClick(e_) {
this.props.disableHover(this.refs.overlay);
}
handleOver(e_) {
if (this.props.hover) {
this.refs.overlay.show();
}
}
handleOut(e_) {
if (this.props.hover) {
this.refs.overlay.hide();
}
}
}
ArcNode.propTypes = {

View File

@ -1,40 +1,59 @@
import React from 'react'
import PillarLabel from "../PillarLabel";
import { Popover, OverlayTrigger } from 'react-bootstrap';
import {Popover, OverlayTrigger} from 'react-bootstrap';
import PropTypes from 'prop-types';
class CircularNode extends React.Component {
handleClick(e_) { this.props.disableHover(this.refs.overlay); }
handleOver(e_) { if(this.props.hover) { this.refs.overlay.show(); } }
handleOut(e_) { if(this.props.hover){ this.refs.overlay.hide(); } }
render() {
let {prefix, index, data} = this.props;
let translate = 'translate(' + data.cx + ',' + data.cy + ')';
return (
<g transform={translate} id={data.node.pillar} key={prefix + 'circularGroup' + index}>
<OverlayTrigger ref={'overlay'} key={prefix + 'CircularOverlay' + index} trigger={null} placement={data.popover} overlay={<Popover id={prefix + 'CircularClickPopover' + index} style={{backgroundColor : data.hex}} title={data.node.pillar}>{data.tooltip}</Popover>} rootClose>
<circle
id={prefix + 'Node_' + index}
className={'circularNode'}
data-tooltip={data.tooltip}
r={data.r}
opacity={0.8}
fill={data.hex}
onClick={this.handleClick.bind(this)}
onMouseEnter={this.handleOver.bind(this)}
onMouseLeave={this.handleOut.bind(this)}
<g transform={translate} id={data.node.pillar} key={prefix + 'circularGroup' + index}>
<OverlayTrigger ref={'overlay'} key={prefix + 'CircularOverlay' + index} trigger={null} placement={data.popover}
overlay={<Popover id={prefix + 'CircularClickPopover' + index}
style={{backgroundColor: data.hex}}
title={data.node.pillar}>{data.tooltip}</Popover>} rootClose>
<circle
id={prefix + 'Node_' + index}
className={'circularNode'}
data-tooltip={data.tooltip}
r={data.r}
opacity={0.8}
fill={data.hex}
onClick={this.handleClick.bind(this)}
onMouseEnter={this.handleOver.bind(this)}
onMouseLeave={this.handleOut.bind(this)}
/>
</OverlayTrigger>
<foreignObject style={{fontSize: data.fontStyle.size, pointerEvents: 'none'}} key={prefix + 'PillarLabelOject' + index} x={data.offset.x - data.fontStyle.size * 6} y={data.offset.y - data.fontStyle.size} width={ data.fontStyle.size * 12} height={data.fontStyle.size * 6}>
<PillarLabel key={prefix + 'PillarLabel' + index} pillar={data.node.pillar} status={data.status} />
</foreignObject>
</g>
/>
</OverlayTrigger>
<foreignObject style={{fontSize: data.fontStyle.size, pointerEvents: 'none'}}
key={prefix + 'PillarLabelOject' + index} x={data.offset.x - data.fontStyle.size * 6}
y={data.offset.y - data.fontStyle.size} width={data.fontStyle.size * 12}
height={data.fontStyle.size * 6}>
<PillarLabel key={prefix + 'PillarLabel' + index} pillar={data.node.pillar} status={data.status}/>
</foreignObject>
</g>
);
}
handleClick(e_) {
this.props.disableHover(this.refs.overlay);
}
handleOver(e_) {
if (this.props.hover) {
this.refs.overlay.show();
}
}
handleOut(e_) {
if (this.props.hover) {
this.refs.overlay.hide();
}
}
}
CircularNode.propTypes = {

View File

@ -12,11 +12,14 @@ class VennDiagram extends React.Component {
this.state = {hover: true, currentPopover: undefined};
this._disableHover = this._disableHover.bind(this);
this.width = this.height = 512;
this.prefix = 'vennDiagram';
this.fontStyles = [{size: Math.max(9, this.width / 28), color: 'white'}, { size: Math.max(6, this.width / 38), color: 'white'}, { size: Math.max(6, this.width / 48), color: 'white'} ];
this.fontStyles = [{size: Math.max(9, this.width / 28), color: 'white'}, {
size: Math.max(6, this.width / 38),
color: 'white'
}, {size: Math.max(6, this.width / 48), color: 'white'}];
this.offset = this.width / 16;
this.thirdWidth = this.width / 3;
@ -25,14 +28,43 @@ class VennDiagram extends React.Component {
this.width1By11 = this.width / 11;
this.width1By28 = this.width / 28;
this.arcNodesGap = 4;
this.layout = {
Data: {cx: 0, cy: 0, r: this.width11By2, offset: {x: 0, y: 0}, popover: 'top'},
People: {cx: -this.width2By7, cy: 0, r: this.width11By2, offset: {x: this.width1By11 + this.fontStyles[1].size / 5 * 3, y: 0}, popover: 'right'},
Networks: {cx: this.width2By7, cy: 0, r: this.width11By2, offset: {x: -this.width1By11 - this.fontStyles[1].size / 5 * 3, y: 0}, popover: 'left'},
Devices: {cx: 0, cy: this.width2By7, r: this.width11By2, offset: {x: 0, y: -this.width1By11 + this.fontStyles[1].size / 6 * 3}, popover: 'top'},
Workloads: {cx: 0, cy: -this.width2By7, r: this.width11By2, offset: {x: 0, y: this.width1By11}, popover: 'bottom' },
VisibilityAndAnalytics: {inner: this.thirdWidth - this.width1By28, outer: this.thirdWidth, icon: '\uf070', popover: 'left'},
People: {
cx: -this.width2By7,
cy: 0,
r: this.width11By2,
offset: {x: this.width1By11 + this.fontStyles[1].size / 5 * 3, y: 0},
popover: 'right'
},
Networks: {
cx: this.width2By7,
cy: 0,
r: this.width11By2,
offset: {x: -this.width1By11 - this.fontStyles[1].size / 5 * 3, y: 0},
popover: 'left'
},
Devices: {
cx: 0,
cy: this.width2By7,
r: this.width11By2,
offset: {x: 0, y: -this.width1By11 + this.fontStyles[1].size / 6 * 3},
popover: 'top'
},
Workloads: {
cx: 0,
cy: -this.width2By7,
r: this.width11By2,
offset: {x: 0, y: this.width1By11},
popover: 'bottom'
},
VisibilityAndAnalytics: {
inner: this.thirdWidth - this.width1By28,
outer: this.thirdWidth,
icon: '\uf070',
popover: 'right'
},
AutomationAndOrchestration: {
inner: this.thirdWidth - this.width1By28 * 2 - this.arcNodesGap,
outer: this.thirdWidth - this.width1By28 - this.arcNodesGap,
@ -85,51 +117,61 @@ class VennDiagram extends React.Component {
}
componentDidMount() { this.parseData(); if(this.state.currentPopover !== undefined) { this.state.currentPopover.show(); } }
_disableHover(ref_) { this.setState({hover: false, currentPopover: ref_, data: this.state.data }); }
componentDidMount() {
this.parseData();
if (this.state.currentPopover !== undefined) {
this.state.currentPopover.show();
}
}
_disableHover(ref_) {
this.setState({hover: false, currentPopover: ref_, data: this.state.data});
}
_onMouseMove(e) {
let self = this;
let hidden = 'none';
let html = '';
let bcolor = '#DEDEDE';
if(this.state.currentPopover !== undefined) { this.state.currentPopover.show(); }
if (this.state.currentPopover !== undefined) {
this.state.currentPopover.show();
}
document.querySelectorAll('circle, path').forEach((d_, i_) => {
d_.setAttribute('opacity', "0.8");
d_.setAttribute('opacity', "0.8");
});
if (e.target.id.includes('Node')) {
e.target.setAttribute('opacity', 0.95);
e.target.setAttribute('opacity', 0.95);
// Set highest z-index
e.target.parentNode.parentNode.appendChild(e.target.parentNode);
// Set highest z-index
e.target.parentNode.parentNode.appendChild(e.target.parentNode);
} else {
// Return z indices to default
Object.keys(this.layout).forEach(function (d_, i_) {
document.querySelector('#' + self.prefix).appendChild(document.querySelector('#' + self.prefix + 'Node_' + i_).parentNode); })
// Return z indices to default
Object.keys(this.layout).forEach(function (d_, i_) {
document.querySelector('#' + self.prefix).appendChild(document.querySelector('#' + self.prefix + 'Node_' + i_).parentNode);
})
}
}
_onClick(e) {
if (!e.target.id.includes('Node')) {
this.state.currentPopover.hide();
this.setState({hover: true, currentPopover: undefined, data: this.state.data });
}
if (!e.target.id.includes('Node')) {
this.state.currentPopover.hide();
this.setState({hover: true, currentPopover: undefined, data: this.state.data});
}
}
parseData() {
let self = this;
let data = [];
const omit = (prop, {[prop]: _, ...rest}) => rest;
@ -157,23 +199,25 @@ class VennDiagram extends React.Component {
this.setState({hover: true, activePopover: undefined, data: data});
this.render();
}
buildTooltipHtmlContent(object_) {
return Object.keys(object_).map((key_, i_) => { return ( <p key={this.prefix + key_ + i_}>{key_}: {object_[key_]}</p> ) })
return Object.keys(object_).map((key_, i_) => {
return (<p key={this.prefix + key_ + i_}>{key_}: {object_[key_]}</p>)
})
}
setLayoutElement(rule_, key_, html_, d_) {
if(rule_ === null) { console.log(Error('The node scores are invalid, please check the data or the rules set.')); }
if (rule_ === null) {
console.log(Error('The node scores are invalid, please check the data or the rules set.'));
}
if (key_ === 'Data') {
this.layout[key_].fontStyle = this.fontStyles[0];
}
else if(this.layout[key_].hasOwnProperty('cx')){
} else if (this.layout[key_].hasOwnProperty('cx')) {
this.layout[key_].fontStyle = this.fontStyles[1];
}
else {
} else {
this.layout[key_].fontStyle = this.fontStyles[2];
}
@ -218,11 +262,12 @@ class VennDiagram extends React.Component {
});
return (
<div ref={(divElement) => this.divElement = divElement} onMouseMove={this._onMouseMove.bind(this)} onClick={this._onClick.bind(this)}>
<svg id={this.prefix} viewBox={viewPortParameters} width={'100%'} height={'100%'}
<div ref={(divElement) => this.divElement = divElement} onMouseMove={this._onMouseMove.bind(this)}
onClick={this._onClick.bind(this)}>
<svg id={this.prefix} viewBox={viewPortParameters} width={'100%'} height={'100%'}
xmlns='http://www.w3.org/2000/svg' xmlnsXlink='http://www.w3.org/1999/xlink'>
{nodes}
</svg>
</svg>
</div>
)
}