From d5f94b76986615b255b77b2a7b7ed336e5ad4838 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Wed, 7 Oct 2020 14:58:48 +0200 Subject: Implement notifications --- frontend/src/dispatcher.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 frontend/src/dispatcher.js (limited to 'frontend/src/dispatcher.js') diff --git a/frontend/src/dispatcher.js b/frontend/src/dispatcher.js new file mode 100644 index 0000000..4b8b5a4 --- /dev/null +++ b/frontend/src/dispatcher.js @@ -0,0 +1,35 @@ + +class Dispatcher { + + constructor() { + this.listeners = []; + } + + dispatch = (topic, payload) => { + this.listeners.filter(l => l.topic === topic).forEach(l => l.callback(payload)); + }; + + register = (topic, callback) => { + if (typeof callback !== "function") { + throw new Error("dispatcher callback must be a function"); + } + if (typeof topic === "string") { + this.listeners.push({topic, callback}); + } else if (typeof topic === "object" && Array.isArray(topic)) { + topic.forEach(e => { + if (typeof e !== "string") { + throw new Error("all topics must be strings"); + } + }); + + topic.forEach(e => this.listeners.push({e, callback})); + } else { + throw new Error("topic must be a string or an array of strings"); + } + }; + +} + +const dispatcher = new Dispatcher(); + +export default dispatcher; -- 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 'frontend/src/dispatcher.js') 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 08456e7f2e1c1af6fc8fdbf580c0178a25b93f8b Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Thu, 15 Oct 2020 08:53:09 +0200 Subject: General improvements --- frontend/public/logo128.png | Bin 0 -> 6498 bytes frontend/public/logo192.png | Bin 6498 -> 0 bytes frontend/public/manifest.json | 8 +- frontend/src/components/Header.js | 2 +- frontend/src/components/Timeline.js | 122 +++++++++++++++------ frontend/src/components/Timeline.scss | 1 + .../components/filters/BooleanConnectionsFilter.js | 64 ++++------- .../src/components/filters/ExitSearchFilter.js | 9 +- .../src/components/filters/FiltersDispatcher.js | 57 ---------- .../components/filters/RulesConnectionsFilter.js | 81 ++++++-------- .../components/filters/StringConnectionsFilter.js | 77 ++++++------- frontend/src/components/objects/Connection.js | 4 +- .../components/objects/ConnectionMatchedRules.js | 21 ++-- frontend/src/components/pages/MainPage.js | 3 - frontend/src/components/panels/ConnectionsPane.js | 122 ++++++++++++--------- frontend/src/components/panels/SearchPane.scss | 1 + frontend/src/components/panels/StreamsPane.js | 2 +- frontend/src/dispatcher.js | 6 + search_controller.go | 4 + statistics_controller.go | 19 ++-- 20 files changed, 299 insertions(+), 304 deletions(-) create mode 100644 frontend/public/logo128.png delete mode 100644 frontend/public/logo192.png delete mode 100644 frontend/src/components/filters/FiltersDispatcher.js (limited to 'frontend/src/dispatcher.js') diff --git a/frontend/public/logo128.png b/frontend/public/logo128.png new file mode 100644 index 0000000..1969e1d Binary files /dev/null and b/frontend/public/logo128.png differ diff --git a/frontend/public/logo192.png b/frontend/public/logo192.png deleted file mode 100644 index 1969e1d..0000000 Binary files a/frontend/public/logo192.png and /dev/null differ diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json index 0409a59..32674ce 100644 --- a/frontend/public/manifest.json +++ b/frontend/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "Caronte", - "name": "Caronte", + "short_name": "caronte", + "name": "caronte", "icons": [ { "src": "favicon.ico", @@ -8,9 +8,9 @@ "type": "image/x-icon" }, { - "src": "logo192.png", + "src": "logo128.png", "type": "image/png", - "sizes": "192x192" + "sizes": "128x128" }, { "src": "logo512.png", diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js index b72b532..b4a2177 100644 --- a/frontend/src/components/Header.js +++ b/frontend/src/components/Header.js @@ -89,7 +89,7 @@ class Header extends Component {
- {/**/} + diff --git a/frontend/src/components/Timeline.js b/frontend/src/components/Timeline.js index 6b8806f..bc42a01 100644 --- a/frontend/src/components/Timeline.js +++ b/frontend/src/components/Timeline.js @@ -35,8 +35,12 @@ import log from "../log"; import dispatcher from "../dispatcher"; const minutes = 60 * 1000; +const _ = require('lodash'); const classNames = require('classnames'); +const leftSelectionPaddingMultiplier = 24; +const rightSelectionPaddingMultiplier = 8; + class Timeline extends Component { state = { @@ -50,25 +54,30 @@ class Timeline extends Component { this.selectionTimeout = null; } - filteredPort = () => { + additionalFilters = () => { const urlParams = new URLSearchParams(this.props.location.search); - return urlParams.get("service_port"); + if (this.state.metric === "matched_rules") { + return urlParams.getAll("matched_rules") || []; + } else { + 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")); + const additionalFilters = this.additionalFilters(); + this.setState({filters: additionalFilters}); + this.loadStatistics(this.state.metric, additionalFilters).then(() => log.debug("Statistics loaded after mount")); dispatcher.register("connection_updates", payload => { this.setState({ selection: new TimeRange(payload.from, payload.to), }); + this.adjustSelection(); }); dispatcher.register("notifications", payload => { if (payload.event === "services.edit") { - this.loadServices().then(() => log.debug("Services reloaded after notification update")); + this.loadServices().then(() => this.adjustSelection()); } }); @@ -79,27 +88,48 @@ class Timeline extends Component { } 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")); + const additionalFilters = this.additionalFilters(); + const updateStatistics = () => { + this.setState({filters: additionalFilters}); + this.loadStatistics(this.state.metric, additionalFilters).then(() => + log.debug("Statistics reloaded after filters changes")); + }; + + if (this.state.metric === "matched_rules") { + if (!Array.isArray(this.state.filters) || + !_.isEqual(_.sortBy(additionalFilters), _.sortBy(this.state.filters))) { + updateStatistics(); + } + } else { + if (this.state.filters !== additionalFilters) { + updateStatistics(); + } } } - loadStatistics = async (metric, filteredPort) => { + loadStatistics = async (metric, filters) => { 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; - } + let columns = []; + if (metric === "matched_rules") { + let rules = await this.loadRules(); + filters.forEach(id => { + urlParams.append("matched_rules", id); + }); + columns = rules.map(r => r.id); + } else { + let services = await this.loadServices(); + const filteredPort = filters; + if (filteredPort && services[filters]) { + const service = services[filteredPort]; + services = {}; + services[filteredPort] = service; + } - const ports = Object.keys(services); - ports.forEach(s => urlParams.append("ports", s)); + columns = Object.keys(services); + columns.forEach(port => urlParams.append("ports", port)); + } const metrics = (await backend.get("/api/statistics?" + urlParams)).json; if (metrics.length === 0) { @@ -109,8 +139,8 @@ class Timeline extends Component { const zeroFilledMetrics = []; const toTime = m => new Date(m["range_start"]).getTime(); let i = 0; - for (let interval = toTime(metrics[0]); interval <= toTime(metrics[metrics.length - 1]); interval += minutes) { - if (interval === toTime(metrics[i])) { + for (let interval = toTime(metrics[0]) - minutes; interval <= toTime(metrics[metrics.length - 1]) + minutes; 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); @@ -118,30 +148,31 @@ class Timeline extends Component { const m = {}; m["range_start"] = new Date(interval); m[metric] = {}; - ports.forEach(p => m[metric][p] = 0); + columns.forEach(c => m[metric][c] = 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))) + 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(); - start.setTime(start.getTime() - minutes); - end.setTime(end.getTime() + minutes); this.setState({ metric, series, timeRange: new TimeRange(start, end), + columns, start, end }); - log.debug(`Loaded statistics for metric "${metric}" for services [${ports}]`); + log.debug(`Loaded statistics for metric "${metric}"`); }; loadServices = async () => { @@ -150,10 +181,22 @@ class Timeline extends Component { return services; }; + loadRules = async () => { + const rules = (await backend.get("/api/rules")).json; + this.setState({rules}); + return rules; + }; + createStyler = () => { - return styler(Object.keys(this.state.services).map(port => { - return {key: port, color: this.state.services[port].color, width: 2}; - })); + 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) => { @@ -179,6 +222,15 @@ class Timeline extends Component { }, 1000); }; + 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); @@ -207,7 +259,7 @@ class Timeline extends Component { max={this.aggregateSeries("max")} width="35" type="linear" transition={300}/> this.loadStatistics(metric, this.state.filteredPort) + "server_bytes_per_service", "duration_per_service", "matched_rules"]} + onChange={(metric) => this.loadStatistics(metric, this.state.filters) .then(() => log.debug("Statistics loaded after metric changes"))} value={this.state.metric}/>
diff --git a/frontend/src/components/Timeline.scss b/frontend/src/components/Timeline.scss index db8d9c8..262da1e 100644 --- a/frontend/src/components/Timeline.scss +++ b/frontend/src/components/Timeline.scss @@ -12,6 +12,7 @@ position: absolute; top: 5px; right: 10px; + width: 180px; } &.pulse-timeline { diff --git a/frontend/src/components/filters/BooleanConnectionsFilter.js b/frontend/src/components/filters/BooleanConnectionsFilter.js index a9a420e..c611a0d 100644 --- a/frontend/src/components/filters/BooleanConnectionsFilter.js +++ b/frontend/src/components/filters/BooleanConnectionsFilter.js @@ -17,65 +17,49 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; -import {Redirect} from "react-router"; import CheckField from "../fields/CheckField"; +import dispatcher from "../../dispatcher"; class BooleanConnectionsFilter extends Component { - constructor(props) { - super(props); - this.state = { - filterActive: "false" - }; - - this.filterChanged = this.filterChanged.bind(this); - this.needRedirect = false; - } + 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); } - componentDidUpdate(prevProps, prevState, snapshot) { - let urlParams = new URLSearchParams(this.props.location.search); - let externalActive = this.toBoolean(urlParams.get(this.props.filterName)); - let filterActive = this.toBoolean(this.state.filterActive); - // if the filterActive state is changed by another component (and not by filterChanged func) and - // the query string is not equals at the filterActive state, update the state of the component - if (this.toBoolean(prevState.filterActive) === filterActive && filterActive !== externalActive) { - this.setState({filterActive: externalActive.toString()}); - } + componentWillUnmount() { + dispatcher.unregister(this.connectionsFiltersCallback); } - toBoolean(value) { + toBoolean = (value) => { return value !== null && value.toLowerCase() === "true"; - } + }; - filterChanged() { - this.needRedirect = true; - this.setState({filterActive: (!this.toBoolean(this.state.filterActive)).toString()}); - } + 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() { - let redirect = null; - if (this.needRedirect) { - let urlParams = new URLSearchParams(this.props.location.search); - if (this.toBoolean(this.state.filterActive)) { - urlParams.set(this.props.filterName, "true"); - } else { - urlParams.delete(this.props.filterName); - } - redirect = ; - - this.needRedirect = false; - } - return (
- {redirect} + onChange={this.filterChanged}/>
); } diff --git a/frontend/src/components/filters/ExitSearchFilter.js b/frontend/src/components/filters/ExitSearchFilter.js index cfee298..68ca686 100644 --- a/frontend/src/components/filters/ExitSearchFilter.js +++ b/frontend/src/components/filters/ExitSearchFilter.js @@ -28,11 +28,16 @@ class ExitSearchFilter extends Component { let params = new URLSearchParams(this.props.location.search); this.setState({performedSearch: params.get("performed_search")}); - dispatcher.register("connections_filters", payload => { + 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() { diff --git a/frontend/src/components/filters/FiltersDispatcher.js b/frontend/src/components/filters/FiltersDispatcher.js deleted file mode 100644 index 3769055..0000000 --- a/frontend/src/components/filters/FiltersDispatcher.js +++ /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 {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 fc0ad4d..4c993dc 100644 --- a/frontend/src/components/filters/RulesConnectionsFilter.js +++ b/frontend/src/components/filters/RulesConnectionsFilter.js @@ -17,87 +17,74 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; -import {Redirect} from "react-router"; import './RulesConnectionsFilter.scss'; import ReactTags from 'react-tag-autocomplete'; import backend from "../../backend"; +import dispatcher from "../../dispatcher"; const classNames = require('classnames'); +const _ = require('lodash'); class RulesConnectionsFilter extends Component { - constructor(props) { - super(props); - this.state = { - mounted: false, - rules: [], - activeRules: [] - }; - - this.needRedirect = false; - } + state = { + rules: [], + activeRules: [] + }; componentDidMount() { - let params = new URLSearchParams(this.props.location.search); + 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, mounted: true}); + 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); } - componentDidUpdate(prevProps, prevState, snapshot) { - let urlParams = new URLSearchParams(this.props.location.search); - let externalRules = urlParams.getAll("matched_rules") || []; - let activeRules = this.state.activeRules.map(r => r.id); - let compareRules = (first, second) => first.sort().join(",") === second.sort().join(","); - if (this.state.mounted && - compareRules(prevState.activeRules.map(r => r.id), activeRules) && - !compareRules(externalRules, activeRules)) { - this.setState({activeRules: externalRules.map(id => this.state.rules.find(r => r.id === id))}); - } + componentWillUnmount() { + dispatcher.unregister(this.connectionsFiltersCallback); } - onDelete(i) { - const activeRules = this.state.activeRules.slice(0); + onDelete = (i) => { + const activeRules = _.clone(this.state.activeRules); activeRules.splice(i, 1); - this.needRedirect = true; - this.setState({ activeRules }); - } + this.setState({activeRules}); + dispatcher.dispatch("connections_filters", {"matched_rules": activeRules.map(r => r.id)}); + }; - onAddition(rule) { + onAddition = (rule) => { if (!this.state.activeRules.includes(rule)) { const activeRules = [].concat(this.state.activeRules, rule); - this.needRedirect = true; this.setState({activeRules}); + dispatcher.dispatch("connections_filters", {"matched_rules": activeRules.map(r => r.id)}); } - } + }; render() { - let redirect = null; - - if (this.needRedirect) { - let urlParams = new URLSearchParams(this.props.location.search); - urlParams.delete("matched_rules"); - this.state.activeRules.forEach(rule => urlParams.append("matched_rules", rule.id)); - redirect = ; - - this.needRedirect = false; - } - return ( -
+
- suggestion.name.startsWith(query) && !this.state.activeRules.includes(suggestion)} /> + suggestion.name.startsWith(query) && !this.state.activeRules.includes(suggestion)}/>
- - {redirect}
); } diff --git a/frontend/src/components/filters/StringConnectionsFilter.js b/frontend/src/components/filters/StringConnectionsFilter.js index a3b45dc..c833220 100644 --- a/frontend/src/components/filters/StringConnectionsFilter.js +++ b/frontend/src/components/filters/StringConnectionsFilter.js @@ -17,37 +17,36 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; -import {Redirect} from "react-router"; import InputField from "../fields/InputField"; +import dispatcher from "../../dispatcher"; class StringConnectionsFilter extends Component { - constructor(props) { - super(props); - this.state = { - fieldValue: "", - filterValue: null, - timeoutHandle: null, - invalidValue: false - }; - this.needRedirect = false; - this.filterChanged = this.filterChanged.bind(this); - } + 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); } - componentDidUpdate(prevProps, prevState, snapshot) { - let urlParams = new URLSearchParams(this.props.location.search); - let filterValue = urlParams.get(this.props.filterName); - if (prevState.filterValue === this.state.filterValue && this.state.filterValue !== filterValue) { - this.updateStateFromFilterValue(filterValue); - } + componentWillUnmount() { + dispatcher.unregister(this.connectionsFiltersCallback); } - updateStateFromFilterValue(filterValue) { + updateStateFromFilterValue = (filterValue) => { if (filterValue !== null) { let fieldValue = filterValue; if (typeof this.props.decodeFunc === "function") { @@ -70,15 +69,21 @@ class StringConnectionsFilter extends Component { } else { this.setState({fieldValue: "", filterValue: null}); } - } + }; - isValueValid(value) { + isValueValid = (value) => { return typeof this.props.validateFunc !== "function" || (typeof this.props.validateFunc === "function" && this.props.validateFunc(value)); - } + }; - filterChanged(fieldValue) { - if (this.state.timeoutHandle !== null) { + changeFilterValue = (value) => { + const urlParams = {}; + urlParams[this.props.filterName] = value; + dispatcher.dispatch("connections_filters", urlParams); + }; + + filterChanged = (fieldValue) => { + if (this.state.timeoutHandle) { clearTimeout(this.state.timeoutHandle); } @@ -87,11 +92,12 @@ class StringConnectionsFilter extends Component { } if (fieldValue === "") { - this.needRedirect = true; this.setState({fieldValue: "", filterValue: null, invalidValue: false}); - return; + return this.changeFilterValue(null); } + + if (this.isValueValid(fieldValue)) { let filterValue = fieldValue; if (filterValue !== "" && typeof this.props.encodeFunc === "function") { @@ -101,40 +107,27 @@ class StringConnectionsFilter extends Component { this.setState({ fieldValue: fieldValue, timeoutHandle: setTimeout(() => { - this.needRedirect = true; this.setState({filterValue: filterValue}); + this.changeFilterValue(filterValue); }, 500), invalidValue: false }); } else { - this.needRedirect = true; this.setState({ fieldValue: fieldValue, invalidValue: true }); } - } + }; render() { - let redirect = null; - if (this.needRedirect) { - let urlParams = new URLSearchParams(this.props.location.search); - if (this.state.filterValue !== null) { - urlParams.set(this.props.filterName, this.state.filterValue); - } else { - urlParams.delete(this.props.filterName); - } - redirect = ; - this.needRedirect = false; - } let active = this.state.filterValue !== null; return (
- {redirect} + value={this.state.fieldValue} inline={true} small={true}/>
); } diff --git a/frontend/src/components/objects/Connection.js b/frontend/src/components/objects/Connection.js index e0e942a..96f2235 100644 --- a/frontend/src/components/objects/Connection.js +++ b/frontend/src/components/objects/Connection.js @@ -23,6 +23,7 @@ import {dateTimeToTime, durationBetween, formatSize} from "../../utils"; import ButtonField from "../fields/ButtonField"; import LinkPopover from "./LinkPopover"; import TextField from "../fields/TextField"; +import dispatcher from "../../dispatcher"; const classNames = require('classnames'); @@ -99,7 +100,8 @@ class Connection extends Component { this.props.addServicePortFilter(conn["port_dst"])}/> + onClick={() => dispatcher.dispatch("connections_filters", + {"service_port": conn["port_dst"].toString()})}/> {conn["ip_src"]} diff --git a/frontend/src/components/objects/ConnectionMatchedRules.js b/frontend/src/components/objects/ConnectionMatchedRules.js index 73d5c5d..92bde49 100644 --- a/frontend/src/components/objects/ConnectionMatchedRules.js +++ b/frontend/src/components/objects/ConnectionMatchedRules.js @@ -18,20 +18,25 @@ import React, {Component} from 'react'; import './ConnectionMatchedRules.scss'; import ButtonField from "../fields/ButtonField"; +import dispatcher from "../../dispatcher"; +import {withRouter} from "react-router-dom"; class ConnectionMatchedRules extends Component { - constructor(props) { - super(props); - this.state = { - }; - } + 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.props.addMatchedRulesFilter(rule.id)} name={rule.name} - color={rule.color} small />; + return this.onMatchedRulesSelected(rule.id)} name={rule.name} + color={rule.color} small/>; }); return ( @@ -43,4 +48,4 @@ class ConnectionMatchedRules extends Component { } } -export default ConnectionMatchedRules; +export default withRouter(ConnectionMatchedRules); diff --git a/frontend/src/components/pages/MainPage.js b/frontend/src/components/pages/MainPage.js index da57e1a..0b06f55 100644 --- a/frontend/src/components/pages/MainPage.js +++ b/frontend/src/components/pages/MainPage.js @@ -29,7 +29,6 @@ import Header from "../Header"; import Filters from "../dialogs/Filters"; import MainPane from "../panels/MainPane"; import SearchPane from "../panels/SearchPane"; -import FiltersDispatcher from "../filters/FiltersDispatcher"; class MainPage extends Component { @@ -70,8 +69,6 @@ class MainPage extends Component {
- -
); diff --git a/frontend/src/components/panels/ConnectionsPane.js b/frontend/src/components/panels/ConnectionsPane.js index 1f79ab8..33dd7c1 100644 --- a/frontend/src/components/panels/ConnectionsPane.js +++ b/frontend/src/components/panels/ConnectionsPane.js @@ -19,13 +19,13 @@ import React, {Component} from 'react'; import './ConnectionsPane.scss'; import Connection from "../objects/Connection"; import Table from 'react-bootstrap/Table'; -import {Redirect} from 'react-router'; import {withRouter} from "react-router-dom"; import backend from "../../backend"; import ConnectionMatchedRules from "../objects/ConnectionMatchedRules"; import log from "../../log"; import ButtonField from "../fields/ButtonField"; import dispatcher from "../../dispatcher"; +import {Redirect} from "react-router"; const classNames = require('classnames'); @@ -50,60 +50,91 @@ class ConnectionsPane extends Component { } componentDidMount() { - const initialParams = {limit: this.queryLimit}; + 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]; - initialParams.from = id; + additionalParams.from = id; backend.get(`/api/connections/${id}`) - .then(res => this.connectionSelected(res.json, false)) + .then(res => this.connectionSelected(res.json)) .catch(error => log.error("Error loading initial connection", error)); } - this.loadConnections(initialParams, true).then(() => log.debug("Connections loaded")); + this.loadConnections(additionalParams, urlParams, true).then(() => log.debug("Connections loaded")); + + this.connectionsFiltersCallback = payload => { + const params = this.state.urlParams; + const initialParams = params.toString(); + + Object.entries(payload).forEach(([key, value]) => { + if (value == null) { + params.delete(key); + } else if (Array.isArray(value)) { + params.delete(key); + value.forEach(v => params.append(key, v)); + } else { + params.set(key, value); + } + }); + + if (initialParams === params.toString()) { + return; + } - dispatcher.register("timeline_updates", payload => { + log.debug("Update following url params:", payload); + this.queryStringRedirect = true; + this.setState({urlParams}); + + this.loadConnections({limit: this.queryLimit}, urlParams) + .then(() => log.info("ConnectionsPane reloaded after query string update")); + }; + dispatcher.register("connections_filters", this.connectionsFiltersCallback); + + this.timelineUpdatesCallback = payload => { this.connectionsListRef.current.scrollTop = 0; this.loadConnections({ started_after: Math.round(payload.from.getTime() / 1000), started_before: Math.round(payload.to.getTime() / 1000), limit: this.maxConnections }).then(() => log.info(`Loading connections between ${payload.from} and ${payload.to}`)); - }); + }; + dispatcher.register("timeline_updates", this.timelineUpdatesCallback); - dispatcher.register("notifications", payload => { + this.notificationsCallback = payload => { if (payload.event === "rules.new" || payload.event === "rules.edit") { this.loadRules().then(() => log.debug("Loaded connection rules after notification update")); } - }); - - dispatcher.register("notifications", payload => { if (payload.event === "services.edit") { this.loadServices().then(() => log.debug("Services reloaded after notification update")); } - }); + }; + dispatcher.register("notifications", this.notificationsCallback); - dispatcher.register("pulse_connections_view", payload => { + this.pulseConnectionsViewCallback = payload => { this.setState({pulseConnectionsView: true}); setTimeout(() => this.setState({pulseConnectionsView: false}), payload.duration); - }); + }; + dispatcher.register("pulse_connections_view", this.pulseConnectionsViewCallback); + } + + componentWillUnmount() { + dispatcher.unregister(this.timelineUpdatesCallback); + dispatcher.unregister(this.notificationsCallback); + dispatcher.unregister(this.pulseConnectionsViewCallback); + dispatcher.unregister(this.connectionsFiltersCallback); } - connectionSelected = (c, doRedirect = true) => { - this.doSelectedConnectionRedirect = doRedirect; + connectionSelected = (c) => { + this.connectionSelectedRedirect = true; this.setState({selected: c.id}); this.props.onSelected(c); log.debug(`Connection ${c.id} selected`); }; - componentDidUpdate(prevProps, prevState, snapshot) { - if (prevProps.location.search !== this.props.location.search) { - this.loadConnections({limit: this.queryLimit}) - .then(() => log.info("ConnectionsPane reloaded after query string update")); - } - } - handleScroll = (e) => { if (this.disableScrollHandler) { this.lastScrollPosition = e.currentTarget.scrollTop; @@ -135,27 +166,12 @@ class ConnectionsPane extends Component { this.lastScrollPosition = e.currentTarget.scrollTop; }; - addServicePortFilter = (port) => { - const urlParams = new URLSearchParams(this.props.location.search); - urlParams.set("service_port", port); - this.doQueryStringRedirect = true; - this.setState({queryString: urlParams}); - }; - - addMatchedRulesFilter = (matchedRule) => { - const urlParams = new URLSearchParams(this.props.location.search); - const oldMatchedRules = urlParams.getAll("matched_rules") || []; - - if (!oldMatchedRules.includes(matchedRule)) { - urlParams.append("matched_rules", matchedRule); - this.doQueryStringRedirect = true; - this.setState({queryString: urlParams}); + async loadConnections(additionalParams, initialParams = null, isInitial = false) { + if (!initialParams) { + initialParams = this.state.urlParams; } - }; - - async loadConnections(params, isInitial = false) { - const urlParams = new URLSearchParams(this.props.location.search); - for (const [name, value] of Object.entries(params)) { + const urlParams = new URLSearchParams(initialParams.toString()); + for (const [name, value] of Object.entries(additionalParams)) { urlParams.set(name, value); } @@ -173,7 +189,7 @@ class ConnectionsPane extends Component { let firstConnection = this.state.firstConnection; let lastConnection = this.state.lastConnection; - if (params !== undefined && params.from !== undefined && params.to === undefined) { + if (additionalParams !== undefined && additionalParams.from !== undefined && additionalParams.to === undefined) { if (res.length > 0) { if (!isInitial) { res = res.slice(1); @@ -189,7 +205,7 @@ class ConnectionsPane extends Component { firstConnection = connections[0]; } } - } else if (params !== undefined && params.to !== undefined && params.from === undefined) { + } else if (additionalParams !== undefined && additionalParams.to !== undefined && additionalParams.from === undefined) { if (res.length > 0) { connections = res.slice(0, res.length - 1).concat(this.state.connections); firstConnection = connections[0]; @@ -235,12 +251,12 @@ class ConnectionsPane extends Component { render() { let redirect; - if (this.doSelectedConnectionRedirect) { - redirect = ; - this.doSelectedConnectionRedirect = false; - } else if (this.doQueryStringRedirect) { - redirect = ; - this.doQueryStringRedirect = false; + if (this.connectionSelectedRedirect) { + redirect = ; + this.connectionSelectedRedirect = false; + } else if (this.queryStringRedirect) { + redirect = ; + this.queryStringRedirect = false; } let loading = null; @@ -288,12 +304,10 @@ class ConnectionsPane extends Component { selected={this.state.selected === c.id} onMarked={marked => c.marked = marked} onEnabled={enabled => c.hidden = !enabled} - addServicePortFilter={this.addServicePortFilter} services={this.state.services}/>, c.matched_rules.length > 0 && + rules={this.state.rules}/> ]; }) } diff --git a/frontend/src/components/panels/SearchPane.scss b/frontend/src/components/panels/SearchPane.scss index 15fc7da..63e11fb 100644 --- a/frontend/src/components/panels/SearchPane.scss +++ b/frontend/src/components/panels/SearchPane.scss @@ -4,6 +4,7 @@ .searches-list { overflow: hidden; + flex: 2 1; .section-content { height: 100%; diff --git a/frontend/src/components/panels/StreamsPane.js b/frontend/src/components/panels/StreamsPane.js index bd1964e..1aa5c53 100644 --- a/frontend/src/components/panels/StreamsPane.js +++ b/frontend/src/components/panels/StreamsPane.js @@ -107,7 +107,7 @@ class StreamsPane extends Component { const json = JSON.parse(m.body); body = ; } catch (e) { - console.log(e); + log.error(e); } } diff --git a/frontend/src/dispatcher.js b/frontend/src/dispatcher.js index 943f7ec..fa08d48 100644 --- a/frontend/src/dispatcher.js +++ b/frontend/src/dispatcher.js @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +const _ = require('lodash'); + class Dispatcher { constructor() { @@ -44,6 +46,10 @@ class Dispatcher { } }; + unregister = (callback) => { + this.listeners = _.without(callback); + }; + } const dispatcher = new Dispatcher(); diff --git a/search_controller.go b/search_controller.go index 723cd93..5ed762a 100644 --- a/search_controller.go +++ b/search_controller.go @@ -76,6 +76,10 @@ func NewSearchController(storage Storage) *SearchController { log.WithError(err).Panic("failed to retrieve performed searches") } + if searches == nil { + searches = []PerformedSearch{} + } + return &SearchController{ storage: storage, performedSearches: searches, diff --git a/statistics_controller.go b/statistics_controller.go index 57c7d95..fda7494 100644 --- a/statistics_controller.go +++ b/statistics_controller.go @@ -26,19 +26,19 @@ import ( type StatisticRecord struct { RangeStart time.Time `json:"range_start" bson:"_id"` - ConnectionsPerService map[uint16]int `json:"connections_per_service,omitempty" bson:"connections_per_service"` - ClientBytesPerService map[uint16]int `json:"client_bytes_per_service,omitempty" bson:"client_bytes_per_service"` - ServerBytesPerService map[uint16]int `json:"server_bytes_per_service,omitempty" bson:"server_bytes_per_service"` - TotalBytesPerService map[uint16]int `json:"total_bytes_per_service,omitempty" bson:"total_bytes_per_service"` - DurationPerService map[uint16]int64 `json:"duration_per_service,omitempty" bson:"duration_per_service"` - MatchedRules map[RowID]int64 `json:"matched_rules,omitempty" bson:"matched_rules"` + ConnectionsPerService map[uint16]int `json:"connections_per_service" bson:"connections_per_service"` + ClientBytesPerService map[uint16]int `json:"client_bytes_per_service" bson:"client_bytes_per_service"` + ServerBytesPerService map[uint16]int `json:"server_bytes_per_service" bson:"server_bytes_per_service"` + TotalBytesPerService map[uint16]int `json:"total_bytes_per_service" bson:"total_bytes_per_service"` + DurationPerService map[uint16]int64 `json:"duration_per_service" bson:"duration_per_service"` + MatchedRules map[string]int64 `json:"matched_rules" bson:"matched_rules"` } type StatisticsFilter struct { RangeFrom time.Time `form:"range_from"` RangeTo time.Time `form:"range_to"` Ports []uint16 `form:"ports"` - RulesIDs []RowID `form:"rules_ids"` + RulesIDs []string `form:"rules_ids"` Metric string `form:"metric"` } @@ -57,7 +57,7 @@ func NewStatisticsController(storage Storage) StatisticsController { func (sc *StatisticsController) GetStatistics(context context.Context, filter StatisticsFilter) []StatisticRecord { var statisticRecords []StatisticRecord - query := sc.storage.Find(Statistics).Context(context) + query := sc.storage.Find(Statistics).Context(context).Sort("_id", true) if !filter.RangeFrom.IsZero() { query = query.Filter(OrderedDocument{{"_id", UnorderedDocument{"$lt": filter.RangeFrom}}}) } @@ -81,7 +81,7 @@ func (sc *StatisticsController) GetStatistics(context context.Context, filter St } for _, ruleID := range filter.RulesIDs { if filter.Metric == "" || filter.Metric == "matched_rules" { - query = query.Projection(OrderedDocument{{fmt.Sprintf("matched_rules.%s", ruleID.Hex()), 1}}) + query = query.Projection(OrderedDocument{{fmt.Sprintf("matched_rules.%s", ruleID), 1}}) } } @@ -91,6 +91,7 @@ func (sc *StatisticsController) GetStatistics(context context.Context, filter St } } + log.Println(query) if err := query.All(&statisticRecords); err != nil { log.WithError(err).WithField("filter", filter).Error("failed to retrieve statistics") return []StatisticRecord{} -- cgit v1.2.3-70-g09d2 From 97b0ee38fcf1e78e66dfe2a2816c95c3c3b10705 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Thu, 15 Oct 2020 09:54:25 +0200 Subject: Update filters --- frontend/.eslintrc.js | 216 --------------------- frontend/src/components/Header.js | 47 ++--- frontend/src/components/Header.scss | 9 +- frontend/src/components/dialogs/Filters.js | 108 ++++------- frontend/src/components/dialogs/Filters.scss | 5 + frontend/src/components/fields/ButtonField.js | 3 +- frontend/src/components/fields/ButtonField.scss | 7 + frontend/src/components/filters/AdvancedFilters.js | 54 ++++++ .../components/filters/BooleanConnectionsFilter.js | 2 +- .../src/components/filters/FiltersDefinitions.js | 73 ------- .../components/filters/StringConnectionsFilter.js | 2 +- frontend/src/components/panels/ConnectionsPane.js | 22 +-- frontend/src/dispatcher.js | 2 +- frontend/src/index.js | 6 +- frontend/src/utils.js | 16 ++ 15 files changed, 158 insertions(+), 414 deletions(-) delete mode 100644 frontend/.eslintrc.js create mode 100644 frontend/src/components/dialogs/Filters.scss create mode 100644 frontend/src/components/filters/AdvancedFilters.js delete mode 100644 frontend/src/components/filters/FiltersDefinitions.js (limited to 'frontend/src/dispatcher.js') diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js deleted file mode 100644 index 16ff228..0000000 --- a/frontend/.eslintrc.js +++ /dev/null @@ -1,216 +0,0 @@ -const OFF = 0, WARN = 1, ERROR = 2; - -module.exports = exports = { - "env": { - "es6": true - }, - - "ecmaFeatures": { - // env=es6 doesn't include modules, which we are using - "modules": true - }, - - "extends": "eslint:recommended", - - "rules": { - // Possible Errors (overrides from recommended set) - "no-extra-parens": ERROR, - "no-unexpected-multiline": ERROR, - // All JSDoc comments must be valid - "valid-jsdoc": [ ERROR, { - "requireReturn": false, - "requireReturnDescription": false, - "requireParamDescription": true, - "prefer": { - "return": "returns" - } - }], - - // Best Practices - - // Allowed a getter without setter, but all setters require getters - "accessor-pairs": [ ERROR, { - "getWithoutSet": false, - "setWithoutGet": true - }], - "block-scoped-var": WARN, - "consistent-return": ERROR, - "curly": ERROR, - "default-case": WARN, - // the dot goes with the property when doing multiline - "dot-location": [ WARN, "property" ], - "dot-notation": WARN, - "eqeqeq": [ ERROR, "smart" ], - "guard-for-in": WARN, - "no-alert": ERROR, - "no-caller": ERROR, - "no-case-declarations": WARN, - "no-div-regex": WARN, - "no-else-return": WARN, - "no-empty-label": WARN, - "no-empty-pattern": WARN, - "no-eq-null": WARN, - "no-eval": ERROR, - "no-extend-native": ERROR, - "no-extra-bind": WARN, - "no-floating-decimal": WARN, - "no-implicit-coercion": [ WARN, { - "boolean": true, - "number": true, - "string": true - }], - "no-implied-eval": ERROR, - "no-invalid-this": ERROR, - "no-iterator": ERROR, - "no-labels": WARN, - "no-lone-blocks": WARN, - "no-loop-func": ERROR, - "no-magic-numbers": WARN, - "no-multi-spaces": ERROR, - "no-multi-str": WARN, - "no-native-reassign": ERROR, - "no-new-func": ERROR, - "no-new-wrappers": ERROR, - "no-new": ERROR, - "no-octal-escape": ERROR, - "no-param-reassign": ERROR, - "no-process-env": WARN, - "no-proto": ERROR, - "no-redeclare": ERROR, - "no-return-assign": ERROR, - "no-script-url": ERROR, - "no-self-compare": ERROR, - "no-throw-literal": ERROR, - "no-unused-expressions": ERROR, - "no-useless-call": ERROR, - "no-useless-concat": ERROR, - "no-void": WARN, - // Produce warnings when something is commented as TODO or FIXME - "no-warning-comments": [ WARN, { - "terms": [ "TODO", "FIXME" ], - "location": "start" - }], - "no-with": WARN, - "radix": WARN, - "vars-on-top": ERROR, - // Enforces the style of wrapped functions - "wrap-iife": [ ERROR, "outside" ], - "yoda": ERROR, - - // Strict Mode - for ES6, never use strict. - "strict": [ ERROR, "never" ], - - // Variables - "init-declarations": [ ERROR, "always" ], - "no-catch-shadow": WARN, - "no-delete-var": ERROR, - "no-label-var": ERROR, - "no-shadow-restricted-names": ERROR, - "no-shadow": WARN, - // We require all vars to be initialized (see init-declarations) - // If we NEED a var to be initialized to undefined, it needs to be explicit - "no-undef-init": OFF, - "no-undef": ERROR, - "no-undefined": OFF, - "no-unused-vars": WARN, - // Disallow hoisting - let & const don't allow hoisting anyhow - "no-use-before-define": ERROR, - - // Node.js and CommonJS - "callback-return": [ WARN, [ "callback", "next" ]], - "global-require": ERROR, - "handle-callback-err": WARN, - "no-mixed-requires": WARN, - "no-new-require": ERROR, - // Use path.concat instead - "no-path-concat": ERROR, - "no-process-exit": ERROR, - "no-restricted-modules": OFF, - "no-sync": WARN, - - // ECMAScript 6 support - "arrow-body-style": [ ERROR, "always" ], - "arrow-parens": [ ERROR, "always" ], - "arrow-spacing": [ ERROR, { "before": true, "after": true }], - "constructor-super": ERROR, - "generator-star-spacing": [ ERROR, "before" ], - "no-arrow-condition": ERROR, - "no-class-assign": ERROR, - "no-const-assign": ERROR, - "no-dupe-class-members": ERROR, - "no-this-before-super": ERROR, - "no-var": WARN, - "object-shorthand": [ WARN, "never" ], - "prefer-arrow-callback": WARN, - "prefer-spread": WARN, - "prefer-template": WARN, - "require-yield": ERROR, - - // Stylistic - everything here is a warning because of style. - "array-bracket-spacing": [ WARN, "always" ], - "block-spacing": [ WARN, "always" ], - "brace-style": [ WARN, "1tbs", { "allowSingleLine": false } ], - "camelcase": WARN, - "comma-spacing": [ WARN, { "before": false, "after": true } ], - "comma-style": [ WARN, "last" ], - "computed-property-spacing": [ WARN, "never" ], - "consistent-this": [ WARN, "self" ], - "eol-last": WARN, - "func-names": WARN, - "func-style": [ WARN, "declaration" ], - "id-length": [ WARN, { "min": 2, "max": 32 } ], - "indent": [ WARN, 4 ], - "jsx-quotes": [ WARN, "prefer-double" ], - "linebreak-style": [ WARN, "unix" ], - "lines-around-comment": [ WARN, { "beforeBlockComment": true } ], - "max-depth": [ WARN, 8 ], - "max-len": [ WARN, 132 ], - "max-nested-callbacks": [ WARN, 8 ], - "max-params": [ WARN, 8 ], - "new-cap": WARN, - "new-parens": WARN, - "no-array-constructor": WARN, - "no-bitwise": OFF, - "no-continue": OFF, - "no-inline-comments": OFF, - "no-lonely-if": WARN, - "no-mixed-spaces-and-tabs": WARN, - "no-multiple-empty-lines": WARN, - "no-negated-condition": OFF, - "no-nested-ternary": WARN, - "no-new-object": WARN, - "no-plusplus": OFF, - "no-spaced-func": WARN, - "no-ternary": OFF, - "no-trailing-spaces": WARN, - "no-underscore-dangle": WARN, - "no-unneeded-ternary": WARN, - "object-curly-spacing": [ WARN, "always" ], - "one-var": OFF, - "operator-assignment": [ WARN, "never" ], - "operator-linebreak": [ WARN, "after" ], - "padded-blocks": [ WARN, "never" ], - "quote-props": [ WARN, "consistent-as-needed" ], - "quotes": [ WARN, "single" ], - "require-jsdoc": [ WARN, { - "require": { - "FunctionDeclaration": true, - "MethodDefinition": true, - "ClassDeclaration": false - } - }], - "semi-spacing": [ WARN, { "before": false, "after": true }], - "semi": [ ERROR, "always" ], - "sort-vars": OFF, - "space-after-keywords": [ WARN, "always" ], - "space-before-blocks": [ WARN, "always" ], - "space-before-function-paren": [ WARN, "never" ], - "space-before-keywords": [ WARN, "always" ], - "space-in-parens": [ WARN, "never" ], - "space-infix-ops": [ WARN, { "int32Hint": true } ], - "space-return-throw-case": ERROR, - "space-unary-ops": ERROR, - "spaced-comment": [ WARN, "always" ], - "wrap-regex": WARN - } -}; diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js index b4a2177..119958b 100644 --- a/frontend/src/components/Header.js +++ b/frontend/src/components/Header.js @@ -18,21 +18,17 @@ import React, {Component} from 'react'; import Typed from 'typed.js'; 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"; +import {cleanNumber, validatePort} from "../utils"; +import StringConnectionsFilter from "./filters/StringConnectionsFilter"; +import RulesConnectionsFilter from "./filters/RulesConnectionsFilter"; +import BooleanConnectionsFilter from "./filters/BooleanConnectionsFilter"; +import AdvancedFilters from "./filters/AdvancedFilters"; class Header extends Component { - constructor(props) { - super(props); - let newState = {}; - filtersNames.forEach(elem => newState[`${elem}_active`] = false); - this.state = newState; - this.fetchStateFromLocalStorage = this.fetchStateFromLocalStorage.bind(this); - } - componentDidMount() { const options = { strings: ["caronte$ "], @@ -40,33 +36,13 @@ class Header extends Component { cursorChar: "❚" }; this.typed = new Typed(this.el, options); - - this.fetchStateFromLocalStorage(); - - if (typeof window !== "undefined") { - window.addEventListener("quick-filters", this.fetchStateFromLocalStorage); - } } componentWillUnmount() { this.typed.destroy(); - - if (typeof window) { - window.removeEventListener("quick-filters", this.fetchStateFromLocalStorage); - } - } - - fetchStateFromLocalStorage() { - let newState = {}; - filtersNames.forEach(elem => newState[`${elem}_active`] = localStorage.getItem(`filters.${elem}`) === "true"); - this.setState(newState); } render() { - let quickFilters = filtersNames.filter(name => this.state[`${name}_active`]) - .map(name => {filtersDefinitions[name]}) - .slice(0, 5); - return (
@@ -82,14 +58,21 @@ class Header extends Component {
- {quickFilters} - + + + + +
- diff --git a/frontend/src/components/Header.scss b/frontend/src/components/Header.scss index e2e8e1c..fff28e6 100644 --- a/frontend/src/components/Header.scss +++ b/frontend/src/components/Header.scss @@ -26,9 +26,16 @@ .filters-bar { padding: 3px 0; - .filter { + .filter, + .button-field { display: inline-block; margin-right: 10px; } + + .button-field button { + font-weight: 400; + padding: 7px 10px; + border-radius: 5px; + } } } diff --git a/frontend/src/components/dialogs/Filters.js b/frontend/src/components/dialogs/Filters.js index dfd554b..d2cce4f 100644 --- a/frontend/src/components/dialogs/Filters.js +++ b/frontend/src/components/dialogs/Filters.js @@ -16,91 +16,63 @@ */ import React, {Component} from 'react'; -import {Col, Container, Modal, Row, Table} from "react-bootstrap"; -import {filtersDefinitions, filtersNames} from "../filters/FiltersDefinitions"; +import {Col, Container, Modal, Row} from "react-bootstrap"; import ButtonField from "../fields/ButtonField"; +import './Filters.scss'; +import {cleanNumber, validateIpAddress, validateMin, validatePort} from "../../utils"; +import StringConnectionsFilter from "../filters/StringConnectionsFilter"; class Filters extends Component { - constructor(props) { - super(props); - let newState = {}; - filtersNames.forEach(elem => newState[`${elem}_active`] = false); - this.state = newState; - } - - componentDidMount() { - let newState = {}; - filtersNames.forEach(elem => newState[`${elem}_active`] = localStorage.getItem(`filters.${elem}`) === "true"); - this.setState(newState); - } - - checkboxChangesHandler(filterName, event) { - this.setState({[`${filterName}_active`]: event.target.checked}); - localStorage.setItem(`filters.${filterName}`, event.target.checked); - if (typeof window !== "undefined") { - window.dispatchEvent(new Event("quick-filters")); - } - } - - generateRows(filtersNames) { - return filtersNames.map(name => - - this.checkboxChangesHandler(name, event)}/> - {filtersDefinitions[name]} - - ); - } - render() { return ( - ~/filters + ~/advanced_filters - - - - - - - - - - - - {this.generateRows(["service_port", "client_address", "min_duration", - "min_bytes"])} - -
showfilter
- - - - - - - - - - - {this.generateRows(["matched_rules", "client_port", "max_duration", - "max_bytes", "marked"])} - -
showfilter
- -
-
+
+
+ + + +
+ +
+ + + +
+
diff --git a/frontend/src/components/dialogs/Filters.scss b/frontend/src/components/dialogs/Filters.scss new file mode 100644 index 0000000..7d09380 --- /dev/null +++ b/frontend/src/components/dialogs/Filters.scss @@ -0,0 +1,5 @@ +.advanced-filters { + .filter { + margin: 10px; + } +} diff --git a/frontend/src/components/fields/ButtonField.js b/frontend/src/components/fields/ButtonField.js index 193339c..850f837 100644 --- a/frontend/src/components/fields/ButtonField.js +++ b/frontend/src/components/fields/ButtonField.js @@ -55,7 +55,8 @@ class ButtonField extends Component { } return ( -
+
diff --git a/frontend/src/components/fields/ButtonField.scss b/frontend/src/components/fields/ButtonField.scss index 9e46b9f..99afe08 100644 --- a/frontend/src/components/fields/ButtonField.scss +++ b/frontend/src/components/fields/ButtonField.scss @@ -15,6 +15,13 @@ } } + &.field-active { + button { + color: $color-primary-1; + background-color: $color-primary-4; + } + } + .button-variant-red { color: $color-red-light; background-color: $color-red; diff --git a/frontend/src/components/filters/AdvancedFilters.js b/frontend/src/components/filters/AdvancedFilters.js new file mode 100644 index 0000000..f5ba825 --- /dev/null +++ b/frontend/src/components/filters/AdvancedFilters.js @@ -0,0 +1,54 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import React, {Component} from 'react'; +import {withRouter} from "react-router-dom"; +import dispatcher from "../../dispatcher"; +import ButtonField from "../fields/ButtonField"; +import {updateParams} from "../../utils"; + +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: 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.js b/frontend/src/components/filters/BooleanConnectionsFilter.js index c611a0d..9558323 100644 --- a/frontend/src/components/filters/BooleanConnectionsFilter.js +++ b/frontend/src/components/filters/BooleanConnectionsFilter.js @@ -59,7 +59,7 @@ class BooleanConnectionsFilter extends Component { return (
+ onChange={this.filterChanged} small/>
); } diff --git a/frontend/src/components/filters/FiltersDefinitions.js b/frontend/src/components/filters/FiltersDefinitions.js deleted file mode 100644 index 9fb3b18..0000000 --- a/frontend/src/components/filters/FiltersDefinitions.js +++ /dev/null @@ -1,73 +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 {cleanNumber, validateIpAddress, validateMin, validatePort} from "../../utils"; -import StringConnectionsFilter from "./StringConnectionsFilter"; -import React from "react"; -import RulesConnectionsFilter from "./RulesConnectionsFilter"; -import BooleanConnectionsFilter from "./BooleanConnectionsFilter"; - -export const filtersNames = ["service_port", "matched_rules", "client_address", "client_port", - "min_duration", "max_duration", "min_bytes", "max_bytes", "marked"]; - -export const filtersDefinitions = { - service_port: , - matched_rules: , - client_address: , - client_port: , - min_duration: , - max_duration: , - min_bytes: , - max_bytes: , - contains_string: , - marked: -}; diff --git a/frontend/src/components/filters/StringConnectionsFilter.js b/frontend/src/components/filters/StringConnectionsFilter.js index c833220..18b3784 100644 --- a/frontend/src/components/filters/StringConnectionsFilter.js +++ b/frontend/src/components/filters/StringConnectionsFilter.js @@ -127,7 +127,7 @@ class StringConnectionsFilter extends Component {
+ value={this.state.fieldValue} inline={this.props.inline} small={this.props.small}/>
); } diff --git a/frontend/src/components/panels/ConnectionsPane.js b/frontend/src/components/panels/ConnectionsPane.js index 33dd7c1..89859e6 100644 --- a/frontend/src/components/panels/ConnectionsPane.js +++ b/frontend/src/components/panels/ConnectionsPane.js @@ -26,6 +26,7 @@ import log from "../../log"; import ButtonField from "../fields/ButtonField"; import dispatcher from "../../dispatcher"; import {Redirect} from "react-router"; +import {updateParams} from "../../utils"; const classNames = require('classnames'); @@ -67,29 +68,16 @@ class ConnectionsPane extends Component { this.loadConnections(additionalParams, urlParams, true).then(() => log.debug("Connections loaded")); this.connectionsFiltersCallback = payload => { - const params = this.state.urlParams; - const initialParams = params.toString(); - - Object.entries(payload).forEach(([key, value]) => { - if (value == null) { - params.delete(key); - } else if (Array.isArray(value)) { - params.delete(key); - value.forEach(v => params.append(key, v)); - } else { - params.set(key, value); - } - }); - - if (initialParams === params.toString()) { + 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}); + this.setState({urlParams: newParams}); - this.loadConnections({limit: this.queryLimit}, urlParams) + this.loadConnections({limit: this.queryLimit}, newParams) .then(() => log.info("ConnectionsPane reloaded after query string update")); }; dispatcher.register("connections_filters", this.connectionsFiltersCallback); diff --git a/frontend/src/dispatcher.js b/frontend/src/dispatcher.js index fa08d48..881970f 100644 --- a/frontend/src/dispatcher.js +++ b/frontend/src/dispatcher.js @@ -47,7 +47,7 @@ class Dispatcher { }; unregister = (callback) => { - this.listeners = _.without(callback); + _.remove(this.listeners, l => l.callback === callback); }; } diff --git a/frontend/src/index.js b/frontend/src/index.js index ca1273a..4bc2730 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -26,9 +26,9 @@ import notifications from "./notifications"; notifications.createWebsocket(); ReactDOM.render( - - - , + // + , + // , document.getElementById('root') ); diff --git a/frontend/src/utils.js b/frontend/src/utils.js index f333f0d..06414ac 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -146,3 +146,19 @@ export function downloadBlob(blob, fileName) { a.click(); window.URL.revokeObjectURL(url); } + +export function updateParams(urlParams, payload) { + const params = new URLSearchParams(urlParams.toString()); + Object.entries(payload).forEach(([key, value]) => { + if (value == null) { + params.delete(key); + } else if (Array.isArray(value)) { + params.delete(key); + value.forEach(v => params.append(key, v)); + } else { + params.set(key, value); + } + }); + + return params; +} -- cgit v1.2.3-70-g09d2 From 2fb8993008752063fa13f253784e9e92552e339d Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Fri, 16 Oct 2020 11:13:21 +0200 Subject: Refactor js files --- frontend/src/components/Header.js | 18 ++-- frontend/src/components/Notifications.js | 8 +- frontend/src/components/Timeline.js | 30 +++--- frontend/src/components/dialogs/Filters.js | 6 +- frontend/src/components/fields/ButtonField.js | 8 +- frontend/src/components/fields/CheckField.js | 12 +-- frontend/src/components/fields/InputField.js | 20 ++-- frontend/src/components/fields/TagField.js | 12 +-- frontend/src/components/fields/TextField.js | 10 +- .../src/components/fields/extensions/ColorField.js | 17 ++-- .../components/fields/extensions/NumericField.js | 6 +- frontend/src/components/filters/AdvancedFilters.js | 4 +- .../components/filters/BooleanConnectionsFilter.js | 6 +- .../src/components/filters/ExitSearchFilter.js | 4 +- .../components/filters/RulesConnectionsFilter.js | 6 +- .../components/filters/StringConnectionsFilter.js | 20 +--- frontend/src/components/objects/Connection.js | 12 +-- frontend/src/components/objects/LinkPopover.js | 15 +-- frontend/src/components/pages/ConfigurationPage.js | 43 ++++----- frontend/src/components/pages/MainPage.js | 20 ++-- .../src/components/pages/ServiceUnavailablePage.js | 4 +- frontend/src/components/panels/ConnectionsPane.js | 4 +- frontend/src/components/panels/MainPane.js | 12 +-- frontend/src/components/panels/PcapsPane.js | 34 +++---- frontend/src/components/panels/SearchPane.js | 106 +++++++++++---------- frontend/src/components/panels/StreamsPane.js | 18 ++-- frontend/src/dispatcher.js | 2 +- frontend/src/index.js | 20 ++-- frontend/src/notifications.js | 2 +- frontend/src/serviceWorker.js | 12 +-- frontend/src/setupProxy.js | 10 +- frontend/src/setupTests.js | 2 +- frontend/src/utils.js | 20 ++-- 33 files changed, 258 insertions(+), 265 deletions(-) (limited to 'frontend/src/dispatcher.js') diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js index 119958b..ab16dd1 100644 --- a/frontend/src/components/Header.js +++ b/frontend/src/components/Header.js @@ -15,17 +15,17 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; -import Typed from 'typed.js'; -import './Header.scss'; +import React, {Component} from "react"; import {Link, withRouter} from "react-router-dom"; +import Typed from "typed.js"; +import {cleanNumber, validatePort} from "../utils"; import ButtonField from "./fields/ButtonField"; +import AdvancedFilters from "./filters/AdvancedFilters"; +import BooleanConnectionsFilter from "./filters/BooleanConnectionsFilter"; import ExitSearchFilter from "./filters/ExitSearchFilter"; -import {cleanNumber, validatePort} from "../utils"; -import StringConnectionsFilter from "./filters/StringConnectionsFilter"; import RulesConnectionsFilter from "./filters/RulesConnectionsFilter"; -import BooleanConnectionsFilter from "./filters/BooleanConnectionsFilter"; -import AdvancedFilters from "./filters/AdvancedFilters"; +import StringConnectionsFilter from "./filters/StringConnectionsFilter"; +import "./Header.scss"; class Header extends Component { @@ -49,7 +49,7 @@ class Header extends Component {

- { + { this.el = el; }}/> @@ -67,7 +67,7 @@ class Header extends Component { - +

diff --git a/frontend/src/components/Notifications.js b/frontend/src/components/Notifications.js index ad681a2..56a4508 100644 --- a/frontend/src/components/Notifications.js +++ b/frontend/src/components/Notifications.js @@ -15,12 +15,12 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; -import './Notifications.scss'; +import React, {Component} from "react"; import dispatcher from "../dispatcher"; +import "./Notifications.scss"; -const _ = require('lodash'); -const classNames = require('classnames'); +const _ = require("lodash"); +const classNames = require("classnames"); class Notifications extends Component { diff --git a/frontend/src/components/Timeline.js b/frontend/src/components/Timeline.js index 1d88bcb..8d1fd40 100644 --- a/frontend/src/components/Timeline.js +++ b/frontend/src/components/Timeline.js @@ -62,7 +62,7 @@ class Timeline extends Component { this.loadStatistics(this.state.metric).then(() => log.debug("Statistics loaded after mount")); - this.connectionsFiltersCallback = payload => { + this.connectionsFiltersCallback = (payload) => { if ("service_port" in payload && this.state.servicePortFilter !== payload["service_port"]) { this.setState({servicePortFilter: payload["service_port"]}); this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after service port changed")); @@ -74,22 +74,22 @@ class Timeline extends Component { }; dispatcher.register("connections_filters", this.connectionsFiltersCallback); - dispatcher.register("connection_updates", payload => { + dispatcher.register("connection_updates", (payload) => { this.setState({ selection: new TimeRange(payload.from, payload.to), }); this.adjustSelection(); }); - dispatcher.register("notifications", payload => { + dispatcher.register("notifications", (payload) => { if (payload.event === "services.edit" && this.state.metric !== "matched_rules") { - this.loadServices().then(() => log.debug("Statistics reloaded after services updates")); + 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.loadServices().then(() => log.debug("Statistics reloaded after rules updates")); + this.loadStatistics(this.state.metric).then(() => log.debug("Statistics reloaded after rules updates")); } }); - dispatcher.register("pulse_timeline", payload => { + dispatcher.register("pulse_timeline", (payload) => { this.setState({pulseTimeline: true}); setTimeout(() => this.setState({pulseTimeline: false}), payload.duration); }); @@ -107,12 +107,12 @@ class Timeline extends Component { if (metric === "matched_rules") { let rules = await this.loadRules(); if (this.state.matchedRulesFilter.length > 0) { - this.state.matchedRulesFilter.forEach(id => { + this.state.matchedRulesFilter.forEach((id) => { urlParams.append("rules_ids", id); }); columns = this.state.matchedRulesFilter; } else { - columns = rules.map(r => r.id); + columns = rules.map((r) => r.id); } } else { let services = await this.loadServices(); @@ -124,7 +124,7 @@ class Timeline extends Component { } columns = Object.keys(services); - columns.forEach(port => urlParams.append("ports", port)); + columns.forEach((port) => urlParams.append("ports", port)); } const metrics = (await backend.get("/api/statistics?" + urlParams)).json; @@ -133,7 +133,7 @@ class Timeline extends Component { } const zeroFilledMetrics = []; - const toTime = m => new Date(m["range_start"]).getTime(); + const toTime = (m) => new Date(m["range_start"]).getTime(); let i = 0; for (let interval = toTime(metrics[0]) - minutes; interval <= toTime(metrics[metrics.length - 1]) + minutes; interval += minutes) { if (i < metrics.length && interval === toTime(metrics[i])) { @@ -144,7 +144,7 @@ class Timeline extends Component { const m = {}; m["range_start"] = new Date(interval); m[metric] = {}; - columns.forEach(c => m[metric][c] = 0); + columns.forEach((c) => m[metric][c] = 0); zeroFilledMetrics.push(m); } } @@ -152,7 +152,7 @@ class Timeline extends Component { const series = new TimeSeries({ name: "statistics", columns: ["time"].concat(columns), - points: zeroFilledMetrics.map(m => [m["range_start"]].concat(columns.map(c => + points: zeroFilledMetrics.map((m) => [m["range_start"]].concat(columns.map(c => ((metric in m) && (m[metric] != null)) ? (m[metric][c] || 0) : 0 ))) }); @@ -184,11 +184,11 @@ class Timeline extends Component { createStyler = () => { if (this.state.metric === "matched_rules") { - return styler(this.state.rules.map(rule => { + 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 styler(Object.keys(this.state.services).map((port) => { return {key: port, color: this.state.services[port].color, width: 2}; })); } @@ -227,7 +227,7 @@ class Timeline extends Component { }; aggregateSeries = (func) => { - const values = this.state.series.columns().map(c => this.state.series[func](c)); + const values = this.state.series.columns().map((c) => this.state.series[func](c)); return Math[func](...values); }; diff --git a/frontend/src/components/dialogs/Filters.js b/frontend/src/components/dialogs/Filters.js index a35ece2..a2407df 100644 --- a/frontend/src/components/dialogs/Filters.js +++ b/frontend/src/components/dialogs/Filters.js @@ -15,12 +15,12 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; +import React, {Component} from "react"; import {Modal} from "react-bootstrap"; -import ButtonField from "../fields/ButtonField"; -import './Filters.scss'; import {cleanNumber, validateIpAddress, validateMin, validatePort} from "../../utils"; +import ButtonField from "../fields/ButtonField"; import StringConnectionsFilter from "../filters/StringConnectionsFilter"; +import "./Filters.scss"; class Filters extends Component { diff --git a/frontend/src/components/fields/ButtonField.js b/frontend/src/components/fields/ButtonField.js index 850f837..de747a5 100644 --- a/frontend/src/components/fields/ButtonField.js +++ b/frontend/src/components/fields/ButtonField.js @@ -15,11 +15,11 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; -import './ButtonField.scss'; -import './common.scss'; +import React, {Component} from "react"; +import "./ButtonField.scss"; +import "./common.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class ButtonField extends Component { diff --git a/frontend/src/components/fields/CheckField.js b/frontend/src/components/fields/CheckField.js index a0e2706..bfa1c9d 100644 --- a/frontend/src/components/fields/CheckField.js +++ b/frontend/src/components/fields/CheckField.js @@ -15,12 +15,12 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; -import './CheckField.scss'; -import './common.scss'; +import React, {Component} from "react"; import {randomClassName} from "../../utils"; +import "./CheckField.scss"; +import "./common.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class CheckField extends Component { @@ -41,9 +41,9 @@ class CheckField extends Component { }; return ( -
+
- +
diff --git a/frontend/src/components/fields/InputField.js b/frontend/src/components/fields/InputField.js index 80cce3b..823989d 100644 --- a/frontend/src/components/fields/InputField.js +++ b/frontend/src/components/fields/InputField.js @@ -15,12 +15,12 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; -import './InputField.scss'; -import './common.scss'; +import React, {Component} from "react"; import {randomClassName} from "../../utils"; +import "./common.scss"; +import "./InputField.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class InputField extends Component { @@ -59,23 +59,23 @@ class InputField extends Component { } return ( -
- { name && + {name &&
}
- { type === "file" && } + {type === "file" && } + readOnly={this.props.readonly}/>
- { type !== "file" && value !== "" && + {type !== "file" && value !== "" &&
handler(null)}>del
diff --git a/frontend/src/components/fields/TagField.js b/frontend/src/components/fields/TagField.js index 89445b6..9a36da4 100644 --- a/frontend/src/components/fields/TagField.js +++ b/frontend/src/components/fields/TagField.js @@ -15,14 +15,14 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; -import './TagField.scss'; -import './common.scss'; -import {randomClassName} from "../../utils"; +import React, {Component} from "react"; import ReactTags from "react-tag-autocomplete"; +import {randomClassName} from "../../utils"; +import "./common.scss"; +import "./TagField.scss"; -const classNames = require('classnames'); -const _ = require('lodash'); +const classNames = require("classnames"); +const _ = require("lodash"); class TagField extends Component { diff --git a/frontend/src/components/fields/TextField.js b/frontend/src/components/fields/TextField.js index 9237c0c..4dd77bd 100644 --- a/frontend/src/components/fields/TextField.js +++ b/frontend/src/components/fields/TextField.js @@ -15,12 +15,12 @@ * along with this program. If not, see . */ -import React, {Component} from 'react'; -import './TextField.scss'; -import './common.scss'; +import React, {Component} from "react"; import {randomClassName} from "../../utils"; +import "./common.scss"; +import "./TextField.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class TextField extends Component { @@ -50,7 +50,7 @@ class TextField extends Component { {"field-invalid": this.props.invalid}, {"field-small": this.props.small})}> {name && }