Skip to content

Commit

Permalink
Merge pull request #76 from adaptivethreat/node_channels
Browse files Browse the repository at this point in the history
BloodHound 1.2.0
  • Loading branch information
rvazarkar authored Jan 20, 2017
2 parents ebffbe0 + fa1438f commit 18b6290
Show file tree
Hide file tree
Showing 17 changed files with 849 additions and 413 deletions.
Binary file modified BloodHoundExampleDB.graphdb/neostore.counts.db.a
Binary file not shown.
Binary file modified BloodHoundExampleDB.graphdb/neostore.transaction.db.0
Binary file not shown.
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
<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/bootstrap-3-typeahead/bootstrap3-typeahead.min.js" type="text/javascript"></script>
<script src="node_modules/neo4j-driver/lib/browser/neo4j-web.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>
<link type="text/css" rel="stylesheet" href="src/css/simple-slider.css">
Expand Down
35 changes: 18 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bloodhound",
"version": "1.1.0",
"version": "1.2.0",
"description": "Graph Theory for Active Directory",
"keywords": [
"Graph",
Expand Down Expand Up @@ -34,36 +34,37 @@
]
},
"devDependencies": {
"babel-cli": "^6.11.4",
"babel-core": "^6.11.4",
"babel-loader": "^6.2.4",
"babel-polyfill": "^6.9.1",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-0": "^6.5.0",
"concurrently": "^2.2.0",
"cross-env": "^2.0.0",
"electron": "^1.4.3",
"babel-cli": "^6.22.2",
"babel-core": "^6.22.1",
"babel-loader": "*",
"babel-polyfill": "^6.22.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"babel-preset-stage-0": "^6.22.0",
"concurrently": "^3.1.0",
"cross-env": "^3.1.4",
"electron": "^1.4.15",
"express": "^4.14.0",
"webpack": "^1.13.1",
"webpack-dev-middleware": "^1.6.1",
"webpack-hot-middleware": "^2.12.1",
"webpack-target-electron-renderer": "^0.4.0"
},
"dependencies": {
"async": "^2.1.4",
"bootstrap": "^3.3.6",
"bootstrap-3-typeahead": "^4.0.1",
"configstore": "^2.0.0",
"configstore": "^2.1.0",
"dagre": "^0.7.4",
"eventemitter2": "^2.0.0",
"eventemitter2": "^2.2.2",
"jquery": "^2.2.4",
"linkurious": "^1.5.1",
"mustache": "^2.2.1",
"neo4j-driver": "^1.0.4",
"react": "^15.3.1",
"react-addons-css-transition-group": "^15.3.1",
"neo4j-driver": "^1.1.0",
"react": "^15.4.2",
"react-addons-css-transition-group": "^15.4.2",
"react-bootstrap": "^0.30.3",
"react-dom": "^15.3.1",
"react-dom": "^15.4.2",
"react-if": "^2.1.0"
}
}
4 changes: 4 additions & 0 deletions src/AppContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import ExportContainer from './components/Float/ExportContainer';
import Settings from './components/Float/Settings'
import ZoomContainer from './components/Zoom/ZoomContainer'
import QueryNodeSelect from './components/Float/QueryNodeSelect'
import SessionClearModal from './components/Modals/SessionClearModal'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import About from './components/Modals/About.jsx'

export default class AppContainer extends Component {
constructor(){
Expand All @@ -41,11 +43,13 @@ export default class AppContainer extends Component {
<ClearConfirmModal />
<ClearingModal />
<CancelUploadModal />
<SessionClearModal />
<RawQuery />
<MenuContainer />
<Settings />
<ZoomContainer />
<QueryNodeSelect />
<About />
</div>
</ReactCSSTransitionGroup>
);
Expand Down
170 changes: 128 additions & 42 deletions src/components/Float/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ export default class Login extends Component {
url: "",
icon: null,
loginEnabled: false,
dbHelpVisible: false,
loginHelpVisible: false,
user: "",
password: "",
loginInProgress: false
Expand All @@ -18,6 +16,8 @@ export default class Login extends Component {
checkDBPresence(){
var url = this.state.url;
var icon = this.state.icon;
var jicon = jQuery(icon)
var btn = jQuery(this.refs.loginButton)

if (url === ""){
return;
Expand All @@ -38,28 +38,41 @@ export default class Login extends Component {
icon.removeClass();
icon.addClass("fa fa-spinner fa-spin form-control-feedback");
icon.toggle(true);
var driver = neo4j.v1.driver(url)
var session = driver.session()

session.run('MATCH (n) RETURN (n) LIMIT 1')
.subscribe({
onNext: function(next){
},
onError: function(error){
if (error.code){
this.setState({dbHelpVisible: true})
icon.removeClass();
icon.addClass("fa fa-times-circle red-icon-color form-control-feedback");
}else{
icon.removeClass();
icon.addClass("fa fa-check-circle green-icon-color form-control-feedback");
this.setState({loginEnabled: true, url: url})
}
}.bind(this),
onComplete: function(){
session.close()
}
})
var driver = neo4j.driver(url)
driver.onCompleted = function(){
driver.close()
}
driver.onError = function(error){
console.log(error)
if (error.message && error.message.includes("encryption certificate has changed")){
var path = error.message.match("`(.*?)`")[1]
icon.removeClass();
icon.addClass("fa fa-times-circle red-icon-color form-control-feedback");
icon.attr('data-original-title', 'Certificate error - delete localhost line in {}'.format(path))
.tooltip('fixTitle')
.tooltip('show')
this.setState({
loginInProgress: false,
loginEnabled: false
})
}else if (error.fields && error.fields[0].code === "Neo.ClientError.Security.Unauthorized"){
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
})
}
driver.close()
}.bind(this)
driver.session();
}

checkDBCreds(){
Expand All @@ -68,24 +81,80 @@ export default class Login extends Component {
}
this.setState({
loginInProgress: true,
loginHelpVisible: false,
loginEnabled: false
})

var btn = jQuery(this.refs.loginButton)
var pwf = jQuery(this.refs.password)

var driver = neo4j.v1.driver(this.state.url, neo4j.v1.auth.basic(this.state.user, this.state.password),{knownHosts: 'known_hosts'})
var session = driver.session()
var driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password))
driver.onError = function(error){
if (error.fields && error.fields[0].code === "Neo.ClientError.Security.Unauthorized"){
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.fields && error.fields[0].code === "Neo.ClientError.Security.AuthenticationRateLimit"){
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.message && error.message.includes("encryption certificate has changed")){
var path = error.message.match("`(.*?)`")[1]
var icon = this.state.icon
icon.toggle('true')
icon.removeClass();
icon.addClass("fa fa-times-circle red-icon-color form-control-feedback");
jQuery(icon).tooltip({
placement : 'right',
title: 'Certificate error - delete localhost line in ' + path,
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>'
})
this.setState({
loginInProgress: false,
loginEnabled: false
})
jQuery(icon).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.toggleClass('activate');
this.setState({
loginHelpVisible: true,
loginInProgress: false,
loginEnabled: true
})

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(){

Expand All @@ -103,14 +172,16 @@ export default class Login extends Component {
user: this.state.user,
password: this.state.password
})
global.driver = driver
appStore.databaseInfo = conf.get('databaseInfo');
jQuery(this.refs.password).tooltip('hide')
jQuery(this.refs.urlspinner).tooltip('hide')
setTimeout(function(){
jQuery(this.refs.outer).fadeOut(400, function(){
renderEmit.emit('login');
});
}.bind(this), 1500)
session.close()
driver.close()
global.driver = neo4j.driver(this.state.url, neo4j.auth.basic(this.state.user, this.state.password))
}.bind(this)
})

Expand All @@ -130,8 +201,23 @@ export default class Login extends Component {
}

componentDidMount() {
jQuery(this.refs.urlspinner).toggle(false)
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.setState({icon: jQuery(this.refs.urlspinner)})
var icon = jQuery(this.refs.urlspinner)
icon.tooltip({
placement : 'right',
title: '',
container: 'body',
delay: {show: 200, hide: 0},
template: '<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();
}
Expand All @@ -142,11 +228,13 @@ export default class Login extends Component {
}

_userChanged(event){
this.setState({user: event.target.value})
this.setState({user: event.target.value})
jQuery(this.refs.password).tooltip('hide')
}

_passChanged(event){
this.setState({password: event.target.value})
this.setState({password: event.target.value})
jQuery(this.refs.password).tooltip('hide')
}

_triggerLogin(e){
Expand All @@ -171,10 +259,9 @@ export default class Login extends Component {
<span className="input-group-addon" id="dburladdon">
Database URL
</span>
<input ref="url" onFocus={function(){this.setState({dbHelpVisible: false})}.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="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" />
<i ref="urlspinner" className="fa fa-spinner fa-spin form-control-feedback" />
</div>
{this.state.dbHelpVisible ? <p className="help-block help-block-add">No Neo4j Database Found</p> : null}
<div className="input-group spacing">
<span className="input-group-addon" id="dbuseraddon">DB Username</span>
<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" />
Expand All @@ -183,7 +270,6 @@ export default class Login extends Component {
<span className="input-group-addon" id="dbpwaddon">DB Password</span>
<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" />
</div>
{this.state.loginHelpVisible ? <p className="help-block help-block-add" style={{color: "#d9534f"}}>Wrong username or password</p> : null}
<button ref="loginButton" disabled={!this.state.loginEnabled} type="button" onClick={this.checkDBCreds.bind(this)} className="btn btn-primary loginbutton has-spinner">
Login
<span className="button-spinner">
Expand Down
7 changes: 5 additions & 2 deletions src/components/Graph.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export default class GraphContainer extends Component {

clearGraph(){
this.state.sigmaInstance.graph.clear()
this.state.sigmaInstance.refresh()
}

setGraphicsMode(){
Expand Down Expand Up @@ -764,8 +765,10 @@ export default class GraphContainer extends Component {
});

dagreListener.bind('stop', function(event){
emitter.emit('updateLoadingText', "Fixing Overlap");
sigmaInstance.startNoverlap();
emitter.emit('updateLoadingText', 'Done!');
setTimeout(function(){
emitter.emit('showLoadingIndicator', false);
}, 1500)
})

dagreListener.bind('start', function(event){
Expand Down
Loading

0 comments on commit 18b6290

Please sign in to comment.