aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiliano Ciavatta2020-10-08 20:17:04 +0000
committerEmiliano Ciavatta2020-10-08 20:17:04 +0000
commitd203f3c7e3bcaa20895c0f32f348cd1513ae9876 (patch)
treebc5beea659f6d1717a0e31b0ee10cde6699da2ad
parente1198433a63eec2c900ac8986dbf0ae7db16b777 (diff)
Frontend folder structure refactor
-rw-r--r--connection_streams_controller.go44
-rw-r--r--frontend/src/components/App.js (renamed from frontend/src/views/App.js)39
-rw-r--r--frontend/src/components/Header.js (renamed from frontend/src/views/Header.js)12
-rw-r--r--frontend/src/components/Header.scss (renamed from frontend/src/views/Header.scss)2
-rw-r--r--frontend/src/components/Timeline.js (renamed from frontend/src/views/Timeline.js)2
-rw-r--r--frontend/src/components/Timeline.scss (renamed from frontend/src/views/Timeline.scss)2
-rw-r--r--frontend/src/components/dialogs/Filters.js (renamed from frontend/src/views/Filters.js)4
-rw-r--r--frontend/src/components/objects/Connection.js (renamed from frontend/src/components/Connection.js)8
-rw-r--r--frontend/src/components/objects/Connection.scss (renamed from frontend/src/components/Connection.scss)2
-rw-r--r--frontend/src/components/objects/ConnectionMatchedRules.js (renamed from frontend/src/components/ConnectionMatchedRules.js)2
-rw-r--r--frontend/src/components/objects/ConnectionMatchedRules.scss (renamed from frontend/src/components/ConnectionMatchedRules.scss)2
-rw-r--r--frontend/src/components/objects/MessageAction.js (renamed from frontend/src/components/MessageAction.js)4
-rw-r--r--frontend/src/components/objects/MessageAction.scss (renamed from frontend/src/components/MessageAction.scss)2
-rw-r--r--frontend/src/components/pages/ConfigurationPage.js (renamed from frontend/src/components/panels/ConfigurationPane.js)10
-rw-r--r--frontend/src/components/pages/ConfigurationPage.scss (renamed from frontend/src/components/panels/ConfigurationPane.scss)2
-rw-r--r--frontend/src/components/pages/MainPage.js76
-rw-r--r--frontend/src/components/pages/MainPage.scss24
-rw-r--r--frontend/src/components/pages/ServiceUnavailablePage.js34
-rw-r--r--frontend/src/components/pages/common.scss16
-rw-r--r--frontend/src/components/panels/ConnectionsPane.js (renamed from frontend/src/views/Connections.js)59
-rw-r--r--frontend/src/components/panels/ConnectionsPane.scss (renamed from frontend/src/views/Connections.scss)2
-rw-r--r--frontend/src/components/panels/MainPane.js47
-rw-r--r--frontend/src/components/panels/MainPane.scss17
-rw-r--r--frontend/src/components/panels/PcapsPane.js (renamed from frontend/src/components/panels/PcapPane.js)6
-rw-r--r--frontend/src/components/panels/PcapsPane.scss (renamed from frontend/src/components/panels/PcapPane.scss)0
-rw-r--r--frontend/src/components/panels/RulesPane.js (renamed from frontend/src/components/panels/RulePane.js)6
-rw-r--r--frontend/src/components/panels/RulesPane.scss (renamed from frontend/src/components/panels/RulePane.scss)0
-rw-r--r--frontend/src/components/panels/ServicesPane.js (renamed from frontend/src/components/panels/ServicePane.js)6
-rw-r--r--frontend/src/components/panels/ServicesPane.scss (renamed from frontend/src/components/panels/ServicePane.scss)0
-rw-r--r--frontend/src/components/panels/StreamsPane.js (renamed from frontend/src/components/ConnectionContent.js)77
-rw-r--r--frontend/src/components/panels/StreamsPane.scss (renamed from frontend/src/components/ConnectionContent.scss)2
-rw-r--r--frontend/src/index.js2
-rw-r--r--frontend/src/views/App.scss16
33 files changed, 293 insertions, 234 deletions
diff --git a/connection_streams_controller.go b/connection_streams_controller.go
index 9251a3a..89e484d 100644
--- a/connection_streams_controller.go
+++ b/connection_streams_controller.go
@@ -28,8 +28,7 @@ import (
)
const (
- initialPayloadsSize = 1024
- defaultQueryFormatLimit = 8024
+ initialMessagesSize = 1024
initialRegexSlicesCount = 8
pwntoolsMaxServerBytes = 20
)
@@ -66,8 +65,6 @@ type RegexSlice struct {
type GetMessageFormat struct {
Format string `form:"format"`
- Skip uint64 `form:"skip"`
- Limit uint64 `form:"limit"`
}
type DownloadMessageFormat struct {
@@ -92,12 +89,8 @@ func (csc ConnectionStreamsController) GetConnectionMessages(c context.Context,
return nil, false
}
- payloads := make([]*Message, 0, initialPayloadsSize)
- var clientIndex, serverIndex, globalIndex uint64
-
- if format.Limit <= 0 {
- format.Limit = defaultQueryFormatLimit
- }
+ messages := make([]*Message, 0, initialMessagesSize)
+ var clientIndex, serverIndex uint64
var clientBlocksIndex, serverBlocksIndex int
var clientDocumentIndex, serverDocumentIndex int
@@ -111,8 +104,8 @@ func (csc ConnectionStreamsController) GetConnectionMessages(c context.Context,
return serverBlocksIndex < len(serverStream.BlocksIndexes)
}
- var payload *Message
- payloadsBuffer := make([]*Message, 0, 16)
+ var message *Message
+ messagesBuffer := make([]*Message, 0, 16)
contentChunkBuffer := new(bytes.Buffer)
var lastContentSlice []byte
var sideChanged, lastClient, lastServer bool
@@ -129,7 +122,7 @@ func (csc ConnectionStreamsController) GetConnectionMessages(c context.Context,
}
size := uint64(end - start)
- payload = &Message{
+ message = &Message{
FromClient: true,
Content: DecodeBytes(clientStream.Payload[start:end], format.Format),
Index: start,
@@ -138,7 +131,6 @@ func (csc ConnectionStreamsController) GetConnectionMessages(c context.Context,
RegexMatches: findMatchesBetween(clientStream.PatternMatches, clientIndex, clientIndex+size),
}
clientIndex += size
- globalIndex += size
clientBlocksIndex++
lastContentSlice = clientStream.Payload[start:end]
@@ -153,7 +145,7 @@ func (csc ConnectionStreamsController) GetConnectionMessages(c context.Context,
}
size := uint64(end - start)
- payload = &Message{
+ message = &Message{
FromClient: false,
Content: DecodeBytes(serverStream.Payload[start:end], format.Format),
Index: start,
@@ -162,7 +154,6 @@ func (csc ConnectionStreamsController) GetConnectionMessages(c context.Context,
RegexMatches: findMatchesBetween(serverStream.PatternMatches, serverIndex, serverIndex+size),
}
serverIndex += size
- globalIndex += size
serverBlocksIndex++
lastContentSlice = serverStream.Payload[start:end]
@@ -172,49 +163,43 @@ func (csc ConnectionStreamsController) GetConnectionMessages(c context.Context,
if !hasClientBlocks() {
clientDocumentIndex++
clientBlocksIndex = 0
+ clientIndex = 0
clientStream = csc.getConnectionStream(c, connectionID, true, clientDocumentIndex)
}
if !hasServerBlocks() {
serverDocumentIndex++
serverBlocksIndex = 0
+ serverIndex = 0
serverStream = csc.getConnectionStream(c, connectionID, false, serverDocumentIndex)
}
updateMetadata := func() {
metadata := parsers.Parse(contentChunkBuffer.Bytes())
var isMetadataContinuation bool
- for _, elem := range payloadsBuffer {
+ for _, elem := range messagesBuffer {
elem.Metadata = metadata
elem.IsMetadataContinuation = isMetadataContinuation
isMetadataContinuation = true
}
- payloadsBuffer = payloadsBuffer[:0]
+ messagesBuffer = messagesBuffer[:0]
contentChunkBuffer.Reset()
}
if sideChanged {
updateMetadata()
}
- payloadsBuffer = append(payloadsBuffer, payload)
+ messagesBuffer = append(messagesBuffer, message)
contentChunkBuffer.Write(lastContentSlice)
if clientStream.ID.IsZero() && serverStream.ID.IsZero() {
updateMetadata()
}
- if globalIndex > format.Skip {
- // problem: waste of time if the payload is discarded
- payloads = append(payloads, payload)
- }
- if globalIndex > format.Skip+format.Limit {
- // problem: the last chunk is not parsed, but can be ok because it is not finished
- updateMetadata()
- return payloads, true
- }
+ messages = append(messages, message)
}
- return payloads, true
+ return messages, true
}
func (csc ConnectionStreamsController) DownloadConnectionMessages(c context.Context, connectionID RowID,
@@ -345,7 +330,6 @@ func findMatchesBetween(patternMatches map[uint][]PatternSlice, from, to uint64)
continue
}
- log.Info(slice[0], slice[1], from, to)
var start, end uint64
if from > slice[0] {
start = 0
diff --git a/frontend/src/views/App.js b/frontend/src/components/App.js
index 8105117..bf959c5 100644
--- a/frontend/src/views/App.js
+++ b/frontend/src/components/App.js
@@ -16,15 +16,11 @@
*/
import React, {Component} from 'react';
-import './App.scss';
-import Header from "./Header";
-import MainPane from "../components/panels/MainPane";
-import Timeline from "./Timeline";
-import {BrowserRouter as Router} from "react-router-dom";
-import Filters from "./Filters";
-import ConfigurationPane from "../components/panels/ConfigurationPane";
-import Notifications from "../components/Notifications";
+import ConfigurationPage from "./pages/ConfigurationPage";
+import Notifications from "./Notifications";
import dispatcher from "../dispatcher";
+import MainPage from "./pages/MainPage";
+import ServiceUnavailablePage from "./pages/ServiceUnavailablePage";
class App extends Component {
@@ -50,30 +46,15 @@ class App extends Component {
}
render() {
- let modal;
- if (this.state.filterWindowOpen && this.state.configured) {
- modal = <Filters onHide={() => this.setState({filterWindowOpen: false})}/>;
- }
-
return (
- <div className="main">
+ <>
<Notifications/>
- {this.state.connected &&
- <Router>
- <div className="main-header">
- <Header onOpenFilters={() => this.setState({filterWindowOpen: true})}/>
- </div>
- <div className="main-content">
- {this.state.configured ? <MainPane/> :
- <ConfigurationPane onConfigured={() => this.setState({configured: true})}/>}
- {modal}
- </div>
- <div className="main-footer">
- {this.state.configured && <Timeline/>}
- </div>
- </Router>
+ {this.state.connected ?
+ (this.state.configured ? <MainPage/> :
+ <ConfigurationPage onConfigured={() => this.setState({configured: true})}/>) :
+ <ServiceUnavailablePage/>
}
- </div>
+ </>
);
}
}
diff --git a/frontend/src/views/Header.js b/frontend/src/components/Header.js
index 2cfe9fb..4d29364 100644
--- a/frontend/src/views/Header.js
+++ b/frontend/src/components/Header.js
@@ -18,9 +18,9 @@
import React, {Component} from 'react';
import Typed from 'typed.js';
import './Header.scss';
-import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions";
+import {filtersDefinitions, filtersNames} from "./filters/FiltersDefinitions";
import {Link, withRouter} from "react-router-dom";
-import ButtonField from "../components/fields/ButtonField";
+import ButtonField from "./fields/ButtonField";
class Header extends Component {
@@ -71,9 +71,11 @@ class Header extends Component {
<div className="row">
<div className="col-auto">
<h1 className="header-title type-wrap">
- <span style={{whiteSpace: 'pre'}} ref={(el) => {
- this.el = el;
- }}/>
+ <Link to="/">
+ <span style={{whiteSpace: 'pre'}} ref={(el) => {
+ this.el = el;
+ }}/>
+ </Link>
</h1>
</div>
diff --git a/frontend/src/views/Header.scss b/frontend/src/components/Header.scss
index 0711159..e2e8e1c 100644
--- a/frontend/src/views/Header.scss
+++ b/frontend/src/components/Header.scss
@@ -1,4 +1,4 @@
-@import "../colors.scss";
+@import "../colors";
.header {
height: 80px;
diff --git a/frontend/src/views/Timeline.js b/frontend/src/components/Timeline.js
index ebe3eb9..7be42e0 100644
--- a/frontend/src/views/Timeline.js
+++ b/frontend/src/components/Timeline.js
@@ -29,7 +29,7 @@ import {
} from "react-timeseries-charts";
import {TimeRange, TimeSeries} from "pondjs";
import backend from "../backend";
-import ChoiceField from "../components/fields/ChoiceField";
+import ChoiceField from "./fields/ChoiceField";
import {withRouter} from "react-router-dom";
import log from "../log";
import dispatcher from "../dispatcher";
diff --git a/frontend/src/views/Timeline.scss b/frontend/src/components/Timeline.scss
index 14360d4..eeb9d50 100644
--- a/frontend/src/views/Timeline.scss
+++ b/frontend/src/components/Timeline.scss
@@ -1,4 +1,4 @@
-@import "../colors.scss";
+@import "../colors";
.footer {
padding: 15px;
diff --git a/frontend/src/views/Filters.js b/frontend/src/components/dialogs/Filters.js
index 3dd8280..35c11df 100644
--- a/frontend/src/views/Filters.js
+++ b/frontend/src/components/dialogs/Filters.js
@@ -17,8 +17,8 @@
import React, {Component} from 'react';
import {Col, Container, Modal, Row, Table} from "react-bootstrap";
-import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions";
-import ButtonField from "../components/fields/ButtonField";
+import {filtersDefinitions, filtersNames} from "../filters/FiltersDefinitions";
+import ButtonField from "../fields/ButtonField";
class Filters extends Component {
diff --git a/frontend/src/components/Connection.js b/frontend/src/components/objects/Connection.js
index c7b0010..5e2beba 100644
--- a/frontend/src/components/Connection.js
+++ b/frontend/src/components/objects/Connection.js
@@ -18,10 +18,10 @@
import React, {Component} from 'react';
import './Connection.scss';
import {Form, OverlayTrigger, Popover} from "react-bootstrap";
-import backend from "../backend";
-import {dateTimeToTime, durationBetween, formatSize} from "../utils";
-import ButtonField from "./fields/ButtonField";
-import LinkPopover from "./objects/LinkPopover";
+import backend from "../../backend";
+import {dateTimeToTime, durationBetween, formatSize} from "../../utils";
+import ButtonField from "../fields/ButtonField";
+import LinkPopover from "./LinkPopover";
const classNames = require('classnames');
diff --git a/frontend/src/components/Connection.scss b/frontend/src/components/objects/Connection.scss
index cc1ea96..3b9f479 100644
--- a/frontend/src/components/Connection.scss
+++ b/frontend/src/components/objects/Connection.scss
@@ -1,4 +1,4 @@
-@import "../colors.scss";
+@import "../../colors";
.connection {
border-top: 3px solid $color-primary-3;
diff --git a/frontend/src/components/ConnectionMatchedRules.js b/frontend/src/components/objects/ConnectionMatchedRules.js
index 35643c5..73d5c5d 100644
--- a/frontend/src/components/ConnectionMatchedRules.js
+++ b/frontend/src/components/objects/ConnectionMatchedRules.js
@@ -17,7 +17,7 @@
import React, {Component} from 'react';
import './ConnectionMatchedRules.scss';
-import ButtonField from "./fields/ButtonField";
+import ButtonField from "../fields/ButtonField";
class ConnectionMatchedRules extends Component {
diff --git a/frontend/src/components/ConnectionMatchedRules.scss b/frontend/src/components/objects/ConnectionMatchedRules.scss
index 65d9ac8..f46a914 100644
--- a/frontend/src/components/ConnectionMatchedRules.scss
+++ b/frontend/src/components/objects/ConnectionMatchedRules.scss
@@ -1,4 +1,4 @@
-@import "../colors.scss";
+@import "../../colors";
.connection-matches {
background-color: $color-primary-0;
diff --git a/frontend/src/components/MessageAction.js b/frontend/src/components/objects/MessageAction.js
index b94cbb9..9f199b7 100644
--- a/frontend/src/components/MessageAction.js
+++ b/frontend/src/components/objects/MessageAction.js
@@ -18,8 +18,8 @@
import React, {Component} from 'react';
import './MessageAction.scss';
import {Modal} from "react-bootstrap";
-import TextField from "./fields/TextField";
-import ButtonField from "./fields/ButtonField";
+import TextField from "../fields/TextField";
+import ButtonField from "../fields/ButtonField";
class MessageAction extends Component {
diff --git a/frontend/src/components/MessageAction.scss b/frontend/src/components/objects/MessageAction.scss
index faa23d3..996007b 100644
--- a/frontend/src/components/MessageAction.scss
+++ b/frontend/src/components/objects/MessageAction.scss
@@ -1,4 +1,4 @@
-@import "../colors.scss";
+@import "../../colors";
.message-action-value {
font-size: 13px;
diff --git a/frontend/src/components/panels/ConfigurationPane.js b/frontend/src/components/pages/ConfigurationPage.js
index 9ae2cfb..6ab8ae3 100644
--- a/frontend/src/components/panels/ConfigurationPane.js
+++ b/frontend/src/components/pages/ConfigurationPage.js
@@ -16,8 +16,8 @@
*/
import React, {Component} from 'react';
-import './common.scss';
-import './ConfigurationPane.scss';
+import '../panels/common.scss';
+import './ConfigurationPage.scss';
import LinkPopover from "../objects/LinkPopover";
import {Col, Container, Row} from "react-bootstrap";
import InputField from "../fields/InputField";
@@ -29,7 +29,7 @@ import Table from "react-bootstrap/Table";
import validation from "../../validation";
import backend from "../../backend";
-class ConfigurationPane extends Component {
+class ConfigurationPage extends Component {
constructor(props) {
super(props);
@@ -114,7 +114,7 @@ class ConfigurationPane extends Component {
</tr>);
return (
- <div className="configuration-pane">
+ <div className="configuration-page">
<div className="pane">
<div className="pane-container">
<div className="pane-section">
@@ -176,4 +176,4 @@ class ConfigurationPane extends Component {
}
}
-export default ConfigurationPane;
+export default ConfigurationPage;
diff --git a/frontend/src/components/panels/ConfigurationPane.scss b/frontend/src/components/pages/ConfigurationPage.scss
index ef48b34..4509865 100644
--- a/frontend/src/components/panels/ConfigurationPane.scss
+++ b/frontend/src/components/pages/ConfigurationPage.scss
@@ -1,6 +1,6 @@
@import "../../colors";
-.configuration-pane {
+.configuration-page {
display: flex;
align-items: center;
justify-content: center;
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;
+ }
+}
diff --git a/frontend/src/views/Connections.js b/frontend/src/components/panels/ConnectionsPane.js
index b2edd3f..038ef8f 100644
--- a/frontend/src/views/Connections.js
+++ b/frontend/src/components/panels/ConnectionsPane.js
@@ -16,18 +16,18 @@
*/
import React, {Component} from 'react';
-import './Connections.scss';
-import Connection from "../components/Connection";
+import './ConnectionsPane.scss';
+import Connection from "../objects/Connection";
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";
-import log from "../log";
-import ButtonField from "../components/fields/ButtonField";
-import dispatcher from "../dispatcher";
+import backend from "../../backend";
+import ConnectionMatchedRules from "../objects/ConnectionMatchedRules";
+import log from "../../log";
+import ButtonField from "../fields/ButtonField";
+import dispatcher from "../../dispatcher";
-class Connections extends Component {
+class ConnectionsPane extends Component {
state = {
loading: false,
@@ -45,17 +45,22 @@ class Connections extends Component {
this.queryLimit = 50;
this.connectionsListRef = React.createRef();
this.lastScrollPosition = 0;
- this.doQueryStringRedirect = false;
- this.doSelectedConnectionRedirect = false;
}
componentDidMount() {
- this.loadConnections({limit: this.queryLimit})
- .then(() => this.setState({loaded: true}));
- if (this.props.initialConnection) {
- this.setState({selected: this.props.initialConnection.id});
+ const initialParams = {limit: this.queryLimit};
+
+ const match = this.props.location.pathname.match(/^\/connections\/([a-f0-9]{24})$/);
+ if (match != null) {
+ const id = match[1];
+ initialParams.from = id;
+ backend.get(`/api/connections/${id}`)
+ .then(res => this.connectionSelected(res.json, false))
+ .catch(error => log.error("Error loading initial connection", error));
}
+ this.loadConnections(initialParams, true).then(() => log.debug("Connections loaded"));
+
dispatcher.register("timeline_updates", payload => {
this.connectionsListRef.current.scrollTop = 0;
this.loadConnections({
@@ -78,16 +83,17 @@ class Connections extends Component {
});
}
- connectionSelected = (c) => {
- this.doSelectedConnectionRedirect = true;
+ connectionSelected = (c, doRedirect = true) => {
+ this.doSelectedConnectionRedirect = doRedirect;
this.setState({selected: c.id});
this.props.onSelected(c);
+ log.debug(`Connection ${c.id} selected`);
};
componentDidUpdate(prevProps, prevState, snapshot) {
- if (this.state.loaded && prevProps.location.search !== this.props.location.search) {
+ if (prevProps.location.search !== this.props.location.search) {
this.loadConnections({limit: this.queryLimit})
- .then(() => log.info("Connections reloaded after query string update"));
+ .then(() => log.info("ConnectionsPane reloaded after query string update"));
}
}
@@ -140,8 +146,7 @@ class Connections extends Component {
}
};
- async loadConnections(params) {
- let url = "/api/connections";
+ async loadConnections(params, isInitial = false) {
const urlParams = new URLSearchParams(this.props.location.search);
for (const [name, value] of Object.entries(params)) {
urlParams.set(name, value);
@@ -155,7 +160,7 @@ class Connections extends Component {
await this.loadServices();
}
- let res = (await backend.get(`${url}?${urlParams}`)).json;
+ let res = (await backend.get(`/api/connections?${urlParams}`)).json;
let connections = this.state.connections;
let firstConnection = this.state.firstConnection;
@@ -163,8 +168,14 @@ class Connections extends Component {
if (params !== undefined && params.from !== undefined && params.to === undefined) {
if (res.length > 0) {
- connections = this.state.connections.concat(res.slice(1));
+ if (!isInitial) {
+ res = res.slice(1);
+ }
+ connections = this.state.connections.concat(res);
lastConnection = connections[connections.length - 1];
+ if (isInitial) {
+ firstConnection = connections[0];
+ }
if (connections.length > this.maxConnections) {
connections = connections.slice(connections.length - this.maxConnections,
connections.length - 1);
@@ -228,7 +239,7 @@ class Connections extends Component {
let loading = null;
if (this.state.loading) {
loading = <tr>
- <td colSpan={9}>Loading...</td>
+ <td colSpan={10}>Loading...</td>
</tr>;
}
@@ -290,4 +301,4 @@ class Connections extends Component {
}
-export default withRouter(Connections);
+export default withRouter(ConnectionsPane);
diff --git a/frontend/src/views/Connections.scss b/frontend/src/components/panels/ConnectionsPane.scss
index de06096..06f5827 100644
--- a/frontend/src/views/Connections.scss
+++ b/frontend/src/components/panels/ConnectionsPane.scss
@@ -1,4 +1,4 @@
-@import "../colors.scss";
+@import "../../colors";
.connections-container {
position: relative;
diff --git a/frontend/src/components/panels/MainPane.js b/frontend/src/components/panels/MainPane.js
index d34d58a..74c859c 100644
--- a/frontend/src/components/panels/MainPane.js
+++ b/frontend/src/components/panels/MainPane.js
@@ -17,57 +17,22 @@
import React, {Component} from 'react';
import './common.scss';
-import './MainPane.scss';
-import Connections from "../../views/Connections";
-import ConnectionContent from "../ConnectionContent";
-import {Route, Switch, withRouter} from "react-router-dom";
-import PcapPane from "./PcapPane";
-import backend from "../../backend";
-import RulePane from "./RulePane";
-import ServicePane from "./ServicePane";
-import log from "../../log";
+import './ServicesPane.scss';
class MainPane extends Component {
state = {};
- componentDidMount() {
- const match = this.props.location.pathname.match(/^\/connections\/([a-f0-9]{24})$/);
- if (match != null) {
- this.loading = true;
- backend.get(`/api/connections/${match[1]}`)
- .then(res => {
- this.loading = false;
- this.setState({selectedConnection: res.json});
- log.debug(`Initial connection ${match[1]} loaded`);
- })
- .catch(error => log.error("Error loading initial connection", error));
- }
- }
-
render() {
return (
- <div className="main-pane">
- <div className="pane connections-pane">
- {
- !this.loading &&
- <Connections onSelected={(c) => this.setState({selectedConnection: c})}
- initialConnection={this.state.selectedConnection}/>
- }
- </div>
- <div className="pane details-pane">
- <Switch>
- <Route path="/pcaps" children={<PcapPane/>}/>
- <Route path="/rules" children={<RulePane/>}/>
- <Route path="/services" children={<ServicePane/>}/>
- <Route exact path="/connections/:id"
- children={<ConnectionContent connection={this.state.selectedConnection}/>}/>
- <Route children={<ConnectionContent/>}/>
- </Switch>
+ <div className="pane-container main-pane">
+ <div className="pane-section">
+ MainPane
</div>
</div>
);
}
+
}
-export default withRouter(MainPane);
+export default MainPane;
diff --git a/frontend/src/components/panels/MainPane.scss b/frontend/src/components/panels/MainPane.scss
index 2973c00..c8460f2 100644
--- a/frontend/src/components/panels/MainPane.scss
+++ b/frontend/src/components/panels/MainPane.scss
@@ -1,22 +1,5 @@
@import "../../colors";
.main-pane {
- display: flex;
- height: 100%;
- padding: 0 15px;
- background-color: $color-primary-2;
- .pane {
- flex: 1;
- }
-
- .connections-pane {
- flex: 1 0;
- margin-right: 7.5px;
- }
-
- .details-pane {
- flex: 1 1;
- margin-left: 7.5px;
- }
}
diff --git a/frontend/src/components/panels/PcapPane.js b/frontend/src/components/panels/PcapsPane.js
index d5c2225..8722230 100644
--- a/frontend/src/components/panels/PcapPane.js
+++ b/frontend/src/components/panels/PcapsPane.js
@@ -16,7 +16,7 @@
*/
import React, {Component} from 'react';
-import './PcapPane.scss';
+import './PcapsPane.scss';
import './common.scss';
import Table from "react-bootstrap/Table";
import backend from "../../backend";
@@ -28,7 +28,7 @@ import ButtonField from "../fields/ButtonField";
import LinkPopover from "../objects/LinkPopover";
import dispatcher from "../../dispatcher";
-class PcapPane extends Component {
+class PcapsPane extends Component {
state = {
sessions: [],
@@ -270,4 +270,4 @@ class PcapPane extends Component {
}
}
-export default PcapPane;
+export default PcapsPane;
diff --git a/frontend/src/components/panels/PcapPane.scss b/frontend/src/components/panels/PcapsPane.scss
index 4dbc2b2..4dbc2b2 100644
--- a/frontend/src/components/panels/PcapPane.scss
+++ b/frontend/src/components/panels/PcapsPane.scss
diff --git a/frontend/src/components/panels/RulePane.js b/frontend/src/components/panels/RulesPane.js
index 9913962..a66cde7 100644
--- a/frontend/src/components/panels/RulePane.js
+++ b/frontend/src/components/panels/RulesPane.js
@@ -17,7 +17,7 @@
import React, {Component} from 'react';
import './common.scss';
-import './RulePane.scss';
+import './RulesPane.scss';
import Table from "react-bootstrap/Table";
import {Col, Container, Row} from "react-bootstrap";
import InputField from "../fields/InputField";
@@ -36,7 +36,7 @@ import dispatcher from "../../dispatcher";
const classNames = require('classnames');
const _ = require('lodash');
-class RulePane extends Component {
+class RulesPane extends Component {
emptyRule = {
"name": "",
@@ -435,4 +435,4 @@ class RulePane extends Component {
}
-export default RulePane;
+export default RulesPane;
diff --git a/frontend/src/components/panels/RulePane.scss b/frontend/src/components/panels/RulesPane.scss
index 992445a..992445a 100644
--- a/frontend/src/components/panels/RulePane.scss
+++ b/frontend/src/components/panels/RulesPane.scss
diff --git a/frontend/src/components/panels/ServicePane.js b/frontend/src/components/panels/ServicesPane.js
index fc7004b..bc82356 100644
--- a/frontend/src/components/panels/ServicePane.js
+++ b/frontend/src/components/panels/ServicesPane.js
@@ -17,7 +17,7 @@
import React, {Component} from 'react';
import './common.scss';
-import './ServicePane.scss';
+import './ServicesPane.scss';
import Table from "react-bootstrap/Table";
import {Col, Container, Row} from "react-bootstrap";
import InputField from "../fields/InputField";
@@ -34,7 +34,7 @@ import dispatcher from "../../dispatcher";
const classNames = require('classnames');
const _ = require('lodash');
-class ServicePane extends Component {
+class ServicesPane extends Component {
emptyService = {
"port": 0,
@@ -209,4 +209,4 @@ class ServicePane extends Component {
}
-export default ServicePane;
+export default ServicesPane;
diff --git a/frontend/src/components/panels/ServicePane.scss b/frontend/src/components/panels/ServicesPane.scss
index daf7e79..daf7e79 100644
--- a/frontend/src/components/panels/ServicePane.scss
+++ b/frontend/src/components/panels/ServicesPane.scss
diff --git a/frontend/src/components/ConnectionContent.js b/frontend/src/components/panels/StreamsPane.js
index b468277..c8bd121 100644
--- a/frontend/src/components/ConnectionContent.js
+++ b/frontend/src/components/panels/StreamsPane.js
@@ -16,47 +16,47 @@
*/
import React, {Component} from 'react';
-import './ConnectionContent.scss';
+import './StreamsPane.scss';
import {Row} from 'react-bootstrap';
-import MessageAction from "./MessageAction";
-import backend from "../backend";
-import ButtonField from "./fields/ButtonField";
-import ChoiceField from "./fields/ChoiceField";
+import MessageAction from "../objects/MessageAction";
+import backend from "../../backend";
+import ButtonField from "../fields/ButtonField";
+import ChoiceField from "../fields/ChoiceField";
import DOMPurify from 'dompurify';
import ReactJson from 'react-json-view'
-import {downloadBlob, getHeaderValue} from "../utils";
-import log from "../log";
+import {downloadBlob, getHeaderValue} from "../../utils";
+import log from "../../log";
const classNames = require('classnames');
-class ConnectionContent extends Component {
+class StreamsPane extends Component {
+
+ state = {
+ messages: [],
+ format: "default",
+ tryParse: true
+ };
constructor(props) {
super(props);
- this.state = {
- loading: false,
- connectionContent: null,
- format: "default",
- tryParse: true,
- messageActionDialog: null
- };
this.validFormats = ["default", "hex", "hexdump", "base32", "base64", "ascii", "binary", "decimal", "octal"];
}
componentDidMount() {
- if (this.props.connection != null) {
- this.loadStream();
+ if (this.props.connection && this.state.currentId !== this.props.connection.id) {
+ this.setState({currentId: this.props.connection.id});
+ this.loadStream(this.props.connection.id);
}
document.title = "caronte:~/$";
}
componentDidUpdate(prevProps, prevState, snapshot) {
- if (this.props.connection != null && (
+ if (this.props.connection && (
this.props.connection !== prevProps.connection || this.state.format !== prevState.format)) {
this.closeRenderWindow();
- this.loadStream();
+ this.loadStream(this.props.connection.id);
}
}
@@ -64,15 +64,10 @@ class ConnectionContent extends Component {
this.closeRenderWindow();
}
- loadStream = () => {
- this.setState({loading: true});
- // TODO: limit workaround.
- backend.get(`/api/streams/${this.props.connection.id}?format=${this.state.format}&limit=999999`).then(res => {
- this.setState({
- connectionContent: res.json,
- loading: false
- });
- });
+ loadStream = (connectionId) => {
+ this.setState({messages: []});
+ backend.get(`/api/streams/${connectionId}?format=${this.state.format}`)
+ .then(res => this.setState({messages: res.json}));
};
setFormat = (format) => {
@@ -128,7 +123,7 @@ class ConnectionContent extends Component {
};
connectionsActions = (connectionMessage) => {
- if (connectionMessage.metadata == null) { //} || !connectionMessage.metadata["reproducers"]) {
+ if (!connectionMessage.metadata) {
return null;
}
@@ -169,9 +164,11 @@ class ConnectionContent extends Component {
};
downloadStreamRaw = (value) => {
- backend.download(`/api/streams/${this.props.connection.id}/download?format=${this.state.format}&type=${value}`)
- .then(res => downloadBlob(res.blob, `${this.props.connection.id}-${value}-${this.state.format}.txt`))
- .catch(_ => log.error("Failed to download stream messages"));
+ if (this.state.currentId) {
+ backend.download(`/api/streams/${this.props.connection.id}/download?format=${this.state.format}&type=${value}`)
+ .then(res => downloadBlob(res.blob, `${this.state.currentId}-${value}-${this.state.format}.txt`))
+ .catch(_ => log.error("Failed to download stream messages"));
+ }
};
closeRenderWindow = () => {
@@ -181,12 +178,14 @@ class ConnectionContent extends Component {
};
render() {
- const conn = this.props.connection;
- const content = this.state.connectionContent;
-
- if (content == null) {
- return <div>select a connection to view</div>;
- }
+ const conn = this.props.connection || {
+ "ip_src": "0.0.0.0",
+ "ip_dst": "0.0.0.0",
+ "port_src": "0",
+ "port_dst": "0",
+ "started_at": new Date().toISOString(),
+ };
+ const content = this.state.messages || [];
let payload = content.map((c, i) =>
<div key={`content-${i}`}
@@ -240,4 +239,4 @@ class ConnectionContent extends Component {
}
-export default ConnectionContent;
+export default StreamsPane;
diff --git a/frontend/src/components/ConnectionContent.scss b/frontend/src/components/panels/StreamsPane.scss
index f4edec9..d5510cf 100644
--- a/frontend/src/components/ConnectionContent.scss
+++ b/frontend/src/components/panels/StreamsPane.scss
@@ -1,4 +1,4 @@
-@import "../colors.scss";
+@import "../../colors";
.connection-content {
height: 100%;
diff --git a/frontend/src/index.js b/frontend/src/index.js
index e3e48de..ca1273a 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -19,7 +19,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css';
import './index.scss';
-import App from './views/App';
+import App from './components/App';
import * as serviceWorker from './serviceWorker';
import notifications from "./notifications";
diff --git a/frontend/src/views/App.scss b/frontend/src/views/App.scss
deleted file mode 100644
index 87661c3..0000000
--- a/frontend/src/views/App.scss
+++ /dev/null
@@ -1,16 +0,0 @@
-
-.main {
- display: flex;
- flex-direction: column;
- height: 100vh;
-
- .main-content {
- overflow: hidden;
- flex: 1 1;
- }
-
- .main-header,
- .main-footer {
- flex: 0 0;
- }
-}