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: '
@@ -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 (
-
- );
- }
+ render() {
+ return (
+
+ );
+ }
}
ProgressBarMenuButton.propTypes = {
- progress : React.PropTypes.number.isRequired,
- click : React.PropTypes.func.isRequired
- }
\ No newline at end of file
+ progress : React.PropTypes.number.isRequired,
+ click : React.PropTypes.func.isRequired
+};
\ No newline at end of file
diff --git a/src/components/SearchContainer/SearchContainer.jsx b/src/components/SearchContainer/SearchContainer.jsx
index fcdb1d1..0d96947 100644
--- a/src/components/SearchContainer/SearchContainer.jsx
+++ b/src/components/SearchContainer/SearchContainer.jsx
@@ -1,86 +1,86 @@
import React, { Component } from 'react';
-import GlyphiconSpan from '../GlyphiconSpan'
-import Icon from '../Icon'
-import TabContainer from './TabContainer'
+import GlyphiconSpan from '../GlyphiconSpan';
+import Icon from '../Icon';
+import TabContainer from './TabContainer';
export default class SearchContainer extends Component {
constructor(props){
- super(props)
+ super(props);
this.state = {
mainPlaceholder:"Start typing to search for a node...",
pathfindingIsOpen: false,
mainValue: "",
pathfindValue: ""
- }
+ };
}
_onPathfindClick(){
- jQuery(this.refs.pathfinding).slideToggle()
- var p = !this.state.pathfindingIsOpen
- var t = this.state.pathfindingIsOpen ? "Start typing to search for a node..." : "Start Node"
+ jQuery(this.refs.pathfinding).slideToggle();
+ var p = !this.state.pathfindingIsOpen;
+ var t = this.state.pathfindingIsOpen ? "Start typing to search for a node..." : "Start Node";
this.setState({
pathfindingIsOpen: p,
mainPlaceholder: t
- })
+ });
}
_onPlayClick(){
- var start = jQuery(this.refs.searchbar).val()
- var end = jQuery(this.refs.pathbar).val()
+ var start = jQuery(this.refs.searchbar).val();
+ var end = jQuery(this.refs.pathbar).val();
if (start !== "" && end !== ""){
- emitter.emit('pathQuery', start, end)
+ emitter.emit('pathQuery', start, end);
}
}
_onExpandClick(){
- jQuery(this.refs.tabs).slideToggle()
+ jQuery(this.refs.tabs).slideToggle();
}
openNodeTab(){
- var e = jQuery(this.refs.tabs)
+ var e = jQuery(this.refs.tabs);
if (!(e.is(":visible"))){
- e.slideToggle()
+ e.slideToggle();
}
}
componentDidMount() {
jQuery(this.refs.pathfinding).slideToggle(0);
jQuery(this.refs.tabs).slideToggle(0);
- emitter.on('userNodeClicked', this.openNodeTab.bind(this))
- emitter.on('groupNodeClicked', this.openNodeTab.bind(this))
- emitter.on('computerNodeClicked', this.openNodeTab.bind(this))
- emitter.on('domainNodeClicked', this.openNodeTab.bind(this))
+ emitter.on('userNodeClicked', this.openNodeTab.bind(this));
+ emitter.on('groupNodeClicked', this.openNodeTab.bind(this));
+ emitter.on('computerNodeClicked', this.openNodeTab.bind(this));
+ emitter.on('domainNodeClicked', this.openNodeTab.bind(this));
emitter.on('setStart', function(payload){
jQuery(this.refs.searchbar).val(payload);
- }.bind(this))
+ }.bind(this));
emitter.on('setEnd', function(payload){
jQuery(this.refs.pathbar).val(payload);
- var e = jQuery(this.refs.pathfinding)
+ var e = jQuery(this.refs.pathfinding);
if (!(e.is(":visible"))){
- e.slideToggle()
+ e.slideToggle();
}
- }.bind(this))
+ }.bind(this));
jQuery(this.refs.searchbar).typeahead({
source: function(query, process) {
- var session = driver.session()
- var t = '(?i).*' + query + '.*'
- var data = []
+ var session = driver.session();
+ var t = '(?i).*' + query + '.*';
+ var data = [];
session.run("MATCH (n) WHERE n.name =~ {name} RETURN n LIMIT 10", {name:t})
.then(function(results){
$.each(results.records, function(index, record){
- data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0])
- })
- session.close()
- return process(data)
- })
+ data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0]);
+ });
+ session.close();
+ return process(data);
+ });
},
afterSelect: function(selected) {
if (!this.state.pathfindingIsOpen) {
- var statement = "MATCH (n) WHERE n.name = {name} RETURN n"
- emitter.emit('searchQuery', statement, {name: selected.split("#")[0]})
+ var statement = "MATCH (n) WHERE n.name = {name} RETURN n";
+ emitter.emit('searchQuery', statement, {name: selected.split("#")[0]});
} else {
var start = jQuery(this.refs.searchbar).val();
var end = jQuery(this.refs.pathbar).val();
@@ -91,57 +91,57 @@ export default class SearchContainer extends Component {
}.bind(this),
autoSelect: false,
updater: function(item){
- return item.split("#")[0]
+ return item.split("#")[0];
},
highlighter: function(item) {
- var parts = item.split("#")
+ var parts = item.split("#");
var query = this.query;
var icon = "";
- var html = ""
+ var html = "";
switch (parts[1]){
case "Group":
- icon = "
"
+ icon = "
";
break;
case "User":
- icon = "
"
+ icon = "
";
break;
case "Computer":
- icon = "
"
+ icon = "
";
break;
case "Domain":
- icon = "
"
- break
+ icon = "
";
+ break;
}
- html = '
' + parts[0] + ' ' + icon + '
'
+ html = '
' + parts[0] + ' ' + icon + '
';
var reEscQuery = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var reQuery = new RegExp('(' + reEscQuery + ')', "gi");
- var jElem = $(html)
+ var jElem = $(html);
var textNodes = $(jElem.find('*')).add(jElem).contents().filter(function () { return this.nodeType === 3; });
textNodes.replaceWith(function() {
- return $(this).text().replace(reQuery, '
$1 ')
+ return $(this).text().replace(reQuery, '
$1 ');
});
return jElem.html();
}
}
- )
+ );
jQuery(this.refs.pathbar).typeahead({
source: function(query, process) {
- var session = driver.session()
- var t = '(?i).*' + query + '.*'
- var data = []
+ var session = driver.session();
+ var t = '(?i).*' + query + '.*';
+ var data = [];
session.run("MATCH (n) WHERE n.name =~ {name} RETURN n LIMIT 10", {name:t})
.then(function(results){
$.each(results.records, function(index, record){
- data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0])
- })
- session.close()
- return process(data)
- })
+ data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0]);
+ });
+ session.close();
+ return process(data);
+ });
},
afterSelect: function(selected) {
var start = jQuery(this.refs.searchbar).val();
@@ -152,47 +152,47 @@ export default class SearchContainer extends Component {
}.bind(this),
autoSelect: false,
updater: function(item){
- return item.split("#")[0]
+ return item.split("#")[0];
},
highlighter: function(item) {
- var parts = item.split("#")
+ var parts = item.split("#");
var query = this.query;
var icon = "";
- var html = ""
+ var html = "";
switch (parts[1]){
case "Group":
- icon = "
"
+ icon = "
";
break;
case "User":
- icon = "
"
+ icon = "
";
break;
case "Computer":
- icon = "
"
+ icon = "
";
break;
case "Domain":
- icon = "
"
- break
+ icon = "
";
+ break;
}
- html = '
' + parts[0] + ' ' + icon + '
'
+ html = '
' + parts[0] + ' ' + icon + '
';
var reEscQuery = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var reQuery = new RegExp('(' + reEscQuery + ')', "gi");
- var jElem = $(html)
+ var jElem = $(html);
var textNodes = $(jElem.find('*')).add(jElem).contents().filter(function () { return this.nodeType === 3; });
textNodes.replaceWith(function() {
- return $(this).text().replace(reQuery, '
$1 ')
+ return $(this).text().replace(reQuery, '
$1 ');
});
return jElem.html();
}
}
- )
+ );
}
_inputKeyPress(e){
- var key = e.keyCode ? e.keyCode : e.which
+ var key = e.keyCode ? e.keyCode : e.which;
var start = jQuery(this.refs.searchbar).val();
var end = jQuery(this.refs.pathbar).val();
var stop = false;
@@ -201,17 +201,17 @@ export default class SearchContainer extends Component {
if (!$('.searchSelectorS > ul').is(':hidden')){
$('.searchSelectorS > ul li').each(function(i){
if($(this).hasClass('active')){
- stop = true
+ stop = true;
}
- })
+ });
}
if (!$('.searchSelectorP > ul').is(':hidden')){
$('.searchSelectorP > ul li').each(function(i){
if($(this).hasClass('active')){
- stop = true
+ stop = true;
}
- })
+ });
}
if (stop){
return;
@@ -219,8 +219,8 @@ export default class SearchContainer extends Component {
if (!this.state.pathfindingIsOpen) {
if (start !== ""){
var statement = "MATCH (n) WHERE n.name =~ {regex} RETURN n";
- var regex = '(?i).*' + start + '.*'
- emitter.emit('searchQuery', statement, {regex:regex})
+ var regex = '(?i).*' + start + '.*';
+ emitter.emit('searchQuery', statement, {regex:regex});
}
} else {
var start = jQuery(this.refs.searchbar).val();
@@ -257,7 +257,7 @@ export default class SearchContainer extends Component {
tooltipTitle="Back"
classes="input-group-addon spanfix"
click={function(){
- emitter.emit('graphBack')
+ emitter.emit('graphBack');
}}>
@@ -289,6 +289,6 @@ export default class SearchContainer extends Component {
- )
+ );
}
}
\ 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 (
-