Skip to content

Commit

Permalink
Support drag and drop file ingestion
Browse files Browse the repository at this point in the history
  • Loading branch information
rvazarkar committed Jul 16, 2018
1 parent d966516 commit f093a68
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 35 deletions.
1 change: 0 additions & 1 deletion main.js
Expand Up @@ -2,7 +2,6 @@ const electron = require('electron')
var platform = require('os').platform()
// Module to control application life.
const app = electron.app
const Tray = electron.Tray
const Menu = electron.Menu

// Module to create native browser window.
Expand Down
3 changes: 2 additions & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "bloodhound",
"version": "2.0",
"version": "2.0.0",
"description": "Graph Theory for Active Directory",
"keywords": [
"Graph",
Expand Down Expand Up @@ -58,6 +58,7 @@
"eventemitter2": "^4.1.0",
"jquery": "^3.2.1",
"linkurious": "^1.5.1",
"magic-number": "^0.1.6",
"mustache": "^2.3.0",
"neo4j-driver": "^1.6.2",
"prop-types": "^15.6.2",
Expand Down
13 changes: 13 additions & 0 deletions src/AppContainer.jsx
Expand Up @@ -20,6 +20,19 @@ import About from "./components/Modals/About.jsx";
import { CSSTransition, TransitionGroup } from "react-transition-group";

export default class AppContainer extends Component {
componentDidMount(){
document.addEventListener('dragover', function(event){
event.preventDefault();
return false;
}, false)

document.addEventListener('drop', function(event){
emitter.emit("filedrop", event)
event.preventDefault();
return false;
}, false)
}

render() {
return (
<TransitionGroup className="max">
Expand Down
4 changes: 2 additions & 2 deletions src/components/Float/Login.jsx
Expand Up @@ -39,6 +39,8 @@ export default class Login extends Component {

if (this.state.password !== "") {
this.checkDBCreds();
}else{
this.checkDBPresence();
}
}

Expand All @@ -59,8 +61,6 @@ 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 Down
82 changes: 59 additions & 23 deletions src/components/Menu/MenuContainer.jsx
Expand Up @@ -12,16 +12,17 @@ import {
buildOuJson
} from "utils";
import { If, Then, Else } from "react-if";
const { dialog, app } = require("electron").remote;
var fs = require("fs");
var async = require("async");
var unzip = require("unzipper");
var fpath = require("path");

const Pick = require("stream-json/filters/Pick");
const { streamArray } = require("stream-json/streamers/StreamArray");
const { chain } = require("stream-chain");
const Asm = require("stream-json/Assembler");
import { remote } from "electron";
const { dialog, app } = remote;
import { unlinkSync, createReadStream, createWriteStream } from "fs";
import { eachSeries } from "async";
import { Parse } from "unzipper";
import { join } from "path";

import { withParser } from "stream-json/filters/Pick";
import { streamArray } from "stream-json/streamers/StreamArray";
import { chain } from "stream-chain";
import { connectTo } from "stream-json/Assembler";

export default class MenuContainer extends Component {
constructor() {
Expand All @@ -35,6 +36,42 @@ export default class MenuContainer extends Component {
};

emitter.on("cancelUpload", this.cancelUpload.bind(this));
emitter.on("filedrop", this.fileDrop.bind(this))
}

fileDrop(e){
let fileNames = []
$.each(e.dataTransfer.files, function(_, file){
fileNames.push({ path: file.path, name: file.name });
})

this.unzipNecessary(fileNames).then(
function(results) {
eachSeries(
results,
function(file, callback) {
emitter.emit(
"showAlert",
"Processing file {}".format(file.name)
);
this.getFileMeta(file.path, callback);
}.bind(this),
function done() {
setTimeout(
function() {
this.setState({ uploading: false });
}.bind(this),
3000
);
$.each(results, function(_, file) {
if (file.delete) {
unlinkSync(file.path);
}
});
}.bind(this)
);
}.bind(this)
);
}

cancelUpload() {
Expand Down Expand Up @@ -88,13 +125,13 @@ export default class MenuContainer extends Component {
var input = jQuery(this.refs.fileInput);
var fileNames = [];

$.each(input[0].files, function(index, file) {
$.each(input[0].files, function(_, file) {
fileNames.push({ path: file.path, name: file.name });
});

this.unzipNecessary(fileNames).then(
function(results) {
async.eachSeries(
eachSeries(
results,
function(file, callback) {
emitter.emit(
Expand All @@ -112,7 +149,7 @@ export default class MenuContainer extends Component {
);
$.each(results, function(index, file) {
if (file.delete) {
fs.unlinkSync(file.path);
unlinkSync(file.path);
}
});
}.bind(this)
Expand All @@ -132,12 +169,11 @@ export default class MenuContainer extends Component {
var name = files[index].name;

if (path.endsWith(".zip")) {
await fs
.createReadStream(path)
.pipe(unzip.Parse())
await createReadStream(path)
.pipe(Parse())
.on("entry", function(entry) {
var output = fpath.join(tempPath, entry.path);
entry.pipe(fs.createWriteStream(output));
var output = join(tempPath, entry.path);
entry.pipe(createWriteStream(output));
processed.push({
path: output,
name: entry.path,
Expand Down Expand Up @@ -175,11 +211,11 @@ export default class MenuContainer extends Component {
console.log(file);

let pipeline = chain([
fs.createReadStream(file, { encoding: "utf8" }),
Pick.withParser({ filter: "meta" })
createReadStream(file, { encoding: "utf8" }),
withParser({ filter: "meta" })
]);

let asm = Asm.connectTo(pipeline);
let asm = connectTo(pipeline);
asm.on(
"done",
function(asm) {
Expand All @@ -199,8 +235,8 @@ export default class MenuContainer extends Component {

processJson(file, callback, count, type) {
let pipeline = chain([
fs.createReadStream(file, { encoding: "utf8" }),
Pick.withParser({ filter: type }),
createReadStream(file, { encoding: "utf8" }),
withParser({ filter: type }),
streamArray()
]);

Expand Down
4 changes: 2 additions & 2 deletions src/components/SearchContainer/SearchContainer.jsx
Expand Up @@ -650,7 +650,7 @@ export default class SearchContainer extends Component {
}

query +=
" WITH m,n MATCH p=allShortestPaths((n)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(m)) RETURN p";
" WITH m,n MATCH p=allShortestPaths((n)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(m)) RETURN p";

emitter.emit("query", query, { aprop: start, bprop: end });
}
Expand Down Expand Up @@ -809,7 +809,7 @@ export default class SearchContainer extends Component {
}

query +=
" WITH m,n MATCH p=allShortestPaths((n)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(m)) RETURN p";
" WITH m,n MATCH p=allShortestPaths((n)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(m)) RETURN p";

emitter.emit("query", query, { aprop: start, bprop: end });
}
Expand Down
12 changes: 6 additions & 6 deletions src/components/tooltip.html
Expand Up @@ -9,7 +9,7 @@
<li onclick="emitter.emit('setEnd', '{{type}}:{{label}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Set as Ending Node
</li>
<li onclick="emitter.emit('query', 'MATCH (n:User {name:{name}}),(m:User),p=shortestPath((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}}')">
<li onclick="emitter.emit('query', 'MATCH (n:User {name:{name}}),(m:User),p=shortestPath((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Shortest Paths to Here
</li>
{{/type_user}} {{#type_computer}}
Expand All @@ -19,7 +19,7 @@
<li onclick="emitter.emit('setEnd', '{{type}}:{{label}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Set as Ending Node
</li>
<li onclick="emitter.emit('query', 'MATCH (n:Computer {name:{name}}),(m:User),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}}')">
<li onclick="emitter.emit('query', 'MATCH (n:Computer {name:{name}}),(m:User),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Shortest Paths to Here
</li>
{{/type_computer}} {{#type_group}}
Expand All @@ -29,7 +29,7 @@
<li onclick="emitter.emit('setEnd', '{{type}}:{{label}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Set as Ending Node
</li>
<li onclick="emitter.emit('query', 'MATCH (n:Group {name:{name}}),(m:User),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}}')">
<li onclick="emitter.emit('query', 'MATCH (n:Group {name:{name}}),(m:User),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Shortest Paths to Here
</li>
{{/type_group}} {{#type_gpo}}
Expand All @@ -39,7 +39,7 @@
<li onclick="emitter.emit('setEnd', '{{type}}:{{guid}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Set as Ending Node
</li>
<li onclick="emitter.emit('query', 'MATCH (n:GPO {name:{name}}),(m),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) WHERE NOT m.guid={guid} RETURN p', {name: '{{name}}'})">
<li onclick="emitter.emit('query', 'MATCH (n:GPO {name:{name}}),(m),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(n)) WHERE NOT m.guid={guid} RETURN p', {name: '{{name}}'})">
<i class="glyphicon glyphicon-screenshot"> </i> Shortest Paths to Here
</li>
{{/type_gpo}} {{#type_ou}}
Expand All @@ -49,7 +49,7 @@
<li onclick="emitter.emit('setEnd', '{{type}}:{{guid}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Set as Ending Node
</li>
<li onclick="emitter.emit('query', 'MATCH (n:OU {guid:{guid}}),(m),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) WHERE NOT m.guid={guid} RETURN p', {guid: '{{guid}}'})">
<li onclick="emitter.emit('query', 'MATCH (n:OU {guid:{guid}}),(m),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(n)) WHERE NOT m.guid={guid} RETURN p', {guid: '{{guid}}'})">
<i class="glyphicon glyphicon-screenshot"> </i> Shortest Paths to Here
</li>
{{/type_ou}} {{#type_domain}}
Expand All @@ -59,7 +59,7 @@
<li onclick="emitter.emit('setEnd', '{{type}}:{{label}}')">
<i class="glyphicon glyphicon-screenshot"> </i> Set as Ending Node
</li>
<li onclick="emitter.emit('query', 'MATCH (n:Domain {name:{name}}),(m:User),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}} ')">
<li onclick="emitter.emit('query', 'MATCH (n:Domain {name:{name}}),(m:User),p=allShortestPaths((m)-[r:MemberOf|AdminTo|HasSession|Contains|GpLink|Owns|DCSync|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM*1..]->(n)) WHERE NOT m.name={name} RETURN p', {name: '{{label}}'}, '{{label}} ')">
<i class="glyphicon glyphicon-screenshot"> </i> Shortest Paths to Here
</li>
{{/type_domain}} {{#expand}}
Expand Down
13 changes: 13 additions & 0 deletions src/js/utils.js
Expand Up @@ -593,6 +593,7 @@ export function buildComputerJson(chunk) {
let localadmins = comp.LocalAdmins;
let rdpers = comp.RemoteDesktopUsers;
let primarygroup = comp.PrimaryGroup;
let dcom = comp.DcomUsers;

if (!queries.properties) {
if (primarygroup === null) {
Expand Down Expand Up @@ -638,6 +639,18 @@ export function buildComputerJson(chunk) {
let p = { name: name, target: aName };
insert(queries, hash, statement, p);
});

$.each(dcom, function(_, dcomu) {
let aType = dcomu.Type;
let aName = dcomu.Name;
let rel = "ExecuteDCOM";

let hash = rel + aType;

let statement = baseQuery.format(aType, rel);
let p = { name: name, target: aName };
insert(queries, hash, statement, p);
});
});
return queries;
}
Expand Down

0 comments on commit f093a68

Please sign in to comment.