ui, rules: added description field

- Added ability to add a description to the rules.
- Display the description field on the Rules view, and remove the internal
  fields (operator, operator_data, etc).
- Added DB migrations.
- Improved rules' executable path field tooltip (#661).

Closes #652 #466
This commit is contained in:
Gustavo Iñiguez Goia 2022-05-12 13:38:23 +02:00
parent db4646dec8
commit 3c524c1942
10 changed files with 442 additions and 309 deletions

View file

@ -33,26 +33,28 @@ const (
// The fields match the ones saved as json to disk.
// If a .json rule file is modified on disk, it's reloaded automatically.
type Rule struct {
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Precedence bool `json:"precedence"`
Action Action `json:"action"`
Duration Duration `json:"duration"`
Operator Operator `json:"operator"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Name string `json:"name"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
Precedence bool `json:"precedence"`
Action Action `json:"action"`
Duration Duration `json:"duration"`
Operator Operator `json:"operator"`
}
// Create creates a new rule object with the specified parameters.
func Create(name string, enabled bool, precedence bool, action Action, duration Duration, op *Operator) *Rule {
func Create(name, description string, enabled bool, precedence bool, action Action, duration Duration, op *Operator) *Rule {
return &Rule{
Created: time.Now(),
Enabled: enabled,
Precedence: precedence,
Name: name,
Action: action,
Duration: duration,
Operator: *op,
Created: time.Now(),
Enabled: enabled,
Precedence: precedence,
Name: name,
Description: description,
Action: action,
Duration: duration,
Operator: *op,
}
}
@ -86,6 +88,7 @@ func Deserialize(reply *protocol.Rule) (*Rule, error) {
return Create(
reply.Name,
reply.Description,
reply.Enabled,
reply.Precedence,
Action(reply.Action),
@ -100,11 +103,12 @@ func (r *Rule) Serialize() *protocol.Rule {
return nil
}
return &protocol.Rule{
Name: string(r.Name),
Enabled: bool(r.Enabled),
Precedence: bool(r.Precedence),
Action: string(r.Action),
Duration: string(r.Duration),
Name: string(r.Name),
Description: string(r.Description),
Enabled: bool(r.Enabled),
Precedence: bool(r.Precedence),
Action: string(r.Action),
Duration: string(r.Duration),
Operator: &protocol.Operator{
Type: string(r.Operator.Type),
Sensitive: bool(r.Operator.Sensitive),

View file

@ -23,10 +23,10 @@ import (
var (
configFile = "/etc/opensnitchd/default-config.json"
dummyOperator, _ = rule.NewOperator(rule.Simple, false, rule.OpTrue, "", make([]rule.Operator, 0))
clientDisconnectedRule = rule.Create("ui.client.disconnected", true, false, rule.Allow, rule.Once, dummyOperator)
clientDisconnectedRule = rule.Create("ui.client.disconnected", "", true, false, rule.Allow, rule.Once, dummyOperator)
// While the GUI is connected, deny by default everything until the user takes an action.
clientConnectedRule = rule.Create("ui.client.connected", true, false, rule.Deny, rule.Once, dummyOperator)
clientErrorRule = rule.Create("ui.client.error", true, false, rule.Allow, rule.Once, dummyOperator)
clientConnectedRule = rule.Create("ui.client.connected", "", true, false, rule.Deny, rule.Once, dummyOperator)
clientErrorRule = rule.Create("ui.client.error", "", true, false, rule.Allow, rule.Once, dummyOperator)
config Config
)

View file

@ -71,11 +71,12 @@ message Operator {
message Rule {
string name = 1;
bool enabled = 2;
bool precedence = 3;
string action = 4;
string duration = 5;
Operator operator = 6;
string description = 2;
bool enabled = 3;
bool precedence = 4;
string action = 5;
string duration = 6;
Operator operator = 7;
}
enum Action {

View file

@ -1,6 +1,7 @@
from PyQt5.QtSql import QSqlDatabase, QSqlQueryModel, QSqlQuery
import threading
import sys
import os
from datetime import datetime, timedelta
class Database:
@ -10,6 +11,8 @@ class Database:
DB_TYPE_MEMORY = 0
DB_TYPE_FILE = 1
DB_VERSION = 1
@staticmethod
def instance():
if Database.__instance == None:
@ -26,6 +29,8 @@ class Database:
if dbtype != Database.DB_TYPE_MEMORY:
self.db_file = dbfile
is_new_file = not os.path.isfile(self.db_file)
self.db = QSqlDatabase.addDatabase("QSQLITE", self.db_name)
self.db.setDatabaseName(self.db_file)
if not self.db.open():
@ -38,7 +43,13 @@ class Database:
print("db.initialize() error:", db_error)
return False, db_error
if is_new_file:
print("is new file, or IN MEMORY, setting initial schema version")
self.set_schema_version(self.DB_VERSION)
self._create_tables()
self._upgrade_db_schema()
return True, None
def close(self):
@ -77,6 +88,7 @@ class Database:
def _create_tables(self):
# https://www.sqlite.org/wal.html
if self.db_file == Database.DB_IN_MEMORY:
self.set_schema_version(self.DB_VERSION)
q = QSqlQuery("PRAGMA journal_mode = OFF", self.db)
q.exec_()
q = QSqlQuery("PRAGMA synchronous = OFF", self.db)
@ -137,6 +149,7 @@ class Database:
"operator_sensitive text, " \
"operator_operand text, " \
"operator_data text, " \
"description text, " \
"UNIQUE(node, name)"
")", self.db)
q.exec_()
@ -168,6 +181,49 @@ class Database:
, self.db)
q.exec_()
def get_schema_version(self):
q = QSqlQuery("PRAGMA user_version;", self.db)
q.exec_()
if q.next():
print("schema version:", q.value(0))
return int(q.value(0))
return 0
def set_schema_version(self, version):
print("setting schema version to:", version)
q = QSqlQuery("PRAGMA user_version = {0}".format(version), self.db)
q.exec_()
def _upgrade_db_schema(self):
migrations_path = os.path.dirname(os.path.realpath(__file__)) + "/migrations"
schema_version = self.get_schema_version()
if schema_version == self.DB_VERSION:
print("db schema is up to date")
return
while schema_version < self.DB_VERSION:
schema_version += 1
try:
print("applying schema upgrade:", schema_version)
self._apply_db_upgrade("{0}/upgrade_{1}.sql".format(migrations_path, schema_version))
except Exception:
print("Not applyging upgrade_{0}.sql".format(schema_version))
self.set_schema_version(schema_version)
def _apply_db_upgrade(self, file):
print("applying upgrade from:", file)
q = QSqlQuery(self.db)
with open(file) as f:
for line in f.readlines():
# skip comments
if line.startswith("--"):
continue
print("applying upgrade:", line, end="")
if q.exec(line) == False:
print("\tError:", q.lastError().text())
else:
print("\tOK")
def optimize(self):
"""https://www.sqlite.org/pragma.html#pragma_optimize
"""
@ -430,9 +486,9 @@ class Database:
def insert_rule(self, rule, node_addr):
self.insert("rules",
"(time, node, name, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
"(time, node, name, description, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
node_addr, rule.name,
node_addr, rule.name, rule.description,
str(rule.enabled), str(rule.precedence),
rule.action, rule.duration, rule.operator.type,
str(rule.operator.sensitive), rule.operator.operand, rule.operator.data),

View file

@ -0,0 +1,2 @@
--ALTER TABLE rules ADD COLUMN description;
create table x(id int);

View file

@ -269,6 +269,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
rule.operator.sensitive = self._bool(records.value(8))
rule.operator.operand = records.value(9)
rule.operator.data = "" if records.value(10) == None else str(records.value(10))
rule.description = records.value(11)
return rule
@ -277,6 +278,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.rule = None
self.ruleNameEdit.setText("")
self.ruleDescEdit.setPlainText("")
self.statusLabel.setText("")
self.actionDenyRadio.setChecked(True)
@ -327,6 +329,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
return False
self.ruleNameEdit.setText(rule.name)
self.ruleDescEdit.setPlainText(rule.description)
self.enableCheck.setChecked(rule.enabled)
self.precedenceCheck.setChecked(rule.precedence)
if rule.action == Config.ACTION_DENY:
@ -449,9 +452,9 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def _insert_rule_to_db(self, node_addr):
self._db.insert("rules",
"(time, node, name, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
"(time, node, name, description, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
node_addr, self.rule.name,
node_addr, self.rule.name, self.rule.description,
str(self.rule.enabled), str(self.rule.precedence),
self.rule.action, self.rule.duration, self.rule.operator.type,
str(self.rule.operator.sensitive), self.rule.operator.operand, self.rule.operator.data),
@ -509,6 +512,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
"""
self.rule = ui_pb2.Rule()
self.rule.name = self.ruleNameEdit.text()
self.rule.description = self.ruleDescEdit.toPlainText()
self.rule.enabled = self.enableCheck.isChecked()
self.rule.precedence = self.precedenceCheck.isChecked()
self.rule.operator.type = Config.RULE_TYPE_SIMPLE

View file

@ -200,7 +200,13 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
"filterLine": None,
"model": None,
"delegate": commonDelegateConf,
"display_fields": "*",
"display_fields": "time as Time," \
"node as Node," \
"name as Name," \
"enabled as Enabled," \
"action as Action," \
"duration as Duration," \
"description as Description",
"header_labels": [],
"last_order_by": "2",
"last_order_to": 0,
@ -336,6 +342,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.COL_STR_TIME = QC.translate("stats", "Time", "This is a word, without spaces and symbols.")
self.COL_STR_ACTION = QC.translate("stats", "Action", "This is a word, without spaces and symbols.")
self.COL_STR_DURATION = QC.translate("stats", "Duration", "This is a word, without spaces and symbols.")
self.COL_STR_DESCRIPTION = QC.translate("stats", "Description", "This is a word, without spaces and symbols.")
self.COL_STR_NODE = QC.translate("stats", "Node", "This is a word, without spaces and symbols.")
self.COL_STR_ENABLED = QC.translate("stats", "Enabled", "This is a word, without spaces and symbols.")
self.COL_STR_PRECEDENCE = QC.translate("stats", "Precedence", "This is a word, without spaces and symbols.")
@ -447,13 +454,9 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.COL_STR_NODE,
self.COL_STR_NAME,
self.COL_STR_ENABLED,
self.COL_STR_PRECEDENCE,
self.COL_STR_ACTION,
self.COL_STR_DURATION,
"operator_type",
"operator_sensitive",
"operator_operand",
"operator_data",
self.COL_STR_DESCRIPTION,
]
stats_headers = [
@ -492,8 +495,8 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
verticalScrollBar=self.verticalScrollBar,
sort_direction=self.SORT_ORDER[1],
delegate=self.TABLES[self.TAB_NODES]['delegate'])
self.TABLES[self.TAB_RULES]['view'] = self._setup_table(QtWidgets.QTableView,
self.rulesTable, "rules",
self.TABLES[self.TAB_RULES]['view'] = self._setup_table(QtWidgets.QTableView, self.rulesTable, "rules",
fields=self.TABLES[self.TAB_RULES]['display_fields'],
model=GenericTableModel("rules", self.TABLES[self.TAB_RULES]['header_labels']),
verticalScrollBar=self.rulesScrollBar,
delegate=self.TABLES[self.TAB_RULES]['delegate'],
@ -688,6 +691,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def _configure_buttons_icons(self):
self.iconStart = self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_MediaPlay"))
self.iconPause = self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_MediaPause"))
fwIcon = self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_VistaShield"))
self.newRuleButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_FileIcon")))
self.delRuleButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_TrashIcon")))
@ -695,6 +699,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.saveButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_DialogSaveButton")))
self.prefsButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_FileDialogDetailedView")))
self.startButton.setIcon(self.iconStart)
self.fwButton.setIcon(fwIcon)
self.cmdProcDetails.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_FileDialogContentsView")))
self.TABLES[self.TAB_MAIN]['cmdCleanStats'].setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_DialogResetButton")))
for idx in range(1,8):
@ -1869,7 +1874,12 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
what = what + " AND"
what = what + " r.name LIKE '%{0}%'".format(filter_text)
model = self._get_active_table().model()
self.setQuery(model, "SELECT * FROM rules as r %s %s %s" % (what, self._get_order(), self._get_limit()))
self.setQuery(model, "SELECT {0} FROM rules as r {1} {2} {3}".format(
self.TABLES[self.TAB_RULES]['display_fields'],
what,
self._get_order(),
self._get_limit()
))
self._restore_details_view_columns(
self.TABLES[self.TAB_RULES]['view'].horizontalHeader(),
"{0}{1}".format(Config.STATS_VIEW_COL_STATE, self.TAB_RULES)

View file

@ -70,27 +70,27 @@ class Nodes(QObject):
def add_fw_rules(self, addr, fwconfig):
self._nodes[addr]['fwrules'] = fwconfig
def add_rule(self, time, node, name, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data):
def add_rule(self, time, node, name, description, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data):
# don't add rule if the user has selected to exclude temporary
# rules
if duration in Config.RULES_DURATION_FILTER:
return
self._db.insert("rules",
"(time, node, name, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
(time, node, name, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data),
"(time, node, name, description, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
(time, node, name, description, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data),
action_on_conflict="REPLACE")
def add_rules(self, addr, rules):
try:
for _,r in enumerate(rules):
self.add_rule(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
addr,
r.name, str(r.enabled), str(r.precedence), r.action, r.duration,
r.operator.type,
str(r.operator.sensitive),
r.operator.operand,
r.operator.data)
addr,
r.name, r.description, str(r.enabled),
str(r.precedence), r.action, r.duration,
r.operator.type,
str(r.operator.sensitive),
r.operator.operand, r.operator.data)
except Exception as e:
print(self.LOG_TAG + " exception adding node to db: ", e)

View file

@ -6,39 +6,202 @@
<rect>
<x>0</x>
<y>0</y>
<width>540</width>
<height>490</height>
<width>552</width>
<height>528</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Rule</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="enableCheck">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
<item row="5" column="1">
<widget class="QGroupBox" name="enableGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<property name="verticalSpacing">
<number>12</number>
</property>
<item row="3" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Action</string>
</property>
</widget>
</item>
<item row="4" column="4">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="4">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Duration</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QComboBox" name="durationCombo">
<item>
<property name="text">
<string>once</string>
</property>
</item>
<item>
<property name="text">
<string>30s</string>
</property>
</item>
<item>
<property name="text">
<string>5m</string>
</property>
</item>
<item>
<property name="text">
<string>15m</string>
</property>
</item>
<item>
<property name="text">
<string>30m</string>
</property>
</item>
<item>
<property name="text">
<string>1h</string>
</property>
</item>
<item>
<property name="text">
<string>until reboot</string>
</property>
</item>
<item>
<property name="text">
<string>always</string>
</property>
</item>
</widget>
</item>
<item row="3" column="6">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="actionDenyRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Deny will just discard the connection</string>
</property>
<property name="text">
<string>Deny</string>
</property>
<property name="icon">
<iconset theme="emblem-important">
<normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</iconset>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="actionRejectRadio">
<property name="toolTip">
<string>Reject will drop the connection, and kill the socket that initiated it</string>
</property>
<property name="text">
<string>Reject</string>
</property>
<property name="icon">
<iconset theme="window-close">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="actionAllowRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Allow will allow the connection</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Allow</string>
</property>
<property name="icon">
<iconset theme="emblem-default">
<normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QCheckBox" name="precedenceCheck">
@ -80,7 +243,63 @@ You must name the rule in such manner that it'll be checked first, because they'
</item>
</layout>
</item>
<item row="8" column="1">
<item row="1" column="1">
<widget class="QPlainTextEdit" name="ruleDescEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>60</height>
</size>
</property>
<property name="placeholderText">
<string>Description...</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="enableCheck">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="9" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_6">
@ -110,7 +329,53 @@ You must name the rule in such manner that it'll be checked first, because they'
</item>
</layout>
</item>
<item row="1" column="1">
<item row="7" column="1">
<widget class="QLabel" name="statusLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="ruleNameEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>The rules are checked in alphabetical order, so you can name them accordingly to prioritize them.
000-allow-localhost
001-deny-broadcast
...</string>
</property>
<property name="placeholderText">
<string>leave blank to autocreate</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
@ -144,7 +409,7 @@ You must name the rule in such manner that it'll be checked first, because they'
</item>
</layout>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
@ -155,9 +420,10 @@ You must name the rule in such manner that it'll be checked first, because they'
<property name="documentMode">
<bool>true</bool>
</property>
<widget class="QWidget" name="tabWidgetPage1" native="true">
<widget class="QWidget" name="tabWidgetPage1">
<attribute name="icon">
<iconset theme="system-run"/>
<iconset theme="system-run">
<normaloff>.</normaloff>.</iconset>
</attribute>
<attribute name="title">
<string>Applications</string>
@ -213,7 +479,7 @@ You must name the rule in such manner that it'll be checked first, because they'
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This field will only match the executable path. It is not modifiable by the user.&lt;br/&gt;&lt;/p&gt;&lt;p&gt;You can use regular expressions to deny executions from /tmp for example:&lt;br/&gt;&lt;/p&gt;&lt;p&gt;^/tmp/.*$&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The value of this field is always the absolute path to the executable: /path/to/binary&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Examples:&lt;/p&gt;&lt;p&gt;- Simple: /path/to/binary&lt;/p&gt;&lt;p&gt;- Multiple paths: ^/usr/lib(64|)/firefox/firefox$&lt;/p&gt;&lt;p&gt;- Multiple binaries: ^(/usr/sbin/ntpd|/lib/systemd/systemd-timesyncd|/usr/bin/xbrlapi|/usr/bin/dirmngr)$ &lt;/p&gt;&lt;p&gt;- Deny/Allow executions from /tmp:&lt;/p&gt;&lt;p&gt;^/(var/|)tmp/.*$&lt;br/&gt;&lt;/p&gt;&lt;p&gt;For more examples visit the &lt;a href=&quot;https://github.com/evilsocket/opensnitch/wiki/Rules-examples&quot;&gt;wiki page&lt;/a&gt; or ask on the &lt;a href=&quot;https://github.com/evilsocket/opensnitch/discussions&quot;&gt;Discussion forums&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="placeholderText">
<string notr="true">/path/to/executable, .*/bin/executable[0-9\.]+$, ...</string>
@ -279,9 +545,10 @@ You must name the rule in such manner that it'll be checked first, because they'
</item>
</layout>
</widget>
<widget class="QWidget" name="tabWidgetPage2" native="true">
<widget class="QWidget" name="tabWidgetPage2">
<attribute name="icon">
<iconset theme="preferences-system-network"/>
<iconset theme="preferences-system-network">
<normaloff>.</normaloff>.</iconset>
</attribute>
<attribute name="title">
<string>Network</string>
@ -528,9 +795,10 @@ Note: Commas or spaces are not allowed to separate IPs or networks.</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabWidgetPage3" native="true">
<widget class="QWidget" name="tabWidgetPage3">
<attribute name="icon">
<iconset theme="document-properties"/>
<iconset theme="document-properties">
<normaloff>.</normaloff>.</iconset>
</attribute>
<attribute name="title">
<string>List of domains/IPs</string>
@ -561,7 +829,8 @@ Note: Commas or spaces are not allowed to separate IPs or networks.</string>
<string/>
</property>
<property name="icon">
<iconset theme="system-search"/>
<iconset theme="system-search">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -595,7 +864,8 @@ Note: Commas or spaces are not allowed to separate IPs or networks.</string>
<string/>
</property>
<property name="icon">
<iconset theme="system-search"/>
<iconset theme="system-search">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -664,7 +934,8 @@ Note: Commas or spaces are not allowed to separate IPs or networks.</string>
<string/>
</property>
<property name="icon">
<iconset theme="system-search"/>
<iconset theme="system-search">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
@ -684,222 +955,6 @@ Note: Commas or spaces are not allowed to separate IPs or networks.</string>
</widget>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="statusLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="ruleNameEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>The rules are checked in alphabetical order, so you can name them accordingly to prioritize them.
000-allow-localhost
001-deny-broadcast
...</string>
</property>
<property name="placeholderText">
<string>leave blank to autocreate</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QGroupBox" name="enableGroup">
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<property name="verticalSpacing">
<number>12</number>
</property>
<item row="3" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Action</string>
</property>
</widget>
</item>
<item row="4" column="4">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="4">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Duration</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QComboBox" name="durationCombo">
<item>
<property name="text">
<string>once</string>
</property>
</item>
<item>
<property name="text">
<string>30s</string>
</property>
</item>
<item>
<property name="text">
<string>5m</string>
</property>
</item>
<item>
<property name="text">
<string>15m</string>
</property>
</item>
<item>
<property name="text">
<string>30m</string>
</property>
</item>
<item>
<property name="text">
<string>1h</string>
</property>
</item>
<item>
<property name="text">
<string>until reboot</string>
</property>
</item>
<item>
<property name="text">
<string>always</string>
</property>
</item>
</widget>
</item>
<item row="3" column="6">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="actionDenyRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Deny</string>
</property>
<property name="icon">
<iconset theme="emblem-important">
<normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</iconset>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="actionRejectRadio">
<property name="text">
<string>Reject</string>
</property>
<property name="icon">
<iconset theme="window-close">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="actionAllowRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Allow</string>
</property>
<property name="icon">
<iconset theme="emblem-default">
<normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</normaloff>../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View file

@ -549,9 +549,10 @@ class UIService(ui_pb2_grpc.UIServicer, QtWidgets.QGraphicsObject):
proto, addr = self._get_peer(kwargs['peer'])
self._nodes.add_rule((datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
"{0}:{1}".format(proto, addr),
rule.name, str(rule.enabled), str(rule.precedence), rule.action, rule.duration,
rule.operator.type, str(rule.operator.sensitive), rule.operator.operand,
rule.operator.data)
rule.name, rule.description, str(rule.enabled),
str(rule.precedence), rule.action, rule.duration,
rule.operator.type, str(rule.operator.sensitive), rule.operator.operand,
rule.operator.data)
elif kwargs['action'] == self.DELETE_RULE:
self._db.delete_rule(kwargs['name'], kwargs['addr'])