Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BloodHound 1.2.0 #76

Merged
merged 20 commits into from
Jan 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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