diff --git a/ui/opensnitch/nodes.py b/ui/opensnitch/nodes.py index 4370b051..6782b987 100644 --- a/ui/opensnitch/nodes.py +++ b/ui/opensnitch/nodes.py @@ -134,6 +134,9 @@ class Nodes(QObject): return nid, notif, rules_list + def disable_rule(self, addr, rule_name): + self._rules.disable(addr, rule_name) + def update_rule_time(self, time, rule_name, addr): self._rules.update_time(time, rule_name, addr) diff --git a/ui/opensnitch/rules.py b/ui/opensnitch/rules.py index ca487d48..a0939c42 100644 --- a/ui/opensnitch/rules.py +++ b/ui/opensnitch/rules.py @@ -165,6 +165,16 @@ class Rules(QObject): return rule_name + def disable(self, addr, name): + """Mark a rule as not enabled in the DB""" + self._db.update( + "rules", + "enabled='False'", + (name, addr), + "name=? AND node=?", + action_on_conflict="OR REPLACE" + ) + def update_time(self, time, name, addr): """Updates the time of a rule, whenever a new connection matched a rule. diff --git a/ui/opensnitch/service.py b/ui/opensnitch/service.py index da184fcd..8d9890ae 100644 --- a/ui/opensnitch/service.py +++ b/ui/opensnitch/service.py @@ -26,8 +26,15 @@ from opensnitch.nodes import Nodes from opensnitch.config import Config from opensnitch.version import version from opensnitch.database import Database -from opensnitch.utils import Utils, CleanerTask, Themes -from opensnitch.utils import Message, languages +from opensnitch.utils import ( + Utils, + CleanerTask, + Themes, + OneshotTimer, + languages, + Message +) +from opensnitch.utils.duration import duration from opensnitch.utils.xdg import Autostart class UIService(ui_pb2_grpc.UIServicer, QtWidgets.QGraphicsObject): @@ -738,6 +745,16 @@ class UIService(ui_pb2_grpc.UIServicer, QtWidgets.QGraphicsObject): # daemon. rule.operator.data = "" + # disable temporal rules in the db + def _disable_temp_rule(args): + self._nodes.disable_rule(args[0], args[1].name) + timeout = duration.to_seconds(rule.duration) + if rule.duration == Config.DURATION_ONCE: + timeout = 1 + if timeout > 0: + ost = OneshotTimer(timeout, _disable_temp_rule, (kwargs['peer'], rule,)) + ost.start() + elif kwargs['action'] == self.DELETE_RULE: self._db.delete_rule(kwargs['name'], kwargs['addr']) diff --git a/ui/opensnitch/utils/__init__.py b/ui/opensnitch/utils/__init__.py index 03793949..668d7a53 100644 --- a/ui/opensnitch/utils/__init__.py +++ b/ui/opensnitch/utils/__init__.py @@ -227,7 +227,13 @@ class OneshotTimer(GenericTimer): def run(self): self.stop_flag.wait(self.interval) + if self.stop_flag.is_set(): + return self.callback(self.args) + self.stop() + + def stop(self): + self.stop_flag.set() class CleanerTask(Thread): interval = 1 diff --git a/ui/opensnitch/utils/duration/__init__.py b/ui/opensnitch/utils/duration/__init__.py new file mode 100644 index 00000000..aee2b892 --- /dev/null +++ b/ui/opensnitch/utils/duration/__init__.py @@ -0,0 +1,20 @@ +# Copyright (C) 2018 Simone Margaritelli +# 2018 MiWCryptAnalytics +# 2023 munix9 +# 2023 Wojtek Widomski +# 2019-2025 Gustavo Iñiguez Goia +# +# This file is part of OpenSnitch. +# +# OpenSnitch 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, either version 3 of the License, or +# (at your option) any later version. +# +# OpenSnitch 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 OpenSnitch. If not, see . diff --git a/ui/opensnitch/utils/duration/duration.py b/ui/opensnitch/utils/duration/duration.py new file mode 100644 index 00000000..fb614fa1 --- /dev/null +++ b/ui/opensnitch/utils/duration/duration.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2018 Simone Margaritelli +# 2018 MiWCryptAnalytics +# 2023 munix9 +# 2023 Wojtek Widomski +# 2019-2025 Gustavo Iñiguez Goia +# +# This file is part of OpenSnitch. +# +# OpenSnitch 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, either version 3 of the License, or +# (at your option) any later version. +# +# OpenSnitch 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 OpenSnitch. If not, see . + + +import re + +r = re.compile(r'(\d+)([smhdw]+)') + +_second = 1 +_minute = 60 +_hour = 60 * _minute +_day = 60 * _hour +_week = 60 * _day + +_units = { + 's': _second, + 'm': _minute, + 'h': _hour, + 'd': _day, + 'w': _week +} + +def to_seconds(dur_str): + """converts a Golang duration string to seconds: + "20s" -> 20 seconds + "2m" -> 120 seconds + ... + """ + secs = 0 + try: + finds = r.findall(dur_str) + for d in finds: + try: + unit = _units[d[1]] + secs += (unit * int(d[0])) + except: + print("duration.to_seconds(): invalid unit:", d) + + return secs + except: + return secs