Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xdg updates + autostart + lockfile #964

Merged
merged 12 commits into from
Jun 21, 2023
152 changes: 85 additions & 67 deletions ui/bin/opensnitch-ui
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ if dist_path not in sys.path:
from opensnitch.service import UIService
from opensnitch.config import Config
from opensnitch.utils import Themes, Utils, Versions
from opensnitch.utils.xdg import xdg_runtime_dir
import opensnitch.ui_pb2
from opensnitch.ui_pb2_grpc import add_UIServicer_to_server

def on_exit():
server.stop(0)
lockfile.unlock()
munix9 marked this conversation as resolved.
Show resolved Hide resolved
app.quit()
sys.exit(0)

Expand Down Expand Up @@ -92,75 +94,91 @@ Examples:
except Exception:
pass

app = QtWidgets.QApplication(sys.argv)
if hasattr(QtCore.Qt, 'AA_UseHighDpiPixmaps'):
app.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
thm = Themes.instance()
thm.load_theme(app)

Utils.create_socket_dirs()
cfg = Config.get()
if args.socket == None:
# default
args.socket = "unix:///tmp/osui.sock"

addr = cfg.getSettings(Config.DEFAULT_SERVER_ADDR)
if addr != None and addr != "":
if addr.startswith("unix://"):
if not os.path.exists(os.path.dirname(addr[7:])):
print("WARNING: unix socket path does not exist, using unix:///tmp/osui.sock, ", addr)
else:
args.socket = addr
try:
app = QtWidgets.QApplication(sys.argv)
lockfile = QtCore.QLockFile(os.path.join(xdg_runtime_dir, 'osui.lock'))

if lockfile.tryLock(100):
if hasattr(QtCore.Qt, 'AA_UseHighDpiPixmaps'):
app.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
thm = Themes.instance()
thm.load_theme(app)

Utils.create_socket_dirs()
cfg = Config.get()
if args.socket == None:
# default
args.socket = "unix:///tmp/osui.sock"

addr = cfg.getSettings(Config.DEFAULT_SERVER_ADDR)
if addr != None and addr != "":
if addr.startswith("unix://"):
if not os.path.exists(os.path.dirname(addr[7:])):
print("WARNING: unix socket path does not exist, using unix:///tmp/osui.sock, ", addr)
else:
args.socket = addr
else:
args.socket = addr

print("Using server address:", args.socket)

maxmsglencfg = cfg.getSettings(Config.DEFAULT_SERVER_MAX_MESSAGE_LENGTH)
if maxmsglencfg == '4MiB':
maxmsglen = 4194304
elif maxmsglencfg == '8MiB':
maxmsglen = 8388608
elif maxmsglencfg == '16MiB':
maxmsglen = 16777216
else:
maxmsglen = 4194304

print("gRPC Max Message Length:", maxmsglencfg)
print(" Bytes:", maxmsglen)

service = UIService(app, on_exit)
# @doc: https://grpc.github.io/grpc/python/grpc.html#server-object
server = grpc.server(futures.ThreadPoolExecutor(),
options=(
# https://github.com/grpc/grpc/blob/master/doc/keepalive.md
# https://grpc.github.io/grpc/core/group__grpc__arg__keys.html
# send keepalive ping every 5 second, default is 2 hours)
('grpc.keepalive_time_ms', 5000),
# after 5s of inactivity, wait 20s and close the connection if
# there's no response.
('grpc.keepalive_timeout_ms', 20000),
('grpc.keepalive_permit_without_calls', True),
('grpc.max_send_message_length', maxmsglen),
('grpc.max_receive_message_length', maxmsglen),
))

add_UIServicer_to_server(service, server)

if args.socket.startswith("unix://"):
socket = args.socket[7:]
socket = os.path.abspath(socket)
server.add_insecure_port("unix:%s" % socket)
else:
args.socket = addr

print("Using server address:", args.socket)

maxmsglencfg = cfg.getSettings(Config.DEFAULT_SERVER_MAX_MESSAGE_LENGTH)
if maxmsglencfg == '4MiB':
maxmsglen = 4194304
elif maxmsglencfg == '8MiB':
maxmsglen = 8388608
elif maxmsglencfg == '16MiB':
maxmsglen = 16777216
else:
maxmsglen = 4194304

print("gRPC Max Message Length:", maxmsglencfg)
print(" Bytes:", maxmsglen)

service = UIService(app, on_exit)
# @doc: https://grpc.github.io/grpc/python/grpc.html#server-object
server = grpc.server(futures.ThreadPoolExecutor(),
options=(
# https://github.com/grpc/grpc/blob/master/doc/keepalive.md
# https://grpc.github.io/grpc/core/group__grpc__arg__keys.html
# send keepalive ping every 5 second, default is 2 hours)
('grpc.keepalive_time_ms', 5000),
# after 5s of inactivity, wait 20s and close the connection if
# there's no response.
('grpc.keepalive_timeout_ms', 20000),
('grpc.keepalive_permit_without_calls', True),
('grpc.max_send_message_length', maxmsglen),
('grpc.max_receive_message_length', maxmsglen),
))

add_UIServicer_to_server(service, server)

if args.socket.startswith("unix://"):
socket = args.socket[7:]
socket = os.path.abspath(socket)
server.add_insecure_port("unix:%s" % socket)
else:
server.add_insecure_port(args.socket)

# https://stackoverflow.com/questions/5160577/ctrl-c-doesnt-work-with-pyqt
signal.signal(signal.SIGINT, signal.SIG_DFL)
server.add_insecure_port(args.socket)

# https://stackoverflow.com/questions/5160577/ctrl-c-doesnt-work-with-pyqt
signal.signal(signal.SIGINT, signal.SIG_DFL)

# print "OpenSnitch UI service running on %s ..." % socket
server.start()
app.exec_()

else:
errortxt = "OpenSnitch UI is already running!"
print(errortxt, "\n")
errormsg = QtWidgets.QMessageBox()
errormsg.setIcon(QtWidgets.QMessageBox.Warning)
errormsg.setWindowTitle("Error")
errormsg.setText(errortxt)
errormsg.setStandardButtons(QtWidgets.QMessageBox.Ok)
errormsg.exec()

try:
# print "OpenSnitch UI service running on %s ..." % socket
server.start()
app.exec_()
except KeyboardInterrupt:
on_exit()

finally:
lockfile.unlock()
3 changes: 2 additions & 1 deletion ui/opensnitch/dialogs/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from opensnitch.customwidgets.generictableview import GenericTableModel
from opensnitch.customwidgets.addresstablemodel import AddressTableModel
from opensnitch.utils import Message, QuickHelp, AsnDB, Icons
from opensnitch.utils.xdg import xdg_current_desktop
from opensnitch.actions import Actions
from opensnitch.rules import Rule, Rules

Expand Down Expand Up @@ -277,7 +278,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def __init__(self, parent=None, address=None, db=None, dbname="db", appicon=None):
super(StatsDialog, self).__init__(parent)

self._current_desktop = os.environ['XDG_CURRENT_DESKTOP'] if os.environ.get("XDG_CURRENT_DESKTOP") != None else None
self._current_desktop = xdg_current_desktop

self.setWindowFlags(QtCore.Qt.Window)
self.setupUi(self)
Expand Down
13 changes: 13 additions & 0 deletions ui/opensnitch/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from opensnitch.database import Database
from opensnitch.utils import Utils, CleanerTask, Themes
from opensnitch.utils import Message, languages
from opensnitch.utils.xdg import Autostart

class UIService(ui_pb2_grpc.UIServicer, QtWidgets.QGraphicsObject):
_new_remote_trigger = QtCore.pyqtSignal(str, ui_pb2.PingRequest)
Expand Down Expand Up @@ -87,6 +88,7 @@ def __init__(self, app, on_exit):
self._msg = QtWidgets.QMessageBox()
self._remote_lock = Lock()
self._remote_stats = {}
self._autostart = Autostart()

self.translator = None
self._init_translation()
Expand Down Expand Up @@ -181,11 +183,22 @@ def _setup_tray(self):
self._menu_enable_fw = self._menu.addAction(self.MENU_ENTRY_FW_DISABLE)
self._menu_enable_fw.setEnabled(False)
self._menu_enable_fw.triggered.connect(self._on_enable_interception_clicked)

self._menu.addSeparator()
self._menu_autostart = self._menu.addAction("Autostart")
self._menu_autostart.setCheckable(True)
self._menu_autostart.setChecked(self._autostart.isEnabled())
self._menu_autostart.triggered.connect(self._on_switch_autostart)
self._menu.addSeparator()

self._menu.addAction(self.MENU_ENTRY_HELP).triggered.connect(
lambda: QtGui.QDesktopServices.openUrl(QtCore.QUrl(Config.HELP_CONFIG_URL))
)
self._menu.addAction(self.MENU_ENTRY_CLOSE).triggered.connect(self._on_close)

def _on_switch_autostart(self):
self._autostart.enable(self._menu_autostart.isChecked())

def _show_gui_if_tray_not_available(self):
"""If the system tray is not available or ready, show the GUI after
10s. This delay helps to skip showing up the GUI when DEs' autologin is on.
Expand Down
50 changes: 48 additions & 2 deletions ui/opensnitch/utils/xdg.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,51 @@

import os
import shutil
import xdg.BaseDirectory
import xdg.DesktopEntry

_user_home = os.path.expanduser('~')
xdg_config_home = os.environ.get('XDG_CONFIG_HOME') or os.path.join(_user_home, '.config')
xdg_config_home = xdg.BaseDirectory.xdg_config_home
xdg_runtime_dir = xdg.BaseDirectory.get_runtime_dir(False)
xdg_current_desktop = os.environ.get('XDG_CURRENT_DESKTOP')

class Autostart():
def __init__(self):
desktopFile = 'opensnitch_ui.desktop'
self.systemDesktop = os.path.join('/usr/share/applications', desktopFile)
self.systemAutostart = os.path.join('/etc/xdg/autostart', desktopFile)
if not os.path.isfile(self.systemAutostart) and os.path.isfile('/usr' + self.systemAutostart):
self.systemAutostart = '/usr' + self.systemAutostart
self.userAutostart = os.path.join(xdg_config_home, 'autostart', desktopFile)

def createUserDir(self):
if not os.path.isdir(xdg_config_home):
os.makedirs(xdg_config_home, 0o700)
if not os.path.isdir(os.path.dirname(self.userAutostart)):
os.makedirs(os.path.dirname(self.userAutostart), 0o755)

def isEnabled(self):
if os.path.isfile(self.userAutostart):
entry = xdg.DesktopEntry.DesktopEntry(self.userAutostart)
if not entry.getHidden():
return True
elif os.path.isfile(self.systemAutostart):
return True
return False

def enable(self, mode=True):
self.createUserDir()
if mode == True:
if os.path.isfile(self.systemAutostart) and os.path.isfile(self.userAutostart):
os.remove(self.userAutostart)
elif os.path.isfile(self.systemDesktop):
shutil.copyfile(self.systemDesktop, self.userAutostart)
else:
if os.path.isfile(self.systemAutostart):
shutil.copyfile(self.systemAutostart, self.userAutostart)
with open(self.userAutostart, 'a') as f:
f.write('Hidden=true\n')
elif os.path.isfile(self.userAutostart):
os.remove(self.userAutostart)

def disable(self):
self.enable(False)
1 change: 1 addition & 0 deletions ui/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pyinotify==0.9.6
unicode_slugify==0.1.5
pyqt5>=5.6
protobuf
pyxdg
2 changes: 1 addition & 1 deletion ui/resources/opensnitch_ui.desktop
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[Desktop Entry]
Type=Application
Name=OpenSnitch
Exec=/bin/sh -c "pkill -15 opensnitch-ui; opensnitch-ui"
Exec=opensnitch-ui
Icon=opensnitch-ui
GenericName=OpenSnitch Firewall
GenericName[hu]=OpenSnitch-tűzfal
Expand Down