aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components/objects
diff options
context:
space:
mode:
authorEmiliano Ciavatta2020-10-16 17:06:05 +0000
committerEmiliano Ciavatta2020-10-16 17:06:05 +0000
commit56f70a72196c777f248038bb2e2e4099e6e1367d (patch)
tree714ad5aed8698dfffbb472b3fa74909acb8cdead /frontend/src/components/objects
parent6204c99e69d1707a79c5e56685b47310106c60b0 (diff)
parent79b8b2fa3e8563c986da8baa3a761f2d4f0c6f47 (diff)
Merge branch 'develop'
Diffstat (limited to 'frontend/src/components/objects')
-rw-r--r--frontend/src/components/objects/Connection.js114
-rw-r--r--frontend/src/components/objects/Connection.scss72
-rw-r--r--frontend/src/components/objects/ConnectionMatchedRules.js51
-rw-r--r--frontend/src/components/objects/ConnectionMatchedRules.scss23
-rw-r--r--frontend/src/components/objects/CopyLinkPopover.js54
-rw-r--r--frontend/src/components/objects/LinkPopover.js32
-rw-r--r--frontend/src/components/objects/LinkPopover.scss5
-rw-r--r--frontend/src/components/objects/MessageAction.js69
-rw-r--r--frontend/src/components/objects/MessageAction.scss8
9 files changed, 421 insertions, 7 deletions
diff --git a/frontend/src/components/objects/Connection.js b/frontend/src/components/objects/Connection.js
new file mode 100644
index 0000000..b70b7f7
--- /dev/null
+++ b/frontend/src/components/objects/Connection.js
@@ -0,0 +1,114 @@
+/*
+ * 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 {Form} from "react-bootstrap";
+import backend from "../../backend";
+import dispatcher from "../../dispatcher";
+import {dateTimeToTime, durationBetween, formatSize} from "../../utils";
+import ButtonField from "../fields/ButtonField";
+import "./Connection.scss";
+import CopyLinkPopover from "./CopyLinkPopover";
+import LinkPopover from "./LinkPopover";
+
+const classNames = require("classnames");
+
+class Connection extends Component {
+
+ state = {
+ update: false
+ };
+
+ handleAction = (name) => {
+ if (name === "hide") {
+ const enabled = !this.props.data.hidden;
+ backend.post(`/api/connections/${this.props.data.id}/${enabled ? "hide" : "show"}`)
+ .then((_) => {
+ this.props.onEnabled(!enabled);
+ this.setState({update: true});
+ });
+ }
+ if (name === "mark") {
+ const marked = this.props.data.marked;
+ backend.post(`/api/connections/${this.props.data.id}/${marked ? "unmark" : "mark"}`)
+ .then((_) => {
+ this.props.onMarked(!marked);
+ this.setState({update: true});
+ });
+ }
+ };
+
+ render() {
+ let conn = this.props.data;
+ let serviceName = "/dev/null";
+ let serviceColor = "#0f192e";
+ if (this.props.services[conn["port_dst"]]) {
+ const service = this.props.services[conn["port_dst"]];
+ serviceName = service.name;
+ serviceColor = service.color;
+ }
+ let startedAt = new Date(conn["started_at"]);
+ let closedAt = new Date(conn["closed_at"]);
+ let processedAt = new Date(conn["processed_at"]);
+ let timeInfo = <div>
+ <span>Started at {startedAt.toLocaleDateString() + " " + startedAt.toLocaleTimeString()}</span><br/>
+ <span>Processed at {processedAt.toLocaleDateString() + " " + processedAt.toLocaleTimeString()}</span><br/>
+ <span>Closed at {closedAt.toLocaleDateString() + " " + closedAt.toLocaleTimeString()}</span>
+ </div>;
+
+ const commentPopoverContent = <div>
+ <span>Click to <strong>{conn.comment.length > 0 ? "edit" : "add"}</strong> comment</span>
+ {conn.comment && <Form.Control as="textarea" readOnly={true} rows={2} defaultValue={conn.comment}/>}
+ </div>;
+
+ return (
+ <tr className={classNames("connection", {"connection-selected": this.props.selected},
+ {"has-matched-rules": conn.matched_rules.length > 0})}>
+ <td>
+ <span className="connection-service">
+ <ButtonField small fullSpan color={serviceColor} name={serviceName}
+ onClick={() => dispatcher.dispatch("connections_filters",
+ {"service_port": conn["port_dst"].toString()})}/>
+ </span>
+ </td>
+ <td className="clickable" onClick={this.props.onSelected}>{conn["ip_src"]}</td>
+ <td className="clickable" onClick={this.props.onSelected}>{conn["port_src"]}</td>
+ <td className="clickable" onClick={this.props.onSelected}>{conn["ip_dst"]}</td>
+ <td className="clickable" onClick={this.props.onSelected}>{conn["port_dst"]}</td>
+ <td className="clickable" onClick={this.props.onSelected}>
+ <LinkPopover text={dateTimeToTime(conn["started_at"])} content={timeInfo} placement="right"/>
+ </td>
+ <td className="clickable" onClick={this.props.onSelected}>{durationBetween(startedAt, closedAt)}</td>
+ <td className="clickable" onClick={this.props.onSelected}>{formatSize(conn["client_bytes"])}</td>
+ <td className="clickable" onClick={this.props.onSelected}>{formatSize(conn["server_bytes"])}</td>
+ <td className="connection-actions">
+ <LinkPopover text={<span className={classNames("connection-icon", {"icon-enabled": conn.marked})}
+ onClick={() => this.handleAction("mark")}>!!</span>}
+ content={<span>Mark this connection</span>} placement="right"/>
+ <LinkPopover text={<span className={classNames("connection-icon", {"icon-enabled": conn.comment})}
+ onClick={() => this.handleAction("comment")}>@</span>}
+ content={commentPopoverContent} placement="right"/>
+ <CopyLinkPopover text="#" value={conn.id}
+ textClassName={classNames("connection-icon", {"icon-enabled": conn.hidden})}/>
+ </td>
+ </tr>
+ );
+ }
+
+}
+
+export default Connection;
diff --git a/frontend/src/components/objects/Connection.scss b/frontend/src/components/objects/Connection.scss
new file mode 100644
index 0000000..bf66272
--- /dev/null
+++ b/frontend/src/components/objects/Connection.scss
@@ -0,0 +1,72 @@
+@import "../../colors";
+
+.connection {
+ border-top: 3px solid $color-primary-3;
+ border-bottom: 3px solid $color-primary-3;
+ background-color: $color-primary-0;
+
+ td {
+ vertical-align: middle;
+ }
+
+ .connection-service {
+ .btn {
+ width: 100%;
+ }
+
+ .btn:hover {
+ color: $color-primary-4;
+ background-color: $color-primary-1 !important;
+ }
+ }
+
+ .connection-icon {
+ font-size: 18px;
+ font-weight: 600;
+ margin-right: 6px;
+ cursor: pointer;
+ }
+
+ .connection-icon.icon-enabled {
+ color: $color-secondary-2;
+ }
+
+ &:hover {
+ background-color: $color-primary-2;
+ }
+
+ &.connection-selected {
+ background-color: $color-primary-2;
+ }
+
+ &.has-matched-rules {
+ border-bottom: 0;
+ }
+
+ .link-popover {
+ font-weight: 400;
+ }
+
+ .connection-actions .link-popover {
+ text-decoration: none;
+ }
+}
+
+.connection-popover {
+ border: none;
+ background-color: $color-primary-4;
+
+ .popover-body {
+ color: $color-primary-1;
+
+ textarea {
+ font-size: 12px;
+ width: 200px;
+ background-color: $color-primary-3;
+ }
+ }
+
+ .arrow::after {
+ border-right-color: $color-primary-4;
+ }
+}
diff --git a/frontend/src/components/objects/ConnectionMatchedRules.js b/frontend/src/components/objects/ConnectionMatchedRules.js
new file mode 100644
index 0000000..a69cad8
--- /dev/null
+++ b/frontend/src/components/objects/ConnectionMatchedRules.js
@@ -0,0 +1,51 @@
+/*
+ * 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 {withRouter} from "react-router-dom";
+import dispatcher from "../../dispatcher";
+import ButtonField from "../fields/ButtonField";
+import "./ConnectionMatchedRules.scss";
+
+class ConnectionMatchedRules extends Component {
+
+ onMatchedRulesSelected = (id) => {
+ const params = new URLSearchParams(this.props.location.search);
+ const rules = params.getAll("matched_rules");
+ if (!rules.includes(id)) {
+ rules.push(id);
+ dispatcher.dispatch("connections_filters", {"matched_rules": rules});
+ }
+ };
+
+ render() {
+ const matchedRules = this.props.matchedRules.map((mr) => {
+ const rule = this.props.rules.find((r) => r.id === mr);
+ return <ButtonField key={mr} onClick={() => this.onMatchedRulesSelected(rule.id)} name={rule.name}
+ color={rule.color} small/>;
+ });
+
+ return (
+ <tr className="connection-matches">
+ <td className="row-label">matched_rules:</td>
+ <td className="rule-buttons" colSpan={9}>{matchedRules}</td>
+ </tr>
+ );
+ }
+}
+
+export default withRouter(ConnectionMatchedRules);
diff --git a/frontend/src/components/objects/ConnectionMatchedRules.scss b/frontend/src/components/objects/ConnectionMatchedRules.scss
new file mode 100644
index 0000000..f46a914
--- /dev/null
+++ b/frontend/src/components/objects/ConnectionMatchedRules.scss
@@ -0,0 +1,23 @@
+@import "../../colors";
+
+.connection-matches {
+ background-color: $color-primary-0;
+
+ .rule-buttons {
+ padding: 0;
+ }
+
+ .button-field {
+ display: inline-block;
+ margin-right: 5px;
+
+ button {
+ font-size: 0.8em;
+ padding: 2px 10px;
+ }
+ }
+
+ .row-label {
+ font-size: 0.8em;
+ }
+}
diff --git a/frontend/src/components/objects/CopyLinkPopover.js b/frontend/src/components/objects/CopyLinkPopover.js
new file mode 100644
index 0000000..b951603
--- /dev/null
+++ b/frontend/src/components/objects/CopyLinkPopover.js
@@ -0,0 +1,54 @@
+/*
+ * 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 TextField from "../fields/TextField";
+import LinkPopover from "./LinkPopover";
+
+class CopyLinkPopover extends Component {
+
+ state = {};
+
+ constructor(props) {
+ super(props);
+
+ this.copyTextarea = React.createRef();
+ }
+
+ handleClick = () => {
+ this.copyTextarea.current.select();
+ document.execCommand("copy");
+ this.setState({copiedMessage: true});
+ setTimeout(() => this.setState({copiedMessage: false}), 3000);
+ };
+
+ render() {
+ const copyPopoverContent = <div style={{"width": "250px"}}>
+ {this.state.copiedMessage ? <span><strong>Copied!</strong></span> :
+ <span>Click to <strong>copy</strong></span>}
+ <TextField readonly rows={2} value={this.props.value} textRef={this.copyTextarea}/>
+ </div>;
+
+ return (
+ <LinkPopover text={<span className={this.props.textClassName}
+ onClick={this.handleClick}>{this.props.text}</span>}
+ content={copyPopoverContent} placement="right"/>
+ );
+ }
+}
+
+export default CopyLinkPopover;
diff --git a/frontend/src/components/objects/LinkPopover.js b/frontend/src/components/objects/LinkPopover.js
index 8768caa..551a819 100644
--- a/frontend/src/components/objects/LinkPopover.js
+++ b/frontend/src/components/objects/LinkPopover.js
@@ -1,7 +1,24 @@
-import React, {Component} from 'react';
-import {randomClassName} from "../../utils";
+/*
+ * 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 {OverlayTrigger, Popover} from "react-bootstrap";
-import './LinkPopover.scss';
+import {randomClassName} from "../../utils";
+import "./LinkPopover.scss";
class LinkPopover extends Component {
@@ -22,10 +39,11 @@ class LinkPopover extends Component {
);
return (this.props.content ?
- <OverlayTrigger trigger={["hover", "focus"]} placement={this.props.placement || "top"} overlay={popover}>
- <span className="link-popover">{this.props.text}</span>
- </OverlayTrigger> :
- <span className="link-popover-empty">{this.props.text}</span>
+ <OverlayTrigger trigger={["hover", "focus"]} placement={this.props.placement || "top"}
+ overlay={popover}>
+ <span className="link-popover">{this.props.text}</span>
+ </OverlayTrigger> :
+ <span className="link-popover-empty">{this.props.text}</span>
);
}
}
diff --git a/frontend/src/components/objects/LinkPopover.scss b/frontend/src/components/objects/LinkPopover.scss
index 725224c..c81f8bb 100644
--- a/frontend/src/components/objects/LinkPopover.scss
+++ b/frontend/src/components/objects/LinkPopover.scss
@@ -5,3 +5,8 @@
cursor: pointer;
text-decoration: underline;
}
+
+.popover {
+ font-family: "Fira Code", monospace;
+ font-size: 0.75em;
+}
diff --git a/frontend/src/components/objects/MessageAction.js b/frontend/src/components/objects/MessageAction.js
new file mode 100644
index 0000000..e0c96e8
--- /dev/null
+++ b/frontend/src/components/objects/MessageAction.js
@@ -0,0 +1,69 @@
+/*
+ * 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 {Modal} from "react-bootstrap";
+import ButtonField from "../fields/ButtonField";
+import TextField from "../fields/TextField";
+import "./MessageAction.scss";
+
+class MessageAction extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ copyButtonText: "copy"
+ };
+ this.actionValue = React.createRef();
+ this.copyActionValue = this.copyActionValue.bind(this);
+ }
+
+ copyActionValue() {
+ this.actionValue.current.select();
+ document.execCommand("copy");
+ this.setState({copyButtonText: "copied!"});
+ setTimeout(() => this.setState({copyButtonText: "copy"}), 3000);
+ }
+
+ render() {
+ return (
+ <Modal
+ {...this.props}
+ show={true}
+ size="lg"
+ aria-labelledby="message-action-dialog"
+ centered
+ >
+ <Modal.Header>
+ <Modal.Title id="message-action-dialog">
+ {this.props.actionName}
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <TextField readonly value={this.props.actionValue} textRef={this.actionValue} rows={15}/>
+ </Modal.Body>
+ <Modal.Footer className="dialog-footer">
+ <ButtonField variant="green" bordered onClick={this.copyActionValue}
+ name={this.state.copyButtonText}/>
+ <ButtonField variant="red" bordered onClick={this.props.onHide} name="close"/>
+ </Modal.Footer>
+ </Modal>
+ );
+ }
+}
+
+export default MessageAction;
diff --git a/frontend/src/components/objects/MessageAction.scss b/frontend/src/components/objects/MessageAction.scss
new file mode 100644
index 0000000..996007b
--- /dev/null
+++ b/frontend/src/components/objects/MessageAction.scss
@@ -0,0 +1,8 @@
+@import "../../colors";
+
+.message-action-value {
+ font-size: 13px;
+ padding: 15px;
+ color: $color-primary-4;
+ background-color: $color-primary-2;
+}