From 43135c255d82aa7c54ea83b14369c93425ae75f6 Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Wed, 30 Sep 2020 13:29:04 +0200
Subject: Complete pcap page
---
frontend/src/components/Connection.js | 10 +-
frontend/src/components/ConnectionContent.js | 2 +-
.../components/filters/RulesConnectionsFilter.js | 2 +-
frontend/src/components/objects/LinkPopover.js | 2 +-
frontend/src/components/panels/PcapPane.js | 289 ++++++++++++---------
frontend/src/components/panels/PcapPane.scss | 25 +-
frontend/src/components/panels/RulePane.js | 6 +-
frontend/src/components/panels/common.scss | 16 ++
8 files changed, 209 insertions(+), 143 deletions(-)
(limited to 'frontend/src/components')
diff --git a/frontend/src/components/Connection.js b/frontend/src/components/Connection.js
index 7887185..95b27ff 100644
--- a/frontend/src/components/Connection.js
+++ b/frontend/src/components/Connection.js
@@ -2,7 +2,7 @@ import React, {Component} from 'react';
import './Connection.scss';
import {Form, OverlayTrigger, Popover} from "react-bootstrap";
import backend from "../backend";
-import {formatSize} from "../utils";
+import {durationBetween, formatSize} from "../utils";
import ButtonField from "./fields/ButtonField";
class Connection extends Component {
@@ -54,12 +54,6 @@ class Connection extends Component {
let startedAt = new Date(conn.started_at);
let closedAt = new Date(conn.closed_at);
let processedAt = new Date(conn.processed_at);
- let duration = ((closedAt - startedAt) / 1000).toFixed(3);
- if (duration > 1000 || duration < -1000) {
- duration = "∞";
- } else {
- duration += "s";
- }
let timeInfo =
Started at {startedAt.toLocaleDateString() + " " + startedAt.toLocaleTimeString()}
Processed at {processedAt.toLocaleDateString() + " " + processedAt.toLocaleTimeString()}
@@ -108,7 +102,7 @@ class Connection extends Component {
- {duration}
+ {durationBetween(startedAt, closedAt)}
|
{formatSize(conn.client_bytes)} |
diff --git a/frontend/src/components/ConnectionContent.js b/frontend/src/components/ConnectionContent.js
index a9d34d3..6bc0c96 100644
--- a/frontend/src/components/ConnectionContent.js
+++ b/frontend/src/components/ConnectionContent.js
@@ -40,7 +40,7 @@ class ConnectionContent extends Component {
loadStream = () => {
this.setState({loading: true});
// TODO: limit workaround.
- backend.getJson(`/api/streams/${this.props.connection.id}?format=${this.state.format}&limit=999999`).then(res => {
+ backend.get(`/api/streams/${this.props.connection.id}?format=${this.state.format}&limit=999999`).then(res => {
this.setState({
connectionContent: res.json,
loading: false
diff --git a/frontend/src/components/filters/RulesConnectionsFilter.js b/frontend/src/components/filters/RulesConnectionsFilter.js
index f4d0b1c..8366189 100644
--- a/frontend/src/components/filters/RulesConnectionsFilter.js
+++ b/frontend/src/components/filters/RulesConnectionsFilter.js
@@ -24,7 +24,7 @@ class RulesConnectionsFilter extends Component {
let params = new URLSearchParams(this.props.location.search);
let activeRules = params.getAll("matched_rules") || [];
- backend.getJson("/api/rules").then(res => {
+ backend.get("/api/rules").then(res => {
let rules = res.json.flatMap(rule => rule.enabled ? [{id: rule.id, name: rule.name}] : []);
activeRules = rules.filter(rule => activeRules.some(id => rule.id === id));
this.setState({rules, activeRules, mounted: true});
diff --git a/frontend/src/components/objects/LinkPopover.js b/frontend/src/components/objects/LinkPopover.js
index 58b2f6a..8768caa 100644
--- a/frontend/src/components/objects/LinkPopover.js
+++ b/frontend/src/components/objects/LinkPopover.js
@@ -22,7 +22,7 @@ class LinkPopover extends Component {
);
return (this.props.content ?
-
+
{this.props.text}
:
{this.props.text}
diff --git a/frontend/src/components/panels/PcapPane.js b/frontend/src/components/panels/PcapPane.js
index cfba037..e83e3da 100644
--- a/frontend/src/components/panels/PcapPane.js
+++ b/frontend/src/components/panels/PcapPane.js
@@ -1,14 +1,14 @@
import React, {Component} from 'react';
-// import './PcapPane.scss';
+import './PcapPane.scss';
import './common.scss';
import Table from "react-bootstrap/Table";
import backend from "../../backend";
-import {createCurlCommand, formatSize, timestampToTime2} from "../../utils";
-import {Col, Container, Row} from "react-bootstrap";
+import {createCurlCommand, dateTimeToTime, durationBetween, formatSize} from "../../utils";
import InputField from "../fields/InputField";
import CheckField from "../fields/CheckField";
import TextField from "../fields/TextField";
import ButtonField from "../fields/ButtonField";
+import LinkPopover from "../objects/LinkPopover";
class PcapPane extends Component {
@@ -19,16 +19,11 @@ class PcapPane extends Component {
sessions: [],
isUploadFileValid: true,
isUploadFileFocused: false,
- uploadSelectedFile: null,
uploadFlushAll: false,
- uploadStatusCode: null,
- uploadOutput: null,
isFileValid: true,
isFileFocused: false,
fileValue: "",
- fileFlushAll: false,
- fileStatusCode: null,
- fileOutput: null,
+ processFlushAll: false,
deleteOriginalFile: false
};
}
@@ -38,46 +33,38 @@ class PcapPane extends Component {
}
loadSessions = () => {
- backend.getJson("/api/pcap/sessions").then(res => this.setState({sessions: res.json}));
+ backend.get("/api/pcap/sessions")
+ .then(res => this.setState({sessions: res.json, sessionsStatusCode: res.status}))
+ .catch(res => this.setState({
+ sessions: res.json, sessionsStatusCode: res.status,
+ sessionsResponse: JSON.stringify(res.json)
+ }));
};
- handleUploadFileChange = (file) => {
- this.setState({
- isUploadFileValid: file != null && file.type.endsWith("pcap"),
- isUploadFileFocused: false,
- uploadSelectedFile: file
- });
- };
-
- handleUploadPcap = () => {
+ uploadPcap = () => {
if (this.state.uploadSelectedFile == null || !this.state.isUploadFileValid) {
this.setState({isUploadFileFocused: true});
return;
}
const formData = new FormData();
- formData.append(
- "file",
- this.state.uploadSelectedFile
- );
-
- backend.postFile("/api/pcap/upload", formData).then(response =>
- response.json().then(result => this.setState({
- uploadStatusCode: response.status + " " + response.statusText,
- uploadOutput: JSON.stringify(result)
- }))
+ formData.append("file", this.state.uploadSelectedFile);
+ formData.append("flush_all", this.state.uploadFlushAll);
+ backend.postFile("/api/pcap/upload", formData).then(res => {
+ this.setState({
+ uploadStatusCode: res.status,
+ uploadResponse: JSON.stringify(res.json)
+ });
+ this.resetUpload();
+ this.loadSessions();
+ }).catch(res => this.setState({
+ uploadStatusCode: res.status,
+ uploadResponse: JSON.stringify(res.json)
+ })
);
};
- handleFileChange = (file) => {
- this.setState({
- isFileValid: file !== "" && file.endsWith("pcap"),
- isFileFocused: false,
- fileValue: file
- });
- };
-
- handleProcessPcap = () => {
+ processPcap = () => {
if (this.state.fileValue === "" || !this.state.isFileValid) {
this.setState({isFileFocused: true});
return;
@@ -85,123 +72,177 @@ class PcapPane extends Component {
backend.post("/api/pcap/file", {
file: this.state.fileValue,
- flush_all: this.state.fileFlushAll,
+ flush_all: this.state.processFlushAll,
delete_original_file: this.state.deleteOriginalFile
- }).then(response =>
- response.json().then(result => this.setState({
- fileStatusCode: response.status + " " + response.statusText,
- fileOutput: JSON.stringify(result)
- }))
+ }).then(res => {
+ this.setState({
+ processStatusCode: res.status,
+ processResponse: JSON.stringify(res.json)
+ });
+ this.resetProcess();
+ this.loadSessions();
+ }).catch(res => this.setState({
+ processStatusCode: res.status,
+ processResponse: JSON.stringify(res.json)
+ })
);
};
+ resetUpload = () => {
+ this.setState({
+ isUploadFileValid: true,
+ isUploadFileFocused: false,
+ uploadFlushAll: false,
+ uploadSelectedFile: null
+ });
+ };
+
+ resetProcess = () => {
+ this.setState({
+ isFileValid: true,
+ isFileFocused: false,
+ fileValue: "",
+ processFlushAll: false,
+ deleteOriginalFile: false,
+ });
+ };
+
render() {
let sessions = this.state.sessions.map(s =>
{s["id"].substring(0, 8)} |
- {timestampToTime2(s["started_at"])} |
- {((new Date(s["completed_at"]) - new Date(s["started_at"])) / 1000).toFixed(3)}s |
+ {dateTimeToTime(s["started_at"])} |
+ {durationBetween(s["started_at"], s["completed_at"])} |
{formatSize(s["size"])} |
{s["processed_packets"]} |
{s["invalid_packets"]} |
- undefined |
+ |
download
|
);
- const uploadOutput = this.state.uploadOutput != null ? this.state.uploadOutput :
- createCurlCommand("pcap/upload", "POST", null, {
- file: "@" + ((this.state.uploadSelectedFile != null && this.state.isUploadFileValid) ? this.state.uploadSelectedFile.name :
- "invalid.pcap"),
- flush_all: this.state.uploadFlushAll
- })
- ;
+ const handleUploadFileChange = (file) => {
+ this.setState({
+ isUploadFileValid: file == null || (file.type.endsWith("pcap") || file.type.endsWith("pcapng")),
+ isUploadFileFocused: false,
+ uploadSelectedFile: file,
+ uploadStatusCode: null,
+ uploadResponse: null
+ });
+ };
+
+ const handleFileChange = (file) => {
+ this.setState({
+ isFileValid: (file.endsWith("pcap") || file.endsWith("pcapng")),
+ isFileFocused: false,
+ fileValue: file,
+ processStatusCode: null,
+ processResponse: null
+ });
+ };
+
+ const uploadCurlCommand = createCurlCommand("pcap/upload", "POST", null, {
+ file: "@" + ((this.state.uploadSelectedFile != null && this.state.isUploadFileValid) ?
+ this.state.uploadSelectedFile.name : "invalid.pcap"),
+ flush_all: this.state.uploadFlushAll
+ });
+
+ const fileCurlCommand = createCurlCommand("pcap/file", "POST", {
+ file: this.state.fileValue,
+ flush_all: this.state.processFlushAll,
+ delete_original_file: this.state.deleteOriginalFile
+ });
return (
-
-
+
+
GET /api/pcap/sessions
- 200 OK
+
-
-
-
-
- id |
- started_at |
- duration |
- size |
- processed_packets |
- invalid_packets |
- packets_per_service |
- actions |
-
-
-
- {sessions}
-
-
+
+
+
+
+
+ id |
+ started_at |
+ duration |
+ size |
+ processed_packets |
+ invalid_packets |
+ packets_per_service |
+ actions |
+
+
+
+ {sessions}
+
+
+
-
-
-
-
-
-
POST /api/pcap/upload
-
{this.state.uploadStatusCode}
+
+
+
+ POST /api/pcap/upload
+
+
+
+
+
+
+
+ options:
+ this.setState({uploadFlushAll: v})}/>
+
+
-
-
-
-
-
- options:
- this.setState({uploadFlushAll: v})}/>
-
-
-
-
-
-
-
+
+
+
-
-
-
POST /api/pcap/file
-
{this.state.fileStatusCode}
+
+
+ POST /api/pcap/file
+
+
+
+
+
+
+
+
+ this.setState({processFlushAll: v})}/>
+ this.setState({deleteOriginalFile: v})}/>
+
+
-
-
-
-
-
- this.setState({uploadFlushAll: v})}/>
- this.setState({uploadFlushAll: v})}/>
-
-
-
-
-
-
-
-
-
+
+
+
);
diff --git a/frontend/src/components/panels/PcapPane.scss b/frontend/src/components/panels/PcapPane.scss
index 3c4d10b..721560a 100644
--- a/frontend/src/components/panels/PcapPane.scss
+++ b/frontend/src/components/panels/PcapPane.scss
@@ -1,10 +1,25 @@
@import '../../colors.scss';
-.pane-container {
+.pcap-pane {
+ display: flex;
+ flex-direction: column;
- .table-cell-action {
- font-size: 13px;
- font-weight: 600;
+ .pcap-list {
+ flex: 1;
+ overflow: hidden;
+
+ .section-content {
+ height: 100%;
+ }
+
+ .section-table {
+ height: calc(100% - 30px);
+ }
+
+ .table-cell-action {
+ font-size: 13px;
+ font-weight: 600;
+ }
}
.upload-actions {
@@ -21,4 +36,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/frontend/src/components/panels/RulePane.js b/frontend/src/components/panels/RulePane.js
index 01e37fa..d4c5460 100644
--- a/frontend/src/components/panels/RulePane.js
+++ b/frontend/src/components/panels/RulePane.js
@@ -73,13 +73,13 @@ class RulePane extends Component {
};
loadRules = () => {
- backend.getJson("/api/rules").then(res => this.setState({rules: res.json, rulesStatusCode: res.status}))
+ 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)}));
};
addRule = () => {
if (this.validateRule(this.state.newRule)) {
- backend.postJson("/api/rules", this.state.newRule).then(res => {
+ backend.post("/api/rules", this.state.newRule).then(res => {
this.reset();
this.setState({ruleStatusCode: res.status});
this.loadRules();
@@ -92,7 +92,7 @@ class RulePane extends Component {
updateRule = () => {
const rule = this.state.selectedRule;
if (this.validateRule(rule)) {
- backend.putJson(`/api/rules/${rule.id}`, rule).then(res => {
+ backend.put(`/api/rules/${rule.id}`, rule).then(res => {
this.reset();
this.setState({ruleStatusCode: res.status});
this.loadRules();
diff --git a/frontend/src/components/panels/common.scss b/frontend/src/components/panels/common.scss
index cab0de1..ea8da94 100644
--- a/frontend/src/components/panels/common.scss
+++ b/frontend/src/components/panels/common.scss
@@ -82,4 +82,20 @@
margin-left: 10px;
}
}
+
+ .double-pane-container {
+ display: flex;
+
+ .pane-section {
+ flex: 1;
+ }
+
+ .pane-section:nth-child(1) {
+ margin-right: 5px;
+ }
+
+ .pane-section:nth-child(2) {
+ margin-left: 5px;
+ }
+ }
}
--
cgit v1.2.3-70-g09d2