);
}
diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js
index fe655b3..bd631a2 100644
--- a/frontend/src/views/Connections.js
+++ b/frontend/src/views/Connections.js
@@ -6,9 +6,9 @@ import {Redirect} from 'react-router';
import {withRouter} from "react-router-dom";
import backend from "../backend";
import ConnectionMatchedRules from "../components/ConnectionMatchedRules";
-import dispatcher from "../globals";
import log from "../log";
import ButtonField from "../components/fields/ButtonField";
+import dispatcher from "../dispatcher";
class Connections extends Component {
@@ -17,8 +17,6 @@ class Connections extends Component {
connections: [],
firstConnection: null,
lastConnection: null,
- flagRule: null,
- rules: null,
queryString: null
};
@@ -41,14 +39,24 @@ class Connections extends Component {
// TODO: scroll to initial connection
}
- dispatcher.register((payload) => {
- if (payload.actionType === "timeline-update") {
- 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", 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("notifications", payload => {
+ if (payload.event === "rules.new" || payload.event === "rules.edit") {
+ this.loadRules().then(() => log.debug("Loaded connection rules after notification update"));
+ }
+ });
+
+ dispatcher.register("notifications", payload => {
+ if (payload.event === "services.edit") {
+ this.loadServices().then(() => log.debug("Services reloaded after notification update"));
}
});
}
@@ -116,6 +124,13 @@ class Connections extends Component {
}
this.setState({loading: true});
+ if (!this.state.rules) {
+ await this.loadRules();
+ }
+ if (!this.state.services) {
+ await this.loadServices();
+ }
+
let res = (await backend.get(`${url}?${urlParams}`)).json;
let connections = this.state.connections;
@@ -154,28 +169,29 @@ class Connections extends Component {
}
}
- let rules = this.state.rules;
- if (rules == null) {
- rules = (await backend.get("/api/rules")).json;
- }
-
this.setState({
loading: false,
connections: connections,
- rules: rules,
firstConnection: firstConnection,
lastConnection: lastConnection
});
if (firstConnection != null && lastConnection != null) {
- dispatcher.dispatch({
- actionType: "connections-update",
+ dispatcher.dispatch("connection_updates", {
from: new Date(lastConnection["started_at"]),
to: new Date(firstConnection["started_at"])
});
}
}
+ loadRules = async () => {
+ return backend.get("/api/rules").then(res => this.setState({rules: res.json}));
+ };
+
+ loadServices = async () => {
+ return backend.get("/api/services").then(res => this.setState({services: res.json}));
+ };
+
render() {
let redirect;
let queryString = this.state.queryString !== null ? this.state.queryString : "";
@@ -222,7 +238,8 @@ class Connections extends Component {
selected={this.state.selected === c.id}
onMarked={marked => c.marked = marked}
onEnabled={enabled => c.hidden = !enabled}
- addServicePortFilter={this.addServicePortFilter}/>,
+ addServicePortFilter={this.addServicePortFilter}
+ services={this.state.services}/>,
c.matched_rules.length > 0 &&
- log.debug("Statistics loaded after mount"));
-
- dispatcher.register((payload) => {
- if (payload.actionType === "connections-update") {
- this.setState({
- selection: new TimeRange(payload.from, payload.to),
- });
- }
+ this.loadStatistics(this.state.metric, filteredPort).then(() => log.debug("Statistics loaded after mount"));
+
+ dispatcher.register("connection_updates", payload => {
+ this.setState({
+ selection: new TimeRange(payload.from, payload.to),
+ });
});
}
@@ -109,8 +106,7 @@ class Footer extends Component {
clearTimeout(this.selectionTimeout);
}
this.selectionTimeout = setTimeout(() => {
- dispatcher.dispatch({
- actionType: "timeline-update",
+ dispatcher.dispatch("timeline_updates", {
from: timeRange.begin(),
to: timeRange.end()
});
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index fa150ab..e3cade9 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1656,6 +1656,13 @@
"@types/minimatch" "*"
"@types/node" "*"
+"@types/http-proxy@^1.17.4":
+ version "1.17.4"
+ resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.4.tgz#e7c92e3dbe3e13aa799440ff42e6d3a17a9d045b"
+ integrity sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q==
+ dependencies:
+ "@types/node" "*"
+
"@types/invariant@^2.2.33":
version "2.2.34"
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.34.tgz#05e4f79f465c2007884374d4795452f995720bbe"
@@ -2707,7 +2714,7 @@ braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
-braces@~3.0.2:
+braces@^3.0.1, braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
@@ -5738,7 +5745,18 @@ http-proxy-middleware@0.19.1:
lodash "^4.17.11"
micromatch "^3.1.10"
-http-proxy@^1.17.0:
+http-proxy-middleware@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.0.5.tgz#4c6e25d95a411e3d750bc79ccf66290675176dc2"
+ integrity sha512-CKzML7u4RdGob8wuKI//H8Ein6wNTEQR7yjVEzPbhBLGdOfkfvgTnp2HLnniKBDP9QW4eG10/724iTWLBeER3g==
+ dependencies:
+ "@types/http-proxy" "^1.17.4"
+ http-proxy "^1.18.1"
+ is-glob "^4.0.1"
+ lodash "^4.17.19"
+ micromatch "^4.0.2"
+
+http-proxy@^1.17.0, http-proxy@^1.18.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
@@ -7434,6 +7452,14 @@ micromatch@^3.1.10, micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
+micromatch@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
+ integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
+ dependencies:
+ braces "^3.0.1"
+ picomatch "^2.0.5"
+
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -8405,7 +8431,7 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
-picomatch@^2.0.4, picomatch@^2.2.1:
+picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
diff --git a/go.mod b/go.mod
index 308b16b..404f64c 100644
--- a/go.mod
+++ b/go.mod
@@ -9,6 +9,7 @@ require (
github.com/go-playground/validator/v10 v10.2.0
github.com/golang/protobuf v1.3.5 // indirect
github.com/google/gopacket v1.1.17
+ github.com/gorilla/websocket v1.4.2
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/sirupsen/logrus v1.4.2
diff --git a/go.sum b/go.sum
index fd63c39..d29e0cb 100644
--- a/go.sum
+++ b/go.sum
@@ -58,6 +58,8 @@ github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbB
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw=
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
diff --git a/notification_controller.go b/notification_controller.go
new file mode 100644
index 0000000..88c9e8c
--- /dev/null
+++ b/notification_controller.go
@@ -0,0 +1,165 @@
+package main
+
+import (
+ "github.com/gin-gonic/gin"
+ "github.com/gorilla/websocket"
+ log "github.com/sirupsen/logrus"
+ "net"
+ "net/http"
+ "time"
+)
+
+const (
+ InsertNotification = "insert"
+ UpdateNotification = "update"
+ DeleteNotification = "delete"
+
+ writeWait = 10 * time.Second
+ pongWait = 60 * time.Second
+ pingPeriod = (pongWait * 9) / 10
+ maxMessageSize = 512
+)
+
+type NotificationController struct {
+ upgrader websocket.Upgrader
+ clients map[net.Addr]*client
+ broadcast chan interface{}
+ register chan *client
+ unregister chan *client
+ applicationContext *ApplicationContext
+}
+
+func NewNotificationController(applicationContext *ApplicationContext) *NotificationController {
+ return &NotificationController{
+ upgrader: websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+ },
+ clients: make(map[net.Addr]*client),
+ broadcast: make(chan interface{}),
+ register: make(chan *client),
+ unregister: make(chan *client),
+ applicationContext: applicationContext,
+ }
+}
+
+type client struct {
+ conn *websocket.Conn
+ send chan interface{}
+ notificationController *NotificationController
+}
+
+func (wc *NotificationController) NotificationHandler(w http.ResponseWriter, r *http.Request) error {
+ conn, err := wc.upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.WithError(err).Error("failed to set websocket upgrade")
+ return err
+ }
+
+ client := &client{
+ conn: conn,
+ send: make(chan interface{}),
+ notificationController: wc,
+ }
+ wc.register <- client
+ go client.readPump()
+ go client.writePump()
+
+ return nil
+}
+
+func (wc *NotificationController) Run() {
+ for {
+ select {
+ case client := <-wc.register:
+ wc.clients[client.conn.RemoteAddr()] = client
+ payload := gin.H{"event": "connected", "message": gin.H{
+ "version": wc.applicationContext.Version,
+ "is_configured": wc.applicationContext.IsConfigured,
+ "connected_clients": len(wc.clients),
+ }}
+ client.send <- payload
+ log.WithField("connected_clients", len(wc.clients)).
+ WithField("remote_address", client.conn.RemoteAddr()).
+ Info("[+] a websocket client connected")
+ case client := <-wc.unregister:
+ if _, ok := wc.clients[client.conn.RemoteAddr()]; ok {
+ close(client.send)
+ _ = client.conn.WriteMessage(websocket.CloseMessage, nil)
+ _ = client.conn.Close()
+ delete(wc.clients, client.conn.RemoteAddr())
+ log.WithField("connected_clients", len(wc.clients)).
+ WithField("remote_address", client.conn.RemoteAddr()).
+ Info("[-] a websocket client disconnected")
+ }
+ case payload := <-wc.broadcast:
+ for _, client := range wc.clients {
+ select {
+ case client.send <- payload:
+ default:
+ close(client.send)
+ delete(wc.clients, client.conn.RemoteAddr())
+ }
+ }
+ }
+ }
+}
+
+func (wc *NotificationController) Notify(event string, eventType string, message interface{}) {
+ wc.broadcast <- gin.H{"event": event, "event_type": eventType, "message": message}
+}
+
+func (c *client) readPump() {
+ c.conn.SetReadLimit(maxMessageSize)
+ if err := c.conn.SetReadDeadline(time.Now().Add(pongWait)); err != nil {
+ c.close()
+ return
+ }
+ c.conn.SetPongHandler(func(string) error { return c.conn.SetReadDeadline(time.Now().Add(pongWait)) })
+ for {
+ if _, _, err := c.conn.ReadMessage(); err != nil {
+ if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
+ log.WithError(err).WithField("remote_address", c.conn.RemoteAddr()).
+ Warn("unexpected websocket disconnection")
+ }
+ break
+ }
+ }
+
+ c.close()
+}
+
+func (c *client) writePump() {
+ ticker := time.NewTicker(pingPeriod)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case payload, ok := <-c.send:
+ if !ok {
+ return
+ }
+ if err := c.conn.SetWriteDeadline(time.Now().Add(writeWait)); err != nil {
+ c.close()
+ return
+ }
+ if err := c.conn.WriteJSON(payload); err != nil {
+ c.close()
+ return
+ }
+ case <-ticker.C:
+ if err := c.conn.SetWriteDeadline(time.Now().Add(writeWait)); err != nil {
+ c.close()
+ return
+ }
+ if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
+ c.close()
+ return
+ }
+ }
+ }
+}
+
+func (c *client) close() {
+ c.notificationController.unregister <- c
+}
diff --git a/pcap_importer.go b/pcap_importer.go
index 1739b3f..78a5e6c 100644
--- a/pcap_importer.go
+++ b/pcap_importer.go
@@ -19,7 +19,6 @@ import (
const PcapsBasePath = "pcaps/"
const ProcessingPcapsBasePath = PcapsBasePath + "processing/"
const initialAssemblerPoolSize = 16
-const flushOlderThan = 5 * time.Minute
const importUpdateProgressInterval = 100 * time.Millisecond
type PcapImporter struct {
@@ -201,8 +200,8 @@ func (pi *PcapImporter) parsePcap(session ImportingSession, fileName string, flu
var servicePort uint16
var index int
- isDstServer := pi.serverNet.Contains(packet.NetworkLayer().NetworkFlow().Dst().Raw())
- isSrcServer := pi.serverNet.Contains(packet.NetworkLayer().NetworkFlow().Src().Raw())
+ isDstServer := pi.serverNet.Contains(packet.NetworkLayer().NetworkFlow().Dst().Raw())
+ isSrcServer := pi.serverNet.Contains(packet.NetworkLayer().NetworkFlow().Src().Raw())
if isDstServer && !isSrcServer {
servicePort = uint16(tcp.DstPort)
index = 0
@@ -284,7 +283,7 @@ func deleteProcessingFile(fileName string) {
}
func moveProcessingFile(sessionID string, fileName string) {
- if err := os.Rename(ProcessingPcapsBasePath + fileName, PcapsBasePath + sessionID + path.Ext(fileName)); err != nil {
+ if err := os.Rename(ProcessingPcapsBasePath+fileName, PcapsBasePath+sessionID+path.Ext(fileName)); err != nil {
log.WithError(err).Error("failed to move processed file")
}
}
--
cgit v1.2.3-70-g09d2
From a30815021e61023f996b1450ddcd9164a6e18bef Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Thu, 8 Oct 2020 17:07:07 +0200
Subject: Add header license to all files
---
application_context.go | 17 +++++++++++++++++
application_context_test.go | 17 +++++++++++++++++
application_router.go | 17 +++++++++++++++++
application_router_test.go | 17 +++++++++++++++++
caronte.go | 17 +++++++++++++++++
caronte_test.go | 17 +++++++++++++++++
connection_handler.go | 17 +++++++++++++++++
connection_handler_test.go | 17 +++++++++++++++++
connection_streams_controller.go | 17 +++++++++++++++++
connections_controller.go | 17 +++++++++++++++++
frontend/src/backend.js | 17 +++++++++++++++++
frontend/src/components/Connection.js | 17 +++++++++++++++++
frontend/src/components/ConnectionContent.js | 17 +++++++++++++++++
frontend/src/components/ConnectionMatchedRules.js | 17 +++++++++++++++++
frontend/src/components/MessageAction.js | 17 +++++++++++++++++
frontend/src/components/Notifications.js | 17 +++++++++++++++++
frontend/src/components/fields/ButtonField.js | 17 +++++++++++++++++
frontend/src/components/fields/CheckField.js | 17 +++++++++++++++++
frontend/src/components/fields/ChoiceField.js | 17 +++++++++++++++++
frontend/src/components/fields/InputField.js | 17 +++++++++++++++++
frontend/src/components/fields/TextField.js | 17 +++++++++++++++++
.../src/components/fields/extensions/ColorField.js | 17 +++++++++++++++++
.../components/fields/extensions/NumericField.js | 17 +++++++++++++++++
.../components/filters/BooleanConnectionsFilter.js | 17 +++++++++++++++++
.../src/components/filters/FiltersDefinitions.js | 17 +++++++++++++++++
.../components/filters/RulesConnectionsFilter.js | 17 +++++++++++++++++
.../components/filters/StringConnectionsFilter.js | 17 +++++++++++++++++
frontend/src/components/objects/LinkPopover.js | 17 +++++++++++++++++
frontend/src/components/panels/ConfigurationPane.js | 17 +++++++++++++++++
frontend/src/components/panels/MainPane.js | 17 +++++++++++++++++
frontend/src/components/panels/PcapPane.js | 17 +++++++++++++++++
frontend/src/components/panels/RulePane.js | 17 +++++++++++++++++
frontend/src/components/panels/ServicePane.js | 17 +++++++++++++++++
frontend/src/dispatcher.js | 16 ++++++++++++++++
frontend/src/index.js | 17 +++++++++++++++++
frontend/src/log.js | 17 +++++++++++++++++
frontend/src/notifications.js | 17 +++++++++++++++++
frontend/src/setupProxy.js | 17 +++++++++++++++++
frontend/src/utils.js | 17 +++++++++++++++++
frontend/src/validation.js | 16 ++++++++++++++++
frontend/src/views/App.js | 17 +++++++++++++++++
frontend/src/views/Connections.js | 17 +++++++++++++++++
frontend/src/views/Filters.js | 21 +++++++++++++++++++--
frontend/src/views/Header.js | 17 +++++++++++++++++
frontend/src/views/Timeline.js | 17 +++++++++++++++++
notification_controller.go | 17 +++++++++++++++++
parsers/http_request_parser.go | 17 +++++++++++++++++
parsers/http_response_parser.go | 17 +++++++++++++++++
parsers/parser.go | 17 +++++++++++++++++
parsers/parser_utils.go | 17 +++++++++++++++++
pcap_importer.go | 17 +++++++++++++++++
pcap_importer_test.go | 17 +++++++++++++++++
resources_controller.go | 17 +++++++++++++++++
rules_manager.go | 17 +++++++++++++++++
rules_manager_test.go | 17 +++++++++++++++++
services_controller.go | 17 +++++++++++++++++
statistics_controller.go | 17 +++++++++++++++++
storage.go | 17 +++++++++++++++++
storage_test.go | 17 +++++++++++++++++
stream_handler.go | 17 +++++++++++++++++
stream_handler_test.go | 17 +++++++++++++++++
utils.go | 17 +++++++++++++++++
62 files changed, 1054 insertions(+), 2 deletions(-)
(limited to 'application_context.go')
diff --git a/application_context.go b/application_context.go
index 9a9c97a..9897bb6 100644
--- a/application_context.go
+++ b/application_context.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/application_context_test.go b/application_context_test.go
index 28c81a5..a7f1a49 100644
--- a/application_context_test.go
+++ b/application_context_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/application_router.go b/application_router.go
index da71538..9fd7e3d 100644
--- a/application_router.go
+++ b/application_router.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/application_router_test.go b/application_router_test.go
index f4804e3..9741eed 100644
--- a/application_router_test.go
+++ b/application_router_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/caronte.go b/caronte.go
index d999724..d4265bc 100644
--- a/caronte.go
+++ b/caronte.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/caronte_test.go b/caronte_test.go
index 12ec50f..8935ea3 100644
--- a/caronte_test.go
+++ b/caronte_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/connection_handler.go b/connection_handler.go
index 3d38531..6b2b411 100644
--- a/connection_handler.go
+++ b/connection_handler.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/connection_handler_test.go b/connection_handler_test.go
index 0bee0ac..d980041 100644
--- a/connection_handler_test.go
+++ b/connection_handler_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/connection_streams_controller.go b/connection_streams_controller.go
index 98f2aca..9251a3a 100644
--- a/connection_streams_controller.go
+++ b/connection_streams_controller.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/connections_controller.go b/connections_controller.go
index e872c9f..30a5ee5 100644
--- a/connections_controller.go
+++ b/connections_controller.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/frontend/src/backend.js b/frontend/src/backend.js
index 1b2d8d2..cc8604a 100644
--- a/frontend/src/backend.js
+++ b/frontend/src/backend.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
async function json(method, url, data, json, headers) {
const options = {
method: method,
diff --git a/frontend/src/components/Connection.js b/frontend/src/components/Connection.js
index b7e2531..c7b0010 100644
--- a/frontend/src/components/Connection.js
+++ b/frontend/src/components/Connection.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './Connection.scss';
import {Form, OverlayTrigger, Popover} from "react-bootstrap";
diff --git a/frontend/src/components/ConnectionContent.js b/frontend/src/components/ConnectionContent.js
index b09dcf3..b468277 100644
--- a/frontend/src/components/ConnectionContent.js
+++ b/frontend/src/components/ConnectionContent.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './ConnectionContent.scss';
import {Row} from 'react-bootstrap';
diff --git a/frontend/src/components/ConnectionMatchedRules.js b/frontend/src/components/ConnectionMatchedRules.js
index 21f2a92..35643c5 100644
--- a/frontend/src/components/ConnectionMatchedRules.js
+++ b/frontend/src/components/ConnectionMatchedRules.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './ConnectionMatchedRules.scss';
import ButtonField from "./fields/ButtonField";
diff --git a/frontend/src/components/MessageAction.js b/frontend/src/components/MessageAction.js
index 8f4b031..b94cbb9 100644
--- a/frontend/src/components/MessageAction.js
+++ b/frontend/src/components/MessageAction.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './MessageAction.scss';
import {Modal} from "react-bootstrap";
diff --git a/frontend/src/components/Notifications.js b/frontend/src/components/Notifications.js
index 9ce2b58..1017a42 100644
--- a/frontend/src/components/Notifications.js
+++ b/frontend/src/components/Notifications.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './Notifications.scss';
import dispatcher from "../dispatcher";
diff --git a/frontend/src/components/fields/ButtonField.js b/frontend/src/components/fields/ButtonField.js
index cc32b0f..ffcceae 100644
--- a/frontend/src/components/fields/ButtonField.js
+++ b/frontend/src/components/fields/ButtonField.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './ButtonField.scss';
import './common.scss';
diff --git a/frontend/src/components/fields/CheckField.js b/frontend/src/components/fields/CheckField.js
index 33f4f83..dd44970 100644
--- a/frontend/src/components/fields/CheckField.js
+++ b/frontend/src/components/fields/CheckField.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './CheckField.scss';
import './common.scss';
diff --git a/frontend/src/components/fields/ChoiceField.js b/frontend/src/components/fields/ChoiceField.js
index 73e950d..14071c3 100644
--- a/frontend/src/components/fields/ChoiceField.js
+++ b/frontend/src/components/fields/ChoiceField.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './ChoiceField.scss';
import './common.scss';
diff --git a/frontend/src/components/fields/InputField.js b/frontend/src/components/fields/InputField.js
index 84c981b..80cce3b 100644
--- a/frontend/src/components/fields/InputField.js
+++ b/frontend/src/components/fields/InputField.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './InputField.scss';
import './common.scss';
diff --git a/frontend/src/components/fields/TextField.js b/frontend/src/components/fields/TextField.js
index de68c21..9237c0c 100644
--- a/frontend/src/components/fields/TextField.js
+++ b/frontend/src/components/fields/TextField.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './TextField.scss';
import './common.scss';
diff --git a/frontend/src/components/fields/extensions/ColorField.js b/frontend/src/components/fields/extensions/ColorField.js
index 96ebc49..f1c0caf 100644
--- a/frontend/src/components/fields/extensions/ColorField.js
+++ b/frontend/src/components/fields/extensions/ColorField.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import {OverlayTrigger, Popover} from "react-bootstrap";
import './ColorField.scss';
diff --git a/frontend/src/components/fields/extensions/NumericField.js b/frontend/src/components/fields/extensions/NumericField.js
index 19a9e46..d4d027d 100644
--- a/frontend/src/components/fields/extensions/NumericField.js
+++ b/frontend/src/components/fields/extensions/NumericField.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import InputField from "../InputField";
diff --git a/frontend/src/components/filters/BooleanConnectionsFilter.js b/frontend/src/components/filters/BooleanConnectionsFilter.js
index 4c5a78a..a9a420e 100644
--- a/frontend/src/components/filters/BooleanConnectionsFilter.js
+++ b/frontend/src/components/filters/BooleanConnectionsFilter.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import {withRouter} from "react-router-dom";
import {Redirect} from "react-router";
diff --git a/frontend/src/components/filters/FiltersDefinitions.js b/frontend/src/components/filters/FiltersDefinitions.js
index d4f2912..cde3cfb 100644
--- a/frontend/src/components/filters/FiltersDefinitions.js
+++ b/frontend/src/components/filters/FiltersDefinitions.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import {cleanNumber, validateIpAddress, validateMin, validatePort} from "../../utils";
import StringConnectionsFilter from "./StringConnectionsFilter";
import React from "react";
diff --git a/frontend/src/components/filters/RulesConnectionsFilter.js b/frontend/src/components/filters/RulesConnectionsFilter.js
index 8366189..48affb0 100644
--- a/frontend/src/components/filters/RulesConnectionsFilter.js
+++ b/frontend/src/components/filters/RulesConnectionsFilter.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import {withRouter} from "react-router-dom";
import {Redirect} from "react-router";
diff --git a/frontend/src/components/filters/StringConnectionsFilter.js b/frontend/src/components/filters/StringConnectionsFilter.js
index f463593..a3b45dc 100644
--- a/frontend/src/components/filters/StringConnectionsFilter.js
+++ b/frontend/src/components/filters/StringConnectionsFilter.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import {withRouter} from "react-router-dom";
import {Redirect} from "react-router";
diff --git a/frontend/src/components/objects/LinkPopover.js b/frontend/src/components/objects/LinkPopover.js
index 8768caa..3c5bf67 100644
--- a/frontend/src/components/objects/LinkPopover.js
+++ b/frontend/src/components/objects/LinkPopover.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import {randomClassName} from "../../utils";
import {OverlayTrigger, Popover} from "react-bootstrap";
diff --git a/frontend/src/components/panels/ConfigurationPane.js b/frontend/src/components/panels/ConfigurationPane.js
index 10309f6..9ae2cfb 100644
--- a/frontend/src/components/panels/ConfigurationPane.js
+++ b/frontend/src/components/panels/ConfigurationPane.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './common.scss';
import './ConfigurationPane.scss';
diff --git a/frontend/src/components/panels/MainPane.js b/frontend/src/components/panels/MainPane.js
index bd25e0c..d34d58a 100644
--- a/frontend/src/components/panels/MainPane.js
+++ b/frontend/src/components/panels/MainPane.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './common.scss';
import './MainPane.scss';
diff --git a/frontend/src/components/panels/PcapPane.js b/frontend/src/components/panels/PcapPane.js
index 13f7cb3..d5c2225 100644
--- a/frontend/src/components/panels/PcapPane.js
+++ b/frontend/src/components/panels/PcapPane.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './PcapPane.scss';
import './common.scss';
diff --git a/frontend/src/components/panels/RulePane.js b/frontend/src/components/panels/RulePane.js
index 76f3ac0..9913962 100644
--- a/frontend/src/components/panels/RulePane.js
+++ b/frontend/src/components/panels/RulePane.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './common.scss';
import './RulePane.scss';
diff --git a/frontend/src/components/panels/ServicePane.js b/frontend/src/components/panels/ServicePane.js
index 22c6655..fc7004b 100644
--- a/frontend/src/components/panels/ServicePane.js
+++ b/frontend/src/components/panels/ServicePane.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './common.scss';
import './ServicePane.scss';
diff --git a/frontend/src/dispatcher.js b/frontend/src/dispatcher.js
index 4b8b5a4..943f7ec 100644
--- a/frontend/src/dispatcher.js
+++ b/frontend/src/dispatcher.js
@@ -1,3 +1,19 @@
+/*
+ * 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 .
+ */
class Dispatcher {
diff --git a/frontend/src/index.js b/frontend/src/index.js
index beb52ae..e3e48de 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css';
diff --git a/frontend/src/log.js b/frontend/src/log.js
index 0883962..424e1b4 100644
--- a/frontend/src/log.js
+++ b/frontend/src/log.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
const log = {
debug: (...obj) => console.info(...obj),
info: (...obj) => console.info(...obj),
diff --git a/frontend/src/notifications.js b/frontend/src/notifications.js
index 2a77ffb..f04036d 100644
--- a/frontend/src/notifications.js
+++ b/frontend/src/notifications.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import log from "./log";
import dispatcher from "./dispatcher";
diff --git a/frontend/src/setupProxy.js b/frontend/src/setupProxy.js
index 6f082c8..f2e1c39 100644
--- a/frontend/src/setupProxy.js
+++ b/frontend/src/setupProxy.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
diff --git a/frontend/src/utils.js b/frontend/src/utils.js
index aacc625..f333f0d 100644
--- a/frontend/src/utils.js
+++ b/frontend/src/utils.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
const timeRegex = /^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/;
export function createCurlCommand(subCommand, method = null, json = null, data = null) {
diff --git a/frontend/src/validation.js b/frontend/src/validation.js
index 7089d7f..87b08de 100644
--- a/frontend/src/validation.js
+++ b/frontend/src/validation.js
@@ -1,3 +1,19 @@
+/*
+ * 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 .
+ */
const validation = {
isValidColor: (color) => /^#(?:[0-9a-fA-F]{3}){1,2}$/.test(color),
diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js
index 4bb9f57..8105117 100644
--- a/frontend/src/views/App.js
+++ b/frontend/src/views/App.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './App.scss';
import Header from "./Header";
diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js
index e835dcb..b2edd3f 100644
--- a/frontend/src/views/Connections.js
+++ b/frontend/src/views/Connections.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './Connections.scss';
import Connection from "../components/Connection";
diff --git a/frontend/src/views/Filters.js b/frontend/src/views/Filters.js
index ba7d467..3dd8280 100644
--- a/frontend/src/views/Filters.js
+++ b/frontend/src/views/Filters.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import {Col, Container, Modal, Row, Table} from "react-bootstrap";
import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions";
@@ -31,7 +48,7 @@ class Filters extends Component {
);
@@ -89,7 +106,7 @@ class Filters extends Component {
-
+
);
diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js
index f5eff17..2cfe9fb 100644
--- a/frontend/src/views/Header.js
+++ b/frontend/src/views/Header.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import Typed from 'typed.js';
import './Header.scss';
diff --git a/frontend/src/views/Timeline.js b/frontend/src/views/Timeline.js
index 3adbf88..ebe3eb9 100644
--- a/frontend/src/views/Timeline.js
+++ b/frontend/src/views/Timeline.js
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
import React, {Component} from 'react';
import './Timeline.scss';
import {
diff --git a/notification_controller.go b/notification_controller.go
index 88c9e8c..3fa3c5b 100644
--- a/notification_controller.go
+++ b/notification_controller.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/parsers/http_request_parser.go b/parsers/http_request_parser.go
index e2224b8..bc98f8f 100644
--- a/parsers/http_request_parser.go
+++ b/parsers/http_request_parser.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package parsers
import (
diff --git a/parsers/http_response_parser.go b/parsers/http_response_parser.go
index 1770116..e5ef1ac 100644
--- a/parsers/http_response_parser.go
+++ b/parsers/http_response_parser.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package parsers
import (
diff --git a/parsers/parser.go b/parsers/parser.go
index 06cc0dc..a29b1ab 100644
--- a/parsers/parser.go
+++ b/parsers/parser.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package parsers
type Parser interface {
diff --git a/parsers/parser_utils.go b/parsers/parser_utils.go
index b688262..575b666 100644
--- a/parsers/parser_utils.go
+++ b/parsers/parser_utils.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package parsers
import (
diff --git a/pcap_importer.go b/pcap_importer.go
index 78a5e6c..41ed082 100644
--- a/pcap_importer.go
+++ b/pcap_importer.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/pcap_importer_test.go b/pcap_importer_test.go
index be09ea9..8940060 100644
--- a/pcap_importer_test.go
+++ b/pcap_importer_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/resources_controller.go b/resources_controller.go
index 050157a..10b31e3 100644
--- a/resources_controller.go
+++ b/resources_controller.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/rules_manager.go b/rules_manager.go
index a5dc7ce..636fc74 100644
--- a/rules_manager.go
+++ b/rules_manager.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/rules_manager_test.go b/rules_manager_test.go
index a2ec501..dded096 100644
--- a/rules_manager_test.go
+++ b/rules_manager_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/services_controller.go b/services_controller.go
index 9907b5e..e5fa200 100644
--- a/services_controller.go
+++ b/services_controller.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/statistics_controller.go b/statistics_controller.go
index 65c7d58..006b230 100644
--- a/statistics_controller.go
+++ b/statistics_controller.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/storage.go b/storage.go
index 0888ce0..f8b7f9c 100644
--- a/storage.go
+++ b/storage.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/storage_test.go b/storage_test.go
index 4caa30d..dd91e97 100644
--- a/storage_test.go
+++ b/storage_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/stream_handler.go b/stream_handler.go
index bccdeee..48dba34 100644
--- a/stream_handler.go
+++ b/stream_handler.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/stream_handler_test.go b/stream_handler_test.go
index 199ae5b..127aa82 100644
--- a/stream_handler_test.go
+++ b/stream_handler_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
diff --git a/utils.go b/utils.go
index ec5a807..639fd94 100644
--- a/utils.go
+++ b/utils.go
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
package main
import (
--
cgit v1.2.3-70-g09d2
From bc989facca1f3381afed2f7c982da7784fad2327 Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Sun, 11 Oct 2020 21:49:40 +0200
Subject: [inconsistent] SearchOption validation checkpoint
---
application_context.go | 2 +
application_router.go | 70 +++++++++++++++
connection_streams_controller.go | 1 +
search_controller.go | 189 +++++++++++++++++++++++++++++++++++++++
statistics_controller.go | 8 +-
storage.go | 41 ++++++---
stream_handler.go | 2 +
7 files changed, 299 insertions(+), 14 deletions(-)
create mode 100644 search_controller.go
(limited to 'application_context.go')
diff --git a/application_context.go b/application_context.go
index 9897bb6..fc76d00 100644
--- a/application_context.go
+++ b/application_context.go
@@ -37,6 +37,7 @@ type ApplicationContext struct {
ConnectionsController ConnectionsController
ServicesController *ServicesController
ConnectionStreamsController ConnectionStreamsController
+ SearchController *SearchController
StatisticsController StatisticsController
IsConfigured bool
Version string
@@ -113,6 +114,7 @@ func (sm *ApplicationContext) configure() {
sm.ServicesController = NewServicesController(sm.Storage)
sm.ConnectionsController = NewConnectionsController(sm.Storage, sm.ServicesController)
sm.ConnectionStreamsController = NewConnectionStreamsController(sm.Storage)
+ sm.SearchController = NewSearchController(sm.Storage)
sm.StatisticsController = NewStatisticsController(sm.Storage)
sm.IsConfigured = true
}
diff --git a/application_router.go b/application_router.go
index 89b471b..dc9f9d4 100644
--- a/application_router.go
+++ b/application_router.go
@@ -22,6 +22,8 @@ import (
"fmt"
"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
+ "github.com/go-playground/validator/v10"
log "github.com/sirupsen/logrus"
"net/http"
"os"
@@ -294,6 +296,74 @@ func CreateApplicationRouter(applicationContext *ApplicationContext,
}
})
+ api.GET("/searches", func(c *gin.Context) {
+ success(c, applicationContext.SearchController.PerformedSearches())
+ })
+
+ api.POST("/searches/perform", func(c *gin.Context) {
+ var options SearchOptions
+
+
+ parentIsZero := func (fl validator.FieldLevel) bool {
+ log.Println(fl.FieldName())
+ log.Println("noooooo")
+ return fl.Parent().IsZero()
+ }
+ eitherWith := func (fl validator.FieldLevel) bool {
+ otherField := fl.Parent().FieldByName(fl.Param())
+ log.Println(fl.Param())
+ log.Println("bbbbbbbbbb")
+ return (fl.Field().IsZero() && !otherField.IsZero()) || (!fl.Field().IsZero() && otherField.IsZero())
+ }
+ aaa := func (fl validator.FieldLevel) bool {
+
+ log.Println("awww")
+ return fl.Field().IsZero()
+ }
+
+ bbb := func (fl validator.FieldLevel) bool {
+
+ log.Println("iiiii")
+ return true
+ }
+
+ if validate, ok := binding.Validator.Engine().(*validator.Validate); ok {
+ if err := validate.RegisterValidation("parent_is_zero", parentIsZero); err != nil {
+ log.WithError(err).Panic("cannot register 'topzero' validator")
+ }
+ if err := validate.RegisterValidation("either_with", eitherWith); err != nil {
+ log.WithError(err).Panic("cannot register 'either_with' validator")
+ }
+ if err := validate.RegisterValidation("aaa", aaa); err != nil {
+ log.WithError(err).Panic("cannot register 'either_with' validator")
+ }
+ if err := validate.RegisterValidation("bbb", bbb); err != nil {
+ log.WithError(err).Panic("cannot register 'either_with' validator")
+ }
+ } else {
+ log.Panic("cannot ")
+ }
+
+
+ if err := c.ShouldBindJSON(&options); err != nil {
+ badRequest(c, err)
+ return
+ }
+
+ log.Println(options)
+
+
+ success(c, "ok")
+
+
+
+
+
+
+
+ //success(c, applicationContext.SearchController.PerformSearch(c, options))
+ })
+
api.GET("/streams/:id", func(c *gin.Context) {
id, err := RowIDFromHex(c.Param("id"))
if err != nil {
diff --git a/connection_streams_controller.go b/connection_streams_controller.go
index 89e484d..eef1a2a 100644
--- a/connection_streams_controller.go
+++ b/connection_streams_controller.go
@@ -39,6 +39,7 @@ type ConnectionStream struct {
FromClient bool `bson:"from_client"`
DocumentIndex int `bson:"document_index"`
Payload []byte `bson:"payload"`
+ PayloadString string `bson:"payload_string"`
BlocksIndexes []int `bson:"blocks_indexes"`
BlocksTimestamps []time.Time `bson:"blocks_timestamps"`
BlocksLoss []bool `bson:"blocks_loss"`
diff --git a/search_controller.go b/search_controller.go
new file mode 100644
index 0000000..ad47dbc
--- /dev/null
+++ b/search_controller.go
@@ -0,0 +1,189 @@
+/*
+ * 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 .
+ */
+
+package main
+
+import (
+ "context"
+ log "github.com/sirupsen/logrus"
+ "strings"
+ "sync"
+ "time"
+)
+
+const (
+ secondsToNano = 1000 * 1000 * 1000
+ maxSearchTimeout = 60 * secondsToNano
+)
+
+type PerformedSearch struct {
+ ID RowID `bson:"_id" json:"id"`
+ SearchOptions SearchOptions `bson:"search_options" json:"search_options"`
+ AffectedConnections []RowID `bson:"affected_connections" json:"affected_connections,omitempty"`
+ AffectedConnectionsCount int `bson:"affected_connections_count" json:"affected_connections_count"`
+ StartedAt time.Time `bson:"started_at" json:"started_at"`
+ FinishedAt time.Time `bson:"finished_at" json:"finished_at"`
+ UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
+ Timeout time.Duration `bson:"timeout" json:"timeout"`
+}
+
+type SearchOptions struct {
+ TextSearch TextSearch `bson:"text_search" json:"text_search" validate:"either_with=RegexSearch"`
+ RegexSearch RegexSearch `bson:"regex_search" json:"regex_search" validate:"either_with=TextSearch"`
+ Timeout time.Duration `bson:"timeout" json:"timeout" binding:"max=60"`
+}
+
+type TextSearch struct {
+ Terms []string `bson:"terms" json:"terms" binding:"parent_is_zero|either_with=ExactPhrase,isdefault|min=1,dive,min=3"`
+ ExcludedTerms []string `bson:"excluded_terms" json:"excluded_terms" binding:"required_with=Terms,dive,isdefault|min=1"`
+ ExactPhrase string `bson:"exact_phrase" json:"exact_phrase" binding:"isdefault|min=3,parent_is_zero|either_with=Terms"`
+ CaseSensitive bool `bson:"case_sensitive" json:"case_sensitive"`
+}
+
+type RegexSearch struct {
+ Pattern string `bson:"pattern" json:"pattern" binding:"parent_is_zero|either_with=NotPattern,isdefault|min=3"`
+ NotPattern string `bson:"not_pattern" json:"not_pattern" binding:"parent_is_zero|either_with=Pattern,isdefault|min=3"`
+ CaseInsensitive bool `bson:"case_insensitive" json:"case_insensitive"`
+ MultiLine bool `bson:"multi_line" json:"multi_line"`
+ IgnoreWhitespaces bool `bson:"ignore_whitespaces" json:"ignore_whitespaces"`
+ DotCharacter bool `bson:"dot_character" json:"dot_character"`
+}
+
+type SearchController struct {
+ storage Storage
+ performedSearches []PerformedSearch
+ mutex sync.Mutex
+}
+
+func NewSearchController(storage Storage) *SearchController {
+ var searches []PerformedSearch
+ if err := storage.Find(Searches).All(&searches); err != nil {
+ // log.WithError(err).Panic("failed to retrieve performed searches")
+ }
+
+ return &SearchController{
+ storage: storage,
+ performedSearches: searches,
+ }
+}
+
+func (sc *SearchController) PerformedSearches() []PerformedSearch {
+ sc.mutex.Lock()
+ defer sc.mutex.Unlock()
+
+ return sc.performedSearches
+}
+
+func (sc *SearchController) PerformSearch(c context.Context, options SearchOptions) PerformedSearch {
+ findQuery := sc.storage.Find(ConnectionStreams).Projection(OrderedDocument{{"connection_id", 1}}).Context(c)
+ timeout := options.Timeout * secondsToNano
+ if timeout <= 0 || timeout > maxSearchTimeout {
+ timeout = maxSearchTimeout
+ }
+ findQuery = findQuery.MaxTime(timeout)
+
+ if !options.TextSearch.isZero() {
+ var text string
+ if options.TextSearch.ExactPhrase != "" {
+ text = "\"" + options.TextSearch.ExactPhrase + "\""
+ } else {
+ text = strings.Join(options.TextSearch.Terms, " ")
+ if options.TextSearch.ExcludedTerms != nil {
+ text += " -" + strings.Join(options.TextSearch.ExcludedTerms, " -")
+ }
+ }
+
+ findQuery = findQuery.Filter(OrderedDocument{{"$text", UnorderedDocument{
+ "$search": text,
+ "$language": "none",
+ "$caseSensitive": options.TextSearch.CaseSensitive,
+ "$diacriticSensitive": false,
+ }}})
+ } else {
+ var regexOptions string
+ if options.RegexSearch.CaseInsensitive {
+ regexOptions += "i"
+ }
+ if options.RegexSearch.MultiLine {
+ regexOptions += "m"
+ }
+ if options.RegexSearch.IgnoreWhitespaces {
+ regexOptions += "x"
+ }
+ if options.RegexSearch.DotCharacter {
+ regexOptions += "s"
+ }
+
+ var regex UnorderedDocument
+ if options.RegexSearch.Pattern != "" {
+ regex = UnorderedDocument{"$regex": options.RegexSearch.Pattern, "$options": regexOptions}
+ } else {
+ regex = UnorderedDocument{"$not":
+ UnorderedDocument{"$regex": options.RegexSearch.NotPattern, "$options": regexOptions}}
+ }
+
+ findQuery = findQuery.Filter(OrderedDocument{{"payload_string", regex}})
+ }
+
+ var connections []ConnectionStream
+ startedAt := time.Now()
+ if err := findQuery.All(&connections); err != nil {
+ log.WithError(err).Error("oh no")
+ }
+ affectedConnections := uniqueConnectionIds(connections)
+
+ finishedAt := time.Now()
+ performedSearch := PerformedSearch{
+ ID: NewRowID(),
+ SearchOptions: options,
+ AffectedConnections: affectedConnections,
+ AffectedConnectionsCount: len(affectedConnections),
+ StartedAt: startedAt,
+ FinishedAt: finishedAt,
+ UpdatedAt: finishedAt,
+ Timeout: options.Timeout,
+ }
+ if _, err := sc.storage.Insert(Searches).Context(c).One(performedSearch); err != nil {
+ log.WithError(err).Panic("failed to insert a new performed search")
+ }
+
+ sc.mutex.Lock()
+ sc.performedSearches = append([]PerformedSearch{performedSearch}, sc.performedSearches...)
+ sc.mutex.Unlock()
+
+ return performedSearch
+}
+
+func (sc TextSearch) isZero() bool {
+ return sc.Terms == nil && sc.ExcludedTerms == nil && sc.ExactPhrase == ""
+}
+
+func (sc RegexSearch) isZero() bool {
+ return RegexSearch{} == sc
+}
+
+func uniqueConnectionIds(connections []ConnectionStream) []RowID {
+ keys := make(map[RowID]bool)
+ var out []RowID
+ for _, entry := range connections {
+ if _, value := keys[entry.ConnectionID]; !value {
+ keys[entry.ConnectionID] = true
+ out = append(out, entry.ConnectionID)
+ }
+ }
+ return out
+}
diff --git a/statistics_controller.go b/statistics_controller.go
index 006b230..1714c0b 100644
--- a/statistics_controller.go
+++ b/statistics_controller.go
@@ -26,10 +26,10 @@ import (
type StatisticRecord struct {
RangeStart time.Time `json:"range_start" bson:"_id"`
- ConnectionsPerService map[uint16]int `json:"connections_per_service" bson:"connections_per_service"`
- ClientBytesPerService map[uint16]int `json:"client_bytes_per_service" bson:"client_bytes_per_service"`
- ServerBytesPerService map[uint16]int `json:"server_bytes_per_service" bson:"server_bytes_per_service"`
- DurationPerService map[uint16]int64 `json:"duration_per_service" bson:"duration_per_service"`
+ ConnectionsPerService map[uint16]int `json:"connections_per_service,omitempty" bson:"connections_per_service"`
+ ClientBytesPerService map[uint16]int `json:"client_bytes_per_service,omitempty" bson:"client_bytes_per_service"`
+ ServerBytesPerService map[uint16]int `json:"server_bytes_per_service,omitempty" bson:"server_bytes_per_service"`
+ DurationPerService map[uint16]int64 `json:"duration_per_service,omitempty" bson:"duration_per_service"`
}
type StatisticsFilter struct {
diff --git a/storage.go b/storage.go
index f8b7f9c..304e88c 100644
--- a/storage.go
+++ b/storage.go
@@ -25,16 +25,20 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
+ "time"
)
// Collections names
-const Connections = "connections"
-const ConnectionStreams = "connection_streams"
-const ImportingSessions = "importing_sessions"
-const Rules = "rules"
-const Settings = "settings"
-const Services = "services"
-const Statistics = "statistics"
+const (
+ Connections = "connections"
+ ConnectionStreams = "connection_streams"
+ ImportingSessions = "importing_sessions"
+ Rules = "rules"
+ Searches = "searches"
+ Settings = "settings"
+ Services = "services"
+ Statistics = "statistics"
+)
var ZeroRowID [12]byte
@@ -73,6 +77,7 @@ func NewMongoStorage(uri string, port int, database string) (*MongoStorage, erro
ConnectionStreams: db.Collection(ConnectionStreams),
ImportingSessions: db.Collection(ImportingSessions),
Rules: db.Collection(Rules),
+ Searches: db.Collection(Services),
Settings: db.Collection(Settings),
Services: db.Collection(Services),
Statistics: db.Collection(Statistics),
@@ -85,9 +90,13 @@ func NewMongoStorage(uri string, port int, database string) (*MongoStorage, erro
return nil, err
}
- if _, err := collections[ConnectionStreams].Indexes().CreateOne(ctx, mongo.IndexModel{
- Keys: bson.D{{"connection_id", -1}}, // descending
- Options: options.Index(),
+ if _, err := collections[ConnectionStreams].Indexes().CreateMany(ctx, []mongo.IndexModel{
+ {
+ Keys: bson.D{{"connection_id", -1}}, // descending
+ },
+ {
+ Keys: bson.D{{"payload_string", "text"}},
+ },
}); err != nil {
return nil, err
}
@@ -277,6 +286,8 @@ type FindOperation interface {
Projection(filter OrderedDocument) FindOperation
Sort(field string, ascending bool) FindOperation
Limit(n int64) FindOperation
+ Skip(n int64) FindOperation
+ MaxTime(duration time.Duration) FindOperation
First(result interface{}) error
All(results interface{}) error
}
@@ -318,6 +329,16 @@ func (fo MongoFindOperation) Limit(n int64) FindOperation {
return fo
}
+func (fo MongoFindOperation) Skip(n int64) FindOperation {
+ fo.optFind.SetSkip(n)
+ return fo
+}
+
+func (fo MongoFindOperation) MaxTime(duration time.Duration) FindOperation {
+ fo.optFind.SetMaxTime(duration)
+ return fo
+}
+
func (fo MongoFindOperation) Sort(field string, ascending bool) FindOperation {
var sort int
if ascending {
diff --git a/stream_handler.go b/stream_handler.go
index 48dba34..f08bd70 100644
--- a/stream_handler.go
+++ b/stream_handler.go
@@ -22,6 +22,7 @@ import (
"github.com/flier/gohs/hyperscan"
"github.com/google/gopacket/tcpassembly"
log "github.com/sirupsen/logrus"
+ "strings"
"time"
)
@@ -176,6 +177,7 @@ func (sh *StreamHandler) storageCurrentDocument() {
ConnectionID: ZeroRowID,
DocumentIndex: len(sh.documentsIDs),
Payload: sh.buffer.Bytes(),
+ PayloadString: strings.ToValidUTF8(string(sh.buffer.Bytes()), ""),
BlocksIndexes: sh.indexes,
BlocksTimestamps: sh.timestamps,
BlocksLoss: sh.lossBlocks,
--
cgit v1.2.3-70-g09d2
From 828aeef9a7333aaabeaf9324a85aac56348b3805 Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Sun, 11 Oct 2020 22:50:20 +0200
Subject: Add SearchController
---
application_context.go | 4 +--
application_router.go | 71 +++++++++++++----------------------------------
connections_controller.go | 47 +++++++++++++++++++------------
search_controller.go | 44 ++++++++++++++++++++---------
storage.go | 2 +-
5 files changed, 83 insertions(+), 85 deletions(-)
(limited to 'application_context.go')
diff --git a/application_context.go b/application_context.go
index fc76d00..8abb6f4 100644
--- a/application_context.go
+++ b/application_context.go
@@ -112,9 +112,9 @@ func (sm *ApplicationContext) configure() {
sm.RulesManager = rulesManager
sm.PcapImporter = NewPcapImporter(sm.Storage, *serverNet, sm.RulesManager)
sm.ServicesController = NewServicesController(sm.Storage)
- sm.ConnectionsController = NewConnectionsController(sm.Storage, sm.ServicesController)
- sm.ConnectionStreamsController = NewConnectionStreamsController(sm.Storage)
sm.SearchController = NewSearchController(sm.Storage)
+ sm.ConnectionsController = NewConnectionsController(sm.Storage, sm.SearchController, sm.ServicesController)
+ sm.ConnectionStreamsController = NewConnectionStreamsController(sm.Storage)
sm.StatisticsController = NewStatisticsController(sm.Storage)
sm.IsConfigured = true
}
diff --git a/application_router.go b/application_router.go
index dc9f9d4..656b63e 100644
--- a/application_router.go
+++ b/application_router.go
@@ -22,8 +22,6 @@ import (
"fmt"
"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
- "github.com/gin-gonic/gin/binding"
- "github.com/go-playground/validator/v10"
log "github.com/sirupsen/logrus"
"net/http"
"os"
@@ -297,71 +295,42 @@ func CreateApplicationRouter(applicationContext *ApplicationContext,
})
api.GET("/searches", func(c *gin.Context) {
- success(c, applicationContext.SearchController.PerformedSearches())
+ success(c, applicationContext.SearchController.GetPerformedSearches())
})
api.POST("/searches/perform", func(c *gin.Context) {
var options SearchOptions
-
- parentIsZero := func (fl validator.FieldLevel) bool {
- log.Println(fl.FieldName())
- log.Println("noooooo")
- return fl.Parent().IsZero()
- }
- eitherWith := func (fl validator.FieldLevel) bool {
- otherField := fl.Parent().FieldByName(fl.Param())
- log.Println(fl.Param())
- log.Println("bbbbbbbbbb")
- return (fl.Field().IsZero() && !otherField.IsZero()) || (!fl.Field().IsZero() && otherField.IsZero())
- }
- aaa := func (fl validator.FieldLevel) bool {
-
- log.Println("awww")
- return fl.Field().IsZero()
+ if err := c.ShouldBindJSON(&options); err != nil {
+ badRequest(c, err)
+ return
}
- bbb := func (fl validator.FieldLevel) bool {
-
- log.Println("iiiii")
- return true
+ // stupid checks because validator library is a shit
+ var badContentError error
+ if options.TextSearch.isZero() == options.RegexSearch.isZero() {
+ badContentError = errors.New("specify either 'text_search' or 'regex_search'")
}
-
- if validate, ok := binding.Validator.Engine().(*validator.Validate); ok {
- if err := validate.RegisterValidation("parent_is_zero", parentIsZero); err != nil {
- log.WithError(err).Panic("cannot register 'topzero' validator")
+ if !options.TextSearch.isZero() {
+ if (options.TextSearch.Terms == nil) == (options.TextSearch.ExactPhrase == "") {
+ badContentError = errors.New("specify either 'terms' or 'exact_phrase'")
}
- if err := validate.RegisterValidation("either_with", eitherWith); err != nil {
- log.WithError(err).Panic("cannot register 'either_with' validator")
+ if (options.TextSearch.Terms == nil) && (options.TextSearch.ExcludedTerms != nil) {
+ badContentError = errors.New("'excluded_terms' must be specified only with 'terms'")
}
- if err := validate.RegisterValidation("aaa", aaa); err != nil {
- log.WithError(err).Panic("cannot register 'either_with' validator")
- }
- if err := validate.RegisterValidation("bbb", bbb); err != nil {
- log.WithError(err).Panic("cannot register 'either_with' validator")
+ }
+ if !options.RegexSearch.isZero() {
+ if (options.RegexSearch.Pattern == "") == (options.RegexSearch.NotPattern == "") {
+ badContentError = errors.New("specify either 'pattern' or 'not_pattern'")
}
- } else {
- log.Panic("cannot ")
}
-
- if err := c.ShouldBindJSON(&options); err != nil {
- badRequest(c, err)
+ if badContentError != nil {
+ badRequest(c, badContentError)
return
}
- log.Println(options)
-
-
- success(c, "ok")
-
-
-
-
-
-
-
- //success(c, applicationContext.SearchController.PerformSearch(c, options))
+ success(c, applicationContext.SearchController.PerformSearch(c, options))
})
api.GET("/streams/:id", func(c *gin.Context) {
diff --git a/connections_controller.go b/connections_controller.go
index 30a5ee5..a293a80 100644
--- a/connections_controller.go
+++ b/connections_controller.go
@@ -48,33 +48,37 @@ type Connection struct {
}
type ConnectionsFilter struct {
- From string `form:"from" binding:"omitempty,hexadecimal,len=24"`
- To string `form:"to" binding:"omitempty,hexadecimal,len=24"`
- ServicePort uint16 `form:"service_port"`
- ClientAddress string `form:"client_address" binding:"omitempty,ip"`
- ClientPort uint16 `form:"client_port"`
- MinDuration uint `form:"min_duration"`
- MaxDuration uint `form:"max_duration" binding:"omitempty,gtefield=MinDuration"`
- MinBytes uint `form:"min_bytes"`
- MaxBytes uint `form:"max_bytes" binding:"omitempty,gtefield=MinBytes"`
- StartedAfter int64 `form:"started_after" `
- StartedBefore int64 `form:"started_before" binding:"omitempty,gtefield=StartedAfter"`
- ClosedAfter int64 `form:"closed_after" `
- ClosedBefore int64 `form:"closed_before" binding:"omitempty,gtefield=ClosedAfter"`
- Hidden bool `form:"hidden"`
- Marked bool `form:"marked"`
- MatchedRules []string `form:"matched_rules" binding:"dive,hexadecimal,len=24"`
- Limit int64 `form:"limit"`
+ From string `form:"from" binding:"omitempty,hexadecimal,len=24"`
+ To string `form:"to" binding:"omitempty,hexadecimal,len=24"`
+ ServicePort uint16 `form:"service_port"`
+ ClientAddress string `form:"client_address" binding:"omitempty,ip"`
+ ClientPort uint16 `form:"client_port"`
+ MinDuration uint `form:"min_duration"`
+ MaxDuration uint `form:"max_duration" binding:"omitempty,gtefield=MinDuration"`
+ MinBytes uint `form:"min_bytes"`
+ MaxBytes uint `form:"max_bytes" binding:"omitempty,gtefield=MinBytes"`
+ StartedAfter int64 `form:"started_after" `
+ StartedBefore int64 `form:"started_before" binding:"omitempty,gtefield=StartedAfter"`
+ ClosedAfter int64 `form:"closed_after" `
+ ClosedBefore int64 `form:"closed_before" binding:"omitempty,gtefield=ClosedAfter"`
+ Hidden bool `form:"hidden"`
+ Marked bool `form:"marked"`
+ MatchedRules []string `form:"matched_rules" binding:"dive,hexadecimal,len=24"`
+ PerformedSearch string `form:"performed_search" binding:"omitempty,hexadecimal,len=24"`
+ Limit int64 `form:"limit"`
}
type ConnectionsController struct {
storage Storage
+ searchController *SearchController
servicesController *ServicesController
}
-func NewConnectionsController(storage Storage, servicesController *ServicesController) ConnectionsController {
+func NewConnectionsController(storage Storage, searchesController *SearchController,
+ servicesController *ServicesController) ConnectionsController {
return ConnectionsController{
storage: storage,
+ searchController: searchesController,
servicesController: servicesController,
}
}
@@ -144,6 +148,13 @@ func (cc ConnectionsController) GetConnections(c context.Context, filter Connect
query = query.Filter(OrderedDocument{{"matched_rules", UnorderedDocument{"$all": matchedRules}}})
}
+ performedSearchID, _ := RowIDFromHex(filter.PerformedSearch)
+ if !performedSearchID.IsZero() {
+ performedSearch := cc.searchController.GetPerformedSearch(performedSearchID)
+ if !performedSearch.ID.IsZero() {
+ query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$in": performedSearch.AffectedConnections}}})
+ }
+ }
if filter.Limit > 0 && filter.Limit <= MaxQueryLimit {
query = query.Limit(filter.Limit)
} else {
diff --git a/search_controller.go b/search_controller.go
index ad47dbc..723cd93 100644
--- a/search_controller.go
+++ b/search_controller.go
@@ -26,14 +26,15 @@ import (
)
const (
- secondsToNano = 1000 * 1000 * 1000
- maxSearchTimeout = 60 * secondsToNano
+ secondsToNano = 1000 * 1000 * 1000
+ maxSearchTimeout = 10 * secondsToNano
+ maxRecentSearches = 200
)
type PerformedSearch struct {
ID RowID `bson:"_id" json:"id"`
SearchOptions SearchOptions `bson:"search_options" json:"search_options"`
- AffectedConnections []RowID `bson:"affected_connections" json:"affected_connections,omitempty"`
+ AffectedConnections []RowID `bson:"affected_connections" json:"-"`
AffectedConnectionsCount int `bson:"affected_connections_count" json:"affected_connections_count"`
StartedAt time.Time `bson:"started_at" json:"started_at"`
FinishedAt time.Time `bson:"finished_at" json:"finished_at"`
@@ -42,21 +43,21 @@ type PerformedSearch struct {
}
type SearchOptions struct {
- TextSearch TextSearch `bson:"text_search" json:"text_search" validate:"either_with=RegexSearch"`
- RegexSearch RegexSearch `bson:"regex_search" json:"regex_search" validate:"either_with=TextSearch"`
+ TextSearch TextSearch `bson:"text_search" json:"text_search"`
+ RegexSearch RegexSearch `bson:"regex_search" json:"regex_search"`
Timeout time.Duration `bson:"timeout" json:"timeout" binding:"max=60"`
}
type TextSearch struct {
- Terms []string `bson:"terms" json:"terms" binding:"parent_is_zero|either_with=ExactPhrase,isdefault|min=1,dive,min=3"`
- ExcludedTerms []string `bson:"excluded_terms" json:"excluded_terms" binding:"required_with=Terms,dive,isdefault|min=1"`
- ExactPhrase string `bson:"exact_phrase" json:"exact_phrase" binding:"isdefault|min=3,parent_is_zero|either_with=Terms"`
+ Terms []string `bson:"terms" json:"terms" binding:"isdefault|min=1,dive,min=3"`
+ ExcludedTerms []string `bson:"excluded_terms" json:"excluded_terms" binding:"isdefault|min=1,dive,min=3"`
+ ExactPhrase string `bson:"exact_phrase" json:"exact_phrase" binding:"isdefault|min=3"`
CaseSensitive bool `bson:"case_sensitive" json:"case_sensitive"`
}
type RegexSearch struct {
- Pattern string `bson:"pattern" json:"pattern" binding:"parent_is_zero|either_with=NotPattern,isdefault|min=3"`
- NotPattern string `bson:"not_pattern" json:"not_pattern" binding:"parent_is_zero|either_with=Pattern,isdefault|min=3"`
+ Pattern string `bson:"pattern" json:"pattern" binding:"isdefault|min=3"`
+ NotPattern string `bson:"not_pattern" json:"not_pattern" binding:"isdefault|min=3"`
CaseInsensitive bool `bson:"case_insensitive" json:"case_insensitive"`
MultiLine bool `bson:"multi_line" json:"multi_line"`
IgnoreWhitespaces bool `bson:"ignore_whitespaces" json:"ignore_whitespaces"`
@@ -71,8 +72,8 @@ type SearchController struct {
func NewSearchController(storage Storage) *SearchController {
var searches []PerformedSearch
- if err := storage.Find(Searches).All(&searches); err != nil {
- // log.WithError(err).Panic("failed to retrieve performed searches")
+ if err := storage.Find(Searches).Limit(maxRecentSearches).All(&searches); err != nil {
+ log.WithError(err).Panic("failed to retrieve performed searches")
}
return &SearchController{
@@ -81,13 +82,27 @@ func NewSearchController(storage Storage) *SearchController {
}
}
-func (sc *SearchController) PerformedSearches() []PerformedSearch {
+func (sc *SearchController) GetPerformedSearches() []PerformedSearch {
sc.mutex.Lock()
defer sc.mutex.Unlock()
return sc.performedSearches
}
+func (sc *SearchController) GetPerformedSearch(id RowID) PerformedSearch {
+ sc.mutex.Lock()
+ defer sc.mutex.Unlock()
+
+ var performedSearch PerformedSearch
+ for _, search := range sc.performedSearches {
+ if search.ID == id {
+ performedSearch = search
+ }
+ }
+
+ return performedSearch
+}
+
func (sc *SearchController) PerformSearch(c context.Context, options SearchOptions) PerformedSearch {
findQuery := sc.storage.Find(ConnectionStreams).Projection(OrderedDocument{{"connection_id", 1}}).Context(c)
timeout := options.Timeout * secondsToNano
@@ -163,6 +178,9 @@ func (sc *SearchController) PerformSearch(c context.Context, options SearchOptio
sc.mutex.Lock()
sc.performedSearches = append([]PerformedSearch{performedSearch}, sc.performedSearches...)
+ if len(sc.performedSearches) > maxRecentSearches {
+ sc.performedSearches = sc.performedSearches[:200]
+ }
sc.mutex.Unlock()
return performedSearch
diff --git a/storage.go b/storage.go
index 304e88c..8505bfe 100644
--- a/storage.go
+++ b/storage.go
@@ -77,7 +77,7 @@ func NewMongoStorage(uri string, port int, database string) (*MongoStorage, erro
ConnectionStreams: db.Collection(ConnectionStreams),
ImportingSessions: db.Collection(ImportingSessions),
Rules: db.Collection(Rules),
- Searches: db.Collection(Services),
+ Searches: db.Collection(Searches),
Settings: db.Collection(Settings),
Services: db.Collection(Services),
Statistics: db.Collection(Statistics),
--
cgit v1.2.3-70-g09d2
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
---
application_context.go | 12 +-
caronte.go | 2 +
frontend/src/components/App.js | 6 +-
frontend/src/components/Notifications.js | 17 +-
frontend/src/components/Timeline.js | 88 +++++----
frontend/src/components/fields/ButtonField.js | 2 +-
frontend/src/components/fields/ChoiceField.js | 10 +-
frontend/src/components/objects/Connection.js | 36 +---
.../components/objects/ConnectionMatchedRules.js | 10 +-
frontend/src/components/objects/CopyLinkPopover.js | 54 ++++++
frontend/src/components/objects/MessageAction.js | 15 +-
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 ++++---
frontend/src/serviceWorker.js | 208 ++++++++++-----------
parsers/http_request_parser.go | 12 +-
pcap_importer.go | 39 ++--
19 files changed, 458 insertions(+), 353 deletions(-)
create mode 100644 frontend/src/components/objects/CopyLinkPopover.js
(limited to 'application_context.go')
diff --git a/application_context.go b/application_context.go
index 8abb6f4..0410b88 100644
--- a/application_context.go
+++ b/application_context.go
@@ -39,6 +39,7 @@ type ApplicationContext struct {
ConnectionStreamsController ConnectionStreamsController
SearchController *SearchController
StatisticsController StatisticsController
+ NotificationController *NotificationController
IsConfigured bool
Version string
}
@@ -70,13 +71,12 @@ func CreateApplicationContext(storage Storage, version string) (*ApplicationCont
Version: version,
}
- applicationContext.configure()
return applicationContext, nil
}
func (sm *ApplicationContext) SetConfig(config Config) {
sm.Config = config
- sm.configure()
+ sm.Configure()
var upsertResults interface{}
if _, err := sm.Storage.Update(Settings).Upsert(&upsertResults).
Filter(OrderedDocument{{"_id", "config"}}).One(UnorderedDocument{"config": config}); err != nil {
@@ -93,7 +93,11 @@ func (sm *ApplicationContext) SetAccounts(accounts gin.Accounts) {
}
}
-func (sm *ApplicationContext) configure() {
+func (sm *ApplicationContext) SetNotificationController(notificationController *NotificationController) {
+ sm.NotificationController = notificationController
+}
+
+func (sm *ApplicationContext) Configure() {
if sm.IsConfigured {
return
}
@@ -110,7 +114,7 @@ func (sm *ApplicationContext) configure() {
log.WithError(err).Panic("failed to create a RulesManager")
}
sm.RulesManager = rulesManager
- sm.PcapImporter = NewPcapImporter(sm.Storage, *serverNet, sm.RulesManager)
+ sm.PcapImporter = NewPcapImporter(sm.Storage, *serverNet, sm.RulesManager, sm.NotificationController)
sm.ServicesController = NewServicesController(sm.Storage)
sm.SearchController = NewSearchController(sm.Storage)
sm.ConnectionsController = NewConnectionsController(sm.Storage, sm.SearchController, sm.ServicesController)
diff --git a/caronte.go b/caronte.go
index 2d24af6..95f00ef 100644
--- a/caronte.go
+++ b/caronte.go
@@ -51,10 +51,12 @@ func main() {
notificationController := NewNotificationController(applicationContext)
go notificationController.Run()
+ applicationContext.SetNotificationController(notificationController)
resourcesController := NewResourcesController(notificationController)
go resourcesController.Run()
+ applicationContext.Configure()
applicationRouter := CreateApplicationRouter(applicationContext, notificationController, resourcesController)
if applicationRouter.Run(fmt.Sprintf("%s:%v", *bindAddress, *bindPort)) != nil {
log.WithError(err).WithFields(logFields).Fatal("failed to create the server")
diff --git a/frontend/src/components/App.js b/frontend/src/components/App.js
index 0f700db..888ff86 100644
--- a/frontend/src/components/App.js
+++ b/frontend/src/components/App.js
@@ -15,10 +15,10 @@
* along with this program. If not, see .
*/
-import React, {Component} from 'react';
-import ConfigurationPage from "./pages/ConfigurationPage";
-import Notifications from "./Notifications";
+import React, {Component} from "react";
import dispatcher from "../dispatcher";
+import Notifications from "./Notifications";
+import ConfigurationPage from "./pages/ConfigurationPage";
import MainPage from "./pages/MainPage";
import ServiceUnavailablePage from "./pages/ServiceUnavailablePage";
diff --git a/frontend/src/components/Notifications.js b/frontend/src/components/Notifications.js
index 56a4508..92731d9 100644
--- a/frontend/src/components/Notifications.js
+++ b/frontend/src/components/Notifications.js
@@ -17,6 +17,7 @@
import React, {Component} from "react";
import dispatcher from "../dispatcher";
+import {randomClassName} from "../utils";
import "./Notifications.scss";
const _ = require("lodash");
@@ -30,9 +31,15 @@ class Notifications extends Component {
};
componentDidMount() {
- dispatcher.register("notifications", n => this.notificationHandler(n));
+ dispatcher.register("notifications", this.handleNotifications);
}
+ componentWillUnmount() {
+ dispatcher.unregister(this.handleNotifications);
+ }
+
+ handleNotifications = (n) => this.notificationHandler(n);
+
notificationHandler = (n) => {
switch (n.event) {
case "connected":
@@ -54,6 +61,11 @@ class Notifications extends Component {
n.description = `existing rule updated: ${n.message["name"]}`;
n.variant = "blue";
return this.pushNotification(n);
+ case "pcap.completed":
+ n.title = "new pcap analyzed";
+ n.description = `${n.message["processed_packets"]} packets processed`;
+ n.variant = "blue";
+ return this.pushNotification(n);
default:
return;
}
@@ -61,6 +73,7 @@ class Notifications extends Component {
pushNotification = (notification) => {
const notifications = this.state.notifications;
+ notification.id = randomClassName();
notifications.push(notification);
this.setState({notifications});
setTimeout(() => {
@@ -103,7 +116,7 @@ class Notifications extends Component {
if (n.variant) {
notificationClassnames[`notification-${n.variant}`] = true;
}
- return
+ return
{n.title}
{n.description}
;
diff --git a/frontend/src/components/Timeline.js b/frontend/src/components/Timeline.js
index 8d1fd40..94fa4d0 100644
--- a/frontend/src/components/Timeline.js
+++ b/frontend/src/components/Timeline.js
@@ -15,8 +15,9 @@
* along with this program. If not, see .
*/
-import React, {Component} from 'react';
-import './Timeline.scss';
+import {TimeRange, TimeSeries} from "pondjs";
+import React, {Component} from "react";
+import {withRouter} from "react-router-dom";
import {
ChartContainer,
ChartRow,
@@ -27,15 +28,14 @@ import {
styler,
YAxis
} from "react-timeseries-charts";
-import {TimeRange, TimeSeries} from "pondjs";
import backend from "../backend";
-import ChoiceField from "./fields/ChoiceField";
-import {withRouter} from "react-router-dom";
-import log from "../log";
import dispatcher from "../dispatcher";
+import log from "../log";
+import ChoiceField from "./fields/ChoiceField";
+import "./Timeline.scss";
const minutes = 60 * 1000;
-const classNames = require('classnames');
+const classNames = require("classnames");
const leftSelectionPaddingMultiplier = 24;
const rightSelectionPaddingMultiplier = 8;
@@ -61,42 +61,17 @@ class Timeline extends Component {
});
this.loadStatistics(this.state.metric).then(() => log.debug("Statistics loaded after mount"));
-
- this.connectionsFiltersCallback = (payload) => {
- if ("service_port" in payload && this.state.servicePortFilter !== payload["service_port"]) {
- this.setState({servicePortFilter: payload["service_port"]});
- this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after service port changed"));
- }
- if ("matched_rules" in payload && this.state.matchedRulesFilter !== payload["matched_rules"]) {
- this.setState({matchedRulesFilter: payload["matched_rules"]});
- this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after matched rules changed"));
- }
- };
- dispatcher.register("connections_filters", this.connectionsFiltersCallback);
-
- dispatcher.register("connection_updates", (payload) => {
- this.setState({
- selection: new TimeRange(payload.from, payload.to),
- });
- this.adjustSelection();
- });
-
- dispatcher.register("notifications", (payload) => {
- if (payload.event === "services.edit" && this.state.metric !== "matched_rules") {
- this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after services updates"));
- } else if (payload.event.startsWith("rules") && this.state.metric === "matched_rules") {
- this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after rules updates"));
- }
- });
-
- dispatcher.register("pulse_timeline", (payload) => {
- this.setState({pulseTimeline: true});
- setTimeout(() => this.setState({pulseTimeline: false}), payload.duration);
- });
+ dispatcher.register("connections_filters", this.handleConnectionsFiltersCallback);
+ dispatcher.register("connection_updates", this.handleConnectionUpdates);
+ dispatcher.register("notifications", this.handleNotifications);
+ dispatcher.register("pulse_timeline", this.handlePulseTimeline);
}
componentWillUnmount() {
- dispatcher.unregister(this.connectionsFiltersCallback);
+ dispatcher.unregister(this.handleConnectionsFiltersCallback);
+ dispatcher.unregister(this.handleConnectionUpdates);
+ dispatcher.unregister(this.handleNotifications);
+ dispatcher.unregister(this.handlePulseTimeline);
}
loadStatistics = async (metric) => {
@@ -217,6 +192,39 @@ class Timeline extends Component {
}, 1000);
};
+ handleConnectionsFiltersCallback = (payload) => {
+ if ("service_port" in payload && this.state.servicePortFilter !== payload["service_port"]) {
+ this.setState({servicePortFilter: payload["service_port"]});
+ this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after service port changed"));
+ }
+ if ("matched_rules" in payload && this.state.matchedRulesFilter !== payload["matched_rules"]) {
+ this.setState({matchedRulesFilter: payload["matched_rules"]});
+ this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after matched rules changed"));
+ }
+ };
+
+ handleConnectionUpdates = (payload) => {
+ this.setState({
+ selection: new TimeRange(payload.from, payload.to),
+ });
+ this.adjustSelection();
+ };
+
+ handleNotifications = (payload) => {
+ if (payload.event === "services.edit" && this.state.metric !== "matched_rules") {
+ this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after services updates"));
+ } else if (payload.event.startsWith("rules") && this.state.metric === "matched_rules") {
+ this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after rules updates"));
+ } else if (payload.event === "pcap.completed") {
+ this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after pcap processed"));
+ }
+ };
+
+ handlePulseTimeline = (payload) => {
+ this.setState({pulseTimeline: true});
+ setTimeout(() => this.setState({pulseTimeline: false}), payload.duration);
+ };
+
adjustSelection = () => {
const seriesRange = this.state.series.range();
const selection = this.state.selection;
diff --git a/frontend/src/components/fields/ButtonField.js b/frontend/src/components/fields/ButtonField.js
index de747a5..15ef179 100644
--- a/frontend/src/components/fields/ButtonField.js
+++ b/frontend/src/components/fields/ButtonField.js
@@ -58,7 +58,7 @@ class ButtonField extends Component {
);
diff --git a/frontend/src/components/objects/ConnectionMatchedRules.js b/frontend/src/components/objects/ConnectionMatchedRules.js
index 92bde49..cfd1254 100644
--- a/frontend/src/components/objects/ConnectionMatchedRules.js
+++ b/frontend/src/components/objects/ConnectionMatchedRules.js
@@ -15,11 +15,11 @@
* along with this program. If not, see .
*/
-import React, {Component} from 'react';
-import './ConnectionMatchedRules.scss';
-import ButtonField from "../fields/ButtonField";
-import dispatcher from "../../dispatcher";
+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 {
@@ -28,7 +28,7 @@ class ConnectionMatchedRules extends Component {
const rules = params.getAll("matched_rules");
if (!rules.includes(id)) {
rules.push(id);
- dispatcher.dispatch("connections_filters",{"matched_rules": rules});
+ dispatcher.dispatch("connections_filters", {"matched_rules": rules});
}
};
diff --git a/frontend/src/components/objects/CopyLinkPopover.js b/frontend/src/components/objects/CopyLinkPopover.js
new file mode 100644
index 0000000..fa9266f
--- /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 .
+ */
+
+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 =