- );
- }
-}
-
-export default Notifications;
diff --git a/frontend/src/components/Timeline.jsx b/frontend/src/components/Timeline.jsx
deleted file mode 100644
index faaa8de..0000000
--- a/frontend/src/components/Timeline.jsx
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * 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 ChartContainer from "react-timeseries-charts/lib/components/ChartContainer";
-import ChartRow from "react-timeseries-charts/lib/components/ChartRow";
-import Charts from "react-timeseries-charts/lib/components/Charts";
-import LineChart from "react-timeseries-charts/lib/components/LineChart";
-import MultiBrush from "react-timeseries-charts/lib/components/MultiBrush";
-import Resizable from "react-timeseries-charts/lib/components/Resizable";
-import YAxis from "react-timeseries-charts/lib/components/YAxis";
-import { TimeRange, TimeSeries } from "pondjs";
-import styler from "react-timeseries-charts/lib/js/styler";
-
-import backend from "../backend";
-import dispatcher from "../dispatcher";
-import log from "../log";
-import ChoiceField from "./fields/ChoiceField";
-import "./Timeline.scss";
-
-const minutes = 60 * 1000;
-const maxTimelineRange = 24 * 60 * minutes;
-import classNames from "classnames";
-
-const leftSelectionPaddingMultiplier = 24;
-const rightSelectionPaddingMultiplier = 8;
-
-class Timeline extends Component {
- state = {
- metric: "connections_per_service",
- };
-
- constructor() {
- super();
-
- this.disableTimeSeriesChanges = false;
- this.selectionTimeout = null;
- }
-
- componentDidMount() {
- const urlParams = new URLSearchParams(this.props.location.search);
- this.setState({
- servicePortFilter: urlParams.get("service_port") || null,
- matchedRulesFilter: urlParams.getAll("matched_rules") || null,
- });
-
- this.loadStatistics(this.state.metric).then(() =>
- log.debug("Statistics loaded after mount")
- );
- dispatcher.register(
- "connections_filters",
- this.handleConnectionsFiltersCallback
- );
- dispatcher.register("connection_updates", this.handleConnectionUpdates);
- dispatcher.register("notifications", this.handleNotifications);
- dispatcher.register("pulse_timeline", this.handlePulseTimeline);
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.handleConnectionsFiltersCallback);
- dispatcher.unregister(this.handleConnectionUpdates);
- dispatcher.unregister(this.handleNotifications);
- dispatcher.unregister(this.handlePulseTimeline);
- }
-
- loadStatistics = async (metric) => {
- const urlParams = new URLSearchParams();
- urlParams.set("metric", metric);
-
- let columns = [];
- if (metric === "matched_rules") {
- let rules = await this.loadRules();
- if (this.state.matchedRulesFilter.length > 0) {
- this.state.matchedRulesFilter.forEach((id) => {
- urlParams.append("rules_ids", id);
- });
- columns = this.state.matchedRulesFilter;
- } else {
- columns = rules.map((r) => r.id);
- }
- } else {
- let services = await this.loadServices();
- const filteredPort = this.state.servicePortFilter;
- if (filteredPort && services[filteredPort]) {
- const service = services[filteredPort];
- services = {};
- services[filteredPort] = service;
- }
-
- columns = Object.keys(services);
- columns.forEach((port) => urlParams.append("ports", port));
- }
-
- const metrics = (await backend.get("/api/statistics?" + urlParams)).json;
- if (metrics.length === 0) {
- return;
- }
-
- const zeroFilledMetrics = [];
- const toTime = (m) => new Date(m["range_start"]).getTime();
-
- let i;
- let timeStart = toTime(metrics[0]) - minutes;
- for (i = 0; timeStart < 0 && i < metrics.length; i++) {
- // workaround to remove negative timestamps :(
- timeStart = toTime(metrics[i]) - minutes;
- }
-
- let timeEnd = toTime(metrics[metrics.length - 1]) + minutes;
- if (timeEnd - timeStart > maxTimelineRange) {
- timeEnd = timeStart + maxTimelineRange;
-
- const now = new Date().getTime();
- if (
- !this.lastDisplayNotificationTime ||
- this.lastDisplayNotificationTime + minutes < now
- ) {
- this.lastDisplayNotificationTime = now;
- dispatcher.dispatch("notifications", { event: "timeline.range.large" });
- }
- }
-
- for (let interval = timeStart; interval <= timeEnd; interval += minutes) {
- if (i < metrics.length && 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] = {};
- columns.forEach((c) => (m[metric][c] = 0));
- zeroFilledMetrics.push(m);
- }
- }
-
- const series = new TimeSeries({
- name: "statistics",
- columns: ["time"].concat(columns),
- points: zeroFilledMetrics.map((m) =>
- [m["range_start"]].concat(
- columns.map((c) =>
- metric in m && m[metric] != null ? m[metric][c] || 0 : 0
- )
- )
- ),
- });
-
- const start = series.range().begin();
- const end = series.range().end();
-
- this.setState({
- metric,
- series,
- timeRange: new TimeRange(start, end),
- columns,
- start,
- end,
- });
- };
-
- loadServices = async () => {
- const services = (await backend.get("/api/services")).json;
- this.setState({ services });
- return services;
- };
-
- loadRules = async () => {
- const rules = (await backend.get("/api/rules")).json;
- this.setState({ rules });
- return rules;
- };
-
- createStyler = () => {
- if (this.state.metric === "matched_rules") {
- return styler(
- this.state.rules.map((rule) => {
- return { key: rule.id, color: rule.color, width: 2 };
- })
- );
- } else {
- 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);
- };
-
- handleConnectionsFiltersCallback = (payload) => {
- if (
- "service_port" in payload &&
- this.state.servicePortFilter !== payload["service_port"]
- ) {
- this.setState({ servicePortFilter: payload["service_port"] });
- this.loadStatistics(this.state.metric).then(() =>
- log.debug("Statistics reloaded after service port changed")
- );
- }
- if (
- "matched_rules" in payload &&
- this.state.matchedRulesFilter !== payload["matched_rules"]
- ) {
- this.setState({ matchedRulesFilter: payload["matched_rules"] });
- this.loadStatistics(this.state.metric).then(() =>
- log.debug("Statistics reloaded after matched rules changed")
- );
- }
- };
-
- handleConnectionUpdates = (payload) => {
- if (
- payload.from >= this.state.start &&
- payload.from < payload.to &&
- payload.to <= this.state.end
- ) {
- this.setState({
- selection: new TimeRange(payload.from, payload.to),
- });
- this.adjustSelection();
- }
- };
-
- handleNotifications = (payload) => {
- if (
- payload.event === "services.edit" &&
- this.state.metric !== "matched_rules"
- ) {
- this.loadStatistics(this.state.metric).then(() =>
- log.debug("Statistics reloaded after services updates")
- );
- } else if (
- payload.event.startsWith("rules") &&
- this.state.metric === "matched_rules"
- ) {
- this.loadStatistics(this.state.metric).then(() =>
- log.debug("Statistics reloaded after rules updates")
- );
- } else if (payload.event === "pcap.completed") {
- this.loadStatistics(this.state.metric).then(() =>
- log.debug("Statistics reloaded after pcap processed")
- );
- }
- };
-
- handlePulseTimeline = (payload) => {
- this.setState({ pulseTimeline: true });
- setTimeout(() => this.setState({ pulseTimeline: false }), payload.duration);
- };
-
- adjustSelection = () => {
- const seriesRange = this.state.series.range();
- const selection = this.state.selection;
- const delta = selection.end() - selection.begin();
- const start = Math.max(
- selection.begin().getTime() - delta * leftSelectionPaddingMultiplier,
- seriesRange.begin().getTime()
- );
- const end = Math.min(
- selection.end().getTime() + delta * rightSelectionPaddingMultiplier,
- seriesRange.end().getTime()
- );
- this.setState({ timeRange: new TimeRange(start, end) });
- };
-
- 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 (
-
- );
- }
-}
-
-export default withRouter(Timeline);
diff --git a/frontend/src/components/dialogs/CommentDialog.jsx b/frontend/src/components/dialogs/CommentDialog.jsx
deleted file mode 100644
index 970aa83..0000000
--- a/frontend/src/components/dialogs/CommentDialog.jsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 {Modal} from "react-bootstrap";
-import backend from "../../backend";
-import log from "../../log";
-import ButtonField from "../fields/ButtonField";
-import TextField from "../fields/TextField";
-
-class CommentDialog extends Component {
-
- state = {};
-
- componentDidMount() {
- this.setState({comment: this.props.initialComment || ""});
- }
-
- setComment = () => {
- if (this.state.comment === this.props.initialComment) {
- return this.close();
- }
- const comment = this.state.comment || null;
- backend.post(`/api/connections/${this.props.connectionId}/comment`, {comment})
- .then((_) => {
- this.close();
- }).catch((e) => {
- log.error(e);
- this.setState({error: "failed to save comment"});
- });
- };
-
- close = () => this.props.onSave(this.state.comment || null);
-
- render() {
- return (
-
-
-
- ~/.comment
-
-
-
- this.setState({comment})}
- rows={7} error={this.state.error}/>
-
-
-
-
-
-
- );
- }
-}
-
-export default CommentDialog;
diff --git a/frontend/src/components/dialogs/CopyDialog.jsx b/frontend/src/components/dialogs/CopyDialog.jsx
deleted file mode 100644
index 069fd2e..0000000
--- a/frontend/src/components/dialogs/CopyDialog.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 {Modal} from "react-bootstrap";
-import ButtonField from "../fields/ButtonField";
-import TextField from "../fields/TextField";
-
-class CopyDialog extends Component {
-
- state = {
- copyButtonText: "copy"
- };
-
- constructor(props) {
- super(props);
- this.textbox = React.createRef();
- }
-
- copyActionValue = () => {
- this.textbox.current.select();
- document.execCommand("copy");
- this.setState({copyButtonText: "copied!"});
- this.timeoutHandle = setTimeout(() => this.setState({copyButtonText: "copy"}), 3000);
- };
-
- componentWillUnmount() {
- if (this.timeoutHandle) {
- clearTimeout(this.timeoutHandle);
- }
- }
-
- render() {
- return (
-
-
-
- {this.props.name}
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default CopyDialog;
diff --git a/frontend/src/components/dialogs/Filters.jsx b/frontend/src/components/dialogs/Filters.jsx
deleted file mode 100644
index a2407df..0000000
--- a/frontend/src/components/dialogs/Filters.jsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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 {Modal} from "react-bootstrap";
-import {cleanNumber, validateIpAddress, validateMin, validatePort} from "../../utils";
-import ButtonField from "../fields/ButtonField";
-import StringConnectionsFilter from "../filters/StringConnectionsFilter";
-import "./Filters.scss";
-
-class Filters extends Component {
-
- render() {
- return (
-
-
-
- ~/advanced_filters
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default Filters;
diff --git a/frontend/src/components/fields/ButtonField.jsx b/frontend/src/components/fields/ButtonField.jsx
deleted file mode 100644
index ae5b33a..0000000
--- a/frontend/src/components/fields/ButtonField.jsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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";
-import classNames from "classnames";
-
-class ButtonField extends Component {
- render() {
- const handler = () => {
- if (typeof this.props.onClick === "function") {
- this.props.onClick();
- }
- };
-
- let buttonClassnames = {
- "button-bordered": this.props.bordered,
- };
- if (this.props.variant) {
- buttonClassnames[`button-variant-${this.props.variant}`] = true;
- }
-
- let buttonStyle = {};
- if (this.props.color) {
- buttonStyle["backgroundColor"] = this.props.color;
- }
- if (this.props.border) {
- buttonStyle["borderColor"] = this.props.border;
- }
- if (this.props.fullSpan) {
- buttonStyle["width"] = "100%";
- }
- if (this.props.rounded) {
- buttonStyle["borderRadius"] = "3px";
- }
- if (this.props.inline) {
- buttonStyle["marginTop"] = "8px";
- }
-
- return (
-
-
-
- );
- }
-}
-
-export default ButtonField;
diff --git a/frontend/src/components/fields/CheckField.jsx b/frontend/src/components/fields/CheckField.jsx
deleted file mode 100644
index 1a04f18..0000000
--- a/frontend/src/components/fields/CheckField.jsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 "./CheckField.scss";
-import "./common.scss";
-
-import classNames from "classnames";
-
-class CheckField extends Component {
- constructor(props) {
- super(props);
-
- this.id = `field-${this.props.name || "noname"}-${randomClassName()}`;
- }
-
- render() {
- const checked = this.props.checked || false;
- const small = this.props.small || false;
- const name = this.props.name || null;
- const handler = () => {
- if (!this.props.readonly && this.props.onChange) {
- this.props.onChange(!checked);
- }
- };
-
- return (
-
-
-
-
-
-
- );
- }
-}
-
-export default CheckField;
diff --git a/frontend/src/components/fields/ChoiceField.jsx b/frontend/src/components/fields/ChoiceField.jsx
deleted file mode 100644
index c44d0a9..0000000
--- a/frontend/src/components/fields/ChoiceField.jsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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 "./ChoiceField.scss";
-import "./common.scss";
-
-import classNames from 'classnames';
-
-class ChoiceField extends Component {
-
- constructor(props) {
- super(props);
-
- this.state = {
- expanded: false
- };
-
- this.id = `field-${this.props.name || "noname"}-${randomClassName()}`;
- }
-
- render() {
- const name = this.props.name || null;
- const inline = this.props.inline;
-
- const collapse = () => this.setState({expanded: false});
- const expand = () => this.setState({expanded: true});
-
- const handler = (key) => {
- collapse();
- if (this.props.onChange) {
- this.props.onChange(key);
- }
- };
-
- const keys = this.props.keys || [];
- const values = this.props.values || [];
-
- const options = keys.map((key, i) =>
- handler(key)}>{values[i]}
- );
-
- let fieldValue = "";
- if (inline && name) {
- fieldValue = name;
- }
- if (!this.props.onlyName && inline && name) {
- fieldValue += ": ";
- }
- if (!this.props.onlyName) {
- fieldValue += this.props.value || "select a value";
- }
-
- return (
-
- {!inline && name && }
-
this.state.expanded ? collapse() : expand()}>
-
{fieldValue}
-
- {options}
-
-
-
- );
- }
-}
-
-export default ChoiceField;
diff --git a/frontend/src/components/fields/InputField.jsx b/frontend/src/components/fields/InputField.jsx
deleted file mode 100644
index f9609df..0000000
--- a/frontend/src/components/fields/InputField.jsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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 "./common.scss";
-import "./InputField.scss";
-
-import classNames from 'classnames';
-
-class InputField extends Component {
-
- constructor(props) {
- super(props);
-
- this.id = `field-${this.props.name || "noname"}-${randomClassName()}`;
- }
-
- render() {
- const active = this.props.active || false;
- const invalid = this.props.invalid || false;
- const small = this.props.small || false;
- const inline = this.props.inline || false;
- const name = this.props.name || null;
- const value = this.props.value || "";
- const defaultValue = this.props.defaultValue || "";
- const type = this.props.type || "text";
- const error = this.props.error || null;
-
- const handler = (e) => {
- if (typeof this.props.onChange === "function") {
- if (type === "file") {
- let file = e.target.files[0];
- this.props.onChange(file);
- } else if (e == null) {
- this.props.onChange(defaultValue);
- } else {
- this.props.onChange(e.target.value);
- }
- }
- };
- let inputProps = {};
- if (type !== "file") {
- inputProps["value"] = value || defaultValue;
- }
-
- return (
-
- );
- }
-}
-
-export default InputField;
diff --git a/frontend/src/components/fields/TagField.jsx b/frontend/src/components/fields/TagField.jsx
deleted file mode 100644
index 79e2314..0000000
--- a/frontend/src/components/fields/TagField.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 ReactTags from "react-tag-autocomplete";
-import {randomClassName} from "../../utils";
-import "./common.scss";
-import "./TagField.scss";
-
-import classNames from 'classnames';
-import _ from 'lodash';
-
-class TagField extends Component {
-
- state = {};
-
- constructor(props) {
- super(props);
-
- this.id = `field-${this.props.name || "noname"}-${randomClassName()}`;
- }
-
- onAddition = (tag) => {
- if (typeof this.props.onChange === "function") {
- this.props.onChange([].concat(this.props.tags, tag), true, tag); // true == addition
- }
- };
-
- onDelete = (i) => {
- if (typeof this.props.onChange === "function") {
- const tags = _.clone(this.props.tags);
- const tag = tags[i];
- tags.splice(i, 1);
- this.props.onChange(tags, true, tag); // false == delete
- }
- };
-
-
- 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/TextField.jsx b/frontend/src/components/fields/TextField.jsx
deleted file mode 100644
index 1138ffc..0000000
--- a/frontend/src/components/fields/TextField.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 "./common.scss";
-import "./TextField.scss";
-
-import classNames from 'classnames';
-
-class TextField extends Component {
-
- constructor(props) {
- super(props);
-
- this.id = `field-${this.props.name || "noname"}-${randomClassName()}`;
- }
-
- render() {
- const name = this.props.name || null;
- const error = this.props.error || null;
- const rows = this.props.rows || 3;
-
- const handler = (e) => {
- if (this.props.onChange) {
- if (e == null) {
- this.props.onChange("");
- } else {
- this.props.onChange(e.target.value);
- }
- }
- };
-
- return (
-
- {name && }
-
- );
- }
-}
-
-export default TextField;
diff --git a/frontend/src/components/filters/AdvancedFilters.jsx b/frontend/src/components/filters/AdvancedFilters.jsx
deleted file mode 100644
index 8598185..0000000
--- a/frontend/src/components/filters/AdvancedFilters.jsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 dispatcher from "../../dispatcher";
-import {updateParams} from "../../utils";
-import ButtonField from "../fields/ButtonField";
-
-class AdvancedFilters extends Component {
-
- state = {};
-
- componentDidMount() {
- this.urlParams = new URLSearchParams(this.props.location.search);
-
- this.connectionsFiltersCallback = (payload) => {
- this.urlParams = updateParams(this.urlParams, payload);
- const active = ["client_address", "client_port", "min_duration", "max_duration", "min_bytes", "max_bytes"]
- .some((f) => this.urlParams.has(f));
- if (this.state.active !== active) {
- this.setState({active});
- }
- };
- dispatcher.register("connections_filters", this.connectionsFiltersCallback);
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.connectionsFiltersCallback);
- }
-
- render() {
- return (
-
- );
- }
-
-}
-
-export default withRouter(AdvancedFilters);
diff --git a/frontend/src/components/filters/BooleanConnectionsFilter.jsx b/frontend/src/components/filters/BooleanConnectionsFilter.jsx
deleted file mode 100644
index 0355167..0000000
--- a/frontend/src/components/filters/BooleanConnectionsFilter.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 dispatcher from "../../dispatcher";
-import CheckField from "../fields/CheckField";
-
-class BooleanConnectionsFilter extends Component {
-
- state = {
- filterActive: "false"
- };
-
- componentDidMount() {
- let params = new URLSearchParams(this.props.location.search);
- this.setState({filterActive: this.toBoolean(params.get(this.props.filterName)).toString()});
-
- this.connectionsFiltersCallback = (payload) => {
- const name = this.props.filterName;
- if (name in payload && this.state.filterActive !== payload[name]) {
- this.setState({filterActive: payload[name]});
- }
- };
- dispatcher.register("connections_filters", this.connectionsFiltersCallback);
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.connectionsFiltersCallback);
- }
-
- toBoolean = (value) => {
- return value !== null && value.toLowerCase() === "true";
- };
-
- filterChanged = () => {
- const newValue = (!this.toBoolean(this.state.filterActive)).toString();
- const urlParams = {};
- urlParams[this.props.filterName] = newValue === "true" ? "true" : null;
- dispatcher.dispatch("connections_filters", urlParams);
- this.setState({filterActive: newValue});
- };
-
- render() {
- return (
-
-
-
- );
- }
-
-}
-
-export default withRouter(BooleanConnectionsFilter);
diff --git a/frontend/src/components/filters/ExitSearchFilter.jsx b/frontend/src/components/filters/ExitSearchFilter.jsx
deleted file mode 100644
index 0aacfd6..0000000
--- a/frontend/src/components/filters/ExitSearchFilter.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 dispatcher from "../../dispatcher";
-import CheckField from "../fields/CheckField";
-
-class ExitSearchFilter extends Component {
-
- state = {};
-
- componentDidMount() {
- let params = new URLSearchParams(this.props.location.search);
- this.setState({performedSearch: params.get("performed_search")});
-
- this.connectionsFiltersCallback = (payload) => {
- if (this.state.performedSearch !== payload["performed_search"]) {
- this.setState({performedSearch: payload["performed_search"]});
- }
- };
- dispatcher.register("connections_filters", this.connectionsFiltersCallback);
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.connectionsFiltersCallback);
- }
-
- render() {
- return (
- <>
- {this.state.performedSearch &&
-
}
- >
- );
- }
-
-}
-
-export default withRouter(ExitSearchFilter);
diff --git a/frontend/src/components/filters/RulesConnectionsFilter.jsx b/frontend/src/components/filters/RulesConnectionsFilter.jsx
deleted file mode 100644
index 4ae769a..0000000
--- a/frontend/src/components/filters/RulesConnectionsFilter.jsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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 backend from "../../backend";
-import dispatcher from "../../dispatcher";
-import TagField from "../fields/TagField";
-
-import classNames from 'classnames';
-import _ from 'lodash';
-
-class RulesConnectionsFilter extends Component {
-
- state = {
- rules: [],
- activeRules: []
- };
-
- componentDidMount() {
- const params = new URLSearchParams(this.props.location.search);
- let activeRules = params.getAll("matched_rules") || [];
-
- backend.get("/api/rules").then((res) => {
- let rules = res.json.flatMap((rule) => rule.enabled ? [{id: rule.id, name: rule.name}] : []);
- activeRules = rules.filter((rule) => activeRules.some((id) => rule.id === id));
- this.setState({rules, activeRules});
- });
-
- this.connectionsFiltersCallback = (payload) => {
- if ("matched_rules" in payload && !_.isEqual(payload["matched_rules"].sort(), this.state.activeRules.sort())) {
- const newRules = this.state.rules.filter((r) => payload["matched_rules"].includes(r.id));
- this.setState({
- activeRules: newRules.map((r) => {
- return {id: r.id, name: r.name};
- })
- });
- }
- };
- dispatcher.register("connections_filters", this.connectionsFiltersCallback);
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.connectionsFiltersCallback);
- }
-
- onChange = (activeRules) => {
- if (!_.isEqual(activeRules.sort(), this.state.activeRules.sort())) {
- this.setState({activeRules});
- dispatcher.dispatch("connections_filters", {"matched_rules": activeRules.map((r) => r.id)});
- }
- };
-
- render() {
- return (
-
-
-
-
-
- );
- }
-
-}
-
-export default withRouter(RulesConnectionsFilter);
diff --git a/frontend/src/components/filters/StringConnectionsFilter.jsx b/frontend/src/components/filters/StringConnectionsFilter.jsx
deleted file mode 100644
index c5d7075..0000000
--- a/frontend/src/components/filters/StringConnectionsFilter.jsx
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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 dispatcher from "../../dispatcher";
-import InputField from "../fields/InputField";
-
-class StringConnectionsFilter extends Component {
-
- state = {
- fieldValue: "",
- filterValue: null,
- timeoutHandle: null,
- invalidValue: false
- };
-
- componentDidMount() {
- let params = new URLSearchParams(this.props.location.search);
- this.updateStateFromFilterValue(params.get(this.props.filterName));
-
- this.connectionsFiltersCallback = (payload) => {
- const name = this.props.filterName;
- if (name in payload && this.state.filterValue !== payload[name]) {
- this.updateStateFromFilterValue(payload[name]);
- }
- };
- dispatcher.register("connections_filters", this.connectionsFiltersCallback);
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.connectionsFiltersCallback);
- }
-
- updateStateFromFilterValue = (filterValue) => {
- if (filterValue !== null) {
- let fieldValue = filterValue;
- if (typeof this.props.decodeFunc === "function") {
- fieldValue = this.props.decodeFunc(filterValue);
- }
- if (typeof this.props.replaceFunc === "function") {
- fieldValue = this.props.replaceFunc(fieldValue);
- }
- if (this.isValueValid(fieldValue)) {
- this.setState({fieldValue, filterValue});
- } else {
- this.setState({fieldValue, invalidValue: true});
- }
- } else {
- this.setState({fieldValue: "", filterValue: null});
- }
- };
-
- isValueValid = (value) => {
- return typeof this.props.validateFunc !== "function" ||
- (typeof this.props.validateFunc === "function" && this.props.validateFunc(value));
- };
-
- changeFilterValue = (value) => {
- const urlParams = {};
- urlParams[this.props.filterName] = value;
- dispatcher.dispatch("connections_filters", urlParams);
- };
-
- filterChanged = (fieldValue) => {
- if (this.state.timeoutHandle) {
- clearTimeout(this.state.timeoutHandle);
- }
-
- if (typeof this.props.replaceFunc === "function") {
- fieldValue = this.props.replaceFunc(fieldValue);
- }
-
- if (fieldValue === "") {
- this.setState({fieldValue: "", filterValue: null, invalidValue: false});
- return this.changeFilterValue(null);
- }
-
-
- if (this.isValueValid(fieldValue)) {
- let filterValue = fieldValue;
- if (filterValue !== "" && typeof this.props.encodeFunc === "function") {
- filterValue = this.props.encodeFunc(filterValue);
- }
-
- this.setState({
- fieldValue,
- timeoutHandle: setTimeout(() => {
- this.setState({filterValue});
- this.changeFilterValue(filterValue);
- }, 500),
- invalidValue: false
- });
- } else {
- this.setState({fieldValue, invalidValue: true});
- }
- };
-
- render() {
- let active = this.state.filterValue !== null;
-
- return (
-
-
-
- );
- }
-
-}
-
-export default withRouter(StringConnectionsFilter);
diff --git a/frontend/src/components/objects/Connection.jsx b/frontend/src/components/objects/Connection.jsx
deleted file mode 100644
index 113ed21..0000000
--- a/frontend/src/components/objects/Connection.jsx
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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 backend from "../../backend";
-import dispatcher from "../../dispatcher";
-import {dateTimeToTime, durationBetween, formatSize} from "../../utils";
-import CommentDialog from "../dialogs/CommentDialog";
-import ButtonField from "../fields/ButtonField";
-import TextField from "../fields/TextField";
-import "./Connection.scss";
-import CopyLinkPopover from "./CopyLinkPopover";
-import LinkPopover from "./LinkPopover";
-
-import classNames from 'classnames';
-
-class Connection extends Component {
-
- state = {
- update: false
- };
-
- handleAction = (name, comment) => {
- if (name === "mark") {
- const marked = this.props.data.marked;
- backend.post(`/api/connections/${this.props.data.id}/${marked ? "unmark" : "mark"}`)
- .then((_) => {
- this.props.onMarked(!marked);
- this.setState({update: true});
- });
- } else if (name === "comment") {
- this.props.onCommented(comment);
- this.setState({showCommentDialog: false});
- }
- };
-
- render() {
- let conn = this.props.data;
- let serviceName = "/dev/null";
- let serviceColor = "#0f192e";
- if (this.props.services[conn["port_dst"]]) {
- const service = this.props.services[conn["port_dst"]];
- serviceName = service.name;
- serviceColor = service.color;
- }
- let startedAt = new Date(conn["started_at"]);
- let closedAt = new Date(conn["closed_at"]);
- let processedAt = new Date(conn["processed_at"]);
- let timeInfo =
- Started at {startedAt.toLocaleDateString() + " " + startedAt.toLocaleTimeString()}
- Processed at {processedAt.toLocaleDateString() + " " + processedAt.toLocaleTimeString()}
- Closed at {closedAt.toLocaleDateString() + " " + closedAt.toLocaleTimeString()}
-
- );
- }
-
-}
-
-export default Connection;
diff --git a/frontend/src/components/objects/ConnectionMatchedRules.jsx b/frontend/src/components/objects/ConnectionMatchedRules.jsx
deleted file mode 100644
index a69cad8..0000000
--- a/frontend/src/components/objects/ConnectionMatchedRules.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 dispatcher from "../../dispatcher";
-import ButtonField from "../fields/ButtonField";
-import "./ConnectionMatchedRules.scss";
-
-class ConnectionMatchedRules extends Component {
-
- onMatchedRulesSelected = (id) => {
- const params = new URLSearchParams(this.props.location.search);
- const rules = params.getAll("matched_rules");
- if (!rules.includes(id)) {
- rules.push(id);
- dispatcher.dispatch("connections_filters", {"matched_rules": rules});
- }
- };
-
- render() {
- const matchedRules = this.props.matchedRules.map((mr) => {
- const rule = this.props.rules.find((r) => r.id === mr);
- return this.onMatchedRulesSelected(rule.id)} name={rule.name}
- color={rule.color} small/>;
- });
-
- return (
-
-
matched_rules:
-
{matchedRules}
-
- );
- }
-}
-
-export default withRouter(ConnectionMatchedRules);
diff --git a/frontend/src/components/objects/CopyLinkPopover.jsx b/frontend/src/components/objects/CopyLinkPopover.jsx
deleted file mode 100644
index b951603..0000000
--- a/frontend/src/components/objects/CopyLinkPopover.jsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * This file is part of caronte (https://github.com/eciavatta/caronte).
- * Copyright (c) 2020 Emiliano Ciavatta.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-import React, {Component} from "react";
-import TextField from "../fields/TextField";
-import LinkPopover from "./LinkPopover";
-
-class CopyLinkPopover extends Component {
-
- state = {};
-
- constructor(props) {
- super(props);
-
- this.copyTextarea = React.createRef();
- }
-
- handleClick = () => {
- this.copyTextarea.current.select();
- document.execCommand("copy");
- this.setState({copiedMessage: true});
- setTimeout(() => this.setState({copiedMessage: false}), 3000);
- };
-
- render() {
- const copyPopoverContent =
;
-
- return (
- {this.props.text}}
- content={copyPopoverContent} placement="right"/>
- );
- }
-}
-
-export default CopyLinkPopover;
diff --git a/frontend/src/components/objects/LinkPopover.jsx b/frontend/src/components/objects/LinkPopover.jsx
deleted file mode 100644
index 551a819..0000000
--- a/frontend/src/components/objects/LinkPopover.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 {randomClassName} from "../../utils";
-import "./LinkPopover.scss";
-
-class LinkPopover extends Component {
-
- constructor(props) {
- super(props);
-
- this.id = `link-overlay-${randomClassName()}`;
- }
-
- render() {
- const popover = (
-
- {this.props.title && {this.props.title}}
-
- {this.props.content}
-
-
- );
-
- return (this.props.content ?
-
- {this.props.text}
- :
- {this.props.text}
- );
- }
-}
-
-export default LinkPopover;
diff --git a/frontend/src/components/pages/ConfigurationPage.jsx b/frontend/src/components/pages/ConfigurationPage.jsx
deleted file mode 100644
index c8646fb..0000000
--- a/frontend/src/components/pages/ConfigurationPage.jsx
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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, Row} from "react-bootstrap";
-import Table from "react-bootstrap/Table";
-import backend from "../../backend";
-import {createCurlCommand} from "../../utils";
-import validation from "../../validation";
-import ButtonField from "../fields/ButtonField";
-import CheckField from "../fields/CheckField";
-import InputField from "../fields/InputField";
-import TextField from "../fields/TextField";
-import Header from "../Header";
-import LinkPopover from "../objects/LinkPopover";
-import "../panels/common.scss";
-import "./ConfigurationPage.scss";
-
-class ConfigurationPage extends Component {
-
- constructor(props) {
- super(props);
- this.state = {
- settings: {
- "config": {
- "server_address": "",
- "flag_regex": "",
- "auth_required": false
- },
- "accounts": {}
- },
- newUsername: "",
- newPassword: ""
- };
- }
-
- saveSettings = () => {
- if (this.validateSettings(this.state.settings)) {
- backend.post("/setup", this.state.settings).then((_) => {
- this.props.onConfigured();
- }).catch((res) => {
- this.setState({setupStatusCode: res.status, setupResponse: JSON.stringify(res.json)});
- });
- }
- };
-
- validateSettings = (settings) => {
- let valid = true;
- if (!validation.isValidAddress(settings.config["server_address"], true)) {
- this.setState({serverAddressError: "invalid ip_address"});
- valid = false;
- }
- if (settings.config["flag_regex"].length < 8) {
- this.setState({flagRegexError: "flag_regex.length < 8"});
- valid = false;
- }
-
- return valid;
- };
-
- updateParam = (callback) => {
- callback(this.state.settings);
- this.setState({settings: this.state.settings});
- };
-
- addAccount = () => {
- if (this.state.newUsername.length !== 0 && this.state.newPassword.length !== 0) {
- const settings = this.state.settings;
- settings.accounts[this.state.newUsername] = this.state.newPassword;
-
- this.setState({
- newUsername: "",
- newPassword: "",
- settings
- });
- } else {
- this.setState({
- newUsernameActive: this.state.newUsername.length === 0,
- newPasswordActive: this.state.newPassword.length === 0
- });
- }
- };
-
- render() {
- const settings = this.state.settings;
- const curlCommand = createCurlCommand("/setup", "POST", settings);
-
- const accounts = Object.entries(settings.accounts).map(([username, password]) =>
-
- );
- }
-}
-
-export default ConfigurationPage;
diff --git a/frontend/src/components/pages/MainPage.jsx b/frontend/src/components/pages/MainPage.jsx
deleted file mode 100644
index b9a9e6e..0000000
--- a/frontend/src/components/pages/MainPage.jsx
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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 {ReflexContainer, ReflexElement, ReflexSplitter} from "react-reflex";
-import "react-reflex/styles.css"
-import {Route, Switch} from "react-router-dom";
-import Filters from "../dialogs/Filters";
-import Header from "../Header";
-import Connections from "../panels/ConnectionsPane";
-import MainPane from "../panels/MainPane";
-import PcapsPane from "../panels/PcapsPane";
-import RulesPane from "../panels/RulesPane";
-import SearchPane from "../panels/SearchPane";
-import ServicesPane from "../panels/ServicesPane";
-import StatsPane from "../panels/StatsPane";
-import StreamsPane from "../panels/StreamsPane";
-import "./MainPage.scss";
-
-class MainPage extends Component {
-
- state = {
- timelineHeight: 210
- };
-
- handleTimelineResize = (e) => {
- if (this.timelineTimeoutHandle) {
- clearTimeout(this.timelineTimeoutHandle);
- }
-
- this.timelineTimeoutHandle = setTimeout(() =>
- this.setState({timelineHeight: e.domElement.clientHeight}), 100);
- };
-
- render() {
- let modal;
- if (this.state.filterWindowOpen) {
- modal = this.setState({filterWindowOpen: false})}/>;
- }
-
- return (
-
-
-
-
-
-
- this.setState({selectedConnection: c})}/>
-
-
-
-
-
-
- }/>
- }/>
- }/>
- }/>
- }/>
- }/>
- }/>
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default MainPage;
diff --git a/frontend/src/components/pages/ServiceUnavailablePage.jsx b/frontend/src/components/pages/ServiceUnavailablePage.jsx
deleted file mode 100644
index deb4cf8..0000000
--- a/frontend/src/components/pages/ServiceUnavailablePage.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 "./MainPage.scss";
-
-class ServiceUnavailablePage extends Component {
-
- state = {};
-
- render() {
- return (
-
-
-
- );
- }
-}
-
-export default ServiceUnavailablePage;
diff --git a/frontend/src/components/panels/ConnectionsPane.jsx b/frontend/src/components/panels/ConnectionsPane.jsx
deleted file mode 100644
index 2c7fadd..0000000
--- a/frontend/src/components/panels/ConnectionsPane.jsx
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * 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 Table from "react-bootstrap/Table";
-import {Redirect} from "react-router";
-import {withRouter} from "react-router-dom";
-import backend from "../../backend";
-import dispatcher from "../../dispatcher";
-import log from "../../log";
-import {updateParams} from "../../utils";
-import ButtonField from "../fields/ButtonField";
-import Connection from "../objects/Connection";
-import ConnectionMatchedRules from "../objects/ConnectionMatchedRules";
-import "./ConnectionsPane.scss";
-
-import classNames from 'classnames';
-
-class ConnectionsPane extends Component {
-
- state = {
- loading: false,
- connections: [],
- firstConnection: null,
- lastConnection: null,
- };
-
- constructor(props) {
- super(props);
-
- this.scrollTopThreashold = 0.00001;
- this.scrollBottomThreashold = 0.99999;
- this.maxConnections = 200;
- this.queryLimit = 50;
- this.connectionsListRef = React.createRef();
- this.lastScrollPosition = 0;
- }
-
- componentDidMount() {
- let urlParams = new URLSearchParams(this.props.location.search);
- this.setState({urlParams});
-
- const additionalParams = {limit: this.queryLimit};
-
- const match = this.props.location.pathname.match(/^\/connections\/([a-f0-9]{24})$/);
- if (match != null) {
- const id = match[1];
- additionalParams.from = id;
- backend.get(`/api/connections/${id}`)
- .then((res) => this.connectionSelected(res.json))
- .catch((error) => log.error("Error loading initial connection", error));
- }
-
- this.loadConnections(additionalParams, urlParams, true).then(() => log.debug("Connections loaded"));
-
- dispatcher.register("connections_filters", this.handleConnectionsFilters);
- dispatcher.register("timeline_updates", this.handleTimelineUpdates);
- dispatcher.register("notifications", this.handleNotifications);
- dispatcher.register("pulse_connections_view", this.handlePulseConnectionsView);
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.handleConnectionsFilters);
- dispatcher.unregister(this.handleTimelineUpdates);
- dispatcher.unregister(this.handleNotifications);
- dispatcher.unregister(this.handlePulseConnectionsView);
- }
-
- handleConnectionsFilters = (payload) => {
- const newParams = updateParams(this.state.urlParams, payload);
- if (this.state.urlParams.toString() === newParams.toString()) {
- return;
- }
-
- log.debug("Update following url params:", payload);
- this.queryStringRedirect = true;
- this.setState({urlParams: newParams});
-
- this.loadConnections({limit: this.queryLimit}, newParams)
- .then(() => log.info("ConnectionsPane reloaded after query string update"));
- };
-
- handleTimelineUpdates = (payload) => {
- this.connectionsListRef.current.scrollTop = 0;
- this.loadConnections({
- "started_after": Math.round(payload.from.getTime() / 1000),
- "started_before": Math.round(payload.to.getTime() / 1000),
- limit: this.maxConnections
- }).then(() => log.info(`Loading connections between ${payload.from} and ${payload.to}`));
- };
-
- handleNotifications = (payload) => {
- if (payload.event === "rules.new" || payload.event === "rules.edit") {
- this.loadRules().then(() => log.debug("Loaded connection rules after notification update"));
- }
- if (payload.event === "services.edit") {
- this.loadServices().then(() => log.debug("Services reloaded after notification update"));
- }
- };
-
- handlePulseConnectionsView = (payload) => {
- this.setState({pulseConnectionsView: true});
- setTimeout(() => this.setState({pulseConnectionsView: false}), payload.duration);
- };
-
- connectionSelected = (c) => {
- this.connectionSelectedRedirect = true;
- this.setState({selected: c.id});
- this.props.onSelected(c);
- log.debug(`Connection ${c.id} selected`);
- };
-
- 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,})
- .then(() => log.info("Following connections loaded"));
- }
- if (!this.state.loading && relativeScroll < this.scrollTopThreashold) {
- this.loadConnections({to: this.state.firstConnection.id, limit: this.queryLimit,})
- .then(() => log.info("Previous connections loaded"));
- if (this.state.showMoreRecentButton) {
- this.setState({showMoreRecentButton: false});
- }
- } else {
- if (this.lastScrollPosition > e.currentTarget.scrollTop) {
- if (!this.state.showMoreRecentButton) {
- this.setState({showMoreRecentButton: true});
- }
- } else {
- if (this.state.showMoreRecentButton) {
- this.setState({showMoreRecentButton: false});
- }
- }
- }
- this.lastScrollPosition = e.currentTarget.scrollTop;
- };
-
- async loadConnections(additionalParams, initialParams = null, isInitial = false) {
- if (!initialParams) {
- initialParams = this.state.urlParams;
- }
- const urlParams = new URLSearchParams(initialParams.toString());
- for (const [name, value] of Object.entries(additionalParams)) {
- urlParams.set(name, value);
- }
-
- this.setState({loading: true});
- if (!this.state.rules) {
- await this.loadRules();
- }
- if (!this.state.services) {
- await this.loadServices();
- }
-
- let res = (await backend.get(`/api/connections?${urlParams}`)).json;
-
- let connections = this.state.connections;
- let firstConnection = this.state.firstConnection;
- let lastConnection = this.state.lastConnection;
-
- if (additionalParams && additionalParams.from && !additionalParams.to) {
- if (res.length > 0) {
- if (!isInitial) {
- res = res.slice(1);
- }
- connections = this.state.connections.concat(res);
- lastConnection = connections[connections.length - 1];
- if (isInitial) {
- firstConnection = connections[0];
- }
- if (connections.length > this.maxConnections) {
- connections = connections.slice(connections.length - this.maxConnections,
- connections.length - 1);
- firstConnection = connections[0];
- }
- }
- } else if (additionalParams && additionalParams.to && !additionalParams.from) {
- if (res.length > 0) {
- 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);
- lastConnection = connections[this.maxConnections - 1];
- }
- }
- } else {
- if (res.length > 0) {
- connections = res;
- firstConnection = connections[0];
- lastConnection = connections[connections.length - 1];
- } else {
- connections = [];
- firstConnection = null;
- lastConnection = null;
- }
- }
-
- this.setState({loading: false, connections, firstConnection, lastConnection});
-
- if (firstConnection != null && lastConnection != null) {
- dispatcher.dispatch("connection_updates", {
- from: new Date(lastConnection["started_at"]),
- to: new Date(firstConnection["started_at"])
- });
- }
- }
-
- loadRules = async () => {
- return backend.get("/api/rules").then((res) => this.setState({rules: res.json}));
- };
-
- loadServices = async () => {
- return backend.get("/api/services").then((res) => this.setState({services: res.json}));
- };
-
- render() {
- let redirect;
- if (this.connectionSelectedRedirect) {
- redirect = ;
- this.connectionSelectedRedirect = false;
- } else if (this.queryStringRedirect) {
- redirect = ;
- this.queryStringRedirect = false;
- }
-
- let loading = null;
- if (this.state.loading) {
- loading =
- );
- }
-
-}
-
-export default withRouter(ConnectionsPane);
diff --git a/frontend/src/components/panels/MainPane.jsx b/frontend/src/components/panels/MainPane.jsx
deleted file mode 100644
index ce72be5..0000000
--- a/frontend/src/components/panels/MainPane.jsx
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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 dispatcher from "../../dispatcher";
-import "./common.scss";
-import "./MainPane.scss";
-import PcapsPane from "./PcapsPane";
-import RulesPane from "./RulesPane";
-import ServicesPane from "./ServicesPane";
-import StreamsPane from "./StreamsPane";
-
-class MainPane extends Component {
-
- state = {};
-
- componentDidMount() {
- const nl = "^600\n^400";
- const options = {
- strings: [
- `welcome to caronte!^1000 the current version is ${this.props.version}` + nl +
- "caronte is a network analyzer,^300 it is able to read pcaps and extract connections", // 0
- "the left panel lists all connections that have already been closed" + nl +
- "scrolling up the list will load the most recent connections,^300 downward the oldest ones", // 1
- "by selecting a connection you can view its content,^300 which will be shown in the right panel" + nl +
- "you can choose the display format,^300 or decide to download the connection content", // 2
- "below there is the timeline,^300 which shows the number of connections per minute per service" + nl +
- "you can use the sliding window to move the time range of the connections to be displayed", // 3
- "there are also additional metrics,^300 selectable from the drop-down menu", // 4
- "at the top are the filters,^300 which can be used to select only certain types of connections" + nl +
- "you can choose which filters to display in the top bar from the filters window", // 5
- "in the pcaps panel it is possible to analyze new pcaps,^300 or to see the pcaps already analyzed" + nl +
- "you can load pcaps from your browser,^300 or process pcaps already present on the filesystem", // 6
- "in the rules panel you can see the rules already created,^300 or create new ones" + nl +
- "the rules inserted will be used only to label new connections, not those already analyzed" + nl +
- "a connection is tagged if it meets all the requirements specified by the rule", // 7
- "in the services panel you can assign new services or edit existing ones" + nl +
- "each service is associated with a port number,^300 and will be shown in the connection list", // 8
- "from the configuration panel you can change the settings of the frontend application", // 9
- "that's all! and have fun!" + nl + "created by @eciavatta" // 10
- ],
- typeSpeed: 40,
- cursorChar: "_",
- backSpeed: 5,
- smartBackspace: false,
- backDelay: 1500,
- preStringTyped: (arrayPos) => {
- switch (arrayPos) {
- case 1:
- return dispatcher.dispatch("pulse_connections_view", {duration: 12000});
- case 2:
- return this.setState({backgroundPane: });
- case 3:
- this.setState({backgroundPane: null});
- return dispatcher.dispatch("pulse_timeline", {duration: 12000});
- case 6:
- return this.setState({backgroundPane: });
- case 7:
- return this.setState({backgroundPane: });
- case 8:
- return this.setState({backgroundPane: });
- case 10:
- return this.setState({backgroundPane: null});
- default:
- return;
- }
- },
- };
- this.typed = new Typed(this.el, options);
- }
-
- componentWillUnmount() {
- this.typed.destroy();
- }
-
- render() {
- return (
-
-
-
-
- {
- this.el = el;
- }}/>
-
-
-
-
- {this.state.backgroundPane}
-
-
- );
- }
-
-}
-
-export default MainPane;
diff --git a/frontend/src/components/panels/PcapsPane.jsx b/frontend/src/components/panels/PcapsPane.jsx
deleted file mode 100644
index b7d5ce9..0000000
--- a/frontend/src/components/panels/PcapsPane.jsx
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * 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 Table from "react-bootstrap/Table";
-import backend from "../../backend";
-import dispatcher from "../../dispatcher";
-import {createCurlCommand, dateTimeToTime, durationBetween, formatSize} from "../../utils";
-import ButtonField from "../fields/ButtonField";
-import CheckField from "../fields/CheckField";
-import InputField from "../fields/InputField";
-import TextField from "../fields/TextField";
-import CopyLinkPopover from "../objects/CopyLinkPopover";
-import LinkPopover from "../objects/LinkPopover";
-import "./common.scss";
-import "./PcapsPane.scss";
-
-class PcapsPane extends Component {
-
- state = {
- sessions: [],
- isUploadFileValid: true,
- isUploadFileFocused: false,
- uploadFlushAll: false,
- isFileValid: true,
- isFileFocused: false,
- fileValue: "",
- processFlushAll: false,
- deleteOriginalFile: false
- };
-
- componentDidMount() {
- this.loadSessions();
- dispatcher.register("notifications", this.handleNotifications);
- document.title = "caronte:~/pcaps$";
- }
-
- componentWillUnmount() {
- dispatcher.unregister(this.handleNotifications);
- }
-
- handleNotifications = (payload) => {
- if (payload.event.startsWith("pcap")) {
- this.loadSessions();
- }
- };
-
- loadSessions = () => {
- backend.get("/api/pcap/sessions")
- .then((res) => this.setState({sessions: res.json, sessionsStatusCode: res.status}))
- .catch((res) => this.setState({
- sessions: res.json, sessionsStatusCode: res.status,
- sessionsResponse: JSON.stringify(res.json)
- }));
- };
-
- uploadPcap = () => {
- if (this.state.uploadSelectedFile == null || !this.state.isUploadFileValid) {
- this.setState({isUploadFileFocused: true});
- return;
- }
-
- const formData = new FormData();
- formData.append("file", this.state.uploadSelectedFile);
- formData.append("flush_all", this.state.uploadFlushAll);
- backend.postFile("/api/pcap/upload", formData).then((res) => {
- this.setState({
- uploadStatusCode: res.status,
- uploadResponse: JSON.stringify(res.json)
- });
- this.resetUpload();
- this.loadSessions();
- }).catch((res) => this.setState({
- uploadStatusCode: res.status,
- uploadResponse: JSON.stringify(res.json)
- })
- );
- };
-
- processPcap = () => {
- if (this.state.fileValue === "" || !this.state.isFileValid) {
- this.setState({isFileFocused: true});
- return;
- }
-
- backend.post("/api/pcap/file", {
- "file": this.state.fileValue,
- "flush_all": this.state.processFlushAll,
- "delete_original_file": this.state.deleteOriginalFile
- }).then((res) => {
- this.setState({
- processStatusCode: res.status,
- processResponse: JSON.stringify(res.json)
- });
- this.resetProcess();
- this.loadSessions();
- }).catch((res) => this.setState({
- processStatusCode: res.status,
- processResponse: JSON.stringify(res.json)
- })
- );
- };
-
- resetUpload = () => {
- this.setState({
- isUploadFileValid: true,
- isUploadFileFocused: false,
- uploadFlushAll: false,
- uploadSelectedFile: null
- });
- };
-
- resetProcess = () => {
- this.setState({
- isFileValid: true,
- isFileFocused: false,
- fileValue: "",
- processFlushAll: false,
- deleteOriginalFile: false,
- });
- };
-
- render() {
- let sessions = this.state.sessions.map((s) => {
- const startedAt = new Date(s["started_at"]);
- const completedAt = new Date(s["completed_at"]);
- let timeInfo =
- Started at {startedAt.toLocaleDateString() + " " + startedAt.toLocaleTimeString()}
- Completed at {completedAt.toLocaleDateString() + " " + completedAt.toLocaleTimeString()}
-
- );
- }
-}
-
-export default StreamsPane;
diff --git a/frontend/src/index.jsx b/frontend/src/index.jsx
deleted file mode 100644
index 62cb974..0000000
--- a/frontend/src/index.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 "bootstrap/dist/css/bootstrap.css";
-import React from "react";
-import ReactDOM from "react-dom";
-import App from "./components/App";
-import "./index.scss";
-import notifications from "./notifications";
-
-notifications.createWebsocket();
-
-ReactDOM.render(
- //
- ,
- // ,
- document.getElementById("root")
-);
--
cgit v1.2.3-70-g09d2