From d6e2aaad41f916c2080c59cf7b4e42bf87a1a03f Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Wed, 30 Sep 2020 22:57:25 +0200 Subject: Complete setup page --- frontend/src/views/App.js | 58 ++++----- frontend/src/views/App.scss | 15 +++ frontend/src/views/Config.js | 242 -------------------------------------- frontend/src/views/Config.scss | 55 --------- frontend/src/views/Connections.js | 42 ++++--- frontend/src/views/Filters.js | 1 - frontend/src/views/Header.js | 7 +- frontend/src/views/MainPane.js | 59 ---------- frontend/src/views/MainPane.scss | 6 - frontend/src/views/Services.js | 210 --------------------------------- frontend/src/views/Services.scss | 32 ----- 11 files changed, 67 insertions(+), 660 deletions(-) create mode 100644 frontend/src/views/App.scss delete mode 100644 frontend/src/views/Config.js delete mode 100644 frontend/src/views/Config.scss delete mode 100644 frontend/src/views/MainPane.js delete mode 100644 frontend/src/views/MainPane.scss delete mode 100644 frontend/src/views/Services.js delete mode 100644 frontend/src/views/Services.scss (limited to 'frontend/src/views') diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index 8bd5e46..fb4454c 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -1,62 +1,46 @@ import React, {Component} from 'react'; +import './App.scss'; import Header from "./Header"; -import MainPane from "./MainPane"; +import MainPane from "../components/panels/MainPane"; import Footer from "./Footer"; import {BrowserRouter as Router} from "react-router-dom"; -import Services from "./Services"; import Filters from "./Filters"; -import Config from "./Config"; +import backend from "../backend"; +import ConfigurationPane from "../components/panels/ConfigurationPane"; class App extends Component { constructor(props) { super(props); - this.state = { - servicesWindowOpen: false, - filterWindowOpen: false, - configWindowOpen: 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}); - } - }); + this.state = {}; + } + componentDidMount() { + backend.get("/api/services").then(_ => this.setState({configured: true})); } render() { let modal; - if (this.state.servicesWindowOpen) { - modal = this.setState({servicesWindowOpen: false})}/>; - } - if (this.state.filterWindowOpen) { + if (this.state.filterWindowOpen && this.state.configured) { modal = this.setState({filterWindowOpen: false})}/>; } - if (this.state.configWindowOpen) { - modal = this.setState({configWindowOpen: false})} - onDone={() => this.setState({configDone: true})}/>; - } return ( -
+
-
this.setState({servicesWindowOpen: true})} - onOpenFilters={() => this.setState({filterWindowOpen: true})} - onOpenConfig={() => this.setState({configWindowOpen: true})} - onOpenUpload={() => this.setState({uploadWindowOpen: true})} - onConfigDone={this.state.configDone} - /> - - {modal} -
+
+
this.setState({filterWindowOpen: true})} /> +
+
+ {this.state.configured ? : + this.setState({configured: true})} />} + {modal} +
+
+ {this.state.configured &&
} +
-
); } diff --git a/frontend/src/views/App.scss b/frontend/src/views/App.scss new file mode 100644 index 0000000..b25d4c9 --- /dev/null +++ b/frontend/src/views/App.scss @@ -0,0 +1,15 @@ + +.main { + display: flex; + flex-direction: column; + height: 100vh; + + .main-content { + flex: 1 1; + overflow: hidden; + } + + .main-header, .main-footer { + flex: 0 0; + } +} diff --git a/frontend/src/views/Config.js b/frontend/src/views/Config.js deleted file mode 100644 index b11f827..0000000 --- a/frontend/src/views/Config.js +++ /dev/null @@ -1,242 +0,0 @@ -import React, {Component} from 'react'; -import './Config.scss'; -import {Button, ButtonGroup, Col, Container, Form, Modal, Row, Table, ToggleButton} from "react-bootstrap"; - -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 - }) - }; - - 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 => - - {u} - - ); - - - - return ( - <> - - - - # passwd - - - - - -
- - username: - - - - - password: - - - - - confirm password: - - - - -
- -
- -
-
- - - - - -
- - - - ~/.config - - - - -
- - - - - - this.authRequiredChanged()} - > - Authentication - - - - - - - - - - - - {rows} - - -
users
- -
- - - - - - - -
- - server_address: - - - - - flag_regex: - - - -
- - - -
- -
- - {this.state.errors - .split('\n').map((item, key) => { - return {item}
}) - } -
-
-
- -
-
- - - - -
- - ); - } -} - -export default Config; diff --git a/frontend/src/views/Config.scss b/frontend/src/views/Config.scss deleted file mode 100644 index 331d7a7..0000000 --- a/frontend/src/views/Config.scss +++ /dev/null @@ -1,55 +0,0 @@ -@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/Connections.js b/frontend/src/views/Connections.js index 9dca7e9..73979c4 100644 --- a/frontend/src/views/Connections.js +++ b/frontend/src/views/Connections.js @@ -5,6 +5,7 @@ import Table from 'react-bootstrap/Table'; import {Redirect} from 'react-router'; import {withRouter} from "react-router-dom"; import backend from "../backend"; +import ConnectionMatchedRules from "../components/ConnectionMatchedRules"; class Connections extends Component { @@ -62,11 +63,21 @@ class Connections extends Component { }; addServicePortFilter = (port) => { - let urlParams = new URLSearchParams(this.props.location.search); + const urlParams = new URLSearchParams(this.props.location.search); urlParams.set("service_port", port); this.setState({queryString: "?" + urlParams}); }; + addMatchedRulesFilter = (matchedRule) => { + const urlParams = new URLSearchParams(this.props.location.search); + const oldMatchedRules = urlParams.getAll("matched_rules") || []; + + if (!oldMatchedRules.includes(matchedRule)) { + urlParams.append("matched_rules", matchedRule); + this.setState({queryString: "?" + urlParams}); + } + }; + async loadConnections(params) { let url = "/api/connections"; const urlParams = new URLSearchParams(this.props.location.search); @@ -112,20 +123,15 @@ class Connections extends Component { } } - let flagRule = this.state.flagRule; let rules = this.state.rules; - if (flagRule === null) { + if (rules === null) { rules = (await backend.get("/api/rules")).json; - flagRule = rules.filter(rule => { - return rule.name === "flag"; - })[0]; } this.setState({ loading: false, connections: connections, - rules: res, - flagRule: flagRule, + rules: rules, firstConnection: firstConnection, lastConnection: lastConnection }); @@ -158,6 +164,7 @@ class Connections extends Component { srcport dstip dstport + started_at duration up down @@ -166,13 +173,18 @@ class Connections extends Component { { - this.state.connections.map(c => - this.connectionSelected(c)} - selected={this.state.selected === c.id} onMarked={marked => c.marked = marked} - onEnabled={enabled => c.hidden = !enabled} - containsFlag={this.state.flagRule && c.matched_rules.includes(this.state.flagRule.id)} - addServicePortFilter={this.addServicePortFilter}/> - ) + this.state.connections.flatMap(c => { + return [ this.connectionSelected(c)} + selected={this.state.selected === c.id} + onMarked={marked => c.marked = marked} + onEnabled={enabled => c.hidden = !enabled} + addServicePortFilter={this.addServicePortFilter} />, + c.matched_rules.length > 0 && + + ]; + }) } {loading} diff --git a/frontend/src/views/Filters.js b/frontend/src/views/Filters.js index b62e7eb..ba7d467 100644 --- a/frontend/src/views/Filters.js +++ b/frontend/src/views/Filters.js @@ -1,5 +1,4 @@ import React, {Component} from 'react'; -import './Services.scss'; import {Col, Container, Modal, Row, Table} from "react-bootstrap"; import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions"; import ButtonField from "../components/fields/ButtonField"; diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js index c38c22d..944f1d5 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -46,7 +46,7 @@ class Header extends Component { render() { let quickFilters = filtersNames.filter(name => this.state[`${name}_active`]) - .map(name => filtersDefinitions[name]) + .map(name => {filtersDefinitions[name]}) .slice(0, 5); return ( @@ -78,8 +78,9 @@ class Header extends Component { - + + +
diff --git a/frontend/src/views/MainPane.js b/frontend/src/views/MainPane.js deleted file mode 100644 index d2950ab..0000000 --- a/frontend/src/views/MainPane.js +++ /dev/null @@ -1,59 +0,0 @@ -import React, {Component} from 'react'; -import './MainPane.scss'; -import Connections from "./Connections"; -import ConnectionContent from "../components/ConnectionContent"; -import {Route, Switch, withRouter} from "react-router-dom"; -import PcapPane from "../components/panels/PcapPane"; -import backend from "../backend"; -import RulePane from "../components/panels/RulePane"; -import ServicePane from "../components/panels/ServicePane"; - -class MainPane extends Component { - - constructor(props) { - super(props); - this.state = { - selectedConnection: null, - loading: false - }; - } - - componentDidMount() { - const match = this.props.location.pathname.match(/^\/connections\/([a-f0-9]{24})$/); - if (match != null) { - this.setState({loading: true}); - backend.get(`/api/connections/${match[1]}`) - .then(res => this.setState({selectedConnection: res.json, loading: false})) - .catch(error => console.log(error)); - } - } - - render() { - return ( -
-
-
-
- { - !this.state.loading && - this.setState({selectedConnection: c})} - initialConnection={this.state.selectedConnection} /> - } -
-
- - } /> - } /> - } /> - } /> - } /> - -
-
-
-
- ); - } -} - -export default withRouter(MainPane); diff --git a/frontend/src/views/MainPane.scss b/frontend/src/views/MainPane.scss deleted file mode 100644 index 20720ba..0000000 --- a/frontend/src/views/MainPane.scss +++ /dev/null @@ -1,6 +0,0 @@ -.main-pane { - .pane { - height: calc(100vh - 210px); - position: relative; - } -} diff --git a/frontend/src/views/Services.js b/frontend/src/views/Services.js deleted file mode 100644 index 97368dc..0000000 --- a/frontend/src/views/Services.js +++ /dev/null @@ -1,210 +0,0 @@ -import React, {Component} from 'react'; -import './Services.scss'; -import {Button, ButtonGroup, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap"; -import {createCurlCommand} from '../utils'; -import backend from "../backend"; - -class Services extends Component { - - constructor(props) { - super(props); - this.alphabet = 'abcdefghijklmnopqrstuvwxyz'; - this.colors = ["#E53935", "#D81B60", "#8E24AA", "#5E35B1", "#3949AB", "#1E88E5", "#039BE5", "#00ACC1", - "#00897B", "#43A047", "#7CB342", "#9E9D24", "#F9A825", "#FB8C00", "#F4511E", "#6D4C41"]; - - this.state = { - services: {}, - port: 0, - portValid: false, - name: "", - nameValid: false, - color: this.colors[0], - colorValid: false, - notes: "" - }; - - this.portChanged = this.portChanged.bind(this); - this.nameChanged = this.nameChanged.bind(this); - this.notesChanged = this.notesChanged.bind(this); - this.newService = this.newService.bind(this); - this.editService = this.editService.bind(this); - this.saveService = this.saveService.bind(this); - this.loadServices = this.loadServices.bind(this); - } - - componentDidMount() { - this.loadServices(); - } - - portChanged(event) { - let value = event.target.value.replace(/[^\d]/gi, ''); - let port = 0; - if (value !== "") { - port = parseInt(value); - } - this.setState({port: port}); - } - - nameChanged(event) { - let value = event.target.value.replace(/[\s]/gi, '_').replace(/[^\w]/gi, '').toLowerCase(); - this.setState({name: value}); - } - - notesChanged(event) { - this.setState({notes: event.target.value}); - } - - newService() { - this.setState({name: "", port: 0, notes: ""}); - } - - editService(service) { - this.setState({name: service.name, port: service.port, color: service.color, notes: service.notes}); - } - - saveService() { - if (this.state.portValid && this.state.nameValid) { - backend.put("/api/services", { - color: this.state.color, - name: this.state.name, - notes: this.state.notes, - port: this.state.port, - }).then(_ => { - this.newService(); - this.loadServices(); - }); - } - } - - loadServices() { - backend.get("/api/services").then(res => this.setState({services: res})); - } - - componentDidUpdate(prevProps, prevState, snapshot) { - if (this.state.name != null && prevState.name !== this.state.name) { - this.setState({ - nameValid: this.state.name.length >= 3 - }); - } - if (prevState.port !== this.state.port) { - this.setState({ - portValid: this.state.port > 0 && this.state.port <= 65565 - }); - } - } - - render() { - let output = ""; - if (!this.state.portValid) { - output += "assert(1 <= port <= 65565)\n"; - } - if (!this.state.nameValid) { - output += "assert(len(name) >= 3)\n"; - } - if (output === "") { - output = createCurlCommand("/services", "PUT", { - "port": this.state.port, - "name": this.state.name, - "color": this.state.color, - "notes": this.state.notes - }); - } - let rows = Object.values(this.state.services).map(s => - - - {s.port} - {s.name} - - ); - - let colorButtons = this.colors.map((color, i) => - ); - - return ( - - - - ~/services - - - - - - - - - - - - - - - - {rows} - -
portname
- - -
- - port: - - - - - name: - - - - - color: - - {colorButtons.slice(0, 8)} - - - {colorButtons.slice(8, 18)} - - - - - notes: - - -
- - - - -
- - - - - - - - - -
-
- - - - -
- ); - } -} - -export default Services; diff --git a/frontend/src/views/Services.scss b/frontend/src/views/Services.scss deleted file mode 100644 index 2abb55e..0000000 --- a/frontend/src/views/Services.scss +++ /dev/null @@ -1,32 +0,0 @@ -@import '../colors.scss'; - -.curl-output { - width: 100%; - font-size: 13px; -} - -.services-list { - .btn { - width: 70px; - } - - td { - background-color: $color-primary-2; - border-top: 2px solid $color-primary-0; - vertical-align: middle; - } - - th { - background-color: $color-primary-1; - } -} - -.btn-color { - border: 3px solid #fff; -} - -.dialog-footer { - .btn { - width: 80px; - } -} -- cgit v1.2.3-70-g09d2