saikyo-packages-src/saikyo-security-profile/bin/saikyo-security-profile-gui

164 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import json
import os
import subprocess
import sys
from pathlib import Path
from PyQt5 import QtCore, QtWidgets
APP_TITLE = "SAIKYO OS — Security Profile Manager"
def _run(cmd, check=False):
return subprocess.run(cmd, check=check)
def _pkexec(cmd):
# pkexec will prompt for admin auth via polkit
return _run(["/usr/bin/pkexec"] + cmd, check=False)
def _profiles_dir() -> Path:
return Path("/usr/share/saikyo-security-profile/profiles")
def _read_profile(profile: str) -> dict:
p = _profiles_dir() / f"{profile}.json"
return json.loads(p.read_text(encoding="utf-8"))
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle(APP_TITLE)
self.setMinimumSize(720, 480)
root = QtWidgets.QWidget(self)
self.setCentralWidget(root)
self.profile_combo = QtWidgets.QComboBox()
self.profile_combo.addItems(["standard", "secure"])
self.apply_btn = QtWidgets.QPushButton("Применить")
self.export_btn = QtWidgets.QPushButton("Экспорт...")
self.import_btn = QtWidgets.QPushButton("Импорт...")
self.reload_btn = QtWidgets.QPushButton("Обновить")
self.preview = QtWidgets.QPlainTextEdit()
self.preview.setReadOnly(True)
self.preview.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap)
top = QtWidgets.QHBoxLayout()
top.addWidget(QtWidgets.QLabel("Профиль:"))
top.addWidget(self.profile_combo, 1)
top.addWidget(self.apply_btn)
top.addWidget(self.export_btn)
top.addWidget(self.import_btn)
top.addWidget(self.reload_btn)
layout = QtWidgets.QVBoxLayout(root)
layout.addLayout(top)
layout.addWidget(self.preview, 1)
self.apply_btn.clicked.connect(self.on_apply)
self.export_btn.clicked.connect(self.on_export)
self.import_btn.clicked.connect(self.on_import)
self.reload_btn.clicked.connect(self.refresh_preview)
self.profile_combo.currentTextChanged.connect(lambda _: self.refresh_preview())
self.refresh_preview()
def current_profile(self) -> str:
return self.profile_combo.currentText().strip()
def refresh_preview(self):
prof_name = self.current_profile()
try:
data = _read_profile(prof_name)
self.preview.setPlainText(json.dumps(data, indent=2, sort_keys=True) + "\n")
except Exception as e:
self.preview.setPlainText(f"Ошибка чтения профиля '{prof_name}': {e}\n")
def _msg(self, title: str, text: str, icon=QtWidgets.QMessageBox.Information):
m = QtWidgets.QMessageBox(self)
m.setIcon(icon)
m.setWindowTitle(title)
m.setText(text)
m.exec_()
def on_apply(self):
prof = self.current_profile()
rc = _pkexec(["/usr/sbin/saikyo-security-profile", "apply", prof]).returncode
if rc == 0:
self._msg("Готово", f"Профиль '{prof}' применён.")
else:
self._msg("Ошибка", f"Не удалось применить профиль '{prof}'. Код: {rc}", QtWidgets.QMessageBox.Critical)
def on_export(self):
prof = self.current_profile()
path, _ = QtWidgets.QFileDialog.getSaveFileName(
self,
"Экспорт профиля",
str(Path.home() / f"{prof}.json"),
"JSON (*.json);;All files (*)",
)
if not path:
return
try:
# Export does not require root
rc = _run(["/usr/sbin/saikyo-security-profile", "export", prof, path], check=False).returncode
if rc == 0:
self._msg("Готово", f"Профиль '{prof}' экспортирован в:\n{path}")
else:
self._msg("Ошибка", f"Не удалось экспортировать профиль '{prof}'. Код: {rc}", QtWidgets.QMessageBox.Critical)
except Exception as e:
self._msg("Ошибка", str(e), QtWidgets.QMessageBox.Critical)
def on_import(self):
prof = self.current_profile()
path, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
"Импорт профиля",
str(Path.home()),
"JSON (*.json);;All files (*)",
)
if not path:
return
# Validate JSON before asking for auth
try:
json.loads(Path(path).read_text(encoding="utf-8"))
except Exception as e:
self._msg("Ошибка", f"Некорректный JSON: {e}", QtWidgets.QMessageBox.Critical)
return
rc = _pkexec(["/usr/sbin/saikyo-security-profile", "import", prof, path]).returncode
if rc == 0:
self._msg("Готово", f"Профиль '{prof}' импортирован из:\n{path}")
self.refresh_preview()
else:
self._msg("Ошибка", f"Не удалось импортировать профиль '{prof}'. Код: {rc}", QtWidgets.QMessageBox.Critical)
def main(argv):
if not Path("/usr/sbin/saikyo-security-profile").exists():
print("ERROR: /usr/sbin/saikyo-security-profile not found", file=sys.stderr)
return 2
if not Path("/usr/bin/pkexec").exists():
print("ERROR: pkexec not found (install policykit-1)", file=sys.stderr)
return 2
app = QtWidgets.QApplication(list(argv))
app.setApplicationName("saikyo-security-profile-gui")
w = MainWindow()
w.show()
return app.exec_()
if __name__ == "__main__":
raise SystemExit(main(sys.argv))