diff options
Diffstat (limited to 'frontend/src/components/pages')
-rw-r--r-- | frontend/src/components/pages/ConfigurationPage.js | 179 | ||||
-rw-r--r-- | frontend/src/components/pages/ConfigurationPage.scss | 18 | ||||
-rw-r--r-- | frontend/src/components/pages/MainPage.js | 76 | ||||
-rw-r--r-- | frontend/src/components/pages/MainPage.scss | 24 | ||||
-rw-r--r-- | frontend/src/components/pages/ServiceUnavailablePage.js | 34 | ||||
-rw-r--r-- | frontend/src/components/pages/common.scss | 16 |
6 files changed, 347 insertions, 0 deletions
diff --git a/frontend/src/components/pages/ConfigurationPage.js b/frontend/src/components/pages/ConfigurationPage.js new file mode 100644 index 0000000..6ab8ae3 --- /dev/null +++ b/frontend/src/components/pages/ConfigurationPage.js @@ -0,0 +1,179 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from 'react'; +import '../panels/common.scss'; +import './ConfigurationPage.scss'; +import LinkPopover from "../objects/LinkPopover"; +import {Col, Container, Row} from "react-bootstrap"; +import InputField from "../fields/InputField"; +import TextField from "../fields/TextField"; +import ButtonField from "../fields/ButtonField"; +import CheckField from "../fields/CheckField"; +import {createCurlCommand} from "../../utils"; +import Table from "react-bootstrap/Table"; +import validation from "../../validation"; +import backend from "../../backend"; + +class ConfigurationPage extends Component { + + constructor(props) { + super(props); + this.state = { + settings: { + "config": { + "server_address": "", + "flag_regex": "", + "auth_required": false + }, + "accounts": { + } + }, + newUsername: "", + newPassword: "" + }; + } + + saveSettings = () => { + if (this.validateSettings(this.state.settings)) { + backend.post("/setup", this.state.settings).then(_ => { + this.props.onConfigured(); + }).catch(res => { + this.setState({setupStatusCode: res.status, setupResponse: JSON.stringify(res.json)}); + }); + } + }; + + validateSettings = (settings) => { + let valid = true; + if (!validation.isValidAddress(settings.config.server_address, true)) { + this.setState({serverAddressError: "invalid ip_address"}); + valid = false; + } + if (settings.config.flag_regex.length < 8) { + this.setState({flagRegexError: "flag_regex.length < 8"}); + valid = false; + } + + return valid; + }; + + updateParam = (callback) => { + callback(this.state.settings); + this.setState({settings: this.state.settings}); + }; + + addAccount = () => { + if (this.state.newUsername.length !== 0 && this.state.newPassword.length !== 0) { + const settings = this.state.settings; + settings.accounts[this.state.newUsername] = this.state.newPassword; + + this.setState({ + newUsername: "", + newPassword: "", + settings: settings + }); + } else { + this.setState({ + newUsernameActive: this.state.newUsername.length === 0, + newPasswordActive: this.state.newPassword.length === 0 + }); + } + }; + + render() { + const settings = this.state.settings; + const curlCommand = createCurlCommand("/setup", "POST", settings); + + const accounts = Object.entries(settings.accounts).map(([username, password]) => + <tr key={username}> + <td>{username}</td> + <td><LinkPopover text="******" content={password} /></td> + <td><ButtonField variant="red" small rounded name="delete" + onClick={() => this.updateParam((s) => delete s.accounts[username]) }/></td> + </tr>).concat(<tr key={"new_account"}> + <td><InputField value={this.state.newUsername} small active={this.state.newUsernameActive} + onChange={(v) => this.setState({newUsername: v})} /></td> + <td><InputField value={this.state.newPassword} small active={this.state.newPasswordActive} + onChange={(v) => this.setState({newPassword: v})} /></td> + <td><ButtonField variant="green" small rounded name="add" onClick={this.addAccount}/></td> + </tr>); + + return ( + <div className="configuration-page"> + <div className="pane"> + <div className="pane-container"> + <div className="pane-section"> + <div className="section-header"> + <span className="api-request">POST /setup</span> + <span className="api-response"><LinkPopover text={this.state.setupStatusCode} + content={this.state.setupResponse} + placement="left" /></span> + </div> + + <div className="section-content"> + <Container className="p-0"> + <Row> + <Col> + <InputField name="server_address" value={settings.config.server_address} + error={this.state.serverAddressError} + onChange={(v) => this.updateParam((s) => s.config.server_address = v)} /> + <InputField name="flag_regex" value={settings.config.flag_regex} + onChange={(v) => this.updateParam((s) => s.config.flag_regex = v)} + error={this.state.flagRegexError} /> + <div style={{"marginTop": "10px"}}> + <CheckField checked={settings.config.auth_required} name="auth_required" + onChange={(v) => this.updateParam((s) => s.config.auth_required = v)}/> + </div> + + </Col> + + <Col> + accounts: + <div className="section-table"> + <Table borderless size="sm"> + <thead> + <tr> + <th>username</th> + <th>password</th> + <th>actions</th> + </tr> + </thead> + <tbody> + {accounts} + </tbody> + </Table> + </div> + </Col> + </Row> + </Container> + + <TextField value={curlCommand} rows={4} readonly small={true}/> + </div> + + <div className="section-footer"> + <ButtonField variant="green" name="save" bordered onClick={this.saveSettings} /> + </div> + </div> + </div> + </div> + </div> + ); + } +} + +export default ConfigurationPage; diff --git a/frontend/src/components/pages/ConfigurationPage.scss b/frontend/src/components/pages/ConfigurationPage.scss new file mode 100644 index 0000000..4509865 --- /dev/null +++ b/frontend/src/components/pages/ConfigurationPage.scss @@ -0,0 +1,18 @@ +@import "../../colors"; + +.configuration-page { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + background-color: $color-primary-0; + + .pane { + flex-basis: 900px; + margin-bottom: 200px; + } + + .pane-container { + padding-bottom: 1px; + } +} diff --git a/frontend/src/components/pages/MainPage.js b/frontend/src/components/pages/MainPage.js new file mode 100644 index 0000000..7376091 --- /dev/null +++ b/frontend/src/components/pages/MainPage.js @@ -0,0 +1,76 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from 'react'; +import './MainPage.scss'; +import './common.scss'; +import Connections from "../panels/ConnectionsPane"; +import StreamsPane from "../panels/StreamsPane"; +import {BrowserRouter as Router, Route, Switch} from "react-router-dom"; +import Timeline from "../Timeline"; +import PcapsPane from "../panels/PcapsPane"; +import RulesPane from "../panels/RulesPane"; +import ServicesPane from "../panels/ServicesPane"; +import Header from "../Header"; +import Filters from "../dialogs/Filters"; +import MainPane from "../panels/MainPane"; + +class MainPage extends Component { + + state = {}; + + render() { + let modal; + if (this.state.filterWindowOpen) { + modal = <Filters onHide={() => this.setState({filterWindowOpen: false})}/>; + } + + return ( + <div className="page main-page"> + <Router> + <div className="page-header"> + <Header onOpenFilters={() => this.setState({filterWindowOpen: true})}/> + </div> + + <div className="page-content"> + <div className="pane connections-pane"> + <Connections onSelected={(c) => this.setState({selectedConnection: c})}/> + </div> + <div className="pane details-pane"> + <Switch> + <Route path="/pcaps" children={<PcapsPane/>}/> + <Route path="/rules" children={<RulesPane/>}/> + <Route path="/services" children={<ServicesPane/>}/> + <Route exact path="/connections/:id" + children={<StreamsPane connection={this.state.selectedConnection}/>}/> + <Route children={<MainPane/>}/> + </Switch> + </div> + + {modal} + </div> + + <div className="page-footer"> + <Timeline/> + </div> + </Router> + </div> + ); + } +} + +export default MainPage; diff --git a/frontend/src/components/pages/MainPage.scss b/frontend/src/components/pages/MainPage.scss new file mode 100644 index 0000000..3b1a689 --- /dev/null +++ b/frontend/src/components/pages/MainPage.scss @@ -0,0 +1,24 @@ +@import "../../colors"; + +.main-page { + .page-content { + display: flex; + flex: 1; + padding: 0 15px; + background-color: $color-primary-2; + + .connections-pane { + flex: 1 0; + margin-right: 7.5px; + } + + .details-pane { + flex: 1 1; + margin-left: 7.5px; + } + } + + .page-footer { + flex: 0; + } +} diff --git a/frontend/src/components/pages/ServiceUnavailablePage.js b/frontend/src/components/pages/ServiceUnavailablePage.js new file mode 100644 index 0000000..f27d84d --- /dev/null +++ b/frontend/src/components/pages/ServiceUnavailablePage.js @@ -0,0 +1,34 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from 'react'; +import './MainPage.scss'; + +class ServiceUnavailablePage extends Component { + + state = {}; + + render() { + return ( + <div className="main-page"> + + </div> + ); + } +} + +export default ServiceUnavailablePage; diff --git a/frontend/src/components/pages/common.scss b/frontend/src/components/pages/common.scss new file mode 100644 index 0000000..fcf5c20 --- /dev/null +++ b/frontend/src/components/pages/common.scss @@ -0,0 +1,16 @@ +.page { + position: relative; + display: flex; + flex-direction: column; + height: 100vh; + + .page-header, + .page-footer { + flex: 0; + } + + .page-content { + overflow: hidden; + flex: 1; + } +} |