From e905618113309eaba7227ff1328a20f6846e4afd Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Mon, 5 Oct 2020 23:46:18 +0200 Subject: Implement timeline --- connections_controller.go | 52 ++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'connections_controller.go') diff --git a/connections_controller.go b/connections_controller.go index 2773506..2894193 100644 --- a/connections_controller.go +++ b/connections_controller.go @@ -31,40 +31,40 @@ 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"` + 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"` + Limit int64 `form:"limit"` } type ConnectionsController struct { - storage Storage + storage Storage servicesController *ServicesController } func NewConnectionsController(storage Storage, servicesController *ServicesController) ConnectionsController { return ConnectionsController{ - storage: storage, + storage: storage, servicesController: servicesController, } } func (cc ConnectionsController) GetConnections(c context.Context, filter ConnectionsFilter) []Connection { var connections []Connection - query := cc.storage.Find(Connections).Context(c).Sort("_id", false) + query := cc.storage.Find(Connections).Context(c) from, _ := RowIDFromHex(filter.From) if !from.IsZero() { @@ -73,6 +73,8 @@ func (cc ConnectionsController) GetConnections(c context.Context, filter Connect to, _ := RowIDFromHex(filter.To) if !to.IsZero() { query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$gt": to}}}) + } else { + query = query.Sort("_id", false) } if filter.ServicePort > 0 { query = query.Filter(OrderedDocument{{"port_dst", filter.ServicePort}}) @@ -146,6 +148,10 @@ func (cc ConnectionsController) GetConnections(c context.Context, filter Connect } } + if !to.IsZero() { + connections = reverseConnections(connections) + } + return connections } @@ -178,3 +184,11 @@ func (cc ConnectionsController) setProperty(c context.Context, id RowID, propert } return updated } + +func reverseConnections(connections []Connection) []Connection { + for i := 0; i < len(connections)/2; i++ { + j := len(connections) - i - 1 + connections[i], connections[j] = connections[j], connections[i] + } + return connections +} -- cgit v1.2.3-70-g09d2 From 2b2b8e66e7244592672c283fe7bb5d9a1fd9da99 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Thu, 8 Oct 2020 11:16:38 +0200 Subject: Minor changes --- application_router.go | 6 +- connections_controller.go | 4 +- frontend/src/components/Connection.js | 33 ++--- frontend/src/components/Connection.scss | 4 + frontend/src/components/Notifications.js | 14 +- frontend/src/components/Notifications.scss | 1 + frontend/src/views/App.js | 4 +- frontend/src/views/Connections.js | 44 ++++-- frontend/src/views/Footer.js | 176 ----------------------- frontend/src/views/Footer.scss | 22 --- frontend/src/views/Header.js | 24 ++-- frontend/src/views/Timeline.js | 215 +++++++++++++++++++++++++++++ frontend/src/views/Timeline.scss | 22 +++ 13 files changed, 313 insertions(+), 256 deletions(-) delete mode 100644 frontend/src/views/Footer.js delete mode 100644 frontend/src/views/Footer.scss create mode 100644 frontend/src/views/Timeline.js create mode 100644 frontend/src/views/Timeline.scss (limited to 'connections_controller.go') diff --git a/application_router.go b/application_router.go index 6431e22..30ec7c6 100644 --- a/application_router.go +++ b/application_router.go @@ -269,9 +269,9 @@ func CreateApplicationRouter(applicationContext *ApplicationContext, } if result { - c.Status(http.StatusAccepted) - notificationController.Notify("connections.action", UpdateNotification, - gin.H{"connection_id": c.Param("id"), "action": c.Param("action")}) + response := gin.H{"connection_id": c.Param("id"), "action": c.Param("action")} + success(c, response) + notificationController.Notify("connections.action", UpdateNotification, response) } else { notFound(c, gin.H{"connection": id}) } diff --git a/connections_controller.go b/connections_controller.go index 2894193..e872c9f 100644 --- a/connections_controller.go +++ b/connections_controller.go @@ -68,11 +68,11 @@ func (cc ConnectionsController) GetConnections(c context.Context, filter Connect from, _ := RowIDFromHex(filter.From) if !from.IsZero() { - query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$lt": from}}}) + query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$lte": from}}}) } to, _ := RowIDFromHex(filter.To) if !to.IsZero() { - query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$gt": to}}}) + query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$gte": to}}}) } else { query = query.Sort("_id", false) } diff --git a/frontend/src/components/Connection.js b/frontend/src/components/Connection.js index 46a0cab..b7e2531 100644 --- a/frontend/src/components/Connection.js +++ b/frontend/src/components/Connection.js @@ -4,6 +4,7 @@ import {Form, OverlayTrigger, Popover} from "react-bootstrap"; import backend from "../backend"; import {dateTimeToTime, durationBetween, formatSize} from "../utils"; import ButtonField from "./fields/ButtonField"; +import LinkPopover from "./objects/LinkPopover"; const classNames = require('classnames'); @@ -54,9 +55,9 @@ class Connection extends Component { serviceName = service.name; serviceColor = service.color; } - let startedAt = new Date(conn.started_at); - let closedAt = new Date(conn.closed_at); - let processedAt = new Date(conn.processed_at); + let startedAt = new Date(conn["started_at"]); + let closedAt = new Date(conn["closed_at"]); + let processedAt = new Date(conn["processed_at"]); let timeInfo =
Started at {startedAt.toLocaleDateString() + " " + startedAt.toLocaleTimeString()}
Processed at {processedAt.toLocaleDateString() + " " + processedAt.toLocaleTimeString()}
@@ -88,28 +89,20 @@ class Connection extends Component { this.props.addServicePortFilter(conn.port_dst)}/> + onClick={() => this.props.addServicePortFilter(conn["port_dst"])}/> - {conn.ip_src} - {conn.port_src} - {conn.ip_dst} - {conn.port_dst} - {dateTimeToTime(conn.started_at)} + {conn["ip_src"]} + {conn["port_src"]} + {conn["ip_dst"]} + {conn["port_dst"]} - - {durationBetween(startedAt, closedAt)} - + - {formatSize(conn.client_bytes)} - {formatSize(conn.server_bytes)} + {durationBetween(startedAt, closedAt)} + {formatSize(conn["client_bytes"])} + {formatSize(conn["server_bytes"])} - {/*Hide this connection from the list)}>*/} - {/* this.handleAction("hide")}>%*/} - {/**/} Mark this connection)}> { const notifications = this.state.notifications; notification.open = true; this.setState({notifications}); }, 100); - setTimeout(() => { + const hideHandle = setTimeout(() => { const notifications = _.without(this.state.notifications, notification); const closedNotifications = this.state.closedNotifications.concat([notification]); notification.closed = true; this.setState({notifications, closedNotifications}); }, 5000); - setTimeout(() => { + const removeHandle = setTimeout(() => { const closedNotifications = _.without(this.state.closedNotifications, notification); this.setState({closedNotifications}); }, 6000); + + notification.onClick = () => { + clearTimeout(hideHandle); + clearTimeout(removeHandle); + const notifications = _.without(this.state.notifications, notification); + this.setState({notifications}); + }; }); } @@ -45,7 +51,7 @@ class Notifications extends Component { { this.state.closedNotifications.concat(this.state.notifications).map(n =>
+ {"notification-open": n.open})} onClick={n.onClick}>

{n.event}

{JSON.stringify(n.message)}
diff --git a/frontend/src/components/Notifications.scss b/frontend/src/components/Notifications.scss index bec7734..324d0bb 100644 --- a/frontend/src/components/Notifications.scss +++ b/frontend/src/components/Notifications.scss @@ -18,6 +18,7 @@ color: $color-green-light; border-left: 5px solid $color-green-dark; background-color: $color-green; + cursor: pointer; .notification-title { font-size: 0.9em; diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index c14b7f5..4bb9f57 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -2,7 +2,7 @@ import React, {Component} from 'react'; import './App.scss'; import Header from "./Header"; import MainPane from "../components/panels/MainPane"; -import Footer from "./Footer"; +import Timeline from "./Timeline"; import {BrowserRouter as Router} from "react-router-dom"; import Filters from "./Filters"; import ConfigurationPane from "../components/panels/ConfigurationPane"; @@ -52,7 +52,7 @@ class App extends Component { {modal}
- {this.state.configured &&
} diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js index bd631a2..e835dcb 100644 --- a/frontend/src/views/Connections.js +++ b/frontend/src/views/Connections.js @@ -17,7 +17,6 @@ class Connections extends Component { connections: [], firstConnection: null, lastConnection: null, - queryString: null }; constructor(props) { @@ -29,14 +28,15 @@ class Connections extends Component { this.queryLimit = 50; this.connectionsListRef = React.createRef(); this.lastScrollPosition = 0; + this.doQueryStringRedirect = false; + this.doSelectedConnectionRedirect = false; } componentDidMount() { this.loadConnections({limit: this.queryLimit}) .then(() => this.setState({loaded: true})); - if (this.props.initialConnection != null) { + if (this.props.initialConnection) { this.setState({selected: this.props.initialConnection.id}); - // TODO: scroll to initial connection } dispatcher.register("timeline_updates", payload => { @@ -62,19 +62,24 @@ class Connections extends Component { } connectionSelected = (c) => { + this.doSelectedConnectionRedirect = true; this.setState({selected: c.id}); this.props.onSelected(c); }; componentDidUpdate(prevProps, prevState, snapshot) { if (this.state.loaded && prevProps.location.search !== this.props.location.search) { - this.setState({queryString: this.props.location.search}); this.loadConnections({limit: this.queryLimit}) .then(() => log.info("Connections reloaded after query string update")); } } handleScroll = (e) => { + if (this.disableScrollHandler) { + this.lastScrollPosition = e.currentTarget.scrollTop; + return; + } + let relativeScroll = e.currentTarget.scrollTop / (e.currentTarget.scrollHeight - e.currentTarget.clientHeight); if (!this.state.loading && relativeScroll > this.scrollBottomThreashold) { this.loadConnections({from: this.state.lastConnection.id, limit: this.queryLimit,}) @@ -103,7 +108,8 @@ class Connections extends Component { addServicePortFilter = (port) => { const urlParams = new URLSearchParams(this.props.location.search); urlParams.set("service_port", port); - this.setState({queryString: "?" + urlParams}); + this.doQueryStringRedirect = true; + this.setState({queryString: urlParams}); }; addMatchedRulesFilter = (matchedRule) => { @@ -112,7 +118,8 @@ class Connections extends Component { if (!oldMatchedRules.includes(matchedRule)) { urlParams.append("matched_rules", matchedRule); - this.setState({queryString: "?" + urlParams}); + this.doQueryStringRedirect = true; + this.setState({queryString: urlParams}); } }; @@ -139,7 +146,7 @@ class Connections extends Component { if (params !== undefined && params.from !== undefined && params.to === undefined) { if (res.length > 0) { - connections = this.state.connections.concat(res); + connections = this.state.connections.concat(res.slice(1)); lastConnection = connections[connections.length - 1]; if (connections.length > this.maxConnections) { connections = connections.slice(connections.length - this.maxConnections, @@ -149,7 +156,7 @@ class Connections extends Component { } } else if (params !== undefined && params.to !== undefined && params.from === undefined) { if (res.length > 0) { - connections = res.concat(this.state.connections); + connections = res.slice(0, res.length - 1).concat(this.state.connections); firstConnection = connections[0]; if (connections.length > this.maxConnections) { connections = connections.slice(0, this.maxConnections); @@ -157,7 +164,6 @@ class Connections extends Component { } } } else { - this.connectionsListRef.current.scrollTop = 0; if (res.length > 0) { connections = res; firstConnection = connections[0]; @@ -194,9 +200,12 @@ class Connections extends Component { render() { let redirect; - let queryString = this.state.queryString !== null ? this.state.queryString : ""; - if (this.state.selected) { - redirect = ; + if (this.doSelectedConnectionRedirect) { + redirect = ; + this.doSelectedConnectionRedirect = false; + } else if (this.doQueryStringRedirect) { + redirect = ; + this.doQueryStringRedirect = false; } let loading = null; @@ -209,10 +218,15 @@ class Connections extends Component { return (
{this.state.showMoreRecentButton &&
- + { + this.disableScrollHandler = true; + this.connectionsListRef.current.scrollTop = 0; this.loadConnections({limit: this.queryLimit}) - .then(() => log.info("Most recent connections loaded")) - }/> + .then(() => { + this.disableScrollHandler = false; + log.info("Most recent connections loaded"); + }); + }}/>
}
diff --git a/frontend/src/views/Footer.js b/frontend/src/views/Footer.js deleted file mode 100644 index dcf9cf8..0000000 --- a/frontend/src/views/Footer.js +++ /dev/null @@ -1,176 +0,0 @@ -import React, {Component} from 'react'; -import './Footer.scss'; -import { - ChartContainer, - ChartRow, - Charts, - LineChart, - MultiBrush, - Resizable, - styler, - YAxis -} from "react-timeseries-charts"; -import {TimeRange, TimeSeries} from "pondjs"; -import backend from "../backend"; -import ChoiceField from "../components/fields/ChoiceField"; -import {withRouter} from "react-router-dom"; -import log from "../log"; -import dispatcher from "../dispatcher"; - - -class Footer extends Component { - - state = { - metric: "connections_per_service" - }; - - constructor() { - super(); - - this.disableTimeSeriesChanges = false; - this.selectionTimeout = null; - } - - filteredPort = () => { - const urlParams = new URLSearchParams(this.props.location.search); - return urlParams.get("service_port"); - }; - - componentDidMount() { - const filteredPort = this.filteredPort(); - this.setState({filteredPort}); - 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), - }); - }); - } - - componentDidUpdate(prevProps, prevState, snapshot) { - const filteredPort = this.filteredPort(); - if (this.state.filteredPort !== filteredPort) { - this.setState({filteredPort}); - this.loadStatistics(this.state.metric, filteredPort).then(() => - log.debug("Statistics reloaded after filtered port changes")); - } - } - - loadStatistics = async (metric, filteredPort) => { - const urlParams = new URLSearchParams(); - urlParams.set("metric", metric); - - let services = (await backend.get("/api/services")).json; - if (filteredPort && services[filteredPort]) { - const service = services[filteredPort]; - services = {}; - services[filteredPort] = service; - } - - const ports = Object.keys(services); - ports.forEach(s => urlParams.append("ports", s)); - - const metrics = (await backend.get("/api/statistics?" + urlParams)).json; - const series = new TimeSeries({ - name: "statistics", - columns: ["time"].concat(ports), - points: metrics.map(m => [new Date(m["range_start"])].concat(ports.map(p => m[metric][p] || 0))) - }); - this.setState({ - metric, - series, - services, - timeRange: series.range(), - }); - log.debug(`Loaded statistics for metric "${metric}" for services [${ports}]`); - }; - - createStyler = () => { - return styler(Object.keys(this.state.services).map(port => { - return {key: port, color: this.state.services[port].color, width: 2}; - })); - }; - - handleTimeRangeChange = (timeRange) => { - if (!this.disableTimeSeriesChanges) { - this.setState({timeRange}); - } - }; - - handleSelectionChange = (timeRange) => { - this.disableTimeSeriesChanges = true; - - this.setState({selection: timeRange}); - if (this.selectionTimeout) { - clearTimeout(this.selectionTimeout); - } - this.selectionTimeout = setTimeout(() => { - dispatcher.dispatch("timeline_updates", { - from: timeRange.begin(), - to: timeRange.end() - }); - this.selectionTimeout = null; - this.disableTimeSeriesChanges = false; - }, 1000); - }; - - aggregateSeries = (func) => { - const values = this.state.series.columns().map(c => this.state.series[func](c)); - return Math[func](...values); - }; - - render() { - return ( -
-
- {this.state.series && - <> - - - - - - - - - - - - - - -
- this.loadStatistics(metric, this.state.filteredPort) - .then(() => log.debug("Statistics loaded after metric changes"))} - value={this.state.metric}/> -
- - } -
-
- ); - } -} - -export default withRouter(Footer); diff --git a/frontend/src/views/Footer.scss b/frontend/src/views/Footer.scss deleted file mode 100644 index 14360d4..0000000 --- a/frontend/src/views/Footer.scss +++ /dev/null @@ -1,22 +0,0 @@ -@import "../colors.scss"; - -.footer { - padding: 15px; - - .time-line { - position: relative; - background-color: $color-primary-0; - - .metric-selection { - font-size: 0.8em; - position: absolute; - top: 5px; - right: 10px; - } - } - - svg text { - font-family: "Fira Code", monospace !important; - fill: $color-primary-4 !important; - } -} diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js index 944f1d5..f5eff17 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -2,7 +2,7 @@ import React, {Component} from 'react'; import Typed from 'typed.js'; import './Header.scss'; import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions"; -import {Link} from "react-router-dom"; +import {Link, withRouter} from "react-router-dom"; import ButtonField from "../components/fields/ButtonField"; class Header extends Component { @@ -46,7 +46,7 @@ class Header extends Component { render() { let quickFilters = filtersNames.filter(name => this.state[`${name}_active`]) - .map(name => {filtersDefinitions[name]}) + .map(name => {filtersDefinitions[name]}) .slice(0, 5); return ( @@ -68,18 +68,18 @@ class Header extends Component {
- - - + + + - - + + - - + + - - + +
@@ -89,4 +89,4 @@ class Header extends Component { } } -export default Header; +export default withRouter(Header); diff --git a/frontend/src/views/Timeline.js b/frontend/src/views/Timeline.js new file mode 100644 index 0000000..3adbf88 --- /dev/null +++ b/frontend/src/views/Timeline.js @@ -0,0 +1,215 @@ +import React, {Component} from 'react'; +import './Timeline.scss'; +import { + ChartContainer, + ChartRow, + Charts, + LineChart, + MultiBrush, + Resizable, + styler, + YAxis +} from "react-timeseries-charts"; +import {TimeRange, TimeSeries} from "pondjs"; +import backend from "../backend"; +import ChoiceField from "../components/fields/ChoiceField"; +import {withRouter} from "react-router-dom"; +import log from "../log"; +import dispatcher from "../dispatcher"; + +const minutes = 60 * 1000; + +class Timeline extends Component { + + state = { + metric: "connections_per_service" + }; + + constructor() { + super(); + + this.disableTimeSeriesChanges = false; + this.selectionTimeout = null; + } + + filteredPort = () => { + const urlParams = new URLSearchParams(this.props.location.search); + return urlParams.get("service_port"); + }; + + componentDidMount() { + const filteredPort = this.filteredPort(); + this.setState({filteredPort}); + 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), + }); + }); + + dispatcher.register("notifications", payload => { + if (payload.event === "services.edit") { + this.loadServices().then(() => log.debug("Services reloaded after notification update")); + } + }); + } + + componentDidUpdate(prevProps, prevState, snapshot) { + const filteredPort = this.filteredPort(); + if (this.state.filteredPort !== filteredPort) { + this.setState({filteredPort}); + this.loadStatistics(this.state.metric, filteredPort).then(() => + log.debug("Statistics reloaded after filtered port changes")); + } + } + + loadStatistics = async (metric, filteredPort) => { + const urlParams = new URLSearchParams(); + urlParams.set("metric", metric); + + let services = await this.loadServices(); + if (filteredPort && services[filteredPort]) { + const service = services[filteredPort]; + services = {}; + services[filteredPort] = service; + } + + const ports = Object.keys(services); + ports.forEach(s => urlParams.append("ports", s)); + + const metrics = (await backend.get("/api/statistics?" + urlParams)).json; + const zeroFilledMetrics = []; + const toTime = m => new Date(m["range_start"]).getTime(); + + if (metrics.length > 0) { + let i = 0; + for (let interval = toTime(metrics[0]); interval <= toTime(metrics[metrics.length - 1]); interval += minutes) { + if (interval === toTime(metrics[i])) { + const m = metrics[i++]; + m["range_start"] = new Date(m["range_start"]); + zeroFilledMetrics.push(m); + } else { + const m = {}; + m["range_start"] = new Date(interval); + m[metric] = {}; + ports.forEach(p => m[metric][p] = 0); + zeroFilledMetrics.push(m); + } + } + } + + const series = new TimeSeries({ + name: "statistics", + columns: ["time"].concat(ports), + points: zeroFilledMetrics.map(m => [m["range_start"]].concat(ports.map(p => m[metric][p] || 0))) + }); + const start = series.range().begin(); + const end = series.range().end(); + start.setTime(start.getTime() - minutes); + end.setTime(end.getTime() + minutes); + + this.setState({ + metric, + series, + timeRange: new TimeRange(start, end), + start, + end + }); + log.debug(`Loaded statistics for metric "${metric}" for services [${ports}]`); + }; + + loadServices = async () => { + const services = (await backend.get("/api/services")).json; + this.setState({services}); + return services; + }; + + createStyler = () => { + return styler(Object.keys(this.state.services).map(port => { + return {key: port, color: this.state.services[port].color, width: 2}; + })); + }; + + handleTimeRangeChange = (timeRange) => { + if (!this.disableTimeSeriesChanges) { + this.setState({timeRange}); + } + }; + + handleSelectionChange = (timeRange) => { + this.disableTimeSeriesChanges = true; + + this.setState({selection: timeRange}); + if (this.selectionTimeout) { + clearTimeout(this.selectionTimeout); + } + this.selectionTimeout = setTimeout(() => { + dispatcher.dispatch("timeline_updates", { + from: timeRange.begin(), + to: timeRange.end() + }); + this.selectionTimeout = null; + this.disableTimeSeriesChanges = false; + }, 1000); + }; + + aggregateSeries = (func) => { + const values = this.state.series.columns().map(c => this.state.series[func](c)); + return Math[func](...values); + }; + + render() { + if (!this.state.series) { + return null; + } + + return ( +
+
+ + + + + + + + + + + + + + +
+ this.loadStatistics(metric, this.state.filteredPort) + .then(() => log.debug("Statistics loaded after metric changes"))} + value={this.state.metric}/> +
+
+
+ ); + } +} + +export default withRouter(Timeline); diff --git a/frontend/src/views/Timeline.scss b/frontend/src/views/Timeline.scss new file mode 100644 index 0000000..14360d4 --- /dev/null +++ b/frontend/src/views/Timeline.scss @@ -0,0 +1,22 @@ +@import "../colors.scss"; + +.footer { + padding: 15px; + + .time-line { + position: relative; + background-color: $color-primary-0; + + .metric-selection { + font-size: 0.8em; + position: absolute; + top: 5px; + right: 10px; + } + } + + svg text { + font-family: "Fira Code", monospace !important; + fill: $color-primary-4 !important; + } +} -- 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 'connections_controller.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 { this.checkboxChangesHandler(name, event)} /> + onChange={event => this.checkboxChangesHandler(name, event)}/> {filtersDefinitions[name]} ); @@ -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 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 'connections_controller.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 a44b70943ea4fce61261fc5fadf84a2a98fd2435 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Mon, 12 Oct 2020 20:08:45 +0200 Subject: Add search pane on frontend --- connections_controller.go | 2 +- frontend/src/components/Header.js | 9 +- frontend/src/components/fields/CheckField.js | 2 +- frontend/src/components/fields/TagField.js | 78 ++++++ frontend/src/components/fields/TagField.scss | 120 +++++++++ .../src/components/filters/ExitSearchFilter.js | 52 ++++ .../src/components/filters/FiltersDispatcher.js | 57 ++++ .../components/filters/RulesConnectionsFilter.js | 2 +- .../components/filters/RulesConnectionsFilter.scss | 193 +++++++------- frontend/src/components/pages/MainPage.js | 5 + frontend/src/components/panels/SearchPane.js | 293 +++++++++++++++++++++ frontend/src/components/panels/SearchPane.scss | 51 ++++ 12 files changed, 764 insertions(+), 100 deletions(-) create mode 100644 frontend/src/components/fields/TagField.js create mode 100644 frontend/src/components/fields/TagField.scss create mode 100644 frontend/src/components/filters/ExitSearchFilter.js create mode 100644 frontend/src/components/filters/FiltersDispatcher.js create mode 100644 frontend/src/components/panels/SearchPane.js create mode 100644 frontend/src/components/panels/SearchPane.scss (limited to 'connections_controller.go') diff --git a/connections_controller.go b/connections_controller.go index a293a80..924cb53 100644 --- a/connections_controller.go +++ b/connections_controller.go @@ -151,7 +151,7 @@ func (cc ConnectionsController) GetConnections(c context.Context, filter Connect performedSearchID, _ := RowIDFromHex(filter.PerformedSearch) if !performedSearchID.IsZero() { performedSearch := cc.searchController.GetPerformedSearch(performedSearchID) - if !performedSearch.ID.IsZero() { + if !performedSearch.ID.IsZero() && len(performedSearch.AffectedConnections) > 0 { query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$in": performedSearch.AffectedConnections}}}) } } diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js index 4d29364..b72b532 100644 --- a/frontend/src/components/Header.js +++ b/frontend/src/components/Header.js @@ -21,6 +21,7 @@ import './Header.scss'; import {filtersDefinitions, filtersNames} from "./filters/FiltersDefinitions"; import {Link, withRouter} from "react-router-dom"; import ButtonField from "./fields/ButtonField"; +import ExitSearchFilter from "./filters/ExitSearchFilter"; class Header extends Component { @@ -50,7 +51,7 @@ class Header extends Component { componentWillUnmount() { this.typed.destroy(); - if (typeof window !== "undefined") { + if (typeof window) { window.removeEventListener("quick-filters", this.fetchStateFromLocalStorage); } } @@ -82,12 +83,16 @@ class Header extends Component {
{quickFilters} +
- + {/**/} + + + diff --git a/frontend/src/components/fields/CheckField.js b/frontend/src/components/fields/CheckField.js index dd44970..a0e2706 100644 --- a/frontend/src/components/fields/CheckField.js +++ b/frontend/src/components/fields/CheckField.js @@ -35,7 +35,7 @@ class CheckField extends Component { const small = this.props.small || false; const name = this.props.name || null; const handler = () => { - if (this.props.onChange) { + if (!this.props.readonly && this.props.onChange) { this.props.onChange(!checked); } }; diff --git a/frontend/src/components/fields/TagField.js b/frontend/src/components/fields/TagField.js new file mode 100644 index 0000000..f1a48bd --- /dev/null +++ b/frontend/src/components/fields/TagField.js @@ -0,0 +1,78 @@ +/* + * 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 './TagField.scss'; +import './common.scss'; +import {randomClassName} from "../../utils"; +import ReactTags from "react-tag-autocomplete"; + +const classNames = require('classnames'); +const _ = require('lodash'); + +class TagField extends Component { + + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + + state = { + + }; + + onAddition = (tag) => { + if (typeof this.props.onChange === "function") { + const tags = [].concat(this.wrappedTags(), tag); + this.props.onChange(tags.map(t => t.name), true, tag); // true == addition + } + }; + + onDelete = (i) => { + if (typeof this.props.onChange === "function") { + const tags = this.wrappedTags(); + const tag = tags[i]; + tags.splice(i, 1); + this.props.onChange(tags.map(t => t.name), true, tag); // false == delete + } + }; + + wrappedTags = () => this.props.tags.map(t => new Object({"name": t})); + + render() { + const small = this.props.small || false; + const name = this.props.name || null; + + return ( +
+ { name && +
+ +
+ } + +
+ ); + } +} + +export default TagField; diff --git a/frontend/src/components/fields/TagField.scss b/frontend/src/components/fields/TagField.scss new file mode 100644 index 0000000..e77db97 --- /dev/null +++ b/frontend/src/components/fields/TagField.scss @@ -0,0 +1,120 @@ +@import "../../colors.scss"; + +.tag-field { + .react-tags { + font-size: 12px; + position: relative; + z-index: 10; + padding: 0 6px; + cursor: text; + border-radius: 4px; + background-color: $color-primary-2; + } + + .react-tags.is-focused { + border-color: #b1b1b1; + } + + .react-tags__selected { + display: inline; + } + + .react-tags__selected-tag { + font-size: 11px; + display: inline-block; + margin: 0 6px 6px 0; + padding: 2px 4px; + color: $color-primary-3; + border: none; + border-radius: 2px; + background: $color-primary-4; + } + + .react-tags__selected-tag::after { + margin-left: 8px; + content: "\2715"; + color: $color-primary-3; + } + + .react-tags__selected-tag:hover, + .react-tags__selected-tag:focus { + border-color: #b1b1b1; + } + + .react-tags__search { + display: inline-block; + max-width: 100%; + padding: 7px 10px; + } + + @media screen and (min-width: 30em) { + .react-tags__search { + position: relative; + } + } + + .react-tags__search-input { + font-size: inherit; + line-height: inherit; + max-width: 100%; + margin: 0; + padding: 0; + color: $color-primary-4; + border: 0; + outline: none; + background-color: $color-primary-2; + } + + .react-tags__search-input::-ms-clear { + display: none; + } + + .react-tags__suggestions { + position: absolute; + top: 100%; + left: 0; + width: 100%; + } + + @media screen and (min-width: 30em) { + .react-tags__suggestions { + width: 240px; + } + } + + .react-tags__suggestions ul { + font-size: 12px; + margin: 4px -1px; + padding: 0; + list-style: none; + color: $color-primary-1; + border-radius: 2px; + background: $color-primary-4; + } + + .react-tags__suggestions li { + padding: 3px 5px; + border-bottom: 1px solid #ddd; + } + + .react-tags__suggestions li mark { + font-weight: 600; + text-decoration: underline; + background: none; + } + + .react-tags__suggestions li:hover { + cursor: pointer; + color: $color-primary-4; + background: $color-primary-0; + } + + .react-tags__suggestions li.is-active { + background: #b7cfe0; + } + + .react-tags__suggestions li.is-disabled { + cursor: auto; + opacity: 0.5; + } +} \ No newline at end of file diff --git a/frontend/src/components/filters/ExitSearchFilter.js b/frontend/src/components/filters/ExitSearchFilter.js new file mode 100644 index 0000000..cfee298 --- /dev/null +++ b/frontend/src/components/filters/ExitSearchFilter.js @@ -0,0 +1,52 @@ +/* + * 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 CheckField from "../fields/CheckField"; +import dispatcher from "../../dispatcher"; + +class ExitSearchFilter extends Component { + + state = {}; + + componentDidMount() { + let params = new URLSearchParams(this.props.location.search); + this.setState({performedSearch: params.get("performed_search")}); + + dispatcher.register("connections_filters", payload => { + if (this.state.performedSearch !== payload["performed_search"]) { + this.setState({performedSearch: payload["performed_search"]}); + } + }); + } + + render() { + return ( + <> + {this.state.performedSearch && +
+ + dispatcher.dispatch("connections_filters", {"performed_search": null})} small/> +
} + + ); + } + +} + +export default withRouter(ExitSearchFilter); diff --git a/frontend/src/components/filters/FiltersDispatcher.js b/frontend/src/components/filters/FiltersDispatcher.js new file mode 100644 index 0000000..3769055 --- /dev/null +++ b/frontend/src/components/filters/FiltersDispatcher.js @@ -0,0 +1,57 @@ +/* + * 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"; +import dispatcher from "../../dispatcher"; + +class FiltersDispatcher extends Component { + + state = {}; + + componentDidMount() { + let params = new URLSearchParams(this.props.location.search); + this.setState({params}); + + dispatcher.register("connections_filters", payload => { + const params = this.state.params; + + Object.entries(payload).forEach(([key, value]) => { + if (value == null) { + params.delete(key); + } else { + params.set(key, value); + } + }); + + this.needRedirect = true; + this.setState({params}); + }); + } + + render() { + if (this.needRedirect) { + this.needRedirect = false; + return ; + } + + return null; + } +} + +export default withRouter(FiltersDispatcher); diff --git a/frontend/src/components/filters/RulesConnectionsFilter.js b/frontend/src/components/filters/RulesConnectionsFilter.js index 48affb0..fc0ad4d 100644 --- a/frontend/src/components/filters/RulesConnectionsFilter.js +++ b/frontend/src/components/filters/RulesConnectionsFilter.js @@ -89,7 +89,7 @@ class RulesConnectionsFilter extends Component { return (
-
+
+ }/> }/> }/> }/> @@ -67,6 +70,8 @@ class MainPage extends Component {
+ +
); diff --git a/frontend/src/components/panels/SearchPane.js b/frontend/src/components/panels/SearchPane.js new file mode 100644 index 0000000..21ba139 --- /dev/null +++ b/frontend/src/components/panels/SearchPane.js @@ -0,0 +1,293 @@ +/* + * 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 './SearchPane.scss'; +import Table from "react-bootstrap/Table"; +import InputField from "../fields/InputField"; +import TextField from "../fields/TextField"; +import backend from "../../backend"; +import ButtonField from "../fields/ButtonField"; +import LinkPopover from "../objects/LinkPopover"; +import {createCurlCommand, dateTimeToTime, durationBetween} from "../../utils"; +import dispatcher from "../../dispatcher"; +import TagField from "../fields/TagField"; +import CheckField from "../fields/CheckField"; + +const classNames = require('classnames'); +const _ = require('lodash'); + +class SearchPane extends Component { + + searchOptions = { + "text_search": { + "terms": null, + "excluded_terms": null, + "exact_phrase": "", + "case_sensitive": false + }, + "regex_search": { + "pattern": "", + "not_pattern": "", + "case_insensitive": false, + "multi_line": false, + "ignore_whitespaces": false, + "dot_character": false + }, + "timeout": 10 + }; + + state = { + searches: [], + currentSearchOptions: this.searchOptions, + }; + + componentDidMount() { + this.reset(); + this.loadSearches(); + + dispatcher.register("notifications", payload => { + if (payload.event === "searches.new") { + this.loadSearches(); + } + }); + + document.title = "caronte:~/searches$"; + } + + loadSearches = () => { + backend.get("/api/searches") + .then(res => this.setState({searches: res.json, searchesStatusCode: res.status})) + .catch(res => this.setState({searchesStatusCode: res.status, searchesResponse: JSON.stringify(res.json)})); + }; + + performSearch = () => { + const options = this.state.currentSearchOptions; + if (this.validateSearch(options)) { + backend.post("/api/searches/perform", options).then(res => { + this.reset(); + this.setState({searchStatusCode: res.status}); + this.loadSearches(); + this.viewSearch(res.json.id); + }).catch(res => { + this.setState({searchStatusCode: res.status, searchResponse: JSON.stringify(res.json)}); + }); + } + }; + + reset = () => { + this.setState({ + currentSearchOptions: _.cloneDeep(this.searchOptions), + exactPhraseError: null, + patternError: null, + notPatternError: null, + searchStatusCode: null, + searchesStatusCode: null, + searchResponse: null, + searchesResponse: null + }); + }; + + validateSearch = (options) => { + let valid = true; + if (options.text_search.exact_phrase && options.text_search.exact_phrase.length < 3) { + this.setState({exactPhraseError: "text_search.exact_phrase.length < 3"}); + valid = false; + } + if (options.regex_search.pattern && options.regex_search.pattern.length < 3) { + this.setState({patternError: "regex_search.pattern.length < 3"}); + valid = false; + } + if (options.regex_search.not_pattern && options.regex_search.not_pattern.length < 3) { + this.setState({exactPhraseError: "regex_search.not_pattern.length < 3"}); + valid = false; + } + + return valid; + }; + + updateParam = (callback) => { + callback(this.state.currentSearchOptions); + this.setState({currentSearchOptions: this.state.currentSearchOptions}); + }; + + extractPattern = (options) => { + let pattern = ""; + if (_.isEqual(options.regex_search, this.searchOptions.regex_search)) { // is text search + if (options.text_search.exact_phrase) { + pattern += `"${options.text_search.exact_phrase}"`; + } else { + pattern += options.text_search.terms.join(" "); + if (options.text_search.excluded_terms) { + pattern += " -" + options.text_search.excluded_terms.join(" -"); + } + } + options.text_search.case_sensitive && (pattern += "/s"); + } else { // is regex search + if (options.regex_search.pattern) { + pattern += "/" + options.regex_search.pattern + "/"; + } else { + pattern += "!/" + options.regex_search.not_pattern + "/"; + } + options.regex_search.case_insensitive && (pattern += "i"); + options.regex_search.multi_line && (pattern += "m"); + options.regex_search.ignore_whitespaces && (pattern += "x"); + options.regex_search.dot_character && (pattern += "s"); + } + + return pattern; + }; + + viewSearch = (searchId) => { + dispatcher.dispatch("connections_filters", {"performed_search": searchId}); + }; + + render() { + const options = this.state.currentSearchOptions; + + let searches = this.state.searches.map(s => + + {s.id.substring(0, 8)} + {this.extractPattern(s["search_options"])} + {s["affected_connections_count"]} + {dateTimeToTime(s["started_at"])} + {durationBetween(s["started_at"], s["finished_at"])} + this.viewSearch(s.id)}/> + + ); + + const textOptionsModified = !_.isEqual(this.searchOptions.text_search, options.text_search); + const regexOptionsModified = !_.isEqual(this.searchOptions.regex_search, options.regex_search); + + const curlCommand = createCurlCommand("/searches/perform", "POST", options); + + return ( +
+
+
+ GET /api/searches + {this.state.searchesStatusCode && + } +
+ +
+
+ + + + + + + + + + + + + {searches} + +
idpatternoccurrencesstarted_atdurationactions
+
+
+
+ +
+
+ POST /api/searches/perform + +
+ +
+ + NOTE: it is recommended to use the rules for recurring themes. Give preference to textual search over that with regex. + + +
+
+ this.updateParam(s => s.text_search.terms = tags)}/> + this.updateParam(s => s.text_search.excluded_terms = tags)}/> + + or + + this.updateParam(s => s.text_search.exact_phrase = v)} + readonly={regexOptionsModified || (Array.isArray(options.text_search.terms) && options.text_search.terms.length > 0)}/> + + this.updateParam(s => s.text_search.case_sensitive = v)}/> +
+ +
+ or +
+ +
+ this.updateParam(s => s.regex_search.pattern = v)}/> + or + this.updateParam(s => s.regex_search.not_pattern = v)}/> + +
+ this.updateParam(s => s.regex_search.case_insensitive = v)}/> + this.updateParam(s => s.regex_search.multi_line = v)}/> + this.updateParam(s => s.regex_search.ignore_whitespaces = v)}/> + this.updateParam(s => s.regex_search.dot_character = v)}/> +
+
+
+ + +
+ +
+ + +
+
+
+ ); + } + +} + +export default SearchPane; diff --git a/frontend/src/components/panels/SearchPane.scss b/frontend/src/components/panels/SearchPane.scss new file mode 100644 index 0000000..15fc7da --- /dev/null +++ b/frontend/src/components/panels/SearchPane.scss @@ -0,0 +1,51 @@ +.search-pane { + display: flex; + flex-direction: column; + + .searches-list { + overflow: hidden; + + .section-content { + height: 100%; + } + + .section-table { + height: calc(100% - 30px); + } + } + + .search-new { + .content-row { + display: flex; + + .text-search, + .regex-search { + flex: 1; + } + + .exclusive-separator { + font-size: 0.8em; + display: block; + text-align: center; + } + + .separator { + font-size: 0.9em; + flex: 0; + margin: auto 10px; + } + } + + .notes { + font-size: 0.8em; + } + + .checkbox-line { + .check-field { + display: inline-block; + margin-top: 0; + margin-right: 10px; + } + } + } +} -- cgit v1.2.3-70-g09d2