commit
60a68c4a54
|
@ -16,7 +16,6 @@
|
||||||
<script src="node_modules/linkurious/dist/plugins.js" type="text/javascript"></script>
|
<script src="node_modules/linkurious/dist/plugins.js" type="text/javascript"></script>
|
||||||
<script src="node_modules/dagre/dist/dagre.min.js" type="text/javascript"></script>
|
<script src="node_modules/dagre/dist/dagre.min.js" type="text/javascript"></script>
|
||||||
<script src="node_modules/bootstrap-3-typeahead/bootstrap3-typeahead.min.js" type="text/javascript"></script>
|
<script src="node_modules/bootstrap-3-typeahead/bootstrap3-typeahead.min.js" type="text/javascript"></script>
|
||||||
<script src="src/js/papaparse.min.js" type="text/javascript"></script>
|
|
||||||
<script src="src/js/simple-slider.min.js" type="text/javascript"></script>
|
<script src="src/js/simple-slider.min.js" type="text/javascript"></script>
|
||||||
<link type="text/css" rel="stylesheet" href="src/css/simple-slider.css">
|
<link type="text/css" rel="stylesheet" href="src/css/simple-slider.css">
|
||||||
<link type="text/css" rel="stylesheet" href="src/css/simple-slider-volume.css">
|
<link type="text/css" rel="stylesheet" href="src/css/simple-slider-volume.css">
|
||||||
|
|
11
package.json
11
package.json
|
@ -28,7 +28,7 @@
|
||||||
},
|
},
|
||||||
"babel": {
|
"babel": {
|
||||||
"presets": [
|
"presets": [
|
||||||
"es2015",
|
"env",
|
||||||
"stage-0",
|
"stage-0",
|
||||||
"react"
|
"react"
|
||||||
]
|
]
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
"babel-core": "^6.22.1",
|
"babel-core": "^6.22.1",
|
||||||
"babel-loader": "^7.0.0",
|
"babel-loader": "^7.0.0",
|
||||||
"babel-polyfill": "^6.22.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-react": "^6.22.0",
|
||||||
"babel-preset-stage-0": "^6.22.0",
|
"babel-preset-stage-0": "^6.22.0",
|
||||||
"concurrently": "^3.1.0",
|
"concurrently": "^3.1.0",
|
||||||
|
@ -56,15 +56,16 @@
|
||||||
"configstore": "^3.1.0",
|
"configstore": "^3.1.0",
|
||||||
"dagre": "^0.7.4",
|
"dagre": "^0.7.4",
|
||||||
"eventemitter2": "^4.1.0",
|
"eventemitter2": "^4.1.0",
|
||||||
|
"fast-csv": "^2.4.1",
|
||||||
"jquery": "^3.2.1",
|
"jquery": "^3.2.1",
|
||||||
"linkurious": "^1.5.1",
|
"linkurious": "^1.5.1",
|
||||||
"mustache": "^2.2.1",
|
"mustache": "^2.2.1",
|
||||||
"neo4j-driver": "^1.3.0",
|
"neo4j-driver": "^1.4.1",
|
||||||
"prop-types": "^15.5.10",
|
|
||||||
"react": "^15.4.2",
|
"react": "^15.4.2",
|
||||||
"react-bootstrap": "^0.31.0",
|
"react-bootstrap": "^0.31.0",
|
||||||
"react-dom": "^15.4.2",
|
"react-dom": "^15.4.2",
|
||||||
"react-if": "^2.1.0",
|
"react-if": "^2.1.0",
|
||||||
"react-transition-group": "^1.1.3"
|
"react-transition-group": "^1.1.3",
|
||||||
|
"unzipper": "^0.8.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,46 +2,46 @@ import React, { Component } from 'react';
|
||||||
import { Alert } from 'react-bootstrap';
|
import { Alert } from 'react-bootstrap';
|
||||||
|
|
||||||
export default class GenericAlert extends Component {
|
export default class GenericAlert extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super()
|
super();
|
||||||
this.state = {
|
this.state = {
|
||||||
visible: false,
|
visible: false,
|
||||||
text: "No data returned from query",
|
text: "No data returned from query",
|
||||||
timeout: null
|
timeout: null
|
||||||
}
|
};
|
||||||
|
|
||||||
emitter.on('showAlert', this._show.bind(this))
|
emitter.on('showAlert', this._show.bind(this));
|
||||||
emitter.on('hideAlert', this._dismiss.bind(this))
|
emitter.on('hideAlert', this._dismiss.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dismiss(){
|
_dismiss(){
|
||||||
this.setState({visible: false});
|
this.setState({visible: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
_show(val){
|
_show(val){
|
||||||
clearTimeout(this.state.timeout)
|
clearTimeout(this.state.timeout);
|
||||||
var t = setTimeout(function(){
|
var t = setTimeout(function(){
|
||||||
this._dismiss()
|
this._dismiss();
|
||||||
}.bind(this), 2500)
|
}.bind(this), 2500);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
visible: true,
|
visible: true,
|
||||||
text: val,
|
text: val,
|
||||||
timeout: t
|
timeout: t
|
||||||
})
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.visible){
|
if (this.state.visible){
|
||||||
return (
|
return (
|
||||||
<Alert className="alertdiv" bsStyle="danger" onDismiss={this._dismiss.bind(this)}>
|
<Alert className="alertdiv" bsStyle="danger" onDismiss={this._dismiss.bind(this)}>
|
||||||
{this.state.text}
|
{this.state.text}
|
||||||
</Alert>
|
</Alert>
|
||||||
)
|
);
|
||||||
}else{
|
}else{
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,280 +1,285 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
export default class Login extends Component {
|
export default class Login extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
this.state = {
|
this.state = {
|
||||||
url: "",
|
url: "",
|
||||||
icon: null,
|
icon: null,
|
||||||
loginEnabled: false,
|
loginEnabled: false,
|
||||||
user: "",
|
user: "",
|
||||||
password: "",
|
password: "",
|
||||||
loginInProgress: false,
|
loginInProgress: false,
|
||||||
save: false
|
save: false
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
checkDBPresence(){
|
componentWillMount() {
|
||||||
var url = this.state.url;
|
var c = conf.get('databaseInfo');
|
||||||
var icon = this.state.icon;
|
if (typeof c !== 'undefined'){
|
||||||
var jicon = jQuery(icon)
|
this.setState({
|
||||||
var btn = jQuery(this.refs.loginButton)
|
url: c.url,
|
||||||
|
user: c.user,
|
||||||
|
password: c.password,
|
||||||
|
save: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (url === ""){
|
componentDidMount() {
|
||||||
return;
|
jQuery(this.refs.password).tooltip({
|
||||||
}
|
placement : 'right',
|
||||||
|
title: '',
|
||||||
|
container: 'body',
|
||||||
|
trigger: 'manual',
|
||||||
|
template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner tooltip-inner-custom"></div></div>'
|
||||||
|
});
|
||||||
|
this.setIcon();
|
||||||
|
|
||||||
jQuery(this.refs.urlspinner).toggle(true)
|
if (this.state.password !== ""){
|
||||||
|
this.checkDBCreds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
url = url.replace(/\/$/, "");
|
setIcon(){
|
||||||
|
var icon = jQuery(this.refs.urlspinner);
|
||||||
|
icon.tooltip({
|
||||||
|
placement : 'right',
|
||||||
|
title: '',
|
||||||
|
container: 'body',
|
||||||
|
delay: {show: 200, hide: 0},
|
||||||
|
template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner tooltip-inner-custom"></div></div>'
|
||||||
|
});
|
||||||
|
icon.toggle(false);
|
||||||
|
this.setState({icon: jQuery(this.refs.urlspinner)});
|
||||||
|
}
|
||||||
|
|
||||||
if (!url.includes(':')){
|
checkDBPresence(){
|
||||||
url = url + ':7687'
|
var url = this.state.url;
|
||||||
}
|
var icon = this.state.icon;
|
||||||
|
var jicon = jQuery(icon);
|
||||||
|
var btn = jQuery(this.refs.loginButton);
|
||||||
|
|
||||||
if (!url.startsWith('bolt://')){
|
if (url === ""){
|
||||||
url = 'bolt://' + url
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
icon.removeClass();
|
jQuery(this.refs.urlspinner).toggle(true);
|
||||||
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();
|
|
||||||
|
|
||||||
driver.onCompleted = function(){
|
url = url.replace(/\/$/, "");
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
checkDBCreds(){
|
if (!url.includes(':')){
|
||||||
if (this.state.loginInProgress){
|
url = url + ':7687';
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
loginInProgress: true,
|
|
||||||
loginEnabled: false
|
|
||||||
})
|
|
||||||
|
|
||||||
var btn = jQuery(this.refs.loginButton)
|
if (!url.startsWith('bolt://')){
|
||||||
var pwf = jQuery(this.refs.password)
|
url = 'bolt://' + url;
|
||||||
|
}
|
||||||
|
|
||||||
var driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password))
|
icon.removeClass();
|
||||||
driver.onError = function(error){
|
icon.addClass("fa fa-spinner fa-spin form-control-feedback");
|
||||||
console.log(error)
|
icon.toggle(true);
|
||||||
if (error.message.includes("authentication failure")){
|
var driver = neo4j.driver(url, neo4j.auth.basic("",""), {encrypted:'ENCRYPTION_ON'});
|
||||||
btn.removeClass('activate');
|
var session = driver.session();
|
||||||
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(){
|
||||||
onCompleted: function(){
|
session.close();
|
||||||
btn.toggleClass('activate');
|
driver.close();
|
||||||
btn.removeClass('btn-default')
|
};
|
||||||
btn.addClass('btn-success')
|
driver.onError = function(error){
|
||||||
btn.html('Success!')
|
if (error.message.includes("authentication failure")){
|
||||||
this.setState({
|
icon.removeClass();
|
||||||
loginInProgress: false
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
var dbinfo = {
|
checkDBCreds(){
|
||||||
url: this.state.url,
|
if (this.state.loginInProgress){
|
||||||
user: this.state.user,
|
return;
|
||||||
password: this.state.password
|
}
|
||||||
}
|
this.setState({
|
||||||
|
loginInProgress: true,
|
||||||
|
loginEnabled: false
|
||||||
|
});
|
||||||
|
|
||||||
if (this.state.save){
|
var btn = jQuery(this.refs.loginButton);
|
||||||
conf.set('databaseInfo',dbinfo)
|
var pwf = jQuery(this.refs.password);
|
||||||
}
|
|
||||||
|
|
||||||
appStore.databaseInfo = dbinfo;
|
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(){
|
||||||
|
|
||||||
jQuery(this.refs.password).tooltip('hide')
|
},
|
||||||
jQuery(this.refs.urlspinner).tooltip('hide')
|
onCompleted: function(){
|
||||||
setTimeout(function(){
|
btn.toggleClass('activate');
|
||||||
jQuery(this.refs.outer).fadeOut(400, function(){
|
btn.removeClass('btn-default');
|
||||||
renderEmit.emit('login');
|
btn.addClass('btn-success');
|
||||||
});
|
btn.html('Success!');
|
||||||
}.bind(this), 1500)
|
this.setState({
|
||||||
driver.close()
|
loginInProgress: false
|
||||||
global.driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password))
|
});
|
||||||
}.bind(this)
|
|
||||||
})
|
|
||||||
|
|
||||||
btn.toggleClass('activate');
|
var dbinfo = {
|
||||||
|
url: this.state.url,
|
||||||
|
user: this.state.user,
|
||||||
|
password: this.state.password
|
||||||
|
};
|
||||||
|
|
||||||
}
|
if (this.state.save){
|
||||||
|
conf.set('databaseInfo',dbinfo);
|
||||||
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
appStore.databaseInfo = dbinfo;
|
||||||
var c = conf.get('databaseInfo')
|
|
||||||
if (typeof c !== 'undefined'){
|
|
||||||
this.setState({
|
|
||||||
url: c.url,
|
|
||||||
user: c.user,
|
|
||||||
password: c.password,
|
|
||||||
save: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
jQuery(this.refs.password).tooltip('hide');
|
||||||
jQuery(this.refs.password).tooltip({
|
jQuery(this.refs.urlspinner).tooltip('hide');
|
||||||
placement : 'right',
|
setTimeout(function(){
|
||||||
title: '',
|
jQuery(this.refs.outer).fadeOut(400, function(){
|
||||||
container: 'body',
|
renderEmit.emit('login');
|
||||||
trigger: 'manual',
|
});
|
||||||
template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner tooltip-inner-custom"></div></div>'
|
}.bind(this), 1500);
|
||||||
})
|
driver.close();
|
||||||
this.setState({icon: jQuery(this.refs.urlspinner)})
|
global.driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password));
|
||||||
var icon = jQuery(this.refs.urlspinner)
|
}.bind(this)
|
||||||
icon.tooltip({
|
});
|
||||||
placement : 'right',
|
|
||||||
title: '',
|
|
||||||
container: 'body',
|
|
||||||
delay: {show: 200, hide: 0},
|
|
||||||
template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner tooltip-inner-custom"></div></div>'
|
|
||||||
})
|
|
||||||
icon.toggle(false)
|
|
||||||
if (this.state.password !== ""){
|
|
||||||
this.checkDBCreds();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_saveChange(event) {
|
btn.toggleClass('activate');
|
||||||
this.setState({save: event.target.checked});
|
|
||||||
}
|
|
||||||
|
|
||||||
_urlChanged(event){
|
}
|
||||||
this.setState({url: event.target.value})
|
|
||||||
}
|
|
||||||
|
|
||||||
_userChanged(event){
|
_saveChange(event) {
|
||||||
this.setState({user: event.target.value})
|
this.setState({save: event.target.checked});
|
||||||
jQuery(this.refs.password).tooltip('hide')
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_passChanged(event){
|
_urlChanged(event){
|
||||||
this.setState({password: event.target.value})
|
this.setState({url: event.target.value});
|
||||||
jQuery(this.refs.password).tooltip('hide')
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_triggerLogin(e){
|
_userChanged(event){
|
||||||
var key = e.keyCode ? e.keyCode : e.which
|
this.setState({user: event.target.value});
|
||||||
|
jQuery(this.refs.password).tooltip('hide');
|
||||||
|
}
|
||||||
|
|
||||||
if (key === 13){
|
_passChanged(event){
|
||||||
this.checkDBCreds()
|
this.setState({password: event.target.value});
|
||||||
}
|
jQuery(this.refs.password).tooltip('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
_triggerLogin(e){
|
||||||
return (
|
var key = e.keyCode ? e.keyCode : e.which;
|
||||||
<div className="loginwindow">
|
|
||||||
<div id="loginpanel" ref="outer">
|
if (key === 13){
|
||||||
<img src="src/img/logo-white-transparent-full.png" />
|
this.checkDBCreds();
|
||||||
<div className="text-center">
|
}
|
||||||
<span>Log in to Neo4j Database</span>
|
}
|
||||||
</div>
|
|
||||||
<form>
|
render() {
|
||||||
<div className="form-group has-feedback">
|
return (
|
||||||
<div className="input-group">
|
<div className="loginwindow">
|
||||||
<span className="input-group-addon" id="dburladdon">
|
<div id="loginpanel" ref="outer">
|
||||||
Database URL
|
<img src="src/img/logo-white-transparent-full.png" />
|
||||||
</span>
|
<div className="text-center">
|
||||||
<input ref="url" onFocus={function(){jQuery(this.state.icon).tooltip('hide');}.bind(this)} onBlur={this.checkDBPresence.bind(this)} onChange={this._urlChanged.bind(this)} type="text" className="form-control" value={this.state.url} placeholder="bolt://localhost:7687" aria-describedby="dburladdon" />
|
<span>Log in to Neo4j Database</span>
|
||||||
<i ref="urlspinner" className="fa fa-spinner fa-spin form-control-feedback" />
|
</div>
|
||||||
</div>
|
<form>
|
||||||
<div className="input-group spacing">
|
<div className="form-group has-feedback">
|
||||||
<span className="input-group-addon" id="dbuseraddon">DB Username</span>
|
<div className="input-group">
|
||||||
<input ref="user" type="text" value={this.state.user} onKeyUp={this._triggerLogin.bind(this)} onChange={this._userChanged.bind(this)} className="form-control" placeholder="neo4j" aria-describedby="dbuseraddon" />
|
<span className="input-group-addon" id="dburladdon">
|
||||||
</div>
|
Database URL
|
||||||
<div className="input-group spacing">
|
</span>
|
||||||
<span className="input-group-addon" id="dbpwaddon">DB Password</span>
|
<input ref="url" onFocus={function(){jQuery(this.state.icon).tooltip('hide');}.bind(this)} onBlur={this.checkDBPresence.bind(this)} onChange={this._urlChanged.bind(this)} type="text" className="form-control" value={this.state.url} placeholder="bolt://localhost:7687" aria-describedby="dburladdon" />
|
||||||
<input ref="password" value={this.state.password} onKeyDown={this._triggerLogin.bind(this)} onChange={this._passChanged.bind(this)} type="password" className="form-control" placeholder="neo4j" aria-describedby="dbpwaddon" />
|
<i ref="urlspinner" className="fa fa-spinner fa-spin form-control-feedback" />
|
||||||
</div>
|
</div>
|
||||||
<div className="savecontainer">
|
<div className="input-group spacing">
|
||||||
<div className="checkbox logincheck">
|
<span className="input-group-addon" id="dbuseraddon">DB Username</span>
|
||||||
<label><input value={this.state.save} onChange={this._saveChange.bind(this)} ref="save" type="checkbox" />Save Password</label>
|
<input ref="user" type="text" value={this.state.user} onKeyUp={this._triggerLogin.bind(this)} onChange={this._userChanged.bind(this)} className="form-control" placeholder="neo4j" aria-describedby="dbuseraddon" />
|
||||||
</div>
|
</div>
|
||||||
<div className="buttoncontainer">
|
<div className="input-group spacing">
|
||||||
<button ref="loginButton" disabled={!this.state.loginEnabled} type="button" onClick={this.checkDBCreds.bind(this)} className="btn btn-primary loginbutton has-spinner">
|
<span className="input-group-addon" id="dbpwaddon">DB Password</span>
|
||||||
Login
|
<input ref="password" value={this.state.password} onKeyDown={this._triggerLogin.bind(this)} onChange={this._passChanged.bind(this)} type="password" className="form-control" placeholder="neo4j" aria-describedby="dbpwaddon" />
|
||||||
<span className="button-spinner">
|
</div>
|
||||||
<i className="fa fa-spinner fa-spin" />
|
<div className="savecontainer">
|
||||||
</span>
|
<div className="checkbox logincheck">
|
||||||
</button>
|
<label><input checked={this.state.save} onChange={this._saveChange.bind(this)} ref="save" type="checkbox" />Save Password</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="buttoncontainer">
|
||||||
</div>
|
<button ref="loginButton" disabled={!this.state.loginEnabled} type="button" onClick={this.checkDBCreds.bind(this)} className="btn btn-primary loginbutton has-spinner">
|
||||||
</form>
|
Login
|
||||||
</div>
|
<span className="button-spinner">
|
||||||
</div>
|
<i className="fa fa-spinner fa-spin" />
|
||||||
);
|
</span>
|
||||||
}
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,138 +1,139 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
export default class Settings extends Component {
|
export default class Settings extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
emitter.on('openSettings', function(){
|
emitter.on('openSettings', function(){
|
||||||
this.openSettings()
|
this.openSettings()
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
|
|
||||||
$(this.refs.edge).simpleSlider({
|
$(this.refs.edge).simpleSlider({
|
||||||
range: [0,20],
|
range: [0,20],
|
||||||
step: 1,
|
step: 1,
|
||||||
theme: 'volume slideinline'
|
theme: 'volume slideinline'
|
||||||
})
|
})
|
||||||
|
|
||||||
$(this.refs.sibling).simpleSlider({
|
$(this.refs.sibling).simpleSlider({
|
||||||
range: [0,20],
|
range: [0,20],
|
||||||
step: 1,
|
step: 1,
|
||||||
theme: 'volume slideinline'
|
theme: 'volume slideinline'
|
||||||
})
|
})
|
||||||
|
|
||||||
$(this.refs.edge).bind('slider:changed', this.edgeChange.bind(this))
|
$(this.refs.edge).bind('slider:changed', this.edgeChange.bind(this))
|
||||||
$(this.refs.sibling).bind('slider:changed', this.siblingChange.bind(this))
|
$(this.refs.sibling).bind('slider:changed', this.siblingChange.bind(this))
|
||||||
|
|
||||||
$(this.refs.edge).simpleSlider('setValue', appStore.performance.edge)
|
$(this.refs.edge).simpleSlider('setValue', appStore.performance.edge)
|
||||||
$(this.refs.sibling).simpleSlider('setValue', appStore.performance.sibling)
|
$(this.refs.sibling).simpleSlider('setValue', appStore.performance.sibling)
|
||||||
|
|
||||||
$(this.refs.check).prop('checked', appStore.performance.lowGraphics)
|
$(this.refs.check).prop('checked', appStore.performance.lowGraphics)
|
||||||
$(this.refs.debug).prop('checked', appStore.performance.debug)
|
$(this.refs.debug).prop('checked', appStore.performance.debug)
|
||||||
|
|
||||||
$(this.refs.outer).fadeToggle(0)
|
$(this.refs.outer).fadeToggle(0)
|
||||||
$(this.refs.outer).draggable()
|
$(this.refs.outer).draggable()
|
||||||
}
|
}
|
||||||
|
|
||||||
edgeChange(event, data){
|
edgeChange(event, data){
|
||||||
appStore.performance.edge = data.value;
|
appStore.performance.edge = data.value;
|
||||||
$(this.refs.edgeinput).val(data.value)
|
$(this.refs.edgeinput).val(data.value)
|
||||||
conf.set('performance', appStore.performance)
|
conf.set('performance', appStore.performance)
|
||||||
}
|
}
|
||||||
|
|
||||||
siblingChange(event, data){
|
siblingChange(event, data){
|
||||||
appStore.performance.sibling = data.value;
|
appStore.performance.sibling = data.value;
|
||||||
$(this.refs.siblinginput).val(data.value)
|
$(this.refs.siblinginput).val(data.value)
|
||||||
conf.set('performance', appStore.performance)
|
conf.set('performance', appStore.performance)
|
||||||
}
|
}
|
||||||
|
|
||||||
onGfxChange(event){
|
onGfxChange(event){
|
||||||
$(this.refs.check).prop('checked', event.target.checked)
|
$(this.refs.check).prop('checked', event.target.checked)
|
||||||
appStore.performance.lowGraphics = event.target.checked
|
appStore.performance.lowGraphics = event.target.checked
|
||||||
conf.set('performance', appStore.performance)
|
conf.set('performance', appStore.performance)
|
||||||
emitter.emit('changeGraphicsMode')
|
emitter.emit('changeGraphicsMode')
|
||||||
}
|
}
|
||||||
|
|
||||||
onDebugChange(event){
|
onDebugChange(event){
|
||||||
$(this.refs.debug).prop('checked', event.target.checked)
|
$(this.refs.debug).prop('checked', event.target.checked)
|
||||||
appStore.performance.debug = event.target.checked
|
appStore.performance.debug = event.target.checked
|
||||||
conf.set('performance', appStore.performance)
|
conf.set('performance', appStore.performance)
|
||||||
}
|
}
|
||||||
|
|
||||||
closeSettings(){
|
closeSettings(){
|
||||||
$(this.refs.outer).fadeToggle(false)
|
$(this.refs.outer).fadeToggle(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
openSettings(){
|
openSettings(){
|
||||||
$(this.refs.outer).fadeToggle(false)
|
$(this.refs.outer).fadeToggle(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSibling(event){
|
updateSibling(event){
|
||||||
$(this.refs.sibling).simpleSlider('setValue', event.target.value)
|
$(this.refs.sibling).simpleSlider('setValue', event.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEdge(event){
|
updateEdge(event){
|
||||||
$(this.refs.edge).simpleSlider('setValue', event.target.value)
|
$(this.refs.edge).simpleSlider('setValue', event.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div ref="outer" className="settingsDiv panel panel-default">
|
<div ref="outer" className="settingsDiv panel panel-default">
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
Settings
|
Settings
|
||||||
<button type="button" className="close" onClick={this.closeSettings.bind(this)} aria-label="Close">
|
<button type="button" className="close" onClick={this.closeSettings.bind(this)} aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="panel-body sliderfix">
|
<div className="panel-body sliderfix">
|
||||||
<div>
|
<div>
|
||||||
<strong>Sibling Collapse Threshold</strong>
|
<strong>Sibling Collapse Threshold</strong>
|
||||||
<i data-toggle="tooltip"
|
<i data-toggle="tooltip"
|
||||||
data-placement="right"
|
data-placement="right"
|
||||||
title="Merge nodes that have the same parent. 0 to Disable, Default 10"
|
title="Merge nodes that have the same parent. 0 to Disable, Default 10"
|
||||||
className="glyphicon glyphicon-question-sign"></i>
|
className="glyphicon glyphicon-question-sign"></i>
|
||||||
<br/>
|
<br/>
|
||||||
<input type="text" ref="sibling" />
|
<input type="text" ref="sibling" />
|
||||||
<span>
|
<span>
|
||||||
<input onChange={this.updateSibling.bind(this)} type="number" min="0" max="20" className="sliderinput" ref="siblinginput" />
|
<input onChange={this.updateSibling.bind(this)} type="number" min="0" max="20" className="sliderinput" ref="siblinginput" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<strong>Node Collapse Threshold</strong>
|
<strong>Node Collapse Threshold</strong>
|
||||||
<i data-toggle="tooltip"
|
<i data-toggle="tooltip"
|
||||||
data-placement="right"
|
data-placement="right"
|
||||||
title="Collapse nodes at the end of paths that only have one relationship. 0 to Disable, Default 5"
|
title="Collapse nodes at the end of paths that only have one relationship. 0 to Disable, Default 5"
|
||||||
className="glyphicon glyphicon-question-sign"></i>
|
className="glyphicon glyphicon-question-sign"></i>
|
||||||
<br />
|
<br />
|
||||||
<input type="text" ref="edge" />
|
<input type="text" ref="edge" />
|
||||||
<span>
|
<span>
|
||||||
<input type="number" min="0" max="20" className="sliderinput" ref="edgeinput" />
|
<input type="number" min="0" max="20" className="sliderinput" ref="edgeinput" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="checkbox-inline">
|
<br />
|
||||||
<label>
|
<div className="checkbox-inline">
|
||||||
<input ref="debug" type="checkbox" onChange={this.onDebugChange.bind(this)}/> Query Debug Mode
|
<label>
|
||||||
</label>
|
<input ref="debug" type="checkbox" onChange={this.onDebugChange.bind(this)}/> Query Debug Mode
|
||||||
</div>
|
</label>
|
||||||
<i data-toggle="tooltip"
|
</div>
|
||||||
data-placement="right"
|
<i data-toggle="tooltip"
|
||||||
title="Dump queries run into the Raw Query Box"
|
data-placement="right"
|
||||||
className="glyphicon glyphicon-question-sign"></i>
|
title="Dump queries run into the Raw Query Box"
|
||||||
<br />
|
className="glyphicon glyphicon-question-sign"></i>
|
||||||
<div className="checkbox-inline">
|
<br />
|
||||||
<label>
|
<div className="checkbox-inline">
|
||||||
<input ref="check" type="checkbox" onChange={this.onGfxChange.bind(this)}/> Low Detail Mode
|
<label>
|
||||||
</label>
|
<input ref="check" type="checkbox" onChange={this.onGfxChange.bind(this)}/> Low Detail Mode
|
||||||
</div>
|
</label>
|
||||||
<i data-toggle="tooltip"
|
</div>
|
||||||
data-placement="right"
|
<i data-toggle="tooltip"
|
||||||
title="Lower detail of graph to improve performance"
|
data-placement="right"
|
||||||
className="glyphicon glyphicon-question-sign"></i>
|
title="Lower detail of graph to improve performance"
|
||||||
</div>
|
className="glyphicon glyphicon-question-sign"></i>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom';
|
||||||
import { findGraphPath } from 'utils';
|
import { findGraphPath } from 'utils';
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var child_process = require('child_process')
|
var child_process = require('child_process');
|
||||||
var child;
|
var child;
|
||||||
var path = require('path')
|
var path = require('path');
|
||||||
const { dialog } = require('electron').remote
|
const { dialog } = require('electron').remote;
|
||||||
|
|
||||||
export default class GraphContainer extends Component {
|
export default class GraphContainer extends Component {
|
||||||
constructor(props){
|
constructor(props){
|
||||||
super(props)
|
super(props);
|
||||||
|
|
||||||
child = child_process.fork(path.join(__dirname,'src','js','worker.js'), {silent:true});
|
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,
|
firstDraw: true,
|
||||||
template: null,
|
template: null,
|
||||||
session: driver.session()
|
session: driver.session()
|
||||||
}
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'src/components/tooltip.html',
|
url: 'src/components/tooltip.html',
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
success: function(response){
|
success: function(response){
|
||||||
this.setState({template: response})
|
this.setState({template: response});
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
})
|
});
|
||||||
|
|
||||||
child.stdout.on('data', (data) => {
|
child.stdout.on('data', (data) => {
|
||||||
console.log(`stdout: ${data}`);
|
console.log(`stdout: ${data}`);
|
||||||
|
@ -38,64 +39,93 @@ export default class GraphContainer extends Component {
|
||||||
});
|
});
|
||||||
|
|
||||||
child.on('message', function(m) {
|
child.on('message', function(m) {
|
||||||
this.loadFromChildProcess(m)
|
this.loadFromChildProcess(m);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
var s1 = driver.session()
|
var s1 = driver.session();
|
||||||
var s2 = driver.session()
|
var s2 = driver.session();
|
||||||
var s3 = driver.session()
|
var s3 = driver.session();
|
||||||
var s4 = driver.session()
|
var s4 = driver.session();
|
||||||
|
|
||||||
s1.run("CREATE CONSTRAINT ON (c:User) ASSERT c.name IS UNIQUE")
|
s1.run("CREATE CONSTRAINT ON (c:User) ASSERT c.name IS UNIQUE")
|
||||||
.then(function(){
|
.then(function(){
|
||||||
s1.close()
|
s1.close();
|
||||||
s2.run("CREATE CONSTRAINT ON (c:Computer) ASSERT c.name IS UNIQUE")
|
s2.run("CREATE CONSTRAINT ON (c:Computer) ASSERT c.name IS UNIQUE")
|
||||||
.then(function(){
|
.then(function(){
|
||||||
s2.close()
|
s2.close();
|
||||||
s3.run("CREATE CONSTRAINT ON (c:Group) ASSERT c.name IS UNIQUE")
|
s3.run("CREATE CONSTRAINT ON (c:Group) ASSERT c.name IS UNIQUE")
|
||||||
.then(function(){
|
.then(function(){
|
||||||
s3.close()
|
s3.close();
|
||||||
s4.run("CREATE CONSTRAINT ON (c:Domain) ASSERT c.name IS UNIQUE")
|
s4.run("CREATE CONSTRAINT ON (c:Domain) ASSERT c.name IS UNIQUE")
|
||||||
.then(function(){
|
.then(function(){
|
||||||
s4.close()
|
s4.close();
|
||||||
})
|
})
|
||||||
.catch(function(){
|
.catch(function(){
|
||||||
s4.close()
|
s4.close();
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.catch(function(){
|
.catch(function(){
|
||||||
s3.close()
|
s3.close();
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.catch(function(){
|
.catch(function(){
|
||||||
s2.close()
|
s2.close();
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.catch(function(){
|
.catch(function(){
|
||||||
s1.close()
|
s1.close();
|
||||||
})
|
});
|
||||||
|
|
||||||
emitter.on('doLogout', function(){
|
emitter.on('doLogout', function(){
|
||||||
this.state.sigmaInstance.graph.clear();
|
this.state.sigmaInstance.graph.clear();
|
||||||
this.state.sigmaInstance.refresh();
|
this.state.sigmaInstance.refresh();
|
||||||
sigma.layouts.killForceLink();
|
sigma.layouts.killForceLink();
|
||||||
this.setState({sigmaInstance: null})
|
this.setState({sigmaInstance: null});
|
||||||
child.kill();
|
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(){
|
relayout(){
|
||||||
sigma.layouts.stopForceLink()
|
sigma.layouts.stopForceLink();
|
||||||
if (appStore.dagre){
|
if (appStore.dagre){
|
||||||
sigma.layouts.dagre.start(this.state.sigmaInstance);
|
sigma.layouts.dagre.start(this.state.sigmaInstance);
|
||||||
}else{
|
}else{
|
||||||
sigma.layouts.startForceLink()
|
sigma.layouts.startForceLink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export(payload){
|
export(payload){
|
||||||
if (payload === 'image'){
|
if (payload === 'image'){
|
||||||
var size = $('#graph').outerWidth()
|
var size = $('#graph').outerWidth();
|
||||||
sigma.plugins.image(this.state.sigmaInstance,
|
sigma.plugins.image(this.state.sigmaInstance,
|
||||||
this.state.sigmaInstance.renderers[0],
|
this.state.sigmaInstance.renderers[0],
|
||||||
{
|
{
|
||||||
|
@ -106,27 +136,27 @@ export default class GraphContainer extends Component {
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
var json = this.state.sigmaInstance.toJSON({
|
var json = this.state.sigmaInstance.toJSON({
|
||||||
pretty: true,
|
pretty: true
|
||||||
})
|
});
|
||||||
|
|
||||||
json = JSON.parse(json)
|
json = JSON.parse(json);
|
||||||
json.spotlight = appStore.spotlightData
|
json.spotlight = appStore.spotlightData;
|
||||||
|
|
||||||
dialog.showSaveDialog({
|
dialog.showSaveDialog({
|
||||||
defaultPath: 'graph.json'
|
defaultPath: 'graph.json'
|
||||||
}, function(loc){
|
}, function(loc){
|
||||||
fs.writeFile(loc, JSON.stringify(json, null, 2))
|
fs.writeFile(loc, JSON.stringify(json, null, 2));
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFromChildProcess(graph){
|
loadFromChildProcess(graph){
|
||||||
if (graph.nodes.length === 0){
|
if (graph.nodes.length === 0){
|
||||||
emitter.emit('showAlert', "No data returned from query")
|
emitter.emit('showAlert', "No data returned from query");
|
||||||
emitter.emit('updateLoadingText', "Done!")
|
emitter.emit('updateLoadingText', "Done!");
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
emitter.emit('showLoadingIndicator', false);
|
emitter.emit('showLoadingIndicator', false);
|
||||||
}, 1500)
|
}, 1500);
|
||||||
}else{
|
}else{
|
||||||
if (!this.state.firstDraw){
|
if (!this.state.firstDraw){
|
||||||
appStore.queryStack.push({
|
appStore.queryStack.push({
|
||||||
|
@ -135,23 +165,23 @@ export default class GraphContainer extends Component {
|
||||||
spotlight: appStore.spotlightData,
|
spotlight: appStore.spotlightData,
|
||||||
startNode: appStore.startNode,
|
startNode: appStore.startNode,
|
||||||
endNode: appStore.endNode
|
endNode: appStore.endNode
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
$.each(graph.nodes, function(i, node){
|
$.each(graph.nodes, function(i, node){
|
||||||
if (node.start){
|
if (node.start){
|
||||||
appStore.startNode = node
|
appStore.startNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.end){
|
if (node.end){
|
||||||
appStore.endNode = node
|
appStore.endNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.glyphs = $.map(node.glyphs, function(value, index) {
|
node.glyphs = $.map(node.glyphs, function(value, index) {
|
||||||
return [value];
|
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 });
|
sigma.misc.animation.camera(this.state.sigmaInstance.camera, { x: 0, y: 0, ratio: 1.075 });
|
||||||
|
|
||||||
appStore.spotlightData = graph.spotlight;
|
appStore.spotlightData = graph.spotlight;
|
||||||
|
@ -164,7 +194,7 @@ export default class GraphContainer extends Component {
|
||||||
if (appStore.dagre){
|
if (appStore.dagre){
|
||||||
sigma.layouts.dagre.start(this.state.sigmaInstance);
|
sigma.layouts.dagre.start(this.state.sigmaInstance);
|
||||||
}else{
|
}else{
|
||||||
sigma.layouts.startForceLink()
|
sigma.layouts.startForceLink();
|
||||||
}
|
}
|
||||||
emitter.emit('spotlightUpdate');
|
emitter.emit('spotlightUpdate');
|
||||||
}
|
}
|
||||||
|
@ -177,44 +207,44 @@ export default class GraphContainer extends Component {
|
||||||
graph = JSON.parse(data);
|
graph = JSON.parse(data);
|
||||||
}catch (err){
|
}catch (err){
|
||||||
emitter.emit('showAlert', 'Bad JSON File');
|
emitter.emit('showAlert', 'Bad JSON File');
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (graph.nodes.length === 0){
|
if (graph.nodes.length === 0){
|
||||||
emitter.emit('showAlert', "No data returned from query")
|
emitter.emit('showAlert', "No data returned from query");
|
||||||
}else{
|
}else{
|
||||||
$.each(graph.nodes, function(i, node){
|
$.each(graph.nodes, function(i, node){
|
||||||
node.glyphs = $.map(node.glyphs, function(value, index) {
|
node.glyphs = $.map(node.glyphs, function(value, index) {
|
||||||
return [value];
|
return [value];
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
appStore.queryStack.push({
|
appStore.queryStack.push({
|
||||||
nodes: this.state.sigmaInstance.graph.nodes(),
|
nodes: this.state.sigmaInstance.graph.nodes(),
|
||||||
edges: this.state.sigmaInstance.graph.edges(),
|
edges: this.state.sigmaInstance.graph.edges(),
|
||||||
spotlight: appStore.spotlightData,
|
spotlight: appStore.spotlightData,
|
||||||
startNode: appStore.startNode,
|
startNode: appStore.startNode,
|
||||||
endNode: appStore.endNode
|
endNode: appStore.endNode
|
||||||
})
|
});
|
||||||
|
|
||||||
appStore.spotlightData = graph.spotlight;
|
appStore.spotlightData = graph.spotlight;
|
||||||
this.state.sigmaInstance.graph.clear();
|
this.state.sigmaInstance.graph.clear();
|
||||||
this.state.sigmaInstance.graph.read(graph);
|
this.state.sigmaInstance.graph.read(graph);
|
||||||
this.state.sigmaInstance.refresh()
|
this.state.sigmaInstance.refresh();
|
||||||
emitter.emit('spotlightUpdate');
|
emitter.emit('spotlightUpdate');
|
||||||
}
|
}
|
||||||
|
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
clearGraph(){
|
clearGraph(){
|
||||||
this.state.sigmaInstance.graph.clear()
|
this.state.sigmaInstance.graph.clear();
|
||||||
this.state.sigmaInstance.refresh()
|
this.state.sigmaInstance.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
setGraphicsMode(){
|
setGraphicsMode(){
|
||||||
var lowgfx = appStore.performance.lowGraphics
|
var lowgfx = appStore.performance.lowGraphics;
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
this.state.design.clear()
|
this.state.design.clear();
|
||||||
if (lowgfx){
|
if (lowgfx){
|
||||||
sigmaInstance.settings('defaultEdgeType', 'line');
|
sigmaInstance.settings('defaultEdgeType', 'line');
|
||||||
sigmaInstance.settings('defaultEdgeColor', 'black');
|
sigmaInstance.settings('defaultEdgeColor', 'black');
|
||||||
|
@ -226,28 +256,9 @@ export default class GraphContainer extends Component {
|
||||||
this.state.design.setPalette(appStore.highResPalette);
|
this.state.design.setPalette(appStore.highResPalette);
|
||||||
this.state.design.setStyles(appStore.highResStyle);
|
this.state.design.setStyles(appStore.highResStyle);
|
||||||
}
|
}
|
||||||
this.state.design.deprecate()
|
this.state.design.deprecate();
|
||||||
sigmaInstance.refresh()
|
sigmaInstance.refresh();
|
||||||
this.state.design.apply()
|
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetZoom(){
|
resetZoom(){
|
||||||
|
@ -258,7 +269,7 @@ export default class GraphContainer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomOut(){
|
zoomOut(){
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
var cam = sigmaInstance.camera;
|
var cam = sigmaInstance.camera;
|
||||||
|
|
||||||
sigma.misc.animation.camera(cam, {
|
sigma.misc.animation.camera(cam, {
|
||||||
|
@ -269,7 +280,7 @@ export default class GraphContainer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomIn(){
|
zoomIn(){
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
var cam = sigmaInstance.camera;
|
var cam = sigmaInstance.camera;
|
||||||
|
|
||||||
sigma.misc.animation.camera(cam,
|
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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="graph">
|
<div className="graph">
|
||||||
|
@ -321,25 +322,25 @@ export default class GraphContainer extends Component {
|
||||||
|
|
||||||
spotlightClickHandler(nodeId, parentId){
|
spotlightClickHandler(nodeId, parentId){
|
||||||
var sigmaInstance = this.state.sigmaInstance;
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
var parent = sigmaInstance.graph.nodes(nodeId)
|
var parent = sigmaInstance.graph.nodes(nodeId);
|
||||||
var label, child;
|
var label, child;
|
||||||
if (typeof parent === 'undefined'){
|
if (typeof parent === 'undefined'){
|
||||||
child = sigmaInstance.graph.nodes(parentId).folded.nodes.filter(function(val){
|
child = sigmaInstance.graph.nodes(parentId).folded.nodes.filter(function(val){
|
||||||
return val.id == nodeId;
|
return val.id === nodeId;
|
||||||
})[0]
|
})[0];
|
||||||
parent = sigmaInstance.graph.nodes(parentId);
|
parent = sigmaInstance.graph.nodes(parentId);
|
||||||
}else{
|
}else{
|
||||||
child = parent;
|
child = parent;
|
||||||
}
|
}
|
||||||
label = child.label;
|
label = child.label;
|
||||||
if (child.type_user){
|
if (child.type_user){
|
||||||
emitter.emit('userNodeClicked', label)
|
emitter.emit('userNodeClicked', label);
|
||||||
}else if (child.type_group){
|
}else if (child.type_group){
|
||||||
emitter.emit('groupNodeClicked', label)
|
emitter.emit('groupNodeClicked', label);
|
||||||
}else if (child.type_computer){
|
}else if (child.type_computer){
|
||||||
emitter.emit('computerNodeClicked', label)
|
emitter.emit('computerNodeClicked', label);
|
||||||
}
|
}
|
||||||
parent.color = "#2DC486"
|
parent.color = "#2DC486";
|
||||||
sigma.misc.animation.camera(
|
sigma.misc.animation.camera(
|
||||||
sigmaInstance.camera, {
|
sigmaInstance.camera, {
|
||||||
x: parent[sigmaInstance.camera.readPrefix + 'x'],
|
x: parent[sigmaInstance.camera.readPrefix + 'x'],
|
||||||
|
@ -351,119 +352,120 @@ export default class GraphContainer extends Component {
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
parent.color = "black";
|
parent.color = "black";
|
||||||
sigmaInstance.refresh({skipIndexation: true});
|
sigmaInstance.refresh({skipIndexation: true});
|
||||||
}, 2000)
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
doQueryNative(params){
|
doQueryNative(params){
|
||||||
if (appStore.performance.debug){
|
if (appStore.performance.debug){
|
||||||
emitter.emit('setRawQuery',params.statement);
|
emitter.emit('setRawQuery',params.statement);
|
||||||
}
|
}
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
var nodes = {}
|
var nodes = {};
|
||||||
var edges = {}
|
var edges = {};
|
||||||
var session = driver.session()
|
var session = driver.session();
|
||||||
if (typeof params.props === 'undefined'){
|
if (typeof params.props === 'undefined'){
|
||||||
params.props = {}
|
params.props = {};
|
||||||
}
|
}
|
||||||
emitter.emit('showLoadingIndicator', true);
|
emitter.emit('showLoadingIndicator', true);
|
||||||
emitter.emit('updateLoadingText', "Querying Database")
|
emitter.emit('updateLoadingText', "Querying Database");
|
||||||
emitter.emit('resetSpotlight')
|
emitter.emit('resetSpotlight');
|
||||||
session.run(params.statement, params.props)
|
session.run(params.statement, params.props)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
onNext: function(result){
|
onNext: function(result){
|
||||||
$.each(result._fields, function(index, field){
|
$.each(result._fields, function(index, field){
|
||||||
if (field != null){
|
if (field !== null){
|
||||||
if (field.hasOwnProperty('segments')){
|
if (field.hasOwnProperty('segments')){
|
||||||
$.each(field.segments,function(index, segment){
|
$.each(field.segments,function(index, segment){
|
||||||
var end = this.createNodeFromRow(segment.end, params)
|
var end = this.createNodeFromRow(segment.end, params);
|
||||||
var start = this.createNodeFromRow(segment.start, params)
|
var start = this.createNodeFromRow(segment.start, params);
|
||||||
var edge = this.createEdgeFromRow(segment.relationship)
|
var edge = this.createEdgeFromRow(segment.relationship);
|
||||||
|
|
||||||
if (!edges[edge.id]){
|
if (!edges[edge.id]){
|
||||||
edges[edge.id] = edge
|
edges[edge.id] = edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nodes[end.id]){
|
if (!nodes[end.id]){
|
||||||
nodes[end.id] = end
|
nodes[end.id] = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nodes[start.id]){
|
if (!nodes[start.id]){
|
||||||
nodes[start.id] = start
|
nodes[start.id] = start;
|
||||||
}
|
}
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
}else{
|
}else{
|
||||||
if ($.isArray(field)){
|
if ($.isArray(field)){
|
||||||
$.each(field, function(index, value){
|
$.each(field, function(index, value){
|
||||||
if (value != null){
|
if (value !== null){
|
||||||
var id = value.identity.low
|
var id = value.identity.low;
|
||||||
if (value.end && !edges.id){
|
if (value.end && !edges.id){
|
||||||
edges[id] = this.createEdgeFromRow(value)
|
edges[id] = this.createEdgeFromRow(value);
|
||||||
}else if (!nodes.id){
|
}else if (!nodes.id){
|
||||||
nodes[id] = this.createNodeFromRow(value, params)
|
nodes[id] = this.createNodeFromRow(value, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
}else{
|
}else{
|
||||||
var id = field.identity.low
|
var id = field.identity.low;
|
||||||
if (field.end && !edges.id){
|
if (field.end && !edges.id){
|
||||||
edges[id] = this.createEdgeFromRow(field)
|
edges[id] = this.createEdgeFromRow(field);
|
||||||
}else if (!nodes.id){
|
}else if (!nodes.id){
|
||||||
nodes[id] = this.createNodeFromRow(field, params)
|
nodes[id] = this.createNodeFromRow(field, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
onError: function(error){
|
onError: function(error){
|
||||||
console.log(error)
|
console.log(error);
|
||||||
},
|
},
|
||||||
onCompleted: function(){
|
onCompleted: function(){
|
||||||
var graph = {nodes:[],edges:[]}
|
var graph = {nodes:[],edges:[]};
|
||||||
$.each(nodes, function(node){
|
$.each(nodes, function(node){
|
||||||
graph.nodes.push(nodes[node])
|
graph.nodes.push(nodes[node]);
|
||||||
})
|
});
|
||||||
|
|
||||||
$.each(edges, function(edge){
|
$.each(edges, function(edge){
|
||||||
graph.edges.push(edges[edge])
|
graph.edges.push(edges[edge]);
|
||||||
})
|
});
|
||||||
emitter.emit('updateLoadingText', "Processing Data")
|
emitter.emit('updateLoadingText', "Processing Data");
|
||||||
|
|
||||||
child.send(JSON.stringify({graph: graph,
|
child.send(JSON.stringify({graph: graph,
|
||||||
edge: params.allowCollapse ? appStore.performance.edge : 0 ,
|
edge: params.allowCollapse ? appStore.performance.edge : 0 ,
|
||||||
sibling: params.allowCollapse ? appStore.performance.sibling : 0,
|
sibling: params.allowCollapse ? appStore.performance.sibling : 0,
|
||||||
start: params.start,
|
start: params.start,
|
||||||
end: params.end
|
end: params.end
|
||||||
}))
|
}));
|
||||||
session.close()
|
session.close();
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createEdgeFromRow(data){
|
createEdgeFromRow(data){
|
||||||
var id = data.identity.low
|
var id = data.identity.low;
|
||||||
var type = data.type
|
var type = data.type;
|
||||||
var source = data.start.low
|
var source = data.start.low;
|
||||||
var target = data.end.low
|
var target = data.end.low;
|
||||||
var edge = {
|
var edge = {
|
||||||
id: id,
|
id: id,
|
||||||
type: type,
|
type: type,
|
||||||
source: source,
|
source: source,
|
||||||
target:target,
|
target:target,
|
||||||
label: type
|
label: type
|
||||||
}
|
};
|
||||||
|
|
||||||
return edge
|
return edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
createNodeFromRow(data, params){
|
createNodeFromRow(data, params){
|
||||||
var id = data.identity.low
|
var id = data.identity.low;
|
||||||
var type = data.labels[0]
|
var type = data.labels[0];
|
||||||
var label = data.properties.name
|
var label = data.properties.name;
|
||||||
var node = {
|
var node = {
|
||||||
id: id,
|
id: id,
|
||||||
type: type,
|
type: type,
|
||||||
label: label,
|
label: label,
|
||||||
|
Enabled: data.properties.Enabled,
|
||||||
glyphs: [],
|
glyphs: [],
|
||||||
folded: {
|
folded: {
|
||||||
nodes: [],
|
nodes: [],
|
||||||
|
@ -471,28 +473,28 @@ export default class GraphContainer extends Component {
|
||||||
},
|
},
|
||||||
x: Math.random(),
|
x: Math.random(),
|
||||||
y: Math.random()
|
y: Math.random()
|
||||||
}
|
};
|
||||||
|
|
||||||
if (label === params.start){
|
if (label === params.start){
|
||||||
node.start = true
|
node.start = true;
|
||||||
node.glyphs.push({
|
node.glyphs.push({
|
||||||
'position': 'bottom-right',
|
'position': 'bottom-right',
|
||||||
'font': 'FontAwesome',
|
'font': 'FontAwesome',
|
||||||
'content': '\uF21D',
|
'content': '\uF21D',
|
||||||
'fillColor': '#3399FF',
|
'fillColor': '#3399FF',
|
||||||
'fontScale': 1.5
|
'fontScale': 1.5
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (label === params.end){
|
if (label === params.end){
|
||||||
node.end = true
|
node.end = true;
|
||||||
node.glyphs.push({
|
node.glyphs.push({
|
||||||
'position': 'bottom-right',
|
'position': 'bottom-right',
|
||||||
'font': 'FontAwesome',
|
'font': 'FontAwesome',
|
||||||
'fillColor': '#990000',
|
'fillColor': '#990000',
|
||||||
'content': '\uF05B',
|
'content': '\uF05B',
|
||||||
'fontScale': 1.5
|
'fontScale': 1.5
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -510,60 +512,60 @@ export default class GraphContainer extends Component {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return node
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
unfoldEdgeNode(id){
|
unfoldEdgeNode(id){
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
sigmaInstance.graph.read(sigmaInstance.graph.nodes(id).folded)
|
sigmaInstance.graph.read(sigmaInstance.graph.nodes(id).folded);
|
||||||
this.state.design.deprecate()
|
this.state.design.deprecate();
|
||||||
this.state.design.apply();
|
this.state.design.apply();
|
||||||
this.relayout()
|
this.relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
foldEdgeNode(id){
|
foldEdgeNode(id){
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
$.each(sigmaInstance.graph.nodes(id).folded.nodes, function(index, node){
|
$.each(sigmaInstance.graph.nodes(id).folded.nodes, function(index, node){
|
||||||
sigmaInstance.graph.dropNode(node.id)
|
sigmaInstance.graph.dropNode(node.id);
|
||||||
})
|
});
|
||||||
sigmaInstance.refresh()
|
sigmaInstance.refresh();
|
||||||
this.state.design.deprecate();
|
this.state.design.deprecate();
|
||||||
this.state.design.apply();
|
this.state.design.apply();
|
||||||
this.relayout();
|
this.relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
ungroupNode(id){
|
ungroupNode(id){
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
var node = sigmaInstance.graph.nodes(id)
|
var node = sigmaInstance.graph.nodes(id);
|
||||||
sigmaInstance.graph.dropNode(id);
|
sigmaInstance.graph.dropNode(id);
|
||||||
sigmaInstance.graph.read(node.folded)
|
sigmaInstance.graph.read(node.folded);
|
||||||
this.state.design.deprecate()
|
this.state.design.deprecate();
|
||||||
sigmaInstance.refresh()
|
sigmaInstance.refresh();
|
||||||
this.state.design.apply()
|
this.state.design.apply();
|
||||||
this.relayout();
|
this.relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
doSearchQuery(payload, props){
|
doSearchQuery(payload, props){
|
||||||
if (typeof props === 'undefined'){
|
if (typeof props === 'undefined'){
|
||||||
props = {}
|
props = {};
|
||||||
}
|
}
|
||||||
this.doQueryNative({
|
this.doQueryNative({
|
||||||
statement: payload,
|
statement: payload,
|
||||||
allowCollapse: true,
|
allowCollapse: true,
|
||||||
props: props
|
props: props
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doPathQuery(start, end){
|
doPathQuery(start, end){
|
||||||
var statement = "MATCH (n {name:{start}}), (m {name:{end}}), p=allShortestPaths((n)-[*]->(m)) RETURN p"
|
var statement = "MATCH (n {name:{start}}), (m {name:{end}}), p=allShortestPaths((n)-[*]->(m)) RETURN p";
|
||||||
var props = {start: start, end: end}
|
var props = {start: start, end: end};
|
||||||
this.doQueryNative({
|
this.doQueryNative({
|
||||||
statement: statement,
|
statement: statement,
|
||||||
allowCollapse: true,
|
allowCollapse: true,
|
||||||
props: props,
|
props: props,
|
||||||
start: start,
|
start: start,
|
||||||
end: end
|
end: end
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doGenericQuery(statement, props, start, end, allowCollapse=true){
|
doGenericQuery(statement, props, start, end, allowCollapse=true){
|
||||||
|
@ -572,7 +574,7 @@ export default class GraphContainer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof props === 'undefined'){
|
if (typeof props === 'undefined'){
|
||||||
props = {}
|
props = {};
|
||||||
}
|
}
|
||||||
this.doQueryNative({
|
this.doQueryNative({
|
||||||
statement: statement,
|
statement: statement,
|
||||||
|
@ -580,26 +582,26 @@ export default class GraphContainer extends Component {
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
props: props
|
props: props
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_nodeDragged(){
|
_nodeDragged(){
|
||||||
this.setState({dragged:true})
|
this.setState({dragged:true});
|
||||||
}
|
}
|
||||||
|
|
||||||
_nodeClicked(n){
|
_nodeClicked(n){
|
||||||
if (!this.state.dragged){
|
if (!this.state.dragged){
|
||||||
if (n.data.node.type_user){
|
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){
|
}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')){
|
}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){
|
}else if (n.data.node.type_domain){
|
||||||
emitter.emit('domainNodeClicked', n.data.node.label)
|
emitter.emit('domainNodeClicked', n.data.node.label);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
this.setState({dragged: false})
|
this.setState({dragged: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,7 +612,7 @@ export default class GraphContainer extends Component {
|
||||||
{
|
{
|
||||||
container: 'graph'
|
container: 'graph'
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
sigmaInstance.settings(
|
sigmaInstance.settings(
|
||||||
{
|
{
|
||||||
|
@ -629,7 +631,7 @@ export default class GraphContainer extends Component {
|
||||||
zoomingRatio: 1.4,
|
zoomingRatio: 1.4,
|
||||||
scalingMode: 'inside'
|
scalingMode: 'inside'
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
//Bind sigma events
|
//Bind sigma events
|
||||||
sigmaInstance.renderers[0].bind('render', function(e) {
|
sigmaInstance.renderers[0].bind('render', function(e) {
|
||||||
|
@ -642,21 +644,21 @@ export default class GraphContainer extends Component {
|
||||||
}else{
|
}else{
|
||||||
sigmaInstance.settings('drawEdgeLabels', true);
|
sigmaInstance.settings('drawEdgeLabels', true);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
sigmaInstance.bind('clickNode', this._nodeClicked.bind(this))
|
sigmaInstance.bind('clickNode', this._nodeClicked.bind(this));
|
||||||
|
|
||||||
sigmaInstance.bind('hovers', function(e){
|
sigmaInstance.bind('hovers', function(e){
|
||||||
if (e.data.enter.nodes.length > 0) {
|
if (e.data.enter.nodes.length > 0) {
|
||||||
if (appStore.endNode !== null) {
|
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) {
|
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) {
|
if (e.data.leave.nodes.length > 0) {
|
||||||
|
@ -668,13 +670,13 @@ export default class GraphContainer extends Component {
|
||||||
sigmaInstance.refresh({ 'skipIndexation': true });
|
sigmaInstance.refresh({ 'skipIndexation': true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
//Some key binds
|
//Some key binds
|
||||||
$(window).on('keyup', function(e){
|
$(window).on('keyup', function(e){
|
||||||
var key = e.keyCode ? e.keyCode : e.which
|
var key = e.keyCode ? e.keyCode : e.which;
|
||||||
var mode = appStore.performance.nodeLabels
|
var mode = appStore.performance.nodeLabels;
|
||||||
var sigmaInstance = this.state.sigmaInstance
|
var sigmaInstance = this.state.sigmaInstance;
|
||||||
|
|
||||||
if (document.activeElement === document.body && key === 17){
|
if (document.activeElement === document.body && key === 17){
|
||||||
mode = mode + 1;
|
mode = mode + 1;
|
||||||
|
@ -682,28 +684,28 @@ export default class GraphContainer extends Component {
|
||||||
mode = 0;
|
mode = 0;
|
||||||
}
|
}
|
||||||
appStore.performance.nodeLabels = mode;
|
appStore.performance.nodeLabels = mode;
|
||||||
conf.set('performance', appStore.performance)
|
conf.set('performance', appStore.performance);
|
||||||
|
|
||||||
if (mode === 0){
|
if (mode === 0){
|
||||||
sigmaInstance.settings('labelThreshold', 500);
|
sigmaInstance.settings('labelThreshold', 500);
|
||||||
emitter.emit('showAlert', 'Hiding Node Labels')
|
emitter.emit('showAlert', 'Hiding Node Labels');
|
||||||
}else if (mode === 1){
|
}else if (mode === 1){
|
||||||
sigmaInstance.settings('labelThreshold', 15);
|
sigmaInstance.settings('labelThreshold', 15);
|
||||||
emitter.emit('showAlert', 'Default Node Label Threshold')
|
emitter.emit('showAlert', 'Default Node Label Threshold');
|
||||||
}else{
|
}else{
|
||||||
sigmaInstance.settings('labelThreshold', 1);
|
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
|
//Plugin Configuration
|
||||||
var dragListener = sigma.plugins.dragNodes(sigmaInstance,
|
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(
|
var tooltips = sigma.plugins.tooltips(
|
||||||
sigmaInstance,
|
sigmaInstance,
|
||||||
|
@ -718,7 +720,7 @@ export default class GraphContainer extends Component {
|
||||||
node.expand = false;
|
node.expand = false;
|
||||||
node.collapse = false;
|
node.collapse = false;
|
||||||
if (node.folded.nodes.length > 0 && !node.groupedNode) {
|
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;
|
node.expand = true;
|
||||||
} else {
|
} else {
|
||||||
node.collapse = true;
|
node.collapse = true;
|
||||||
|
@ -753,12 +755,12 @@ export default class GraphContainer extends Component {
|
||||||
forcelinkListener.bind('stop', function(event) {
|
forcelinkListener.bind('stop', function(event) {
|
||||||
emitter.emit('updateLoadingText', "Fixing Overlap");
|
emitter.emit('updateLoadingText', "Fixing Overlap");
|
||||||
sigmaInstance.startNoverlap();
|
sigmaInstance.startNoverlap();
|
||||||
})
|
});
|
||||||
|
|
||||||
forcelinkListener.bind('start', function(event){
|
forcelinkListener.bind('start', function(event){
|
||||||
emitter.emit('updateLoadingText', 'Initial Layout')
|
emitter.emit('updateLoadingText', 'Initial Layout');
|
||||||
emitter.emit('showLoadingIndicator', true)
|
emitter.emit('showLoadingIndicator', true);
|
||||||
})
|
});
|
||||||
|
|
||||||
var dagreListener = sigma.layouts.dagre.configure(sigmaInstance, {
|
var dagreListener = sigma.layouts.dagre.configure(sigmaInstance, {
|
||||||
easing: 'cubicInOut',
|
easing: 'cubicInOut',
|
||||||
|
@ -774,22 +776,22 @@ export default class GraphContainer extends Component {
|
||||||
emitter.emit('updateLoadingText', "Fixing Overlap");
|
emitter.emit('updateLoadingText', "Fixing Overlap");
|
||||||
sigmaInstance.startNoverlap();
|
sigmaInstance.startNoverlap();
|
||||||
needsfix = true;
|
needsfix = true;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
if (!needsfix){
|
if (!needsfix){
|
||||||
emitter.emit('updateLoadingText', 'Done!');
|
emitter.emit('updateLoadingText', 'Done!');
|
||||||
sigma.canvas.edges.autoCurve(sigmaInstance)
|
sigma.canvas.edges.autoCurve(sigmaInstance);
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
emitter.emit('showLoadingIndicator', false);
|
emitter.emit('showLoadingIndicator', false);
|
||||||
}, 1500)
|
}, 1500);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
dagreListener.bind('start', function(event){
|
dagreListener.bind('start', function(event){
|
||||||
emitter.emit('updateLoadingText', 'Initial Layout')
|
emitter.emit('updateLoadingText', 'Initial Layout');
|
||||||
emitter.emit('showLoadingIndicator', true)
|
emitter.emit('showLoadingIndicator', true);
|
||||||
})
|
});
|
||||||
|
|
||||||
// var noverlapListener = sigmaInstance.configNoverlap({
|
// var noverlapListener = sigmaInstance.configNoverlap({
|
||||||
// nodeMargin: 5.0,
|
// 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) {
|
noverlapListener.bind('stop', function(event) {
|
||||||
emitter.emit('updateLoadingText', 'Done!');
|
emitter.emit('updateLoadingText', 'Done!');
|
||||||
sigma.canvas.edges.autoCurve(sigmaInstance)
|
sigma.canvas.edges.autoCurve(sigmaInstance);
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
emitter.emit('showLoadingIndicator', false);
|
emitter.emit('showLoadingIndicator', false);
|
||||||
}, 1500)
|
}, 1500);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var lowgfx = appStore.performance.lowGraphics
|
var lowgfx = appStore.performance.lowGraphics;
|
||||||
|
|
||||||
design = sigma.plugins.design(sigmaInstance);
|
design = sigma.plugins.design(sigmaInstance);
|
||||||
if (lowgfx){
|
if (lowgfx){
|
||||||
|
@ -826,7 +828,7 @@ export default class GraphContainer extends Component {
|
||||||
design.setStyles(appStore.highResStyle);
|
design.setStyles(appStore.highResStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mode = appStore.performance.nodeLabels
|
var mode = appStore.performance.nodeLabels;
|
||||||
|
|
||||||
if (mode === 0){
|
if (mode === 0){
|
||||||
sigmaInstance.settings('labelThreshold', 500);
|
sigmaInstance.settings('labelThreshold', 500);
|
||||||
|
|
|
@ -1,284 +1,310 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import MenuButton from './MenuButton';
|
import MenuButton from './MenuButton';
|
||||||
import ProgressBarMenuButton from './ProgressBarMenuButton';
|
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';
|
import { If, Then, Else } from 'react-if';
|
||||||
const { dialog, clipboard } = require('electron').remote
|
const { dialog, clipboard, app } = require('electron').remote;
|
||||||
var fs = require('fs')
|
var fs = require('fs');
|
||||||
var async = require('async')
|
var async = require('async');
|
||||||
|
var unzip = require('unzipper');
|
||||||
|
var fpath = require('path');
|
||||||
|
var csv = require('fast-csv');
|
||||||
|
|
||||||
export default class MenuContainer extends Component {
|
export default class MenuContainer extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super()
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
refreshHover: false,
|
refreshHover: false,
|
||||||
uploading: false,
|
uploading: false,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
parser: null
|
cancelled: false
|
||||||
}
|
};
|
||||||
|
|
||||||
emitter.on('cancelUpload', this.cancelUpload.bind(this))
|
emitter.on('cancelUpload', this.cancelUpload.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelUpload(){
|
cancelUpload(){
|
||||||
this.state.parser.abort()
|
this.setState({cancelled: true});
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
this.setState({uploading: false})
|
this.setState({uploading: false})
|
||||||
}.bind(this), 1000)
|
}.bind(this), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
_refreshClick(){
|
_refreshClick(){
|
||||||
emitter.emit('graphRefresh')
|
emitter.emit('graphRefresh')
|
||||||
}
|
}
|
||||||
|
|
||||||
_changeLayoutClick(){
|
_changeLayoutClick(){
|
||||||
appStore.dagre = !appStore.dagre
|
appStore.dagre = !appStore.dagre
|
||||||
emitter.emit('graphRefresh')
|
emitter.emit('graphRefresh')
|
||||||
var type = appStore.dagre ? 'Hierarchical' : 'Directed'
|
var type = appStore.dagre ? 'Hierarchical' : 'Directed'
|
||||||
emitter.emit('showAlert', 'Changed Layout to ' + type)
|
emitter.emit('showAlert', 'Changed Layout to ' + type)
|
||||||
}
|
}
|
||||||
|
|
||||||
_exportClick(){
|
_exportClick(){
|
||||||
emitter.emit('showExport');
|
emitter.emit('showExport');
|
||||||
}
|
}
|
||||||
|
|
||||||
_importClick(){
|
_importClick(){
|
||||||
var fname = dialog.showOpenDialog({
|
var fname = dialog.showOpenDialog({
|
||||||
properties: ['openFile']
|
properties: ['openFile']
|
||||||
})
|
});
|
||||||
if (typeof fname !== 'undefined'){
|
if (typeof fname !== 'undefined'){
|
||||||
emitter.emit('import',fname[0])
|
emitter.emit('import',fname[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_settingsClick(){
|
_settingsClick(){
|
||||||
emitter.emit('openSettings')
|
emitter.emit('openSettings')
|
||||||
}
|
}
|
||||||
|
|
||||||
_cancelUploadClick(){
|
_cancelUploadClick(){
|
||||||
emitter.emit('showCancelUpload')
|
emitter.emit('showCancelUpload')
|
||||||
}
|
}
|
||||||
|
|
||||||
_uploadClick(){
|
_uploadClick(){
|
||||||
var input = jQuery(this.refs.fileInput)
|
var input = jQuery(this.refs.fileInput);
|
||||||
var files = $.makeArray(input[0].files)
|
var fileNames = [];
|
||||||
|
|
||||||
async.eachSeries(files, function(file, callback){
|
$.each(input[0].files, function(index, file){
|
||||||
emitter.emit('showAlert', 'Processing file {}'.format(file.name));
|
fileNames.push({path:file.path, name:file.name});
|
||||||
this.processFile(file.path, file, callback)
|
});
|
||||||
}.bind(this),
|
|
||||||
function done(){
|
|
||||||
setTimeout(function(){
|
|
||||||
this.setState({uploading: false})
|
|
||||||
}.bind(this), 3000)
|
|
||||||
}.bind(this))
|
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
_aboutClick(){
|
input.val('');
|
||||||
emitter.emit('showAbout')
|
}.bind(this));
|
||||||
}
|
|
||||||
|
|
||||||
processFile(filename, fileobject, callback){
|
}
|
||||||
var sent = 0
|
|
||||||
|
|
||||||
var i;
|
async unzipNecessary(files){
|
||||||
var count = 0;
|
var index = 0;
|
||||||
var header = ""
|
var processed = [];
|
||||||
var procHeader = true;
|
var tempPath = app.getPath('temp');
|
||||||
fs.createReadStream(filename)
|
while (index < files.length){
|
||||||
.on('data', function(chunk) {
|
var path = files[index].path;
|
||||||
for (i=0; i < chunk.length; ++i){
|
var name = files[index].name;
|
||||||
if (procHeader){
|
|
||||||
header = header + String.fromCharCode(chunk[i])
|
|
||||||
}
|
|
||||||
if (chunk[i] == 10){
|
|
||||||
if (procHeader){
|
|
||||||
procHeader = false;
|
|
||||||
}
|
|
||||||
count++
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
if (path.endsWith(".zip")){
|
||||||
.on('end', function() {
|
await fs.createReadStream(path)
|
||||||
count = count - 1
|
.pipe(unzip.Parse())
|
||||||
var filetype;
|
.on('entry', function(entry){
|
||||||
if (header.includes('UserName') && header.includes('ComputerName') && header.includes('Weight')){
|
var output = fpath.join(tempPath, entry.path);
|
||||||
filetype = 'sessions'
|
entry.pipe(fs.createWriteStream(output));
|
||||||
}else if (header.includes('AccountName') && header.includes('AccountType') && header.includes('GroupName')){
|
processed.push({path:output, name:entry.path, delete: true});
|
||||||
filetype = 'groupmembership'
|
}).promise();
|
||||||
}else if (header.includes('AccountName') && header.includes('AccountType') && header.includes('ComputerName')){
|
}else{
|
||||||
filetype = 'localadmin'
|
processed.push({path:path,name:name, delete: false});
|
||||||
}else if (header.includes('SourceDomain') && header.includes('TargetDomain') && header.includes('TrustDirection') && header.includes('TrustType') && header.includes('Transitive')){
|
}
|
||||||
filetype = 'domain'
|
index++;
|
||||||
}else if (header.includes('ActiveDirectoryRights') && header.includes('ObjectType') && header.includes('PrincipalType')){
|
}
|
||||||
filetype = 'acl'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof filetype === 'undefined'){
|
return processed;
|
||||||
emitter.emit('showAlert', 'Unrecognized CSV Type');
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
_aboutClick(){
|
||||||
uploading: true,
|
emitter.emit('showAbout');
|
||||||
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)
|
|
||||||
|
|
||||||
console.time('IngestTime')
|
processFile(file, callback){
|
||||||
Papa.parse(fileobject,{
|
console.log(file);
|
||||||
header: true,
|
var count = 0;
|
||||||
dynamicTyping: true,
|
var header = "";
|
||||||
skipEmptyLines: true,
|
var processHeader = true;
|
||||||
chunkSize: 5242880,
|
var fileType;
|
||||||
//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()
|
//Lets calculate the number of lines in the file and get the header
|
||||||
var tx = session.beginTransaction()
|
var input = fs.createReadStream(file);
|
||||||
var promises = []
|
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;
|
||||||
|
|
||||||
promises.push(tx.run(userQuery, {props: props.users}))
|
//Subtract one line to account for the header
|
||||||
promises.push(tx.run(computerQuery, {props: props.computers}))
|
count--;
|
||||||
promises.push(tx.run(groupQuery, {props: props.groups}))
|
|
||||||
|
|
||||||
Promise.all(promises)
|
//Change the UI to display our uploading state
|
||||||
.then(function(){
|
this.setState({
|
||||||
tx.commit()
|
uploading: true,
|
||||||
.then(function(){
|
progress: 0
|
||||||
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)'
|
|
||||||
|
|
||||||
var session = driver.session()
|
//Start a timer
|
||||||
var tx = session.beginTransaction()
|
console.time('IngestTime');
|
||||||
var promises = []
|
|
||||||
|
|
||||||
promises.push(tx.run(userQuery, {props: props.users}))
|
//Start parsing the file
|
||||||
promises.push(tx.run(computerQuery, {props: props.computers}))
|
var parser = csv.fromStream(fs.createReadStream(file),
|
||||||
promises.push(tx.run(groupQuery, {props: props.groups}))
|
{
|
||||||
|
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)
|
//If we've collected 10k rows, push it all to the DB.
|
||||||
.then(function(){
|
if (localCount % 10000 === 0){
|
||||||
tx.commit()
|
//Pause the parser until upload is complete
|
||||||
.then(function(){
|
parser.pause();
|
||||||
session.close()
|
this.uploadData(chunk, fileType, count)
|
||||||
this.setState({progress: Math.floor((sent / count) * 100)})
|
.then(function(){
|
||||||
parser.resume()
|
//Update the sent number, and resume the parser
|
||||||
}.bind(this))
|
sent += chunk.length;
|
||||||
}.bind(this))
|
this.setState({progress: Math.floor(sent / count * 100)});
|
||||||
}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)
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(promises)
|
chunk = [];
|
||||||
.then(function(){
|
parser.resume();
|
||||||
tx.commit()
|
}.bind(this));
|
||||||
.then(function(){
|
}
|
||||||
this.setState({progress: Math.floor((sent / count) * 100)})
|
}.bind(this))
|
||||||
session.close()
|
.on('end', function(){
|
||||||
parser.resume()
|
//Upload any remaining data
|
||||||
}.bind(this))
|
this.uploadData(chunk, fileType, count)
|
||||||
}.bind(this))
|
.then(function(){
|
||||||
}
|
//Set the uploading state to 100%, refresh the db display, and move on to the next file if there is one
|
||||||
}.bind(this)
|
this.setState({progress:100});
|
||||||
})
|
emitter.emit('refreshDBData');
|
||||||
}.bind(this));
|
console.timeEnd('IngestTime');
|
||||||
}
|
callback();
|
||||||
|
}.bind(this));
|
||||||
|
}.bind(this));
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
async uploadData(currentChunk, filetype, total){
|
||||||
return (
|
var index = 0;
|
||||||
<div className="menudiv">
|
var processed;
|
||||||
<div>
|
var sent = 0;
|
||||||
<MenuButton click={this._refreshClick.bind(this)} hoverVal="Refresh" glyphicon="glyphicon glyphicon-refresh" />
|
var session = driver.session();
|
||||||
</div>
|
|
||||||
<div>
|
if (filetype === 'groupmembership'){
|
||||||
<MenuButton click={this._exportClick.bind(this)} hoverVal="Export Graph" glyphicon="glyphicon glyphicon-export" />
|
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)';
|
||||||
</div>
|
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)';
|
||||||
<div>
|
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)';
|
||||||
<MenuButton click={this._importClick.bind(this)} hoverVal="Import Graph" glyphicon="glyphicon glyphicon-import" />
|
|
||||||
</div>
|
processed = buildGroupMembershipProps(currentChunk);
|
||||||
<div>
|
|
||||||
<If condition={this.state.uploading}>
|
await session.run(userQuery, {props: processed.users});
|
||||||
<Then>
|
await session.run(computerQuery, {props: processed.computers});
|
||||||
<ProgressBarMenuButton click={this._cancelUploadClick.bind(this)} progress={this.state.progress} committed={this.state.committed}/>
|
await session.run(groupQuery, {props: processed.groups});
|
||||||
</Then>
|
}else if (filetype === 'localadmin'){
|
||||||
<Else>{ () =>
|
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)';
|
||||||
<MenuButton click={function(){jQuery(this.refs.fileInput).click()}.bind(this)} hoverVal="Upload Data" glyphicon="glyphicon glyphicon-upload" />
|
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)';
|
||||||
}</Else>
|
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)';
|
||||||
</If>
|
|
||||||
</div>
|
processed = buildLocalAdminProps(currentChunk);
|
||||||
<div>
|
|
||||||
<MenuButton click={this._changeLayoutClick.bind(this)} hoverVal="Change Layout Type" glyphicon="fa fa-line-chart" />
|
await session.run(userQuery, {props: processed.users});
|
||||||
</div>
|
await session.run(computerQuery, {props: processed.computers});
|
||||||
<div>
|
await session.run(groupQuery, {props: processed.groups});
|
||||||
<MenuButton click={this._settingsClick.bind(this)} hoverVal="Settings" glyphicon="fa fa-cogs" />
|
}else if (filetype === 'sessions'){
|
||||||
</div>
|
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)';
|
||||||
<div>
|
|
||||||
<MenuButton click={this._aboutClick.bind(this)} hoverVal="About" glyphicon="fa fa-info" />
|
processed = buildSessionProps(currentChunk);
|
||||||
</div>
|
|
||||||
<input ref="fileInput" multiple className="hide" type="file" onChange={this._uploadClick.bind(this)}/>
|
await session.run(query, {props: processed});
|
||||||
</div>
|
}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 (
|
||||||
|
<div className="menudiv">
|
||||||
|
<div>
|
||||||
|
<MenuButton click={this._refreshClick.bind(this)} hoverVal="Refresh" glyphicon="glyphicon glyphicon-refresh" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<MenuButton click={this._exportClick.bind(this)} hoverVal="Export Graph" glyphicon="glyphicon glyphicon-export" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<MenuButton click={this._importClick.bind(this)} hoverVal="Import Graph" glyphicon="glyphicon glyphicon-import" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<If condition={this.state.uploading}>
|
||||||
|
<Then>
|
||||||
|
<ProgressBarMenuButton click={this._cancelUploadClick.bind(this)} progress={this.state.progress} committed={this.state.committed}/>
|
||||||
|
</Then>
|
||||||
|
<Else>{ () =>
|
||||||
|
<MenuButton click={function(){jQuery(this.refs.fileInput).click()}.bind(this)} hoverVal="Upload Data" glyphicon="glyphicon glyphicon-upload" />
|
||||||
|
}</Else>
|
||||||
|
</If>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<MenuButton click={this._changeLayoutClick.bind(this)} hoverVal="Change Layout Type" glyphicon="fa fa-line-chart" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<MenuButton click={this._settingsClick.bind(this)} hoverVal="Settings" glyphicon="fa fa-cogs" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<MenuButton click={this._aboutClick.bind(this)} hoverVal="About" glyphicon="fa fa-info" />
|
||||||
|
</div>
|
||||||
|
<input ref="fileInput" multiple className="hide" type="file" onChange={this._uploadClick.bind(this)}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +1,80 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class ProgressBarMenuButton extends Component {
|
export default class ProgressBarMenuButton extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super()
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
expanded: false
|
expanded: false
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_leave(e){
|
componentDidMount(){
|
||||||
this.setState({expanded: false})
|
$(this.refs.btn).html('{}%'.format(this.props.progress));
|
||||||
var target = $(e.target)
|
$(this.refs.btn).css('padding','6px 0px 6px 0px');
|
||||||
var oldWidth = target.width()
|
$(this.refs.btn).css('width','41px');
|
||||||
target.html('{}%'.format(this.props.progress))
|
}
|
||||||
target.animate({
|
|
||||||
width: '41px'
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
_enter(e){
|
componentWillReceiveProps(nextProps){
|
||||||
this.setState({expanded: true})
|
if (this.state.expanded){
|
||||||
var target = $(e.target)
|
var template = `<div class="progress" style="margin-bottom:0px">
|
||||||
var oldWidth = target.width()
|
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-value-now={} aria-value-max="100" style="width:{}%">
|
||||||
var template = `
|
</div>
|
||||||
<div class="progress" style="margin-bottom:0px">
|
<span>
|
||||||
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-value-now={} aria-value-max="100" style="width:{}%">
|
{}%
|
||||||
</div>
|
</span>
|
||||||
<span>
|
</div>`.formatAll(nextProps.progress);
|
||||||
{}%
|
$(this.refs.btn).html(template);
|
||||||
</span>
|
}else{
|
||||||
</div>
|
$(this.refs.btn).html('{}%'.format(nextProps.progress));
|
||||||
`.formatAll(this.props.progress)
|
}
|
||||||
|
|
||||||
target.html(template)
|
this.forceUpdate();
|
||||||
target.animate({
|
}
|
||||||
width: '150px'
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps){
|
shouldComponentUpdate(nextProps, nextState){
|
||||||
if (this.state.expanded){
|
return true;
|
||||||
var template = `<div class="progress" style="margin-bottom:0px">
|
}
|
||||||
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-value-now={} aria-value-max="100" style="width:{}%">
|
|
||||||
</div>
|
|
||||||
<span>
|
|
||||||
{}%
|
|
||||||
</span>
|
|
||||||
</div>`.formatAll(nextProps.progress)
|
|
||||||
$(this.refs.btn).html(template)
|
|
||||||
}else{
|
|
||||||
$(this.refs.btn).html('{}%'.format(nextProps.progress))
|
|
||||||
}
|
|
||||||
|
|
||||||
this.forceUpdate()
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState){
|
_enter(e){
|
||||||
return true
|
this.setState({expanded: true});
|
||||||
}
|
var target = $(e.target);
|
||||||
|
var oldWidth = target.width();
|
||||||
|
var template = `
|
||||||
|
<div class="progress" style="margin-bottom:0px">
|
||||||
|
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-value-now={} aria-value-max="100" style="width:{}%">
|
||||||
|
</div>
|
||||||
|
<span>
|
||||||
|
{}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`.formatAll(this.props.progress);
|
||||||
|
|
||||||
componentDidMount(){
|
target.html(template);
|
||||||
$(this.refs.btn).html('{}%'.format(this.props.progress))
|
target.animate({
|
||||||
$(this.refs.btn).css('padding','6px 0px 6px 0px')
|
width: '150px'
|
||||||
$(this.refs.btn).css('width','41px')
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<button ref="btn" onClick={this.props.click} onMouseLeave={this._leave.bind(this)} onMouseEnter={this._enter.bind(this)} className="btn" />
|
<button ref="btn" onClick={this.props.click} onMouseLeave={this._leave.bind(this)} onMouseEnter={this._enter.bind(this)} className="btn" />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressBarMenuButton.propTypes = {
|
ProgressBarMenuButton.propTypes = {
|
||||||
progress : React.PropTypes.number.isRequired,
|
progress : React.PropTypes.number.isRequired,
|
||||||
click : React.PropTypes.func.isRequired
|
click : React.PropTypes.func.isRequired
|
||||||
}
|
};
|
|
@ -1,86 +1,86 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import GlyphiconSpan from '../GlyphiconSpan'
|
import GlyphiconSpan from '../GlyphiconSpan';
|
||||||
import Icon from '../Icon'
|
import Icon from '../Icon';
|
||||||
import TabContainer from './TabContainer'
|
import TabContainer from './TabContainer';
|
||||||
|
|
||||||
export default class SearchContainer extends Component {
|
export default class SearchContainer extends Component {
|
||||||
constructor(props){
|
constructor(props){
|
||||||
super(props)
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
mainPlaceholder:"Start typing to search for a node...",
|
mainPlaceholder:"Start typing to search for a node...",
|
||||||
pathfindingIsOpen: false,
|
pathfindingIsOpen: false,
|
||||||
mainValue: "",
|
mainValue: "",
|
||||||
pathfindValue: ""
|
pathfindValue: ""
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPathfindClick(){
|
_onPathfindClick(){
|
||||||
jQuery(this.refs.pathfinding).slideToggle()
|
jQuery(this.refs.pathfinding).slideToggle();
|
||||||
var p = !this.state.pathfindingIsOpen
|
var p = !this.state.pathfindingIsOpen;
|
||||||
var t = this.state.pathfindingIsOpen ? "Start typing to search for a node..." : "Start Node"
|
var t = this.state.pathfindingIsOpen ? "Start typing to search for a node..." : "Start Node";
|
||||||
this.setState({
|
this.setState({
|
||||||
pathfindingIsOpen: p,
|
pathfindingIsOpen: p,
|
||||||
mainPlaceholder: t
|
mainPlaceholder: t
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPlayClick(){
|
_onPlayClick(){
|
||||||
var start = jQuery(this.refs.searchbar).val()
|
var start = jQuery(this.refs.searchbar).val();
|
||||||
var end = jQuery(this.refs.pathbar).val()
|
var end = jQuery(this.refs.pathbar).val();
|
||||||
if (start !== "" && end !== ""){
|
if (start !== "" && end !== ""){
|
||||||
emitter.emit('pathQuery', start, end)
|
emitter.emit('pathQuery', start, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onExpandClick(){
|
_onExpandClick(){
|
||||||
jQuery(this.refs.tabs).slideToggle()
|
jQuery(this.refs.tabs).slideToggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
openNodeTab(){
|
openNodeTab(){
|
||||||
var e = jQuery(this.refs.tabs)
|
var e = jQuery(this.refs.tabs);
|
||||||
if (!(e.is(":visible"))){
|
if (!(e.is(":visible"))){
|
||||||
e.slideToggle()
|
e.slideToggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
jQuery(this.refs.pathfinding).slideToggle(0);
|
jQuery(this.refs.pathfinding).slideToggle(0);
|
||||||
jQuery(this.refs.tabs).slideToggle(0);
|
jQuery(this.refs.tabs).slideToggle(0);
|
||||||
emitter.on('userNodeClicked', this.openNodeTab.bind(this))
|
emitter.on('userNodeClicked', this.openNodeTab.bind(this));
|
||||||
emitter.on('groupNodeClicked', this.openNodeTab.bind(this))
|
emitter.on('groupNodeClicked', this.openNodeTab.bind(this));
|
||||||
emitter.on('computerNodeClicked', this.openNodeTab.bind(this))
|
emitter.on('computerNodeClicked', this.openNodeTab.bind(this));
|
||||||
emitter.on('domainNodeClicked', this.openNodeTab.bind(this))
|
emitter.on('domainNodeClicked', this.openNodeTab.bind(this));
|
||||||
emitter.on('setStart', function(payload){
|
emitter.on('setStart', function(payload){
|
||||||
jQuery(this.refs.searchbar).val(payload);
|
jQuery(this.refs.searchbar).val(payload);
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
emitter.on('setEnd', function(payload){
|
emitter.on('setEnd', function(payload){
|
||||||
jQuery(this.refs.pathbar).val(payload);
|
jQuery(this.refs.pathbar).val(payload);
|
||||||
var e = jQuery(this.refs.pathfinding)
|
var e = jQuery(this.refs.pathfinding);
|
||||||
if (!(e.is(":visible"))){
|
if (!(e.is(":visible"))){
|
||||||
e.slideToggle()
|
e.slideToggle();
|
||||||
}
|
}
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
jQuery(this.refs.searchbar).typeahead({
|
jQuery(this.refs.searchbar).typeahead({
|
||||||
source: function(query, process) {
|
source: function(query, process) {
|
||||||
var session = driver.session()
|
var session = driver.session();
|
||||||
var t = '(?i).*' + query + '.*'
|
var t = '(?i).*' + query + '.*';
|
||||||
var data = []
|
var data = [];
|
||||||
session.run("MATCH (n) WHERE n.name =~ {name} RETURN n LIMIT 10", {name:t})
|
session.run("MATCH (n) WHERE n.name =~ {name} RETURN n LIMIT 10", {name:t})
|
||||||
.then(function(results){
|
.then(function(results){
|
||||||
$.each(results.records, function(index, record){
|
$.each(results.records, function(index, record){
|
||||||
data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0])
|
data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0]);
|
||||||
})
|
});
|
||||||
session.close()
|
session.close();
|
||||||
return process(data)
|
return process(data);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
afterSelect: function(selected) {
|
afterSelect: function(selected) {
|
||||||
if (!this.state.pathfindingIsOpen) {
|
if (!this.state.pathfindingIsOpen) {
|
||||||
var statement = "MATCH (n) WHERE n.name = {name} RETURN n"
|
var statement = "MATCH (n) WHERE n.name = {name} RETURN n";
|
||||||
emitter.emit('searchQuery', statement, {name: selected.split("#")[0]})
|
emitter.emit('searchQuery', statement, {name: selected.split("#")[0]});
|
||||||
} else {
|
} else {
|
||||||
var start = jQuery(this.refs.searchbar).val();
|
var start = jQuery(this.refs.searchbar).val();
|
||||||
var end = jQuery(this.refs.pathbar).val();
|
var end = jQuery(this.refs.pathbar).val();
|
||||||
|
@ -91,57 +91,57 @@ export default class SearchContainer extends Component {
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
autoSelect: false,
|
autoSelect: false,
|
||||||
updater: function(item){
|
updater: function(item){
|
||||||
return item.split("#")[0]
|
return item.split("#")[0];
|
||||||
},
|
},
|
||||||
highlighter: function(item) {
|
highlighter: function(item) {
|
||||||
var parts = item.split("#")
|
var parts = item.split("#");
|
||||||
var query = this.query;
|
var query = this.query;
|
||||||
var icon = "";
|
var icon = "";
|
||||||
var html = ""
|
var html = "";
|
||||||
switch (parts[1]){
|
switch (parts[1]){
|
||||||
case "Group":
|
case "Group":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-users\"></i>"
|
icon = "<i style=\"float:right\" class=\"fa fa-users\"></i>";
|
||||||
break;
|
break;
|
||||||
case "User":
|
case "User":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-user\"></i>"
|
icon = "<i style=\"float:right\" class=\"fa fa-user\"></i>";
|
||||||
break;
|
break;
|
||||||
case "Computer":
|
case "Computer":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-desktop\"></i>"
|
icon = "<i style=\"float:right\" class=\"fa fa-desktop\"></i>";
|
||||||
break;
|
break;
|
||||||
case "Domain":
|
case "Domain":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-globe\"></i>"
|
icon = "<i style=\"float:right\" class=\"fa fa-globe\"></i>";
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
html = '<div>' + parts[0] + ' ' + icon + '</div>'
|
html = '<div>' + parts[0] + ' ' + icon + '</div>';
|
||||||
|
|
||||||
var reEscQuery = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
var reEscQuery = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||||
var reQuery = new RegExp('(' + reEscQuery + ')', "gi");
|
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; });
|
var textNodes = $(jElem.find('*')).add(jElem).contents().filter(function () { return this.nodeType === 3; });
|
||||||
textNodes.replaceWith(function() {
|
textNodes.replaceWith(function() {
|
||||||
return $(this).text().replace(reQuery, '<strong>$1</strong>')
|
return $(this).text().replace(reQuery, '<strong>$1</strong>');
|
||||||
});
|
});
|
||||||
|
|
||||||
return jElem.html();
|
return jElem.html();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
jQuery(this.refs.pathbar).typeahead({
|
jQuery(this.refs.pathbar).typeahead({
|
||||||
source: function(query, process) {
|
source: function(query, process) {
|
||||||
var session = driver.session()
|
var session = driver.session();
|
||||||
var t = '(?i).*' + query + '.*'
|
var t = '(?i).*' + query + '.*';
|
||||||
var data = []
|
var data = [];
|
||||||
session.run("MATCH (n) WHERE n.name =~ {name} RETURN n LIMIT 10", {name:t})
|
session.run("MATCH (n) WHERE n.name =~ {name} RETURN n LIMIT 10", {name:t})
|
||||||
.then(function(results){
|
.then(function(results){
|
||||||
$.each(results.records, function(index, record){
|
$.each(results.records, function(index, record){
|
||||||
data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0])
|
data.push(record._fields[0].properties.name + "#" + record._fields[0].labels[0]);
|
||||||
})
|
});
|
||||||
session.close()
|
session.close();
|
||||||
return process(data)
|
return process(data);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
afterSelect: function(selected) {
|
afterSelect: function(selected) {
|
||||||
var start = jQuery(this.refs.searchbar).val();
|
var start = jQuery(this.refs.searchbar).val();
|
||||||
|
@ -152,47 +152,47 @@ export default class SearchContainer extends Component {
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
autoSelect: false,
|
autoSelect: false,
|
||||||
updater: function(item){
|
updater: function(item){
|
||||||
return item.split("#")[0]
|
return item.split("#")[0];
|
||||||
},
|
},
|
||||||
highlighter: function(item) {
|
highlighter: function(item) {
|
||||||
var parts = item.split("#")
|
var parts = item.split("#");
|
||||||
var query = this.query;
|
var query = this.query;
|
||||||
var icon = "";
|
var icon = "";
|
||||||
var html = ""
|
var html = "";
|
||||||
switch (parts[1]){
|
switch (parts[1]){
|
||||||
case "Group":
|
case "Group":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-users\"></i>"
|
icon = "<i class=\"fa fa-users\"></i>";
|
||||||
break;
|
break;
|
||||||
case "User":
|
case "User":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-user\"></i>"
|
icon = "<i class=\"fa fa-user\"></i>";
|
||||||
break;
|
break;
|
||||||
case "Computer":
|
case "Computer":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-desktop\"></i>"
|
icon = "<i class=\"fa fa-desktop\"></i>";
|
||||||
break;
|
break;
|
||||||
case "Domain":
|
case "Domain":
|
||||||
icon = "<i style=\"float:right\" class=\"fa fa-globe\"></i>"
|
icon = "<i class=\"fa fa-globe\"></i>";
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
html = '<div>' + parts[0] + ' ' + icon + '</div>'
|
html = '<div>' + parts[0] + ' ' + icon + '</div>';
|
||||||
|
|
||||||
var reEscQuery = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
var reEscQuery = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||||
var reQuery = new RegExp('(' + reEscQuery + ')', "gi");
|
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; });
|
var textNodes = $(jElem.find('*')).add(jElem).contents().filter(function () { return this.nodeType === 3; });
|
||||||
textNodes.replaceWith(function() {
|
textNodes.replaceWith(function() {
|
||||||
return $(this).text().replace(reQuery, '<strong>$1</strong>')
|
return $(this).text().replace(reQuery, '<strong>$1</strong>');
|
||||||
});
|
});
|
||||||
|
|
||||||
return jElem.html();
|
return jElem.html();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_inputKeyPress(e){
|
_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 start = jQuery(this.refs.searchbar).val();
|
||||||
var end = jQuery(this.refs.pathbar).val();
|
var end = jQuery(this.refs.pathbar).val();
|
||||||
var stop = false;
|
var stop = false;
|
||||||
|
@ -201,17 +201,17 @@ export default class SearchContainer extends Component {
|
||||||
if (!$('.searchSelectorS > ul').is(':hidden')){
|
if (!$('.searchSelectorS > ul').is(':hidden')){
|
||||||
$('.searchSelectorS > ul li').each(function(i){
|
$('.searchSelectorS > ul li').each(function(i){
|
||||||
if($(this).hasClass('active')){
|
if($(this).hasClass('active')){
|
||||||
stop = true
|
stop = true;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$('.searchSelectorP > ul').is(':hidden')){
|
if (!$('.searchSelectorP > ul').is(':hidden')){
|
||||||
$('.searchSelectorP > ul li').each(function(i){
|
$('.searchSelectorP > ul li').each(function(i){
|
||||||
if($(this).hasClass('active')){
|
if($(this).hasClass('active')){
|
||||||
stop = true
|
stop = true;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (stop){
|
if (stop){
|
||||||
return;
|
return;
|
||||||
|
@ -219,8 +219,8 @@ export default class SearchContainer extends Component {
|
||||||
if (!this.state.pathfindingIsOpen) {
|
if (!this.state.pathfindingIsOpen) {
|
||||||
if (start !== ""){
|
if (start !== ""){
|
||||||
var statement = "MATCH (n) WHERE n.name =~ {regex} RETURN n";
|
var statement = "MATCH (n) WHERE n.name =~ {regex} RETURN n";
|
||||||
var regex = '(?i).*' + start + '.*'
|
var regex = '(?i).*' + start + '.*';
|
||||||
emitter.emit('searchQuery', statement, {regex:regex})
|
emitter.emit('searchQuery', statement, {regex:regex});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var start = jQuery(this.refs.searchbar).val();
|
var start = jQuery(this.refs.searchbar).val();
|
||||||
|
@ -257,7 +257,7 @@ export default class SearchContainer extends Component {
|
||||||
tooltipTitle="Back"
|
tooltipTitle="Back"
|
||||||
classes="input-group-addon spanfix"
|
classes="input-group-addon spanfix"
|
||||||
click={function(){
|
click={function(){
|
||||||
emitter.emit('graphBack')
|
emitter.emit('graphBack');
|
||||||
}}>
|
}}>
|
||||||
<Icon glyph="step-backward" extraClass="menuglyph" />
|
<Icon glyph="step-backward" extraClass="menuglyph" />
|
||||||
</GlyphiconSpan>
|
</GlyphiconSpan>
|
||||||
|
@ -289,6 +289,6 @@ export default class SearchContainer extends Component {
|
||||||
<TabContainer />
|
<TabContainer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,344 +1,386 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import NodeALink from './NodeALink'
|
import NodeALink from './NodeALink';
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class ComputerNodeData extends Component {
|
export default class ComputerNodeData extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
label: "",
|
label: "",
|
||||||
os: "None",
|
explicitAdmins: -1,
|
||||||
unconstrained: "None",
|
unrolledAdmins: -1,
|
||||||
explicitAdmins: -1,
|
firstDegreeGroupMembership: -1,
|
||||||
unrolledAdmins: -1,
|
unrolledGroupMembership: -1,
|
||||||
firstDegreeGroupMembership: -1,
|
firstDegreeLocalAdmin: -1,
|
||||||
unrolledGroupMembership: -1,
|
groupDelegatedLocalAdmin: -1,
|
||||||
firstDegreeLocalAdmin: -1,
|
derivativeLocalAdmin: -1,
|
||||||
groupDelegatedLocalAdmin: -1,
|
sessions: -1,
|
||||||
derivativeLocalAdmin: -1,
|
firstdegreeControl: -1,
|
||||||
sessions: -1,
|
groupDelegatedControl: -1,
|
||||||
firstdegreeControl: -1,
|
transitiveControl: -1,
|
||||||
groupDelegatedControl: -1,
|
derivativeLocalAdmins: -1,
|
||||||
transitiveControl: -1,
|
driversessions: [],
|
||||||
derivativeLocalAdmins: -1,
|
propertyMap: {}
|
||||||
driversessions: []
|
};
|
||||||
}
|
|
||||||
|
|
||||||
emitter.on('computerNodeClicked', this.getNodeData.bind(this));
|
emitter.on('computerNodeClicked', this.getNodeData.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodeData(payload){
|
getNodeData(payload){
|
||||||
$.each(this.state.driversessions, function(index, record){
|
$.each(this.state.driversessions, function(index, record){
|
||||||
record.close();
|
record.close();
|
||||||
})
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
label: payload,
|
label: payload,
|
||||||
os: "None",
|
explicitAdmins: -1,
|
||||||
unconstrained: "None",
|
unrolledAdmins: -1,
|
||||||
explicitAdmins: -1,
|
firstDegreeGroupMembership: -1,
|
||||||
unrolledAdmins: -1,
|
unrolledGroupMembership: -1,
|
||||||
firstDegreeGroupMembership: -1,
|
sessions: -1,
|
||||||
unrolledGroupMembership: -1,
|
firstDegreeLocalAdmin: -1,
|
||||||
sessions: -1,
|
groupDelegatedLocalAdmin: -1,
|
||||||
firstDegreeLocalAdmin: -1,
|
derivativeLocalAdmin: -1,
|
||||||
groupDelegatedLocalAdmin: -1,
|
firstdegreeControl: -1,
|
||||||
derivativeLocalAdmin: -1,
|
groupDelegatedControl: -1,
|
||||||
firstdegreeControl: -1,
|
transitiveControl: -1,
|
||||||
groupDelegatedControl: -1,
|
derivativeLocalAdmins: -1,
|
||||||
transitiveControl: -1,
|
propertyMap: {}
|
||||||
derivativeLocalAdmins: -1
|
});
|
||||||
})
|
|
||||||
|
|
||||||
var s1 = driver.session()
|
var s1 = driver.session();
|
||||||
var s2 = driver.session()
|
var s2 = driver.session();
|
||||||
var s3 = driver.session()
|
var s3 = driver.session();
|
||||||
var s4 = driver.session()
|
var s4 = driver.session();
|
||||||
var s5 = driver.session()
|
var s5 = driver.session();
|
||||||
var s6 = driver.session()
|
var s6 = driver.session();
|
||||||
var s7 = driver.session()
|
var s7 = driver.session();
|
||||||
var s8 = driver.session()
|
var s8 = driver.session();
|
||||||
var s9 = driver.session()
|
var s9 = driver.session();
|
||||||
var s10 = driver.session()
|
var s10 = driver.session();
|
||||||
var s11 = driver.session()
|
var s11 = driver.session();
|
||||||
var s12 = driver.session()
|
var s12 = driver.session();
|
||||||
var s13 = driver.session()
|
var s13 = driver.session();
|
||||||
|
|
||||||
s1.run("MATCH (a)-[b:AdminTo]->(c:Computer {name:{name}}) RETURN count(a)", {name:payload})
|
var propCollection = driver.session();
|
||||||
.then(function(result){
|
propCollection.run("MATCH (c:Computer {name:{name}}) RETURN c", {name:payload})
|
||||||
this.setState({'explicitAdmins':result.records[0]._fields[0].low})
|
.then(function(result){
|
||||||
s1.close()
|
var properties = result.records[0]._fields[0].properties;
|
||||||
}.bind(this))
|
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})
|
s1.run("MATCH (a)-[b:AdminTo]->(c:Computer {name:{name}}) RETURN count(a)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'unrolledAdmins':result.records[0]._fields[0].low})
|
this.setState({'explicitAdmins':result.records[0]._fields[0].low});
|
||||||
s2.close()
|
s1.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s3.run("MATCH (m:Computer {name:{name}}), (n:Computer), (m)-[r:AdminTo]->(n) RETURN count(distinct(m))", {name:payload})
|
s2.run("MATCH p=(n:User)-[r:MemberOf|AdminTo*1..]->(m:Computer {name:{name}}) RETURN count(distinct(n))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low})
|
this.setState({'unrolledAdmins':result.records[0]._fields[0].low});
|
||||||
s3.close()
|
s2.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s4.run("MATCH p=(n:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c2:Computer) RETURN count(c2)", {name:payload})
|
s3.run("MATCH (m:Computer {name:{name}}), (n:Computer), (m)-[r:AdminTo]->(n) RETURN count(distinct(m))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low});
|
||||||
s4.close()
|
s3.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low})
|
this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low});
|
||||||
s5.close()
|
s4.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s6.run("MATCH (n:Computer {name:{name}}),(target:Group), (n)-[r:MemberOf]->(target) RETURN count(target)", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low})
|
this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low});
|
||||||
s6.close()
|
s5.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s7.run("MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload})
|
s6.run("MATCH (n:Computer {name:{name}}),(target:Group), (n)-[r:MemberOf]->(target) RETURN count(target)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low});
|
||||||
s7.close()
|
s6.close();
|
||||||
}.bind(this))
|
}.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})
|
s7.run("MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'sessions':result.records[0]._fields[0].low})
|
this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low});
|
||||||
s8.close()
|
s7.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s9.run("MATCH p = shortestPath((n)-[r:AdminTo|MemberOf|HasSession*1..]->(m:Computer {name:{name}})) RETURN COUNT(DISTINCT(n))", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'derivativeLocalAdmins':result.records[0]._fields[0].low})
|
this.setState({'sessions':result.records[0]._fields[0].low});
|
||||||
s9.close()
|
s8.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'foreignGroupMembership':result.records[0]._fields[0].low})
|
this.setState({'derivativeLocalAdmins':result.records[0]._fields[0].low});
|
||||||
s10.close()
|
s9.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'firstdegreeControl':result.records[0]._fields[0].low})
|
this.setState({'foreignGroupMembership':result.records[0]._fields[0].low});
|
||||||
s11.close()
|
s10.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'groupDelegatedControl':result.records[0]._fields[0].low})
|
this.setState({'firstdegreeControl':result.records[0]._fields[0].low});
|
||||||
s12.close()
|
s11.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'transitiveControl':result.records[0]._fields[0].low})
|
this.setState({'groupDelegatedControl':result.records[0]._fields[0].low});
|
||||||
s13.close()
|
s12.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13]})
|
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));
|
||||||
|
|
||||||
render() {
|
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,propCollection]});
|
||||||
return (
|
}
|
||||||
<div className={this.props.visible ? "" : "displaynone"}>
|
|
||||||
<dl className='dl-horizontal'>
|
convertToDisplayProp(propName){
|
||||||
<h4>Node Info</h4>
|
var obj = this.state.propertyMap[propName];
|
||||||
<dt>
|
var type = typeof obj;
|
||||||
Name
|
if (type === 'undefined'){
|
||||||
</dt>
|
return "No Data";
|
||||||
<dd>
|
}else if (obj.hasOwnProperty('low')){
|
||||||
{this.state.label}
|
var t = obj.low;
|
||||||
</dd>
|
if (t === 0){
|
||||||
<dt>
|
return "Never";
|
||||||
OS
|
}else{
|
||||||
</dt>
|
return new Date(obj.low * 1000).toUTCString();
|
||||||
<dd>
|
}
|
||||||
{this.state.os}
|
}else if (type === 'boolean'){
|
||||||
</dd>
|
return obj.toString().toTitleCase();
|
||||||
<dt>
|
}else if (obj === ""){
|
||||||
Allows Unconstrained Delegation
|
return "None";
|
||||||
</dt>
|
}else{
|
||||||
<dd>
|
return obj;
|
||||||
{this.state.unconstrained}
|
}
|
||||||
</dd>
|
}
|
||||||
<dt>
|
|
||||||
Sessions
|
render() {
|
||||||
</dt>
|
return (
|
||||||
<dd>
|
<div className={this.props.visible ? "" : "displaynone"}>
|
||||||
<NodeALink
|
<dl className='dl-horizontal'>
|
||||||
ready={this.state.sessions !== -1}
|
<h4>Node Info</h4>
|
||||||
value={this.state.sessions}
|
<dt>
|
||||||
click={function(){
|
Name
|
||||||
emitter.emit('query',
|
</dt>
|
||||||
"MATCH (m:Computer {name:{name}})-[r:HasSession]->(n:User) WITH n,r,m WHERE NOT n.name ENDS WITH '$' RETURN n,r,m", {name: this.state.label})
|
<dd>
|
||||||
}.bind(this)} />
|
{this.state.label}
|
||||||
</dd>
|
</dd>
|
||||||
<br />
|
<dt>
|
||||||
<h4>Local Admins</h4>
|
OS
|
||||||
<dt>
|
</dt>
|
||||||
Explicit Admins
|
<dd>
|
||||||
</dt>
|
{this.convertToDisplayProp("OperatingSystem")}
|
||||||
<dd>
|
</dd>
|
||||||
<NodeALink
|
<dt>
|
||||||
ready={this.state.explicitAdmins !== -1}
|
Enabled
|
||||||
value={this.state.explicitAdmins}
|
</dt>
|
||||||
click={function(){
|
<dd>
|
||||||
emitter.emit('query',
|
{this.convertToDisplayProp("Enabled")}
|
||||||
"MATCH (n)-[r:AdminTo]->(m:Computer {name:{name}}) RETURN n,r,m",{name: this.state.label})
|
</dd>
|
||||||
}.bind(this)} />
|
<dt>
|
||||||
</dd>
|
Allows Unconstrained Delegation
|
||||||
<dt>
|
</dt>
|
||||||
Unrolled Admins
|
<dd>
|
||||||
</dt>
|
{this.convertToDisplayProp("UnconstrainedDelegation")}
|
||||||
<dd>
|
</dd>
|
||||||
<NodeALink
|
<dt>
|
||||||
ready={this.state.unrolledAdmins !== -1}
|
Sessions
|
||||||
value={this.state.unrolledAdmins}
|
</dt>
|
||||||
click={function(){
|
<dd>
|
||||||
emitter.emit('query',
|
<NodeALink
|
||||||
"MATCH p = (n:User)-[r:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c:Computer {name:{name}}) RETURN p",
|
ready={this.state.sessions !== -1}
|
||||||
{name: this.state.label},
|
value={this.state.sessions}
|
||||||
this.state.label)
|
click={function(){
|
||||||
}.bind(this)} />
|
emitter.emit('query',
|
||||||
</dd>
|
"MATCH (m:Computer {name:{name}})-[r:HasSession]->(n:User) WITH n,r,m WHERE NOT n.name ENDS WITH '$' RETURN n,r,m", {name: this.state.label});
|
||||||
<dt>
|
}.bind(this)}
|
||||||
Derivative Local Admins
|
/>
|
||||||
</dt>
|
</dd>
|
||||||
<dd>
|
<h4>Local Admins</h4>
|
||||||
<NodeALink
|
<dt>
|
||||||
ready={this.state.derivativeLocalAdmins !== -1}
|
Explicit Admins
|
||||||
value={this.state.derivativeLocalAdmins}
|
</dt>
|
||||||
click={function(){
|
<dd>
|
||||||
emitter.emit('query',
|
<NodeALink
|
||||||
"MATCH p = shortestPath((n)-[r:AdminTo|MemberOf|HasSession*1..]->(m:Computer {name:{name}})) RETURN p",{name: this.state.label}, this.state.label)
|
ready={this.state.explicitAdmins !== -1}
|
||||||
}.bind(this)} />
|
value={this.state.explicitAdmins}
|
||||||
</dd>
|
click={function(){
|
||||||
<br />
|
emitter.emit('query',
|
||||||
<h4>Group Memberships</h4>
|
"MATCH (n)-[r:AdminTo]->(m:Computer {name:{name}}) RETURN n,r,m",{name: this.state.label});
|
||||||
<dt>
|
}.bind(this)}
|
||||||
First Degree Group Membership
|
/>
|
||||||
</dt>
|
</dd>
|
||||||
<dd>
|
<dt>
|
||||||
<NodeALink
|
Unrolled Admins
|
||||||
ready={this.state.firstDegreeGroupMembership !== -1}
|
</dt>
|
||||||
value={this.state.firstDegreeGroupMembership}
|
<dd>
|
||||||
click={function(){
|
<NodeALink
|
||||||
emitter.emit('query',
|
ready={this.state.unrolledAdmins !== -1}
|
||||||
"MATCH (n:Computer {name:{name}}),(m:Group), (n)-[r:MemberOf]->(m) RETURN n,r,m",{name: this.state.label}, this.state.label)
|
value={this.state.unrolledAdmins}
|
||||||
}.bind(this)} />
|
click={function(){
|
||||||
</dd>
|
emitter.emit('query',
|
||||||
<dt>
|
"MATCH p = (n:User)-[r:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c:Computer {name:{name}}) RETURN p",
|
||||||
Unrolled Group Membership
|
{name: this.state.label},
|
||||||
</dt>
|
this.state.label);
|
||||||
<dd>
|
}.bind(this)}
|
||||||
<NodeALink
|
/>
|
||||||
ready={this.state.unrolledGroupMembership !== -1}
|
</dd>
|
||||||
value={this.state.unrolledGroupMembership}
|
<dt>
|
||||||
click={function(){
|
Derivative Local Admins
|
||||||
emitter.emit('query',
|
</dt>
|
||||||
"MATCH p = (n:Computer {name:{name}})-[r:MemberOf*1..]->(m:Group) RETURN p",{name: this.state.label}, this.state.label)
|
<dd>
|
||||||
}.bind(this)} />
|
<NodeALink
|
||||||
</dd>
|
ready={this.state.derivativeLocalAdmins !== -1}
|
||||||
<dt>
|
value={this.state.derivativeLocalAdmins}
|
||||||
Foreign Group Membership
|
click={function(){
|
||||||
</dt>
|
emitter.emit('query',
|
||||||
<dd>
|
"MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((n)-[r:AdminTo|MemberOf|HasSession*1..]->(m:Computer {name:{name}})) RETURN p",{name: this.state.label}, this.state.label);
|
||||||
<NodeALink
|
}.bind(this)}
|
||||||
ready={this.state.foreignGroupMembership !== -1}
|
/>
|
||||||
value={this.state.foreignGroupMembership}
|
</dd>
|
||||||
click={function(){
|
<h4>Group Memberships</h4>
|
||||||
emitter.emit('query',
|
<dt>
|
||||||
"MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) WHERE NOT g.domain = c.domain RETURN p",{name: this.state.label}, this.state.label)
|
First Degree Group Membership
|
||||||
}.bind(this)} />
|
</dt>
|
||||||
</dd>
|
<dd>
|
||||||
<br />
|
<NodeALink
|
||||||
<h4>Local Admin Rights</h4>
|
ready={this.state.firstDegreeGroupMembership !== -1}
|
||||||
<dt>
|
value={this.state.firstDegreeGroupMembership}
|
||||||
First Degree Local Admin
|
click={function(){
|
||||||
</dt>
|
emitter.emit('query',
|
||||||
<dd>
|
"MATCH (n:Computer {name:{name}}),(m:Group), (n)-[r:MemberOf]->(m) RETURN n,r,m",{name: this.state.label}, this.state.label);
|
||||||
<NodeALink
|
}.bind(this)}
|
||||||
ready={this.state.firstDegreeLocalAdmin !== -1}
|
/>
|
||||||
value={this.state.firstDegreeLocalAdmin}
|
</dd>
|
||||||
click={function(){
|
<dt>
|
||||||
emitter.emit('query',
|
Unrolled Group Membership
|
||||||
"MATCH (n:Computer {name:{name}}), (m:Computer), p=(n)-[r:AdminTo]->(m) RETURN p",{name: this.state.label}, this.state.label)
|
</dt>
|
||||||
}.bind(this)} />
|
<dd>
|
||||||
</dd>
|
<NodeALink
|
||||||
<dt>
|
ready={this.state.unrolledGroupMembership !== -1}
|
||||||
Group Delegated Local Admin
|
value={this.state.unrolledGroupMembership}
|
||||||
</dt>
|
click={function(){
|
||||||
<dd>
|
emitter.emit('query',
|
||||||
<NodeALink
|
"MATCH p = (n:Computer {name:{name}})-[r:MemberOf*1..]->(m:Group) RETURN p",{name: this.state.label}, this.state.label);
|
||||||
ready={this.state.groupDelegatedLocalAdmin !== -1}
|
}.bind(this)}
|
||||||
value={this.state.groupDelegatedLocalAdmin}
|
/>
|
||||||
click={function(){
|
</dd>
|
||||||
emitter.emit('query',
|
<dt>
|
||||||
"MATCH p=(n:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(m:Computer) RETURN p",{name: this.state.label}, this.state.label)
|
Foreign Group Membership
|
||||||
}.bind(this)} />
|
</dt>
|
||||||
</dd>
|
<dd>
|
||||||
<dt>
|
<NodeALink
|
||||||
Derivative Local Admin
|
ready={this.state.foreignGroupMembership !== -1}
|
||||||
</dt>
|
value={this.state.foreignGroupMembership}
|
||||||
<dd>
|
click={function(){
|
||||||
<NodeALink
|
emitter.emit('query',
|
||||||
ready={this.state.derivativeLocalAdmin !== -1}
|
"MATCH p = (c:Computer {name:{name}})-[r:MemberOf*1..]->(g:Group) WHERE NOT g.domain = c.domain RETURN p",{name: this.state.label}, this.state.label);
|
||||||
value={this.state.derivativeLocalAdmin}
|
}.bind(this)}
|
||||||
click={function(){
|
/>
|
||||||
emitter.emit('query',
|
</dd>
|
||||||
"MATCH p = shortestPath((c1:Computer {name:{name}})-[r:AdminTo|MemberOf|HasSession*1..]->(c:Computer)) RETURN p",{name: this.state.label}, this.state.label)
|
<h4>Local Admin Rights</h4>
|
||||||
}.bind(this)} />
|
<dt>
|
||||||
</dd>
|
First Degree Local Admin
|
||||||
<br />
|
</dt>
|
||||||
<h4>Outbound Object Control</h4>
|
<dd>
|
||||||
<dt>
|
<NodeALink
|
||||||
First Degree Object Control
|
ready={this.state.firstDegreeLocalAdmin !== -1}
|
||||||
</dt>
|
value={this.state.firstDegreeLocalAdmin}
|
||||||
<dd>
|
click={function(){
|
||||||
<NodeALink
|
emitter.emit('query',
|
||||||
ready={this.state.firstdegreeControl !== -1}
|
"MATCH (n:Computer {name:{name}}), (m:Computer), p=(n)-[r:AdminTo]->(m) RETURN p",{name: this.state.label}, this.state.label);
|
||||||
value={this.state.firstdegreeControl}
|
}.bind(this)}
|
||||||
click={function(){
|
/>
|
||||||
emitter.emit('query', "MATCH p = (c:Computer {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label})
|
</dd>
|
||||||
}.bind(this)} />
|
<dt>
|
||||||
</dd>
|
Group Delegated Local Admin
|
||||||
<dt>
|
</dt>
|
||||||
Group Delegated Object Control
|
<dd>
|
||||||
</dt>
|
<NodeALink
|
||||||
<dd>
|
ready={this.state.groupDelegatedLocalAdmin !== -1}
|
||||||
<NodeALink
|
value={this.state.groupDelegatedLocalAdmin}
|
||||||
ready={this.state.groupDelegatedControl !== -1}
|
click={function(){
|
||||||
value={this.state.groupDelegatedControl}
|
emitter.emit('query',
|
||||||
click={function(){
|
"MATCH p=(n:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(m:Computer) RETURN p",{name: this.state.label}, this.state.label);
|
||||||
emitter.emit('query', "MATCH p = (c:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label}
|
}.bind(this)}
|
||||||
,this.state.label)
|
/>
|
||||||
}.bind(this)} />
|
</dd>
|
||||||
</dd>
|
<dt>
|
||||||
<dt>
|
Derivative Local Admin
|
||||||
Transitive Object Control
|
</dt>
|
||||||
</dt>
|
<dd>
|
||||||
<dd>
|
<NodeALink
|
||||||
<NodeALink
|
ready={this.state.derivativeLocalAdmin !== -1}
|
||||||
ready={this.state.transitiveControl !== -1}
|
value={this.state.derivativeLocalAdmin}
|
||||||
value={this.state.transitiveControl}
|
click={function(){
|
||||||
click={function(){
|
emitter.emit('query',
|
||||||
emitter.emit('query', "MATCH p = shortestPath((c:Computer {name:{name}})-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN p", {name:this.state.label}
|
"MATCH (c:Computer) WHERE NOT c.name={name} WITH c MATCH p = shortestPath((c1:Computer {name:{name}})-[r:AdminTo|MemberOf|HasSession*1..]->(c)) RETURN p",{name: this.state.label}, this.state.label);
|
||||||
,this.state.label)
|
}.bind(this)}
|
||||||
}.bind(this)} />
|
/>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
<h4>Outbound Object Control</h4>
|
||||||
</div>
|
<dt>
|
||||||
);
|
First Degree Object Control
|
||||||
}
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<NodeALink
|
||||||
|
ready={this.state.firstdegreeControl !== -1}
|
||||||
|
value={this.state.firstdegreeControl}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "MATCH p = (c:Computer {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label});
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
Group Delegated Object Control
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<NodeALink
|
||||||
|
ready={this.state.groupDelegatedControl !== -1}
|
||||||
|
value={this.state.groupDelegatedControl}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "MATCH p = (c:Computer {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label}
|
||||||
|
,this.state.label);
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
Transitive Object Control
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<NodeALink
|
||||||
|
ready={this.state.transitiveControl !== -1}
|
||||||
|
value={this.state.transitiveControl}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((c:Computer {name:{name}})-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN p", {name:this.state.label}
|
||||||
|
,this.state.label);
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ComputerNodeData.propTypes= {
|
ComputerNodeData.propTypes= {
|
||||||
visible : React.PropTypes.bool.isRequired
|
visible : React.PropTypes.bool.isRequired
|
||||||
}
|
};
|
||||||
|
|
|
@ -2,121 +2,134 @@ import React, { Component } from 'react';
|
||||||
import LogoutModal from 'modals/LogoutModal';
|
import LogoutModal from 'modals/LogoutModal';
|
||||||
|
|
||||||
export default class DatabaseDataDisplay extends Component {
|
export default class DatabaseDataDisplay extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super()
|
super();
|
||||||
this.state = {
|
this.state = {
|
||||||
url: appStore.databaseInfo.url,
|
url: appStore.databaseInfo.url,
|
||||||
user: appStore.databaseInfo.user,
|
user: appStore.databaseInfo.user,
|
||||||
num_users: 'Refreshing',
|
num_users: 'Refreshing',
|
||||||
num_computers: 'Refreshing',
|
num_computers: 'Refreshing',
|
||||||
num_groups: 'Refreshing',
|
num_groups: 'Refreshing',
|
||||||
num_relationships: 'Refreshing',
|
num_relationships: 'Refreshing',
|
||||||
num_sessions: 'Refreshing',
|
num_sessions: 'Refreshing',
|
||||||
interval: null
|
num_acls: 'Refreshing',
|
||||||
}
|
interval: null
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.refreshDBData()
|
this.refreshDBData();
|
||||||
var x = setInterval(function(){
|
emitter.on('hideDBClearModal', this.refreshDBData.bind(this));
|
||||||
this.refreshDBData()
|
emitter.on('refreshDBData', this.refreshDBData.bind(this));
|
||||||
}.bind(this), 60000);
|
this.createInterval();
|
||||||
this.setState({
|
}
|
||||||
interval: x
|
|
||||||
})
|
|
||||||
emitter.on('hideDBClearModal', this.refreshDBData.bind(this))
|
|
||||||
emitter.on('refreshDBData', this.refreshDBData.bind(this))
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
clearInterval(this.state.interval)
|
clearInterval(this.state.interval);
|
||||||
this.setState({
|
this.setState({
|
||||||
interval: null,
|
interval: null,
|
||||||
session: null
|
session: null
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLogoutModal(){
|
createInterval(){
|
||||||
emitter.emit('showLogout');
|
var x = setInterval(function(){
|
||||||
}
|
this.refreshDBData();
|
||||||
|
}.bind(this), 60000);
|
||||||
|
this.setState({
|
||||||
|
interval: x
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
toggleDBWarnModal(){
|
toggleLogoutModal(){
|
||||||
emitter.emit('openDBWarnModal')
|
emitter.emit('showLogout');
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSessionClearModal(){
|
toggleDBWarnModal(){
|
||||||
emitter.emit('openSessionClearModal')
|
emitter.emit('openDBWarnModal');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSessionClearModal(){
|
||||||
|
emitter.emit('openSessionClearModal');
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
refreshDBData(){
|
||||||
return (
|
var s1 = driver.session();
|
||||||
<div>
|
var s2 = driver.session();
|
||||||
<h3>Database Info</h3>
|
var s3 = driver.session();
|
||||||
<dl className="dl-horizontal dl-horizontal-fix">
|
var s4 = driver.session();
|
||||||
<dt>DB Address</dt>
|
var s5 = driver.session();
|
||||||
<dd>{this.state.url}</dd>
|
var s6 = driver.session();
|
||||||
<dt>DB User</dt>
|
|
||||||
<dd>{this.state.user}</dd>
|
|
||||||
<dt>Users</dt>
|
|
||||||
<dd>{this.state.num_users}</dd>
|
|
||||||
<dt>Computers</dt>
|
|
||||||
<dd>{this.state.num_computers}</dd>
|
|
||||||
<dt>Groups</dt>
|
|
||||||
<dd>{this.state.num_groups}</dd>
|
|
||||||
<dt>Sessions</dt>
|
|
||||||
<dd>{this.state.num_sessions}</dd>
|
|
||||||
<dt>Relationships</dt>
|
|
||||||
<dd>{this.state.num_relationships}</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<div className="text-center">
|
s1.run("MATCH (n:User) WHERE NOT n.name ENDS WITH '$' RETURN count(n)")
|
||||||
<div className="btn-group btn-group-sm dbbuttons">
|
.then(function(result){
|
||||||
<button type="button" className="btn btn-success" onClick={function(){this.refreshDBData()}.bind(this)}>Refresh DB Stats</button>
|
this.setState({'num_users':result.records[0]._fields[0].low});
|
||||||
<button type="button" className="btn btn-info" onClick={this.toggleSessionClearModal}>Clear Sessions</button>
|
s1.close();
|
||||||
<button type="button" className="btn btn-warning" onClick={this.toggleLogoutModal}>Log Out/Switch DB</button>
|
}.bind(this));
|
||||||
<button type="button" className="btn btn-danger" onClick={this.toggleDBWarnModal}>Clear Database</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshDBData(){
|
s2.run("MATCH (n:Group) RETURN count(n)")
|
||||||
var s1 = driver.session()
|
.then(function(result){
|
||||||
var s2 = driver.session()
|
this.setState({'num_groups':result.records[0]._fields[0].low});
|
||||||
var s3 = driver.session()
|
s2.close();
|
||||||
var s4 = driver.session()
|
}.bind(this));
|
||||||
var s5 = driver.session()
|
|
||||||
|
|
||||||
s1.run("MATCH (n:User) WHERE NOT n.name ENDS WITH '$' RETURN count(n)")
|
s3.run("MATCH (n:Computer) RETURN count(n)")
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'num_users':result.records[0]._fields[0].low})
|
this.setState({'num_computers':result.records[0]._fields[0].low});
|
||||||
s1.close()
|
s3.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s2.run("MATCH (n:Group) RETURN count(n)")
|
s4.run("MATCH ()-[r:HasSession]->() RETURN count(r)")
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'num_groups':result.records[0]._fields[0].low})
|
this.setState({'num_sessions':result.records[0]._fields[0].low});
|
||||||
s2.close()
|
s4.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s3.run("MATCH (n:Computer) RETURN count(n)")
|
s6.run("MATCH ()-[r {isACL: true}]->() RETURN count(r)")
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'num_computers':result.records[0]._fields[0].low})
|
this.setState({'num_acls':result.records[0]._fields[0].low});
|
||||||
s3.close()
|
s6.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s4.run("MATCH ()-[r:HasSession]->() RETURN count(r)")
|
s5.run("MATCH ()-[r]->() RETURN count(r)")
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'num_sessions':result.records[0]._fields[0].low})
|
this.setState({'num_relationships':result.records[0]._fields[0].low});
|
||||||
s4.close()
|
s5.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
s5.run("MATCH ()-[r]->() RETURN count(r)")
|
render() {
|
||||||
.then(function(result){
|
return (
|
||||||
this.setState({'num_relationships':result.records[0]._fields[0].low})
|
<div>
|
||||||
s5.close()
|
<h3>Database Info</h3>
|
||||||
}.bind(this))
|
<dl className="dl-horizontal dl-horizontal-fix">
|
||||||
}
|
<dt>DB Address</dt>
|
||||||
|
<dd>{this.state.url}</dd>
|
||||||
|
<dt>DB User</dt>
|
||||||
|
<dd>{this.state.user}</dd>
|
||||||
|
<dt>Users</dt>
|
||||||
|
<dd>{this.state.num_users}</dd>
|
||||||
|
<dt>Computers</dt>
|
||||||
|
<dd>{this.state.num_computers}</dd>
|
||||||
|
<dt>Groups</dt>
|
||||||
|
<dd>{this.state.num_groups}</dd>
|
||||||
|
<dt>Sessions</dt>
|
||||||
|
<dd>{this.state.num_sessions}</dd>
|
||||||
|
<dt>ACLs</dt>
|
||||||
|
<dd>{this.state.num_acls}</dd>
|
||||||
|
<dt>Relationships</dt>
|
||||||
|
<dd>{this.state.num_relationships}</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="btn-group btn-group-sm dbbuttons">
|
||||||
|
<button type="button" className="btn btn-success" onClick={function(){this.refreshDBData();}.bind(this)}>Refresh DB Stats</button>
|
||||||
|
<button type="button" className="btn btn-info" onClick={this.toggleSessionClearModal}>Clear Sessions</button>
|
||||||
|
<button type="button" className="btn btn-warning" onClick={this.toggleLogoutModal}>Log Out/Switch DB</button>
|
||||||
|
<button type="button" className="btn btn-danger" onClick={this.toggleDBWarnModal}>Clear Database</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,233 +1,243 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import NodeALink from './NodeALink.jsx'
|
import NodeALink from './NodeALink.jsx';
|
||||||
import LoadLabel from './LoadLabel.jsx'
|
import LoadLabel from './LoadLabel.jsx';
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class DomainNodeData extends Component {
|
export default class DomainNodeData extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
label: "",
|
label: "",
|
||||||
users: -1,
|
users: -1,
|
||||||
groups: -1,
|
groups: -1,
|
||||||
computers: -1,
|
computers: -1,
|
||||||
foreignGroups: -1,
|
foreignGroups: -1,
|
||||||
foreignUsers: -1,
|
foreignUsers: -1,
|
||||||
firstDegreeOutboundTrusts: -1,
|
firstDegreeOutboundTrusts: -1,
|
||||||
effectiveOutboundTrusts: -1,
|
effectiveOutboundTrusts: -1,
|
||||||
firstDegreeInboundTrusts: -1,
|
firstDegreeInboundTrusts: -1,
|
||||||
effectiveInboundTrusts: -1,
|
effectiveInboundTrusts: -1,
|
||||||
driversessions: []
|
driversessions: []
|
||||||
}
|
};
|
||||||
|
|
||||||
emitter.on('domainNodeClicked', this.getNodeData.bind(this));
|
emitter.on('domainNodeClicked', this.getNodeData.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodeData(payload){
|
getNodeData(payload){
|
||||||
$.each(this.state.driversessions, function(index, record){
|
$.each(this.state.driversessions, function(index, record){
|
||||||
record.close();
|
record.close();
|
||||||
})
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
label: payload,
|
label: payload,
|
||||||
users: -1,
|
users: -1,
|
||||||
groups: -1,
|
groups: -1,
|
||||||
computers: -1,
|
computers: -1,
|
||||||
foreignGroups: -1,
|
foreignGroups: -1,
|
||||||
foreignUsers: -1,
|
foreignUsers: -1,
|
||||||
firstDegreeOutboundTrusts: -1,
|
firstDegreeOutboundTrusts: -1,
|
||||||
effectiveOutboundTrusts: -1,
|
effectiveOutboundTrusts: -1,
|
||||||
firstDegreeInboundTrusts: -1,
|
firstDegreeInboundTrusts: -1,
|
||||||
effectiveInboundTrusts: -1
|
effectiveInboundTrusts: -1
|
||||||
})
|
});
|
||||||
|
|
||||||
var s1 = driver.session()
|
var s1 = driver.session();
|
||||||
var s2 = driver.session()
|
var s2 = driver.session();
|
||||||
var s3 = driver.session()
|
var s3 = driver.session();
|
||||||
var s4 = driver.session()
|
var s4 = driver.session();
|
||||||
var s5 = driver.session()
|
var s5 = driver.session();
|
||||||
var s6 = driver.session()
|
var s6 = driver.session();
|
||||||
var s7 = driver.session()
|
var s7 = driver.session();
|
||||||
var s8 = driver.session()
|
var s8 = driver.session();
|
||||||
var s9 = driver.session()
|
var s9 = driver.session();
|
||||||
|
|
||||||
s1.run("MATCH (a:User) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload})
|
s1.run("MATCH (a:User) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'users':result.records[0]._fields[0].low})
|
this.setState({'users':result.records[0]._fields[0].low});
|
||||||
s1.close()
|
s1.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s2.run("MATCH (a:Group) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload})
|
s2.run("MATCH (a:Group) WHERE a.name ENDS WITH ('@' + {name}) RETURN COUNT(a)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'groups':result.records[0]._fields[0].low})
|
this.setState({'groups':result.records[0]._fields[0].low});
|
||||||
s2.close()
|
s2.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'computers':result.records[0]._fields[0].low})
|
this.setState({'computers':result.records[0]._fields[0].low});
|
||||||
s3.close()
|
s3.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'foreignGroups':result.records[0]._fields[0].low})
|
this.setState({'foreignGroups':result.records[0]._fields[0].low});
|
||||||
s4.close()
|
s4.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'foreignUsers':result.records[0]._fields[0].low})
|
this.setState({'foreignUsers':result.records[0]._fields[0].low});
|
||||||
s5.close()
|
s5.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s6.run("MATCH (a:Domain {name:{name}})<-[r:TrustedBy]-(b:Domain) RETURN count(b)", {name:payload})
|
s6.run("MATCH (a:Domain {name:{name}})<-[r:TrustedBy]-(b:Domain) RETURN count(b)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeInboundTrusts':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeInboundTrusts':result.records[0]._fields[0].low});
|
||||||
s6.close()
|
s6.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s7.run("MATCH (a:Domain {name:{name}})-[r:TrustedBy]->(b:Domain) RETURN count(b)", {name:payload})
|
s7.run("MATCH (a:Domain {name:{name}})-[r:TrustedBy]->(b:Domain) RETURN count(b)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeOutboundTrusts':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeOutboundTrusts':result.records[0]._fields[0].low});
|
||||||
s7.close()
|
s7.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s8.run("MATCH p=shortestPath((a:Domain {name:{name}})<-[r:TrustedBy*1..]-(b:Domain)) RETURN count(b)", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'effectiveInboundTrusts':result.records[0]._fields[0].low})
|
this.setState({'effectiveInboundTrusts':result.records[0]._fields[0].low});
|
||||||
s8.close()
|
s8.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s9.run("MATCH p=shortestPath((a:Domain {name:{name}})-[r:TrustedBy*1..]->(b:Domain)) RETURN count(b)", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'effectiveOutboundTrusts':result.records[0]._fields[0].low})
|
this.setState({'effectiveOutboundTrusts':result.records[0]._fields[0].low});
|
||||||
s9.close()
|
s9.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9]})
|
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9]});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.visible ? "" : "displaynone"}>
|
<div className={this.props.visible ? "" : "displaynone"}>
|
||||||
<dl className='dl-horizontal'>
|
<dl className='dl-horizontal'>
|
||||||
<dt>
|
<dt>
|
||||||
Node
|
Node
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{this.state.label}
|
{this.state.label}
|
||||||
</dd>
|
</dd>
|
||||||
<br />
|
<br />
|
||||||
<dt>
|
<dt>
|
||||||
Users
|
Users
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<LoadLabel
|
<LoadLabel
|
||||||
ready={this.state.users !== -1}
|
ready={this.state.users !== -1}
|
||||||
value={this.state.users} />
|
value={this.state.users}
|
||||||
</dd>
|
/>
|
||||||
<dt>
|
</dd>
|
||||||
Groups
|
<dt>
|
||||||
</dt>
|
Groups
|
||||||
<dd>
|
</dt>
|
||||||
<LoadLabel
|
<dd>
|
||||||
ready={this.state.groups !== -1}
|
<LoadLabel
|
||||||
value={this.state.groups} />
|
ready={this.state.groups !== -1}
|
||||||
</dd>
|
value={this.state.groups}
|
||||||
<dt>
|
/>
|
||||||
Computers
|
</dd>
|
||||||
</dt>
|
<dt>
|
||||||
<dd>
|
Computers
|
||||||
<LoadLabel
|
</dt>
|
||||||
ready={this.state.computers !== -1}
|
<dd>
|
||||||
value={this.state.computers} />
|
<LoadLabel
|
||||||
</dd>
|
ready={this.state.computers !== -1}
|
||||||
<br />
|
value={this.state.computers}
|
||||||
<dt>
|
/>
|
||||||
Foreign Users
|
</dd>
|
||||||
</dt>
|
<br />
|
||||||
<dd>
|
<dt>
|
||||||
<NodeALink
|
Foreign Users
|
||||||
ready={this.state.foreignUsers !== -1}
|
</dt>
|
||||||
value={this.state.foreignUsers}
|
<dd>
|
||||||
click={function(){
|
<NodeALink
|
||||||
emitter.emit('query', "MATCH (a:User) WHERE NOT a.name ENDS WITH ('@' + {domain}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {domain}) WITH a,b MATCH (a)-[r:MemberOf]-(b) RETURN a,r,b", {domain: this.state.label})
|
ready={this.state.foreignUsers !== -1}
|
||||||
}.bind(this)} />
|
value={this.state.foreignUsers}
|
||||||
</dd>
|
click={function(){
|
||||||
<dt>
|
emitter.emit('query', "MATCH (a:User) WHERE NOT a.name ENDS WITH ('@' + {domain}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {domain}) WITH a,b MATCH (a)-[r:MemberOf]-(b) RETURN a,r,b", {domain: this.state.label});
|
||||||
Foreign Groups
|
}.bind(this)}
|
||||||
</dt>
|
/>
|
||||||
<dd>
|
</dd>
|
||||||
<NodeALink
|
<dt>
|
||||||
ready={this.state.foreignGroups !== -1}
|
Foreign Groups
|
||||||
value={this.state.foreignGroups}
|
</dt>
|
||||||
click={function(){
|
<dd>
|
||||||
emitter.emit('query', "MATCH (a:Group) WHERE NOT a.name ENDS WITH ('@' + {domain}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {domain}) WITH a,b MATCH (a)-[r:MemberOf]-(b) RETURN a,r,b", {domain: this.state.label})
|
<NodeALink
|
||||||
}.bind(this)} />
|
ready={this.state.foreignGroups !== -1}
|
||||||
</dd>
|
value={this.state.foreignGroups}
|
||||||
<dt>
|
click={function(){
|
||||||
Foreign Admins
|
emitter.emit('query', "MATCH (a:Group) WHERE NOT a.name ENDS WITH ('@' + {domain}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {domain}) WITH a,b MATCH (a)-[r:MemberOf]-(b) RETURN a,r,b", {domain: this.state.label});
|
||||||
</dt>
|
}.bind(this)}
|
||||||
<dd>
|
/>
|
||||||
<NodeALink
|
</dd>
|
||||||
ready={this.state.foreignAdmins !== -1}
|
<dt>
|
||||||
value={this.state.foreignAdmins}
|
Foreign Admins
|
||||||
click={function(){
|
</dt>
|
||||||
emitter.emit('query', "MATCH (a:Group) WHERE NOT a.name ENDS WITH ('@' + {domain}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {domain}) WITH a,b MATCH (a)-[r:MemberOf]-(b) RETURN a,r,b", {domain: this.state.label})
|
<dd>
|
||||||
}.bind(this)} />
|
<NodeALink
|
||||||
</dd>
|
ready={this.state.foreignAdmins !== -1}
|
||||||
<br />
|
value={this.state.foreignAdmins}
|
||||||
<dt>
|
click={function(){
|
||||||
Inbound Trusts
|
emitter.emit('query', "MATCH (a:Group) WHERE NOT a.name ENDS WITH ('@' + {domain}) WITH a MATCH (b:Group) WHERE b.name ENDS WITH ('@' + {domain}) WITH a,b MATCH (a)-[r:MemberOf]-(b) RETURN a,r,b", {domain: this.state.label});
|
||||||
</dt>
|
}.bind(this)}
|
||||||
<dd>
|
/>
|
||||||
<NodeALink
|
</dd>
|
||||||
ready={this.state.firstDegreeInboundTrusts !== -1}
|
<br />
|
||||||
value={this.state.firstDegreeInboundTrusts}
|
<dt>
|
||||||
click={function(){
|
Inbound Trusts
|
||||||
emitter.emit('query', "MATCH (a:Domain {name:{domain}})<-[r:TrustedBy]-(b:Domain) RETURN a,r,b", {domain: this.state.label})
|
</dt>
|
||||||
}.bind(this)} />
|
<dd>
|
||||||
</dd>
|
<NodeALink
|
||||||
<dt>
|
ready={this.state.firstDegreeInboundTrusts !== -1}
|
||||||
Effective Inbound Trusts
|
value={this.state.firstDegreeInboundTrusts}
|
||||||
</dt>
|
click={function(){
|
||||||
<dd>
|
emitter.emit('query', "MATCH (a:Domain {name:{domain}})<-[r:TrustedBy]-(b:Domain) RETURN a,r,b", {domain: this.state.label});
|
||||||
<NodeALink
|
}.bind(this)}
|
||||||
ready={this.state.effectiveInboundTrusts !== -1}
|
/>
|
||||||
value={this.state.effectiveInboundTrusts}
|
</dd>
|
||||||
click={function(){
|
<dt>
|
||||||
emitter.emit('query', "MATCH p=shortestPath((a:Domain {name:{domain}})<-[r:TrustedBy*1..]-(b:Domain)) RETURN p", {domain: this.state.label})
|
Effective Inbound Trusts
|
||||||
}.bind(this)} />
|
</dt>
|
||||||
</dd>
|
<dd>
|
||||||
<dt>
|
<NodeALink
|
||||||
Outbound Trusts
|
ready={this.state.effectiveInboundTrusts !== -1}
|
||||||
</dt>
|
value={this.state.effectiveInboundTrusts}
|
||||||
<dd>
|
click={function(){
|
||||||
<NodeALink
|
emitter.emit('query', "MATCH (b:Domain) WHERE NOT b.name={domain} WITH b MATCH p=shortestPath((a:Domain {name:{domain}})<-[r:TrustedBy*1..]-(b)) RETURN p", {domain: this.state.label});
|
||||||
ready={this.state.firstDegreeOutboundTrusts !== -1}
|
}.bind(this)}
|
||||||
value={this.state.firstDegreeOutboundTrusts}
|
/>
|
||||||
click={function(){
|
</dd>
|
||||||
emitter.emit('query', "MATCH (a:Domain {name:{domain}})-[r:TrustedBy]->(b:Domain) RETURN a,r,b", {domain: this.state.label})
|
<dt>
|
||||||
}.bind(this)} />
|
Outbound Trusts
|
||||||
</dd>
|
</dt>
|
||||||
<dt>
|
<dd>
|
||||||
Effective Outbound Trusts
|
<NodeALink
|
||||||
</dt>
|
ready={this.state.firstDegreeOutboundTrusts !== -1}
|
||||||
<dd>
|
value={this.state.firstDegreeOutboundTrusts}
|
||||||
<NodeALink
|
click={function(){
|
||||||
ready={this.state.effectiveOutboundTrusts !== -1}
|
emitter.emit('query', "MATCH (a:Domain {name:{domain}})-[r:TrustedBy]->(b:Domain) RETURN a,r,b", {domain: this.state.label});
|
||||||
value={this.state.effectiveOutboundTrusts}
|
}.bind(this)}
|
||||||
click={function(){
|
/>
|
||||||
emitter.emit('query', "MATCH p=shortestPath((a:Domain {name:{domain}})-[r:TrustedBy*1..]->(b:Domain)) RETURN p", {domain: this.state.label})
|
</dd>
|
||||||
}.bind(this)} />
|
<dt>
|
||||||
</dd>
|
Effective Outbound Trusts
|
||||||
</dl>
|
</dt>
|
||||||
</div>
|
<dd>
|
||||||
);
|
<NodeALink
|
||||||
}
|
ready={this.state.effectiveOutboundTrusts !== -1}
|
||||||
|
value={this.state.effectiveOutboundTrusts}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "MATCH (b:Domain) WHERE NOT b.name={domain} WITH b MATCH p=shortestPath((a:Domain {name:{domain}})-[r:TrustedBy*1..]->(b:Domain)) RETURN p", {domain: this.state.label});
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DomainNodeData.propTypes = {
|
DomainNodeData.propTypes = {
|
||||||
visible : React.PropTypes.bool.isRequired
|
visible : React.PropTypes.bool.isRequired
|
||||||
}
|
};
|
|
@ -1,394 +1,405 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import NodeALink from './NodeALink'
|
import NodeALink from './NodeALink';
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class GroupNodeData extends Component {
|
export default class GroupNodeData extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
label: "",
|
label: "",
|
||||||
directMembers: -1,
|
directMembers: -1,
|
||||||
unrolledMembers: -1,
|
unrolledMembers: -1,
|
||||||
directAdminTo: -1,
|
directAdminTo: -1,
|
||||||
derivativeAdminTo: -1,
|
derivativeAdminTo: -1,
|
||||||
unrolledMemberOf: -1,
|
unrolledMemberOf: -1,
|
||||||
sessions: -1,
|
sessions: -1,
|
||||||
foreignGroupMembership: -1,
|
foreignGroupMembership: -1,
|
||||||
foreignGroupMembers: -1,
|
foreignGroupMembers: -1,
|
||||||
firstDegreeGroupMembership: -1,
|
firstDegreeGroupMembership: -1,
|
||||||
groupDelegatedAdmin: -1,
|
groupDelegatedAdmin: -1,
|
||||||
firstdegreeControl: -1,
|
firstdegreeControl: -1,
|
||||||
groupDelegatedControl: -1,
|
groupDelegatedControl: -1,
|
||||||
transitiveControl: -1,
|
transitiveControl: -1,
|
||||||
firstDegreeControllers: -1,
|
firstDegreeControllers: -1,
|
||||||
unrolledControllers: -1,
|
unrolledControllers: -1,
|
||||||
transitiveControllers: -1,
|
transitiveControllers: -1,
|
||||||
driversessions: []
|
driversessions: []
|
||||||
}
|
};
|
||||||
|
|
||||||
emitter.on('groupNodeClicked', this.getNodeData.bind(this));
|
emitter.on('groupNodeClicked', this.getNodeData.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodeData(payload){
|
getNodeData(payload){
|
||||||
$.each(this.state.driversessions, function(index, record){
|
$.each(this.state.driversessions, function(index, record){
|
||||||
record.close();
|
record.close();
|
||||||
})
|
});
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
label: payload,
|
label: payload,
|
||||||
directMembers: -1,
|
directMembers: -1,
|
||||||
unrolledMembers: -1,
|
unrolledMembers: -1,
|
||||||
directAdminTo: -1,
|
directAdminTo: -1,
|
||||||
derivativeAdminTo: -1,
|
derivativeAdminTo: -1,
|
||||||
unrolledMemberOf: -1,
|
unrolledMemberOf: -1,
|
||||||
sessions: -1,
|
sessions: -1,
|
||||||
foreignGroupMembership: -1,
|
foreignGroupMembership: -1,
|
||||||
foreignGroupMembers: -1,
|
foreignGroupMembers: -1,
|
||||||
firstDegreeGroupMembership: -1,
|
firstDegreeGroupMembership: -1,
|
||||||
groupDelegatedAdmin: -1,
|
groupDelegatedAdmin: -1,
|
||||||
firstdegreeControl: -1,
|
firstdegreeControl: -1,
|
||||||
groupDelegatedControl: -1,
|
groupDelegatedControl: -1,
|
||||||
transitiveControl: -1,
|
transitiveControl: -1,
|
||||||
firstDegreeControllers: -1,
|
firstDegreeControllers: -1,
|
||||||
unrolledControllers: -1,
|
unrolledControllers: -1,
|
||||||
transitiveControllers: -1
|
transitiveControllers: -1
|
||||||
})
|
});
|
||||||
|
|
||||||
var domain = '@' + payload.split('@').last()
|
var domain = '@' + payload.split('@').last();
|
||||||
var s1 = driver.session()
|
var s1 = driver.session();
|
||||||
var s2 = driver.session()
|
var s2 = driver.session();
|
||||||
var s3 = driver.session()
|
var s3 = driver.session();
|
||||||
var s4 = driver.session()
|
var s4 = driver.session();
|
||||||
var s5 = driver.session()
|
var s5 = driver.session();
|
||||||
var s6 = driver.session()
|
var s6 = driver.session();
|
||||||
var s7 = driver.session()
|
var s7 = driver.session();
|
||||||
var s8 = driver.session()
|
var s8 = driver.session();
|
||||||
var s9 = driver.session()
|
var s9 = driver.session();
|
||||||
var s10 = driver.session()
|
var s10 = driver.session();
|
||||||
var s11 = driver.session()
|
var s11 = driver.session();
|
||||||
var s12 = driver.session()
|
var s12 = driver.session();
|
||||||
var s13 = driver.session()
|
var s13 = driver.session();
|
||||||
var s14 = driver.session()
|
var s14 = driver.session();
|
||||||
var s15 = driver.session()
|
var s15 = driver.session();
|
||||||
var s16 = driver.session()
|
var s16 = driver.session();
|
||||||
|
|
||||||
s1.run("MATCH (a)-[b:MemberOf]->(c:Group {name:{name}}) RETURN count(a)", {name:payload})
|
s1.run("MATCH (a)-[b:MemberOf]->(c:Group {name:{name}}) RETURN count(a)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'directMembers':result.records[0]._fields[0].low})
|
this.setState({'directMembers':result.records[0]._fields[0].low});
|
||||||
s1.close()
|
s1.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s2.run("MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) RETURN COUNT(n)", {name:payload})
|
s2.run("MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) RETURN COUNT(n)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'unrolledMembers':result.records[0]._fields[0].low})
|
this.setState({'unrolledMembers':result.records[0]._fields[0].low});
|
||||||
s2.close()
|
s2.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s3.run("MATCH (n:Group {name:{name}})-[r:AdminTo]->(m:Computer) RETURN count(distinct(m))", {name:payload})
|
s3.run("MATCH (n:Group {name:{name}})-[r:AdminTo]->(m:Computer) RETURN count(distinct(m))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'directAdminTo':result.records[0]._fields[0].low})
|
this.setState({'directAdminTo':result.records[0]._fields[0].low});
|
||||||
s3.close()
|
s3.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s4.run("MATCH p = shortestPath((g:Group {name:{name}})-[r:MemberOf|AdminTo|HasSession*1..]->(c:Computer)) RETURN COUNT(DISTINCT(c))", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'derivativeAdminTo':result.records[0]._fields[0].low})
|
this.setState({'derivativeAdminTo':result.records[0]._fields[0].low});
|
||||||
s4.close()
|
s4.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s5.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf*1..]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload})
|
s5.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf*1..]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'unrolledMemberOf':result.records[0]._fields[0].low})
|
this.setState({'unrolledMemberOf':result.records[0]._fields[0].low});
|
||||||
s5.close()
|
s5.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s6.run("MATCH p = (c:Computer)-[r1:HasSession]->(u:User)-[r2:MemberOf*1..]->(g:Group {name: {name}}) RETURN COUNT(r1)", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'sessions':result.records[0]._fields[0].low})
|
this.setState({'sessions':result.records[0]._fields[0].low});
|
||||||
s6.close()
|
s6.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'foreignGroupMembership':result.records[0]._fields[0].low})
|
this.setState({'foreignGroupMembership':result.records[0]._fields[0].low});
|
||||||
s7.close()
|
s7.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'foreignGroupMembers':result.records[0]._fields[0].low})
|
this.setState({'foreignGroupMembers':result.records[0]._fields[0].low});
|
||||||
s8.close()
|
s8.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s9.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload})
|
s9.run("MATCH p = (g1:Group {name:{name}})-[r:MemberOf]->(g2:Group) RETURN COUNT(DISTINCT(g2))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low});
|
||||||
s9.close()
|
s9.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'groupDelegatedAdmin':result.records[0]._fields[0].low})
|
this.setState({'groupDelegatedAdmin':result.records[0]._fields[0].low});
|
||||||
s10.close()
|
s10.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'firstdegreeControl':result.records[0]._fields[0].low})
|
this.setState({'firstdegreeControl':result.records[0]._fields[0].low});
|
||||||
s11.close()
|
s11.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'groupDelegatedControl':result.records[0]._fields[0].low})
|
this.setState({'groupDelegatedControl':result.records[0]._fields[0].low});
|
||||||
s12.close()
|
s12.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'transitiveControl':result.records[0]._fields[0].low})
|
this.setState({'transitiveControl':result.records[0]._fields[0].low});
|
||||||
s13.close()
|
s13.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeControllers':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeControllers':result.records[0]._fields[0].low});
|
||||||
s14.close()
|
s14.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'unrolledControllers':result.records[0]._fields[0].low})
|
this.setState({'unrolledControllers':result.records[0]._fields[0].low});
|
||||||
s15.close()
|
s15.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'transitiveControllers':result.records[0]._fields[0].low})
|
this.setState({'transitiveControllers':result.records[0]._fields[0].low});
|
||||||
s16.close()
|
s16.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16]})
|
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16]});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var domain = '@' + this.state.label.split('@')
|
var domain = '@' + this.state.label.split('@');
|
||||||
return (
|
return (
|
||||||
<div className={this.props.visible ? "" : "displaynone"}>
|
<div className={this.props.visible ? "" : "displaynone"}>
|
||||||
<dl className='dl-horizontal'>
|
<dl className='dl-horizontal'>
|
||||||
<h4>Node Info</h4>
|
<h4>Node Info</h4>
|
||||||
<dt>
|
<dt>
|
||||||
Name
|
Name
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{this.state.label}
|
{this.state.label}
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
Sessions
|
Sessions
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<NodeALink
|
<NodeALink
|
||||||
ready={this.state.sessions !== -1}
|
ready={this.state.sessions !== -1}
|
||||||
value={this.state.sessions}
|
value={this.state.sessions}
|
||||||
click={function(){
|
click={function(){
|
||||||
emitter.emit('query', "MATCH p = (c:Computer)-[r1:HasSession]->(u:User)-[r2:MemberOf*1..]->(g:Group {name: {name}}) RETURN p", {name: this.state.label},
|
emitter.emit('query', "MATCH p = (c:Computer)-[r1:HasSession]->(u:User)-[r2:MemberOf*1..]->(g:Group {name: {name}}) RETURN p", {name: this.state.label},
|
||||||
"",this.state.label)
|
"",this.state.label);
|
||||||
}.bind(this)} />
|
}.bind(this)}
|
||||||
</dd>
|
/>
|
||||||
<br />
|
</dd>
|
||||||
<h4>Group Members</h4>
|
<h4>Group Members</h4>
|
||||||
<dt>
|
<dt>
|
||||||
Direct Members
|
Direct Members
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<NodeALink
|
<NodeALink
|
||||||
ready={this.state.directMembers !== -1}
|
ready={this.state.directMembers !== -1}
|
||||||
value={this.state.directMembers}
|
value={this.state.directMembers}
|
||||||
click={function(){
|
click={function(){
|
||||||
emitter.emit('query', "MATCH (n)-[r:MemberOf]->(m:Group {name:{name}}) RETURN n,r,m", {name: this.state.label})
|
emitter.emit('query', "MATCH (n)-[r:MemberOf]->(m:Group {name:{name}}) RETURN n,r,m", {name: this.state.label});
|
||||||
}.bind(this)} />
|
}.bind(this)}
|
||||||
</dd>
|
/>
|
||||||
<dt>
|
</dd>
|
||||||
Unrolled Members
|
<dt>
|
||||||
</dt>
|
Unrolled Members
|
||||||
<dd>
|
</dt>
|
||||||
<NodeALink
|
<dd>
|
||||||
ready={this.state.unrolledMembers !== -1}
|
<NodeALink
|
||||||
value={this.state.unrolledMembers}
|
ready={this.state.unrolledMembers !== -1}
|
||||||
click={function(){
|
value={this.state.unrolledMembers}
|
||||||
emitter.emit('query', "MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) RETURN p", {name: this.state.label},
|
click={function(){
|
||||||
this.state.label)
|
emitter.emit('query', "MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) RETURN p", {name: this.state.label},
|
||||||
}.bind(this)} />
|
this.state.label);
|
||||||
</dd>
|
}.bind(this)}
|
||||||
<dt>
|
/>
|
||||||
Foreign Members
|
</dd>
|
||||||
</dt>
|
<dt>
|
||||||
<dd>
|
Foreign Members
|
||||||
<NodeALink
|
</dt>
|
||||||
ready={this.state.foreignGroupMembers !== -1}
|
<dd>
|
||||||
value={this.state.foreignGroupMembers}
|
<NodeALink
|
||||||
click={function(){
|
ready={this.state.foreignGroupMembers !== -1}
|
||||||
emitter.emit('query', "MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) WHERE NOT g.domain = n.domain RETURN p", {name: this.state.label},
|
value={this.state.foreignGroupMembers}
|
||||||
this.state.label)
|
click={function(){
|
||||||
}.bind(this)} />
|
emitter.emit('query', "MATCH p = (n)-[r:MemberOf*1..]->(g:Group {name:{name}}) WHERE NOT g.domain = n.domain RETURN p", {name: this.state.label},
|
||||||
</dd>
|
this.state.label);
|
||||||
<br />
|
}.bind(this)}
|
||||||
<h4>Group Membership</h4>
|
/>
|
||||||
<dt>
|
</dd>
|
||||||
First Degree Group Membership
|
<h4>Group Membership</h4>
|
||||||
</dt>
|
<dt>
|
||||||
<dd>
|
First Degree Group Membership
|
||||||
<NodeALink
|
</dt>
|
||||||
ready={this.state.firstDegreeGroupMembership !== -1}
|
<dd>
|
||||||
value={this.state.firstDegreeGroupMembership}
|
<NodeALink
|
||||||
click={function(){
|
ready={this.state.firstDegreeGroupMembership !== -1}
|
||||||
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r:MemberOf]->(g2:Group) RETURN p", {name: this.state.label},
|
value={this.state.firstDegreeGroupMembership}
|
||||||
this.state.label)
|
click={function(){
|
||||||
}.bind(this)} />
|
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r:MemberOf]->(g2:Group) RETURN p", {name: this.state.label},
|
||||||
</dd>
|
this.state.label);
|
||||||
<dt>
|
}.bind(this)}
|
||||||
Unrolled Member Of
|
/>
|
||||||
</dt>
|
</dd>
|
||||||
<dd>
|
<dt>
|
||||||
<NodeALink
|
Unrolled Member Of
|
||||||
ready={this.state.unrolledMemberOf !== -1}
|
</dt>
|
||||||
value={this.state.unrolledMemberOf}
|
<dd>
|
||||||
click={function(){
|
<NodeALink
|
||||||
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r:MemberOf*1..]->(g2:Group) RETURN p", {name: this.state.label},
|
ready={this.state.unrolledMemberOf !== -1}
|
||||||
this.state.label)
|
value={this.state.unrolledMemberOf}
|
||||||
}.bind(this)} />
|
click={function(){
|
||||||
</dd>
|
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r:MemberOf*1..]->(g2:Group) RETURN p", {name: this.state.label},
|
||||||
<dt>
|
this.state.label);
|
||||||
Foreign Group Membership
|
}.bind(this)}
|
||||||
</dt>
|
/>
|
||||||
<dd>
|
</dd>
|
||||||
<NodeALink
|
<dt>
|
||||||
ready={this.state.foreignGroupMembership !== -1}
|
Foreign Group Membership
|
||||||
value={this.state.foreignGroupMembership}
|
</dt>
|
||||||
click={function(){
|
<dd>
|
||||||
emitter.emit('query', "MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:Group {name:{name}}) MATCH (m)-[r:MemberOf]->(n) RETURN m,r,n", {name: this.state.label, domain: domain})
|
<NodeALink
|
||||||
}.bind(this)} />
|
ready={this.state.foreignGroupMembership !== -1}
|
||||||
</dd>
|
value={this.state.foreignGroupMembership}
|
||||||
<br />
|
click={function(){
|
||||||
<h4>Local Admin Rights</h4>
|
emitter.emit('query', "MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:Group {name:{name}}) MATCH (m)-[r:MemberOf]->(n) RETURN m,r,n", {name: this.state.label, domain: domain});
|
||||||
<dt>
|
}.bind(this)}
|
||||||
First Degree Local Admin
|
/>
|
||||||
</dt>
|
</dd>
|
||||||
<dd>
|
<h4>Local Admin Rights</h4>
|
||||||
<NodeALink
|
<dt>
|
||||||
ready={this.state.directAdminTo !== -1}
|
First Degree Local Admin
|
||||||
value={this.state.directAdminTo}
|
</dt>
|
||||||
click={function(){
|
<dd>
|
||||||
emitter.emit('query', "MATCH p=(g:Group {name:{name}})-[r:AdminTo]->(c:Computer) RETURN p", {name: this.state.label},
|
<NodeALink
|
||||||
this.state.label)
|
ready={this.state.directAdminTo !== -1}
|
||||||
}.bind(this)} />
|
value={this.state.directAdminTo}
|
||||||
</dd>
|
click={function(){
|
||||||
<dt>
|
emitter.emit('query', "MATCH p=(g:Group {name:{name}})-[r:AdminTo]->(c:Computer) RETURN p", {name: this.state.label},
|
||||||
Group Delegated Local Admin Rights
|
this.state.label);
|
||||||
</dt>
|
}.bind(this)}
|
||||||
<dd>
|
/>
|
||||||
<NodeALink
|
</dd>
|
||||||
ready={this.state.groupDelegatedAdmin !== -1}
|
<dt>
|
||||||
value={this.state.groupDelegatedAdmin}
|
Group Delegated Local Admin Rights
|
||||||
click={function(){
|
</dt>
|
||||||
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name: this.state.label},
|
<dd>
|
||||||
this.state.label)
|
<NodeALink
|
||||||
}.bind(this)} />
|
ready={this.state.groupDelegatedAdmin !== -1}
|
||||||
</dd>
|
value={this.state.groupDelegatedAdmin}
|
||||||
<dt>
|
click={function(){
|
||||||
Derivative Local Admin Rights
|
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name: this.state.label},
|
||||||
</dt>
|
this.state.label);
|
||||||
<dd>
|
}.bind(this)}
|
||||||
<NodeALink
|
/>
|
||||||
ready={this.state.derivativeAdminTo !== -1}
|
</dd>
|
||||||
value={this.state.derivativeAdminTo}
|
<dt>
|
||||||
click={function(){
|
Derivative Local Admin Rights
|
||||||
emitter.emit('query', "MATCH p = shortestPath((g:Group {name:{name}})-[r:MemberOf|AdminTo|HasSession*1..]->(c:Computer)) RETURN p", {name: this.state.label},
|
</dt>
|
||||||
this.state.label)
|
<dd>
|
||||||
}.bind(this)} />
|
<NodeALink
|
||||||
</dd>
|
ready={this.state.derivativeAdminTo !== -1}
|
||||||
<br />
|
value={this.state.derivativeAdminTo}
|
||||||
<h4>Outbound Object Control</h4>
|
click={function(){
|
||||||
<dt>
|
emitter.emit('query', "MATCH (c:Computer) WHERE NOT c.name={name} WITH c MATCH p = shortestPath((g:Group {name:{name}})-[r:MemberOf|AdminTo|HasSession*1..]->(c)) RETURN p", {name: this.state.label},
|
||||||
First Degree Object Control
|
this.state.label);
|
||||||
</dt>
|
}.bind(this)}
|
||||||
<dd>
|
/>
|
||||||
<NodeALink
|
</dd>
|
||||||
ready={this.state.firstdegreeControl !== -1}
|
<h4>Outbound Object Control</h4>
|
||||||
value={this.state.firstdegreeControl}
|
<dt>
|
||||||
click={function(){
|
First Degree Object Control
|
||||||
emitter.emit('query', "MATCH p = (g:Group {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label})
|
</dt>
|
||||||
}.bind(this)} />
|
<dd>
|
||||||
</dd>
|
<NodeALink
|
||||||
<dt>
|
ready={this.state.firstdegreeControl !== -1}
|
||||||
Group Delegated Object Control
|
value={this.state.firstdegreeControl}
|
||||||
</dt>
|
click={function(){
|
||||||
<dd>
|
emitter.emit('query', "MATCH p = (g:Group {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label});
|
||||||
<NodeALink
|
}.bind(this)}
|
||||||
ready={this.state.groupDelegatedControl !== -1}
|
/>
|
||||||
value={this.state.groupDelegatedControl}
|
</dd>
|
||||||
click={function(){
|
<dt>
|
||||||
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label}
|
Group Delegated Object Control
|
||||||
,this.state.label)
|
</dt>
|
||||||
}.bind(this)} />
|
<dd>
|
||||||
</dd>
|
<NodeALink
|
||||||
<dt>
|
ready={this.state.groupDelegatedControl !== -1}
|
||||||
Transitive Object Control
|
value={this.state.groupDelegatedControl}
|
||||||
</dt>
|
click={function(){
|
||||||
<dd>
|
emitter.emit('query', "MATCH p = (g1:Group {name:{name}})-[r1:MemberOf*1..]->(g2:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label}
|
||||||
<NodeALink
|
,this.state.label);
|
||||||
ready={this.state.transitiveControl !== -1}
|
}.bind(this)}
|
||||||
value={this.state.transitiveControl}
|
/>
|
||||||
click={function(){
|
</dd>
|
||||||
emitter.emit('query', "MATCH p = shortestPath((g:Group {name:{name}})-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN p", {name:this.state.label}
|
<dt>
|
||||||
,this.state.label)
|
Transitive Object Control
|
||||||
}.bind(this)} />
|
</dt>
|
||||||
</dd>
|
<dd>
|
||||||
<br />
|
<NodeALink
|
||||||
<h4>Inbound Object Control</h4>
|
ready={this.state.transitiveControl !== -1}
|
||||||
<dt>
|
value={this.state.transitiveControl}
|
||||||
Explicit Object Controllers
|
click={function(){
|
||||||
</dt>
|
emitter.emit('query', "MATCH (n) WHERE NOT n.name={name} WITH n MATCH p = shortestPath((g:Group {name:{name}})-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN p", {name:this.state.label}
|
||||||
<dd>
|
,this.state.label);
|
||||||
<NodeALink
|
}.bind(this)}
|
||||||
ready={this.state.firstDegreeControllers !== -1}
|
/>
|
||||||
value={this.state.firstDegreeControllers}
|
</dd>
|
||||||
click={function(){
|
<h4>Inbound Object Control</h4>
|
||||||
emitter.emit('query', "MATCH p = (n)-[r:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g:Group {name: {name}}) RETURN p", {name:this.state.label}
|
<dt>
|
||||||
,this.state.label)
|
Explicit Object Controllers
|
||||||
}.bind(this)} />
|
</dt>
|
||||||
</dd>
|
<dd>
|
||||||
<dt>
|
<NodeALink
|
||||||
Unrolled Object Controllers
|
ready={this.state.firstDegreeControllers !== -1}
|
||||||
</dt>
|
value={this.state.firstDegreeControllers}
|
||||||
<dd>
|
click={function(){
|
||||||
<NodeALink
|
emitter.emit('query', "MATCH p = (n)-[r:AddMembers|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(g:Group {name: {name}}) RETURN p", {name:this.state.label}
|
||||||
ready={this.state.unrolledControllers !== -1}
|
,this.state.label);
|
||||||
value={this.state.unrolledControllers}
|
}.bind(this)}
|
||||||
click={function(){
|
/>
|
||||||
emitter.emit('query', "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 p", {name:this.state.label}
|
</dd>
|
||||||
,this.state.label)
|
<dt>
|
||||||
}.bind(this)} />
|
Unrolled Object Controllers
|
||||||
</dd>
|
</dt>
|
||||||
<dt>
|
<dd>
|
||||||
Transitive Object Controllers
|
<NodeALink
|
||||||
</dt>
|
ready={this.state.unrolledControllers !== -1}
|
||||||
<dd>
|
value={this.state.unrolledControllers}
|
||||||
<NodeALink
|
click={function(){
|
||||||
ready={this.state.transitiveControllers !== -1}
|
emitter.emit('query', "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 p", {name:this.state.label}
|
||||||
value={this.state.transitiveControllers}
|
,this.state.label);
|
||||||
click={function(){
|
}.bind(this)}
|
||||||
emitter.emit('query', "MATCH p = shortestPath((n)-[r:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(g:Group {name: {name}})) RETURN p", {name:this.state.label}
|
/>
|
||||||
,this.state.label)
|
</dd>
|
||||||
}.bind(this)} />
|
<dt>
|
||||||
</dd>
|
Transitive Object Controllers
|
||||||
</dl>
|
</dt>
|
||||||
</div>
|
<dd>
|
||||||
);
|
<NodeALink
|
||||||
}
|
ready={this.state.transitiveControllers !== -1}
|
||||||
|
value={this.state.transitiveControllers}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "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 p", {name:this.state.label}
|
||||||
|
,this.state.label);
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupNodeData.propTypes = {
|
GroupNodeData.propTypes = {
|
||||||
visible : React.PropTypes.bool.isRequired
|
visible : React.PropTypes.bool.isRequired
|
||||||
}
|
};
|
|
@ -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 [
|
||||||
|
<dt>{this.props.keyName}</dt>,
|
||||||
|
<dd>{obj.low}</dd>
|
||||||
|
];
|
||||||
|
}else if (this.isArray(obj)){
|
||||||
|
console.log(obj);
|
||||||
|
if (obj.length === 0){
|
||||||
|
return [
|
||||||
|
<dt>{this.props.keyName}</dt>,
|
||||||
|
<dd>None</dd>
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
var elements = [];
|
||||||
|
$.each(obj, function(index, prop){
|
||||||
|
elements.push(<dt></dt>);
|
||||||
|
elements.push(<dd>{prop}</dd>);
|
||||||
|
});
|
||||||
|
elements[0] = <dt>Service Principal Names</dt>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}else if (typeof obj === 'boolean'){
|
||||||
|
return [
|
||||||
|
<dt>{this.props.keyName}</dt>,
|
||||||
|
<dd>{this.props.keyValue.toString().toTitleCase()}</dd>
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
return [
|
||||||
|
<dt>{this.props.keyName}</dt>,
|
||||||
|
<dd>{this.props.keyValue.toString()}</dd>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,363 +1,432 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import NodeALink from './NodeALink'
|
import NodeALink from './NodeALink';
|
||||||
import PropTypes from 'prop-types'
|
import NodePropItem from './NodePropItem';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { If, Then, Else } from 'react-if';
|
||||||
|
|
||||||
export default class UserNodeData extends Component {
|
export default class UserNodeData extends Component {
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
label: "",
|
label: "",
|
||||||
samAccountName: "None",
|
firstDegreeGroupMembership: -1,
|
||||||
displayName: "None",
|
unrolledGroupMembership: -1,
|
||||||
pwdLastChanged: "None",
|
foreignGroupMembership: -1,
|
||||||
firstDegreeGroupMembership: -1,
|
firstDegreeLocalAdmin: -1,
|
||||||
unrolledGroupMembership: -1,
|
groupDelegatedLocalAdmin: -1,
|
||||||
foreignGroupMembership: -1,
|
derivativeLocalAdmin: -1,
|
||||||
firstDegreeLocalAdmin: -1,
|
sessions: -1,
|
||||||
groupDelegatedLocalAdmin: -1,
|
firstdegreeControllers: -1,
|
||||||
derivativeLocalAdmin: -1,
|
unrolledControllers: -1,
|
||||||
sessions: -1,
|
transitiveControllers: -1,
|
||||||
firstdegreeControllers: -1,
|
firstdegreeControl: -1,
|
||||||
unrolledControllers: -1,
|
unrolledControl: -1,
|
||||||
transitiveControllers: -1,
|
transitiveControl: -1,
|
||||||
firstdegreeControl: -1,
|
driversessions : [],
|
||||||
unrolledControl: -1,
|
propertyMap: {ServicePrincipalNames: []}
|
||||||
transitiveControl: -1,
|
};
|
||||||
driversessions : []
|
|
||||||
}
|
|
||||||
|
|
||||||
emitter.on('userNodeClicked', this.getNodeData.bind(this));
|
emitter.on('userNodeClicked', this.getNodeData.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodeData(payload){
|
getNodeData(payload){
|
||||||
$.each(this.state.driversessions,function(index, record){
|
$.each(this.state.driversessions,function(index, record){
|
||||||
record.close();
|
record.close();
|
||||||
})
|
});
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
label: payload,
|
label: payload,
|
||||||
samAccountName: "None",
|
firstDegreeGroupMembership: -1,
|
||||||
displayName: "None",
|
unrolledGroupMembership: -1,
|
||||||
pwdLastChanged: "None",
|
foreignGroupMembership: -1,
|
||||||
firstDegreeGroupMembership: -1,
|
firstDegreeLocalAdmin: -1,
|
||||||
unrolledGroupMembership: -1,
|
groupDelegatedLocalAdmin: -1,
|
||||||
foreignGroupMembership: -1,
|
derivativeLocalAdmin: -1,
|
||||||
firstDegreeLocalAdmin: -1,
|
sessions: -1,
|
||||||
groupDelegatedLocalAdmin: -1,
|
firstdegreeControllers: -1,
|
||||||
derivativeLocalAdmin: -1,
|
unrolledControllers: -1,
|
||||||
sessions: -1,
|
transitiveControllers: -1,
|
||||||
firstdegreeControllers: -1,
|
firstdegreeControl: -1,
|
||||||
unrolledControllers: -1,
|
unrolledControl: -1,
|
||||||
transitiveControllers: -1,
|
transitiveControl: -1,
|
||||||
firstdegreeControl: -1,
|
propertyMap: {ServicePrincipalNames: []}
|
||||||
unrolledControl: -1,
|
});
|
||||||
transitiveControl: -1
|
|
||||||
})
|
|
||||||
|
|
||||||
var domain = '@' + payload.split('@').last()
|
var domain = '@' + payload.split('@').last();
|
||||||
|
|
||||||
var s1 = driver.session()
|
var s1 = driver.session();
|
||||||
var s2 = driver.session()
|
var s2 = driver.session();
|
||||||
var s3 = driver.session()
|
var s3 = driver.session();
|
||||||
var s4 = driver.session()
|
var s4 = driver.session();
|
||||||
var s5 = driver.session()
|
var s5 = driver.session();
|
||||||
var s6 = driver.session()
|
var s6 = driver.session();
|
||||||
var s7 = driver.session()
|
var s7 = driver.session();
|
||||||
var s8 = driver.session()
|
var s8 = driver.session();
|
||||||
var s9 = driver.session()
|
var s9 = driver.session();
|
||||||
var s10 = driver.session()
|
var s10 = driver.session();
|
||||||
var s11 = driver.session()
|
var s11 = driver.session();
|
||||||
var s12 = driver.session()
|
var s12 = driver.session();
|
||||||
var s13 = 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})
|
var props = driver.session();
|
||||||
.then(function(result){
|
props.run("MATCH (n:User {name:{name}}) RETURN n", {name: payload})
|
||||||
this.setState({'foreignGroupMembership':result.records[0]._fields[0].low})
|
.then(function(result){
|
||||||
s1.close()
|
var properties = result.records[0]._fields[0].properties;
|
||||||
}.bind(this))
|
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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low})
|
this.setState({'foreignGroupMembership':result.records[0]._fields[0].low});
|
||||||
s2.close()
|
s1.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s3.run("MATCH p = (n:User {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload})
|
s2.run("MATCH (n:User {name:{name}}), (m:Group), p=(n)-[:MemberOf]->(m) RETURN count(m)", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeGroupMembership':result.records[0]._fields[0].low});
|
||||||
s3.close()
|
s2.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s4.run("MATCH p = (n:User {name:{name}})-[r:AdminTo]->(c:Computer) RETURN COUNT(DISTINCT(c))", {name:payload})
|
s3.run("MATCH p = (n:User {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN COUNT(DISTINCT(g))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low})
|
this.setState({'unrolledGroupMembership':result.records[0]._fields[0].low});
|
||||||
s4.close()
|
s3.close();
|
||||||
}.bind(this))
|
}.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})
|
s4.run("MATCH p = (n:User {name:{name}})-[r:AdminTo]->(c:Computer) RETURN COUNT(DISTINCT(c))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low})
|
this.setState({'firstDegreeLocalAdmin':result.records[0]._fields[0].low});
|
||||||
s5.close()
|
s4.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s6.run("MATCH p = shortestPath((n:User {name:{name}})-[r:HasSession|AdminTo|MemberOf*1..]->(c:Computer)) RETURN COUNT(c)", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low})
|
this.setState({'groupDelegatedLocalAdmin':result.records[0]._fields[0].low});
|
||||||
s6.close()
|
s5.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s7.run("MATCH p = (n:Computer)-[r:HasSession]->(m:User {name:{name}}) RETURN COUNT(DISTINCT(n))", {name:payload})
|
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){
|
.then(function(result){
|
||||||
this.setState({'sessions':result.records[0]._fields[0].low})
|
this.setState({'derivativeLocalAdmin':result.records[0]._fields[0].low});
|
||||||
s7.close()
|
s6.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
s8.run("MATCH p = (n)-[r:AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u1:User {name: {name}}) RETURN COUNT(DISTINCT(n))", {name:payload})
|
s7.run("MATCH p = (n:Computer)-[r:HasSession]->(m:User {name:{name}}) RETURN COUNT(DISTINCT(n))", {name:payload})
|
||||||
.then(function(result){
|
.then(function(result){
|
||||||
this.setState({'firstdegreeControllers':result.records[0]._fields[0].low})
|
this.setState({'sessions':result.records[0]._fields[0].low});
|
||||||
s8.close()
|
s7.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'unrolledControllers':result.records[0]._fields[0].low})
|
this.setState({'firstdegreeControllers':result.records[0]._fields[0].low});
|
||||||
s9.close()
|
s8.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'transitiveControllers':result.records[0]._fields[0].low})
|
this.setState({'unrolledControllers':result.records[0]._fields[0].low});
|
||||||
s10.close()
|
s9.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'firstdegreeControl':result.records[0]._fields[0].low})
|
this.setState({'transitiveControllers':result.records[0]._fields[0].low});
|
||||||
s11.close()
|
s10.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'unrolledControl':result.records[0]._fields[0].low})
|
this.setState({'firstdegreeControl':result.records[0]._fields[0].low});
|
||||||
s12.close()
|
s11.close();
|
||||||
}.bind(this))
|
}.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})
|
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){
|
.then(function(result){
|
||||||
this.setState({'transitiveControl':result.records[0]._fields[0].low})
|
this.setState({'unrolledControl':result.records[0]._fields[0].low});
|
||||||
s13.close()
|
s12.close();
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
|
|
||||||
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13]})
|
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));
|
||||||
|
|
||||||
render() {
|
this.setState({'driversessions': [s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,props]});
|
||||||
var domain = '@' + this.state.label.split('@').last()
|
}
|
||||||
return (
|
|
||||||
<div className={this.props.visible ? "" : "displaynone"}>
|
isArray(object){
|
||||||
<dl className='dl-horizontal'>
|
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 (
|
||||||
|
<div className={this.props.visible ? "" : "displaynone"}>
|
||||||
|
<dl className='dl-horizontal'>
|
||||||
<h4>
|
<h4>
|
||||||
Node Info
|
User Info
|
||||||
</h4>
|
</h4>
|
||||||
<dt>
|
<dt>
|
||||||
Name
|
Name
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{this.state.label}
|
{this.state.label}
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
SAMAccountName
|
Display Name
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{this.state.samAccountName}
|
{this.convertToDisplayProp("DisplayName")}
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
Display Name
|
Password Last Changed
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{this.state.displayName}
|
{this.convertToDisplayProp("PwdLastSet")}
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
Password Last Changed
|
Last Logon
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{this.state.pwdLastChanged}
|
{this.convertToDisplayProp("LastLogon")}
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
Sessions
|
Enabled
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<NodeALink
|
{this.convertToDisplayProp("Enabled")}
|
||||||
ready={this.state.sessions !== -1}
|
</dd>
|
||||||
value={this.state.sessions}
|
<dt>
|
||||||
click={function(){
|
Email
|
||||||
emitter.emit('query', "MATCH (n:Computer)-[r:HasSession]->(m:User {name:{name}}) RETURN n,r,m", {name:this.state.label}
|
</dt>
|
||||||
,this.state.label)
|
<dd>
|
||||||
}.bind(this)} />
|
{this.convertToDisplayProp("Email")}
|
||||||
</dd>
|
</dd>
|
||||||
<br />
|
<dt>
|
||||||
<h4>Group Membership</h4>
|
Service Principal Names
|
||||||
<dt>
|
</dt>
|
||||||
First Degree Group Memberships
|
{(() => {
|
||||||
</dt>
|
if (this.state.propertyMap.ServicePrincipalNames.length === 0){
|
||||||
<dd>
|
return <dd>None</dd>;
|
||||||
<NodeALink
|
}
|
||||||
ready={this.state.firstDegreeGroupMembership !== -1}
|
})()}
|
||||||
value={this.state.firstDegreeGroupMembership}
|
{Object.keys(this.state.propertyMap.ServicePrincipalNames).map(function(key){
|
||||||
click={function(){
|
var x = <dd key={key}>{this.state.propertyMap.ServicePrincipalNames[key]}</dd>;
|
||||||
emitter.emit(
|
return x;
|
||||||
'query',
|
}.bind(this))}
|
||||||
"MATCH p = (n:User {name:{name}})-[r:MemberOf]->(g:Group) RETURN p", {name:this.state.label}
|
<dt>
|
||||||
)
|
Sessions
|
||||||
}.bind(this)} />
|
</dt>
|
||||||
</dd>
|
<dd>
|
||||||
<dt>
|
<NodeALink
|
||||||
Unrolled Group Memberships
|
ready={this.state.sessions !== -1}
|
||||||
</dt>
|
value={this.state.sessions}
|
||||||
<dd>
|
click={function(){
|
||||||
<NodeALink
|
emitter.emit('query', "MATCH (n:Computer)-[r:HasSession]->(m:User {name:{name}}) RETURN n,r,m", {name:this.state.label}
|
||||||
ready={this.state.unrolledGroupMembership !== -1}
|
,this.state.label);
|
||||||
value={this.state.unrolledGroupMembership}
|
}.bind(this)}
|
||||||
click={function(){
|
/>
|
||||||
emitter.emit('query', "MATCH p = (n:User {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN p", {name:this.state.label},
|
</dd>
|
||||||
this.state.label)
|
|
||||||
}.bind(this)} />
|
<h4>Group Membership</h4>
|
||||||
</dd>
|
<dt>
|
||||||
<dt>
|
First Degree Group Memberships
|
||||||
Foreign Group Membership
|
</dt>
|
||||||
</dt>
|
<dd>
|
||||||
<dd>
|
<NodeALink
|
||||||
<NodeALink
|
ready={this.state.firstDegreeGroupMembership !== -1}
|
||||||
ready={this.state.foreignGroupMembership !== -1}
|
value={this.state.firstDegreeGroupMembership}
|
||||||
value={this.state.foreignGroupMembership}
|
click={function(){
|
||||||
click={function(){
|
emitter.emit(
|
||||||
emitter.emit('query',
|
'query',
|
||||||
"MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:User {name:{name}}) WITH n,m MATCH p = (m)-[r:MemberOf*1..]->(n) RETURN p", {name: this.state.label, domain: domain})
|
"MATCH p = (n:User {name:{name}})-[r:MemberOf]->(g:Group) RETURN p", {name:this.state.label}
|
||||||
}.bind(this)} />
|
);
|
||||||
</dd>
|
}.bind(this)}
|
||||||
<br />
|
/>
|
||||||
<h4>
|
</dd>
|
||||||
Local Admin Rights
|
<dt>
|
||||||
</h4>
|
Unrolled Group Memberships
|
||||||
<dt>
|
</dt>
|
||||||
First Degree Local Admin
|
<dd>
|
||||||
</dt>
|
<NodeALink
|
||||||
<dd>
|
ready={this.state.unrolledGroupMembership !== -1}
|
||||||
<NodeALink
|
value={this.state.unrolledGroupMembership}
|
||||||
ready={this.state.firstDegreeLocalAdmin !== -1}
|
click={function(){
|
||||||
value={this.state.firstDegreeLocalAdmin}
|
emitter.emit('query', "MATCH p = (n:User {name:{name}})-[r:MemberOf*1..]->(g:Group) RETURN p", {name:this.state.label},
|
||||||
click={function(){
|
this.state.label);
|
||||||
emitter.emit('query', "MATCH p = (n:User {name:{name}})-[r:AdminTo]->(c:Computer) RETURN p", {name:this.state.label})
|
}.bind(this)}
|
||||||
}.bind(this)} />
|
/>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
Group Delegated Local Admin Rights
|
Foreign Group Membership
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<NodeALink
|
<NodeALink
|
||||||
ready={this.state.groupDelegatedLocalAdmin !== -1}
|
ready={this.state.foreignGroupMembership !== -1}
|
||||||
value={this.state.groupDelegatedLocalAdmin}
|
value={this.state.foreignGroupMembership}
|
||||||
click={function(){
|
click={function(){
|
||||||
emitter.emit('query', "MATCH p=(n:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name:this.state.label}
|
emitter.emit('query',
|
||||||
,this.state.label)
|
"MATCH (n:Group) WHERE NOT n.name ENDS WITH {domain} WITH n MATCH (m:User {name:{name}}) WITH n,m MATCH p = (m)-[r:MemberOf*1..]->(n) RETURN p", {name: this.state.label, domain: domain});
|
||||||
}.bind(this)} />
|
}.bind(this)}
|
||||||
</dd>
|
/>
|
||||||
<dt>
|
</dd>
|
||||||
Derivative Local Admin Rights
|
|
||||||
</dt>
|
<h4>
|
||||||
<dd>
|
Local Admin Rights
|
||||||
<NodeALink
|
</h4>
|
||||||
ready={this.state.derivativeLocalAdmin !== -1}
|
<dt>
|
||||||
value={this.state.derivativeLocalAdmin}
|
First Degree Local Admin
|
||||||
click={function(){
|
</dt>
|
||||||
emitter.emit('query', "MATCH p = shortestPath((n:User {name:{name}})-[r:HasSession|AdminTo|MemberOf*1..]->(c:Computer)) RETURN p", {name:this.state.label}
|
<dd>
|
||||||
,this.state.label)
|
<NodeALink
|
||||||
}.bind(this)} />
|
ready={this.state.firstDegreeLocalAdmin !== -1}
|
||||||
</dd>
|
value={this.state.firstDegreeLocalAdmin}
|
||||||
<br />
|
click={function(){
|
||||||
<h4>
|
emitter.emit('query', "MATCH p = (n:User {name:{name}})-[r:AdminTo]->(c:Computer) RETURN p", {name:this.state.label});
|
||||||
Outbound Object Control
|
}.bind(this)}
|
||||||
</h4>
|
/>
|
||||||
<dt>
|
</dd>
|
||||||
First Degree Object Control
|
<dt>
|
||||||
</dt>
|
Group Delegated Local Admin Rights
|
||||||
<dd>
|
</dt>
|
||||||
<NodeALink
|
<dd>
|
||||||
ready={this.state.firstdegreeControl !== -1}
|
<NodeALink
|
||||||
value={this.state.firstdegreeControl}
|
ready={this.state.groupDelegatedLocalAdmin !== -1}
|
||||||
click={function(){
|
value={this.state.groupDelegatedLocalAdmin}
|
||||||
emitter.emit('query', "MATCH p = (u:User {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label})
|
click={function(){
|
||||||
}.bind(this)} />
|
emitter.emit('query', "MATCH p=(n:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c:Computer) RETURN p", {name:this.state.label}
|
||||||
</dd>
|
,this.state.label);
|
||||||
<dt>
|
}.bind(this)}
|
||||||
Group Delegated Object Control
|
/>
|
||||||
</dt>
|
</dd>
|
||||||
<dd>
|
<dt>
|
||||||
<NodeALink
|
Derivative Local Admin Rights
|
||||||
ready={this.state.unrolledControl !== -1}
|
</dt>
|
||||||
value={this.state.unrolledControl}
|
<dd>
|
||||||
click={function(){
|
<NodeALink
|
||||||
emitter.emit('query', "MATCH p = (u:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label}
|
ready={this.state.derivativeLocalAdmin !== -1}
|
||||||
,this.state.label)
|
value={this.state.derivativeLocalAdmin}
|
||||||
}.bind(this)} />
|
click={function(){
|
||||||
</dd>
|
emitter.emit('query', "MATCH (c:Computer) WHERE NOT c.name={name} WITH c MATCH p = shortestPath((n:User {name:{name}})-[r:HasSession|AdminTo|MemberOf*1..]->(c)) RETURN p", {name:this.state.label}
|
||||||
<dt>
|
,this.state.label);
|
||||||
Transitive Object Control
|
}.bind(this)}
|
||||||
</dt>
|
/>
|
||||||
<dd>
|
</dd>
|
||||||
<NodeALink
|
|
||||||
ready={this.state.transitiveControl !== -1}
|
<h4>
|
||||||
value={this.state.transitiveControl}
|
Outbound Object Control
|
||||||
click={function(){
|
</h4>
|
||||||
emitter.emit('query', "MATCH p = shortestPath((u:User {name:{name}})-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) RETURN p", {name:this.state.label}
|
<dt>
|
||||||
,this.state.label)
|
First Degree Object Control
|
||||||
}.bind(this)} />
|
</dt>
|
||||||
</dd>
|
<dd>
|
||||||
<br />
|
<NodeALink
|
||||||
<h4>Inbound Object Control</h4>
|
ready={this.state.firstdegreeControl !== -1}
|
||||||
<dt>
|
value={this.state.firstdegreeControl}
|
||||||
Explicit Object Controllers
|
click={function(){
|
||||||
</dt>
|
emitter.emit('query', "MATCH p = (u:User {name:{name}})-[r1:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label});
|
||||||
<dd>
|
}.bind(this)}
|
||||||
<NodeALink
|
/>
|
||||||
ready={this.state.firstdegreeControllers !== -1}
|
</dd>
|
||||||
value={this.state.firstdegreeControllers}
|
<dt>
|
||||||
click={function(){
|
Group Delegated Object Control
|
||||||
emitter.emit('query', "MATCH p = (n)-[r:AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u1:User {name: {name}}) RETURN p", {name:this.state.label}
|
</dt>
|
||||||
,this.state.label)
|
<dd>
|
||||||
}.bind(this)} />
|
<NodeALink
|
||||||
</dd>
|
ready={this.state.unrolledControl !== -1}
|
||||||
<dt>
|
value={this.state.unrolledControl}
|
||||||
Unrolled Object Controllers
|
click={function(){
|
||||||
</dt>
|
emitter.emit('query', "MATCH p = (u:User {name:{name}})-[r1:MemberOf*1..]->(g:Group)-[r2:AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(n) RETURN p", {name:this.state.label}
|
||||||
<dd>
|
,this.state.label);
|
||||||
<NodeALink
|
}.bind(this)}
|
||||||
ready={this.state.unrolledControllers !== -1}
|
/>
|
||||||
value={this.state.unrolledControllers}
|
</dd>
|
||||||
click={function(){
|
<dt>
|
||||||
emitter.emit('query', "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 p", {name:this.state.label}
|
Transitive Object Control
|
||||||
,this.state.label)
|
</dt>
|
||||||
}.bind(this)} />
|
<dd>
|
||||||
</dd>
|
<NodeALink
|
||||||
<dt>
|
ready={this.state.transitiveControl !== -1}
|
||||||
Transitive Object Controllers
|
value={this.state.transitiveControl}
|
||||||
</dt>
|
click={function(){
|
||||||
<dd>
|
emitter.emit('query', "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 p", {name:this.state.label}
|
||||||
<NodeALink
|
,this.state.label);
|
||||||
ready={this.state.transitiveControllers !== -1}
|
}.bind(this)}
|
||||||
value={this.state.transitiveControllers}
|
/>
|
||||||
click={function(){
|
</dd>
|
||||||
emitter.emit('query', "MATCH p = shortestPath((n1)-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(u1:User {name: {name}})) RETURN p", {name:this.state.label}
|
|
||||||
,this.state.label)
|
<h4>Inbound Object Control</h4>
|
||||||
}.bind(this)} />
|
<dt>
|
||||||
</dd>
|
Explicit Object Controllers
|
||||||
</dl>
|
</dt>
|
||||||
</div>
|
<dd>
|
||||||
);
|
<NodeALink
|
||||||
}
|
ready={this.state.firstdegreeControllers !== -1}
|
||||||
|
value={this.state.firstdegreeControllers}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "MATCH p = (n)-[r:AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner]->(u1:User {name: {name}}) RETURN p", {name:this.state.label}
|
||||||
|
,this.state.label);
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
Unrolled Object Controllers
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<NodeALink
|
||||||
|
ready={this.state.unrolledControllers !== -1}
|
||||||
|
value={this.state.unrolledControllers}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "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 p", {name:this.state.label}
|
||||||
|
,this.state.label);
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
Transitive Object Controllers
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<NodeALink
|
||||||
|
ready={this.state.transitiveControllers !== -1}
|
||||||
|
value={this.state.transitiveControllers}
|
||||||
|
click={function(){
|
||||||
|
emitter.emit('query', "MATCH (n1) WHERE NOT n1.name={name} WITH n1 MATCH p = shortestPath((n1)-[r1:MemberOf|AddMembers|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(u1:User {name: {name}})) RETURN p", {name:this.state.label}
|
||||||
|
,this.state.label);
|
||||||
|
}.bind(this)}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UserNodeData.propTypes = {
|
UserNodeData.propTypes = {
|
||||||
visible : React.PropTypes.bool.isRequired
|
visible : PropTypes.bool.isRequired
|
||||||
}
|
};
|
|
@ -4,6 +4,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.max{
|
.max{
|
||||||
|
@ -94,6 +95,13 @@ div.tooltip-inner-custom {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: lightgray;
|
background-color: lightgray;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item > i{
|
||||||
|
float:right;
|
||||||
|
margin-top:3px;
|
||||||
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph:focus {
|
.graph:focus {
|
||||||
|
@ -187,6 +195,12 @@ div.tooltip-inner-custom {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dl-horizontal > h4 {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
.dl-horizontal{
|
.dl-horizontal{
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
@ -763,7 +777,6 @@ div.tooltip-inner-custom {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-content > div:nth-last-child(2) > div{
|
.tab-content > div:nth-last-child(2) > div{
|
||||||
height: 600px;
|
max-height: 600px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
resize: vertical;
|
|
||||||
}
|
}
|
|
@ -106,10 +106,11 @@ global.appStore = {
|
||||||
'ForceChangePassword': 'tapered',
|
'ForceChangePassword': 'tapered',
|
||||||
'GenericAll': 'tapered',
|
'GenericAll': 'tapered',
|
||||||
'GenericWrite': 'tapered',
|
'GenericWrite': 'tapered',
|
||||||
'WriteDACL': 'tapered',
|
'WriteDacl': 'tapered',
|
||||||
'WriteOwner': 'tapered',
|
'WriteOwner': 'tapered',
|
||||||
'AddMembers': 'tapered',
|
'AddMembers': 'tapered',
|
||||||
'TrustedBy': 'curvedArrow'
|
'TrustedBy': 'curvedArrow',
|
||||||
|
'DCSync' : 'tapered'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
lowResPalette: {
|
lowResPalette: {
|
||||||
|
|
File diff suppressed because one or more lines are too long
193
src/js/utils.js
193
src/js/utils.js
|
@ -10,32 +10,32 @@ export function generateUniqueId(sigmaInstance, isNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Recursive function to highlight paths to start/end nodes
|
//Recursive function to highlight paths to start/end nodes
|
||||||
export function findGraphPath(sigmaInstance, reverse, nodeid) {
|
export function findGraphPath(sigmaInstance, reverse, nodeid) {
|
||||||
var target = reverse ? appStore.startNode : appStore.endNode
|
var target = reverse ? appStore.startNode : appStore.endNode;
|
||||||
//This is our stop condition for recursing
|
//This is our stop condition for recursing
|
||||||
if (nodeid !== target.id) {
|
if (nodeid !== target.id) {
|
||||||
var edges = sigmaInstance.graph.adjacentEdges(nodeid)
|
var edges = sigmaInstance.graph.adjacentEdges(nodeid);
|
||||||
var nodes = reverse ? sigmaInstance.graph.inboundNodes(nodeid) : sigmaInstance.graph.outboundNodes(nodeid)
|
var nodes = reverse ? sigmaInstance.graph.inboundNodes(nodeid) : sigmaInstance.graph.outboundNodes(nodeid);
|
||||||
//Loop over the nodes near us and the edges connecting to those nodes
|
//Loop over the nodes near us and the edges connecting to those nodes
|
||||||
$.each(nodes, function(index, node) {
|
$.each(nodes, function(index, node) {
|
||||||
$.each(edges, function(index, edge) {
|
$.each(edges, function(index, edge) {
|
||||||
var check = reverse ? edge.source : edge.target
|
var check = reverse ? edge.source : edge.target;
|
||||||
//If an edge is pointing in the right direction, set its color
|
//If an edge is pointing in the right direction, set its color
|
||||||
//Push the edge into our store and then
|
//Push the edge into our store and then
|
||||||
node = parseInt(node)
|
node = parseInt(node);
|
||||||
if (check === node) {
|
if (check === node) {
|
||||||
edge.color = reverse ? 'blue' : 'red';
|
edge.color = reverse ? 'blue' : 'red';
|
||||||
appStore.highlightedEdges.push(edge);
|
appStore.highlightedEdges.push(edge);
|
||||||
findGraphPath(sigmaInstance, reverse, node);
|
findGraphPath(sigmaInstance, reverse, node);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,192 +45,211 @@ export function clearSessions(){
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteSessions(){
|
function deleteSessions(){
|
||||||
var session = driver.session()
|
var session = driver.session();
|
||||||
session.run("MATCH ()-[r:HasSession]-() WITH r LIMIT 100000 DELETE r RETURN count(r)")
|
session.run("MATCH ()-[r:HasSession]-() WITH r LIMIT 100000 DELETE r RETURN count(r)")
|
||||||
.then(function(results) {
|
.then(function(results) {
|
||||||
session.close()
|
session.close();
|
||||||
emitter.emit("refreshDBData")
|
emitter.emit("refreshDBData");
|
||||||
var count = results.records[0]._fields[0].low
|
var count = results.records[0]._fields[0].low;
|
||||||
if (count === 0) {
|
if (count === 0) {
|
||||||
emitter.emit('hideDBClearModal')
|
emitter.emit('hideDBClearModal');
|
||||||
} else {
|
} else {
|
||||||
deleteSessions();
|
deleteSessions();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearDatabase() {
|
export function clearDatabase() {
|
||||||
emitter.emit('openClearingModal');
|
emitter.emit('openClearingModal');
|
||||||
deleteEdges()
|
deleteEdges();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteEdges() {
|
function deleteEdges() {
|
||||||
var session = driver.session()
|
var session = driver.session();
|
||||||
session.run("MATCH ()-[r]-() WITH r LIMIT 100000 DELETE r RETURN count(r)")
|
session.run("MATCH ()-[r]-() WITH r LIMIT 100000 DELETE r RETURN count(r)")
|
||||||
.then(function(results) {
|
.then(function(results) {
|
||||||
emitter.emit("refreshDBData");
|
emitter.emit("refreshDBData");
|
||||||
session.close()
|
session.close();
|
||||||
var count = results.records[0]._fields[0].low
|
var count = results.records[0]._fields[0].low;
|
||||||
if (count === 0) {
|
if (count === 0) {
|
||||||
deleteNodes()
|
deleteNodes();
|
||||||
} else {
|
} else {
|
||||||
deleteEdges()
|
deleteEdges();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteNodes() {
|
function deleteNodes() {
|
||||||
var session = driver.session()
|
var session = driver.session();
|
||||||
session.run("MATCH (n) WITH n LIMIT 100000 DELETE n RETURN count(n)")
|
session.run("MATCH (n) WITH n LIMIT 100000 DELETE n RETURN count(n)")
|
||||||
.then(function(results) {
|
.then(function(results) {
|
||||||
emitter.emit("refreshDBData")
|
emitter.emit("refreshDBData");
|
||||||
session.close()
|
session.close();
|
||||||
var count = results.records[0]._fields[0].low
|
var count = results.records[0]._fields[0].low;
|
||||||
if (count === 0) {
|
if (count === 0) {
|
||||||
emitter.emit('hideDBClearModal')
|
emitter.emit('hideDBClearModal');
|
||||||
} else {
|
} else {
|
||||||
deleteNodes()
|
deleteNodes();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findObjectType(header){
|
||||||
|
if (header.includes('UserName') && header.includes('ComputerName') && header.includes('Weight')){
|
||||||
|
return 'sessions';
|
||||||
|
}else if (header.includes('AccountName') && header.includes('AccountType') && header.includes('GroupName')){
|
||||||
|
return 'groupmembership';
|
||||||
|
}else if (header.includes('AccountName') && header.includes('AccountType') && header.includes('ComputerName')){
|
||||||
|
return 'localadmin';
|
||||||
|
}else if (header.includes('SourceDomain') && header.includes('TargetDomain') && header.includes('TrustDirection') && header.includes('TrustType') && header.includes('Transitive')){
|
||||||
|
return 'domain';
|
||||||
|
}else if (header.includes('ActiveDirectoryRights') && header.includes('ObjectType') && header.includes('PrincipalType') && header.includes('PrincipalName') && header.includes('ObjectName') && header.includes('ACEType') && header.includes('AccessControlType') && header.includes('IsInherited')){
|
||||||
|
return 'acl';
|
||||||
|
}else if (header.includes('AccountName') && header.includes('Enabled') && header.includes('PwdLastSet') && header.includes('LastLogon') && header.includes('Sid') && header.includes('SidHistory') && header.includes('HasSPN') && header.includes('ServicePrincipalNames')){
|
||||||
|
return 'userprops';
|
||||||
|
}else if (header.includes('AccountName') && header.includes('Enabled') && header.includes('PwdLastSet') && header.includes('LastLogon') && header.includes('OperatingSystem') && header.includes('Sid')){
|
||||||
|
return 'compprops';
|
||||||
|
}else{
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildGroupMembershipProps(rows) {
|
export function buildGroupMembershipProps(rows) {
|
||||||
var users = []
|
var users = [];
|
||||||
var groups = []
|
var groups = [];
|
||||||
var computers = []
|
var computers = [];
|
||||||
$.each(rows, function(index, row) {
|
$.each(rows, function(index, row) {
|
||||||
switch (row.AccountType) {
|
switch (row.AccountType) {
|
||||||
case 'user':
|
case 'user':
|
||||||
users.push({ account: row.AccountName.toUpperCase(), group: row.GroupName.toUpperCase() })
|
users.push({ account: row.AccountName.toUpperCase(), group: row.GroupName.toUpperCase() });
|
||||||
break
|
break;
|
||||||
case 'computer':
|
case 'computer':
|
||||||
computers.push({ account: row.AccountName.toUpperCase(), group: row.GroupName.toUpperCase() })
|
computers.push({ account: row.AccountName.toUpperCase(), group: row.GroupName.toUpperCase() });
|
||||||
break
|
break;
|
||||||
case 'group':
|
case 'group':
|
||||||
groups.push({ account: row.AccountName.toUpperCase(), group: row.GroupName.toUpperCase() })
|
groups.push({ account: row.AccountName.toUpperCase(), group: row.GroupName.toUpperCase() });
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return { users: users, groups: groups, computers: computers }
|
return { users: users, groups: groups, computers: computers };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildLocalAdminProps(rows) {
|
export function buildLocalAdminProps(rows) {
|
||||||
var users = []
|
var users = [];
|
||||||
var groups = []
|
var groups = [];
|
||||||
var computers = []
|
var computers = [];
|
||||||
$.each(rows, function(index, row) {
|
$.each(rows, function(index, row) {
|
||||||
if (row.AccountName.startsWith('@')) {
|
if (row.AccountName.startsWith('@')) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
switch (row.AccountType) {
|
switch (row.AccountType) {
|
||||||
case 'user':
|
case 'user':
|
||||||
users.push({ account: row.AccountName.toUpperCase(), computer: row.ComputerName.toUpperCase() })
|
users.push({ account: row.AccountName.toUpperCase(), computer: row.ComputerName.toUpperCase() });
|
||||||
break;
|
break;
|
||||||
case 'group':
|
case 'group':
|
||||||
groups.push({ account: row.AccountName.toUpperCase(), computer: row.ComputerName.toUpperCase() })
|
groups.push({ account: row.AccountName.toUpperCase(), computer: row.ComputerName.toUpperCase() });
|
||||||
break;
|
break;
|
||||||
case 'computer':
|
case 'computer':
|
||||||
computers.push({ account: row.AccountName.toUpperCase(), computer: row.ComputerName.toUpperCase() })
|
computers.push({ account: row.AccountName.toUpperCase(), computer: row.ComputerName.toUpperCase() });
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return { users: users, groups: groups, computers: computers }
|
return { users: users, groups: groups, computers: computers };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildSessionProps(rows) {
|
export function buildSessionProps(rows) {
|
||||||
var sessions = []
|
var sessions = [];
|
||||||
$.each(rows, function(index, row) {
|
$.each(rows, function(index, row) {
|
||||||
if (row.UserName === 'ANONYMOUS LOGON@UNKNOWN' || row.UserName === '') {
|
if (row.UserName === 'ANONYMOUS LOGON@UNKNOWN' || row.UserName === '') {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
sessions.push({ account: row.UserName.toUpperCase(), computer: row.ComputerName.toUpperCase(), weight: row.Weight })
|
sessions.push({ account: row.UserName.toUpperCase(), computer: row.ComputerName.toUpperCase(), weight: row.Weight });
|
||||||
})
|
});
|
||||||
|
|
||||||
return sessions
|
return sessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildDomainProps(rows) {
|
export function buildDomainProps(rows) {
|
||||||
var domains = []
|
var domains = [];
|
||||||
$.each(rows, function(index, row) {
|
$.each(rows, function(index, row) {
|
||||||
switch (row.TrustDirection) {
|
switch (row.TrustDirection) {
|
||||||
case 'Inbound':
|
case 'Inbound':
|
||||||
domains.push({ domain1: row.TargetDomain.toUpperCase(), domain2: row.SourceDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive })
|
domains.push({ domain1: row.TargetDomain.toUpperCase(), domain2: row.SourceDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive });
|
||||||
break;
|
break;
|
||||||
case 'Outbound':
|
case 'Outbound':
|
||||||
domains.push({ domain1: row.SourceDomain.toUpperCase(), domain2: row.TargetDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive })
|
domains.push({ domain1: row.SourceDomain.toUpperCase(), domain2: row.TargetDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive });
|
||||||
break;
|
break;
|
||||||
case 'Bidirectional':
|
case 'Bidirectional':
|
||||||
domains.push({ domain1: row.TargetDomain.toUpperCase(), domain2: row.SourceDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive })
|
domains.push({ domain1: row.TargetDomain.toUpperCase(), domain2: row.SourceDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive });
|
||||||
domains.push({ domain1: row.SourceDomain.toUpperCase(), domain2: row.TargetDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive })
|
domains.push({ domain1: row.SourceDomain.toUpperCase(), domain2: row.TargetDomain.toUpperCase(), trusttype: row.TrustType, transitive: row.Transitive });
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return domains
|
return domains;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildACLProps(rows) {
|
export function buildACLProps(rows) {
|
||||||
var datadict = {}
|
var datadict = {};
|
||||||
|
|
||||||
$.each(rows, function(index, row) {
|
$.each(rows, function(index, row) {
|
||||||
var b = row.ObjectName.toUpperCase()
|
var b = row.ObjectName.toUpperCase();
|
||||||
var a = row.PrincipalName.toUpperCase()
|
var a = row.PrincipalName.toUpperCase();
|
||||||
var btype = row.ObjectType.toTitleCase()
|
var btype = row.ObjectType.toTitleCase();
|
||||||
var atype = row.PrincipalType.toTitleCase()
|
var atype = row.PrincipalType.toTitleCase();
|
||||||
var rel = row.ActiveDirectoryRights
|
var rel = row.ActiveDirectoryRights;
|
||||||
var extright = row.ACEType
|
var extright = row.ACEType;
|
||||||
|
|
||||||
var rights = []
|
var rights = [];
|
||||||
|
|
||||||
if (extright === 'All'){
|
if (extright === 'All'){
|
||||||
rights.push("AllExtendedRights")
|
rights.push("AllExtendedRights");
|
||||||
}else if (extright === 'User-Force-Change-Password'){
|
}else if (extright === 'User-Force-Change-Password'){
|
||||||
rights.push("ForceChangePassword")
|
rights.push("ForceChangePassword");
|
||||||
}else if (rel === "ExtendedRight"){
|
}else if (rel === "ExtendedRight"){
|
||||||
rights.push(extright)
|
rights.push(extright);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rel.includes("GenericAll")){
|
if (rel.includes("GenericAll")){
|
||||||
rights.push("GenericAll")
|
rights.push("GenericAll");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rel.includes("WriteDacl")){
|
if (rel.includes("WriteDacl")){
|
||||||
rights.push("WriteDacl")
|
rights.push("WriteDacl");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rel.includes("WriteOwner")){
|
if (rel.includes("WriteOwner")){
|
||||||
rights.push("WriteOwner")
|
rights.push("WriteOwner");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rel.includes("GenericWrite")){
|
if (rel.includes("GenericWrite")){
|
||||||
rights.push("GenericWrite")
|
rights.push("GenericWrite");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rel.includes("WriteProperty") && extright === "Member"){
|
if (rel.includes("WriteProperty") && extright === "Member"){
|
||||||
rights.push("AddMember")
|
rights.push("AddMember");
|
||||||
}
|
}
|
||||||
|
|
||||||
$.each(rights, function(index, record){
|
$.each(rights, function(index, record){
|
||||||
var hash = (atype + record + btype).toUpperCase()
|
var hash = (atype + record + btype).toUpperCase();
|
||||||
if (btype === 'Computer') {
|
if (btype === 'Computer') {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datadict[hash]) {
|
if (datadict[hash]) {
|
||||||
datadict[hash].props.push({
|
datadict[hash].props.push({
|
||||||
account: a,
|
account: a,
|
||||||
principal: b
|
principal: b
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
datadict[hash] = {
|
datadict[hash] = {
|
||||||
statement: 'UNWIND {props} AS prop MERGE (a:{} {name:prop.account}) WITH a,prop MERGE (b:{} {name: prop.principal}) WITH a,b,prop MERGE (a)-[r:{} {isACL:true}]->(b)'.format(atype, btype, record),
|
statement: 'UNWIND {props} AS prop MERGE (a:{} {name:prop.account}) WITH a,prop MERGE (b:{} {name: prop.principal}) WITH a,b,prop MERGE (a)-[r:{} {isACL:true}]->(b)'.format(atype, btype, record),
|
||||||
props: [{ account: a, principal: b }]
|
props: [{ account: a, principal: b }]
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
});
|
||||||
|
|
||||||
})
|
return datadict;
|
||||||
|
|
||||||
return datadict
|
|
||||||
}
|
}
|
308
src/js/worker.js
308
src/js/worker.js
|
@ -1,5 +1,5 @@
|
||||||
global.sigma = require('linkurious')
|
global.sigma = require('linkurious');
|
||||||
require('./sigma.helpers.graph.min.js')
|
require('./sigma.helpers.graph.min.js');
|
||||||
Array.prototype.allEdgesSameType = function() {
|
Array.prototype.allEdgesSameType = function() {
|
||||||
|
|
||||||
for (var i = 1; i < this.length; i++) {
|
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();
|
return this.inNeighborsIndex.get(id).keyList();
|
||||||
});
|
});
|
||||||
|
|
||||||
var sigmaInstance = new sigma()
|
var sigmaInstance = new sigma();
|
||||||
|
|
||||||
|
|
||||||
process.on('message', function(m){
|
process.on('message', function(m){
|
||||||
var data = JSON.parse(m)
|
var data = JSON.parse(m);
|
||||||
params = {edge: data.edge,sibling: data.sibling, start: data.start, end: data.end}
|
params = {edge: data.edge,sibling: data.sibling, start: data.start, end: data.end};
|
||||||
var spotlightData = {}
|
var spotlightData = {};
|
||||||
sigmaInstance.graph.clear()
|
sigmaInstance.graph.clear();
|
||||||
sigmaInstance.graph.read(data.graph)
|
sigmaInstance.graph.read(data.graph);
|
||||||
sigmaInstance.graph.nodes().forEach(function(node){
|
sigmaInstance.graph.nodes().forEach(function(node){
|
||||||
node.degree = sigmaInstance.graph.degree(node.id)
|
node.degree = sigmaInstance.graph.degree(node.id);
|
||||||
})
|
});
|
||||||
var result = collapseEdgeNodes(sigmaInstance, params, spotlightData)
|
var result = collapseEdgeNodes(sigmaInstance, params, spotlightData);
|
||||||
sigmaInstance = result[0]
|
sigmaInstance = result[0];
|
||||||
spotlightData = result[1]
|
spotlightData = result[1];
|
||||||
result = collapseSiblingNodes(sigmaInstance, params, spotlightData)
|
result = collapseSiblingNodes(sigmaInstance, params, spotlightData);
|
||||||
sigmaInstance = result[0]
|
sigmaInstance = result[0];
|
||||||
spotlightData = result[1]
|
spotlightData = result[1];
|
||||||
sigmaInstance.graph.nodes().forEach(function(node) {
|
sigmaInstance.graph.nodes().forEach(function(node) {
|
||||||
if (!spotlightData.hasOwnProperty(node.id)) {
|
if (!spotlightData.hasOwnProperty(node.id)) {
|
||||||
spotlightData[node.id] = [node.label, 0, "", node.type, ""];
|
spotlightData[node.id] = [node.label, 0, "", node.type, ""];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var toSend = {nodes: sigmaInstance.graph.nodes(), edges: sigmaInstance.graph.edges(), spotlight: spotlightData}
|
var toSend = {nodes: sigmaInstance.graph.nodes(), edges: sigmaInstance.graph.edges(), spotlight: spotlightData};
|
||||||
process.send(toSend)
|
process.send(toSend);
|
||||||
})
|
});
|
||||||
|
|
||||||
function collapseEdgeNodes(sigmaInstance, params, spotlightData){
|
function collapseEdgeNodes(sigmaInstance, params, spotlightData){
|
||||||
var threshold = params.edge;
|
var threshold = params.edge;
|
||||||
|
|
||||||
if (threshold == 0){
|
if (threshold == 0){
|
||||||
return [sigmaInstance, spotlightData]
|
return [sigmaInstance, spotlightData];
|
||||||
}
|
}
|
||||||
sigmaInstance.graph.nodes().forEach(function(node){
|
sigmaInstance.graph.nodes().forEach(function(node){
|
||||||
if (node.degree < threshold){
|
if (node.degree < threshold){
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sigmaInstance.graph.adjacentNodes(node.id).forEach(function(anode){
|
sigmaInstance.graph.adjacentNodes(node.id).forEach(function(anode){
|
||||||
if (params.end !== null && anode.label === params.end){
|
if (params.end !== null && anode.label === params.end){
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.start !== null && anode.label === params.start){
|
if (params.start !== null && anode.label === params.start){
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var edges = sigmaInstance.graph.adjacentEdges(anode.id);
|
var edges = sigmaInstance.graph.adjacentEdges(anode.id);
|
||||||
if ((edges.length > 1 || edges.length === 0) || (anode.folded.nodes.length > 0)){
|
if ((edges.length > 1 || edges.length === 0) || (anode.folded.nodes.length > 0)){
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var edge = edges[0];
|
var edge = edges[0];
|
||||||
|
|
||||||
if ((anode.type_user)
|
if ((anode.type_user)
|
||||||
|| (anode.type_computer)
|
|| (anode.type_computer)
|
||||||
|| (anode.type_group && edge.label === 'AdminTo')){
|
|| (anode.type_group && edge.label === 'AdminTo')){
|
||||||
|
|
||||||
node.isGrouped = true
|
node.isGrouped = true;
|
||||||
node.folded.nodes.push(anode)
|
node.folded.nodes.push(anode);
|
||||||
node.folded.edges.push(edge)
|
node.folded.edges.push(edge);
|
||||||
spotlightData[anode.id] = [anode.label, node.id, node.label, anode.type, node.type];
|
spotlightData[anode.id] = [anode.label, node.id, node.label, anode.type, node.type];
|
||||||
sigmaInstance.graph.dropNode(anode.id);
|
sigmaInstance.graph.dropNode(anode.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (node.folded.nodes.length > 0){
|
if (node.folded.nodes.length > 0){
|
||||||
node.glyphs.push({
|
node.glyphs.push({
|
||||||
'position': 'bottom-left',
|
'position': 'bottom-left',
|
||||||
'content': node.folded.nodes.length
|
'content': node.folded.nodes.length
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return [sigmaInstance, spotlightData]
|
return [sigmaInstance, spotlightData];
|
||||||
}
|
}
|
||||||
|
|
||||||
function collapseSiblingNodes(sigmaInstance, params, spotlightData){
|
function collapseSiblingNodes(sigmaInstance, params, spotlightData){
|
||||||
var threshold = params.sibling
|
var threshold = params.sibling;
|
||||||
|
|
||||||
if (threshold === 0){
|
if (threshold === 0){
|
||||||
return [sigmaInstance, spotlightData]
|
return [sigmaInstance, spotlightData];
|
||||||
}
|
}
|
||||||
|
|
||||||
sigmaInstance.graph.nodes().forEach(function(node){
|
sigmaInstance.graph.nodes().forEach(function(node){
|
||||||
//Dont apply this logic to anything thats folded or isn't a computer
|
//Dont apply this logic to anything thats folded or isn't a computer
|
||||||
if (!node.type_computer || node.folded.nodes.length > 0){
|
if (!node.type_computer || node.folded.nodes.length > 0){
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Start by getting all the edges attached to this node
|
//Start by getting all the edges attached to this node
|
||||||
var adjacent = sigmaInstance.graph.adjacentEdges(node.id)
|
var adjacent = sigmaInstance.graph.adjacentEdges(node.id);
|
||||||
var siblings = []
|
var siblings = [];
|
||||||
|
|
||||||
//Check to see if all the edges are the same type (i.e. AdminTo)
|
//Check to see if all the edges are the same type (i.e. AdminTo)
|
||||||
if (adjacent.length > 1 && adjacent.allEdgesSameType()){
|
if (adjacent.length > 1 && adjacent.allEdgesSameType()){
|
||||||
//Get the "parents" by mapping the source from every edge
|
//Get the "parents" by mapping the source from every edge
|
||||||
var parents = adjacent.map(
|
var parents = adjacent.map(
|
||||||
function(e){
|
function(e){
|
||||||
return e.source
|
return e.source;
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
//Generate our string to compare other nodes to
|
//Generate our string to compare other nodes to
|
||||||
//by sorting the parents and turning it into a string
|
//by sorting the parents and turning it into a string
|
||||||
var checkString = parents.sort().join(',')
|
var checkString = parents.sort().join(',');
|
||||||
var testString;
|
var testString;
|
||||||
|
|
||||||
//Loop back over nodes in the graph and look for any nodes
|
//Loop back over nodes in the graph and look for any nodes
|
||||||
//with identical parents
|
//with identical parents
|
||||||
sigmaInstance.graph.nodes().forEach(function(node2){
|
sigmaInstance.graph.nodes().forEach(function(node2){
|
||||||
testString = sigmaInstance.graph.adjacentEdges(node2.id).map(
|
testString = sigmaInstance.graph.adjacentEdges(node2.id).map(
|
||||||
function(e){
|
function(e){
|
||||||
return e.source;
|
return e.source;
|
||||||
}
|
}
|
||||||
).sort().join(',')
|
).sort().join(',');
|
||||||
if (testString === checkString){
|
if (testString === checkString){
|
||||||
siblings.push(node2);
|
siblings.push(node2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (siblings.length >= threshold){
|
if (siblings.length >= threshold){
|
||||||
//Generate a new ID for our grouped node
|
//Generate a new ID for our grouped node
|
||||||
var nodeId = generateUniqueId(sigmaInstance, true);
|
var nodeId = generateUniqueId(sigmaInstance, true);
|
||||||
|
|
||||||
sigmaInstance.graph.addNode({
|
sigmaInstance.graph.addNode({
|
||||||
id: nodeId,
|
id: nodeId,
|
||||||
x: node.x,
|
x: node.x,
|
||||||
y: node.y,
|
y: node.y,
|
||||||
degree: siblings.length,
|
degree: siblings.length,
|
||||||
label: "Grouped Computers",
|
label: "Grouped Computers",
|
||||||
type: 'Computer',
|
type: 'Computer',
|
||||||
type_computer: true,
|
type_computer: true,
|
||||||
groupedNode: true,
|
groupedNode: true,
|
||||||
glyphs: [{
|
glyphs: [{
|
||||||
position: 'bottom-left',
|
position: 'bottom-left',
|
||||||
content: siblings.length
|
content: siblings.length
|
||||||
}],
|
}],
|
||||||
folded: {
|
folded: {
|
||||||
nodes: [],
|
nodes: [],
|
||||||
edges: []
|
edges: []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Generate new edges for each parent going to our new node
|
//Generate new edges for each parent going to our new node
|
||||||
parents.forEach(function(parent){
|
parents.forEach(function(parent){
|
||||||
var id = generateUniqueId(sigmaInstance, false);
|
var id = generateUniqueId(sigmaInstance, false);
|
||||||
|
|
||||||
sigmaInstance.graph.addEdge({
|
sigmaInstance.graph.addEdge({
|
||||||
id: id,
|
id: id,
|
||||||
source: parent,
|
source: parent,
|
||||||
target: nodeId,
|
target: nodeId,
|
||||||
label: 'AdminTo',
|
label: 'AdminTo',
|
||||||
neo4j_type: 'AdminTo',
|
neo4j_type: 'AdminTo',
|
||||||
size: 1
|
size: 1
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
var n = sigmaInstance.graph.nodes(nodeId);
|
var n = sigmaInstance.graph.nodes(nodeId);
|
||||||
//Loop over all the siblings, and push the edges into our new parent node
|
//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
|
//Push the nodes in as well so we can unfold them
|
||||||
siblings.forEach(function(sibling){
|
siblings.forEach(function(sibling){
|
||||||
sigmaInstance.graph.adjacentEdges(sibling.id).forEach(function(edge){
|
sigmaInstance.graph.adjacentEdges(sibling.id).forEach(function(edge){
|
||||||
n.folded.edges.push(edge)
|
n.folded.edges.push(edge);
|
||||||
})
|
});
|
||||||
|
|
||||||
n.folded.nodes.push(sibling)
|
n.folded.nodes.push(sibling);
|
||||||
spotlightData[sibling.id] = [sibling.label, nodeId, n.label, sibling.type, n.type];
|
spotlightData[sibling.id] = [sibling.label, nodeId, n.label, sibling.type, n.type];
|
||||||
sigmaInstance.graph.dropNode(sibling.id)
|
sigmaInstance.graph.dropNode(sibling.id);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return [sigmaInstance, spotlightData]
|
return [sigmaInstance, spotlightData];
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateUniqueId(sigmaInstance, isNode){
|
function generateUniqueId(sigmaInstance, isNode){
|
||||||
var i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10;
|
var i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10;
|
||||||
if (isNode){
|
if (isNode){
|
||||||
while (typeof sigmaInstance.graph.nodes(i) !== 'undefined'){
|
while (typeof sigmaInstance.graph.nodes(i) !== 'undefined'){
|
||||||
i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10;
|
i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
while (typeof sigmaInstance.graph.edges(i) !== 'undefined'){
|
while (typeof sigmaInstance.graph.edges(i) !== 'undefined'){
|
||||||
i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10;
|
i = Math.floor(Math.random() * (100000 - 10 + 1)) + 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
return i;
|
||||||
}
|
}
|
Loading…
Reference in New Issue