mirror of
https://github.com/evilsocket/opensnitch.git
synced 2025-03-04 08:34:40 +01:00
ui,stats: added more options to handle rules in batch
- allow to change duration and action to multiple rules at once. closes #393 - fixed updating a rule on the db (per node). - fixed typo. #334
This commit is contained in:
parent
c7411a4770
commit
2c1c3b0251
2 changed files with 102 additions and 40 deletions
|
@ -17,6 +17,10 @@ class Config:
|
|||
DURATION_UNTIL_RESTART = "until restart"
|
||||
DURATION_ALWAYS = "always"
|
||||
DURATION_ONCE = "once"
|
||||
DURATION_1h = "1h"
|
||||
DURATION_30m = "30m"
|
||||
DURATION_15m = "15m"
|
||||
DURATION_5m = "5m"
|
||||
|
||||
DEFAULT_TIMEOUT_KEY = "global/default_timeout"
|
||||
DEFAULT_ACTION_KEY = "global/default_action"
|
||||
|
|
|
@ -5,6 +5,7 @@ import os
|
|||
import csv
|
||||
|
||||
from PyQt5 import QtCore, QtGui, uic, QtWidgets
|
||||
from PyQt5.QtCore import QCoreApplication as QC
|
||||
|
||||
import ui_pb2
|
||||
from config import Config
|
||||
|
@ -240,25 +241,24 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
self.setWindowFlags(QtCore.Qt.Window)
|
||||
self.setupUi(self)
|
||||
|
||||
|
||||
# columns names
|
||||
self.COL_STR_NAME = QtCore.QCoreApplication.translate("stats", "Name")
|
||||
self.COL_STR_ADDR = QtCore.QCoreApplication.translate("stats", "Address")
|
||||
self.COL_STR_STATUS = QtCore.QCoreApplication.translate("stats", "Status")
|
||||
self.COL_STR_HOSTNAME = QtCore.QCoreApplication.translate("stats", "Hostname")
|
||||
self.COL_STR_VERSION = QtCore.QCoreApplication.translate("stats", "Version")
|
||||
self.COL_STR_RULES_NUM = QtCore.QCoreApplication.translate("stats", "Rules")
|
||||
self.COL_STR_TIME = QtCore.QCoreApplication.translate("stats", "Time")
|
||||
self.COL_STR_ACTION = QtCore.QCoreApplication.translate("stats", "Action")
|
||||
self.COL_STR_DURATION = QtCore.QCoreApplication.translate("stats", "Duration")
|
||||
self.COL_STR_NODE = QtCore.QCoreApplication.translate("stats", "Node")
|
||||
self.COL_STR_ENABLED = QtCore.QCoreApplication.translate("stats", "Enabled")
|
||||
self.COL_STR_HITS = QtCore.QCoreApplication.translate("stats", "Hits")
|
||||
self.COL_STR_PROTOCOL = QtCore.QCoreApplication.translate("stats", "Protocol")
|
||||
self.COL_STR_NAME = QC.translate("stats", "Name")
|
||||
self.COL_STR_ADDR = QC.translate("stats", "Address")
|
||||
self.COL_STR_STATUS = QC.translate("stats", "Status")
|
||||
self.COL_STR_HOSTNAME = QC.translate("stats", "Hostname")
|
||||
self.COL_STR_VERSION = QC.translate("stats", "Version")
|
||||
self.COL_STR_RULES_NUM = QC.translate("stats", "Rules")
|
||||
self.COL_STR_TIME = QC.translate("stats", "Time")
|
||||
self.COL_STR_ACTION = QC.translate("stats", "Action")
|
||||
self.COL_STR_DURATION = QC.translate("stats", "Duration")
|
||||
self.COL_STR_NODE = QC.translate("stats", "Node")
|
||||
self.COL_STR_ENABLED = QC.translate("stats", "Enabled")
|
||||
self.COL_STR_HITS = QC.translate("stats", "Hits")
|
||||
self.COL_STR_PROTOCOL = QC.translate("stats", "Protocol")
|
||||
|
||||
self.FIREWALL_STOPPED = QtCore.QCoreApplication.translate("stats", "Not running")
|
||||
self.FIREWALL_DISABLED = QtCore.QCoreApplication.translate("stats", "Disabled")
|
||||
self.FIREWALL_RUNNING = QtCore.QCoreApplication.translate("stats", "Running")
|
||||
self.FIREWALL_STOPPED = QC.translate("stats", "Not running")
|
||||
self.FIREWALL_DISABLED = QC.translate("stats", "Disabled")
|
||||
self.FIREWALL_RUNNING = QC.translate("stats", "Running")
|
||||
|
||||
self._db = db
|
||||
self._db_sqlite = self._db.get_db()
|
||||
|
@ -437,9 +437,9 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
def showEvent(self, event):
|
||||
super(StatsDialog, self).showEvent(event)
|
||||
self._shown_trigger.emit()
|
||||
window_title = QtCore.QCoreApplication.translate("stats", "OpenSnitch Network Statistics {0}").format(version)
|
||||
window_title = QC.translate("stats", "OpenSnitch Network Statistics {0}").format(version)
|
||||
if self._address is not None:
|
||||
window_title = QtCore.QCoreApplication.translate("stats", "OpenSnitch Network Statistics for {0}").format(self._address)
|
||||
window_title = QC.translate("stats", "OpenSnitch Network Statistics for {0}").format(self._address)
|
||||
self.nodeLabel.setText(self._address)
|
||||
self._load_settings()
|
||||
self._add_rulesTree_nodes()
|
||||
|
@ -581,7 +581,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
if reply.id in self._notifications_sent:
|
||||
if reply.code == ui_pb2.ERROR:
|
||||
Message.ok(
|
||||
QtCore.QCoreApplication.translate("stats", "<b>Error:</b><br><br>{0}").format(reply.data),
|
||||
QC.translate("stats", "<b>Error:</b><br><br>{0}").format(reply.data),
|
||||
"",
|
||||
QtWidgets.QMessageBox.Warning)
|
||||
|
||||
|
@ -606,23 +606,42 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
# the only table with context menu for now is the rules table
|
||||
return
|
||||
|
||||
self._context_menu_active = True
|
||||
self._configure_rules_contextual_menu(pos)
|
||||
self._context_menu_active = False
|
||||
|
||||
def _configure_rules_contextual_menu(self, pos):
|
||||
cur_idx = self.tabWidget.currentIndex()
|
||||
table = self._get_active_table()
|
||||
model = table.model()
|
||||
self._context_menu_active = True
|
||||
|
||||
selection = table.selectionModel().selectedRows()
|
||||
if selection:
|
||||
menu = QtWidgets.QMenu()
|
||||
durMenu = QtWidgets.QMenu(self.COL_STR_DURATION)
|
||||
actionMenu = QtWidgets.QMenu(self.COL_STR_ACTION)
|
||||
|
||||
_actAllow = actionMenu.addAction(QC.translate("stats", "Allow"))
|
||||
_actDeny = actionMenu.addAction(QC.translate("stats", "Deny"))
|
||||
menu.addMenu(actionMenu)
|
||||
|
||||
_durAlways = durMenu.addAction(QC.translate("stats", "Always"))
|
||||
_durUntilReboot = durMenu.addAction(QC.translate("stats", "Until reboot"))
|
||||
_dur1h = durMenu.addAction(Config.DURATION_1h)
|
||||
_dur30m = durMenu.addAction(Config.DURATION_30m)
|
||||
_dur15m = durMenu.addAction(Config.DURATION_15m)
|
||||
_dur5m = durMenu.addAction(Config.DURATION_5m)
|
||||
menu.addMenu(durMenu)
|
||||
|
||||
is_rule_enabled = model.index(selection[0].row(), self.COL_R_ENABLED).data()
|
||||
menu_label_enable = QtCore.QCoreApplication.translate("stats", "Disable")
|
||||
menu_label_enable = QC.translate("stats", "Disable")
|
||||
if is_rule_enabled == "False":
|
||||
menu_label_enable = QtCore.QCoreApplication.translate("stats", "Enable")
|
||||
menu_label_enable = QC.translate("stats", "Enable")
|
||||
|
||||
_menu_enable = menu.addAction(QtCore.QCoreApplication.translate("stats", menu_label_enable))
|
||||
_menu_duplicate = menu.addAction(QtCore.QCoreApplication.translate("stats", "Duplicate"))
|
||||
_menu_edit = menu.addAction(QtCore.QCoreApplication.translate("stats", "Edit"))
|
||||
_menu_delete = menu.addAction(QtCore.QCoreApplication.translate("stats", "Delete"))
|
||||
_menu_enable = menu.addAction(QC.translate("stats", menu_label_enable))
|
||||
_menu_duplicate = menu.addAction(QC.translate("stats", "Duplicate"))
|
||||
_menu_edit = menu.addAction(QC.translate("stats", "Edit"))
|
||||
_menu_delete = menu.addAction(QC.translate("stats", "Delete"))
|
||||
|
||||
# move away menu a few pixels to the right, to avoid clicking on it by mistake
|
||||
point = QtCore.QPoint(pos.x()+10, pos.y()+5)
|
||||
|
@ -631,8 +650,8 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
model = table.model()
|
||||
if action == _menu_delete:
|
||||
ret = Message.yes_no(
|
||||
QtCore.QCoreApplication.translate("stats", " Your are about to delete this rule. "),
|
||||
QtCore.QCoreApplication.translate("stats", " Are you sure?"),
|
||||
QC.translate("stats", " Your are about to delete this rule. "),
|
||||
QC.translate("stats", " Are you sure?"),
|
||||
QtWidgets.QMessageBox.Warning)
|
||||
if ret == QtWidgets.QMessageBox.Cancel:
|
||||
return
|
||||
|
@ -643,8 +662,23 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
self._table_menu_enable(cur_idx, model, selection, is_rule_enabled)
|
||||
elif action == _menu_duplicate:
|
||||
self._table_menu_duplicate(cur_idx, model, selection)
|
||||
elif action == _durAlways:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "duration", Config.DURATION_ALWAYS)
|
||||
elif action == _dur1h:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "duration", Config.DURATION_1h)
|
||||
elif action == _dur30m:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "duration", Config.DURATION_30m)
|
||||
elif action == _dur15m:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "duration", Config.DURATION_15m)
|
||||
elif action == _dur5m:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "duration", Config.DURATION_5m)
|
||||
elif action == _durUntilReboot:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "duration", Config.DURATION_UNTIL_RESTART)
|
||||
elif action == _actAllow:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "action", Config.ACTION_ALLOW)
|
||||
elif action == _actDeny:
|
||||
self._table_menu_change_rule_field(cur_idx, model, selection, "action", Config.ACTION_DENY)
|
||||
|
||||
self._context_menu_active = False
|
||||
self._refresh_active_table()
|
||||
|
||||
def _table_menu_duplicate(self, cur_idx, model, selection):
|
||||
|
@ -674,6 +708,29 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
nid = self._nodes.send_notification(node_addr, noti, self._notification_callback)
|
||||
self._notifications_sent[nid] = noti
|
||||
|
||||
def _table_menu_change_rule_field(self, cur_idx, model, selection, field, value):
|
||||
for idx in selection:
|
||||
rule_name = model.index(idx.row(), self.COL_R_NAME).data()
|
||||
node_addr = model.index(idx.row(), self.COL_R_NODE).data()
|
||||
|
||||
records = self._get_rule(rule_name, node_addr)
|
||||
rule = self._rules_dialog.get_rule_from_records(records)
|
||||
|
||||
self._db.update(table="rules", fields="{0}=?".format(field),
|
||||
values=[value], condition="name='{0}' AND node='{1}'".format(rule_name, node_addr),
|
||||
action_on_conflict="")
|
||||
|
||||
if field == "action":
|
||||
rule.action = value
|
||||
elif field == "duration":
|
||||
rule.duration = value
|
||||
elif field == "precedence":
|
||||
rule.precedence = value
|
||||
|
||||
noti = ui_pb2.Notification(type=ui_pb2.CHANGE_RULE, rules=[rule])
|
||||
nid = self._nodes.send_notification(node_addr, noti, self._notification_callback)
|
||||
self._notifications_sent[nid] = noti
|
||||
|
||||
def _table_menu_enable(self, cur_idx, model, selection, is_rule_enabled):
|
||||
rule_status = "False" if is_rule_enabled == "True" else "True"
|
||||
|
||||
|
@ -686,7 +743,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
rule_type = ui_pb2.DISABLE_RULE if is_rule_enabled == "True" else ui_pb2.ENABLE_RULE
|
||||
|
||||
self._db.update(table="rules", fields="enabled=?",
|
||||
values=[rule_status], condition="name='{0}'".format(rule_name),
|
||||
values=[rule_status], condition="name='{0}' AND node='{1}'".format(rule_name, node_addr),
|
||||
action_on_conflict="")
|
||||
|
||||
noti = ui_pb2.Notification(type=rule_type, rules=[rule])
|
||||
|
@ -708,7 +765,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
records = self._get_rule(name, node)
|
||||
if records == None or records == -1:
|
||||
Message.ok("Rule error",
|
||||
QtCore.QCoreApplication.translate("stats", "Rule not found by that name and node"),
|
||||
QC.translate("stats", "Rule not found by that name and node"),
|
||||
QtWidgets.QMessageBox.Warning)
|
||||
return
|
||||
self._rules_dialog.edit_rule(records, name)
|
||||
|
@ -880,8 +937,8 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
|
||||
def _cb_del_rule_clicked(self):
|
||||
ret = Message.yes_no(
|
||||
QtCore.QCoreApplication.translate("stats", " Your are about to delete this rule. "),
|
||||
QtCore.QCoreApplication.translate("stats", " Are you sure?"),
|
||||
QC.translate("stats", " You are about to delete this rule. "),
|
||||
QC.translate("stats", " Are you sure?"),
|
||||
QtWidgets.QMessageBox.Warning)
|
||||
if ret == QtWidgets.QMessageBox.Cancel:
|
||||
return
|
||||
|
@ -1271,7 +1328,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
tab_idx = self.tabWidget.currentIndex()
|
||||
|
||||
filename = QtWidgets.QFileDialog.getSaveFileName(self,
|
||||
QtCore.QCoreApplication.translate("stats", 'Save as CSV'),
|
||||
QC.translate("stats", 'Save as CSV'),
|
||||
self._file_names[tab_idx],
|
||||
'All Files (*);;CSV Files (*.csv)')[0].strip()
|
||||
if filename == '':
|
||||
|
@ -1380,12 +1437,13 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
|
|||
super(StatsDialog, self).keyPressEvent(event)
|
||||
|
||||
def setQuery(self, model, q):
|
||||
if self._context_menu_active == True:
|
||||
return
|
||||
with self._lock:
|
||||
try:
|
||||
if self._context_menu_active == False:
|
||||
model.query().clear()
|
||||
model.setQuery(q, self._db_sqlite)
|
||||
if model.lastError().isValid():
|
||||
print("setQuery() error: ", model.lastError().text())
|
||||
model.query().clear()
|
||||
model.setQuery(q, self._db_sqlite)
|
||||
if model.lastError().isValid():
|
||||
print("setQuery() error: ", model.lastError().text())
|
||||
except Exception as e:
|
||||
print(self._address, "setQuery() exception: ", e)
|
||||
|
|
Loading…
Add table
Reference in a new issue