forked from Support/sp-hydra-veil-gui
488 lines
20 KiB
Python
Executable file
488 lines
20 KiB
Python
Executable file
import os
|
|
import subprocess
|
|
|
|
from PyQt6.QtWidgets import QApplication, QPushButton, QLabel
|
|
from PyQt6.QtGui import QIcon
|
|
from PyQt6.QtCore import QSize, QTimer
|
|
from PyQt6 import QtCore
|
|
|
|
from gui.v2.ui.pages.Page import Page
|
|
from gui.v2.workers.worker_thread import WorkerThread
|
|
|
|
|
|
class InstallSystemPackage(Page):
|
|
def __init__(self, page_stack, main_window=None, parent=None):
|
|
super().__init__("InstallPackage", page_stack, main_window, parent)
|
|
self.btn_path = main_window.btn_path
|
|
self.update_status = main_window
|
|
self.package_name = ""
|
|
self.install_command = ""
|
|
self.manual_install_command = ""
|
|
self.is_sync = False
|
|
self.ui_elements = []
|
|
self.permanent_elements = []
|
|
self.current_distro = "debian"
|
|
self.distro_buttons = {}
|
|
|
|
self._setup_permanent_ui()
|
|
self._setup_distro_buttons()
|
|
|
|
self.auto_install_package_commands = {
|
|
'all': {
|
|
'debian': 'pkexec apt install -y bubblewrap iproute2 microsocks proxychains4 ratpoison tor wireguard xserver-xephyr',
|
|
'arch': 'pkexec pacman -S bubblewrap iproute2 microsocks proxychains-ng tor wireguard-tools xorg-server-xephyr',
|
|
'fedora': 'pkexec dnf -y install bubblewrap iproute proxychains4 ratpoison tor wireguard-tools xorg-x11-server-Xephyr'
|
|
},
|
|
'bwrap': {
|
|
'debian': 'pkexec apt -y install bubblewrap',
|
|
'arch': 'pkexec pacman -S bubblewrap',
|
|
'fedora': 'pkexec dnf -y install bubblewrap'
|
|
},
|
|
'ip': {
|
|
'debian': 'pkexec apt -y install iproute2',
|
|
'arch': 'pkexec pacman -S iproute2',
|
|
'fedora': 'pkexec dnf -y install iproute'
|
|
},
|
|
'microsocks': {
|
|
'debian': 'pkexec apt -y install microsocks',
|
|
'arch': 'pkexec pacman -S microsocks',
|
|
'fedora': 'zenity --warning --text="An essential dependency (microsocks) is not included in your distribution\'s default repository. Please build it from source or contact support."'
|
|
},
|
|
'proxychains4': {
|
|
'debian': 'pkexec apt -y install proxychains4',
|
|
'arch': 'pkexec pacman -S proxychains-ng',
|
|
'fedora': 'pkexec dnf -y install proxychains4'
|
|
},
|
|
'ratpoison': {
|
|
'debian': 'pkexec apt -y install ratpoison',
|
|
'arch': 'zenity --warning --text="An essential dependency (ratpoison) is not included in your distribution\'s default repository. Please build it from source or contact support."',
|
|
'fedora': 'pkexec dnf -y install ratpoison'
|
|
},
|
|
'tor': {
|
|
'debian': 'pkexec apt -y install tor',
|
|
'arch': 'pkexec pacman -S tor',
|
|
'fedora': 'pkexec dnf -y install tor'
|
|
},
|
|
'wg-quick': {
|
|
'debian': 'pkexec apt -y install wireguard',
|
|
'arch': 'pkexec pacman -S wireguard-tools',
|
|
'fedora': 'pkexec dnf -y install wireguard-tools'
|
|
},
|
|
'Xephyr': {
|
|
'debian': 'pkexec apt -y install xserver-xephyr',
|
|
'arch': 'pkexec pacman -S xorg-server-xephyr',
|
|
'fedora': 'pkexec dnf -y install xorg-x11-server-Xephyr'
|
|
}
|
|
}
|
|
|
|
self.manual_install_package_commands = {
|
|
'all': {
|
|
'debian': 'sudo apt install -y bubblewrap iproute2 microsocks proxychains4 ratpoison tor wireguard xserver-xephyr',
|
|
'arch': 'sudo pacman -S bubblewrap iproute2 microsocks proxychains-ng tor wireguard-tools xorg-server-xephyr',
|
|
'fedora': 'sudo dnf -y install bubblewrap iproute proxychains4 ratpoison tor wireguard-tools xorg-x11-server-Xephyr'
|
|
},
|
|
'bwrap': {
|
|
'debian': 'sudo apt -y install bubblewrap',
|
|
'arch': 'sudo pacman -S bubblewrap',
|
|
'fedora': 'sudo dnf -y install bubblewrap'
|
|
},
|
|
'ip': {
|
|
'debian': 'sudo apt -y install iproute2',
|
|
'arch': 'sudo pacman -S iproute2',
|
|
'fedora': 'sudo dnf -y install iproute'
|
|
},
|
|
'microsocks': {
|
|
'debian': 'sudo apt -y install microsocks',
|
|
'arch': 'sudo pacman -S microsocks',
|
|
'fedora': '# Package not available.'
|
|
},
|
|
'proxychains4': {
|
|
'debian': 'sudo apt -y install proxychains4',
|
|
'arch': 'sudo pacman -S proxychains-ng',
|
|
'fedora': 'sudo dnf -y install proxychains4'
|
|
},
|
|
'ratpoison': {
|
|
'debian': 'sudo apt -y install ratpoison',
|
|
'arch': '# Package not available.',
|
|
'fedora': 'sudo dnf -y install ratpoison'
|
|
},
|
|
'tor': {
|
|
'debian': 'sudo apt -y install tor',
|
|
'arch': 'sudo pacman -S tor',
|
|
'fedora': 'sudo dnf -y install tor'
|
|
},
|
|
'wg-quick': {
|
|
'debian': 'sudo apt -y install wireguard',
|
|
'arch': 'sudo pacman -S wireguard-tools',
|
|
'fedora': 'sudo dnf -y install wireguard-tools'
|
|
},
|
|
'Xephyr': {
|
|
'debian': 'sudo apt -y install xserver-xephyr',
|
|
'arch': 'sudo pacman -S xorg-server-xephyr',
|
|
'fedora': 'sudo dnf -y install xorg-x11-server-Xephyr'
|
|
}
|
|
}
|
|
|
|
def _setup_permanent_ui(self):
|
|
self.title.setGeometry(20, 50, 300, 60)
|
|
self.title.setText("Package Installation")
|
|
self.title.setStyleSheet("font-size: 22px; font-weight: bold;")
|
|
self.permanent_elements.append(self.title)
|
|
|
|
self.display.setGeometry(QtCore.QRect(100, 160, 580, 435))
|
|
self.permanent_elements.append(self.display)
|
|
|
|
def _setup_distro_buttons(self):
|
|
distros = ["debian", "arch", "fedora"]
|
|
|
|
for i, distro in enumerate(distros):
|
|
btn = QPushButton(self)
|
|
btn.setGeometry(360 + i*140, 40, 120, 49)
|
|
btn.setIcon(QIcon(os.path.join(self.btn_path, f"{distro}.png")))
|
|
btn.setIconSize(QSize(120, 49))
|
|
btn.setCheckable(True)
|
|
btn.clicked.connect(
|
|
lambda checked, d=distro: self.switch_distro(d))
|
|
self.distro_buttons[distro] = btn
|
|
self.permanent_elements.append(btn)
|
|
|
|
self.distro_buttons[self.current_distro].setChecked(True)
|
|
|
|
def switch_distro(self, distro):
|
|
self.current_distro = distro
|
|
|
|
for d, btn in self.distro_buttons.items():
|
|
btn.setChecked(d == distro)
|
|
|
|
if self.package_name:
|
|
self.update_command()
|
|
self.setup_ui()
|
|
|
|
def update_command(self):
|
|
if self.package_name in self.auto_install_package_commands:
|
|
if self.is_sync:
|
|
self.install_command = self.auto_install_package_commands[
|
|
'tor_sync'][self.current_distro]
|
|
self.manual_install_command = self.manual_install_package_commands[
|
|
'tor_sync'][self.current_distro]
|
|
else:
|
|
self.install_command = self.auto_install_package_commands[
|
|
self.package_name][self.current_distro]
|
|
self.manual_install_command = self.manual_install_package_commands[
|
|
self.package_name][self.current_distro]
|
|
else:
|
|
self.install_command = ""
|
|
self.manual_install_command = ""
|
|
|
|
def configure(self, package_name, distro, is_sync=False):
|
|
self.package_name = package_name
|
|
self.current_distro = distro
|
|
self.is_sync = is_sync
|
|
self.update_command()
|
|
self.setup_ui()
|
|
return self
|
|
|
|
def setup_ui(self):
|
|
self.button_back.setVisible(False)
|
|
self.button_go.setVisible(True)
|
|
if not self.package_name:
|
|
return
|
|
|
|
self.clear_ui()
|
|
|
|
self._setup_auto_install()
|
|
self._setup_manual_install()
|
|
|
|
self._setup_status_and_nav()
|
|
|
|
for element in self.ui_elements:
|
|
element.setParent(self)
|
|
element.setVisible(True)
|
|
element.raise_()
|
|
|
|
def clear_ui(self):
|
|
for element in self.ui_elements:
|
|
element.setParent(None)
|
|
element.deleteLater()
|
|
self.ui_elements.clear()
|
|
|
|
self.command_box = None
|
|
self.status_label = None
|
|
self.install_button = None
|
|
self.check_button = None
|
|
|
|
def _setup_auto_install(self):
|
|
auto_install_label = QLabel(
|
|
f"Automatic Installation for {self.current_distro}", self)
|
|
auto_install_label.setGeometry(80, 130, 580, 30)
|
|
auto_install_label.setStyleSheet("font-size: 18px; font-weight: bold;")
|
|
auto_install_label.setVisible(True)
|
|
self.ui_elements.append(auto_install_label)
|
|
|
|
auto_install_desc = QLabel(
|
|
"Click the button below to automatically install the missing packages:", self)
|
|
auto_install_desc.setStyleSheet("font-size: 14px; font-weight: bold;")
|
|
auto_install_desc.setGeometry(80, 170, 650, 30)
|
|
auto_install_desc.setVisible(True)
|
|
self.ui_elements.append(auto_install_desc)
|
|
|
|
self.install_button = QPushButton(self)
|
|
self.install_button.setGeometry(135, 210, 100, 40)
|
|
self.install_button.setIcon(
|
|
QIcon(os.path.join(self.btn_path, "install.png")))
|
|
self.install_button.setIconSize(self.install_button.size())
|
|
self.install_button.clicked.connect(self.install_package)
|
|
self.install_button.setVisible(True)
|
|
self.ui_elements.append(self.install_button)
|
|
|
|
if self.current_distro == 'arch':
|
|
auto_install_label.setGeometry(50, 110, 580, 30)
|
|
auto_install_desc.setGeometry(50, 140, 650, 30)
|
|
|
|
self.install_button.setGeometry(150, 185, 100, 40)
|
|
|
|
self.check_button = QPushButton(self)
|
|
self.check_button.setGeometry(270, 185, 100, 40)
|
|
self.check_button.setIcon(
|
|
QIcon(os.path.join(self.btn_path, "check.png")))
|
|
self.check_button.setIconSize(self.check_button.size())
|
|
self.check_button.clicked.connect(self.check_package)
|
|
self.check_button.setVisible(True)
|
|
self.ui_elements.append(self.check_button)
|
|
|
|
def _setup_manual_install(self):
|
|
if self.current_distro != 'arch':
|
|
manual_install_label = QLabel(
|
|
f"Manual Installation for {self.current_distro}", self)
|
|
manual_install_label.setGeometry(80, 290, 650, 30)
|
|
manual_install_label.setStyleSheet(
|
|
"font-size: 18px; font-weight: bold;")
|
|
manual_install_label.setVisible(True)
|
|
self.ui_elements.append(manual_install_label)
|
|
|
|
manual_install_desc = QLabel(
|
|
"Run this command in your terminal:", self)
|
|
manual_install_desc.setStyleSheet(
|
|
"font-size: 14px; font-weight: bold;")
|
|
manual_install_desc.setGeometry(80, 330, 380, 30)
|
|
manual_install_desc.setVisible(True)
|
|
|
|
self.ui_elements.append(manual_install_desc)
|
|
|
|
self.command_box = QLabel(self.manual_install_command, self)
|
|
|
|
self.command_box.setGeometry(80, 370, 380, 40)
|
|
|
|
if self.current_distro == 'arch':
|
|
self.command_box.setGeometry(50, 280, 380, 40)
|
|
|
|
metrics = self.command_box.fontMetrics()
|
|
text_width = metrics.horizontalAdvance(
|
|
self.manual_install_command) + 100
|
|
available_width = self.command_box.width() - 20
|
|
font_size = 18
|
|
MIN_FONT_SIZE = 10
|
|
while text_width > available_width:
|
|
if font_size <= MIN_FONT_SIZE:
|
|
break
|
|
font_size -= 1
|
|
text_width -= 10
|
|
|
|
self.command_box.setStyleSheet(f"""
|
|
background-color: #2b2b2b;
|
|
color: #ffffff;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
font-family: monospace;
|
|
font-size: {font_size}px;
|
|
""")
|
|
|
|
self.command_box.mousePressEvent = lambda _: self.copy_command()
|
|
self.command_box.setVisible(True)
|
|
self.ui_elements.append(self.command_box)
|
|
|
|
if self.current_distro == 'arch':
|
|
pacman_label = QLabel("Pacman Installation:", self)
|
|
pacman_label.setGeometry(50, 240, 650, 30)
|
|
pacman_label.setStyleSheet(
|
|
"font-size: 18px; font-weight: bold; color: #00ffff;")
|
|
pacman_label.setVisible(True)
|
|
self.ui_elements.append(pacman_label)
|
|
|
|
aur_label = QLabel("AUR / Yay Installation:", self)
|
|
aur_label.setGeometry(50, 350, 300, 30)
|
|
aur_label.setStyleSheet(
|
|
"font-size: 18px; font-weight: bold; color: #00ffff;")
|
|
self.ui_elements.append(aur_label)
|
|
|
|
self.yay_command_box = QLabel("sudo yay -S ratpoison", self)
|
|
self.yay_command_box.setGeometry(50, 390, 300, 40)
|
|
self._setup_command_box_style(self.yay_command_box)
|
|
self.yay_command_box.mousePressEvent = lambda _: self.copy_command(
|
|
"sudo yay -S ratpoison", self.yay_command_box)
|
|
self.ui_elements.append(self.yay_command_box)
|
|
|
|
aur_command = "git clone https://aur.archlinux.org/ratpoison.git\ncd ratpoison\nmakepkg -si --skippgpcheck"
|
|
self.aur_command_box = QLabel(aur_command, self)
|
|
self.aur_command_box.setGeometry(370, 390, 380, 60)
|
|
self._setup_command_box_style(self.aur_command_box)
|
|
self.aur_command_box.setWordWrap(True)
|
|
self.aur_command_box.mousePressEvent = lambda _: self.copy_command(
|
|
aur_command, self.aur_command_box)
|
|
self.ui_elements.append(self.aur_command_box)
|
|
|
|
else:
|
|
self.command_box = QLabel(self.manual_install_command, self)
|
|
self.command_box.setGeometry(80, 370, 380, 40)
|
|
metrics = self.command_box.fontMetrics()
|
|
text_width = metrics.horizontalAdvance(
|
|
self.manual_install_command) + 100
|
|
available_width = self.command_box.width() - 20
|
|
font_size = 18
|
|
MIN_FONT_SIZE = 10
|
|
while text_width > available_width:
|
|
if font_size <= MIN_FONT_SIZE:
|
|
break
|
|
font_size -= 1
|
|
text_width -= 10
|
|
|
|
self.command_box.setStyleSheet(f"""
|
|
background-color: #2b2b2b;
|
|
color: #ffffff;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
font-family: monospace;
|
|
font-size: {font_size}px;
|
|
""")
|
|
|
|
self.command_box.mousePressEvent = lambda _: self.copy_command()
|
|
self.command_box.setVisible(True)
|
|
self.ui_elements.append(self.command_box)
|
|
|
|
def _setup_command_box_style(self, command_box):
|
|
metrics = command_box.fontMetrics()
|
|
text_width = metrics.horizontalAdvance(command_box.text()) + 100
|
|
available_width = command_box.width() - 20
|
|
font_size = 18
|
|
MIN_FONT_SIZE = 10
|
|
while text_width > available_width:
|
|
if font_size <= MIN_FONT_SIZE:
|
|
break
|
|
font_size -= 1
|
|
text_width -= 10
|
|
|
|
command_box.setStyleSheet(f"""
|
|
background-color: #2b2b2b;
|
|
color: #ffffff;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
font-family: monospace;
|
|
font-size: {font_size}px;
|
|
""")
|
|
command_box.setVisible(True)
|
|
|
|
def copy_yay_command(self):
|
|
clipboard = QApplication.clipboard()
|
|
clipboard.setText("sudo yay -S ratpoison")
|
|
|
|
original_style = self.yay_command_box.styleSheet()
|
|
self.yay_command_box.setStyleSheet(
|
|
original_style + "background-color: #27ae60;")
|
|
QTimer.singleShot(
|
|
200, lambda: self.yay_command_box.setStyleSheet(original_style))
|
|
self.update_status.update_status("Yay command copied to clipboard")
|
|
|
|
def _setup_status_and_nav(self):
|
|
if self.current_distro != 'arch':
|
|
self.check_button = QPushButton(self)
|
|
self.check_button.setGeometry(130, 430, 100, 40)
|
|
self.check_button.setIcon(
|
|
QIcon(os.path.join(self.btn_path, "check.png")))
|
|
self.check_button.setIconSize(self.check_button.size())
|
|
self.check_button.clicked.connect(self.check_package)
|
|
self.ui_elements.append(self.check_button)
|
|
|
|
self.button_go.clicked.connect(self.go_next)
|
|
self.button_back.clicked.connect(self.go_next)
|
|
|
|
self.status_label = QLabel("", self)
|
|
self.status_label.setGeometry(300, 430, 250, 40)
|
|
if self.current_distro == 'arch':
|
|
self.status_label.setGeometry(450, 185, 250, 40)
|
|
self.ui_elements.append(self.status_label)
|
|
|
|
def copy_command(self, command=None, command_box=None):
|
|
if command_box is None:
|
|
command_box = self.command_box
|
|
|
|
clipboard = QApplication.clipboard()
|
|
if command:
|
|
clipboard.setText(command)
|
|
else:
|
|
clipboard.setText(self.manual_install_command)
|
|
|
|
original_style = command_box.styleSheet()
|
|
command_box.setStyleSheet(
|
|
original_style + "background-color: #27ae60;")
|
|
QTimer.singleShot(
|
|
200, lambda: command_box.setStyleSheet(original_style))
|
|
self.update_status.update_status("Command copied to clipboard")
|
|
|
|
def install_package(self):
|
|
if not self.install_command:
|
|
self.update_status.update_status(
|
|
f"Installation not supported for {self.current_distro}")
|
|
return
|
|
|
|
if subprocess.getstatusoutput('pkexec --help')[0] == 127:
|
|
self.update_status.update_status("polkit toolkit is not installed")
|
|
self.install_button.setDisabled(True)
|
|
return
|
|
|
|
self.worker_thread = WorkerThread('INSTALL_PACKAGE',
|
|
package_command=self.install_command,
|
|
package_name=self.package_name)
|
|
self.worker_thread.text_output.connect(
|
|
self.update_status.update_status)
|
|
self.worker_thread.finished.connect(self.installation_complete)
|
|
self.worker_thread.start()
|
|
|
|
def installation_complete(self, success):
|
|
if success:
|
|
self.check_package()
|
|
|
|
def check_package(self):
|
|
try:
|
|
if self.package_name.lower() == 'all':
|
|
packages = ['bwrap', 'ip', 'microsocks',
|
|
'proxychains4', 'ratpoison', 'tor', 'Xephyr', 'wg']
|
|
for package in packages:
|
|
if subprocess.getstatusoutput(f'{package} --help')[0] == 127:
|
|
self.status_label.setText(
|
|
f"{package} is not installed")
|
|
self.status_label.setStyleSheet("color: red;")
|
|
return
|
|
self.status_label.setText("All packages installed!")
|
|
self.status_label.setStyleSheet("color: green;")
|
|
elif self.package_name.lower() == 'wireguard':
|
|
self.install_name = 'wg'
|
|
elif self.package_name.lower() == 'bubblewrap':
|
|
self.install_name = 'bwrap'
|
|
elif self.package_name.lower() == 'xserver-xephyr':
|
|
self.install_name = 'Xephyr'
|
|
else:
|
|
self.install_name = self.package_name
|
|
if subprocess.getstatusoutput(f'{self.install_name.lower()} --help')[0] == 127:
|
|
self.status_label.setText(
|
|
f"{self.package_name} is not installed")
|
|
self.status_label.setStyleSheet("color: red;")
|
|
else:
|
|
self.status_label.setText(
|
|
f"{self.package_name} is installed!")
|
|
self.status_label.setStyleSheet("color: green;")
|
|
except Exception:
|
|
self.status_label.setText("Check failed")
|
|
self.status_label.setStyleSheet("color: red;")
|
|
|
|
def go_next(self):
|
|
self.custom_window.navigator.navigate("menu")
|