diff --git a/index.html b/index.html index c35f124..1608292 100644 --- a/index.html +++ b/index.html @@ -16,7 +16,6 @@ - diff --git a/package.json b/package.json index 0931650..915490e 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ }, "babel": { "presets": [ - "es2015", + "env", "stage-0", "react" ] @@ -38,7 +38,7 @@ "babel-core": "^6.22.1", "babel-loader": "^7.0.0", "babel-polyfill": "^6.22.0", - "babel-preset-es2015": "^6.22.0", + "babel-preset-env": "^1.6.0", "babel-preset-react": "^6.22.0", "babel-preset-stage-0": "^6.22.0", "concurrently": "^3.1.0", @@ -56,15 +56,16 @@ "configstore": "^3.1.0", "dagre": "^0.7.4", "eventemitter2": "^4.1.0", + "fast-csv": "^2.4.1", "jquery": "^3.2.1", "linkurious": "^1.5.1", "mustache": "^2.2.1", - "neo4j-driver": "^1.3.0", - "prop-types": "^15.5.10", + "neo4j-driver": "^1.4.1", "react": "^15.4.2", "react-bootstrap": "^0.31.0", "react-dom": "^15.4.2", "react-if": "^2.1.0", - "react-transition-group": "^1.1.3" + "react-transition-group": "^1.1.3", + "unzipper": "^0.8.9" } } diff --git a/src/components/Float/Alert.jsx b/src/components/Float/Alert.jsx index 69daeef..a2856ff 100644 --- a/src/components/Float/Alert.jsx +++ b/src/components/Float/Alert.jsx @@ -2,46 +2,46 @@ import React, { Component } from 'react'; import { Alert } from 'react-bootstrap'; export default class GenericAlert extends Component { - constructor(){ - super() - this.state = { - visible: false, - text: "No data returned from query", - timeout: null - } + constructor(){ + super(); + this.state = { + visible: false, + text: "No data returned from query", + timeout: null + }; - emitter.on('showAlert', this._show.bind(this)) - emitter.on('hideAlert', this._dismiss.bind(this)) - } + emitter.on('showAlert', this._show.bind(this)); + emitter.on('hideAlert', this._dismiss.bind(this)); + } - _dismiss(){ - this.setState({visible: false}); - } + _dismiss(){ + this.setState({visible: false}); + } - _show(val){ - clearTimeout(this.state.timeout) - var t = setTimeout(function(){ - this._dismiss() - }.bind(this), 2500) - - this.setState({ - visible: true, - text: val, - timeout: t - }) + _show(val){ + clearTimeout(this.state.timeout); + var t = setTimeout(function(){ + this._dismiss(); + }.bind(this), 2500); - } + this.setState({ + visible: true, + text: val, + timeout: t + }); + + } - render() { - if (this.state.visible){ - return ( - - {this.state.text} - - ) - }else{ - return null - } - - } + render() { + if (this.state.visible){ + return ( + + {this.state.text} + + ); + }else{ + return null; + } + + } } diff --git a/src/components/Float/Login.jsx b/src/components/Float/Login.jsx index e1cdb52..82ecbe0 100644 --- a/src/components/Float/Login.jsx +++ b/src/components/Float/Login.jsx @@ -1,280 +1,285 @@ import React, { Component } from 'react'; export default class Login extends Component { - constructor(){ - super(); - this.state = { - url: "", - icon: null, - loginEnabled: false, - user: "", - password: "", - loginInProgress: false, - save: false - } - } + constructor(){ + super(); + this.state = { + url: "", + icon: null, + loginEnabled: false, + user: "", + password: "", + loginInProgress: false, + save: false + }; + } - checkDBPresence(){ - var url = this.state.url; - var icon = this.state.icon; - var jicon = jQuery(icon) - var btn = jQuery(this.refs.loginButton) + componentWillMount() { + var c = conf.get('databaseInfo'); + if (typeof c !== 'undefined'){ + this.setState({ + url: c.url, + user: c.user, + password: c.password, + save: true + }); + } + } - if (url === ""){ - return; - } + componentDidMount() { + jQuery(this.refs.password).tooltip({ + placement : 'right', + title: '', + container: 'body', + trigger: 'manual', + template: '' + }); + this.setIcon(); + + if (this.state.password !== ""){ + this.checkDBCreds(); + } + } - jQuery(this.refs.urlspinner).toggle(true) + setIcon(){ + var icon = jQuery(this.refs.urlspinner); + icon.tooltip({ + placement : 'right', + title: '', + container: 'body', + delay: {show: 200, hide: 0}, + template: '' + }); + icon.toggle(false); + this.setState({icon: jQuery(this.refs.urlspinner)}); + } - url = url.replace(/\/$/, ""); + checkDBPresence(){ + var url = this.state.url; + var icon = this.state.icon; + var jicon = jQuery(icon); + var btn = jQuery(this.refs.loginButton); - if (!url.includes(':')){ - url = url + ':7687' - } + if (url === ""){ + return; + } - if (!url.startsWith('bolt://')){ - url = 'bolt://' + url - } + jQuery(this.refs.urlspinner).toggle(true); - icon.removeClass(); - icon.addClass("fa fa-spinner fa-spin form-control-feedback"); - icon.toggle(true); - var driver = neo4j.driver(url, neo4j.auth.basic("",""), {encrypted:'ENCRYPTION_ON'}) - var session = driver.session(); + url = url.replace(/\/$/, ""); - driver.onCompleted = function(){ - session.close() - driver.close() - } - driver.onError = function(error){ - if (error.message.includes("authentication failure")){ - icon.removeClass(); - icon.addClass("fa fa-check-circle green-icon-color form-control-feedback"); - this.setState({loginEnabled: true, url: url}) - }else{ - icon.removeClass(); - icon.addClass("fa fa-times-circle red-icon-color form-control-feedback"); - icon.attr('data-original-title', 'No database found') - .tooltip('fixTitle') - .tooltip('show') - this.setState({ - loginInProgress: false, - loginEnabled: false - }) - } - session.close() - driver.close() - }.bind(this) - session.run("return 1") - } + if (!url.includes(':')){ + url = url + ':7687'; + } - checkDBCreds(){ - if (this.state.loginInProgress){ - return; - } - this.setState({ - loginInProgress: true, - loginEnabled: false - }) + if (!url.startsWith('bolt://')){ + url = 'bolt://' + url; + } - var btn = jQuery(this.refs.loginButton) - var pwf = jQuery(this.refs.password) + icon.removeClass(); + icon.addClass("fa fa-spinner fa-spin form-control-feedback"); + icon.toggle(true); + var driver = neo4j.driver(url, neo4j.auth.basic("",""), {encrypted:'ENCRYPTION_ON'}); + var session = driver.session(); - var driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password)) - driver.onError = function(error){ - console.log(error) - if (error.message.includes("authentication failure")){ - btn.removeClass('activate'); - this.setState({ - loginInProgress: false, - loginEnabled: true - }) - pwf.attr('data-original-title', 'Invalid username or password') - .tooltip('fixTitle') - .tooltip('show') - }else if (error.message.includes("too many times in a row")){ - btn.removeClass('activate'); - this.setState({ - loginInProgress: false, - loginEnabled: true - }) - pwf.attr('data-original-title', 'Too many authentication attempts, please wait') - .tooltip('fixTitle') - .tooltip('show') - }else if (error.toString().includes('ECONNREFUSED')){ - var icon = this.state.icon - icon.toggle('true') - icon.removeClass(); - icon.addClass("fa fa-times-circle red-icon-color form-control-feedback"); - icon.attr('data-original-title', 'No database found') - .tooltip('fixTitle') - .tooltip('show') - this.setState({ - loginInProgress: false, - loginEnabled: false - }) - } - driver.close() - }.bind(this) - var session = driver.session(); - session.run('MATCH (n) RETURN (n) LIMIT 1') - .subscribe({ - onError: function(error){ - btn.removeClass('activate'); - var url = this.state.url.replace('bolt://','http://').replace('7687','7474') - if (error.fields && error.fields[0].code === "Neo.ClientError.Security.CredentialsExpired"){ - pwf.attr('data-original-title', 'Credentials need to be changed from the neo4j browser first. Go to {} and change them.'.format(url)) - .tooltip('fixTitle') - .tooltip('show') - this.setState({ - loginInProgress: false, - loginEnabled: true - }) - } - }.bind(this), - onNext: function(){ + driver.onCompleted = function(){ + session.close(); + driver.close(); + }; + driver.onError = function(error){ + if (error.message.includes("authentication failure")){ + icon.removeClass(); + icon.addClass("fa fa-check-circle green-icon-color form-control-feedback"); + this.setState({loginEnabled: true, url: url}); + }else{ + icon.removeClass(); + icon.addClass("fa fa-times-circle red-icon-color form-control-feedback"); + icon.attr('data-original-title', 'No database found') + .tooltip('fixTitle') + .tooltip('show'); + this.setState({ + loginInProgress: false, + loginEnabled: false + }); + } + session.close(); + driver.close(); + }.bind(this); + session.run("return 1"); + } - }, - onCompleted: function(){ - btn.toggleClass('activate'); - btn.removeClass('btn-default') - btn.addClass('btn-success') - btn.html('Success!') - this.setState({ - loginInProgress: false - }) + checkDBCreds(){ + if (this.state.loginInProgress){ + return; + } + this.setState({ + loginInProgress: true, + loginEnabled: false + }); - var dbinfo = { - url: this.state.url, - user: this.state.user, - password: this.state.password - } - - if (this.state.save){ - conf.set('databaseInfo',dbinfo) - } + var btn = jQuery(this.refs.loginButton); + var pwf = jQuery(this.refs.password); - appStore.databaseInfo = dbinfo; - - jQuery(this.refs.password).tooltip('hide') - jQuery(this.refs.urlspinner).tooltip('hide') - setTimeout(function(){ - jQuery(this.refs.outer).fadeOut(400, function(){ - renderEmit.emit('login'); - }); - }.bind(this), 1500) - driver.close() - global.driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password)) - }.bind(this) - }) + var driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password)); + driver.onError = function(error){ + console.log(error); + if (error.message.includes("authentication failure")){ + btn.removeClass('activate'); + this.setState({ + loginInProgress: false, + loginEnabled: true + }); + pwf.attr('data-original-title', 'Invalid username or password') + .tooltip('fixTitle') + .tooltip('show'); + }else if (error.message.includes("too many times in a row")){ + btn.removeClass('activate'); + this.setState({ + loginInProgress: false, + loginEnabled: true + }); + pwf.attr('data-original-title', 'Too many authentication attempts, please wait') + .tooltip('fixTitle') + .tooltip('show'); + }else if (error.toString().includes('ECONNREFUSED')){ + var icon = this.state.icon; + icon.toggle('true'); + icon.removeClass(); + icon.addClass("fa fa-times-circle red-icon-color form-control-feedback"); + icon.attr('data-original-title', 'No database found') + .tooltip('fixTitle') + .tooltip('show'); + this.setState({ + loginInProgress: false, + loginEnabled: false + }); + } + driver.close(); + }.bind(this); + var session = driver.session(); + session.run('MATCH (n) RETURN (n) LIMIT 1') + .subscribe({ + onError: function(error){ + btn.removeClass('activate'); + var url = this.state.url.replace('bolt://','http://').replace('7687','7474'); + if (error.fields && error.fields[0].code === "Neo.ClientError.Security.CredentialsExpired"){ + pwf.attr('data-original-title', 'Credentials need to be changed from the neo4j browser first. Go to {} and change them.'.format(url)) + .tooltip('fixTitle') + .tooltip('show'); + this.setState({ + loginInProgress: false, + loginEnabled: true + }); + } + }.bind(this), + onNext: function(){ - btn.toggleClass('activate'); + }, + onCompleted: function(){ + btn.toggleClass('activate'); + btn.removeClass('btn-default'); + btn.addClass('btn-success'); + btn.html('Success!'); + this.setState({ + loginInProgress: false + }); - } + var dbinfo = { + url: this.state.url, + user: this.state.user, + password: this.state.password + }; + + if (this.state.save){ + conf.set('databaseInfo',dbinfo); + } - componentWillMount() { - var c = conf.get('databaseInfo') - if (typeof c !== 'undefined'){ - this.setState({ - url: c.url, - user: c.user, - password: c.password, - save: true - }) - } - } + appStore.databaseInfo = dbinfo; + + jQuery(this.refs.password).tooltip('hide'); + jQuery(this.refs.urlspinner).tooltip('hide'); + setTimeout(function(){ + jQuery(this.refs.outer).fadeOut(400, function(){ + renderEmit.emit('login'); + }); + }.bind(this), 1500); + driver.close(); + global.driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password)); + }.bind(this) + }); - componentDidMount() { - jQuery(this.refs.password).tooltip({ - placement : 'right', - title: '', - container: 'body', - trigger: 'manual', - template: '' - }) - this.setState({icon: jQuery(this.refs.urlspinner)}) - var icon = jQuery(this.refs.urlspinner) - icon.tooltip({ - placement : 'right', - title: '', - container: 'body', - delay: {show: 200, hide: 0}, - template: '' - }) - icon.toggle(false) - if (this.state.password !== ""){ - this.checkDBCreds(); - } - } + btn.toggleClass('activate'); - _saveChange(event) { - this.setState({save: event.target.checked}); - } + } - _urlChanged(event){ - this.setState({url: event.target.value}) - } + _saveChange(event) { + this.setState({save: event.target.checked}); + } - _userChanged(event){ - this.setState({user: event.target.value}) - jQuery(this.refs.password).tooltip('hide') - } + _urlChanged(event){ + this.setState({url: event.target.value}); + } - _passChanged(event){ - this.setState({password: event.target.value}) - jQuery(this.refs.password).tooltip('hide') - } + _userChanged(event){ + this.setState({user: event.target.value}); + jQuery(this.refs.password).tooltip('hide'); + } - _triggerLogin(e){ - var key = e.keyCode ? e.keyCode : e.which + _passChanged(event){ + this.setState({password: event.target.value}); + jQuery(this.refs.password).tooltip('hide'); + } - if (key === 13){ - this.checkDBCreds() - } - } + _triggerLogin(e){ + var key = e.keyCode ? e.keyCode : e.which; - render() { - return ( -
-
- -
- Log in to Neo4j Database -
-
-
-
- - Database URL - - - -
-
- DB Username - -
-
- DB Password - -
-
-
- -
-
- -
-
-
- -
-
- ); - } + if (key === 13){ + this.checkDBCreds(); + } + } + + render() { + return ( +
+
+ +
+ Log in to Neo4j Database +
+
+
+
+ + Database URL + + + +
+
+ DB Username + +
+
+ DB Password + +
+
+
+ +
+
+ +
+
+
+ +
+
+ ); + } } diff --git a/src/components/Float/Settings.jsx b/src/components/Float/Settings.jsx index dfb4501..51b99e6 100644 --- a/src/components/Float/Settings.jsx +++ b/src/components/Float/Settings.jsx @@ -1,138 +1,139 @@ import React, { Component } from 'react'; export default class Settings extends Component { - constructor(){ - super(); - } + constructor(){ + super(); + } - componentDidMount() { - emitter.on('openSettings', function(){ - this.openSettings() - }.bind(this)) + componentDidMount() { + emitter.on('openSettings', function(){ + this.openSettings() + }.bind(this)) - $(this.refs.edge).simpleSlider({ - range: [0,20], - step: 1, - theme: 'volume slideinline' - }) + $(this.refs.edge).simpleSlider({ + range: [0,20], + step: 1, + theme: 'volume slideinline' + }) - $(this.refs.sibling).simpleSlider({ - range: [0,20], - step: 1, - theme: 'volume slideinline' - }) + $(this.refs.sibling).simpleSlider({ + range: [0,20], + step: 1, + theme: 'volume slideinline' + }) - $(this.refs.edge).bind('slider:changed', this.edgeChange.bind(this)) - $(this.refs.sibling).bind('slider:changed', this.siblingChange.bind(this)) + $(this.refs.edge).bind('slider:changed', this.edgeChange.bind(this)) + $(this.refs.sibling).bind('slider:changed', this.siblingChange.bind(this)) - $(this.refs.edge).simpleSlider('setValue', appStore.performance.edge) - $(this.refs.sibling).simpleSlider('setValue', appStore.performance.sibling) + $(this.refs.edge).simpleSlider('setValue', appStore.performance.edge) + $(this.refs.sibling).simpleSlider('setValue', appStore.performance.sibling) - $(this.refs.check).prop('checked', appStore.performance.lowGraphics) - $(this.refs.debug).prop('checked', appStore.performance.debug) + $(this.refs.check).prop('checked', appStore.performance.lowGraphics) + $(this.refs.debug).prop('checked', appStore.performance.debug) - $(this.refs.outer).fadeToggle(0) - $(this.refs.outer).draggable() - } + $(this.refs.outer).fadeToggle(0) + $(this.refs.outer).draggable() + } - edgeChange(event, data){ - appStore.performance.edge = data.value; - $(this.refs.edgeinput).val(data.value) - conf.set('performance', appStore.performance) - } + edgeChange(event, data){ + appStore.performance.edge = data.value; + $(this.refs.edgeinput).val(data.value) + conf.set('performance', appStore.performance) + } - siblingChange(event, data){ - appStore.performance.sibling = data.value; - $(this.refs.siblinginput).val(data.value) - conf.set('performance', appStore.performance) - } + siblingChange(event, data){ + appStore.performance.sibling = data.value; + $(this.refs.siblinginput).val(data.value) + conf.set('performance', appStore.performance) + } - onGfxChange(event){ - $(this.refs.check).prop('checked', event.target.checked) - appStore.performance.lowGraphics = event.target.checked - conf.set('performance', appStore.performance) - emitter.emit('changeGraphicsMode') - } + onGfxChange(event){ + $(this.refs.check).prop('checked', event.target.checked) + appStore.performance.lowGraphics = event.target.checked + conf.set('performance', appStore.performance) + emitter.emit('changeGraphicsMode') + } - onDebugChange(event){ - $(this.refs.debug).prop('checked', event.target.checked) - appStore.performance.debug = event.target.checked - conf.set('performance', appStore.performance) - } + onDebugChange(event){ + $(this.refs.debug).prop('checked', event.target.checked) + appStore.performance.debug = event.target.checked + conf.set('performance', appStore.performance) + } - closeSettings(){ - $(this.refs.outer).fadeToggle(false) - } + closeSettings(){ + $(this.refs.outer).fadeToggle(false) + } - openSettings(){ - $(this.refs.outer).fadeToggle(false) - } + openSettings(){ + $(this.refs.outer).fadeToggle(false) + } - updateSibling(event){ - $(this.refs.sibling).simpleSlider('setValue', event.target.value) - } + updateSibling(event){ + $(this.refs.sibling).simpleSlider('setValue', event.target.value) + } - updateEdge(event){ - $(this.refs.edge).simpleSlider('setValue', event.target.value) - } + updateEdge(event){ + $(this.refs.edge).simpleSlider('setValue', event.target.value) + } - render() { - return ( -
-
- Settings - -
+ render() { + return ( +
+
+ Settings + +
-
-
- Sibling Collapse Threshold - -
- - - - -
+
+
+ Sibling Collapse Threshold + +
+ + + + +
-
- Node Collapse Threshold - -
- - - - -
-
- -
- -
-
- -
- -
-
- ); - } +
+ Node Collapse Threshold + +
+ + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ ); + } } diff --git a/src/components/Graph.jsx b/src/components/Graph.jsx index 3729d27..8548855 100644 --- a/src/components/Graph.jsx +++ b/src/components/Graph.jsx @@ -1,15 +1,15 @@ import React, { Component } from 'react'; -import ReactDOM from 'react-dom' +import ReactDOM from 'react-dom'; import { findGraphPath } from 'utils'; var fs = require('fs'); -var child_process = require('child_process') +var child_process = require('child_process'); var child; -var path = require('path') -const { dialog } = require('electron').remote +var path = require('path'); +const { dialog } = require('electron').remote; export default class GraphContainer extends Component { constructor(props){ - super(props) + super(props); child = child_process.fork(path.join(__dirname,'src','js','worker.js'), {silent:true}); @@ -20,14 +20,15 @@ export default class GraphContainer extends Component { firstDraw: true, template: null, session: driver.session() - } + }; + $.ajax({ url: 'src/components/tooltip.html', type: 'GET', success: function(response){ - this.setState({template: response}) + this.setState({template: response}); }.bind(this) - }) + }); child.stdout.on('data', (data) => { console.log(`stdout: ${data}`); @@ -38,64 +39,93 @@ export default class GraphContainer extends Component { }); child.on('message', function(m) { - this.loadFromChildProcess(m) + this.loadFromChildProcess(m); }.bind(this)); - var s1 = driver.session() - var s2 = driver.session() - var s3 = driver.session() - var s4 = driver.session() + var s1 = driver.session(); + var s2 = driver.session(); + var s3 = driver.session(); + var s4 = driver.session(); s1.run("CREATE CONSTRAINT ON (c:User) ASSERT c.name IS UNIQUE") .then(function(){ - s1.close() + s1.close(); s2.run("CREATE CONSTRAINT ON (c:Computer) ASSERT c.name IS UNIQUE") .then(function(){ - s2.close() + s2.close(); s3.run("CREATE CONSTRAINT ON (c:Group) ASSERT c.name IS UNIQUE") .then(function(){ - s3.close() + s3.close(); s4.run("CREATE CONSTRAINT ON (c:Domain) ASSERT c.name IS UNIQUE") .then(function(){ - s4.close() + s4.close(); }) .catch(function(){ - s4.close() - }) + s4.close(); + }); }) .catch(function(){ - s3.close() - }) + s3.close(); + }); }) .catch(function(){ - s2.close() - }) + s2.close(); + }); }) .catch(function(){ - s1.close() - }) + s1.close(); + }); emitter.on('doLogout', function(){ this.state.sigmaInstance.graph.clear(); this.state.sigmaInstance.refresh(); sigma.layouts.killForceLink(); - this.setState({sigmaInstance: null}) + this.setState({sigmaInstance: null}); child.kill(); - }.bind(this)) + }.bind(this)); + } + + componentWillMount() { + emitter.on('searchQuery', this.doSearchQuery.bind(this)); + emitter.on('pathQuery', this.doPathQuery.bind(this)); + emitter.on('graphBack', this.goBack.bind(this)); + emitter.on('query', this.doGenericQuery.bind(this)); + emitter.on('spotlightClick', this.spotlightClickHandler.bind(this)); + emitter.on('graphRefresh', this.relayout.bind(this)); + emitter.on('export', this.export.bind(this)); + emitter.on('import', this.import.bind(this)); + emitter.on('clearDB', this.clearGraph.bind(this)); + emitter.on('changeGraphicsMode', this.setGraphicsMode.bind(this)); + emitter.on('ungroupNode', this.ungroupNode.bind(this)); + emitter.on('unfoldNode', this.unfoldEdgeNode.bind(this)); + emitter.on('collapseNode', this.foldEdgeNode.bind(this)); + emitter.on('resetZoom', this.resetZoom.bind(this)); + emitter.on('zoomIn', this.zoomIn.bind(this)); + emitter.on('zoomOut', this.zoomOut.bind(this)); + } + + componentDidMount() { + this.initializeSigma(); + + this.doQueryNative({ + statement: 'MATCH (n:Group) WHERE n.name =~ "(?i).*DOMAIN ADMINS.*" WITH n MATCH (n)<-[r:MemberOf*1..]-(m) RETURN n,r,m', + allowCollapse: false, + props: {} + }); } relayout(){ - sigma.layouts.stopForceLink() + sigma.layouts.stopForceLink(); if (appStore.dagre){ sigma.layouts.dagre.start(this.state.sigmaInstance); }else{ - sigma.layouts.startForceLink() + sigma.layouts.startForceLink(); } } export(payload){ if (payload === 'image'){ - var size = $('#graph').outerWidth() + var size = $('#graph').outerWidth(); sigma.plugins.image(this.state.sigmaInstance, this.state.sigmaInstance.renderers[0], { @@ -106,27 +136,27 @@ export default class GraphContainer extends Component { }); }else{ var json = this.state.sigmaInstance.toJSON({ - pretty: true, - }) + pretty: true + }); - json = JSON.parse(json) - json.spotlight = appStore.spotlightData + json = JSON.parse(json); + json.spotlight = appStore.spotlightData; dialog.showSaveDialog({ defaultPath: 'graph.json' }, function(loc){ - fs.writeFile(loc, JSON.stringify(json, null, 2)) - }) + fs.writeFile(loc, JSON.stringify(json, null, 2)); + }); } } loadFromChildProcess(graph){ if (graph.nodes.length === 0){ - emitter.emit('showAlert', "No data returned from query") - emitter.emit('updateLoadingText', "Done!") + emitter.emit('showAlert', "No data returned from query"); + emitter.emit('updateLoadingText', "Done!"); setTimeout(function(){ emitter.emit('showLoadingIndicator', false); - }, 1500) + }, 1500); }else{ if (!this.state.firstDraw){ appStore.queryStack.push({ @@ -135,23 +165,23 @@ export default class GraphContainer extends Component { spotlight: appStore.spotlightData, startNode: appStore.startNode, endNode: appStore.endNode - }) + }); } $.each(graph.nodes, function(i, node){ if (node.start){ - appStore.startNode = node + appStore.startNode = node; } if (node.end){ - appStore.endNode = node + appStore.endNode = node; } node.glyphs = $.map(node.glyphs, function(value, index) { return [value]; }); - }) + }); - this.setState({firstDraw: false}) + this.setState({firstDraw: false}); sigma.misc.animation.camera(this.state.sigmaInstance.camera, { x: 0, y: 0, ratio: 1.075 }); appStore.spotlightData = graph.spotlight; @@ -164,7 +194,7 @@ export default class GraphContainer extends Component { if (appStore.dagre){ sigma.layouts.dagre.start(this.state.sigmaInstance); }else{ - sigma.layouts.startForceLink() + sigma.layouts.startForceLink(); } emitter.emit('spotlightUpdate'); } @@ -177,44 +207,44 @@ export default class GraphContainer extends Component { graph = JSON.parse(data); }catch (err){ emitter.emit('showAlert', 'Bad JSON File'); - return + return; } if (graph.nodes.length === 0){ - emitter.emit('showAlert', "No data returned from query") + emitter.emit('showAlert', "No data returned from query"); }else{ $.each(graph.nodes, function(i, node){ node.glyphs = $.map(node.glyphs, function(value, index) { return [value]; }); - }) + }); appStore.queryStack.push({ nodes: this.state.sigmaInstance.graph.nodes(), edges: this.state.sigmaInstance.graph.edges(), spotlight: appStore.spotlightData, startNode: appStore.startNode, endNode: appStore.endNode - }) + }); appStore.spotlightData = graph.spotlight; this.state.sigmaInstance.graph.clear(); this.state.sigmaInstance.graph.read(graph); - this.state.sigmaInstance.refresh() + this.state.sigmaInstance.refresh(); emitter.emit('spotlightUpdate'); } - }.bind(this)) + }.bind(this)); } clearGraph(){ - this.state.sigmaInstance.graph.clear() - this.state.sigmaInstance.refresh() + this.state.sigmaInstance.graph.clear(); + this.state.sigmaInstance.refresh(); } setGraphicsMode(){ - var lowgfx = appStore.performance.lowGraphics - var sigmaInstance = this.state.sigmaInstance - this.state.design.clear() + var lowgfx = appStore.performance.lowGraphics; + var sigmaInstance = this.state.sigmaInstance; + this.state.design.clear(); if (lowgfx){ sigmaInstance.settings('defaultEdgeType', 'line'); sigmaInstance.settings('defaultEdgeColor', 'black'); @@ -226,28 +256,9 @@ export default class GraphContainer extends Component { this.state.design.setPalette(appStore.highResPalette); this.state.design.setStyles(appStore.highResStyle); } - this.state.design.deprecate() - sigmaInstance.refresh() - this.state.design.apply() - } - - componentWillMount() { - emitter.on('searchQuery', this.doSearchQuery.bind(this)); - emitter.on('pathQuery', this.doPathQuery.bind(this)); - emitter.on('graphBack', this.goBack.bind(this)); - emitter.on('query', this.doGenericQuery.bind(this)); - emitter.on('spotlightClick', this.spotlightClickHandler.bind(this)) - emitter.on('graphRefresh', this.relayout.bind(this)) - emitter.on('export', this.export.bind(this)) - emitter.on('import', this.import.bind(this)) - emitter.on('clearDB', this.clearGraph.bind(this)) - emitter.on('changeGraphicsMode', this.setGraphicsMode.bind(this)) - emitter.on('ungroupNode', this.ungroupNode.bind(this)) - emitter.on('unfoldNode', this.unfoldEdgeNode.bind(this)) - emitter.on('collapseNode', this.foldEdgeNode.bind(this)) - emitter.on('resetZoom', this.resetZoom.bind(this)) - emitter.on('zoomIn', this.zoomIn.bind(this)) - emitter.on('zoomOut', this.zoomOut.bind(this)) + this.state.design.deprecate(); + sigmaInstance.refresh(); + this.state.design.apply(); } resetZoom(){ @@ -258,7 +269,7 @@ export default class GraphContainer extends Component { } zoomOut(){ - var sigmaInstance = this.state.sigmaInstance + var sigmaInstance = this.state.sigmaInstance; var cam = sigmaInstance.camera; sigma.misc.animation.camera(cam, { @@ -269,7 +280,7 @@ export default class GraphContainer extends Component { } zoomIn(){ - var sigmaInstance = this.state.sigmaInstance + var sigmaInstance = this.state.sigmaInstance; var cam = sigmaInstance.camera; sigma.misc.animation.camera(cam, @@ -281,16 +292,6 @@ export default class GraphContainer extends Component { }); } - componentDidMount() { - this.initializeSigma(); - - this.doQueryNative({ - statement: 'MATCH (n:Group) WHERE n.name =~ "(?i).*DOMAIN ADMINS.*" WITH n MATCH (n)<-[r:MemberOf*1..]-(m) RETURN n,r,m', - allowCollapse: false, - props: {} - }) - } - render() { return (
@@ -321,25 +322,25 @@ export default class GraphContainer extends Component { spotlightClickHandler(nodeId, parentId){ var sigmaInstance = this.state.sigmaInstance; - var parent = sigmaInstance.graph.nodes(nodeId) + var parent = sigmaInstance.graph.nodes(nodeId); var label, child; if (typeof parent === 'undefined'){ child = sigmaInstance.graph.nodes(parentId).folded.nodes.filter(function(val){ - return val.id == nodeId; - })[0] + return val.id === nodeId; + })[0]; parent = sigmaInstance.graph.nodes(parentId); }else{ child = parent; } label = child.label; if (child.type_user){ - emitter.emit('userNodeClicked', label) + emitter.emit('userNodeClicked', label); }else if (child.type_group){ - emitter.emit('groupNodeClicked', label) + emitter.emit('groupNodeClicked', label); }else if (child.type_computer){ - emitter.emit('computerNodeClicked', label) + emitter.emit('computerNodeClicked', label); } - parent.color = "#2DC486" + parent.color = "#2DC486"; sigma.misc.animation.camera( sigmaInstance.camera, { x: parent[sigmaInstance.camera.readPrefix + 'x'], @@ -351,119 +352,120 @@ export default class GraphContainer extends Component { setTimeout(function(){ parent.color = "black"; sigmaInstance.refresh({skipIndexation: true}); - }, 2000) + }, 2000); } doQueryNative(params){ if (appStore.performance.debug){ emitter.emit('setRawQuery',params.statement); } - var sigmaInstance = this.state.sigmaInstance - var nodes = {} - var edges = {} - var session = driver.session() + var sigmaInstance = this.state.sigmaInstance; + var nodes = {}; + var edges = {}; + var session = driver.session(); if (typeof params.props === 'undefined'){ - params.props = {} + params.props = {}; } emitter.emit('showLoadingIndicator', true); - emitter.emit('updateLoadingText', "Querying Database") - emitter.emit('resetSpotlight') + emitter.emit('updateLoadingText', "Querying Database"); + emitter.emit('resetSpotlight'); session.run(params.statement, params.props) .subscribe({ onNext: function(result){ $.each(result._fields, function(index, field){ - if (field != null){ + if (field !== null){ if (field.hasOwnProperty('segments')){ $.each(field.segments,function(index, segment){ - var end = this.createNodeFromRow(segment.end, params) - var start = this.createNodeFromRow(segment.start, params) - var edge = this.createEdgeFromRow(segment.relationship) + var end = this.createNodeFromRow(segment.end, params); + var start = this.createNodeFromRow(segment.start, params); + var edge = this.createEdgeFromRow(segment.relationship); if (!edges[edge.id]){ - edges[edge.id] = edge + edges[edge.id] = edge; } if (!nodes[end.id]){ - nodes[end.id] = end + nodes[end.id] = end; } if (!nodes[start.id]){ - nodes[start.id] = start + nodes[start.id] = start; } - }.bind(this)) + }.bind(this)); }else{ if ($.isArray(field)){ $.each(field, function(index, value){ - if (value != null){ - var id = value.identity.low + if (value !== null){ + var id = value.identity.low; if (value.end && !edges.id){ - edges[id] = this.createEdgeFromRow(value) + edges[id] = this.createEdgeFromRow(value); }else if (!nodes.id){ - nodes[id] = this.createNodeFromRow(value, params) + nodes[id] = this.createNodeFromRow(value, params); } } - }.bind(this)) + }.bind(this)); }else{ - var id = field.identity.low + var id = field.identity.low; if (field.end && !edges.id){ - edges[id] = this.createEdgeFromRow(field) + edges[id] = this.createEdgeFromRow(field); }else if (!nodes.id){ - nodes[id] = this.createNodeFromRow(field, params) + nodes[id] = this.createNodeFromRow(field, params); } } } } - }.bind(this)) + }.bind(this)); }.bind(this), onError: function(error){ - console.log(error) + console.log(error); }, onCompleted: function(){ - var graph = {nodes:[],edges:[]} + var graph = {nodes:[],edges:[]}; $.each(nodes, function(node){ - graph.nodes.push(nodes[node]) - }) + graph.nodes.push(nodes[node]); + }); $.each(edges, function(edge){ - graph.edges.push(edges[edge]) - }) - emitter.emit('updateLoadingText', "Processing Data") + graph.edges.push(edges[edge]); + }); + emitter.emit('updateLoadingText', "Processing Data"); child.send(JSON.stringify({graph: graph, edge: params.allowCollapse ? appStore.performance.edge : 0 , sibling: params.allowCollapse ? appStore.performance.sibling : 0, start: params.start, end: params.end - })) - session.close() + })); + session.close(); }.bind(this) - }) + }); } createEdgeFromRow(data){ - var id = data.identity.low - var type = data.type - var source = data.start.low - var target = data.end.low + var id = data.identity.low; + var type = data.type; + var source = data.start.low; + var target = data.end.low; var edge = { id: id, type: type, source: source, target:target, label: type - } + }; - return edge + return edge; } createNodeFromRow(data, params){ - var id = data.identity.low - var type = data.labels[0] - var label = data.properties.name + var id = data.identity.low; + var type = data.labels[0]; + var label = data.properties.name; var node = { id: id, type: type, label: label, + Enabled: data.properties.Enabled, glyphs: [], folded: { nodes: [], @@ -471,28 +473,28 @@ export default class GraphContainer extends Component { }, x: Math.random(), y: Math.random() - } + }; if (label === params.start){ - node.start = true + node.start = true; node.glyphs.push({ 'position': 'bottom-right', 'font': 'FontAwesome', 'content': '\uF21D', 'fillColor': '#3399FF', 'fontScale': 1.5 - }) + }); } if (label === params.end){ - node.end = true + node.end = true; node.glyphs.push({ 'position': 'bottom-right', 'font': 'FontAwesome', 'fillColor': '#990000', 'content': '\uF05B', 'fontScale': 1.5 - }) + }); } switch (type) { @@ -510,60 +512,60 @@ export default class GraphContainer extends Component { break; } - return node + return node; } unfoldEdgeNode(id){ - var sigmaInstance = this.state.sigmaInstance - sigmaInstance.graph.read(sigmaInstance.graph.nodes(id).folded) - this.state.design.deprecate() + var sigmaInstance = this.state.sigmaInstance; + sigmaInstance.graph.read(sigmaInstance.graph.nodes(id).folded); + this.state.design.deprecate(); this.state.design.apply(); - this.relayout() + this.relayout(); } foldEdgeNode(id){ - var sigmaInstance = this.state.sigmaInstance + var sigmaInstance = this.state.sigmaInstance; $.each(sigmaInstance.graph.nodes(id).folded.nodes, function(index, node){ - sigmaInstance.graph.dropNode(node.id) - }) - sigmaInstance.refresh() + sigmaInstance.graph.dropNode(node.id); + }); + sigmaInstance.refresh(); this.state.design.deprecate(); this.state.design.apply(); this.relayout(); } ungroupNode(id){ - var sigmaInstance = this.state.sigmaInstance - var node = sigmaInstance.graph.nodes(id) + var sigmaInstance = this.state.sigmaInstance; + var node = sigmaInstance.graph.nodes(id); sigmaInstance.graph.dropNode(id); - sigmaInstance.graph.read(node.folded) - this.state.design.deprecate() - sigmaInstance.refresh() - this.state.design.apply() + sigmaInstance.graph.read(node.folded); + this.state.design.deprecate(); + sigmaInstance.refresh(); + this.state.design.apply(); this.relayout(); } doSearchQuery(payload, props){ if (typeof props === 'undefined'){ - props = {} + props = {}; } this.doQueryNative({ statement: payload, allowCollapse: true, props: props - }) + }); } doPathQuery(start, end){ - var statement = "MATCH (n {name:{start}}), (m {name:{end}}), p=allShortestPaths((n)-[*]->(m)) RETURN p" - var props = {start: start, end: end} + var statement = "MATCH (n {name:{start}}), (m {name:{end}}), p=allShortestPaths((n)-[*]->(m)) RETURN p"; + var props = {start: start, end: end}; this.doQueryNative({ statement: statement, allowCollapse: true, props: props, start: start, end: end - }) + }); } doGenericQuery(statement, props, start, end, allowCollapse=true){ @@ -572,7 +574,7 @@ export default class GraphContainer extends Component { } if (typeof props === 'undefined'){ - props = {} + props = {}; } this.doQueryNative({ statement: statement, @@ -580,26 +582,26 @@ export default class GraphContainer extends Component { start: start, end: end, props: props - }) + }); } _nodeDragged(){ - this.setState({dragged:true}) + this.setState({dragged:true}); } _nodeClicked(n){ if (!this.state.dragged){ if (n.data.node.type_user){ - emitter.emit('userNodeClicked', n.data.node.label) + emitter.emit('userNodeClicked', n.data.node.label); }else if (n.data.node.type_group){ - emitter.emit('groupNodeClicked', n.data.node.label) + emitter.emit('groupNodeClicked', n.data.node.label); }else if (n.data.node.type_computer && (n.data.node.label !== 'Grouped Computers')){ - emitter.emit('computerNodeClicked', n.data.node.label) + emitter.emit('computerNodeClicked', n.data.node.label); }else if (n.data.node.type_domain){ - emitter.emit('domainNodeClicked', n.data.node.label) + emitter.emit('domainNodeClicked', n.data.node.label); } }else{ - this.setState({dragged: false}) + this.setState({dragged: false}); } } @@ -610,7 +612,7 @@ export default class GraphContainer extends Component { { container: 'graph' } - ) + ); sigmaInstance.settings( { @@ -629,7 +631,7 @@ export default class GraphContainer extends Component { zoomingRatio: 1.4, scalingMode: 'inside' } - ) + ); //Bind sigma events sigmaInstance.renderers[0].bind('render', function(e) { @@ -642,21 +644,21 @@ export default class GraphContainer extends Component { }else{ sigmaInstance.settings('drawEdgeLabels', true); } - }) + }); - sigmaInstance.bind('clickNode', this._nodeClicked.bind(this)) + sigmaInstance.bind('clickNode', this._nodeClicked.bind(this)); sigmaInstance.bind('hovers', function(e){ if (e.data.enter.nodes.length > 0) { if (appStore.endNode !== null) { - findGraphPath(this.state.sigmaInstance, false, e.data.enter.nodes[0].id) + findGraphPath(this.state.sigmaInstance, false, e.data.enter.nodes[0].id); } if (appStore.startNode !== null) { - findGraphPath(this.state.sigmaInstance, true, e.data.enter.nodes[0].id) + findGraphPath(this.state.sigmaInstance, true, e.data.enter.nodes[0].id); } - sigmaInstance.refresh({'skipIndexation': true}) + sigmaInstance.refresh({'skipIndexation': true}); } if (e.data.leave.nodes.length > 0) { @@ -668,13 +670,13 @@ export default class GraphContainer extends Component { sigmaInstance.refresh({ 'skipIndexation': true }); } } - }.bind(this)) + }.bind(this)); //Some key binds $(window).on('keyup', function(e){ - var key = e.keyCode ? e.keyCode : e.which - var mode = appStore.performance.nodeLabels - var sigmaInstance = this.state.sigmaInstance + var key = e.keyCode ? e.keyCode : e.which; + var mode = appStore.performance.nodeLabels; + var sigmaInstance = this.state.sigmaInstance; if (document.activeElement === document.body && key === 17){ mode = mode + 1; @@ -682,28 +684,28 @@ export default class GraphContainer extends Component { mode = 0; } appStore.performance.nodeLabels = mode; - conf.set('performance', appStore.performance) + conf.set('performance', appStore.performance); if (mode === 0){ sigmaInstance.settings('labelThreshold', 500); - emitter.emit('showAlert', 'Hiding Node Labels') + emitter.emit('showAlert', 'Hiding Node Labels'); }else if (mode === 1){ sigmaInstance.settings('labelThreshold', 15); - emitter.emit('showAlert', 'Default Node Label Threshold') + emitter.emit('showAlert', 'Default Node Label Threshold'); }else{ sigmaInstance.settings('labelThreshold', 1); - emitter.emit('showAlert', 'Always Showing Node Labels') + emitter.emit('showAlert', 'Always Showing Node Labels'); } - sigmaInstance.refresh({'skipIndexation' : true}) + sigmaInstance.refresh({'skipIndexation' : true}); } - }.bind(this)) + }.bind(this)); //Plugin Configuration var dragListener = sigma.plugins.dragNodes(sigmaInstance, - sigmaInstance.renderers[0]) + sigmaInstance.renderers[0]); - dragListener.bind('drag', this._nodeDragged.bind(this)) + dragListener.bind('drag', this._nodeDragged.bind(this)); var tooltips = sigma.plugins.tooltips( sigmaInstance, @@ -718,7 +720,7 @@ export default class GraphContainer extends Component { node.expand = false; node.collapse = false; if (node.folded.nodes.length > 0 && !node.groupedNode) { - if (typeof this.state.sigmaInstance.graph.nodes(node.folded.nodes[0].id) == 'undefined') { + if (typeof this.state.sigmaInstance.graph.nodes(node.folded.nodes[0].id) === 'undefined') { node.expand = true; } else { node.collapse = true; @@ -753,12 +755,12 @@ export default class GraphContainer extends Component { forcelinkListener.bind('stop', function(event) { emitter.emit('updateLoadingText', "Fixing Overlap"); sigmaInstance.startNoverlap(); - }) + }); forcelinkListener.bind('start', function(event){ - emitter.emit('updateLoadingText', 'Initial Layout') - emitter.emit('showLoadingIndicator', true) - }) + emitter.emit('updateLoadingText', 'Initial Layout'); + emitter.emit('showLoadingIndicator', true); + }); var dagreListener = sigma.layouts.dagre.configure(sigmaInstance, { easing: 'cubicInOut', @@ -774,22 +776,22 @@ export default class GraphContainer extends Component { emitter.emit('updateLoadingText', "Fixing Overlap"); sigmaInstance.startNoverlap(); needsfix = true; - return + return; } }, this); if (!needsfix){ emitter.emit('updateLoadingText', 'Done!'); - sigma.canvas.edges.autoCurve(sigmaInstance) + sigma.canvas.edges.autoCurve(sigmaInstance); setTimeout(function(){ emitter.emit('showLoadingIndicator', false); - }, 1500) + }, 1500); } - }) + }); dagreListener.bind('start', function(event){ - emitter.emit('updateLoadingText', 'Initial Layout') - emitter.emit('showLoadingIndicator', true) - }) + emitter.emit('updateLoadingText', 'Initial Layout'); + emitter.emit('showLoadingIndicator', true); + }); // var noverlapListener = sigmaInstance.configNoverlap({ // nodeMargin: 5.0, @@ -799,19 +801,19 @@ export default class GraphContainer extends Component { // }); // - var noverlapListener = sigmaInstance.configNoverlap({}) + var noverlapListener = sigmaInstance.configNoverlap({}); noverlapListener.bind('stop', function(event) { emitter.emit('updateLoadingText', 'Done!'); - sigma.canvas.edges.autoCurve(sigmaInstance) + sigma.canvas.edges.autoCurve(sigmaInstance); setTimeout(function(){ emitter.emit('showLoadingIndicator', false); - }, 1500) + }, 1500); }); - var lowgfx = appStore.performance.lowGraphics + var lowgfx = appStore.performance.lowGraphics; design = sigma.plugins.design(sigmaInstance); if (lowgfx){ @@ -826,7 +828,7 @@ export default class GraphContainer extends Component { design.setStyles(appStore.highResStyle); } - var mode = appStore.performance.nodeLabels + var mode = appStore.performance.nodeLabels; if (mode === 0){ sigmaInstance.settings('labelThreshold', 500); diff --git a/src/components/Menu/MenuContainer.jsx b/src/components/Menu/MenuContainer.jsx index 391707f..800efe1 100644 --- a/src/components/Menu/MenuContainer.jsx +++ b/src/components/Menu/MenuContainer.jsx @@ -1,284 +1,310 @@ import React, { Component } from 'react'; import MenuButton from './MenuButton'; import ProgressBarMenuButton from './ProgressBarMenuButton'; -import { buildDomainProps, buildSessionProps, buildLocalAdminProps, buildGroupMembershipProps, buildACLProps } from 'utils'; +import { buildDomainProps, buildSessionProps, buildLocalAdminProps, buildGroupMembershipProps, buildACLProps, findObjectType} from 'utils'; import { If, Then, Else } from 'react-if'; -const { dialog, clipboard } = require('electron').remote -var fs = require('fs') -var async = require('async') +const { dialog, clipboard, app } = require('electron').remote; +var fs = require('fs'); +var async = require('async'); +var unzip = require('unzipper'); +var fpath = require('path'); +var csv = require('fast-csv'); export default class MenuContainer extends Component { - constructor(){ - super() + constructor(){ + super(); - this.state = { - refreshHover: false, - uploading: false, - progress: 0, - parser: null - } + this.state = { + refreshHover: false, + uploading: false, + progress: 0, + cancelled: false + }; - emitter.on('cancelUpload', this.cancelUpload.bind(this)) - } + emitter.on('cancelUpload', this.cancelUpload.bind(this)) + } - cancelUpload(){ - this.state.parser.abort() - setTimeout(function(){ - this.setState({uploading: false}) - }.bind(this), 1000) - } + cancelUpload(){ + this.setState({cancelled: true}); + setTimeout(function(){ + this.setState({uploading: false}) + }.bind(this), 1000); + } - _refreshClick(){ - emitter.emit('graphRefresh') - } + _refreshClick(){ + emitter.emit('graphRefresh') + } - _changeLayoutClick(){ - appStore.dagre = !appStore.dagre - emitter.emit('graphRefresh') - var type = appStore.dagre ? 'Hierarchical' : 'Directed' - emitter.emit('showAlert', 'Changed Layout to ' + type) - } + _changeLayoutClick(){ + appStore.dagre = !appStore.dagre + emitter.emit('graphRefresh') + var type = appStore.dagre ? 'Hierarchical' : 'Directed' + emitter.emit('showAlert', 'Changed Layout to ' + type) + } - _exportClick(){ - emitter.emit('showExport'); - } + _exportClick(){ + emitter.emit('showExport'); + } - _importClick(){ - var fname = dialog.showOpenDialog({ - properties: ['openFile'] - }) - if (typeof fname !== 'undefined'){ - emitter.emit('import',fname[0]) - } - } + _importClick(){ + var fname = dialog.showOpenDialog({ + properties: ['openFile'] + }); + if (typeof fname !== 'undefined'){ + emitter.emit('import',fname[0]); + } + } - _settingsClick(){ - emitter.emit('openSettings') - } + _settingsClick(){ + emitter.emit('openSettings') + } - _cancelUploadClick(){ - emitter.emit('showCancelUpload') - } + _cancelUploadClick(){ + emitter.emit('showCancelUpload') + } - _uploadClick(){ - var input = jQuery(this.refs.fileInput) - var files = $.makeArray(input[0].files) + _uploadClick(){ + var input = jQuery(this.refs.fileInput); + var fileNames = []; - async.eachSeries(files, function(file, callback){ - emitter.emit('showAlert', 'Processing file {}'.format(file.name)); - this.processFile(file.path, file, callback) - }.bind(this), - function done(){ - setTimeout(function(){ - this.setState({uploading: false}) - }.bind(this), 3000) - }.bind(this)) + $.each(input[0].files, function(index, file){ + fileNames.push({path:file.path, name:file.name}); + }); - input.val('') - } + this.unzipNecessary(fileNames).then(function(results){ + async.eachSeries(results, function(file, callback){ + emitter.emit('showAlert', 'Processing file {}'.format(file.name)); + this.processFile(file.path, callback); + }.bind(this), + function done(){ + setTimeout(function(){ + this.setState({uploading: false}); + }.bind(this), 3000); + $.each(results, function(index, file){ + if (file.delete){ + fs.unlinkSync(file.path); + } + }); + }.bind(this)); + + input.val(''); + }.bind(this)); + + } - _aboutClick(){ - emitter.emit('showAbout') - } + async unzipNecessary(files){ + var index = 0; + var processed = []; + var tempPath = app.getPath('temp'); + while (index < files.length){ + var path = files[index].path; + var name = files[index].name; - processFile(filename, fileobject, callback){ - var sent = 0 + if (path.endsWith(".zip")){ + await fs.createReadStream(path) + .pipe(unzip.Parse()) + .on('entry', function(entry){ + var output = fpath.join(tempPath, entry.path); + entry.pipe(fs.createWriteStream(output)); + processed.push({path:output, name:entry.path, delete: true}); + }).promise(); + }else{ + processed.push({path:path,name:name, delete: false}); + } + index++; + } - var i; - var count = 0; - var header = "" - var procHeader = true; - fs.createReadStream(filename) - .on('data', function(chunk) { - for (i=0; i < chunk.length; ++i){ - if (procHeader){ - header = header + String.fromCharCode(chunk[i]) - } - if (chunk[i] == 10){ - if (procHeader){ - procHeader = false; - } - count++ - }; - } - - }) - .on('end', function() { - count = count - 1 - var filetype; - if (header.includes('UserName') && header.includes('ComputerName') && header.includes('Weight')){ - filetype = 'sessions' - }else if (header.includes('AccountName') && header.includes('AccountType') && header.includes('GroupName')){ - filetype = 'groupmembership' - }else if (header.includes('AccountName') && header.includes('AccountType') && header.includes('ComputerName')){ - filetype = 'localadmin' - }else if (header.includes('SourceDomain') && header.includes('TargetDomain') && header.includes('TrustDirection') && header.includes('TrustType') && header.includes('Transitive')){ - filetype = 'domain' - }else if (header.includes('ActiveDirectoryRights') && header.includes('ObjectType') && header.includes('PrincipalType')){ - filetype = 'acl' - } + return processed; + } - if (typeof filetype === 'undefined'){ - emitter.emit('showAlert', 'Unrecognized CSV Type'); - return; - } + _aboutClick(){ + emitter.emit('showAbout'); + } + + processFile(file, callback){ + console.log(file); + var count = 0; + var header = ""; + var processHeader = true; + var fileType; + + //Lets calculate the number of lines in the file and get the header + var input = fs.createReadStream(file); + input.on('data', function (chunk){ + for (var i=0; i < chunk.length; ++i){ + if (processHeader){ + header = header + String.fromCharCode(chunk[i]); + } + if (chunk[i] === 10){ + //At the first newline, we look at the header to figure out + if (processHeader){ + processHeader = false; + fileType = findObjectType(header); + if (fileType === 'unknown'){ + emitter.emit('showAlert', 'Unrecognized CSV Type'); + input.close(); + } + } + count++; + } + } + }) + .on('end', function(){ + //We've got our line count for progress + var chunk = []; + var localCount = 0; + var sent = 0; - this.setState({ - uploading: true, - progress: 0 - }) - //I have no idea why this workaround is needed. Apparently all my sessions freeze unless I make a random query - setTimeout(function(){ - var sess = driver.session() - sess.run('MATCH (n) RETURN (n) LIMIT 1') - .then(function(){ - sess.close() - }) - }, 1000) + //Subtract one line to account for the header + count--; + + //Change the UI to display our uploading state + this.setState({ + uploading: true, + progress: 0 + }); - console.time('IngestTime') - Papa.parse(fileobject,{ - header: true, - dynamicTyping: true, - skipEmptyLines: true, - chunkSize: 5242880, - //chunkSize: 500000, - chunk: function(rows, parser){ - this.setState({parser: parser}) - if (rows.data.length === 0){ - console.timeEnd('IngestTime') - parser.abort() - this.setState({progress:100}) - emitter.emit('refreshDBData') - callback() - return - } - parser.pause() - sent += rows.data.length - if (filetype === 'sessions'){ - var query = 'UNWIND {props} AS prop MERGE (user:User {name:prop.account}) WITH user,prop MERGE (computer:Computer {name: prop.computer}) WITH user,computer,prop MERGE (computer)-[:HasSession {Weight : prop.weight}]-(user)' - var props = buildSessionProps(rows.data) - var session = driver.session() - session.run(query, {props: props}) - .then(function(){ - this.setState({progress: Math.floor((sent / count) * 100)}) - session.close() - parser.resume() - }.bind(this)) - }else if (filetype === 'groupmembership'){ - var props = buildGroupMembershipProps(rows.data) - var userQuery = 'UNWIND {props} AS prop MERGE (user:User {name:prop.account}) WITH user,prop MERGE (group:Group {name:prop.group}) WITH user,group MERGE (user)-[:MemberOf]->(group)' - var computerQuery = 'UNWIND {props} AS prop MERGE (computer:Computer {name:prop.account}) WITH computer,prop MERGE (group:Group {name:prop.group}) WITH computer,group MERGE (computer)-[:MemberOf]->(group)' - var groupQuery = 'UNWIND {props} AS prop MERGE (group1:Group {name:prop.account}) WITH group1,prop MERGE (group2:Group {name:prop.group}) WITH group1,group2 MERGE (group1)-[:MemberOf]->(group2)' - - var session = driver.session() - var tx = session.beginTransaction() - var promises = [] + //Start a timer + console.time('IngestTime'); - promises.push(tx.run(userQuery, {props: props.users})) - promises.push(tx.run(computerQuery, {props: props.computers})) - promises.push(tx.run(groupQuery, {props: props.groups})) + //Start parsing the file + var parser = csv.fromStream(fs.createReadStream(file), + { + headers: true, + ignoreEmpty: true + }) + .on('data', function(data){ + //On each row, push it into an array and increment a counter + chunk.push(data); + localCount++; - Promise.all(promises) - .then(function(){ - tx.commit() - .then(function(){ - session.close() - this.setState({progress: Math.floor((sent / count) * 100)}) - parser.resume() - }.bind(this)) - }.bind(this)) - }else if (filetype === 'localadmin'){ - var props = buildLocalAdminProps(rows.data) - var userQuery = 'UNWIND {props} AS prop MERGE (user:User {name: prop.account}) WITH user,prop MERGE (computer:Computer {name: prop.computer}) WITH user,computer MERGE (user)-[:AdminTo]->(computer)' - var groupQuery = 'UNWIND {props} AS prop MERGE (group:Group {name: prop.account}) WITH group,prop MERGE (computer:Computer {name: prop.computer}) WITH group,computer MERGE (group)-[:AdminTo]->(computer)' - var computerQuery = 'UNWIND {props} AS prop MERGE (computer1:Computer {name: prop.account}) WITH computer1,prop MERGE (computer2:Computer {name: prop.computer}) WITH computer1,computer2 MERGE (computer1)-[:AdminTo]->(computer2)' + //If we've collected 10k rows, push it all to the DB. + if (localCount % 10000 === 0){ + //Pause the parser until upload is complete + parser.pause(); + this.uploadData(chunk, fileType, count) + .then(function(){ + //Update the sent number, and resume the parser + sent += chunk.length; + this.setState({progress: Math.floor(sent / count * 100)}); - var session = driver.session() - var tx = session.beginTransaction() - var promises = [] + chunk = []; + parser.resume(); + }.bind(this)); + } + }.bind(this)) + .on('end', function(){ + //Upload any remaining data + this.uploadData(chunk, fileType, count) + .then(function(){ + //Set the uploading state to 100%, refresh the db display, and move on to the next file if there is one + this.setState({progress:100}); + emitter.emit('refreshDBData'); + console.timeEnd('IngestTime'); + callback(); + }.bind(this)); + }.bind(this)); + }.bind(this)); + } + + async uploadData(currentChunk, filetype, total){ + var index = 0; + var processed; + var sent = 0; + var session = driver.session(); - promises.push(tx.run(userQuery, {props: props.users})) - promises.push(tx.run(computerQuery, {props: props.computers})) - promises.push(tx.run(groupQuery, {props: props.groups})) + if (filetype === 'groupmembership'){ + var userQuery = 'UNWIND {props} AS prop MERGE (user:User {name:prop.account}) WITH user,prop MERGE (group:Group {name:prop.group}) WITH user,group MERGE (user)-[:MemberOf {isACL:false}]->(group)'; + var computerQuery = 'UNWIND {props} AS prop MERGE (computer:Computer {name:prop.account}) WITH computer,prop MERGE (group:Group {name:prop.group}) WITH computer,group MERGE (computer)-[:MemberOf {isACL:false}]->(group)'; + var groupQuery = 'UNWIND {props} AS prop MERGE (group1:Group {name:prop.account}) WITH group1,prop MERGE (group2:Group {name:prop.group}) WITH group1,group2 MERGE (group1)-[:MemberOf {isACL:false}]->(group2)'; - Promise.all(promises) - .then(function(){ - tx.commit() - .then(function(){ - session.close() - this.setState({progress: Math.floor((sent / count) * 100)}) - parser.resume() - }.bind(this)) - }.bind(this)) - }else if (filetype === 'domain'){ - var props = buildDomainProps(rows.data) - var query = "UNWIND {props} AS prop MERGE (domain1:Domain {name: prop.domain1}) WITH domain1,prop MERGE (domain2:Domain {name: prop.domain2}) WITH domain1,domain2,prop MERGE (domain1)-[:TrustedBy {TrustType : prop.trusttype, Transitive: prop.transitive}]->(domain2)" - var session = driver.session() - session.run(query, {props: props}) - .then(function(){ - this.setState({progress: Math.floor((sent / count) * 100)}) - session.close() - parser.resume() - }.bind(this)) - }else if (filetype === 'acl'){ - var data = buildACLProps(rows.data) - var promises = [] - var session = driver.session() - var tx = session.beginTransaction() - for (var key in data){ - var promise = tx.run(data[key].statement, {props: data[key].props}) - promises.push(promise) - } + processed = buildGroupMembershipProps(currentChunk); - Promise.all(promises) - .then(function(){ - tx.commit() - .then(function(){ - this.setState({progress: Math.floor((sent / count) * 100)}) - session.close() - parser.resume() - }.bind(this)) - }.bind(this)) - } - }.bind(this) - }) - }.bind(this)); - } + await session.run(userQuery, {props: processed.users}); + await session.run(computerQuery, {props: processed.computers}); + await session.run(groupQuery, {props: processed.groups}); + }else if (filetype === 'localadmin'){ + userQuery = 'UNWIND {props} AS prop MERGE (user:User {name: prop.account}) WITH user,prop MERGE (computer:Computer {name: prop.computer}) WITH user,computer MERGE (user)-[:AdminTo {isACL:false}]->(computer)'; + groupQuery = 'UNWIND {props} AS prop MERGE (group:Group {name: prop.account}) WITH group,prop MERGE (computer:Computer {name: prop.computer}) WITH group,computer MERGE (group)-[:AdminTo {isACL:false}]->(computer)'; + computerQuery = 'UNWIND {props} AS prop MERGE (computer1:Computer {name: prop.account}) WITH computer1,prop MERGE (computer2:Computer {name: prop.computer}) WITH computer1,computer2 MERGE (computer1)-[:AdminTo {isACL:false}]->(computer2)'; - render() { - return ( -
-
- -
-
- -
-
- -
-
- - - - - { () => - - } - -
-
- -
-
- -
-
- -
- -
- ); - } + processed = buildLocalAdminProps(currentChunk); + + await session.run(userQuery, {props: processed.users}); + await session.run(computerQuery, {props: processed.computers}); + await session.run(groupQuery, {props: processed.groups}); + }else if (filetype === 'sessions'){ + var query = 'UNWIND {props} AS prop MERGE (user:User {name:prop.account}) WITH user,prop MERGE (computer:Computer {name: prop.computer}) WITH user,computer,prop MERGE (computer)-[:HasSession {Weight : prop.weight, isACL: false}]-(user)'; + + processed = buildSessionProps(currentChunk); + + await session.run(query, {props: processed}); + }else if (filetype === 'domain'){ + query = "UNWIND {props} AS prop MERGE (domain1:Domain {name: prop.domain1}) WITH domain1,prop MERGE (domain2:Domain {name: prop.domain2}) WITH domain1,domain2,prop MERGE (domain1)-[:TrustedBy {TrustType : prop.trusttype, Transitive: toBoolean(prop.transitive), isACL:false}]->(domain2)"; + + processed = buildDomainProps(currentChunk); + + await session.run(query, {props: processed}); + }else if (filetype === 'acl'){ + processed = buildACLProps(currentChunk); + + for (var key in processed){ + await session.run(processed[key].statement, {props: processed[key].props}); + } + }else if (filetype === 'userprops'){ + $.each(currentChunk, function(index, obj){ + var spn = obj.ServicePrincipalNames; + var sh = obj.SidHistory; + + if (spn === ""){ + obj.ServicePrincipalNames = []; + }else{ + obj.ServicePrincipalNames = spn.split('|'); + } + }); + query = 'UNWIND {props} AS prop MERGE (user:User {name: upper(prop.AccountName)}) SET user.Enabled = toBoolean(prop.Enabled),user.PwdLastSet = toInt(prop.PwdLastSet),user.LastLogon = toInt(prop.LastLogon),user.Sid = prop.Sid,user.SidHistory = prop.SidHistory,user.HasSPN = toBoolean(prop.HasSPN),user.DisplayName=prop.DisplayName,user.ServicePrincipalNames = prop.ServicePrincipalNames,user.Email=prop.Email'; + + await session.run(query, {props:currentChunk}); + }else if (filetype === 'compprops'){ + query = 'UNWIND {props} AS prop MERGE (comp:Computer {name: upper(prop.AccountName)}) SET comp.Enabled=toBoolean(prop.Enabled),comp.PwdLastSet=toInt(prop.PwdLastSet),comp.LastLogon=toInt(prop.LastLogon),comp.OperatingSystem=prop.OperatingSystem,comp.Sid=prop.Sid,comp.UnconstrainedDelegation=toBoolean(prop.UnconstrainedDelegation)'; + + await session.run(query, {props:currentChunk}); + } + } + + render() { + return ( +
+
+ +
+
+ +
+
+ +
+
+ + + + + { () => + + } + +
+
+ +
+
+ +
+
+ +
+ +
+ ); + } } diff --git a/src/components/Menu/ProgressBarMenuButton.jsx b/src/components/Menu/ProgressBarMenuButton.jsx index 089f709..5ca0553 100644 --- a/src/components/Menu/ProgressBarMenuButton.jsx +++ b/src/components/Menu/ProgressBarMenuButton.jsx @@ -1,80 +1,80 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types' +import PropTypes from 'prop-types'; export default class ProgressBarMenuButton extends Component { - constructor(){ - super() + constructor(){ + super(); - this.state = { - expanded: false - } - } + this.state = { + expanded: false + }; + } - _leave(e){ - this.setState({expanded: false}) - var target = $(e.target) - var oldWidth = target.width() - target.html('{}%'.format(this.props.progress)) - target.animate({ - width: '41px' - }, 100) - } + componentDidMount(){ + $(this.refs.btn).html('{}%'.format(this.props.progress)); + $(this.refs.btn).css('padding','6px 0px 6px 0px'); + $(this.refs.btn).css('width','41px'); + } - _enter(e){ - this.setState({expanded: true}) - var target = $(e.target) - var oldWidth = target.width() - var template = ` -
-
-
- - {}% - -
- `.formatAll(this.props.progress) - - target.html(template) - target.animate({ - width: '150px' - }, 100) - } + componentWillReceiveProps(nextProps){ + if (this.state.expanded){ + var template = `
+
+
+ + {}% + +
`.formatAll(nextProps.progress); + $(this.refs.btn).html(template); + }else{ + $(this.refs.btn).html('{}%'.format(nextProps.progress)); + } - componentWillReceiveProps(nextProps){ - if (this.state.expanded){ - var template = `
-
-
- - {}% - -
`.formatAll(nextProps.progress) - $(this.refs.btn).html(template) - }else{ - $(this.refs.btn).html('{}%'.format(nextProps.progress)) - } + this.forceUpdate(); + } - this.forceUpdate() - } + shouldComponentUpdate(nextProps, nextState){ + return true; + } - shouldComponentUpdate(nextProps, nextState){ - return true - } + _leave(e){ + this.setState({expanded: false}); + var target = $(e.target); + var oldWidth = target.width(); + target.html('{}%'.format(this.props.progress)); + target.animate({ + width: '41px' + }, 100); + } - componentDidMount(){ - $(this.refs.btn).html('{}%'.format(this.props.progress)) - $(this.refs.btn).css('padding','6px 0px 6px 0px') - $(this.refs.btn).css('width','41px') - } + _enter(e){ + this.setState({expanded: true}); + var target = $(e.target); + var oldWidth = target.width(); + var template = ` +
+
+
+ + {}% + +
+ `.formatAll(this.props.progress); + + target.html(template); + target.animate({ + width: '150px' + }, 100); + } - render() { - return ( -
- ) + ); } } \ No newline at end of file diff --git a/src/components/SearchContainer/Tabs/ComputerNodeData.jsx b/src/components/SearchContainer/Tabs/ComputerNodeData.jsx index d58b5d3..6d4f569 100644 --- a/src/components/SearchContainer/Tabs/ComputerNodeData.jsx +++ b/src/components/SearchContainer/Tabs/ComputerNodeData.jsx @@ -1,344 +1,386 @@ import React, { Component } from 'react'; -import NodeALink from './NodeALink' -import PropTypes from 'prop-types' +import NodeALink from './NodeALink'; +import PropTypes from 'prop-types'; export default class ComputerNodeData extends Component { - constructor(){ - super(); + constructor(){ + super(); - this.state = { - label: "", - os: "None", - unconstrained: "None", - explicitAdmins: -1, - unrolledAdmins: -1, - firstDegreeGroupMembership: -1, - unrolledGroupMembership: -1, - firstDegreeLocalAdmin: -1, - groupDelegatedLocalAdmin: -1, - derivativeLocalAdmin: -1, - sessions: -1, - firstdegreeControl: -1, - groupDelegatedControl: -1, - transitiveControl: -1, - derivativeLocalAdmins: -1, - driversessions: [] - } + this.state = { + label: "", + explicitAdmins: -1, + unrolledAdmins: -1, + firstDegreeGroupMembership: -1, + unrolledGroupMembership: -1, + firstDegreeLocalAdmin: -1, + groupDelegatedLocalAdmin: -1, + derivativeLocalAdmin: -1, + sessions: -1, + firstdegreeControl: -1, + groupDelegatedControl: -1, + transitiveControl: -1, + derivativeLocalAdmins: -1, + driversessions: [], + propertyMap: {} + }; - emitter.on('computerNodeClicked', this.getNodeData.bind(this)); - } + emitter.on('computerNodeClicked', this.getNodeData.bind(this)); + } - getNodeData(payload){ - $.each(this.state.driversessions, function(index, record){ - record.close(); - }) - this.setState({ - label: payload, - os: "None", - unconstrained: "None", - explicitAdmins: -1, - unrolledAdmins: -1, - firstDegreeGroupMembership: -1, - unrolledGroupMembership: -1, - sessions: -1, - firstDegreeLocalAdmin: -1, - groupDelegatedLocalAdmin: -1, - derivativeLocalAdmin: -1, - firstdegreeControl: -1, - groupDelegatedControl: -1, - transitiveControl: -1, - derivativeLocalAdmins: -1 - }) + getNodeData(payload){ + $.each(this.state.driversessions, function(index, record){ + record.close(); + }); + this.setState({ + label: payload, + explicitAdmins: -1, + unrolledAdmins: -1, + firstDegreeGroupMembership: -1, + unrolledGroupMembership: -1, + sessions: -1, + firstDegreeLocalAdmin: -1, + groupDelegatedLocalAdmin: -1, + derivativeLocalAdmin: -1, + firstdegreeControl: -1, + groupDelegatedControl: -1, + transitiveControl: -1, + derivativeLocalAdmins: -1, + propertyMap: {} + }); - var s1 = driver.session() - var s2 = driver.session() - var s3 = driver.session() - var s4 = driver.session() - var s5 = driver.session() - var s6 = driver.session() - var s7 = driver.session() - var s8 = driver.session() - var s9 = driver.session() - var s10 = driver.session() - var s11 = driver.session() - var s12 = driver.session() - var s13 = driver.session() + var s1 = driver.session(); + var s2 = driver.session(); + var s3 = driver.session(); + var s4 = driver.session(); + var s5 = driver.session(); + var s6 = driver.session(); + var s7 = driver.session(); + var s8 = driver.session(); + var s9 = driver.session(); + var s10 = driver.session(); + var s11 = driver.session(); + var s12 = driver.session(); + var s13 = driver.session(); - s1.run("MATCH (a)-[b:AdminTo]->(c:Computer {name:{name}}) RETURN count(a)", {name:payload}) - .then(function(result){ - this.setState({'explicitAdmins':result.records[0]._fields[0].low}) - s1.close() - }.bind(this)) + var propCollection = driver.session(); + propCollection.run("MATCH (c:Computer {name:{name}}) RETURN c", {name:payload}) + .then(function(result){ + var properties = result.records[0]._fields[0].properties; + this.setState({propertyMap: properties}); + propCollection.close(); + }.bind(this)); - s2.run("MATCH p=(n:User)-[r:MemberOf|AdminTo*1..]->(m:Computer {name:{name}}) RETURN count(distinct(n))", {name:payload}) - .then(function(result){ - this.setState({'unrolledAdmins':result.records[0]._fields[0].low}) - s2.close() - }.bind(this)) + s1.run("MATCH (a)-[b:AdminTo]->(c:Computer {name:{name}}) RETURN count(a)", {name:payload}) + .then(function(result){ + this.setState({'explicitAdmins':result.records[0]._fields[0].low}); + s1.close(); + }.bind(this)); - s3.run("MATCH (m:Computer {name:{name}}), (n:Computer), (m)-[r:AdminTo]->(n) RETURN count(distinct(m))", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low}) - s3.close() - }.bind(this)) + s2.run("MATCH p=(n:User)-[r:MemberOf|AdminTo*1..]->(m:Computer {name:{name}}) RETURN count(distinct(n))", {name:payload}) + .then(function(result){ + this.setState({'unrolledAdmins':result.records[0]._fields[0].low}); + s2.close(); + }.bind(this)); - s4.run("MATCH p=(n:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c2:Computer) RETURN count(c2)", {name:payload}) - .then(function(result){ - this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low}) - s4.close() - }.bind(this)) + s3.run("MATCH (m:Computer {name:{name}}), (n:Computer), (m)-[r:AdminTo]->(n) RETURN count(distinct(m))", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low}); + s3.close(); + }.bind(this)); - s5.run("MATCH (n:Computer {name:{name}}), (m:Computer), p=shortestPath((n)-[r:AdminTo|MemberOf*1..]->(m)) RETURN count(distinct(m))", {name:payload}) - .then(function(result){ - this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low}) - s5.close() - }.bind(this)) + s4.run("MATCH p=(n:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c2:Computer) RETURN count(c2)", {name:payload}) + .then(function(result){ + this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low}); + s4.close(); + }.bind(this)); - s6.run("MATCH (n:Computer {name:{name}}),(target:Group), (n)-[r:MemberOf]->(target) RETURN count(target)", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low}) - s6.close() - }.bind(this)) + s5.run("MATCH (n:Computer {name:{name}}), (m:Computer) WHERE NOT m.name={name} MATCH p=shortestPath((n)-[r:AdminTo|MemberOf*1..]->(m)) RETURN count(distinct(m))", {name:payload}) + .then(function(result){ + this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low}); + s5.close(); + }.bind(this)); - s7.run("MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload}) - .then(function(result){ - this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low}) - s7.close() - }.bind(this)) + s6.run("MATCH (n:Computer {name:{name}}),(target:Group), (n)-[r:MemberOf]->(target) RETURN count(target)", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low}); + s6.close(); + }.bind(this)); - s8.run("MATCH (m:Computer {name:{name}})-[r:HasSession]->(n:User) WITH n,r,m WHERE NOT n.name ENDS WITH '$' RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'sessions':result.records[0]._fields[0].low}) - s8.close() - }.bind(this)) + s7.run("MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload}) + .then(function(result){ + this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low}); + s7.close(); + }.bind(this)); - s9.run("MATCH p = shortestPath((n)-[r:AdminTo|MemberOf|HasSession*1..]->(m:Computer {name:{name}})) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'derivativeLocalAdmins':result.records[0]._fields[0].low}) - s9.close() - }.bind(this)) + s8.run("MATCH (m:Computer {name:{name}})-[r:HasSession]->(n:User) WITH n,r,m WHERE NOT n.name ENDS WITH '$' RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'sessions':result.records[0]._fields[0].low}); + s8.close(); + }.bind(this)); - s10.run("MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) WHERE NOT g.domain = c.domain RETURN COUNT(DISTINCT(g))", {name:payload}) - .then(function(result){ - this.setState({'foreignGroupMembership':result.records[0]._fields[0].low}) - s10.close() - }.bind(this)) + s9.run("MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((n)-[r:AdminTo|MemberOf|HasSession*1..]->(m:Computer {name:{name}})) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'derivativeLocalAdmins':result.records[0]._fields[0].low}); + s9.close(); + }.bind(this)); - s11.run("MATCH p = (c:Computer {name:{name}})-[r:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'firstdegreeControl':result.records[0]._fields[0].low}) - s11.close() - }.bind(this)) + s10.run("MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) WHERE NOT g.domain = c.domain RETURN COUNT(DISTINCT(g))", {name:payload}) + .then(function(result){ + this.setState({'foreignGroupMembership':result.records[0]._fields[0].low}); + s10.close(); + }.bind(this)); - s12.run("MATCH p = (c:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'groupDelegatedControl':result.records[0]._fields[0].low}) - s12.close() - }.bind(this)) + s11.run("MATCH p = (c:Computer {name:{name}})-[r:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'firstdegreeControl':result.records[0]._fields[0].low}); + s11.close(); + }.bind(this)); - s13.run("MATCH p = shortestPath((c:Computer {name:{name}})-[r:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'transitiveControl':result.records[0]._fields[0].low}) - s13.close() - }.bind(this)) - - this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13]}) - } + s12.run("MATCH p = (c:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'groupDelegatedControl':result.records[0]._fields[0].low}); + s12.close(); + }.bind(this)); - render() { - return ( -
-
-

Node Info

-
- Name -
-
- {this.state.label} -
-
- OS -
-
- {this.state.os} -
-
- Allows Unconstrained Delegation -
-
- {this.state.unconstrained} -
-
- Sessions -
-
- (n:User) WITH n,r,m WHERE NOT n.name ENDS WITH '$' RETURN n,r,m", {name: this.state.label}) - }.bind(this)} /> -
-
-

Local Admins

-
- Explicit Admins -
-
- (m:Computer {name:{name}}) RETURN n,r,m",{name: this.state.label}) - }.bind(this)} /> -
-
- Unrolled Admins -
-
- (g:Group)-[r2:AdminTo]->(c:Computer {name:{name}}) RETURN p", - {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
- Derivative Local Admins -
-
- (m:Computer {name:{name}})) RETURN p",{name: this.state.label}, this.state.label) - }.bind(this)} /> -
-
-

Group Memberships

-
- First Degree Group Membership -
-
- (m) RETURN n,r,m",{name: this.state.label}, this.state.label) - }.bind(this)} /> -
-
- Unrolled Group Membership -
-
- (m:Group) RETURN p",{name: this.state.label}, this.state.label) - }.bind(this)} /> -
-
- Foreign Group Membership -
-
- (g:Group) WHERE NOT g.domain = c.domain RETURN p",{name: this.state.label}, this.state.label) - }.bind(this)} /> -
-
-

Local Admin Rights

-
- First Degree Local Admin -
-
- (m) RETURN p",{name: this.state.label}, this.state.label) - }.bind(this)} /> -
-
- Group Delegated Local Admin -
-
- (g:Group)-[r2:AdminTo]->(m:Computer) RETURN p",{name: this.state.label}, this.state.label) - }.bind(this)} /> -
-
- Derivative Local Admin -
-
- (c:Computer)) RETURN p",{name: this.state.label}, this.state.label) - }.bind(this)} /> -
-
-

Outbound Object Control

-
- First Degree Object Control -
-
- (n) RETURN p", {name:this.state.label}) - }.bind(this)} /> -
-
- Group Delegated Object Control -
-
- (g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Transitive Object Control -
-
- (n)) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
-
- ); - } + s13.run("MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((c:Computer {name:{name}})-[r:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'transitiveControl':result.records[0]._fields[0].low}); + s13.close(); + }.bind(this)); + + this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,propCollection]}); + } + + convertToDisplayProp(propName){ + var obj = this.state.propertyMap[propName]; + var type = typeof obj; + if (type === 'undefined'){ + return "No Data"; + }else if (obj.hasOwnProperty('low')){ + var t = obj.low; + if (t === 0){ + return "Never"; + }else{ + return new Date(obj.low * 1000).toUTCString(); + } + }else if (type === 'boolean'){ + return obj.toString().toTitleCase(); + }else if (obj === ""){ + return "None"; + }else{ + return obj; + } + } + + render() { + return ( +
+
+

Node Info

+
+ Name +
+
+ {this.state.label} +
+
+ OS +
+
+ {this.convertToDisplayProp("OperatingSystem")} +
+
+ Enabled +
+
+ {this.convertToDisplayProp("Enabled")} +
+
+ Allows Unconstrained Delegation +
+
+ {this.convertToDisplayProp("UnconstrainedDelegation")} +
+
+ Sessions +
+
+ (n:User) WITH n,r,m WHERE NOT n.name ENDS WITH '$' RETURN n,r,m", {name: this.state.label}); + }.bind(this)} + /> +
+

Local Admins

+
+ Explicit Admins +
+
+ (m:Computer {name:{name}}) RETURN n,r,m",{name: this.state.label}); + }.bind(this)} + /> +
+
+ Unrolled Admins +
+
+ (g:Group)-[r2:AdminTo]->(c:Computer {name:{name}}) RETURN p", + {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+
+ Derivative Local Admins +
+
+ (m:Computer {name:{name}})) RETURN p",{name: this.state.label}, this.state.label); + }.bind(this)} + /> +
+

Group Memberships

+
+ First Degree Group Membership +
+
+ (m) RETURN n,r,m",{name: this.state.label}, this.state.label); + }.bind(this)} + /> +
+
+ Unrolled Group Membership +
+
+ (m:Group) RETURN p",{name: this.state.label}, this.state.label); + }.bind(this)} + /> +
+
+ Foreign Group Membership +
+
+ (g:Group) WHERE NOT g.domain = c.domain RETURN p",{name: this.state.label}, this.state.label); + }.bind(this)} + /> +
+

Local Admin Rights

+
+ First Degree Local Admin +
+
+ (m) RETURN p",{name: this.state.label}, this.state.label); + }.bind(this)} + /> +
+
+ Group Delegated Local Admin +
+
+ (g:Group)-[r2:AdminTo]->(m:Computer) RETURN p",{name: this.state.label}, this.state.label); + }.bind(this)} + /> +
+
+ Derivative Local Admin +
+
+ (c)) RETURN p",{name: this.state.label}, this.state.label); + }.bind(this)} + /> +
+

Outbound Object Control

+
+ First Degree Object Control +
+
+ (n) RETURN p", {name:this.state.label}); + }.bind(this)} + /> +
+
+ Group Delegated Object Control +
+
+ (g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Transitive Object Control +
+
+ (n)) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+
+ ); + } } ComputerNodeData.propTypes= { - visible : React.PropTypes.bool.isRequired -} + visible : React.PropTypes.bool.isRequired +}; diff --git a/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx b/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx index 3da5a5a..105d327 100644 --- a/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx +++ b/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx @@ -2,121 +2,134 @@ import React, { Component } from 'react'; import LogoutModal from 'modals/LogoutModal'; export default class DatabaseDataDisplay extends Component { - constructor(){ - super() - this.state = { - url: appStore.databaseInfo.url, - user: appStore.databaseInfo.user, - num_users: 'Refreshing', - num_computers: 'Refreshing', - num_groups: 'Refreshing', - num_relationships: 'Refreshing', - num_sessions: 'Refreshing', - interval: null - } - } + constructor(){ + super(); + this.state = { + url: appStore.databaseInfo.url, + user: appStore.databaseInfo.user, + num_users: 'Refreshing', + num_computers: 'Refreshing', + num_groups: 'Refreshing', + num_relationships: 'Refreshing', + num_sessions: 'Refreshing', + num_acls: 'Refreshing', + interval: null + }; + } - componentDidMount() { - this.refreshDBData() - var x = setInterval(function(){ - this.refreshDBData() - }.bind(this), 60000); - this.setState({ - interval: x - }) - emitter.on('hideDBClearModal', this.refreshDBData.bind(this)) - emitter.on('refreshDBData', this.refreshDBData.bind(this)) - } + componentDidMount() { + this.refreshDBData(); + emitter.on('hideDBClearModal', this.refreshDBData.bind(this)); + emitter.on('refreshDBData', this.refreshDBData.bind(this)); + this.createInterval(); + } - componentWillUnmount() { - clearInterval(this.state.interval) - this.setState({ - interval: null, - session: null - }) - } + componentWillUnmount() { + clearInterval(this.state.interval); + this.setState({ + interval: null, + session: null + }); + } - toggleLogoutModal(){ - emitter.emit('showLogout'); - } + createInterval(){ + var x = setInterval(function(){ + this.refreshDBData(); + }.bind(this), 60000); + this.setState({ + interval: x + }); + }; - toggleDBWarnModal(){ - emitter.emit('openDBWarnModal') - } + toggleLogoutModal(){ + emitter.emit('showLogout'); + } - toggleSessionClearModal(){ - emitter.emit('openSessionClearModal') - } - + toggleDBWarnModal(){ + emitter.emit('openDBWarnModal'); + } - render() { - return ( -
-

Database Info

-
-
DB Address
-
{this.state.url}
-
DB User
-
{this.state.user}
-
Users
-
{this.state.num_users}
-
Computers
-
{this.state.num_computers}
-
Groups
-
{this.state.num_groups}
-
Sessions
-
{this.state.num_sessions}
-
Relationships
-
{this.state.num_relationships}
-
+ toggleSessionClearModal(){ + emitter.emit('openSessionClearModal'); + } -
-
- - - - -
-
-
- ); - } + refreshDBData(){ + var s1 = driver.session(); + var s2 = driver.session(); + var s3 = driver.session(); + var s4 = driver.session(); + var s5 = driver.session(); + var s6 = driver.session(); - refreshDBData(){ - var s1 = driver.session() - var s2 = driver.session() - var s3 = driver.session() - var s4 = driver.session() - var s5 = driver.session() + s1.run("MATCH (n:User) WHERE NOT n.name ENDS WITH '$' RETURN count(n)") + .then(function(result){ + this.setState({'num_users':result.records[0]._fields[0].low}); + s1.close(); + }.bind(this)); + + s2.run("MATCH (n:Group) RETURN count(n)") + .then(function(result){ + this.setState({'num_groups':result.records[0]._fields[0].low}); + s2.close(); + }.bind(this)); + + s3.run("MATCH (n:Computer) RETURN count(n)") + .then(function(result){ + this.setState({'num_computers':result.records[0]._fields[0].low}); + s3.close(); + }.bind(this)); - s1.run("MATCH (n:User) WHERE NOT n.name ENDS WITH '$' RETURN count(n)") - .then(function(result){ - this.setState({'num_users':result.records[0]._fields[0].low}) - s1.close() - }.bind(this)) - - s2.run("MATCH (n:Group) RETURN count(n)") - .then(function(result){ - this.setState({'num_groups':result.records[0]._fields[0].low}) - s2.close() - }.bind(this)) - - s3.run("MATCH (n:Computer) RETURN count(n)") - .then(function(result){ - this.setState({'num_computers':result.records[0]._fields[0].low}) - s3.close() - }.bind(this)) + s4.run("MATCH ()-[r:HasSession]->() RETURN count(r)") + .then(function(result){ + this.setState({'num_sessions':result.records[0]._fields[0].low}); + s4.close(); + }.bind(this)); + + s6.run("MATCH ()-[r {isACL: true}]->() RETURN count(r)") + .then(function(result){ + this.setState({'num_acls':result.records[0]._fields[0].low}); + s6.close(); + }.bind(this)); - s4.run("MATCH ()-[r:HasSession]->() RETURN count(r)") - .then(function(result){ - this.setState({'num_sessions':result.records[0]._fields[0].low}) - s4.close() - }.bind(this)) + s5.run("MATCH ()-[r]->() RETURN count(r)") + .then(function(result){ + this.setState({'num_relationships':result.records[0]._fields[0].low}); + s5.close(); + }.bind(this)); + } + + render() { + return ( +
+

Database Info

+
+
DB Address
+
{this.state.url}
+
DB User
+
{this.state.user}
+
Users
+
{this.state.num_users}
+
Computers
+
{this.state.num_computers}
+
Groups
+
{this.state.num_groups}
+
Sessions
+
{this.state.num_sessions}
+
ACLs
+
{this.state.num_acls}
+
Relationships
+
{this.state.num_relationships}
+
- s5.run("MATCH ()-[r]->() RETURN count(r)") - .then(function(result){ - this.setState({'num_relationships':result.records[0]._fields[0].low}) - s5.close() - }.bind(this)) - } +
+
+ + + + +
+
+
+ ); + } } diff --git a/src/components/SearchContainer/Tabs/DomainNodeData.jsx b/src/components/SearchContainer/Tabs/DomainNodeData.jsx index 8c28cb9..4a9c386 100644 --- a/src/components/SearchContainer/Tabs/DomainNodeData.jsx +++ b/src/components/SearchContainer/Tabs/DomainNodeData.jsx @@ -1,233 +1,243 @@ import React, { Component } from 'react'; -import NodeALink from './NodeALink.jsx' -import LoadLabel from './LoadLabel.jsx' -import PropTypes from 'prop-types' +import NodeALink from './NodeALink.jsx'; +import LoadLabel from './LoadLabel.jsx'; +import PropTypes from 'prop-types'; export default class DomainNodeData extends Component { - constructor(){ - super(); + constructor(){ + super(); - this.state = { - label: "", - users: -1, - groups: -1, - computers: -1, - foreignGroups: -1, - foreignUsers: -1, - firstDegreeOutboundTrusts: -1, - effectiveOutboundTrusts: -1, - firstDegreeInboundTrusts: -1, - effectiveInboundTrusts: -1, - driversessions: [] - } + this.state = { + label: "", + users: -1, + groups: -1, + computers: -1, + foreignGroups: -1, + foreignUsers: -1, + firstDegreeOutboundTrusts: -1, + effectiveOutboundTrusts: -1, + firstDegreeInboundTrusts: -1, + effectiveInboundTrusts: -1, + driversessions: [] + }; - emitter.on('domainNodeClicked', this.getNodeData.bind(this)); - } + emitter.on('domainNodeClicked', this.getNodeData.bind(this)); + } - getNodeData(payload){ - $.each(this.state.driversessions, function(index, record){ - record.close(); - }) - this.setState({ - label: payload, - users: -1, - groups: -1, - computers: -1, - foreignGroups: -1, - foreignUsers: -1, - firstDegreeOutboundTrusts: -1, - effectiveOutboundTrusts: -1, - firstDegreeInboundTrusts: -1, - effectiveInboundTrusts: -1 - }) + getNodeData(payload){ + $.each(this.state.driversessions, function(index, record){ + record.close(); + }); + this.setState({ + label: payload, + users: -1, + groups: -1, + computers: -1, + foreignGroups: -1, + foreignUsers: -1, + firstDegreeOutboundTrusts: -1, + effectiveOutboundTrusts: -1, + firstDegreeInboundTrusts: -1, + effectiveInboundTrusts: -1 + }); - var s1 = driver.session() - var s2 = driver.session() - var s3 = driver.session() - var s4 = driver.session() - var s5 = driver.session() - var s6 = driver.session() - var s7 = driver.session() - var s8 = driver.session() - var s9 = driver.session() + var s1 = driver.session(); + var s2 = driver.session(); + var s3 = driver.session(); + var s4 = driver.session(); + var s5 = driver.session(); + var s6 = driver.session(); + var s7 = driver.session(); + var s8 = driver.session(); + var s9 = driver.session(); - s1.run("MATCH (a:User) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload}) - .then(function(result){ - this.setState({'users':result.records[0]._fields[0].low}) - s1.close() - }.bind(this)) + s1.run("MATCH (a:User) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload}) + .then(function(result){ + this.setState({'users':result.records[0]._fields[0].low}); + s1.close(); + }.bind(this)); - s2.run("MATCH (a:Group) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload}) - .then(function(result){ - this.setState({'groups':result.records[0]._fields[0].low}) - s2.close() - }.bind(this)) + s2.run("MATCH (a:Group) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload}) + .then(function(result){ + this.setState({'groups':result.records[0]._fields[0].low}); + s2.close(); + }.bind(this)); - s3.run("MATCH (n:Computer) WHERE n.name ENDS WITH {name} WITH n WHERE size(split(n.name,'.')) - size(split({name},'.')) = 1 RETURN count(n)", {name:payload}) - .then(function(result){ - this.setState({'computers':result.records[0]._fields[0].low}) - s3.close() - }.bind(this)) + s3.run("MATCH (n:Computer) WHERE n.name ENDS WITH {name} WITH n WHERE size(split(n.name,'.')) - size(split({name},'.')) = 1 RETURN count(n)", {name:payload}) + .then(function(result){ + this.setState({'computers':result.records[0]._fields[0].low}); + s3.close(); + }.bind(this)); - s4.run("MATCH (a:Group) WHERE NOT a.name ENDS WITH ('@' + {name}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {name}) WITH a,b MATCH (a)-[r:MemberOf]->(b) RETURN count(a)", {name:payload}) - .then(function(result){ - this.setState({'foreignGroups':result.records[0]._fields[0].low}) - s4.close() - }.bind(this)) + s4.run("MATCH (a:Group) WHERE NOT a.name ENDS WITH ('@' + {name}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {name}) WITH a,b MATCH (a)-[r:MemberOf]->(b) RETURN count(a)", {name:payload}) + .then(function(result){ + this.setState({'foreignGroups':result.records[0]._fields[0].low}); + s4.close(); + }.bind(this)); - s5.run("MATCH (a:User) WHERE NOT a.name ENDS WITH ('@' + {name}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {name}) WITH a,b MATCH (a)-[r:MemberOf]->(b) RETURN count(a)", {name:payload}) - .then(function(result){ - this.setState({'foreignUsers':result.records[0]._fields[0].low}) - s5.close() - }.bind(this)) + s5.run("MATCH (a:User) WHERE NOT a.name ENDS WITH ('@' + {name}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {name}) WITH a,b MATCH (a)-[r:MemberOf]->(b) RETURN count(a)", {name:payload}) + .then(function(result){ + this.setState({'foreignUsers':result.records[0]._fields[0].low}); + s5.close(); + }.bind(this)); - s6.run("MATCH (a:Domain {name:{name}})<-[r:TrustedBy]-(b:Domain) RETURN count(b)", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeInboundTrusts':result.records[0]._fields[0].low}) - s6.close() - }.bind(this)) + s6.run("MATCH (a:Domain {name:{name}})<-[r:TrustedBy]-(b:Domain) RETURN count(b)", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeInboundTrusts':result.records[0]._fields[0].low}); + s6.close(); + }.bind(this)); - s7.run("MATCH (a:Domain {name:{name}})-[r:TrustedBy]->(b:Domain) RETURN count(b)", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeOutboundTrusts':result.records[0]._fields[0].low}) - s7.close() - }.bind(this)) + s7.run("MATCH (a:Domain {name:{name}})-[r:TrustedBy]->(b:Domain) RETURN count(b)", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeOutboundTrusts':result.records[0]._fields[0].low}); + s7.close(); + }.bind(this)); - s8.run("MATCH p=shortestPath((a:Domain {name:{name}})<-[r:TrustedBy*1..]-(b:Domain)) RETURN count(b)", {name:payload}) - .then(function(result){ - this.setState({'effectiveInboundTrusts':result.records[0]._fields[0].low}) - s8.close() - }.bind(this)) + s8.run("MATCH (b:Domain) WHERE NOT b.name={name} WITH b MATCH p=shortestPath((a:Domain {name:{name}})<-[r:TrustedBy*1..]-(b)) RETURN count(b)", {name:payload}) + .then(function(result){ + this.setState({'effectiveInboundTrusts':result.records[0]._fields[0].low}); + s8.close(); + }.bind(this)); - s9.run("MATCH p=shortestPath((a:Domain {name:{name}})-[r:TrustedBy*1..]->(b:Domain)) RETURN count(b)", {name:payload}) - .then(function(result){ - this.setState({'effectiveOutboundTrusts':result.records[0]._fields[0].low}) - s9.close() - }.bind(this)) - - this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9]}) - } + s9.run("MATCH (b:Domain) WHERE NOT b.name={name} MATCH p=shortestPath((a:Domain {name:{name}})-[r:TrustedBy*1..]->(b)) RETURN count(b)", {name:payload}) + .then(function(result){ + this.setState({'effectiveOutboundTrusts':result.records[0]._fields[0].low}); + s9.close(); + }.bind(this)); + + this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9]}); + } - render() { - return ( -
-
-
- Node -
-
- {this.state.label} -
-
-
- Users -
-
- -
-
- Groups -
-
- -
-
- Computers -
-
- -
-
-
- Foreign Users -
-
- -
-
- Foreign Groups -
-
- -
-
- Foreign Admins -
-
- -
-
-
- Inbound Trusts -
-
- -
-
- Effective Inbound Trusts -
-
- -
-
- Outbound Trusts -
-
- (b:Domain) RETURN a,r,b", {domain: this.state.label}) - }.bind(this)} /> -
-
- Effective Outbound Trusts -
-
- (b:Domain)) RETURN p", {domain: this.state.label}) - }.bind(this)} /> -
-
-
- ); - } + render() { + return ( +
+
+
+ Node +
+
+ {this.state.label} +
+
+
+ Users +
+
+ +
+
+ Groups +
+
+ +
+
+ Computers +
+
+ +
+
+
+ Foreign Users +
+
+ +
+
+ Foreign Groups +
+
+ +
+
+ Foreign Admins +
+
+ +
+
+
+ Inbound Trusts +
+
+ +
+
+ Effective Inbound Trusts +
+
+ +
+
+ Outbound Trusts +
+
+ (b:Domain) RETURN a,r,b", {domain: this.state.label}); + }.bind(this)} + /> +
+
+ Effective Outbound Trusts +
+
+ (b:Domain)) RETURN p", {domain: this.state.label}); + }.bind(this)} + /> +
+
+
+ ); + } } DomainNodeData.propTypes = { - visible : React.PropTypes.bool.isRequired -} \ No newline at end of file + visible : React.PropTypes.bool.isRequired +}; \ No newline at end of file diff --git a/src/components/SearchContainer/Tabs/GroupNodeData.jsx b/src/components/SearchContainer/Tabs/GroupNodeData.jsx index d3d2c72..4627826 100644 --- a/src/components/SearchContainer/Tabs/GroupNodeData.jsx +++ b/src/components/SearchContainer/Tabs/GroupNodeData.jsx @@ -1,394 +1,405 @@ import React, { Component } from 'react'; -import NodeALink from './NodeALink' -import PropTypes from 'prop-types' +import NodeALink from './NodeALink'; +import PropTypes from 'prop-types'; export default class GroupNodeData extends Component { - constructor(){ - super(); + constructor(){ + super(); - this.state = { - label: "", - directMembers: -1, - unrolledMembers: -1, - directAdminTo: -1, - derivativeAdminTo: -1, - unrolledMemberOf: -1, - sessions: -1, - foreignGroupMembership: -1, - foreignGroupMembers: -1, - firstDegreeGroupMembership: -1, - groupDelegatedAdmin: -1, - firstdegreeControl: -1, - groupDelegatedControl: -1, - transitiveControl: -1, - firstDegreeControllers: -1, - unrolledControllers: -1, - transitiveControllers: -1, - driversessions: [] - } + this.state = { + label: "", + directMembers: -1, + unrolledMembers: -1, + directAdminTo: -1, + derivativeAdminTo: -1, + unrolledMemberOf: -1, + sessions: -1, + foreignGroupMembership: -1, + foreignGroupMembers: -1, + firstDegreeGroupMembership: -1, + groupDelegatedAdmin: -1, + firstdegreeControl: -1, + groupDelegatedControl: -1, + transitiveControl: -1, + firstDegreeControllers: -1, + unrolledControllers: -1, + transitiveControllers: -1, + driversessions: [] + }; - emitter.on('groupNodeClicked', this.getNodeData.bind(this)); - } + emitter.on('groupNodeClicked', this.getNodeData.bind(this)); + } - getNodeData(payload){ - $.each(this.state.driversessions, function(index, record){ - record.close(); - }) + getNodeData(payload){ + $.each(this.state.driversessions, function(index, record){ + record.close(); + }); - this.setState({ - label: payload, - directMembers: -1, - unrolledMembers: -1, - directAdminTo: -1, - derivativeAdminTo: -1, - unrolledMemberOf: -1, - sessions: -1, - foreignGroupMembership: -1, - foreignGroupMembers: -1, - firstDegreeGroupMembership: -1, - groupDelegatedAdmin: -1, - firstdegreeControl: -1, - groupDelegatedControl: -1, - transitiveControl: -1, - firstDegreeControllers: -1, - unrolledControllers: -1, - transitiveControllers: -1 - }) + this.setState({ + label: payload, + directMembers: -1, + unrolledMembers: -1, + directAdminTo: -1, + derivativeAdminTo: -1, + unrolledMemberOf: -1, + sessions: -1, + foreignGroupMembership: -1, + foreignGroupMembers: -1, + firstDegreeGroupMembership: -1, + groupDelegatedAdmin: -1, + firstdegreeControl: -1, + groupDelegatedControl: -1, + transitiveControl: -1, + firstDegreeControllers: -1, + unrolledControllers: -1, + transitiveControllers: -1 + }); - var domain = '@' + payload.split('@').last() - var s1 = driver.session() - var s2 = driver.session() - var s3 = driver.session() - var s4 = driver.session() - var s5 = driver.session() - var s6 = driver.session() - var s7 = driver.session() - var s8 = driver.session() - var s9 = driver.session() - var s10 = driver.session() - var s11 = driver.session() - var s12 = driver.session() - var s13 = driver.session() - var s14 = driver.session() - var s15 = driver.session() - var s16 = driver.session() + var domain = '@' + payload.split('@').last(); + var s1 = driver.session(); + var s2 = driver.session(); + var s3 = driver.session(); + var s4 = driver.session(); + var s5 = driver.session(); + var s6 = driver.session(); + var s7 = driver.session(); + var s8 = driver.session(); + var s9 = driver.session(); + var s10 = driver.session(); + var s11 = driver.session(); + var s12 = driver.session(); + var s13 = driver.session(); + var s14 = driver.session(); + var s15 = driver.session(); + var s16 = driver.session(); - s1.run("MATCH (a)-[b:MemberOf]->(c:Group {name:{name}}) RETURN count(a)", {name:payload}) - .then(function(result){ - this.setState({'directMembers':result.records[0]._fields[0].low}) - s1.close() - }.bind(this)) + s1.run("MATCH (a)-[b:MemberOf]->(c:Group {name:{name}}) RETURN count(a)", {name:payload}) + .then(function(result){ + this.setState({'directMembers':result.records[0]._fields[0].low}); + s1.close(); + }.bind(this)); - s2.run("MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) RETURN COUNT(n)", {name:payload}) - .then(function(result){ - this.setState({'unrolledMembers':result.records[0]._fields[0].low}) - s2.close() - }.bind(this)) + s2.run("MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) RETURN COUNT(n)", {name:payload}) + .then(function(result){ + this.setState({'unrolledMembers':result.records[0]._fields[0].low}); + s2.close(); + }.bind(this)); - s3.run("MATCH (n:Group {name:{name}})-[r:AdminTo]->(m:Computer) RETURN count(distinct(m))", {name:payload}) - .then(function(result){ - this.setState({'directAdminTo':result.records[0]._fields[0].low}) - s3.close() - }.bind(this)) + s3.run("MATCH (n:Group {name:{name}})-[r:AdminTo]->(m:Computer) RETURN count(distinct(m))", {name:payload}) + .then(function(result){ + this.setState({'directAdminTo':result.records[0]._fields[0].low}); + s3.close(); + }.bind(this)); - s4.run("MATCH p = shortestPath((g:Group {name:{name}})-[r:MemberOf|AdminTo|HasSession*1..]->(c:Computer)) RETURN COUNT(DISTINCT(c))", {name:payload}) - .then(function(result){ - this.setState({'derivativeAdminTo':result.records[0]._fields[0].low}) - s4.close() - }.bind(this)) + s4.run("MATCH (c:Computer) WHERE NOT c.name={name} WITH c MATCH p = shortestPath((g:Group {name:{name}})-[r:MemberOf|AdminTo|HasSession*1..]->(c)) RETURN COUNT(DISTINCT(c))", {name:payload}) + .then(function(result){ + this.setState({'derivativeAdminTo':result.records[0]._fields[0].low}); + s4.close(); + }.bind(this)); - s5.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf*1..]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload}) - .then(function(result){ - this.setState({'unrolledMemberOf':result.records[0]._fields[0].low}) - s5.close() - }.bind(this)) + s5.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf*1..]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload}) + .then(function(result){ + this.setState({'unrolledMemberOf':result.records[0]._fields[0].low}); + s5.close(); + }.bind(this)); - s6.run("MATCH p = (c:Computer)-[r1:HasSession]->(u:User)-[r2:MemberOf*1..]->(g:Group {name: {name}}) RETURN COUNT(r1)", {name:payload}) - .then(function(result){ - this.setState({'sessions':result.records[0]._fields[0].low}) - s6.close() - }.bind(this)) + s6.run("MATCH p = (c:Computer)-[r1:HasSession]->(u:User)-[r2:MemberOf*1..]->(g:Group {name: {name}}) RETURN COUNT(r1)", {name:payload}) + .then(function(result){ + this.setState({'sessions':result.records[0]._fields[0].low}); + s6.close(); + }.bind(this)); - s7.run("MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:Group {name:{name}}) MATCH (m)-[r:MemberOf]->(n) RETURN count(n)", {name:payload, domain:domain}) - .then(function(result){ - this.setState({'foreignGroupMembership':result.records[0]._fields[0].low}) - s7.close() - }.bind(this)) + s7.run("MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:Group {name:{name}}) MATCH (m)-[r:MemberOf]->(n) RETURN count(n)", {name:payload, domain:domain}) + .then(function(result){ + this.setState({'foreignGroupMembership':result.records[0]._fields[0].low}); + s7.close(); + }.bind(this)); - s8.run("MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) WHERE NOT g.domain = n.domain RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'foreignGroupMembers':result.records[0]._fields[0].low}) - s8.close() - }.bind(this)) + s8.run("MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) WHERE NOT g.domain = n.domain RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'foreignGroupMembers':result.records[0]._fields[0].low}); + s8.close(); + }.bind(this)); - s9.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low}) - s9.close() - }.bind(this)) + s9.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low}); + s9.close(); + }.bind(this)); - s10.run("MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AdminTo]->(c:Computer) RETURN COUNT(DISTINCT(c))", {name:payload}) - .then(function(result){ - this.setState({'groupDelegatedAdmin':result.records[0]._fields[0].low}) - s10.close() - }.bind(this)) + s10.run("MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AdminTo]->(c:Computer) RETURN COUNT(DISTINCT(c))", {name:payload}) + .then(function(result){ + this.setState({'groupDelegatedAdmin':result.records[0]._fields[0].low}); + s10.close(); + }.bind(this)); - s11.run("MATCH p = (g:Group {name:{name}})-[r:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'firstdegreeControl':result.records[0]._fields[0].low}) - s11.close() - }.bind(this)) + s11.run("MATCH p = (g:Group {name:{name}})-[r:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'firstdegreeControl':result.records[0]._fields[0].low}); + s11.close(); + }.bind(this)); - s12.run("MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'groupDelegatedControl':result.records[0]._fields[0].low}) - s12.close() - }.bind(this)) + s12.run("MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'groupDelegatedControl':result.records[0]._fields[0].low}); + s12.close(); + }.bind(this)); - s13.run("MATCH p = shortestPath((g:Group {name:{name}})-[r:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'transitiveControl':result.records[0]._fields[0].low}) - s13.close() - }.bind(this)) + s13.run("MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((g:Group {name:{name}})-[r:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'transitiveControl':result.records[0]._fields[0].low}); + s13.close(); + }.bind(this)); - s14.run("MATCH p = (n)-[r:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g:Group {name:{name}}) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeControllers':result.records[0]._fields[0].low}) - s14.close() - }.bind(this)) + s14.run("MATCH p = (n)-[r:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g:Group {name:{name}}) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeControllers':result.records[0]._fields[0].low}); + s14.close(); + }.bind(this)); - s15.run("MATCH p = (n1)-[r:MemberOf*1..]->(g1:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g2:Group {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = g2.name) AND NOT n1.name = g2.name RETURN COUNT(DISTINCT(n1))", {name:payload}) - .then(function(result){ - this.setState({'unrolledControllers':result.records[0]._fields[0].low}) - s15.close() - }.bind(this)) + s15.run("MATCH p = (n1)-[r:MemberOf*1..]->(g1:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g2:Group {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = g2.name) AND NOT n1.name = g2.name RETURN COUNT(DISTINCT(n1))", {name:payload}) + .then(function(result){ + this.setState({'unrolledControllers':result.records[0]._fields[0].low}); + s15.close(); + }.bind(this)); - s16.run("MATCH p = shortestPath((n)-[r:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(g:Group {name:{name}})) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'transitiveControllers':result.records[0]._fields[0].low}) - s16.close() - }.bind(this)) - - this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16]}) - } + s16.run("MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((n)-[r:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(g:Group {name:{name}})) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'transitiveControllers':result.records[0]._fields[0].low}); + s16.close(); + }.bind(this)); + + this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16]}); + } - render() { - var domain = '@' + this.state.label.split('@') - return ( -
-
-

Node Info

-
- Name -
-
- {this.state.label} -
-
- Sessions -
-
- (u:User)-[r2:MemberOf*1..]->(g:Group {name: {name}}) RETURN p", {name: this.state.label}, - "",this.state.label) - }.bind(this)} /> -
-
-

Group Members

-
- Direct Members -
-
- (m:Group {name:{name}}) RETURN n,r,m", {name: this.state.label}) - }.bind(this)} /> -
-
- Unrolled Members -
-
- (g:Group {name:{name}}) RETURN p", {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
- Foreign Members -
-
- (g:Group {name:{name}}) WHERE NOT g.domain = n.domain RETURN p", {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
-

Group Membership

-
- First Degree Group Membership -
-
- (g2:Group) RETURN p", {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
- Unrolled Member Of -
-
- (g2:Group) RETURN p", {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
- Foreign Group Membership -
-
- (n) RETURN m,r,n", {name: this.state.label, domain: domain}) - }.bind(this)} /> -
-
-

Local Admin Rights

-
- First Degree Local Admin -
-
- (c:Computer) RETURN p", {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
- Group Delegated Local Admin Rights -
-
- (g2:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
- Derivative Local Admin Rights -
-
- (c:Computer)) RETURN p", {name: this.state.label}, - this.state.label) - }.bind(this)} /> -
-
-

Outbound Object Control

-
- First Degree Object Control -
-
- (n) RETURN p", {name:this.state.label}) - }.bind(this)} /> -
-
- Group Delegated Object Control -
-
- (g2:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Transitive Object Control -
-
- (n)) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
-

Inbound Object Control

-
- Explicit Object Controllers -
-
- (g:Group {name: {name}}) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Unrolled Object Controllers -
-
- (g1:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g2:Group {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = g2.name) AND NOT n1.name = g2.name RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Transitive Object Controllers -
-
- (g:Group {name: {name}})) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
-
- ); - } + render() { + var domain = '@' + this.state.label.split('@'); + return ( +
+
+

Node Info

+
+ Name +
+
+ {this.state.label} +
+
+ Sessions +
+
+ (u:User)-[r2:MemberOf*1..]->(g:Group {name: {name}}) RETURN p", {name: this.state.label}, + "",this.state.label); + }.bind(this)} + /> +
+

Group Members

+
+ Direct Members +
+
+ (m:Group {name:{name}}) RETURN n,r,m", {name: this.state.label}); + }.bind(this)} + /> +
+
+ Unrolled Members +
+
+ (g:Group {name:{name}}) RETURN p", {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+
+ Foreign Members +
+
+ (g:Group {name:{name}}) WHERE NOT g.domain = n.domain RETURN p", {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+

Group Membership

+
+ First Degree Group Membership +
+
+ (g2:Group) RETURN p", {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+
+ Unrolled Member Of +
+
+ (g2:Group) RETURN p", {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+
+ Foreign Group Membership +
+
+ (n) RETURN m,r,n", {name: this.state.label, domain: domain}); + }.bind(this)} + /> +
+

Local Admin Rights

+
+ First Degree Local Admin +
+
+ (c:Computer) RETURN p", {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+
+ Group Delegated Local Admin Rights +
+
+ (g2:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+
+ Derivative Local Admin Rights +
+
+ (c)) RETURN p", {name: this.state.label}, + this.state.label); + }.bind(this)} + /> +
+

Outbound Object Control

+
+ First Degree Object Control +
+
+ (n) RETURN p", {name:this.state.label}); + }.bind(this)} + /> +
+
+ Group Delegated Object Control +
+
+ (g2:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Transitive Object Control +
+
+ (n)) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+

Inbound Object Control

+
+ Explicit Object Controllers +
+
+ (g:Group {name: {name}}) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Unrolled Object Controllers +
+
+ (g1:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g2:Group {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = g2.name) AND NOT n1.name = g2.name RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Transitive Object Controllers +
+
+ (g:Group {name: {name}})) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+
+ ); + } } GroupNodeData.propTypes = { - visible : React.PropTypes.bool.isRequired -} \ No newline at end of file + visible : React.PropTypes.bool.isRequired +}; \ No newline at end of file diff --git a/src/components/SearchContainer/Tabs/NodePropItem.jsx b/src/components/SearchContainer/Tabs/NodePropItem.jsx new file mode 100644 index 0000000..031f0f6 --- /dev/null +++ b/src/components/SearchContainer/Tabs/NodePropItem.jsx @@ -0,0 +1,51 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +export default class NodePropItem extends Component{ + constructor(props){ + super(props); + } + + isArray(object){ + return object && typeof object === 'object' && object.constructor === Array; + } + + render() { + var val; + var obj = this.props.keyValue; + if (obj.hasOwnProperty('low')){ + return [ +
{this.props.keyName}
, +
{obj.low}
+ ]; + }else if (this.isArray(obj)){ + console.log(obj); + if (obj.length === 0){ + return [ +
{this.props.keyName}
, +
None
+ ]; + }else{ + var elements = []; + $.each(obj, function(index, prop){ + elements.push(
); + elements.push(
{prop}
); + }); + elements[0] =
Service Principal Names
; + } + + return elements; + }else if (typeof obj === 'boolean'){ + return [ +
{this.props.keyName}
, +
{this.props.keyValue.toString().toTitleCase()}
+ ]; + }else{ + return [ +
{this.props.keyName}
, +
{this.props.keyValue.toString()}
+ ]; + } + + } +} \ No newline at end of file diff --git a/src/components/SearchContainer/Tabs/UserNodeData.jsx b/src/components/SearchContainer/Tabs/UserNodeData.jsx index e4e6e0b..27248c2 100644 --- a/src/components/SearchContainer/Tabs/UserNodeData.jsx +++ b/src/components/SearchContainer/Tabs/UserNodeData.jsx @@ -1,363 +1,432 @@ import React, { Component } from 'react'; -import NodeALink from './NodeALink' -import PropTypes from 'prop-types' +import NodeALink from './NodeALink'; +import NodePropItem from './NodePropItem'; +import PropTypes from 'prop-types'; + +import { If, Then, Else } from 'react-if'; export default class UserNodeData extends Component { - constructor(){ - super(); + constructor(){ + super(); - this.state = { - label: "", - samAccountName: "None", - displayName: "None", - pwdLastChanged: "None", - firstDegreeGroupMembership: -1, - unrolledGroupMembership: -1, - foreignGroupMembership: -1, - firstDegreeLocalAdmin: -1, - groupDelegatedLocalAdmin: -1, - derivativeLocalAdmin: -1, - sessions: -1, - firstdegreeControllers: -1, - unrolledControllers: -1, - transitiveControllers: -1, - firstdegreeControl: -1, - unrolledControl: -1, - transitiveControl: -1, - driversessions : [] - } + this.state = { + label: "", + firstDegreeGroupMembership: -1, + unrolledGroupMembership: -1, + foreignGroupMembership: -1, + firstDegreeLocalAdmin: -1, + groupDelegatedLocalAdmin: -1, + derivativeLocalAdmin: -1, + sessions: -1, + firstdegreeControllers: -1, + unrolledControllers: -1, + transitiveControllers: -1, + firstdegreeControl: -1, + unrolledControl: -1, + transitiveControl: -1, + driversessions : [], + propertyMap: {ServicePrincipalNames: []} + }; - emitter.on('userNodeClicked', this.getNodeData.bind(this)); - } + emitter.on('userNodeClicked', this.getNodeData.bind(this)); + } - getNodeData(payload){ - $.each(this.state.driversessions,function(index, record){ - record.close(); - }) + getNodeData(payload){ + $.each(this.state.driversessions,function(index, record){ + record.close(); + }); - this.setState({ - label: payload, - samAccountName: "None", - displayName: "None", - pwdLastChanged: "None", - firstDegreeGroupMembership: -1, - unrolledGroupMembership: -1, - foreignGroupMembership: -1, - firstDegreeLocalAdmin: -1, - groupDelegatedLocalAdmin: -1, - derivativeLocalAdmin: -1, - sessions: -1, - firstdegreeControllers: -1, - unrolledControllers: -1, - transitiveControllers: -1, - firstdegreeControl: -1, - unrolledControl: -1, - transitiveControl: -1 - }) + this.setState({ + label: payload, + firstDegreeGroupMembership: -1, + unrolledGroupMembership: -1, + foreignGroupMembership: -1, + firstDegreeLocalAdmin: -1, + groupDelegatedLocalAdmin: -1, + derivativeLocalAdmin: -1, + sessions: -1, + firstdegreeControllers: -1, + unrolledControllers: -1, + transitiveControllers: -1, + firstdegreeControl: -1, + unrolledControl: -1, + transitiveControl: -1, + propertyMap: {ServicePrincipalNames: []} + }); - var domain = '@' + payload.split('@').last() - - var s1 = driver.session() - var s2 = driver.session() - var s3 = driver.session() - var s4 = driver.session() - var s5 = driver.session() - var s6 = driver.session() - var s7 = driver.session() - var s8 = driver.session() - var s9 = driver.session() - var s10 = driver.session() - var s11 = driver.session() - var s12 = driver.session() - var s13 = driver.session() + var domain = '@' + payload.split('@').last(); + + var s1 = driver.session(); + var s2 = driver.session(); + var s3 = driver.session(); + var s4 = driver.session(); + var s5 = driver.session(); + var s6 = driver.session(); + var s7 = driver.session(); + var s8 = driver.session(); + var s9 = driver.session(); + var s10 = driver.session(); + var s11 = driver.session(); + var s12 = driver.session(); + var s13 = driver.session(); - s1.run("MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:User {name:{name}}) MATCH (m)-[r:MemberOf*1..]->(n) RETURN count(n)", {name:payload, domain: domain}) - .then(function(result){ - this.setState({'foreignGroupMembership':result.records[0]._fields[0].low}) - s1.close() - }.bind(this)) + var props = driver.session(); + props.run("MATCH (n:User {name:{name}}) RETURN n", {name: payload}) + .then(function(result){ + var properties = result.records[0]._fields[0].properties; + this.setState({propertyMap: properties}); + props.close(); + }.bind(this)); - s2.run("MATCH (n:User {name:{name}}), (m:Group), p=(n)-[:MemberOf]->(m) RETURN count(m)", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low}) - s2.close() - }.bind(this)) + s1.run("MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:User {name:{name}}) MATCH (m)-[r:MemberOf*1..]->(n) RETURN count(n)", {name:payload, domain: domain}) + .then(function(result){ + this.setState({'foreignGroupMembership':result.records[0]._fields[0].low}); + s1.close(); + }.bind(this)); - s3.run("MATCH p = (n:User {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload}) - .then(function(result){ - this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low}) - s3.close() - }.bind(this)) + s2.run("MATCH (n:User {name:{name}}), (m:Group), p=(n)-[:MemberOf]->(m) RETURN count(m)", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low}); + s2.close(); + }.bind(this)); - s4.run("MATCH p = (n:User {name:{name}})-[r:AdminTo]->(c:Computer) RETURN COUNT(DISTINCT(c))", {name:payload}) - .then(function(result){ - this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low}) - s4.close() - }.bind(this)) + s3.run("MATCH p = (n:User {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload}) + .then(function(result){ + this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low}); + s3.close(); + }.bind(this)); - s5.run("MATCH p=(n:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c:Computer) RETURN count(distinct(c))", {name:payload}) - .then(function(result){ - this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low}) - s5.close() - }.bind(this)) + s4.run("MATCH p = (n:User {name:{name}})-[r:AdminTo]->(c:Computer) RETURN COUNT(DISTINCT(c))", {name:payload}) + .then(function(result){ + this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low}); + s4.close(); + }.bind(this)); - s6.run("MATCH p = shortestPath((n:User {name:{name}})-[r:HasSession|AdminTo|MemberOf*1..]->(c:Computer)) RETURN COUNT(c)", {name:payload}) - .then(function(result){ - this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low}) - s6.close() - }.bind(this)) + s5.run("MATCH p=(n:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c:Computer) RETURN count(distinct(c))", {name:payload}) + .then(function(result){ + this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low}); + s5.close(); + }.bind(this)); - s7.run("MATCH p = (n:Computer)-[r:HasSession]->(m:User {name:{name}}) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'sessions':result.records[0]._fields[0].low}) - s7.close() - }.bind(this)) + s6.run("MATCH (c:Computer) WHERE NOT c.name={name} WITH c MATCH p = shortestPath((n:User {name:{name}})-[r:HasSession|AdminTo|MemberOf*1..]->(c)) RETURN COUNT(c)", {name:payload}) + .then(function(result){ + this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low}); + s6.close(); + }.bind(this)); - s8.run("MATCH p = (n)-[r:AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u1:User {name: {name}}) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'firstdegreeControllers':result.records[0]._fields[0].low}) - s8.close() - }.bind(this)) + s7.run("MATCH p = (n:Computer)-[r:HasSession]->(m:User {name:{name}}) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'sessions':result.records[0]._fields[0].low}); + s7.close(); + }.bind(this)); - s9.run("MATCH p = (n1)-[r:MemberOf*1..]->(g:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u:User {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = u.name) AND NOT n1.name = u.name RETURN COUNT(DISTINCT(n1))", {name:payload}) - .then(function(result){ - this.setState({'unrolledControllers':result.records[0]._fields[0].low}) - s9.close() - }.bind(this)) + s8.run("MATCH p = (n)-[r:AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u1:User {name: {name}}) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'firstdegreeControllers':result.records[0]._fields[0].low}); + s8.close(); + }.bind(this)); - s10.run("MATCH p = shortestPath((n1)-[r1:MemberOf|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(u1:User {name: {name}})) RETURN COUNT(DISTINCT(n1))", {name:payload}) - .then(function(result){ - this.setState({'transitiveControllers':result.records[0]._fields[0].low}) - s10.close() - }.bind(this)) + s9.run("MATCH p = (n1)-[r:MemberOf*1..]->(g:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u:User {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = u.name) AND NOT n1.name = u.name RETURN COUNT(DISTINCT(n1))", {name:payload}) + .then(function(result){ + this.setState({'unrolledControllers':result.records[0]._fields[0].low}); + s9.close(); + }.bind(this)); - s11.run("MATCH p = (u:User {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'firstdegreeControl':result.records[0]._fields[0].low}) - s11.close() - }.bind(this)) + s10.run("MATCH (n1) WHERE NOT n1.name={name} WITH n1 MATCH p = shortestPath((n1)-[r1:MemberOf|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(u1:User {name: {name}})) RETURN COUNT(DISTINCT(n1))", {name:payload}) + .then(function(result){ + this.setState({'transitiveControllers':result.records[0]._fields[0].low}); + s10.close(); + }.bind(this)); - s12.run("MATCH p = (u:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'unrolledControl':result.records[0]._fields[0].low}) - s12.close() - }.bind(this)) + s11.run("MATCH p = (u:User {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'firstdegreeControl':result.records[0]._fields[0].low}); + s11.close(); + }.bind(this)); - s13.run("MATCH p = shortestPath((u:User {name:{name}})-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN COUNT(DISTINCT(n))", {name:payload}) - .then(function(result){ - this.setState({'transitiveControl':result.records[0]._fields[0].low}) - s13.close() - }.bind(this)) - - this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13]}) - } + s12.run("MATCH p = (u:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'unrolledControl':result.records[0]._fields[0].low}); + s12.close(); + }.bind(this)); - render() { - var domain = '@' + this.state.label.split('@').last() - return ( -
-
+ s13.run("MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((u:User {name:{name}})-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN COUNT(DISTINCT(n))", {name:payload}) + .then(function(result){ + this.setState({'transitiveControl':result.records[0]._fields[0].low}); + s13.close(); + }.bind(this)); + + this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,props]}); + } + + isArray(object){ + return object && typeof object === 'object' && object.constructor === Array; + } + + convertToDisplayProp(propName){ + var obj = this.state.propertyMap[propName]; + var type = typeof obj; + if (type === 'undefined'){ + return "No Data"; + }else if (obj.hasOwnProperty('low')){ + var t = obj.low; + if (t === 0){ + return "Never"; + }else{ + return new Date(obj.low * 1000).toUTCString(); + } + }else if (type === 'boolean'){ + return obj.toString().toTitleCase(); + }else if (obj === ""){ + return "None"; + }else{ + return obj; + } + } + + render() { + var domain = '@' + this.state.label.split('@').last(); + return ( +
+

- Node Info + User Info

-
- Name -
-
- {this.state.label} -
-
- SAMAccountName -
-
- {this.state.samAccountName} -
-
- Display Name -
-
- {this.state.displayName} -
-
- Password Last Changed -
-
- {this.state.pwdLastChanged} -
-
- Sessions -
-
- (m:User {name:{name}}) RETURN n,r,m", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
-

Group Membership

-
- First Degree Group Memberships -
-
- (g:Group) RETURN p", {name:this.state.label} - ) - }.bind(this)} /> -
-
- Unrolled Group Memberships -
-
- (g:Group) RETURN p", {name:this.state.label}, - this.state.label) - }.bind(this)} /> -
-
- Foreign Group Membership -
-
- (n) RETURN p", {name: this.state.label, domain: domain}) - }.bind(this)} /> -
-
-

- Local Admin Rights -

-
- First Degree Local Admin -
-
- (c:Computer) RETURN p", {name:this.state.label}) - }.bind(this)} /> -
-
- Group Delegated Local Admin Rights -
-
- (g:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Derivative Local Admin Rights -
-
- (c:Computer)) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
-

- Outbound Object Control -

-
- First Degree Object Control -
-
- (n) RETURN p", {name:this.state.label}) - }.bind(this)} /> -
-
- Group Delegated Object Control -
-
- (g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Transitive Object Control -
-
- (n)) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
-

Inbound Object Control

-
- Explicit Object Controllers -
-
- (u1:User {name: {name}}) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Unrolled Object Controllers -
-
- (g:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u:User {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = u.name) AND NOT n1.name = u.name RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
- Transitive Object Controllers -
-
- (u1:User {name: {name}})) RETURN p", {name:this.state.label} - ,this.state.label) - }.bind(this)} /> -
-
-
- ); - } +
+ Name +
+
+ {this.state.label} +
+
+ Display Name +
+
+ {this.convertToDisplayProp("DisplayName")} +
+
+ Password Last Changed +
+
+ {this.convertToDisplayProp("PwdLastSet")} +
+
+ Last Logon +
+
+ {this.convertToDisplayProp("LastLogon")} +
+
+ Enabled +
+
+ {this.convertToDisplayProp("Enabled")} +
+
+ Email +
+
+ {this.convertToDisplayProp("Email")} +
+
+ Service Principal Names +
+ {(() => { + if (this.state.propertyMap.ServicePrincipalNames.length === 0){ + return
None
; + } + })()} + {Object.keys(this.state.propertyMap.ServicePrincipalNames).map(function(key){ + var x =
{this.state.propertyMap.ServicePrincipalNames[key]}
; + return x; + }.bind(this))} +
+ Sessions +
+
+ (m:User {name:{name}}) RETURN n,r,m", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+ +

Group Membership

+
+ First Degree Group Memberships +
+
+ (g:Group) RETURN p", {name:this.state.label} + ); + }.bind(this)} + /> +
+
+ Unrolled Group Memberships +
+
+ (g:Group) RETURN p", {name:this.state.label}, + this.state.label); + }.bind(this)} + /> +
+
+ Foreign Group Membership +
+
+ (n) RETURN p", {name: this.state.label, domain: domain}); + }.bind(this)} + /> +
+ +

+ Local Admin Rights +

+
+ First Degree Local Admin +
+
+ (c:Computer) RETURN p", {name:this.state.label}); + }.bind(this)} + /> +
+
+ Group Delegated Local Admin Rights +
+
+ (g:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Derivative Local Admin Rights +
+
+ (c)) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+ +

+ Outbound Object Control +

+
+ First Degree Object Control +
+
+ (n) RETURN p", {name:this.state.label}); + }.bind(this)} + /> +
+
+ Group Delegated Object Control +
+
+ (g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Transitive Object Control +
+
+ (n)) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+ +

Inbound Object Control

+
+ Explicit Object Controllers +
+
+ (u1:User {name: {name}}) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Unrolled Object Controllers +
+
+ (g:Group)-[r1:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u:User {name: {name}}) WITH LENGTH(p) as pathLength, p, n1 WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.name = u.name) AND NOT n1.name = u.name RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+ Transitive Object Controllers +
+
+ (u1:User {name: {name}})) RETURN p", {name:this.state.label} + ,this.state.label); + }.bind(this)} + /> +
+
+
+ ); + } } UserNodeData.propTypes = { - visible : React.PropTypes.bool.isRequired -} \ No newline at end of file + visible : PropTypes.bool.isRequired +}; \ No newline at end of file diff --git a/src/css/styles.css b/src/css/styles.css index 72c0a53..3cbe9cd 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -3,7 +3,8 @@ #root { position: absolute; width: 100%; - height: 100%; + height: 100%; + overflow: hidden; } .max{ @@ -94,6 +95,13 @@ div.tooltip-inner-custom { width: 100%; height: 100%; background-color: lightgray; + overflow: hidden; +} + +.dropdown-item > i{ + float:right; + margin-top:3px; + margin-left: 2px; } .graph:focus { @@ -187,6 +195,12 @@ div.tooltip-inner-custom { margin-bottom: 1em; } +.dl-horizontal > h4 { + margin-top: 10px; + margin-bottom: 5px; + color: blue; +} + .dl-horizontal{ margin-right: 10px; } @@ -763,7 +777,6 @@ div.tooltip-inner-custom { } .tab-content > div:nth-last-child(2) > div{ - height: 600px; + max-height: 600px; overflow-y: auto; - resize: vertical; } \ No newline at end of file diff --git a/src/index.js b/src/index.js index 3f7101c..2588a2d 100644 --- a/src/index.js +++ b/src/index.js @@ -106,10 +106,11 @@ global.appStore = { 'ForceChangePassword': 'tapered', 'GenericAll': 'tapered', 'GenericWrite': 'tapered', - 'WriteDACL': 'tapered', + 'WriteDacl': 'tapered', 'WriteOwner': 'tapered', 'AddMembers': 'tapered', - 'TrustedBy': 'curvedArrow' + 'TrustedBy': 'curvedArrow', + 'DCSync' : 'tapered' } }, lowResPalette: { diff --git a/src/js/papaparse.min.js b/src/js/papaparse.min.js deleted file mode 100644 index e0524a3..0000000 --- a/src/js/papaparse.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! - Papa Parse - v4.1.2 - https://github.com/mholt/PapaParse -*/ -!function(a,b){"function"==typeof define&&define.amd?define([],b):"object"==typeof module&&module.exports?module.exports=b():a.Papa=b()}(this,function(){"use strict";function a(a,b){if(b=b||{},b.worker&&y.WORKERS_SUPPORTED){var c=j();return c.userStep=b.step,c.userChunk=b.chunk,c.userComplete=b.complete,c.userError=b.error,b.step=q(b.step),b.chunk=q(b.chunk),b.complete=q(b.complete),b.error=q(b.error),delete b.worker,void c.postMessage({input:a,config:b,workerId:c.id})}var g=null;return"string"==typeof a?g=b.download?new d(b):new f(b):(s.File&&a instanceof File||a instanceof Object)&&(g=new e(b)),g.stream(a)}function b(a,b){function c(){"object"==typeof b&&("string"==typeof b.delimiter&&1===b.delimiter.length&&-1===y.BAD_DELIMITERS.indexOf(b.delimiter)&&(i=b.delimiter),("boolean"==typeof b.quotes||b.quotes instanceof Array)&&(h=b.quotes),"string"==typeof b.newline&&(j=b.newline))}function d(a){if("object"!=typeof a)return[];var b=[];for(var c in a)b.push(c);return b}function e(a,b){var c="";"string"==typeof a&&(a=JSON.parse(a)),"string"==typeof b&&(b=JSON.parse(b));var d=a instanceof Array&&a.length>0,e=!(b[0]instanceof Array);if(d){for(var g=0;g0&&(c+=i),c+=f(a[g],g);b.length>0&&(c+=j)}for(var h=0;hl;l++){l>0&&(c+=i);var m=d&&e?a[l]:l;c+=f(b[h][m],l)}h-1||" "===a.charAt(0)||" "===a.charAt(a.length-1);return c?'"'+a+'"':a}function g(a,b){for(var c=0;c-1)return!0;return!1}var h=!1,i=",",j="\r\n";if(c(),"string"==typeof a&&(a=JSON.parse(a)),a instanceof Array){if(!a.length||a[0]instanceof Array)return e(null,a);if("object"==typeof a[0])return e(d(a[0]),a)}else if("object"==typeof a)return"string"==typeof a.data&&(a.data=JSON.parse(a.data)),a.data instanceof Array&&(a.fields||(a.fields=a.meta&&a.meta.fields),a.fields||(a.fields=a.data[0]instanceof Array?a.fields:d(a.data[0])),a.data[0]instanceof Array||"object"==typeof a.data[0]||(a.data=[a.data])),e(a.fields||[],a.data||[]);throw"exception: Unable to serialize unrecognized input"}function c(a){function b(a){var b=o(a);b.chunkSize=parseInt(b.chunkSize),a.step||a.chunk||(b.chunkSize=null),this._handle=new g(b),this._handle.streamer=this,this._config=b}this._handle=null,this._paused=!1,this._finished=!1,this._input=null,this._baseIndex=0,this._partialLine="",this._rowCount=0,this._start=0,this._nextChunk=null,this.isFirstChunk=!0,this._completeResults={data:[],errors:[],meta:{}},b.call(this,a),this.parseChunk=function(a){if(this.isFirstChunk&&q(this._config.beforeFirstChunk)){var b=this._config.beforeFirstChunk(a);void 0!==b&&(a=b)}this.isFirstChunk=!1;var c=this._partialLine+a;this._partialLine="";var d=this._handle.parse(c,this._baseIndex,!this._finished);if(!this._handle.paused()&&!this._handle.aborted()){var e=d.meta.cursor;this._finished||(this._partialLine=c.substring(e-this._baseIndex),this._baseIndex=e),d&&d.data&&(this._rowCount+=d.data.length);var f=this._finished||this._config.preview&&this._rowCount>=this._config.preview;if(u)s.postMessage({results:d,workerId:y.WORKER_ID,finished:f});else if(q(this._config.chunk)){if(this._config.chunk(d,this._handle),this._paused)return;d=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(d.data),this._completeResults.errors=this._completeResults.errors.concat(d.errors),this._completeResults.meta=d.meta),!f||!q(this._config.complete)||d&&d.meta.aborted||this._config.complete(this._completeResults,this._input),f||d&&d.meta.paused||this._nextChunk(),d}},this._sendError=function(a){q(this._config.error)?this._config.error(a):u&&this._config.error&&s.postMessage({workerId:y.WORKER_ID,error:a,finished:!1})}}function d(a){function b(a){var b=a.getResponseHeader("Content-Range");return parseInt(b.substr(b.lastIndexOf("/")+1))}a=a||{},a.chunkSize||(a.chunkSize=y.RemoteChunkSize),c.call(this,a);var d;t?this._nextChunk=function(){this._readChunk(),this._chunkLoaded()}:this._nextChunk=function(){this._readChunk()},this.stream=function(a){this._input=a,this._nextChunk()},this._readChunk=function(){if(this._finished)return void this._chunkLoaded();if(d=new XMLHttpRequest,this._config.withCredentials&&(d.withCredentials=this._config.withCredentials),t||(d.onload=p(this._chunkLoaded,this),d.onerror=p(this._chunkError,this)),d.open("GET",this._input,!t),this._config.chunkSize){var a=this._start+this._config.chunkSize-1;d.setRequestHeader("Range","bytes="+this._start+"-"+a),d.setRequestHeader("If-None-Match","webkit-no-cache")}try{d.send()}catch(b){this._chunkError(b.message)}t&&0===d.status?this._chunkError():this._start+=this._config.chunkSize},this._chunkLoaded=function(){if(4==d.readyState){if(d.status<200||d.status>=400)return void this._chunkError();this._finished=!this._config.chunkSize||this._start>b(d),this.parseChunk(d.responseText)}},this._chunkError=function(a){var b=d.statusText||a;this._sendError(b)}}function e(a){a=a||{},a.chunkSize||(a.chunkSize=y.LocalChunkSize),c.call(this,a);var b,d,e="undefined"!=typeof FileReader;this.stream=function(a){this._input=a,d=a.slice||a.webkitSlice||a.mozSlice,e?(b=new FileReader,b.onload=p(this._chunkLoaded,this),b.onerror=p(this._chunkError,this)):b=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(a.target.result)},this._chunkError=function(){this._sendError(b.error)}}function f(a){a=a||{},c.call(this,a);var b,d;this.stream=function(a){return b=a,d=a,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var a=this._config.chunkSize,b=a?d.substr(0,a):d;return d=a?d.substr(a):"",this._finished=!d,this.parseChunk(b)}}}function g(a){function b(){if(v&&m&&(j("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+y.DefaultDelimiter+"'"),m=!1),a.skipEmptyLines)for(var b=0;b=u.length?(c.__parsed_extra||(c.__parsed_extra=[]),c.__parsed_extra.push(v.data[b][d])):c[u[d]]=v.data[b][d])}a.header&&(v.data[b]=c,d>u.length?j("FieldMismatch","TooManyFields","Too many fields: expected "+u.length+" fields but parsed "+d,b):d1&&(k+=Math.abs(o-f),f=o):f=o}m.data.length>0&&(l/=m.data.length),("undefined"==typeof e||e>k)&&l>1.99&&(e=k,d=j)}return a.delimiter=d,{successful:!!d,bestDelimiter:d}}function g(a){a=a.substr(0,1048576);var b=a.split("\r"),c=a.split("\n"),d=c.length>1&&c[0].length=b.length/2?"\r\n":"\r"}function i(a){var b=n.test(a);return b?parseFloat(a):a}function j(a,b,c,d){v.errors.push({type:a,code:b,message:c,row:d})}var k,l,m,n=/^\s*-?(\d*\.?\d+|\d+\.?\d*)(e[-+]?\d+)?\s*$/i,p=this,r=0,s=!1,t=!1,u=[],v={data:[],errors:[],meta:{}};if(q(a.step)){var w=a.step;a.step=function(d){if(v=d,c())b();else{if(b(),0===v.data.length)return;r+=d.data.length,a.preview&&r>a.preview?l.abort():w(v,p)}}}this.parse=function(c,d,e){if(a.newline||(a.newline=g(c)),m=!1,!a.delimiter){var i=f(c,a.newline);i.successful?a.delimiter=i.bestDelimiter:(m=!0,a.delimiter=y.DefaultDelimiter),v.meta.delimiter=a.delimiter}var j=o(a);return a.preview&&a.header&&j.preview++,k=c,l=new h(j),v=l.parse(k,d,e),b(),s?{meta:{paused:!0}}:v||{meta:{paused:!1}}},this.paused=function(){return s},this.pause=function(){s=!0,l.abort(),k=k.substr(l.getCharIndex())},this.resume=function(){s=!1,p.streamer.parseChunk(k)},this.aborted=function(){return t},this.abort=function(){t=!0,l.abort(),v.meta.aborted=!0,q(a.complete)&&a.complete(v),k=""}}function h(a){a=a||{};var b=a.delimiter,c=a.newline,d=a.comments,e=a.step,f=a.preview,g=a.fastMode;if(("string"!=typeof b||y.BAD_DELIMITERS.indexOf(b)>-1)&&(b=","),d===b)throw"Comment character same as delimiter";d===!0?d="#":("string"!=typeof d||y.BAD_DELIMITERS.indexOf(d)>-1)&&(d=!1),"\n"!=c&&"\r"!=c&&"\r\n"!=c&&(c="\n");var h=0,i=!1;this.parse=function(a,j,k){function l(a){v.push(a),y=h}function m(b){return k?o():("undefined"==typeof b&&(b=a.substr(h)),x.push(b),h=q,l(x),u&&p(),o())}function n(b){h=b,l(x),x=[],C=a.indexOf(c,h)}function o(a){return{data:v,errors:w,meta:{delimiter:b,linebreak:c,aborted:i,truncated:!!a,cursor:y+(j||0)}}}function p(){e(o()),v=[],w=[]}if("string"!=typeof a)throw"Input must be a string";var q=a.length,r=b.length,s=c.length,t=d.length,u="function"==typeof e;h=0;var v=[],w=[],x=[],y=0;if(!a)return o();if(g||g!==!1&&-1===a.indexOf('"')){for(var z=a.split(c),A=0;A=f)return v=v.slice(0,f),o(!0)}}return o()}for(var B=a.indexOf(b,h),C=a.indexOf(c,h);;)if('"'!==a[h])if(d&&0===x.length&&a.substr(h,t)===d){if(-1===C)return o();h=C+s,C=a.indexOf(c,h),B=a.indexOf(b,h)}else if(-1!==B&&(C>B||-1===C))x.push(a.substring(h,B)),h=B+r,B=a.indexOf(b,h);else{if(-1===C)break;if(x.push(a.substring(h,C)),n(C+s),u&&(p(),i))return o();if(f&&v.length>=f)return o(!0)}else{var D=h;for(h++;;){var D=a.indexOf('"',D+1);if(-1===D)return k||w.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:v.length,index:h}),m();if(D===q-1){var E=a.substring(h,D).replace(/""/g,'"');return m(E)}if('"'!==a[D+1]){if(a[D+1]===b){x.push(a.substring(h,D).replace(/""/g,'"')),h=D+1+r,B=a.indexOf(b,h),C=a.indexOf(c,h);break}if(a.substr(D+1,s)===c){if(x.push(a.substring(h,D).replace(/""/g,'"')),n(D+1+s),B=a.indexOf(b,h),u&&(p(),i))return o();if(f&&v.length>=f)return o(!0);break}}else D++}}return m()},this.abort=function(){i=!0},this.getCharIndex=function(){return h}}function i(){var a=document.getElementsByTagName("script");return a.length?a[a.length-1].src:""}function j(){if(!y.WORKERS_SUPPORTED)return!1;if(!v&&null===y.SCRIPT_PATH)throw new Error("Script path cannot be determined automatically when Papa Parse is loaded asynchronously. You need to set Papa.SCRIPT_PATH manually.");var a=y.SCRIPT_PATH||r;a+=(-1!==a.indexOf("?")?"&":"?")+"papaworker";var b=new s.Worker(a);return b.onmessage=k,b.id=x++,w[b.id]=b,b}function k(a){var b=a.data,c=w[b.workerId],d=!1;if(b.error)c.userError(b.error,b.file);else if(b.results&&b.results.data){var e=function(){d=!0,l(b.workerId,{data:[],errors:[],meta:{aborted:!0}})},f={abort:e,pause:m,resume:m};if(q(c.userStep)){for(var g=0;g(b)'.format(atype, btype, record), props: [{ account: a, principal: b }] - } + }; } - }) - - }) + }); + }); - return datadict + return datadict; } \ No newline at end of file diff --git a/src/js/worker.js b/src/js/worker.js index fcb5ec8..b91d8ac 100644 --- a/src/js/worker.js +++ b/src/js/worker.js @@ -1,5 +1,5 @@ -global.sigma = require('linkurious') -require('./sigma.helpers.graph.min.js') +global.sigma = require('linkurious'); +require('./sigma.helpers.graph.min.js'); Array.prototype.allEdgesSameType = function() { for (var i = 1; i < this.length; i++) { @@ -18,192 +18,192 @@ sigma.classes.graph.addMethod('inboundNodes', function(id) { return this.inNeighborsIndex.get(id).keyList(); }); -var sigmaInstance = new sigma() +var sigmaInstance = new sigma(); process.on('message', function(m){ - var data = JSON.parse(m) - params = {edge: data.edge,sibling: data.sibling, start: data.start, end: data.end} - var spotlightData = {} - sigmaInstance.graph.clear() - sigmaInstance.graph.read(data.graph) - sigmaInstance.graph.nodes().forEach(function(node){ - node.degree = sigmaInstance.graph.degree(node.id) - }) - var result = collapseEdgeNodes(sigmaInstance, params, spotlightData) - sigmaInstance = result[0] - spotlightData = result[1] - result = collapseSiblingNodes(sigmaInstance, params, spotlightData) - sigmaInstance = result[0] - spotlightData = result[1] - sigmaInstance.graph.nodes().forEach(function(node) { + var data = JSON.parse(m); + params = {edge: data.edge,sibling: data.sibling, start: data.start, end: data.end}; + var spotlightData = {}; + sigmaInstance.graph.clear(); + sigmaInstance.graph.read(data.graph); + sigmaInstance.graph.nodes().forEach(function(node){ + node.degree = sigmaInstance.graph.degree(node.id); + }); + var result = collapseEdgeNodes(sigmaInstance, params, spotlightData); + sigmaInstance = result[0]; + spotlightData = result[1]; + result = collapseSiblingNodes(sigmaInstance, params, spotlightData); + sigmaInstance = result[0]; + spotlightData = result[1]; + sigmaInstance.graph.nodes().forEach(function(node) { if (!spotlightData.hasOwnProperty(node.id)) { spotlightData[node.id] = [node.label, 0, "", node.type, ""]; } }); - var toSend = {nodes: sigmaInstance.graph.nodes(), edges: sigmaInstance.graph.edges(), spotlight: spotlightData} - process.send(toSend) -}) + var toSend = {nodes: sigmaInstance.graph.nodes(), edges: sigmaInstance.graph.edges(), spotlight: spotlightData}; + process.send(toSend); +}); function collapseEdgeNodes(sigmaInstance, params, spotlightData){ - var threshold = params.edge; + var threshold = params.edge; - if (threshold == 0){ - return [sigmaInstance, spotlightData] - } - sigmaInstance.graph.nodes().forEach(function(node){ - if (node.degree < threshold){ - return - } + if (threshold == 0){ + return [sigmaInstance, spotlightData]; + } + sigmaInstance.graph.nodes().forEach(function(node){ + if (node.degree < threshold){ + return; + } - sigmaInstance.graph.adjacentNodes(node.id).forEach(function(anode){ - if (params.end !== null && anode.label === params.end){ - return - } + sigmaInstance.graph.adjacentNodes(node.id).forEach(function(anode){ + if (params.end !== null && anode.label === params.end){ + return; + } - if (params.start !== null && anode.label === params.start){ - return - } + if (params.start !== null && anode.label === params.start){ + return; + } - var edges = sigmaInstance.graph.adjacentEdges(anode.id); - if ((edges.length > 1 || edges.length === 0) || (anode.folded.nodes.length > 0)){ - return - } + var edges = sigmaInstance.graph.adjacentEdges(anode.id); + if ((edges.length > 1 || edges.length === 0) || (anode.folded.nodes.length > 0)){ + return; + } - var edge = edges[0]; + var edge = edges[0]; - if ((anode.type_user) - || (anode.type_computer) - || (anode.type_group && edge.label === 'AdminTo')){ + if ((anode.type_user) + || (anode.type_computer) + || (anode.type_group && edge.label === 'AdminTo')){ - node.isGrouped = true - node.folded.nodes.push(anode) - node.folded.edges.push(edge) - spotlightData[anode.id] = [anode.label, node.id, node.label, anode.type, node.type]; - sigmaInstance.graph.dropNode(anode.id); - } - }); - if (node.folded.nodes.length > 0){ - node.glyphs.push({ - 'position': 'bottom-left', - 'content': node.folded.nodes.length - }) - } - }) + node.isGrouped = true; + node.folded.nodes.push(anode); + node.folded.edges.push(edge); + spotlightData[anode.id] = [anode.label, node.id, node.label, anode.type, node.type]; + sigmaInstance.graph.dropNode(anode.id); + } + }); + if (node.folded.nodes.length > 0){ + node.glyphs.push({ + 'position': 'bottom-left', + 'content': node.folded.nodes.length + }); + } + }); - return [sigmaInstance, spotlightData] + return [sigmaInstance, spotlightData]; } function collapseSiblingNodes(sigmaInstance, params, spotlightData){ - var threshold = params.sibling + var threshold = params.sibling; - if (threshold === 0){ - return [sigmaInstance, spotlightData] - } + if (threshold === 0){ + return [sigmaInstance, spotlightData]; + } - sigmaInstance.graph.nodes().forEach(function(node){ - //Dont apply this logic to anything thats folded or isn't a computer - if (!node.type_computer || node.folded.nodes.length > 0){ - return - } + sigmaInstance.graph.nodes().forEach(function(node){ + //Dont apply this logic to anything thats folded or isn't a computer + if (!node.type_computer || node.folded.nodes.length > 0){ + return; + } - //Start by getting all the edges attached to this node - var adjacent = sigmaInstance.graph.adjacentEdges(node.id) - var siblings = [] + //Start by getting all the edges attached to this node + var adjacent = sigmaInstance.graph.adjacentEdges(node.id); + var siblings = []; - //Check to see if all the edges are the same type (i.e. AdminTo) - if (adjacent.length > 1 && adjacent.allEdgesSameType()){ - //Get the "parents" by mapping the source from every edge - var parents = adjacent.map( - function(e){ - return e.source - } - ) + //Check to see if all the edges are the same type (i.e. AdminTo) + if (adjacent.length > 1 && adjacent.allEdgesSameType()){ + //Get the "parents" by mapping the source from every edge + var parents = adjacent.map( + function(e){ + return e.source; + } + ); - //Generate our string to compare other nodes to - //by sorting the parents and turning it into a string - var checkString = parents.sort().join(',') - var testString; + //Generate our string to compare other nodes to + //by sorting the parents and turning it into a string + var checkString = parents.sort().join(','); + var testString; - //Loop back over nodes in the graph and look for any nodes - //with identical parents - sigmaInstance.graph.nodes().forEach(function(node2){ - testString = sigmaInstance.graph.adjacentEdges(node2.id).map( - function(e){ - return e.source; - } - ).sort().join(',') - if (testString === checkString){ - siblings.push(node2); - } - }); + //Loop back over nodes in the graph and look for any nodes + //with identical parents + sigmaInstance.graph.nodes().forEach(function(node2){ + testString = sigmaInstance.graph.adjacentEdges(node2.id).map( + function(e){ + return e.source; + } + ).sort().join(','); + if (testString === checkString){ + siblings.push(node2); + } + }); - if (siblings.length >= threshold){ - //Generate a new ID for our grouped node - var nodeId = generateUniqueId(sigmaInstance, true); + if (siblings.length >= threshold){ + //Generate a new ID for our grouped node + var nodeId = generateUniqueId(sigmaInstance, true); - sigmaInstance.graph.addNode({ - id: nodeId, - x: node.x, - y: node.y, - degree: siblings.length, - label: "Grouped Computers", - type: 'Computer', - type_computer: true, - groupedNode: true, - glyphs: [{ - position: 'bottom-left', - content: siblings.length - }], - folded: { - nodes: [], - edges: [] - } - }); + sigmaInstance.graph.addNode({ + id: nodeId, + x: node.x, + y: node.y, + degree: siblings.length, + label: "Grouped Computers", + type: 'Computer', + type_computer: true, + groupedNode: true, + glyphs: [{ + position: 'bottom-left', + content: siblings.length + }], + folded: { + nodes: [], + edges: [] + } + }); - //Generate new edges for each parent going to our new node - parents.forEach(function(parent){ - var id = generateUniqueId(sigmaInstance, false); + //Generate new edges for each parent going to our new node + parents.forEach(function(parent){ + var id = generateUniqueId(sigmaInstance, false); - sigmaInstance.graph.addEdge({ - id: id, - source: parent, - target: nodeId, - label: 'AdminTo', - neo4j_type: 'AdminTo', - size: 1 - }) - }) + sigmaInstance.graph.addEdge({ + id: id, + source: parent, + target: nodeId, + label: 'AdminTo', + neo4j_type: 'AdminTo', + size: 1 + }); + }); - var n = sigmaInstance.graph.nodes(nodeId); - //Loop over all the siblings, and push the edges into our new parent node - //Push the nodes in as well so we can unfold them - siblings.forEach(function(sibling){ - sigmaInstance.graph.adjacentEdges(sibling.id).forEach(function(edge){ - n.folded.edges.push(edge) - }) + var n = sigmaInstance.graph.nodes(nodeId); + //Loop over all the siblings, and push the edges into our new parent node + //Push the nodes in as well so we can unfold them + siblings.forEach(function(sibling){ + sigmaInstance.graph.adjacentEdges(sibling.id).forEach(function(edge){ + n.folded.edges.push(edge); + }); - n.folded.nodes.push(sibling) - spotlightData[sibling.id] = [sibling.label, nodeId, n.label, sibling.type, n.type]; - sigmaInstance.graph.dropNode(sibling.id) - }) - } - } - }) - return [sigmaInstance, spotlightData] + n.folded.nodes.push(sibling); + spotlightData[sibling.id] = [sibling.label, nodeId, n.label, sibling.type, n.type]; + sigmaInstance.graph.dropNode(sibling.id); + }); + } + } + }); + return [sigmaInstance, spotlightData]; } function generateUniqueId(sigmaInstance, isNode){ - var i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10; - if (isNode){ - while (typeof sigmaInstance.graph.nodes(i) !== 'undefined'){ - i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10; - } - }else{ - while (typeof sigmaInstance.graph.edges(i) !== 'undefined'){ - i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10; - } - } + var i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10; + if (isNode){ + while (typeof sigmaInstance.graph.nodes(i) !== 'undefined'){ + i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10; + } + }else{ + while (typeof sigmaInstance.graph.edges(i) !== 'undefined'){ + i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10; + } + } - return i + return i; } \ No newline at end of file