Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Vulcanun/BloodHound into …
Browse files Browse the repository at this point in the history
…foss_vnext_prebuilt

� Conflicts:
�	package-lock.json
�	src/components/SearchContainer/Tabs/PrebuiltQueries.json
  • Loading branch information
rvazarkar committed Jan 18, 2022
2 parents edc778b + ee70d14 commit 63fbb24
Show file tree
Hide file tree
Showing 8 changed files with 937 additions and 170 deletions.
2 changes: 2 additions & 0 deletions src/AppContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { AppContext } from './AppContext';
import GraphErrorModal from './components/Modals/GraphErrorModal';
import MenuContainer from './components/Menu/MenuContainer';
import QueryCustomCreate from './components/Float/QueryCustomCreate';

const fullEdgeList = [
'CanRDP',
Expand Down Expand Up @@ -219,6 +220,7 @@ export default class AppContainer extends Component {
<NodeEditor />
<HelpModal />
<GraphErrorModal />
<QueryCustomCreate />
</div>
</AppContext.Provider>
</CSSTransition>
Expand Down
227 changes: 227 additions & 0 deletions src/components/Float/QueryCustomCreate.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
import React, { useEffect, useState, useContext } from 'react';
import PropTypes from 'prop-types';
import {
Panel,
Button,
FormControl,
ControlLabel,
FormGroup,
Form,
Col,
Checkbox,
Row
} from 'react-bootstrap';
import { Typeahead } from 'react-bootstrap-typeahead';
import styles from './QueryCustomCreate.module.css';
import Draggable from 'react-draggable';
import clsx from 'clsx';
import { AppContext } from '../../AppContext';
import PoseContainer from '../PoseContainer';
import { useDragControls } from 'framer-motion';

import { remote } from 'electron';
const { app } = remote;
import path from 'path';
import fs from 'fs';
import { select } from 'async';

const QueryCustomCreate = () => {
const [nodeCollapse, setNodeCollapse] = useState(appStore.performance.edge);
const [open, setOpen] = useState(false);
const [query, setQuery] = useState('');
const dragControl = useDragControls();
const [categories, setCategories] = useState([]);
const [singleSelections, setSingleSelections] = useState([]);
const [queryName, setQueryName] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');

const context = useContext(AppContext);

const handleOpen = () => {
setOpen(true);
};

const handleClose = () => {
setOpen(false);
};

const changeNodeCollapse = (e) => {
let val = parseInt(e.target.value);
setNodeCollapse(val);
appStore.performance.edge = val;
conf.set('performance', appStore.performance);
};

const edgeLabelChange = (e) => {
let val = parseInt(e.target.value);
context.setEdgeLabels(val);
};

const nodeLabelChange = (e) => {
let val = parseInt(e.target.value);
context.setNodeLabels(val);
};

const onKeyDown = (e) => {
let key = e.keyCode ? e.keyCode : e.which;

if (key === 13) {
emitter.emit('query', query);
}
};

const runQuery = () => {
emitter.emit('query', query);
}

const saveQuery = () => {

let filePath = path.join(
app.getPath('userData'),
'/customqueries.json'
);

fs.readFile(filePath, 'utf8', (err, data) => {
let j = JSON.parse(data);
j.queries.push({ "name": queryName, "category": selectedCategory, "queryList": [{ "final": true, "query": query, "allowColapse": true }] })
fs.writeFile(filePath, JSON.stringify(j, null, "\t"), function (err) { emitter.emit('updateCustomQueries'); })
});

setSingleSelections([]);
setSelectedCategory('');
setQueryName('');
setQuery('');
handleClose();
};

const onChange = (e) => {
setQuery(e.target.value);
};

const registerCategories = (e) => {
let tempCategories = categories;
for (var queryCategory in e) {
if (['last', 'chunk', 'allEdgesSameType'].includes(queryCategory) || categories.includes(queryCategory)) {
continue;
}
tempCategories.push(queryCategory);
}
setCategories(tempCategories);
}

useEffect(() => {
emitter.on('openQueryCreate', handleOpen);
emitter.on('registerQueryCategories', registerCategories);
return () => {
emitter.removeListener('openQueryCreate', handleOpen);
emitter.removeListener('registerQueryCategories', registerCategories);
};
}, []);

return (
<PoseContainer
visible={open}
className={clsx(
styles.container,
context.darkMode ? styles.dark : null
)}
dragHandle={dragControl}
>
<Panel
style={{ width: "800px" }}
>
<Panel.Heading
onMouseDown={(e) => {
dragControl.start(e);
}}
>
Create Custom Query
<Button
onClick={handleClose}
className='close'
aria-label='close'
>
<span aria-hidden='true'>&times;</span>
</Button>
</Panel.Heading>

<Panel.Body>
<FormGroup>
<Row>
<Col componentClass={ControlLabel} sm={6}>
<input
id='queryName'
type='text'
className={clsx(styles.input, 'form-control')}
value={queryName}
autoComplete='off'
placeholder='Name your query.'
onChange={event => setQueryName(event.target.value)}
/>
</Col>
<Col componentClass={ControlLabel} sm={1}>

</Col>
<Col componentClass={ControlLabel} sm={5}>
<Typeahead
placeholder='Select query category'
onChange={setSingleSelections}
options={categories}
selected={singleSelections}
maxHeight={100}
onBlur={event => setSelectedCategory(event.target.defaultValue)}
/>
</Col>
</Row>
</FormGroup>
<FormGroup>
<Row>
<Col componentClass={ControlLabel} sm={11}>
<input
type='text'
onKeyDown={onKeyDown}
onChange={onChange}
value={query}
className={clsx(styles.input, 'form-control')}
autoComplete='off'
placeholder='Enter a cypher query. Your query must return nodes or paths.'
/>
</Col>
<Col componentClass={ControlLabel} style={{ margin: "auto", cursor: "pointer"}} sm={1}>
<i class="fa fa-play fa-2x" onClick={runQuery}></i>
</Col>
</Row>
</FormGroup>
<FormGroup>
<Row>
<Col componentClass={ControlLabel} sm={2}>
<Button
onClick={handleClose}
>
Cancel
</Button>
</Col>
<Col componentClass={ControlLabel} sm={8}>

</Col>
<Col
componentClass={ControlLabel}
style={{"text-align": "right"}}
sm={2}
>
<Button
onClick={saveQuery}
>
Save
</Button>
</Col>
</Row>
</FormGroup>
</Panel.Body>
</Panel>
</PoseContainer>
);
};

QueryCustomCreate.propTypes = {};
export default QueryCustomCreate;
138 changes: 138 additions & 0 deletions src/components/Float/QueryCustomCreate.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
.inputWidth {
width: 6ch;
margin-right: 5px;
}

.glyphMargin {
margin-left: 5px;
}

.container :global {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
box-shadow: 0 5px 15px 0 black;
}

.container :global .panel {
margin-bottom: 0;
border: none;
overflow: hidden;
}

.container :global .panel-heading {
border: none;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
}

.dark :global .panel-heading {
background: #444b55;
font-family: Helvetica;
font-size: 20px;
font-weight: 400;
color: white;
}

.dark :global .panel-body {
background: #151d29;
color: white;
}

.dark :global button.close {
opacity: 1;
background-color: 151d29;
color: white;
}

.dark :global select {
background-color: #444b55;
font-family: Helvetica;
color: white;
border: none;
}

.dark :global input {
background-color: #444b55;
font-family: Helvetica;
font-weight: 400;
color: white;
border: none;
}

label {
font-family: Helvetica;
font-weight: 400 !important;
}

/* Below adapted from https://stackoverflow.com/a/24465732 */

#slider {
width: 400px;
height: 17px;
position: relative;
margin: 100px auto;
background: white;
}

#slider .bar {
width: 388px;
height: 5px;
background: #333;
position: relative;
top: 1px;
left: 1px;
}

#slider .highlight {
height: 2px;
position: absolute;
width: 388px;
top: 6px;
left: 6px;

-webkit-border-radius: 40px;
-moz-border-radius: 40px;
border-radius: 40px;

background: rgba(255, 255, 255, 0.25);
}

input[type='range'] {
-webkit-appearance: none;
background-color: #444b55;
height: 5px;
padding: 0px 0px;
}

input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
position: relative;
top: 0px;
z-index: 1;
width: 16px;
height: 16px;
cursor: pointer;
-webkit-border-radius: 40px;
-moz-border-radius: 40px;
border-radius: 40px;
background-color: #4f80a1;
}

input[type='range']:hover ~ #rangevalue,
input[type='range']:active ~ #rangevalue {
-ms-filter: 'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';
filter: alpha(opacity=100);
opacity: 1;
top: -75px;
}

input[type='range']:focus {
outline: none;
}

.slider {
top: 11px;
}
Loading

0 comments on commit 63fbb24

Please sign in to comment.