aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontend/package.json1
-rw-r--r--frontend/public/favicon.icobin3150 -> 34239 bytes
-rw-r--r--frontend/public/logo192.pngbin5347 -> 34239 bytes
-rw-r--r--frontend/public/logo512.pngbin9664 -> 34239 bytes
-rw-r--r--frontend/src/views/App.js31
-rw-r--r--frontend/src/views/Config.js248
-rw-r--r--frontend/src/views/Config.scss55
-rw-r--r--frontend/src/views/Header.js8
-rw-r--r--frontend/src/views/Services.js23
-rw-r--r--frontend/src/views/Upload.js106
-rw-r--r--frontend/src/views/Upload.scss21
-rw-r--r--frontend/yarn.lock6
12 files changed, 487 insertions, 12 deletions
diff --git a/frontend/package.json b/frontend/package.json
index 661c2c4..bf995c5 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -11,6 +11,7 @@
"@testing-library/user-event": "^7.1.2",
"axios": "^0.19.2",
"bootstrap": "^4.4.1",
+ "bs-custom-file-input": "^1.3.4",
"classnames": "^2.2.6",
"eslint-config-react-app": "^5.2.1",
"node-sass": "^4.14.0",
diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico
index bcd5dfd..1dc499d 100644
--- a/frontend/public/favicon.ico
+++ b/frontend/public/favicon.ico
Binary files differ
diff --git a/frontend/public/logo192.png b/frontend/public/logo192.png
index fc44b0a..1dc499d 100644
--- a/frontend/public/logo192.png
+++ b/frontend/public/logo192.png
Binary files differ
diff --git a/frontend/public/logo512.png b/frontend/public/logo512.png
index a4e47a6..1dc499d 100644
--- a/frontend/public/logo512.png
+++ b/frontend/public/logo512.png
Binary files differ
diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js
index 6c101fa..ebead2f 100644
--- a/frontend/src/views/App.js
+++ b/frontend/src/views/App.js
@@ -6,6 +6,8 @@ import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import Services from "./Services";
import Filters from "./Filters";
import Rules from "./Rules";
+import Config from "./Config";
+import Upload from "./Upload";
class App extends Component {
@@ -14,8 +16,22 @@ class App extends Component {
this.state = {
servicesWindowOpen: false,
filterWindowOpen: false,
- rulesWindowOpen: false
+ rulesWindowOpen: false,
+ configWindowOpen: false,
+ uploadWindowOpen: false,
+ configDone: false
};
+
+ fetch('/api/services')
+ .then(response => {
+ if( response.status === 503){
+ this.setState({configWindowOpen: true});
+ } else if (response.status === 200){
+ this.setState({configDone: true});
+ }
+ });
+
+
}
render() {
@@ -29,13 +45,24 @@ class App extends Component {
if (this.state.rulesWindowOpen) {
modal = <Rules onHide={() => this.setState({rulesWindowOpen: false})}/>;
}
+ if (this.state.configWindowOpen) {
+ modal = <Config onHide={() => this.setState({configWindowOpen: false})}
+ onDone={() => this.setState({configDone: true})}/>;
+ }
+ if (this.state.uploadWindowOpen) {
+ modal = <Upload onHide={() => this.setState({uploadWindowOpen: false}) }/>;
+ }
return (
<div className="app">
<Router>
<Header onOpenServices={() => this.setState({servicesWindowOpen: true})}
onOpenFilters={() => this.setState({filterWindowOpen: true})}
- onOpenRules={() => this.setState({rulesWindowOpen: true})} />
+ onOpenRules={() => this.setState({rulesWindowOpen: true})}
+ onOpenConfig={() => this.setState({configWindowOpen: true})}
+ onOpenUpload={() => this.setState({uploadWindowOpen: true})}
+ onConfigDone={this.state.configDone}
+ />
<Switch>
<Route path="/connections/:id" children={<MainPane/>}/>
<Route path="/" children={<MainPane/>}/>
diff --git a/frontend/src/views/Config.js b/frontend/src/views/Config.js
new file mode 100644
index 0000000..f5766eb
--- /dev/null
+++ b/frontend/src/views/Config.js
@@ -0,0 +1,248 @@
+import {
+ validateIpAddress,
+} from "../utils";
+import React, {Component, useState} from 'react';
+import './Config.scss';
+import {Button, ButtonGroup, ToggleButton, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap";
+import {createCurlCommand} from '../utils';
+
+class Config extends Component {
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ server_address: "",
+ flag_regex: "",
+ auth_required: false,
+ accounts: {},
+ showSignup: false,
+ showConfig: true,
+ tmpUser:"",
+ tmpPass:"",
+ tmpConf:"",
+ errors:""
+ };
+
+ this.serverIpChanged = this.serverIpChanged.bind(this);
+ this.flagRegexChanged = this.flagRegexChanged.bind(this);
+ this.authRequiredChanged = this.authRequiredChanged.bind(this);
+ this.userChanged = this.userChanged.bind(this);
+ this.passwdChanged = this.passwdChanged.bind(this);
+ this.confirmChanged = this.confirmChanged.bind(this);
+ }
+
+ serverIpChanged(event) {
+ this.setState({server_address: event.target.value});
+ }
+
+ flagRegexChanged(event) {
+ this.setState({flag_regex: event.target.value});
+ }
+
+ authRequiredChanged() {
+ this.setState({auth_required: !this.value});
+ this.checked = !this.checked;
+ this.value = !this.value;
+ }
+
+ userChanged(event) {
+ this.setState({tmpUser: event.target.value});
+ }
+
+ passwdChanged(event) {
+ this.setState({tmpPass: event.target.value});
+ }
+
+ confirmChanged(event) {
+ this.setState({tmpConf: event.target.value});
+ }
+
+ setup() {
+ const requestOptions = {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ config: {
+ server_address: this.state.server_address,
+ flag_regex: this.state.flag_regex,
+ auth_required: this.state.auth_required,
+ },
+ accounts: this.state.accounts
+ })
+ };
+
+ let msg = "";
+
+ fetch('/setup', requestOptions)
+ .then(response => {
+ if (response.status === 202 ){
+ //this.setState({showConfig:false});
+ this.props.onHide();
+ this.props.onDone();
+ } else {
+ response.json().then(data => {
+ this.setState(
+ {errors : data.error.toString()}
+ );
+ });
+ }
+ }
+ );
+
+ }
+
+ signup(){
+ if (this.state.tmpPass === this.state.tmpConf){
+ const accounts = {...this.state.accounts};
+ accounts[this.state.tmpUser] = this.state.tmpPass;
+ this.setState({accounts});
+ console.log(this.state);
+ this.setState({showSignup:false,showConfig:true})
+ }
+ this.setState({tmpUser : ""});
+ this.setState({tmpPass : ""});
+ this.setState({tmpConf : ""});
+ }
+
+ render() {
+ let rows = Object.keys(this.state.accounts).map(u =>
+ <tr>
+ <td>{u}</td>
+ </tr>
+ );
+
+
+
+ return (
+ <>
+ <Modal show={this.state.showSignup} size="lg" aria-labelledby="services-dialog" centered >
+ <Modal.Header>
+ <Modal.Title id="services-dialog">
+ # passwd
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Container>
+ <Row>
+ <Form id="passwd-form">
+ <Form.Group controlId="username">
+ <Form.Label>username:</Form.Label>
+ <Form.Control type="text" onChange={this.userChanged} value={this.state.tmpUser}/>
+ </Form.Group>
+
+ <Form.Group controlId="password">
+ <Form.Label>password:</Form.Label>
+ <Form.Control type="password" onChange={this.passwdChanged} value={this.state.tmpPass}/>
+ </Form.Group>
+
+ <Form.Group controlId="confirmPassword">
+ <Form.Label>confirm password:</Form.Label>
+ <Form.Control type="password" onChange={this.confirmChanged} value={this.state.tmpConf}/>
+ </Form.Group>
+
+
+ </Form>
+
+ </Row>
+
+ </Container>
+ </Modal.Body>
+ <Modal.Footer className="dialog-footer">
+ <Button variant="green" onClick={() => this.signup()}>signup</Button>
+ <Button variant="red" onClick={() => this.setState({showSignup:false,showConfig:true})}>close</Button>
+ </Modal.Footer>
+
+ </Modal>
+ <Modal
+ {...this.props}
+ show="true"
+ size="lg"
+ aria-labelledby="services-dialog"
+ centered
+ >
+ <Modal.Header>
+ <Modal.Title id="services-dialog">
+ ~/.config
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <div class="blink"><span><b>Warning:</b></span> once the configuration is completed, it cannot be changed unless you reset caronte :(</div>
+ <hr/>
+ <Container>
+ <Row>
+ <Col md={5}>
+
+ <ButtonGroup toggle className="mb-2">
+ <ToggleButton
+ type="checkbox"
+ variant="secondary"
+ checked={this.state.auth_required}
+ value={this.state.auth_required}
+ onChange={() => this.authRequiredChanged()}
+ >
+ Authentication
+ </ToggleButton>
+ </ButtonGroup>
+
+ <Table borderless size="sm" className="users-list">
+
+ <thead>
+ <tr>
+ <th>users</th>
+ </tr>
+ </thead>
+ <tbody>
+ {rows}
+ <tr> <td>
+ <Button size="sm" onClick={() => this.setState({showSignup:true,showConfig:false})}>new</Button>
+ </td> </tr>
+ </tbody>
+ </Table>
+
+
+
+ </Col>
+
+ <Col md={7}>
+
+ <Form>
+ <Form.Group controlId="server_address">
+ <Form.Label>server_address:</Form.Label>
+ <Form.Control type="text" onChange={this.serverIpChanged} value={this.state.server_address}/>
+ </Form.Group>
+
+ <Form.Group controlId="flag_regex">
+ <Form.Label>flag_regex:</Form.Label>
+ <Form.Control type="text" onChange={this.flagRegexChanged} value={this.state.flag_regex}/>
+ </Form.Group>
+
+ </Form>
+
+ </Col>
+
+ </Row>
+ <Row>
+ <div class="error">
+ <b>
+ {this.state.errors
+ .split('\n').map((item, key) => {
+ return <span key={key}>{item}<br/></span>})
+ }
+ </b>
+ </div>
+ </Row>
+
+ </Container>
+ </Modal.Body>
+ <Modal.Footer className="dialog-footer">
+ <Button variant="green" onClick={() => this.setup()}>set</Button>
+ <Button variant="red" onClick={this.props.onHide}>close</Button>
+ </Modal.Footer>
+ </Modal>
+ </>
+ );
+ }
+}
+
+export default Config;
diff --git a/frontend/src/views/Config.scss b/frontend/src/views/Config.scss
new file mode 100644
index 0000000..331d7a7
--- /dev/null
+++ b/frontend/src/views/Config.scss
@@ -0,0 +1,55 @@
+@import '../colors.scss';
+
+.curl-output {
+ width: 100%;
+ font-size: 13px;
+}
+
+#passwd-form {
+ margin:auto;
+}
+
+.users-list {
+ .btn {
+ width: 70px;
+ }
+
+ td {
+ background-color: $color-primary-2;
+ border-top: 2px solid $color-primary-0;
+ vertical-align: middle;
+ text-align: center;
+ }
+
+ th {
+ background-color: $color-primary-1;
+ text-align: center;
+ }
+}
+
+.btn-color {
+ border: 3px solid #fff;
+}
+
+.dialog-footer {
+ .btn {
+ width: 80px;
+ }
+}
+
+.blink{
+
+ span{
+ animation: blink 1s linear infinite;
+ }
+ @keyframes blink{
+ 0%{opacity: 0;}
+ 50%{opacity: .5;}
+ 100%{opacity: 1;}
+ }
+
+}
+
+.error{
+ color: red;
+}
diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js
index 5d0f690..0af7abf 100644
--- a/frontend/src/views/Header.js
+++ b/frontend/src/views/Header.js
@@ -70,11 +70,11 @@ class Header extends Component {
<div className="col">
<div className="header-buttons">
<Button onClick={this.props.onOpenFilters}>filters</Button>
- <Button variant="yellow" size="sm">pcaps</Button>
+ <Button variant="warning" onClick={this.props.onOpenUpload}>pcaps</Button>
<Button variant="blue" onClick={this.props.onOpenRules}>rules</Button>
- <Button variant="red" onClick={this.props.onOpenServices}>
- services
- </Button>
+ <Button variant="red" onClick={this.props.onOpenServices}>services</Button>
+ <Button variant="green" onClick={this.props.onOpenConfig}
+ disabled={this.props.onConfigDone}>config</Button>
</div>
</div>
</div>
diff --git a/frontend/src/views/Services.js b/frontend/src/views/Services.js
index b95b01c..0de021f 100644
--- a/frontend/src/views/Services.js
+++ b/frontend/src/views/Services.js
@@ -64,12 +64,23 @@ class Services extends Component {
saveService() {
if (this.state.portValid && this.state.nameValid) {
- axios.put("/api/services", {
- name: this.state.name,
- port: this.state.port,
- color: this.state.color,
- notes: this.state.notes
- });
+ const requestOptions = {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ color: this.state.color,
+ name: this.state.name,
+ notes: this.state.notes,
+ port: this.state.port,
+ })
+ };
+
+
+ fetch('/api/services', requestOptions)
+ .then(function(response){
+ console.log(response);
+ }
+ );
this.newService();
this.loadServices();
diff --git a/frontend/src/views/Upload.js b/frontend/src/views/Upload.js
new file mode 100644
index 0000000..522afe8
--- /dev/null
+++ b/frontend/src/views/Upload.js
@@ -0,0 +1,106 @@
+import React, {Component} from 'react';
+import './Upload.scss';
+import {Button, ButtonGroup, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap";
+import bsCustomFileInput from 'bs-custom-file-input'
+import {createCurlCommand} from '../utils';
+
+class Upload extends Component {
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ selectedFile: null,
+ errors: ""
+ };
+
+ }
+
+ onFileChange = event => {
+ this.setState({ selectedFile: event.target.files[0] });
+
+ };
+
+ componentDidMount() {
+ bsCustomFileInput.init()
+ }
+
+ onFileUpload = () => {
+ const formData = new FormData();
+ formData.append(
+ "file",
+ this.state.selectedFile,
+ this.state.selectedFile.name
+ );
+ fetch('/api/pcap/upload', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => {
+ if (response.status === 202 ){
+ //this.setState({showConfig:false});
+ this.props.onHide();
+ //this.props.onDone();
+ } else {
+ response.json().then(data => {
+ this.setState(
+ {errors : data.error.toString()}
+ );
+ });
+ }
+ }
+ );
+ }
+
+
+ render() {
+
+ return (
+ <Modal
+ {...this.props}
+ show="true"
+ size="lg"
+ aria-labelledby="services-dialog"
+ centered
+ >
+ <Modal.Header>
+ <Modal.Title id="services-dialog">
+ /usr/bin/upload
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Container>
+ <Row>
+ <Form.File
+ type="file"
+ className="custom-file"
+ onChange={this.onFileChange}
+ label=".pcap/.pcapng"
+ id="custom-file"
+ custom
+ />
+ </Row>
+ <Row>
+ <div class="error">
+ <b>
+ <br/>
+ {this.state.errors
+ .split('\n').map((item, key) => {
+ return <span key={key}>{item}<br/></span>})
+ }
+ </b>
+ </div>
+ </Row>
+ </Container>
+ </Modal.Body>
+ <Modal.Footer className="dialog-footer">
+
+ <Button variant="green" onClick={this.onFileUpload}>upload</Button>
+ <Button variant="red" onClick={this.props.onHide}>close</Button>
+ </Modal.Footer>
+ </Modal>
+ );
+ }
+}
+
+export default Upload;
diff --git a/frontend/src/views/Upload.scss b/frontend/src/views/Upload.scss
new file mode 100644
index 0000000..e327b8c
--- /dev/null
+++ b/frontend/src/views/Upload.scss
@@ -0,0 +1,21 @@
+@import '../colors.scss';
+
+.curl-output {
+ width: 100%;
+ font-size: 13px;
+}
+
+#pcap-upload{
+ align: center;
+ width: 100%;
+}
+
+.btn-color {
+ border: 3px solid #fff;
+}
+
+.dialog-footer {
+ .btn {
+ width: 80px;
+ }
+}
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index b7fc583..39d346b 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -2801,6 +2801,12 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.6.2, browserslist@^4.
escalade "^3.0.2"
node-releases "^1.1.61"
+bs-custom-file-input@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/bs-custom-file-input/-/bs-custom-file-input-1.3.4.tgz#c275cb8d4f1c02ba026324292509fa9a747dbda8"
+ integrity sha512-NBsQzTnef3OW1MvdKBbMHAYHssCd613MSeJV7z2McXznWtVMnJCy7Ckyc+PwxV6Pk16cu6YBcYWh/ZE0XWNKCA==
+>>>>>>> 98355cdf838d8c18e9a28176ae7a847770545395
+
bser@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"