From d4bac2d6741f7a291522c29c9ecc87c3e32e21d4 Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Fri, 16 Oct 2020 14:16:44 +0200
Subject: Add notification when pcap have been processed
---
frontend/src/components/panels/ConnectionsPane.js | 107 +++++++++++-----------
frontend/src/components/panels/PcapsPane.js | 40 +++++---
frontend/src/components/panels/RulesPane.js | 51 ++++++-----
frontend/src/components/panels/SearchPane.js | 34 ++++---
frontend/src/components/panels/ServicesPane.js | 68 +++++++-------
5 files changed, 169 insertions(+), 131 deletions(-)
(limited to 'frontend/src/components/panels')
diff --git a/frontend/src/components/panels/ConnectionsPane.js b/frontend/src/components/panels/ConnectionsPane.js
index ea47059..23c6114 100644
--- a/frontend/src/components/panels/ConnectionsPane.js
+++ b/frontend/src/components/panels/ConnectionsPane.js
@@ -15,20 +15,20 @@
* along with this program. If not, see .
*/
-import React, {Component} from 'react';
-import './ConnectionsPane.scss';
-import Connection from "../objects/Connection";
-import Table from 'react-bootstrap/Table';
+import React, {Component} from "react";
+import Table from "react-bootstrap/Table";
+import {Redirect} from "react-router";
import {withRouter} from "react-router-dom";
import backend from "../../backend";
-import ConnectionMatchedRules from "../objects/ConnectionMatchedRules";
-import log from "../../log";
-import ButtonField from "../fields/ButtonField";
import dispatcher from "../../dispatcher";
-import {Redirect} from "react-router";
+import log from "../../log";
import {updateParams} from "../../utils";
+import ButtonField from "../fields/ButtonField";
+import Connection from "../objects/Connection";
+import ConnectionMatchedRules from "../objects/ConnectionMatchedRules";
+import "./ConnectionsPane.scss";
-const classNames = require('classnames');
+const classNames = require("classnames");
class ConnectionsPane extends Component {
@@ -67,55 +67,56 @@ class ConnectionsPane extends Component {
this.loadConnections(additionalParams, urlParams, true).then(() => log.debug("Connections loaded"));
- this.connectionsFiltersCallback = payload => {
- const newParams = updateParams(this.state.urlParams, payload);
- if (this.state.urlParams.toString() === newParams.toString()) {
- return;
- }
-
- log.debug("Update following url params:", payload);
- this.queryStringRedirect = true;
- this.setState({urlParams: newParams});
-
- this.loadConnections({limit: this.queryLimit}, newParams)
- .then(() => log.info("ConnectionsPane reloaded after query string update"));
- };
- dispatcher.register("connections_filters", this.connectionsFiltersCallback);
-
- this.timelineUpdatesCallback = payload => {
- this.connectionsListRef.current.scrollTop = 0;
- this.loadConnections({
- "started_after": Math.round(payload.from.getTime() / 1000),
- "started_before": Math.round(payload.to.getTime() / 1000),
- limit: this.maxConnections
- }).then(() => log.info(`Loading connections between ${payload.from} and ${payload.to}`));
- };
- dispatcher.register("timeline_updates", this.timelineUpdatesCallback);
-
- this.notificationsCallback = payload => {
- if (payload.event === "rules.new" || payload.event === "rules.edit") {
- this.loadRules().then(() => log.debug("Loaded connection rules after notification update"));
- }
- if (payload.event === "services.edit") {
- this.loadServices().then(() => log.debug("Services reloaded after notification update"));
- }
- };
- dispatcher.register("notifications", this.notificationsCallback);
-
- this.pulseConnectionsViewCallback = payload => {
- this.setState({pulseConnectionsView: true});
- setTimeout(() => this.setState({pulseConnectionsView: false}), payload.duration);
- };
- dispatcher.register("pulse_connections_view", this.pulseConnectionsViewCallback);
+ dispatcher.register("connections_filters", this.handleConnectionsFilters);
+ dispatcher.register("timeline_updates", this.handleTimelineUpdates);
+ dispatcher.register("notifications", this.handleNotifications);
+ dispatcher.register("pulse_connections_view", this.handlePulseConnectionsView);
}
componentWillUnmount() {
- dispatcher.unregister(this.timelineUpdatesCallback);
- dispatcher.unregister(this.notificationsCallback);
- dispatcher.unregister(this.pulseConnectionsViewCallback);
- dispatcher.unregister(this.connectionsFiltersCallback);
+ dispatcher.unregister(this.handleConnectionsFilters);
+ dispatcher.unregister(this.handleTimelineUpdates);
+ dispatcher.unregister(this.handleNotifications);
+ dispatcher.unregister(this.handlePulseConnectionsView);
}
+ handleConnectionsFilters = (payload) => {
+ const newParams = updateParams(this.state.urlParams, payload);
+ if (this.state.urlParams.toString() === newParams.toString()) {
+ return;
+ }
+
+ log.debug("Update following url params:", payload);
+ this.queryStringRedirect = true;
+ this.setState({urlParams: newParams});
+
+ this.loadConnections({limit: this.queryLimit}, newParams)
+ .then(() => log.info("ConnectionsPane reloaded after query string update"));
+ };
+
+ handleTimelineUpdates = (payload) => {
+ this.connectionsListRef.current.scrollTop = 0;
+ this.loadConnections({
+ "started_after": Math.round(payload.from.getTime() / 1000),
+ "started_before": Math.round(payload.to.getTime() / 1000),
+ limit: this.maxConnections
+ }).then(() => log.info(`Loading connections between ${payload.from} and ${payload.to}`));
+ };
+
+ handleNotifications = (payload) => {
+ if (payload.event === "rules.new" || payload.event === "rules.edit") {
+ this.loadRules().then(() => log.debug("Loaded connection rules after notification update"));
+ }
+ if (payload.event === "services.edit") {
+ this.loadServices().then(() => log.debug("Services reloaded after notification update"));
+ }
+ };
+
+ handlePulseConnectionsView = (payload) => {
+ this.setState({pulseConnectionsView: true});
+ setTimeout(() => this.setState({pulseConnectionsView: false}), payload.duration);
+ };
+
connectionSelected = (c) => {
this.connectionSelectedRedirect = true;
this.setState({selected: c.id});
diff --git a/frontend/src/components/panels/PcapsPane.js b/frontend/src/components/panels/PcapsPane.js
index fd3db75..64e7804 100644
--- a/frontend/src/components/panels/PcapsPane.js
+++ b/frontend/src/components/panels/PcapsPane.js
@@ -24,6 +24,7 @@ import ButtonField from "../fields/ButtonField";
import CheckField from "../fields/CheckField";
import InputField from "../fields/InputField";
import TextField from "../fields/TextField";
+import CopyLinkPopover from "../objects/CopyLinkPopover";
import LinkPopover from "../objects/LinkPopover";
import "./common.scss";
import "./PcapsPane.scss";
@@ -44,16 +45,20 @@ class PcapsPane extends Component {
componentDidMount() {
this.loadSessions();
-
- dispatcher.register("notifications", (payload) => {
- if (payload.event === "pcap.upload" || payload.event === "pcap.file") {
- this.loadSessions();
- }
- });
-
+ dispatcher.register("notifications", this.handleNotifications);
document.title = "caronte:~/pcaps$";
}
+ componentWillUnmount() {
+ dispatcher.unregister(this.handleNotifications);
+ }
+
+ handleNotifications = (payload) => {
+ if (payload.event.startsWith("pcap")) {
+ this.loadSessions();
+ }
+ };
+
loadSessions = () => {
backend.get("/api/pcap/sessions")
.then((res) => this.setState({sessions: res.json, sessionsStatusCode: res.status}))
@@ -130,10 +135,19 @@ class PcapsPane extends Component {
};
render() {
- let sessions = this.state.sessions.map((s) =>
-
- {s["id"].substring(0, 8)} |
- {dateTimeToTime(s["started_at"])} |
+ let sessions = this.state.sessions.map((s) => {
+ const startedAt = new Date(s["started_at"]);
+ const completedAt = new Date(s["completed_at"]);
+ let timeInfo =
+ Started at {startedAt.toLocaleDateString() + " " + startedAt.toLocaleTimeString()}
+ Completed at {completedAt.toLocaleDateString() + " " + completedAt.toLocaleTimeString()}
+
;
+
+ return
+ |
+
+
+ |
{durationBetween(s["started_at"], s["completed_at"])} |
{formatSize(s["size"])} |
{s["processed_packets"]} |
@@ -143,8 +157,8 @@ class PcapsPane extends Component {
placement="left"/>
download
|
-
- );
+ ;
+ });
const handleUploadFileChange = (file) => {
this.setState({
diff --git a/frontend/src/components/panels/RulesPane.js b/frontend/src/components/panels/RulesPane.js
index a66cde7..d872b47 100644
--- a/frontend/src/components/panels/RulesPane.js
+++ b/frontend/src/components/panels/RulesPane.js
@@ -15,26 +15,26 @@
* along with this program. If not, see .
*/
-import React, {Component} from 'react';
-import './common.scss';
-import './RulesPane.scss';
-import Table from "react-bootstrap/Table";
+import React, {Component} from "react";
import {Col, Container, Row} from "react-bootstrap";
-import InputField from "../fields/InputField";
-import CheckField from "../fields/CheckField";
-import TextField from "../fields/TextField";
+import Table from "react-bootstrap/Table";
import backend from "../../backend";
-import NumericField from "../fields/extensions/NumericField";
-import ColorField from "../fields/extensions/ColorField";
-import ChoiceField from "../fields/ChoiceField";
-import ButtonField from "../fields/ButtonField";
+import dispatcher from "../../dispatcher";
import validation from "../../validation";
+import ButtonField from "../fields/ButtonField";
+import CheckField from "../fields/CheckField";
+import ChoiceField from "../fields/ChoiceField";
+import ColorField from "../fields/extensions/ColorField";
+import NumericField from "../fields/extensions/NumericField";
+import InputField from "../fields/InputField";
+import TextField from "../fields/TextField";
+import CopyLinkPopover from "../objects/CopyLinkPopover";
import LinkPopover from "../objects/LinkPopover";
-import {randomClassName} from "../../utils";
-import dispatcher from "../../dispatcher";
+import "./common.scss";
+import "./RulesPane.scss";
-const classNames = require('classnames');
-const _ = require('lodash');
+const classNames = require("classnames");
+const _ = require("lodash");
class RulesPane extends Component {
@@ -88,15 +88,20 @@ class RulesPane extends Component {
this.reset();
this.loadRules();
- dispatcher.register("notifications", payload => {
- if (payload.event === "rules.new" || payload.event === "rules.edit") {
- this.loadRules();
- }
- });
-
+ dispatcher.register("notifications", this.handleNotifications);
document.title = "caronte:~/rules$";
}
+ componentWillUnmount() {
+ dispatcher.unregister(this.handleNotifications);
+ }
+
+ handleNotifications = (payload) => {
+ if (payload.event === "rules.new" || payload.event === "rules.edit") {
+ this.loadRules();
+ }
+ };
+
loadRules = () => {
backend.get("/api/rules").then(res => this.setState({rules: res.json, rulesStatusCode: res.status}))
.catch(res => this.setState({rulesStatusCode: res.status, rulesResponse: JSON.stringify(res.json)}));
@@ -249,7 +254,7 @@ class RulesPane extends Component {
this.reset();
this.setState({selectedRule: _.cloneDeep(r)});
}} className={classNames("row-small", "row-clickable", {"row-selected": rule.id === r.id})}>
- {r["id"].substring(0, 8)} |
+
{r["name"]} |
|
{r["notes"]} |
@@ -260,7 +265,7 @@ class RulesPane extends Component {
rule.patterns.concat(this.state.newPattern) :
rule.patterns
).map(p => p === pattern ?
-
+
{
diff --git a/frontend/src/components/panels/SearchPane.js b/frontend/src/components/panels/SearchPane.js
index d3c0c8b..d36e85e 100644
--- a/frontend/src/components/panels/SearchPane.js
+++ b/frontend/src/components/panels/SearchPane.js
@@ -60,15 +60,14 @@ class SearchPane extends Component {
this.reset();
this.loadSearches();
- dispatcher.register("notifications", payload => {
- if (payload.event === "searches.new") {
- this.loadSearches();
- }
- });
-
+ dispatcher.register("notifications", this.handleNotification);
document.title = "caronte:~/searches$";
}
+ componentWillUnmount() {
+ dispatcher.unregister(this.handleNotification);
+ }
+
loadSearches = () => {
backend.get("/api/searches")
.then(res => this.setState({searches: res.json, searchesStatusCode: res.status}))
@@ -77,14 +76,18 @@ class SearchPane extends Component {
performSearch = () => {
const options = this.state.currentSearchOptions;
+ this.setState({loading: true});
if (this.validateSearch(options)) {
backend.post("/api/searches/perform", options).then(res => {
this.reset();
- this.setState({searchStatusCode: res.status});
+ this.setState({searchStatusCode: res.status, loading: false});
this.loadSearches();
this.viewSearch(res.json.id);
}).catch(res => {
- this.setState({searchStatusCode: res.status, searchResponse: JSON.stringify(res.json)});
+ this.setState({
+ searchStatusCode: res.status, searchResponse: JSON.stringify(res.json),
+ loading: false
+ });
});
}
};
@@ -156,6 +159,12 @@ class SearchPane extends Component {
dispatcher.dispatch("connections_filters", {"performed_search": searchId});
};
+ handleNotification = (payload) => {
+ if (payload.event === "searches.new") {
+ this.loadSearches();
+ }
+ };
+
render() {
const options = this.state.currentSearchOptions;
@@ -263,7 +272,8 @@ class SearchPane extends Component {
onChange={v => this.updateParam(s => s["regex_search"]["not_pattern"] = v)}/>
- this.updateParam(s => s["regex_search"]["case_insensitive"] = v)}/>
-
-
+
+
diff --git a/frontend/src/components/panels/ServicesPane.js b/frontend/src/components/panels/ServicesPane.js
index bc82356..48d9e29 100644
--- a/frontend/src/components/panels/ServicesPane.js
+++ b/frontend/src/components/panels/ServicesPane.js
@@ -15,24 +15,24 @@
* along with this program. If not, see .
*/
-import React, {Component} from 'react';
-import './common.scss';
-import './ServicesPane.scss';
-import Table from "react-bootstrap/Table";
+import React, {Component} from "react";
import {Col, Container, Row} from "react-bootstrap";
-import InputField from "../fields/InputField";
-import TextField from "../fields/TextField";
+import Table from "react-bootstrap/Table";
import backend from "../../backend";
-import NumericField from "../fields/extensions/NumericField";
-import ColorField from "../fields/extensions/ColorField";
-import ButtonField from "../fields/ButtonField";
+import dispatcher from "../../dispatcher";
+import {createCurlCommand} from "../../utils";
import validation from "../../validation";
+import ButtonField from "../fields/ButtonField";
+import ColorField from "../fields/extensions/ColorField";
+import NumericField from "../fields/extensions/NumericField";
+import InputField from "../fields/InputField";
+import TextField from "../fields/TextField";
import LinkPopover from "../objects/LinkPopover";
-import {createCurlCommand} from "../../utils";
-import dispatcher from "../../dispatcher";
+import "./common.scss";
+import "./ServicesPane.scss";
-const classNames = require('classnames');
-const _ = require('lodash');
+const classNames = require("classnames");
+const _ = require("lodash");
class ServicesPane extends Component {
@@ -52,15 +52,20 @@ class ServicesPane extends Component {
this.reset();
this.loadServices();
- dispatcher.register("notifications", payload => {
- if (payload.event === "services.edit") {
- this.loadServices();
- }
- });
-
+ dispatcher.register("notifications", this.handleNotifications);
document.title = "caronte:~/services$";
}
+ componentWillUnmount() {
+ dispatcher.unregister(this.handleNotifications);
+ }
+
+ handleNotifications = (payload) => {
+ if (payload.event === "services.edit") {
+ this.loadServices();
+ }
+ };
+
loadServices = () => {
backend.get("/api/services")
.then(res => this.setState({services: Object.values(res.json), servicesStatusCode: res.status}))
@@ -125,10 +130,10 @@ class ServicesPane extends Component {
{
this.reset();
this.setState({isUpdate: true, currentService: _.cloneDeep(s)});
- }} className={classNames("row-small", "row-clickable", {"row-selected": service.port === s.port })}>
+ }} className={classNames("row-small", "row-clickable", {"row-selected": service.port === s.port})}>
{s["port"]} |
{s["name"]} |
- |
+ |
{s["notes"]} |
);
@@ -141,9 +146,9 @@ class ServicesPane extends Component {
GET /api/services
{this.state.servicesStatusCode &&
- }
+ }
@@ -170,7 +175,7 @@ class ServicesPane extends Component {
PUT /api/services
+ placement="left"/>
@@ -179,17 +184,17 @@ class ServicesPane extends Component {
this.updateParam((s) => s.port = v)}
- min={0} max={65565} error={this.state.servicePortError} />
+ min={0} max={65565} error={this.state.servicePortError}/>
this.updateParam((s) => s.name = v)}
- error={this.state.serviceNameError} />
+ error={this.state.serviceNameError}/>
this.updateParam((s) => s.color = v)} />
+ onChange={(v) => this.updateParam((s) => s.color = v)}/>
this.updateParam((s) => s.notes = v)} />
+ onChange={(v) => this.updateParam((s) => s.notes = v)}/>
@@ -199,8 +204,9 @@ class ServicesPane extends Component {
{}
-
+
--
cgit v1.2.3-70-g09d2
|