parent
8c73698fd4
commit
ec88ff2948
10
package.json
10
package.json
|
@ -52,22 +52,28 @@
|
|||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.1.1",
|
||||
"async": "^2.6.0",
|
||||
"base64-img": "^1.0.4",
|
||||
"bootstrap": "^3.3.7",
|
||||
"bootstrap-3-typeahead": "^4.0.2",
|
||||
"dagre": "^0.7.4",
|
||||
"electron-store": "^1.3.0",
|
||||
"eventemitter2": "^4.1.0",
|
||||
"fontfaceobserver": "^2.0.13",
|
||||
"image-size": "^0.6.3",
|
||||
"image-type": "^3.0.0",
|
||||
"is-zip-file": "^1.0.2",
|
||||
"jquery": "^3.2.1",
|
||||
"linkurious": "^1.5.1",
|
||||
"md5-file": "^4.0.0",
|
||||
"mustache": "^2.3.0",
|
||||
"neo4j-driver": "^1.6.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.2.0",
|
||||
"react": "^16.4.2",
|
||||
"react-bootstrap": "^0.32.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-dom": "^16.4.2",
|
||||
"react-if": "^2.1.0",
|
||||
"react-images": "^0.5.19",
|
||||
"react-photo-gallery": "^6.1.2",
|
||||
"react-transition-group": "^2.2.1",
|
||||
"stream-json": "^1.1.0",
|
||||
"unzipper": "^0.8.9",
|
||||
|
|
|
@ -31,10 +31,15 @@ export default class AppContainer extends Component {
|
|||
event.preventDefault();
|
||||
return false;
|
||||
}, false)
|
||||
|
||||
|
||||
document.addEventListener('drop', function(event){
|
||||
emitter.emit("filedrop", event)
|
||||
event.preventDefault();
|
||||
if (jQuery("#tabcontainer").has(jQuery(event.target)).length === 1){
|
||||
emitter.emit("imageupload", event)
|
||||
}else{
|
||||
emitter.emit("filedrop", event)
|
||||
}
|
||||
|
||||
return false;
|
||||
}, false)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class LoadingContainer extends Component {
|
|||
return (
|
||||
<div className="loadingIndicator" ref="load">
|
||||
<div>{this.state.text}</div>
|
||||
<img src="src/img/loading.gif" />
|
||||
<img src="src/img/loading_new.gif" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ export default class MenuContainer extends Component {
|
|||
},
|
||||
3000
|
||||
);
|
||||
this.addOwnedProp();
|
||||
this.addBaseProps();
|
||||
$.each(results, function(_, file) {
|
||||
if (file.delete) {
|
||||
unlinkSync(file.path);
|
||||
|
@ -150,7 +150,7 @@ export default class MenuContainer extends Component {
|
|||
},
|
||||
3000
|
||||
);
|
||||
this.addOwnedProp();
|
||||
this.addBaseProps();
|
||||
$.each(results, (_, file) => {
|
||||
if (file.delete) {
|
||||
unlinkSync(file.path);
|
||||
|
@ -164,10 +164,11 @@ export default class MenuContainer extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
async addOwnedProp(){
|
||||
async addBaseProps(){
|
||||
let s = driver.session();
|
||||
await s.run("MATCH (n:User) WHERE NOT EXISTS(n.owned) SET n.owned=false");
|
||||
await s.run("MATCH (n:Computer) WHERE NOT EXISTS(n.owned) SET n.owned=false");
|
||||
await s.run("MATCH (n) WHERE NOT EXISTS(n.pics) SET n.pics=[]");
|
||||
s.close();
|
||||
}
|
||||
|
||||
|
@ -229,11 +230,17 @@ export default class MenuContainer extends Component {
|
|||
|
||||
let size = statSync(file).size;
|
||||
createReadStream(file, {encoding: 'utf8', start: size-100, end: size}).on('data', chunk => {
|
||||
type = /type.?:\s?"(\w*)"/g.exec(chunk)[1];
|
||||
count = /count.?:\s?(\d*)/g.exec(chunk)[1];
|
||||
let type;
|
||||
try{
|
||||
type = /type.?:\s?"(\w*)"/g.exec(chunk)[1];
|
||||
count = /count.?:\s?(\d*)/g.exec(chunk)[1];
|
||||
}catch(e){
|
||||
type = null;
|
||||
}
|
||||
|
||||
|
||||
if (!acceptableTypes.includes(type)){
|
||||
emitter.emit("showAlert", "Unrecognized JSON Type");
|
||||
emitter.emit("showAlert", "Unrecognized File");
|
||||
this.setState({
|
||||
uploading: false
|
||||
});
|
||||
|
|
|
@ -812,7 +812,7 @@ export default class SearchContainer extends Component {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div ref="tabs">
|
||||
<div id="tabcontainer" ref="tabs">
|
||||
<TabContainer />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,6 +9,8 @@ import DomainNodeData from "./Tabs/DomainNodeData";
|
|||
import GpoNodeData from "./Tabs/GpoNodeData";
|
||||
import OuNodeData from "./Tabs/OuNodeData";
|
||||
import { Tabs, Tab } from "react-bootstrap";
|
||||
import { openSync, readSync, closeSync } from "fs";
|
||||
import imageType from "image-type";
|
||||
|
||||
export default class TabContainer extends Component {
|
||||
constructor(props) {
|
||||
|
@ -32,6 +34,24 @@ export default class TabContainer extends Component {
|
|||
emitter.on("domainNodeClicked", this._domainNodeClicked.bind(this));
|
||||
emitter.on("gpoNodeClicked", this._gpoNodeClicked.bind(this));
|
||||
emitter.on("ouNodeClicked", this._ouNodeClicked.bind(this));
|
||||
emitter.on("imageupload", this.uploadImage.bind(this));
|
||||
}
|
||||
|
||||
uploadImage(event){
|
||||
let files = [];
|
||||
$.each(event.dataTransfer.files, (_, f) => {
|
||||
let buf = Buffer.alloc(12);
|
||||
let file = openSync(f.path, 'r')
|
||||
readSync(file,buf, 0, 12, 0);
|
||||
closeSync(file)
|
||||
let type = imageType(buf);
|
||||
if (type !== null && type.mime.includes("image")){
|
||||
files.push({path: f.path, name: f.name})
|
||||
}else{
|
||||
emitter.emit("showAlert", `${f.name} is not an image`);
|
||||
}
|
||||
})
|
||||
emitter.emit("imageUploadFinal", files);
|
||||
}
|
||||
|
||||
_userNodeClicked() {
|
||||
|
@ -136,9 +156,7 @@ export default class TabContainer extends Component {
|
|||
/>
|
||||
<UserNodeData visible={this.state.userVisible} />
|
||||
<GroupNodeData visible={this.state.groupVisible} />
|
||||
<ComputerNodeData
|
||||
visible={this.state.computerVisible}
|
||||
/>
|
||||
<ComputerNodeData visible={this.state.computerVisible} />
|
||||
<DomainNodeData visible={this.state.domainVisible} />
|
||||
<GpoNodeData visible={this.state.gpoVisible} />
|
||||
<OuNodeData visible={this.state.ouVisible} />
|
||||
|
|
|
@ -4,6 +4,16 @@ import NodeProps from "./NodeProps";
|
|||
import NodeCypherLink from "./NodeCypherLink";
|
||||
import NodeCypherNoNumberLink from "./NodeCypherNoNumberLink";
|
||||
import NodeCypherLinkComplex from "./NodeCypherLinkComplex";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import SelectedImage from "./SelectedImage";
|
||||
import Lightbox from "react-images";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { base64Sync } from "base64-img";
|
||||
import sizeOf from "image-size";
|
||||
import md5File from "md5-file";
|
||||
import { remote } from "electron";
|
||||
const { app } = remote;
|
||||
import { join } from "path";
|
||||
|
||||
export default class ComputerNodeData extends Component {
|
||||
constructor() {
|
||||
|
@ -20,14 +30,26 @@ export default class ComputerNodeData extends Component {
|
|||
unconstraineddelegation: "Allows Unconstrained Delegation",
|
||||
owned: "Compromised"
|
||||
},
|
||||
notes: null
|
||||
notes: null,
|
||||
pics: [],
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
};
|
||||
|
||||
emitter.on("computerNodeClicked", this.getNodeData.bind(this));
|
||||
emitter.on("imageUploadFinal", this.uploadImage.bind(this));
|
||||
emitter.on("clickPhoto", this.openLightbox.bind(this));
|
||||
emitter.on("deletePhoto", this.handleDelete.bind(this));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
jQuery(this.refs.complete).hide();
|
||||
jQuery(this.refs.piccomplete).hide();
|
||||
}
|
||||
|
||||
getNodeData(payload) {
|
||||
jQuery(this.refs.complete).hide();
|
||||
jQuery(this.refs.piccomplete).hide();
|
||||
$.each(this.state.driversessions, function(_, record) {
|
||||
record.close();
|
||||
});
|
||||
|
@ -37,6 +59,15 @@ export default class ComputerNodeData extends Component {
|
|||
driversessions: []
|
||||
});
|
||||
|
||||
let key = `computer_${this.state.label}`;
|
||||
let c = imageconf.get(key);
|
||||
let pics = [];
|
||||
if (typeof c !== "undefined"){
|
||||
this.setState({pics: c})
|
||||
}else{
|
||||
this.setState({pics: pics})
|
||||
}
|
||||
|
||||
var propCollection = driver.session();
|
||||
propCollection
|
||||
.run("MATCH (c:Computer {name:{name}}) RETURN c", { name: payload })
|
||||
|
@ -75,6 +106,96 @@ export default class ComputerNodeData extends Component {
|
|||
this.setState({ driversessions: [propCollection] });
|
||||
}
|
||||
|
||||
uploadImage(files) {
|
||||
if (!this.props.visible || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let p = this.state.pics;
|
||||
let oLen = p.length;
|
||||
let key = `computer_${this.state.label}`;
|
||||
|
||||
$.each(files, (_, f) => {
|
||||
let exists = false;
|
||||
let hash = md5File.sync(f.path);
|
||||
$.each(p, (_, p1) => {
|
||||
if (p1.hash === hash){
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
if (exists){
|
||||
emitter.emit("showAlert", "Image already exists");
|
||||
return;
|
||||
}
|
||||
let path = join(app.getPath("userData"), "images", hash);
|
||||
let dimensions = sizeOf(f.path);
|
||||
let data = readFileSync(f.path);
|
||||
writeFileSync(path, data);
|
||||
p.push({hash: hash, src: path, width: dimensions.width, height: dimensions.height})
|
||||
});
|
||||
|
||||
if (p.length === oLen){
|
||||
return;
|
||||
}
|
||||
this.setState({pics: p});
|
||||
imageconf.set(key, p)
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
handleDelete(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
let pics = this.state.pics;
|
||||
let temp = pics[event.index];
|
||||
pics.splice(event.index, 1);
|
||||
this.setState({
|
||||
pics: pics
|
||||
})
|
||||
let key = `computer_${this.state.label}`;
|
||||
imageconf.set(key, pics);
|
||||
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
openLightbox(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: event.index,
|
||||
lightboxIsOpen: true
|
||||
});
|
||||
}
|
||||
closeLightbox() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
});
|
||||
}
|
||||
gotoPrevious() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage - 1
|
||||
});
|
||||
}
|
||||
gotoNext() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage + 1
|
||||
});
|
||||
}
|
||||
|
||||
notesChanged(event){
|
||||
this.setState({notes: event.target.value})
|
||||
}
|
||||
|
@ -97,6 +218,28 @@ export default class ComputerNodeData extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
let gallery;
|
||||
if (this.state.pics.length === 0){
|
||||
gallery = (<span>Drop pictures on here to upload!</span>)
|
||||
}else{
|
||||
gallery = (
|
||||
<React.Fragment>
|
||||
<Gallery
|
||||
photos={this.state.pics}
|
||||
ImageComponent={SelectedImage}
|
||||
className={"gallerymod"}
|
||||
/>
|
||||
<Lightbox
|
||||
images={this.state.pics}
|
||||
isOpen={this.state.lightboxIsOpen}
|
||||
onClose={this.closeLightbox.bind(this)}
|
||||
onClickPrev={this.gotoPrevious.bind(this)}
|
||||
onClickNext={this.gotoNext.bind(this)}
|
||||
currentImage={this.state.currentImage}
|
||||
/>
|
||||
</React.Fragment>)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={this.props.visible ? "" : "displaynone"}>
|
||||
<dl className="dl-horizontal">
|
||||
|
@ -278,6 +421,14 @@ export default class ComputerNodeData extends Component {
|
|||
/>
|
||||
</div>
|
||||
<textarea onBlur={this.notesBlur.bind(this)} onChange={this.notesChanged.bind(this)} value={this.state.notes === null ? "" : this.state.notes} className={"node-notes-textarea"} ref="notes" />
|
||||
<div>
|
||||
<h4 className={"inline"}>Pictures</h4>
|
||||
<i
|
||||
ref="piccomplete"
|
||||
className="fa fa-check-circle green-icon-color notes-check-style"
|
||||
/>
|
||||
</div>
|
||||
{gallery}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,16 @@ import NodeCypherLink from "./NodeCypherLink.jsx";
|
|||
import NodeCypherNoNumberLink from "./NodeCypherNoNumberLink";
|
||||
import NodeCypherLinkComplex from "./NodeCypherLinkComplex";
|
||||
import NodeProps from "./NodeProps";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import SelectedImage from "./SelectedImage";
|
||||
import Lightbox from "react-images";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { base64Sync } from "base64-img";
|
||||
import sizeOf from "image-size";
|
||||
import md5File from "md5-file";
|
||||
import { remote } from "electron";
|
||||
const { app } = remote;
|
||||
import { join } from "path";
|
||||
|
||||
export default class DomainNodeData extends Component {
|
||||
constructor() {
|
||||
|
@ -23,10 +33,21 @@ export default class DomainNodeData extends Component {
|
|||
"description":"Description",
|
||||
"functionallevel":"Domain Functional Level"
|
||||
},
|
||||
notes: null
|
||||
notes: null,
|
||||
pics: [],
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
};
|
||||
|
||||
emitter.on("domainNodeClicked", this.getNodeData.bind(this));
|
||||
emitter.on("imageUploadFinal", this.uploadImage.bind(this));
|
||||
emitter.on("clickPhoto", this.openLightbox.bind(this));
|
||||
emitter.on("deletePhoto", this.handleDelete.bind(this));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
jQuery(this.refs.complete).hide();
|
||||
jQuery(this.refs.piccomplete).hide();
|
||||
}
|
||||
|
||||
getNodeData(payload) {
|
||||
|
@ -44,6 +65,15 @@ export default class DomainNodeData extends Component {
|
|||
gpos: -1
|
||||
});
|
||||
|
||||
let key = `domain_${this.state.label}`;
|
||||
let c = imageconf.get(key);
|
||||
let pics = [];
|
||||
if (typeof c !== "undefined"){
|
||||
this.setState({pics: c})
|
||||
}else{
|
||||
this.setState({pics: pics})
|
||||
}
|
||||
|
||||
let props = driver.session();
|
||||
props
|
||||
.run("MATCH (n:Domain {name:{name}}) RETURN n", { name: payload })
|
||||
|
@ -136,7 +166,119 @@ export default class DomainNodeData extends Component {
|
|||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
uploadImage(files) {
|
||||
if (!this.props.visible || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let p = this.state.pics;
|
||||
let oLen = p.length;
|
||||
let key = `domain_${this.state.label}`;
|
||||
|
||||
$.each(files, (_, f) => {
|
||||
let exists = false;
|
||||
let hash = md5File.sync(f.path);
|
||||
$.each(p, (_, p1) => {
|
||||
if (p1.hash === hash){
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
if (exists){
|
||||
emitter.emit("showAlert", "Image already exists");
|
||||
return;
|
||||
}
|
||||
let path = join(app.getPath("userData"), "images", hash);
|
||||
let dimensions = sizeOf(f.path);
|
||||
let data = readFileSync(f.path);
|
||||
writeFileSync(path, data);
|
||||
p.push({hash: hash, src: path, width: dimensions.width, height: dimensions.height})
|
||||
});
|
||||
|
||||
if (p.length === oLen){
|
||||
return;
|
||||
}
|
||||
this.setState({pics: p});
|
||||
imageconf.set(key, p)
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
handleDelete(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
let pics = this.state.pics;
|
||||
let temp = pics[event.index];
|
||||
pics.splice(event.index, 1);
|
||||
this.setState({
|
||||
pics: pics
|
||||
})
|
||||
let key = `domain_${this.state.label}`;
|
||||
imageconf.set(key, pics);
|
||||
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
openLightbox(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: event.index,
|
||||
lightboxIsOpen: true
|
||||
});
|
||||
}
|
||||
closeLightbox() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
});
|
||||
}
|
||||
gotoPrevious() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage - 1
|
||||
});
|
||||
}
|
||||
gotoNext() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage + 1
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let gallery;
|
||||
if (this.state.pics.length === 0){
|
||||
gallery = (<span>Drop pictures on here to upload!</span>)
|
||||
}else{
|
||||
gallery = (
|
||||
<React.Fragment>
|
||||
<Gallery
|
||||
photos={this.state.pics}
|
||||
ImageComponent={SelectedImage}
|
||||
className={"gallerymod"}
|
||||
/>
|
||||
<Lightbox
|
||||
images={this.state.pics}
|
||||
isOpen={this.state.lightboxIsOpen}
|
||||
onClose={this.closeLightbox.bind(this)}
|
||||
onClickPrev={this.gotoPrevious.bind(this)}
|
||||
onClickNext={this.gotoNext.bind(this)}
|
||||
currentImage={this.state.currentImage}
|
||||
/>
|
||||
</React.Fragment>)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={this.props.visible ? "" : "displaynone"}>
|
||||
<dl className="dl-horizontal">
|
||||
|
@ -304,6 +446,14 @@ export default class DomainNodeData extends Component {
|
|||
/>
|
||||
</div>
|
||||
<textarea onBlur={this.notesBlur.bind(this)} onChange={this.notesChanged.bind(this)} value={this.state.notes === null ? "" : this.state.notes} className={"node-notes-textarea"} ref="notes" />
|
||||
<div>
|
||||
<h4 className={"inline"}>Pictures</h4>
|
||||
<i
|
||||
ref="piccomplete"
|
||||
className="fa fa-check-circle green-icon-color notes-check-style"
|
||||
/>
|
||||
</div>
|
||||
{gallery}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,16 @@ import PropTypes from "prop-types";
|
|||
import NodeCypherLink from "./NodeCypherLink.jsx";
|
||||
import NodeCypherLinkComplex from "./NodeCypherLinkComplex.jsx";
|
||||
import NodeProps from "./NodeProps";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import SelectedImage from "./SelectedImage";
|
||||
import Lightbox from "react-images";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { base64Sync } from "base64-img";
|
||||
import sizeOf from "image-size";
|
||||
import md5File from "md5-file";
|
||||
import { remote } from "electron";
|
||||
const { app } = remote;
|
||||
import { join } from "path";
|
||||
|
||||
export default class GpoNodeData extends Component {
|
||||
constructor() {
|
||||
|
@ -15,10 +25,22 @@ export default class GpoNodeData extends Component {
|
|||
displayMap: {
|
||||
"description":"Description",
|
||||
"gpcpath":"GPO File Path"
|
||||
}
|
||||
},
|
||||
notes:null,
|
||||
pics: [],
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
};
|
||||
|
||||
emitter.on("gpoNodeClicked", this.getNodeData.bind(this));
|
||||
emitter.on("imageUploadFinal", this.uploadImage.bind(this));
|
||||
emitter.on("clickPhoto", this.openLightbox.bind(this));
|
||||
emitter.on("deletePhoto", this.handleDelete.bind(this));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
jQuery(this.refs.complete).hide();
|
||||
jQuery(this.refs.piccomplete).hide();
|
||||
}
|
||||
|
||||
getNodeData(payload, guid) {
|
||||
|
@ -27,6 +49,15 @@ export default class GpoNodeData extends Component {
|
|||
label: payload,
|
||||
guid: guid
|
||||
});
|
||||
|
||||
let key = `gpo_${this.state.label}`;
|
||||
let c = imageconf.get(key);
|
||||
let pics = [];
|
||||
if (typeof c !== "undefined"){
|
||||
this.setState({pics: c})
|
||||
}else{
|
||||
this.setState({pics: pics})
|
||||
}
|
||||
|
||||
let props = driver.session();
|
||||
props
|
||||
|
@ -46,6 +77,96 @@ export default class GpoNodeData extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
uploadImage(files) {
|
||||
if (!this.props.visible || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let p = this.state.pics;
|
||||
let oLen = p.length;
|
||||
let key = `gpo_${this.state.label}`;
|
||||
|
||||
$.each(files, (_, f) => {
|
||||
let exists = false;
|
||||
let hash = md5File.sync(f.path);
|
||||
$.each(p, (_, p1) => {
|
||||
if (p1.hash === hash){
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
if (exists){
|
||||
emitter.emit("showAlert", "Image already exists");
|
||||
return;
|
||||
}
|
||||
let path = join(app.getPath("userData"), "images", hash);
|
||||
let dimensions = sizeOf(f.path);
|
||||
let data = readFileSync(f.path);
|
||||
writeFileSync(path, data);
|
||||
p.push({hash: hash, src: path, width: dimensions.width, height: dimensions.height})
|
||||
});
|
||||
|
||||
if (p.length === oLen){
|
||||
return;
|
||||
}
|
||||
this.setState({pics: p});
|
||||
imageconf.set(key, p)
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
handleDelete(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
let pics = this.state.pics;
|
||||
let temp = pics[event.index];
|
||||
pics.splice(event.index, 1);
|
||||
this.setState({
|
||||
pics: pics
|
||||
})
|
||||
let key = `gpo_${this.state.label}`;
|
||||
imageconf.set(key, pics);
|
||||
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
openLightbox(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: event.index,
|
||||
lightboxIsOpen: true
|
||||
});
|
||||
}
|
||||
closeLightbox() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
});
|
||||
}
|
||||
gotoPrevious() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage - 1
|
||||
});
|
||||
}
|
||||
gotoNext() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage + 1
|
||||
});
|
||||
}
|
||||
|
||||
notesChanged(event){
|
||||
this.setState({notes: event.target.value})
|
||||
}
|
||||
|
@ -68,6 +189,28 @@ export default class GpoNodeData extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
let gallery;
|
||||
if (this.state.pics.length === 0){
|
||||
gallery = (<span>Drop pictures on here to upload!</span>)
|
||||
}else{
|
||||
gallery = (
|
||||
<React.Fragment>
|
||||
<Gallery
|
||||
photos={this.state.pics}
|
||||
ImageComponent={SelectedImage}
|
||||
className={"gallerymod"}
|
||||
/>
|
||||
<Lightbox
|
||||
images={this.state.pics}
|
||||
isOpen={this.state.lightboxIsOpen}
|
||||
onClose={this.closeLightbox.bind(this)}
|
||||
onClickPrev={this.gotoPrevious.bind(this)}
|
||||
onClickNext={this.gotoNext.bind(this)}
|
||||
currentImage={this.state.currentImage}
|
||||
/>
|
||||
</React.Fragment>)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={this.props.visible ? "" : "displaynone"}>
|
||||
<dl className="dl-horizontal">
|
||||
|
@ -162,6 +305,14 @@ export default class GpoNodeData extends Component {
|
|||
/>
|
||||
</div>
|
||||
<textarea onBlur={this.notesBlur.bind(this)} onChange={this.notesChanged.bind(this)} value={this.state.notes === null ? "" : this.state.notes} className={"node-notes-textarea"} ref="notes" />
|
||||
<div>
|
||||
<h4 className={"inline"}>Pictures</h4>
|
||||
<i
|
||||
ref="piccomplete"
|
||||
className="fa fa-check-circle green-icon-color notes-check-style"
|
||||
/>
|
||||
</div>
|
||||
{gallery}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,16 @@ import React, { Component } from "react";
|
|||
import PropTypes from "prop-types";
|
||||
import NodeCypherLink from "./NodeCypherLink";
|
||||
import NodeProps from "./NodeProps";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import SelectedImage from "./SelectedImage";
|
||||
import Lightbox from "react-images";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { base64Sync } from "base64-img";
|
||||
import sizeOf from "image-size";
|
||||
import md5File from "md5-file";
|
||||
import { remote } from "electron";
|
||||
const { app } = remote;
|
||||
import { join } from "path";
|
||||
|
||||
export default class GroupNodeData extends Component {
|
||||
constructor() {
|
||||
|
@ -11,17 +21,31 @@ export default class GroupNodeData extends Component {
|
|||
label: "",
|
||||
driversessions: [],
|
||||
propertyMap: {},
|
||||
displayMap: {"description":"Description","admincount":"Admin Count"},
|
||||
displayMap: {
|
||||
description: "Description",
|
||||
admincount: "Admin Count"
|
||||
},
|
||||
ServicePrincipalNames: [],
|
||||
notes: null
|
||||
notes: null,
|
||||
pics: [],
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
};
|
||||
|
||||
emitter.on("groupNodeClicked", this.getNodeData.bind(this));
|
||||
emitter.on("imageUploadFinal", this.uploadImage.bind(this));
|
||||
emitter.on("clickPhoto", this.openLightbox.bind(this));
|
||||
emitter.on("deletePhoto", this.handleDelete.bind(this));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
jQuery(this.refs.complete).hide();
|
||||
jQuery(this.refs.piccomplete).hide();
|
||||
}
|
||||
|
||||
getNodeData(payload) {
|
||||
jQuery(this.refs.complete).hide();
|
||||
$.each(this.state.driversessions, function(index, record) {
|
||||
$.each(this.state.driversessions, function(_, record) {
|
||||
record.close();
|
||||
});
|
||||
|
||||
|
@ -29,6 +53,15 @@ export default class GroupNodeData extends Component {
|
|||
label: payload
|
||||
});
|
||||
|
||||
let key = `group_${this.state.label}`;
|
||||
let c = imageconf.get(key);
|
||||
let pics = [];
|
||||
if (typeof c !== "undefined"){
|
||||
this.setState({pics: c})
|
||||
}else{
|
||||
this.setState({pics: pics})
|
||||
}
|
||||
|
||||
var propCollection = driver.session();
|
||||
propCollection
|
||||
.run("MATCH (c:Group {name:{name}}) RETURN c", { name: payload })
|
||||
|
@ -36,30 +69,42 @@ export default class GroupNodeData extends Component {
|
|||
function(result) {
|
||||
var properties = result.records[0]._fields[0].properties;
|
||||
let notes;
|
||||
if (!properties.notes){
|
||||
if (!properties.notes) {
|
||||
notes = null;
|
||||
}else{
|
||||
} else {
|
||||
notes = properties.notes;
|
||||
}
|
||||
this.setState({ propertyMap: properties, notes: notes });
|
||||
|
||||
this.setState({
|
||||
propertyMap: properties,
|
||||
notes: notes
|
||||
});
|
||||
propCollection.close();
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
notesChanged(event){
|
||||
this.setState({notes: event.target.value})
|
||||
notesChanged(event) {
|
||||
this.setState({ notes: event.target.value });
|
||||
}
|
||||
|
||||
notesBlur(event){
|
||||
let notes = this.state.notes === null || this.state.notes === "" ? null : this.state.notes;
|
||||
notesBlur(event) {
|
||||
let notes =
|
||||
this.state.notes === null || this.state.notes === ""
|
||||
? null
|
||||
: this.state.notes;
|
||||
let q = driver.session();
|
||||
if (notes === null){
|
||||
q.run("MATCH (n:Group {name:{name}}) REMOVE n.notes", {name: this.state.label}).then(x => {
|
||||
if (notes === null) {
|
||||
q.run("MATCH (n:Group {name:{name}}) REMOVE n.notes", {
|
||||
name: this.state.label
|
||||
}).then(x => {
|
||||
q.close();
|
||||
});
|
||||
}else{
|
||||
q.run("MATCH (n:Group {name:{name}}) SET n.notes = {notes}", {name: this.state.label, notes: this.state.notes}).then(x =>{
|
||||
} else {
|
||||
q.run("MATCH (n:Group {name:{name}}) SET n.notes = {notes}", {
|
||||
name: this.state.label,
|
||||
notes: this.state.notes
|
||||
}).then(x => {
|
||||
q.close();
|
||||
});
|
||||
}
|
||||
|
@ -68,7 +113,118 @@ export default class GroupNodeData extends Component {
|
|||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
uploadImage(files) {
|
||||
if (!this.props.visible || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let p = this.state.pics;
|
||||
let oLen = p.length;
|
||||
let key = `group_${this.state.label}`;
|
||||
|
||||
$.each(files, (_, f) => {
|
||||
let exists = false;
|
||||
let hash = md5File.sync(f.path);
|
||||
$.each(p, (_, p1) => {
|
||||
if (p1.hash === hash){
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
if (exists){
|
||||
emitter.emit("showAlert", "Image already exists");
|
||||
return;
|
||||
}
|
||||
let path = join(app.getPath("userData"), "images", hash);
|
||||
let dimensions = sizeOf(f.path);
|
||||
let data = readFileSync(f.path);
|
||||
writeFileSync(path, data);
|
||||
p.push({hash: hash, src: path, width: dimensions.width, height: dimensions.height})
|
||||
});
|
||||
|
||||
if (p.length === oLen){
|
||||
return;
|
||||
}
|
||||
this.setState({pics: p});
|
||||
imageconf.set(key, p)
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
handleDelete(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
let pics = this.state.pics;
|
||||
let temp = pics[event.index];
|
||||
pics.splice(event.index, 1);
|
||||
this.setState({
|
||||
pics: pics
|
||||
})
|
||||
let key = `group_${this.state.label}`;
|
||||
imageconf.set(key, pics);
|
||||
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
openLightbox(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: event.index,
|
||||
lightboxIsOpen: true
|
||||
});
|
||||
}
|
||||
closeLightbox() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
});
|
||||
}
|
||||
gotoPrevious() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage - 1
|
||||
});
|
||||
}
|
||||
gotoNext() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage + 1
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let gallery;
|
||||
if (this.state.pics.length === 0){
|
||||
gallery = (<span>Drop pictures on here to upload!</span>)
|
||||
}else{
|
||||
gallery = (
|
||||
<React.Fragment>
|
||||
<Gallery
|
||||
photos={this.state.pics}
|
||||
ImageComponent={SelectedImage}
|
||||
className={"gallerymod"}
|
||||
/>
|
||||
<Lightbox
|
||||
images={this.state.pics}
|
||||
isOpen={this.state.lightboxIsOpen}
|
||||
onClose={this.closeLightbox.bind(this)}
|
||||
onClickPrev={this.gotoPrevious.bind(this)}
|
||||
onClickNext={this.gotoNext.bind(this)}
|
||||
currentImage={this.state.currentImage}
|
||||
/>
|
||||
</React.Fragment>)
|
||||
}
|
||||
return (
|
||||
<div className={this.props.visible ? "" : "displaynone"}>
|
||||
<dl className="dl-horizontal">
|
||||
|
@ -253,7 +409,21 @@ export default class GroupNodeData extends Component {
|
|||
className="fa fa-check-circle green-icon-color notes-check-style"
|
||||
/>
|
||||
</div>
|
||||
<textarea onBlur={this.notesBlur.bind(this)} onChange={this.notesChanged.bind(this)} value={this.state.notes === null ? "" : this.state.notes} className={"node-notes-textarea"} ref="notes" />
|
||||
<textarea
|
||||
onBlur={this.notesBlur.bind(this)}
|
||||
onChange={this.notesChanged.bind(this)}
|
||||
value={this.state.notes === null ? "" : this.state.notes}
|
||||
className={"node-notes-textarea"}
|
||||
ref="notes"
|
||||
/>
|
||||
<div>
|
||||
<h4 className={"inline"}>Pictures</h4>
|
||||
<i
|
||||
ref="piccomplete"
|
||||
className="fa fa-check-circle green-icon-color notes-check-style"
|
||||
/>
|
||||
</div>
|
||||
{gallery}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,16 @@ import PropTypes from "prop-types";
|
|||
import NodeCypherLink from "./NodeCypherLink.jsx";
|
||||
import NodeCypherNoNumberLink from "./NodeCypherNoNumberLink";
|
||||
import NodeProps from "./NodeProps";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import SelectedImage from "./SelectedImage";
|
||||
import Lightbox from "react-images";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { base64Sync } from "base64-img";
|
||||
import sizeOf from "image-size";
|
||||
import md5File from "md5-file";
|
||||
import { remote } from "electron";
|
||||
const { app } = remote;
|
||||
import { join } from "path";
|
||||
|
||||
export default class OuNodeData extends Component {
|
||||
constructor() {
|
||||
|
@ -16,10 +26,21 @@ export default class OuNodeData extends Component {
|
|||
displayMap: {
|
||||
"description":"Description"
|
||||
},
|
||||
notes: null
|
||||
notes: null,
|
||||
pics: [],
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
};
|
||||
|
||||
emitter.on("ouNodeClicked", this.getNodeData.bind(this));
|
||||
emitter.on("imageUploadFinal", this.uploadImage.bind(this));
|
||||
emitter.on("clickPhoto", this.openLightbox.bind(this));
|
||||
emitter.on("deletePhoto", this.handleDelete.bind(this));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
jQuery(this.refs.complete).hide();
|
||||
jQuery(this.refs.piccomplete).hide();
|
||||
}
|
||||
|
||||
getNodeData(payload, guid, blocksInheritance) {
|
||||
|
@ -33,6 +54,15 @@ export default class OuNodeData extends Component {
|
|||
blocks: bi
|
||||
});
|
||||
|
||||
let key = `ou_${this.state.guid}`;
|
||||
let c = imageconf.get(key);
|
||||
let pics = [];
|
||||
if (typeof c !== "undefined"){
|
||||
this.setState({pics: c})
|
||||
}else{
|
||||
this.setState({pics: pics})
|
||||
}
|
||||
|
||||
let props = driver.session();
|
||||
props
|
||||
.run("MATCH (n:OU {guid:{name}}) RETURN n", { name: guid })
|
||||
|
@ -77,7 +107,119 @@ export default class OuNodeData extends Component {
|
|||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
uploadImage(files) {
|
||||
if (!this.props.visible || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let p = this.state.pics;
|
||||
let oLen = p.length;
|
||||
let key = `ou_${this.state.guid}`;
|
||||
|
||||
$.each(files, (_, f) => {
|
||||
let exists = false;
|
||||
let hash = md5File.sync(f.path);
|
||||
$.each(p, (_, p1) => {
|
||||
if (p1.hash === hash){
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
if (exists){
|
||||
emitter.emit("showAlert", "Image already exists");
|
||||
return;
|
||||
}
|
||||
let path = join(app.getPath("userData"), "images", hash);
|
||||
let dimensions = sizeOf(f.path);
|
||||
let data = readFileSync(f.path);
|
||||
writeFileSync(path, data);
|
||||
p.push({hash: hash, src: path, width: dimensions.width, height: dimensions.height})
|
||||
});
|
||||
|
||||
if (p.length === oLen){
|
||||
return;
|
||||
}
|
||||
this.setState({pics: p});
|
||||
imageconf.set(key, p)
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
handleDelete(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
let pics = this.state.pics;
|
||||
let temp = pics[event.index];
|
||||
pics.splice(event.index, 1);
|
||||
this.setState({
|
||||
pics: pics
|
||||
})
|
||||
let key = `ou_${this.state.guid}`;
|
||||
imageconf.set(key, pics);
|
||||
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
openLightbox(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: event.index,
|
||||
lightboxIsOpen: true
|
||||
});
|
||||
}
|
||||
closeLightbox() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
});
|
||||
}
|
||||
gotoPrevious() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage - 1
|
||||
});
|
||||
}
|
||||
gotoNext() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage + 1
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let gallery;
|
||||
if (this.state.pics.length === 0){
|
||||
gallery = (<span>Drop pictures on here to upload!</span>)
|
||||
}else{
|
||||
gallery = (
|
||||
<React.Fragment>
|
||||
<Gallery
|
||||
photos={this.state.pics}
|
||||
ImageComponent={SelectedImage}
|
||||
className={"gallerymod"}
|
||||
/>
|
||||
<Lightbox
|
||||
images={this.state.pics}
|
||||
isOpen={this.state.lightboxIsOpen}
|
||||
onClose={this.closeLightbox.bind(this)}
|
||||
onClickPrev={this.gotoPrevious.bind(this)}
|
||||
onClickNext={this.gotoNext.bind(this)}
|
||||
currentImage={this.state.currentImage}
|
||||
/>
|
||||
</React.Fragment>)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={this.props.visible ? "" : "displaynone"}>
|
||||
<dl className="dl-horizontal">
|
||||
|
@ -161,6 +303,14 @@ export default class OuNodeData extends Component {
|
|||
/>
|
||||
</div>
|
||||
<textarea onBlur={this.notesBlur.bind(this)} onChange={this.notesChanged.bind(this)} value={this.state.notes === null ? "" : this.state.notes} className={"node-notes-textarea"} ref="notes" />
|
||||
<div>
|
||||
<h4 className={"inline"}>Pictures</h4>
|
||||
<i
|
||||
ref="piccomplete"
|
||||
className="fa fa-check-circle green-icon-color notes-check-style"
|
||||
/>
|
||||
</div>
|
||||
{gallery}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -99,6 +99,15 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Shortest Paths to Unconstrained Delegation Systems",
|
||||
"queryList": [
|
||||
{
|
||||
"final": true,
|
||||
"query": "MATCH (m:Computer) WHERE m.unconstraineddelegation=true MATCH (n) MATCH p=shortestPath((n)-[r:{}*1..]->(m)) WHERE NOT m=n RETURN p"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Shortest Paths from Kerberoastable Users",
|
||||
"queryList": [
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import React, { Component } from "react";
|
||||
const {clipboard} = require('electron')
|
||||
|
||||
export default class SelectedImage extends Component {
|
||||
constructor(){
|
||||
super()
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
}
|
||||
|
||||
click(e, del){
|
||||
let o = {
|
||||
index: this.props.index,
|
||||
photo: this.props.photo
|
||||
}
|
||||
|
||||
if (del){
|
||||
emitter.emit("deletePhoto", o);
|
||||
}else{
|
||||
emitter.emit("clickPhoto", o);
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
let style = {
|
||||
margin: this.props.margin,
|
||||
cursor: "pointer",
|
||||
height: this.props.photo.height,
|
||||
width: this.props.photo.width,
|
||||
position: "relative"
|
||||
};
|
||||
|
||||
return (<div style={style} className="gallery-img">
|
||||
<i className="fa fa-copy" onClick={x => {emitter.emit("showAlert", "Copied file path to clipboard");clipboard.writeText(this.props.photo.src)}} />
|
||||
<i className="fa fa-trash-alt" onClick={e => this.click(e, true)} />
|
||||
<img className={"gallery-img"} onClick={e => this.click(e, false)} {...this.props.photo} style={style} />
|
||||
</div>);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,16 @@ import NodeProps from "./NodeProps";
|
|||
import NodeCypherLink from "./NodeCypherLink";
|
||||
import NodeCypherNoNumberLink from "./NodeCypherNoNumberLink";
|
||||
import NodeCypherLinkComplex from "./NodeCypherLinkComplex";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import SelectedImage from "./SelectedImage";
|
||||
import Lightbox from "react-images";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { base64Sync } from "base64-img";
|
||||
import sizeOf from "image-size";
|
||||
import md5File from "md5-file";
|
||||
import { remote } from "electron";
|
||||
const { app } = remote;
|
||||
import { join } from "path";
|
||||
|
||||
export default class UserNodeData extends Component {
|
||||
constructor() {
|
||||
|
@ -28,14 +38,111 @@ export default class UserNodeData extends Component {
|
|||
admincount: "AdminCount",
|
||||
owned: "Compromised"
|
||||
},
|
||||
notes: null
|
||||
notes: null,
|
||||
pics: [],
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
};
|
||||
|
||||
emitter.on("userNodeClicked", this.getNodeData.bind(this));
|
||||
emitter.on("imageUploadFinal", this.uploadImage.bind(this));
|
||||
emitter.on("clickPhoto", this.openLightbox.bind(this));
|
||||
emitter.on("deletePhoto", this.handleDelete.bind(this));
|
||||
}
|
||||
|
||||
uploadImage(files) {
|
||||
if (!this.props.visible || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let p = this.state.pics;
|
||||
let oLen = p.length;
|
||||
let key = `user_${this.state.label}`;
|
||||
|
||||
$.each(files, (_, f) => {
|
||||
let exists = false;
|
||||
let hash = md5File.sync(f.path);
|
||||
$.each(p, (_, p1) => {
|
||||
if (p1.hash === hash){
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
if (exists){
|
||||
emitter.emit("showAlert", "Image already exists");
|
||||
return;
|
||||
}
|
||||
let path = join(app.getPath("userData"), "images", hash);
|
||||
let dimensions = sizeOf(f.path);
|
||||
let data = readFileSync(f.path);
|
||||
writeFileSync(path, data);
|
||||
p.push({hash: hash, src: path, width: dimensions.width, height: dimensions.height})
|
||||
});
|
||||
|
||||
if (p.length === oLen){
|
||||
return;
|
||||
}
|
||||
this.setState({pics: p});
|
||||
imageconf.set(key, p)
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
handleDelete(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
let pics = this.state.pics;
|
||||
let temp = pics[event.index];
|
||||
pics.splice(event.index, 1);
|
||||
this.setState({
|
||||
pics: pics
|
||||
})
|
||||
let key = `user_${this.state.label}`;
|
||||
imageconf.set(key, pics);
|
||||
|
||||
let check = jQuery(this.refs.piccomplete);
|
||||
check.show();
|
||||
check.fadeOut(2000);
|
||||
}
|
||||
|
||||
openLightbox(event) {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: event.index,
|
||||
lightboxIsOpen: true
|
||||
});
|
||||
}
|
||||
closeLightbox() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: 0,
|
||||
lightboxIsOpen: false
|
||||
});
|
||||
}
|
||||
gotoPrevious() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage - 1
|
||||
});
|
||||
}
|
||||
gotoNext() {
|
||||
if (!this.props.visible) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
currentImage: this.state.currentImage + 1
|
||||
});
|
||||
}
|
||||
|
||||
getNodeData(payload) {
|
||||
jQuery(this.refs.complete).hide();
|
||||
jQuery(this.refs.piccomplete).hide();
|
||||
$.each(this.state.driversessions, function(index, record) {
|
||||
record.close();
|
||||
});
|
||||
|
@ -47,6 +154,15 @@ export default class UserNodeData extends Component {
|
|||
driversessions: []
|
||||
});
|
||||
|
||||
let key = `user_${this.state.label}`;
|
||||
let c = imageconf.get(key);
|
||||
let pics = [];
|
||||
if (typeof c !== "undefined"){
|
||||
this.setState({pics: c})
|
||||
}else{
|
||||
this.setState({pics: pics})
|
||||
}
|
||||
|
||||
var props = driver.session();
|
||||
props
|
||||
.run("MATCH (n:User {name:{name}}) RETURN n", { name: payload })
|
||||
|
@ -108,6 +224,29 @@ export default class UserNodeData extends Component {
|
|||
|
||||
render() {
|
||||
var domain = "@" + this.state.label.split("@").last();
|
||||
|
||||
let gallery;
|
||||
if (this.state.pics.length === 0){
|
||||
gallery = (<span>Drop pictures on here to upload!</span>)
|
||||
}else{
|
||||
gallery = (
|
||||
<React.Fragment>
|
||||
<Gallery
|
||||
photos={this.state.pics}
|
||||
ImageComponent={SelectedImage}
|
||||
className={"gallerymod"}
|
||||
/>
|
||||
<Lightbox
|
||||
images={this.state.pics}
|
||||
isOpen={this.state.lightboxIsOpen}
|
||||
onClose={this.closeLightbox.bind(this)}
|
||||
onClickPrev={this.gotoPrevious.bind(this)}
|
||||
onClickNext={this.gotoNext.bind(this)}
|
||||
currentImage={this.state.currentImage}
|
||||
/>
|
||||
</React.Fragment>)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={this.props.visible ? "" : "displaynone"}>
|
||||
<dl className="dl-horizontal">
|
||||
|
@ -292,6 +431,14 @@ export default class UserNodeData extends Component {
|
|||
/>
|
||||
</div>
|
||||
<textarea onBlur={this.notesBlur.bind(this)} onChange={this.notesChanged.bind(this)} value={this.state.notes === null ? "" : this.state.notes} className={"node-notes-textarea"} ref="notes" />
|
||||
<div>
|
||||
<h4 className={"inline"}>Pictures</h4>
|
||||
<i
|
||||
ref="piccomplete"
|
||||
className="fa fa-check-circle green-icon-color notes-check-style"
|
||||
/>
|
||||
</div>
|
||||
{gallery}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -740,6 +740,34 @@ div.tooltip-inner-custom {
|
|||
border-radius: 0;
|
||||
}
|
||||
|
||||
.react-photo-gallery--gallery{
|
||||
width: 99%;
|
||||
}
|
||||
|
||||
.gallery-img i:first-child{
|
||||
visibility: hidden;
|
||||
position:absolute;
|
||||
top:8px;
|
||||
right: 18px;
|
||||
z-index: 2;
|
||||
font-size: 15px;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.gallery-img i:nth-child(2){
|
||||
visibility: hidden;
|
||||
position:absolute;
|
||||
top:8px;
|
||||
right: 2px;
|
||||
z-index: 2;
|
||||
font-size: 15px;
|
||||
color: rgb(244, 65, 104)
|
||||
}
|
||||
|
||||
.gallery-img:hover i{
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.loadingIndicator {
|
||||
position: absolute;
|
||||
z-index: 25;
|
||||
|
@ -754,7 +782,7 @@ div.tooltip-inner-custom {
|
|||
}
|
||||
|
||||
.loadingIndicator img {
|
||||
width: 80px;
|
||||
width: 150px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
11
src/index.js
11
src/index.js
|
@ -7,18 +7,20 @@ import Login from "./components/Float/Login";
|
|||
|
||||
import { remote, shell } from "electron";
|
||||
const { app } = remote;
|
||||
import { stat, writeFile } from "fs";
|
||||
import { join } from "path";
|
||||
import { stat, writeFile, existsSync, mkdirSync } from "fs";
|
||||
|
||||
import ConfigStore from "electron-store";
|
||||
global.conf = new ConfigStore();
|
||||
global.imageconf = new ConfigStore({
|
||||
name: "images"
|
||||
})
|
||||
import { EventEmitter2 as e } from "eventemitter2";
|
||||
global.emitter = new e({});
|
||||
global.renderEmit = new e({});
|
||||
global.neo4j = require("neo4j-driver").v1;
|
||||
global.Mustache = require("mustache");
|
||||
|
||||
|
||||
//open links externally by default
|
||||
$(document).on('click', 'a[href^="http"]', function(event) {
|
||||
event.preventDefault();
|
||||
|
@ -292,6 +294,11 @@ stat(custompath, function(err, stats) {
|
|||
}
|
||||
});
|
||||
|
||||
let imagepath = join(app.getPath("userData"), "images");
|
||||
if (!existsSync(imagepath)){
|
||||
mkdirSync(imagepath)
|
||||
}
|
||||
|
||||
renderEmit.on("login", function() {
|
||||
emitter.removeAllListeners();
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("root"));
|
||||
|
|
Loading…
Reference in New Issue