diff --git a/assets/script/lin/install_new_portable_version.sh b/assets/script/lin/install_new_portable_version.sh new file mode 100755 index 00000000..7d2383c3 --- /dev/null +++ b/assets/script/lin/install_new_portable_version.sh @@ -0,0 +1,59 @@ +#!/bin/bash + + +if [ "$#" -lt 1 ]; then + echo "Usage: $0 [destination_folder]" >&2 + exit 1 +fi + +GZ_PATH="$1" +DEST_DIR="${2:-/opt}" +TEMP_DIR="/tmp/InstallApp" + +if [ ! -f "$GZ_PATH" ]; then + echo "Error: File $GZ_PATH not found." >&2 + exit 1 +fi + +if [ ! -d "$DEST_DIR" ]; then + echo "Error: Destination directory $DEST_DIR does not exist." >&2 + exit 1 +fi + + +mkdir -p "$TEMP_DIR" + +echo "Extracting $GZ_PATH..." +gzip -d "$GZ_PATH" || { + echo "Error: Failed to extract the .gz file." >&2 + exit 1 +} + + +EXTRACTED_FILE="${GZ_PATH%.gz}" + + +if [ ! -f "$EXTRACTED_FILE" ]; then + echo "Error: Extraction failed, no file found at $EXTRACTED_FILE" >&2 + exit 1 +fi + + +echo "Copying $EXTRACTED_FILE to $DEST_DIR..." +cp "$EXTRACTED_FILE" "$DEST_DIR" || { + echo "Error: Failed to copy the extracted file." >&2 + exit 1 +} + + +echo "Cleaning up temporary files..." +rm -f "$EXTRACTED_FILE" + +echo "Launching $EXTRACTED_FILE..." +"$DEST_DIR/$(basename "$EXTRACTED_FILE")" || { + echo "Error: Failed to launch the application." >&2 + exit 1 +} + +echo "Installation and launch completed successfully in $DEST_DIR!" +exit 0 \ No newline at end of file diff --git a/assets/script/lin/launch_fit_with_privileges.sh b/assets/script/lin/launch_fit_with_admin_privileges.sh similarity index 64% rename from assets/script/lin/launch_fit_with_privileges.sh rename to assets/script/lin/launch_fit_with_admin_privileges.sh index 1709e1a1..e552b336 100644 --- a/assets/script/lin/launch_fit_with_privileges.sh +++ b/assets/script/lin/launch_fit_with_admin_privileges.sh @@ -4,9 +4,9 @@ python_path=${1:-} app_path=${2} if [[ -z "$python_path" ]]; then - echo "Esecuzione dell'app senza Python..." + echo "Running the app without Python..." pkexec "$app_path" else - echo "Esecuzione con Python..." + echo "Running with Python..." pkexec "$python_path" "$app_path" fi diff --git a/assets/script/mac/install_new_portable_version.sh b/assets/script/mac/install_new_portable_version.sh new file mode 100755 index 00000000..b21940c9 --- /dev/null +++ b/assets/script/mac/install_new_portable_version.sh @@ -0,0 +1,77 @@ +#!/bin/bash + + +if [ "$#" -lt 1 ]; then + echo "Usage: $0 [destination_folder]" >&2 + exit 1 +fi + + +DMG_PATH="$1" +DEST_DIR="${2:-/Applications}" +MOUNT_DIR="/Volumes/InstallDMG" + + +if [ ! -f "$DMG_PATH" ]; then + echo "Error: File $DMG_PATH not found." >&2 + exit 1 +fi + + +if [ ! -d "$DEST_DIR" ]; then + echo "Error: Destination directory $DEST_DIR does not exist." >&2 + exit 1 +fi + +echo "Mounting $DMG_PATH..." +hdiutil attach "$DMG_PATH" -nobrowse -mountpoint "$MOUNT_DIR" || { + echo "Error: Failed to mount the DMG file." >&2 + exit 1 +} + + +APP_PATH=$(find "$MOUNT_DIR" -type d -name "*.app" | head -n 1) + +if [ -z "$APP_PATH" ]; then + echo "Error: No application found inside the DMG." >&2 + hdiutil detach "$MOUNT_DIR" + exit 1 +fi + + +APP_NAME=$(basename "$APP_PATH") +TARGET_PATH="$DEST_DIR/$APP_NAME" + +if [ -d "$TARGET_PATH" ]; then + echo "Removing existing version of $APP_NAME in $DEST_DIR..." + rm -rf "$TARGET_PATH" || { + echo "Error: Failed to remove the old version." >&2 + hdiutil detach "$MOUNT_DIR" + exit 1 + } +fi + + +echo "Copying $APP_PATH to $DEST_DIR..." +cp -R "$APP_PATH" "$DEST_DIR" || { + echo "Error: Failed to copy the application." >&2 + hdiutil detach "$MOUNT_DIR" + exit 1 +} + + +echo "Unmounting the DMG..." +hdiutil detach "$MOUNT_DIR" || { + echo "Error: Failed to unmount the DMG." >&2 + exit 1 +} + + +echo "Launching $APP_NAME..." +open "$TARGET_PATH" || { + echo "Error: Failed to launch the application." >&2 + exit 1 +} + +echo "Installation and launch completed successfully in $DEST_DIR!" +exit 0 diff --git a/assets/script/mac/launch_fit_with_privileges.sh b/assets/script/mac/launch_fit_with_admin_privileges.sh similarity index 70% rename from assets/script/mac/launch_fit_with_privileges.sh rename to assets/script/mac/launch_fit_with_admin_privileges.sh index 4021dced..dd91e1b2 100755 --- a/assets/script/mac/launch_fit_with_privileges.sh +++ b/assets/script/mac/launch_fit_with_admin_privileges.sh @@ -1,13 +1,12 @@ #!/bin/bash -# Controlla gli argomenti PYTHON_PATH=${1:-} APP_PATH=${2:-} if [[ -z "$PYTHON_PATH" ]]; then - echo "Percorso di Python mancante. Avvio senza argomento Python." + echo "Missing Python path. Starting without the Python argument." osascript -e "do shell script \"launchctl asuser $(id -u) '${APP_PATH}'\" with administrator privileges" else - echo "Avvio con Python: $PYTHON_PATH" + echo "Starting with Python: $PYTHON_PATH" osascript -e "do shell script \"launchctl asuser $(id -u) '${PYTHON_PATH}' '${APP_PATH}'\" with administrator privileges" fi \ No newline at end of file diff --git a/assets/script/win/install_new_portable_version.ps1 b/assets/script/win/install_new_portable_version.ps1 new file mode 100644 index 00000000..470c788e --- /dev/null +++ b/assets/script/win/install_new_portable_version.ps1 @@ -0,0 +1,52 @@ +if ($args.Count -lt 1) { + Write-Host "Usage: .\$($MyInvocation.MyCommand.Name) [destination_folder]" -ForegroundColor Red + exit 1 +} + +$ZIP_PATH = $args[0] +$DEST_DIR = if ($args.Count -ge 2) { $args[1] } else { "C:\Program Files" } + + +if (-not (Test-Path -Path $ZIP_PATH)) { + Write-Host "Error: File $ZIP_PATH not found." -ForegroundColor Red + exit 1 +} + + +if (-not (Test-Path -Path $DEST_DIR)) { + Write-Host "Error: Destination directory $DEST_DIR does not exist." -ForegroundColor Red + exit 1 +} + + +Write-Host "Extracting $ZIP_PATH..." +try { + Expand-Archive -Path $ZIP_PATH -DestinationPath $DEST_DIR -Force +} catch { + Write-Host "Error: Failed to extract the ZIP file." -ForegroundColor Red + exit 1 +} + +$APP_NAME = (Get-ChildItem -Path $DEST_DIR | Where-Object { $_.PSIsContainer }).Name +$TARGET_PATH = Join-Path -Path $DEST_DIR -ChildPath $APP_NAME + +if (Test-Path -Path $TARGET_PATH) { + Write-Host "Removing existing version of $APP_NAME in $DEST_DIR..." + Remove-Item -Path $TARGET_PATH -Recurse -Force +} + +Write-Host "Moving extracted files to $DEST_DIR..." +Move-Item -Path (Join-Path -Path $DEST_DIR -ChildPath $APP_NAME) -Destination $DEST_DIR + + +Write-Host "Launching $APP_NAME..." +$exePath = Join-Path -Path $DEST_DIR -ChildPath "$APP_NAME\your_application.exe" +if (Test-Path -Path $exePath) { + Start-Process -FilePath $exePath +} else { + Write-Host "Error: Executable not found in $TARGET_PATH." -ForegroundColor Red + exit 1 +} + +Write-Host "Installation and launch completed successfully in $DEST_DIR!" -ForegroundColor Green +exit 0 \ No newline at end of file diff --git a/assets/script/win/launch_fit_with_admin_privileges.ps1 b/assets/script/win/launch_fit_with_admin_privileges.ps1 new file mode 100644 index 00000000..d90560c9 --- /dev/null +++ b/assets/script/win/launch_fit_with_admin_privileges.ps1 @@ -0,0 +1,10 @@ +$python_path = $args[0] +$app_path = $args[1] + +if (-not $python_path) { + Write-Host "Running the app without Python..." + Start-Process -FilePath $app_path -Verb RunAs +} else { + Write-Host "Running with Python..." + Start-Process -FilePath $python_path -ArgumentList $app_path -Verb RunAs +} \ No newline at end of file diff --git a/assets/script/win/launch_fit_with_privileges.bat b/assets/script/win/launch_fit_with_privileges.bat deleted file mode 100644 index dc00181f..00000000 --- a/assets/script/win/launch_fit_with_privileges.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off -set python_path=%1 -set app_path=%2 - -if "%python_path%"=="" ( - echo Esecuzione solo dell'app senza Python... - runas /user:Administrator "%app_path%" -) else ( - echo Esecuzione con Python... - runas /user:Administrator "%python_path% %app_path%" -) \ No newline at end of file diff --git a/common/constants/view/init.py b/common/constants/view/init.py index ac965650..51e7ae44 100644 --- a/common/constants/view/init.py +++ b/common/constants/view/init.py @@ -20,10 +20,19 @@ WAR_NPCAP_NOT_INSTALLED = "Seems Npcap it's not installed in your PC.

Without Npcap fit's functionality is very limited.

Do you want install it?" FIT_NEW_VERSION_TITLE = "New version of FIT" -FIT_NEW_VERSION_MSG = "There is a new version of FIT.

Do you want download and excute it?" +FIT_NEW_VERSION_MSG = ( + "There is a new version of FIT.

Do you want download and excute it?" +) FIT_NEW_VERSION_DOWNLOAD_TITLE = "FIT download" FIT_NEW_VERSION_DOWNLOAD_MSG = "Download new version of FIT" +FIT_NEW_VERSION_INSTALLATION_TITLE = "FIT install" +FIT_NEW_VERSION_INSTALLATION_SUCCESS = "The new version of FIT has been successfully updated. Please wait a few seconds for the new version to start." +FIT_NEW_VERSION_INSTALLATION_ERROR = ( + "Something went wrong during the update, please try again in debug mode." +) + + DOWNLOAD_URL_ERROR = "I couldn't find the download URL." FIT_NEW_VERSION_DOWNLOAD_ERROR = ( @@ -46,6 +55,4 @@ NVIDIA_GPU_PRESENT_MSG = 'This PC has an NVIDIA graphics card.

Check the NVIDIA control panel to see which processor is selected for 3D acceleration. If it is NVIDIA, disable it.

Otherwise, the screen will not be recorded.
' NVIDIA_GPU_GUIDE_URL = "https://github.com/fit-project/fit/wiki/Screen-recorder-Issue" -NVIDIA_GPU_GUIDE = ( - "For more info read the guide" -) \ No newline at end of file +NVIDIA_GPU_GUIDE = "For more info read the guide" diff --git a/common/constants/view/tasks/status.py b/common/constants/view/tasks/status.py index 06af1a93..63cb0e03 100644 --- a/common/constants/view/tasks/status.py +++ b/common/constants/view/tasks/status.py @@ -10,3 +10,4 @@ PENDING = "Pending" FAIL = "Fail" SUCCESS = "Success" +UNKNOW = "Unknow" diff --git a/common/utility.py b/common/utility.py index 0e93b20c..e1ba2746 100644 --- a/common/utility.py +++ b/common/utility.py @@ -338,20 +338,24 @@ def is_cmd(name): return distutils.spawn.find_executable(name) is not None -def is_nvidia_gpu_present(): +def is_nvidia_gpu_installed(): is_present = bool(is_cmd("nvidia-smi")) if is_present is False: if get_platform() == "win": try: - result = subprocess.run(["wmic", "path", "win32_VideoController", "get", "name"], - capture_output=True, text=True, check=True) + result = subprocess.run( + ["wmic", "path", "win32_VideoController", "get", "name"], + capture_output=True, + text=True, + check=True, + ) is_present = "NVIDIA" in result.stdout except FileNotFoundError: is_present = False if is_present is False: - with tempfile.TemporaryDirectory() as temp_dir: + with tempfile.TemporaryDirectory() as temp_dir: dxdiag_output_path = os.path.join(temp_dir, "dxdiag_output.txt") try: subprocess.run(["dxdiag", "/t", dxdiag_output_path], check=True) @@ -360,20 +364,21 @@ def is_nvidia_gpu_present(): gpu_names = re.findall(r"Card name: (.*NVIDIA.*)", output) is_present = bool(gpu_names) - + except subprocess.CalledProcessError as e: is_present = False except FileNotFoundError: is_present = False - + if get_platform() == "lin": try: - result = subprocess.run(["lspci"], capture_output=True, text=True, check=True) + result = subprocess.run( + ["lspci"], capture_output=True, text=True, check=True + ) is_present = "NVIDIA" in result.stdout except FileNotFoundError: is_present = False - return is_present @@ -396,8 +401,6 @@ def get_language(): return controller.options["language"] - - # search for the first free port to bind the proxy def find_free_port(): sock = socket.socket() diff --git a/fit.py b/fit.py index 4230529c..cb4b49ae 100644 --- a/fit.py +++ b/fit.py @@ -11,7 +11,8 @@ from PyQt6 import QtWidgets, QtGui from common.utility import resolve_path -from view.init import Init as InitView + +from view.checks.initial_checks import InitialChecks from view.wizard import Wizard as WizardView from view.scrapers.web.web import Web as WebView from view.scrapers.mail.mail import Mail as MailView @@ -26,6 +27,7 @@ app.setWindowIcon(QtGui.QIcon(resolve_path("icon.ico"))) acquisition_window = None + def start_task(task, case_info): global acquisition_window options = {} @@ -43,13 +45,13 @@ def start_task(task, case_info): acquisition_window.init(case_info, wizard, options) acquisition_window.show() - init = InitView() + initial_checks = InitialChecks() wizard = WizardView() - init.finished.connect(wizard.show) + initial_checks.finished.connect(wizard.show) # Wizard sends a signal when start button is clicked and case is stored on the DB wizard.finished.connect(lambda task, case_info: start_task(task, case_info)) - init.init_check() + initial_checks.run_checks() sys.exit(app.exec()) diff --git a/view/checks/__init__.py b/view/checks/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/view/checks/admin_privileges.py b/view/checks/admin_privileges.py new file mode 100644 index 00000000..e9e122ca --- /dev/null +++ b/view/checks/admin_privileges.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +###### +# ----- +# Copyright (c) 2023 FIT-Project +# SPDX-License-Identifier: GPL-3.0-only +# ----- +###### + + +import sys +import os +from PyQt6 import QtCore +from view.checks.check import Check +from view.dialog import Dialog, DialogButtonTypes + +from common.utility import is_admin, resolve_path, get_platform + +from common.constants.view.tasks import status +from common.constants.view.init import USER_IS_NOT_ADMIN_TITLE, USER_IS_NOT_ADMIN_MSG + + +class AdminPrivilegesCheck(Check): + def __init__(self, parent=None): + super().__init__(parent) + + def __del__(self): + if ( + hasattr(self, "process") + and self.process.state() != QtCore.QProcess.ProcessState.NotRunning + ): + self.process.kill() + self.process.waitForFinished() + + def run_check(self): + if is_admin() is False: + dialog = Dialog(USER_IS_NOT_ADMIN_TITLE, USER_IS_NOT_ADMIN_MSG) + dialog.message.setStyleSheet("font-size: 13px;") + dialog.set_buttons_type(DialogButtonTypes.QUESTION) + dialog.right_button.clicked.connect( + lambda: self.__run_fit_with_user_privileges(dialog) + ) + dialog.left_button.clicked.connect( + lambda: self.__run_fit_with_admin_privileges(dialog) + ) + dialog.content_box.adjustSize() + + dialog.exec() + else: + self.finished.emit(status.SUCCESS) + + def __run_fit_with_user_privileges(self, dialog): + dialog.close() + self.finished.emit(status.FAIL) + + def __quit(self): + try: + self.__cleanup() + except Exception as e: + pass + if hasattr(self, "process") and self.process is not None: + self.process.kill() + + sys.exit(0) + + def __run_fit_with_admin_privileges(self, dialog=None): + if dialog: + dialog.close() + + loop = QtCore.QEventLoop() + QtCore.QTimer.singleShot(500, loop.quit) + loop.exec() + + self.is_finsished = False + + current_app = self.__get_current_app_path() + python_path = sys.executable + + if get_platform() == "macos": + launch_script = resolve_path( + "assets/script/mac/launch_fit_with_admin_privileges.sh" + ) + args = [python_path, current_app] + elif get_platform() == "win": + launch_script = resolve_path( + "assets/script/win/launch_fit_with_admin_privileges.ps1" + ) + args = [python_path, current_app] + elif sys.platform == "lin": + launch_script = resolve_path( + "assets/script/lin/launch_fit_with_admin_privileges.sh" + ) + args = [python_path, current_app] + else: + if self.debug_mode: + raise OSError("OS not supported.") + + self.process = QtCore.QProcess(self) + + self.process.started.connect(self.__on_process_started) + self.process.errorOccurred.connect(self.__on_process_error) + self.process.readyReadStandardError.connect(self.__capture_process_output) + self.process.readyReadStandardOutput.connect(self.__capture_process_output) + + self.process_output = "" # Buffer to store process output + + self.process.start(launch_script, args) + + def __on_process_started(self): + QtCore.QTimer.singleShot(1000, self.__quit) + + def __capture_process_output(self): + self.process_output += self.process.readAllStandardError().data().decode() + self.process_output += self.process.readAllStandardOutput().data().decode() + if self.debug_mode: + print(self.process_output) + + def __cleanup(self): + if ( + hasattr(self, "process") + and self.process.state() != QtCore.QProcess.ProcessState.NotRunning + ): + self.process.terminate() + self.process.waitForFinished() + + def __on_process_error(self, error): + error_map = { + QtCore.QProcess.ProcessError.FailedToStart: "Failed to start the process.", + QtCore.QProcess.ProcessError.Crashed: "The process has crashed.", + QtCore.QProcess.ProcessError.Timedout: "The process timed out.", + QtCore.QProcess.ProcessError.WriteError: "Write error in the process.", + QtCore.QProcess.ProcessError.ReadError: "Read error from the process.", + QtCore.QProcess.ProcessError.UnknownError: "Unknown error.", + } + error_message = error_map.get(error, "Undefined error.") + + if self.debug_mode: + print(f"Error during process execution: {error_message}") + + def __get_current_app_path(self): + if getattr(sys, "frozen", False): + return os.path.abspath(sys.executable) + else: + return os.path.abspath(sys.argv[0]) + + def closeEvent(self, event): + if ( + hasattr(self, "process") + and self.process.state() != QtCore.QProcess.ProcessState.NotRunning + ): + self.process.terminate() + if not self.process.waitForFinished(3000): + self.process.kill() + event.accept() diff --git a/view/checks/check.py b/view/checks/check.py new file mode 100644 index 00000000..e623da8d --- /dev/null +++ b/view/checks/check.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +###### +# ----- +# Copyright (c) 2023 FIT-Project +# SPDX-License-Identifier: GPL-3.0-only +# ----- +###### + + +from PyQt6 import QtCore, QtWidgets + + +class Check(QtCore.QObject): + finished = QtCore.pyqtSignal(str) + + def __init__(self, parent=...): + super().__init__(parent) + self.debug_mode = "--debug" in QtWidgets.QApplication.instance().arguments() + + def run_check(self): + pass diff --git a/view/checks/download_and_save.py b/view/checks/download_and_save.py new file mode 100644 index 00000000..2a809bc3 --- /dev/null +++ b/view/checks/download_and_save.py @@ -0,0 +1,70 @@ +from PyQt6 import QtCore, QtWidgets, QtWebEngineWidgets +from view.dialog import Dialog, DialogButtonTypes + + +class DownloadAndSave(QtWidgets.QDialog): + finished = QtCore.pyqtSignal(str) + + def __init__( + self, url, progress_dialog_title, progress_dialog_message, parent=None + ): + super(DownloadAndSave, self).__init__(parent) + + self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint) + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground) + + self.file_path = None + + self.filename = QtCore.QUrl(url).path() + self.suffix = QtCore.QFileInfo(self.filename).suffix() + + self.progress_dialog = Dialog( + progress_dialog_title, + progress_dialog_message, + ) + self.progress_dialog.message.setStyleSheet("font-size: 13px;") + self.progress_dialog.set_buttons_type(DialogButtonTypes.NONE) + self.progress_dialog.show_progress_bar() + self.progress_dialog.progress_bar.setValue(0) + + self.web_view = QtWebEngineWidgets.QWebEngineView() + self.web_view.page().profile().downloadRequested.connect( + self.on_download_requested + ) + + self.web_view.load(QtCore.QUrl(url)) + self.web_view.hide() + + def on_download_requested(self, download): + self.file_path, _ = QtWidgets.QFileDialog.getSaveFileName( + self, "Save File", self.filename, "*." + self.suffix + ) + + if self.file_path: + download.setDownloadFileName(self.file_path) + download.accept() + download.isFinishedChanged.connect(self.__is_download_finished) + download.receivedBytesChanged.connect( + lambda: self.__progress( + download.receivedBytes(), + download.totalBytes(), + ) + ) + download.totalBytesChanged.connect( + lambda: self.__progress( + download.receivedBytes(), + download.totalBytes(), + ) + ) + self.progress_dialog.show() + else: + self.reject() + + def __is_download_finished(self): + self.progress_dialog.close() + self.finished.emit(self.file_path) + + def __progress(self, bytes_received, bytes_total): + if bytes_total > 0: + download_percentage = int(bytes_received * 100 / bytes_total) + self.progress_dialog.progress_bar.setValue(download_percentage) diff --git a/view/checks/initial_checks.py b/view/checks/initial_checks.py new file mode 100644 index 00000000..d3755b28 --- /dev/null +++ b/view/checks/initial_checks.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +###### +# ----- +# Copyright (c) 2023 FIT-Project +# SPDX-License-Identifier: GPL-3.0-only +# ----- +###### + +import sys +import pkgutil +import importlib +from PyQt6 import QtCore +from view import checks + +from view.util import disable_network_functionality, enable_network_functionality + +from common.constants.view.tasks import status + +from view.checks.admin_privileges import AdminPrivilegesCheck + + +class InitialChecks(QtCore.QObject): + finished = QtCore.pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent) + self.predefined_order = [ + "NetworkCheck", + "AdminPrivilegesCheck", + "NpcapInstalledCheck", + "NvidiaGPUInstalledCheck", + "NewPortableVersionCheck", + ] + self.module_instances = self.__load_checks_modules() + self.current_check_index = 0 + self.__network_status = list() + + def run_checks(self): + self.__run_next_check() + + def __load_checks_modules(self): + module_instances = [] + for class_name in self.predefined_order: + for loader, module_name, is_pkg in pkgutil.iter_modules(checks.__path__): + full_module_name = f"{checks.__name__}.{module_name}" + module = importlib.import_module(full_module_name) + if hasattr(module, class_name): + cls = getattr(module, class_name) + instance = cls() + module_instances.append(instance) + break + return module_instances + + def __run_next_check(self): + if self.current_check_index < len(self.module_instances): + instance = self.module_instances[self.current_check_index] + instance.finished.connect(self.__handle_finished) + instance.run_check() + else: + self.finished.emit() + + def __handle_finished(self, result): + sender = self.sender() + class_name = sender.__class__.__name__ + + if result == status.FAIL: + if class_name == "NetworkCheck": + sys.exit(0) + elif class_name == "AdminPrivilegesCheck": + self.__network_status.append(result) + disable_network_functionality() + elif class_name == "NpcapInstalledCheck": + self.__network_status.append(result) + disable_network_functionality() + if result == status.SUCCESS: + if class_name == "AdminPrivilegesCheck": + self.__network_status.append(result) + elif class_name == "NpcapInstalledCheck": + self.__network_status.append(result) + + if len(self.__network_status) >= 2 and len(set(self.__network_status)) == 1: + enable_network_functionality() + + self.current_check_index += 1 + self.__run_next_check() diff --git a/view/checks/network.py b/view/checks/network.py new file mode 100644 index 00000000..f8af1a0a --- /dev/null +++ b/view/checks/network.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +###### +# ----- +# Copyright (c) 2023 FIT-Project +# SPDX-License-Identifier: GPL-3.0-only +# ----- +###### + + +import sys +from PyQt6 import QtCore, QtWidgets + +from view.checks.check import Check +from view.error import Error as ErrorView +from common.utility import check_internet_connection + +from common.constants.view.tasks import status +from common.constants.view.init import CHECK_CONNETION, ERR_INTERNET_DISCONNECTED + + +class NetworkCheck(Check): + def __init__(self, parent=None): + super().__init__(parent) + + def run_check(self): + if check_internet_connection() is False: + error_dlg = ErrorView( + QtWidgets.QMessageBox.Icon.Critical, + CHECK_CONNETION, + ERR_INTERNET_DISCONNECTED, + "", + ) + error_dlg.message.setStyleSheet("font-size: 13px;") + error_dlg.right_button.clicked.connect( + lambda: self.finished.emit(status.FAIL) + ) + + error_dlg.exec() + else: + self.finished.emit(status.SUCCESS) diff --git a/view/checks/new_portable_version.py b/view/checks/new_portable_version.py new file mode 100644 index 00000000..c4e7745d --- /dev/null +++ b/view/checks/new_portable_version.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +###### +# ----- +# Copyright (c) 2023 FIT-Project +# SPDX-License-Identifier: GPL-3.0-only +# ----- +###### + +import sys +import subprocess +import shutil +import os + +from PyQt6 import QtWidgets, QtCore + +from view.dialog import Dialog, DialogButtonTypes +from view.checks.download_and_save import DownloadAndSave +from view.error import Error as ErrorView +from view.checks.check import Check + +from common.constants.view.tasks import status + +from common.utility import ( + has_new_portable_version, + get_portable_download_url, + get_platform, + resolve_path, +) + +from common.constants.view.tasks import status +from common.constants.view.init import ( + FIT_NEW_VERSION_TITLE, + FIT_NEW_VERSION_MSG, + DOWNLOAD_URL_ERROR, + FIT_NEW_VERSION_DOWNLOAD_TITLE, + FIT_NEW_VERSION_DOWNLOAD_MSG, + FIT_NEW_VERSION_DOWNLOAD_ERROR, + FIT_NEW_VERSION_UNZIP_ERROR, + FIT_NEW_VERSION_EXCUTE_ERROR, + FIT_NEW_VERSION_INSTALLATION_TITLE, + FIT_NEW_VERSION_INSTALLATION_ERROR, + FIT_NEW_VERSION_INSTALLATION_SUCCESS, +) + + +class NewPortableVersionCheck(Check): + def __init__(self, parent=None): + super().__init__(parent) + + def run_check(self): + if getattr(sys, "frozen", False) and has_new_portable_version(): + dialog = Dialog( + FIT_NEW_VERSION_TITLE, + FIT_NEW_VERSION_MSG, + ) + dialog.message.setStyleSheet("font-size: 13px;") + dialog.set_buttons_type(DialogButtonTypes.QUESTION) + dialog.right_button.clicked.connect(lambda: self.__not_install(dialog)) + dialog.left_button.clicked.connect( + lambda: self.__download_portable_version(dialog) + ) + + dialog.exec() + else: + self.finished.emit(status.SUCCESS) + + def __not_install(self, dialog=None): + if dialog: + dialog.close() + self.finished.emit(status.SUCCESS) + + def __download_portable_version(self, dialog=None): + if dialog: + dialog.close() + try: + url = get_portable_download_url() + + if url is None: + error_dlg = ErrorView( + QtWidgets.QMessageBox.Icon.Critical, + FIT_NEW_VERSION_DOWNLOAD_TITLE, + DOWNLOAD_URL_ERROR, + ) + error_dlg.exec() + donwload_and_save = DownloadAndSave( + url, FIT_NEW_VERSION_DOWNLOAD_TITLE, FIT_NEW_VERSION_DOWNLOAD_MSG + ) + # donwload_and_save.finished.connect(self.__unzip_portable_zipfile) + donwload_and_save.finished.connect(self.__install_portable) + donwload_and_save.rejected.connect(self.__not_install) + donwload_and_save.exec() + except Exception as e: + error_dlg = ErrorView( + QtWidgets.QMessageBox.Icon.Critical, + FIT_NEW_VERSION_DOWNLOAD_TITLE, + FIT_NEW_VERSION_DOWNLOAD_ERROR, + str(e), + ) + error_dlg.exec() + + def __install_portable(self, file_path): + + app_dir = os.path.abspath(sys.executable) + + if get_platform() == "macos": + if app_dir.endswith(".app/Contents/MacOS"): + app_dir = os.path.dirname(os.path.dirname(os.path.dirname(app_dir))) + launch_script = resolve_path( + "assets/script/mac/install_new_portable_version.sh" + ) + args = [app_dir, file_path] + elif get_platform() == "win": + app_dir = os.path.dirname(app_dir) + launch_script = resolve_path( + "assets/script/win/install_new_portable_version.ps1" + ) + args = [app_dir, file_path] + elif sys.platform == "lin": + app_dir = os.path.dirname(app_dir) + launch_script = resolve_path( + "assets/script/lin/install_new_portable_version.sh" + ) + args = [app_dir, file_path] + + self.process = QtCore.QProcess(self) + self.process.errorOccurred.connect(self.__on_process_error) + + self.process.readyReadStandardError.connect(self.__capture_process_output) + self.process.readyReadStandardOutput.connect(self.__capture_process_output) + + self.process_output = "" # Buffer to store process output + + self.process.start(launch_script, args) + + self.process.waitForFinished() + + exit_code = self.process.exitCode() + if exit_code == 0: + message = FIT_NEW_VERSION_INSTALLATION_SUCCESS + severity = QtWidgets.QMessageBox.Icon.Information + else: + message = FIT_NEW_VERSION_INSTALLATION_ERROR + severity = QtWidgets.QMessageBox.Icon.Warning + + dialog = Dialog( + FIT_NEW_VERSION_INSTALLATION_TITLE, + message, + "", + severity, + ) + + dialog.message.setStyleSheet("font-size: 13px;") + dialog.set_buttons_type(DialogButtonTypes.MESSAGE) + if exit_code == 0: + dialog.right_button.clicked.connect(lambda: dialog.close()) + dialog.right_button.clicked.connect(self.__quit) + else: + dialog.right_button.clicked.connect(lambda: dialog.close()) + dialog.right_button.clicked.connect( + lambda: self.finished.emit(status.SUCCESS) + ) + + dialog.content_box.adjustSize() + + dialog.exec() + + def __quit(self): + try: + self.__cleanup() + except Exception as e: + pass + if hasattr(self, "process") and self.process is not None: + self.process.kill() + + sys.exit(0) + + def __on_process_error(self, error): + error_map = { + QtCore.QProcess.ProcessError.FailedToStart: "Failed to start the process.", + QtCore.QProcess.ProcessError.Crashed: "The process has crashed.", + QtCore.QProcess.ProcessError.Timedout: "The process timed out.", + QtCore.QProcess.ProcessError.WriteError: "Write error in the process.", + QtCore.QProcess.ProcessError.ReadError: "Read error from the process.", + QtCore.QProcess.ProcessError.UnknownError: "Unknown error.", + } + error_message = error_map.get(error, "Undefined error.") + + if self.debug_mode: + print(f"Error during process execution: {error_message}") + + def __capture_process_output(self): + self.process_output += self.process.readAllStandardError().data().decode() + self.process_output += self.process.readAllStandardOutput().data().decode() + if self.debug_mode: + print(self.process_output) diff --git a/view/checks/npcap_installed.py b/view/checks/npcap_installed.py new file mode 100644 index 00000000..8ce9b99e --- /dev/null +++ b/view/checks/npcap_installed.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +###### +# ----- +# Copyright (c) 2023 FIT-Project +# SPDX-License-Identifier: GPL-3.0-only +# ----- +###### + +import subprocess +import psutil +import time + +from PyQt6 import QtCore, QtWidgets + +from view.checks.check import Check + +from view.dialog import Dialog, DialogButtonTypes +from view.error import Error as ErrorView +from view.checks.download_and_save import DownloadAndSave + +from common.utility import is_npcap_installed, get_npcap_installer_url, get_platform +from common.constants.view.tasks import status +from common.constants.view.init import ( + NPCAP, + WAR_NPCAP_NOT_INSTALLED, + NPCAP_DOWNLOAD, + ERR_NPCAP_RELEASE_VERSION, + NPCAP_ERROR_DURING_INSTALLATION, +) + + +class NpcapInstalledCheck(Check): + def __init__(self, parent=None): + super().__init__(parent) + + def run_check(self): + if get_platform() == "win": + # Check if NPCAP is installed + if is_npcap_installed() is False: + dialog = Dialog( + NPCAP, + WAR_NPCAP_NOT_INSTALLED, + ) + dialog.message.setStyleSheet("font-size: 13px;") + dialog.set_buttons_type(DialogButtonTypes.QUESTION) + dialog.right_button.clicked.connect(lambda: self.__not_install(dialog)) + dialog.left_button.clicked.connect( + lambda: self.__download_npcap(dialog) + ) + + dialog.exec() + else: + self.finished.emit(status.SUCCESS) + + def __not_install(self, dialog=None): + if dialog: + dialog.close() + self.finished.emit(status.FAIL) + + def __download_npcap(self, dialog=None): + if dialog: + dialog.close() + try: + url = get_npcap_installer_url() + + self.ncap_process_name = QtCore.QUrl(url).path().split("/")[-1] + + donwload_and_save = DownloadAndSave(url, NPCAP, NPCAP_DOWNLOAD) + donwload_and_save.rejected.connect(self.__not_install) + donwload_and_save.finished.connect(self.__install_ncap) + donwload_and_save.exec() + except Exception as e: + error_dlg = ErrorView( + QtWidgets.QMessageBox.Icon.Critical, + NPCAP, + ERR_NPCAP_RELEASE_VERSION, + str(e), + ) + error_dlg.exec() + + def __install_ncap(self, file_path): + cmd = 'Powershell -Command Start-Process "{}" -Verb RunAs'.format(file_path) + try: + process = subprocess.run( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + process.check_returncode() + self.__monitoring_npcap_process_installer() + except Exception as e: + self.__not_install() + error_dlg = ErrorView( + QtWidgets.QMessageBox.Icon.Critical, + NPCAP, + NPCAP_ERROR_DURING_INSTALLATION, + str(e), + ) + error_dlg.exec() + + def __monitoring_npcap_process_installer(self): + pid = None + __is_npcap_installed = False + + for proc in psutil.process_iter(["pid", "name"]): + if proc.info["name"] == self.ncap_process_name: + pid = proc.info["pid"] + break + + if pid is not None: + try: + proc = psutil.Process(pid) + while True: + if not proc.is_running(): + __is_npcap_installed = is_npcap_installed() + break + time.sleep(1) + except psutil.NoSuchProcess as e: + raise Exception(e) + except Exception as e: + raise Exception(e) + + if __is_npcap_installed is False: + self.__not_install() + else: + self.finished.emit(status.SUCCESS) diff --git a/view/checks/nvidia_gpu_installed.py b/view/checks/nvidia_gpu_installed.py new file mode 100644 index 00000000..3db37ca8 --- /dev/null +++ b/view/checks/nvidia_gpu_installed.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +###### +# ----- +# Copyright (c) 2023 FIT-Project +# SPDX-License-Identifier: GPL-3.0-only +# ----- +###### + +from PyQt6 import QtWidgets + +from view.dialog import Dialog, DialogButtonTypes +from view.clickable_label import ClickableLabel as ClickableLabelView +from view.checks.check import Check + +from common.utility import is_nvidia_gpu_installed + +from common.constants.view.tasks import status +from common.constants.view.init import ( + NVIDIA_GPU_PRESENT_TITLE, + NVIDIA_GPU_PRESENT_MSG, + NVIDIA_GPU_GUIDE_URL, + NVIDIA_GPU_GUIDE, +) + + +class NvidiaGPUInstalledCheck(Check): + def __init__(self, parent=None): + super().__init__(parent) + + def run_check(self): + if is_nvidia_gpu_installed(): + dialog = Dialog( + NVIDIA_GPU_PRESENT_TITLE, + NVIDIA_GPU_PRESENT_MSG, + "", + QtWidgets.QMessageBox.Icon.Warning, + ) + dialog.message.setStyleSheet("font-size: 13px;") + dialog.set_buttons_type(DialogButtonTypes.MESSAGE) + dialog.right_button.clicked.connect(lambda: dialog.close()) + dialog.right_button.clicked.connect( + lambda: self.finished.emit(status.SUCCESS) + ) + dialog.text_box.addWidget( + ClickableLabelView(NVIDIA_GPU_GUIDE_URL, NVIDIA_GPU_GUIDE) + ) + + dialog.content_box.adjustSize() + + dialog.exec() + else: + self.finished.emit(status.SUCCESS) diff --git a/view/init.py b/view/init.py deleted file mode 100644 index 23e06722..00000000 --- a/view/init.py +++ /dev/null @@ -1,459 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- -###### -# ----- -# Copyright (c) 2023 FIT-Project -# SPDX-License-Identifier: GPL-3.0-only -# ----- -###### - -import subprocess -import psutil -import time -import shutil - -from PyQt6 import QtCore, QtWidgets, QtWebEngineWidgets - -from view.error import Error as ErrorView -from view.dialog import Dialog, DialogButtonTypes -from view.clickable_label import ClickableLabel as ClickableLabelView - -from controller.configurations.tabs.packetcapture.packetcapture import PacketCapture -from controller.configurations.tabs.network.networktools import NetworkTools - -from common.utility import * -from common.constants.view.init import * -from common.constants.view.general import * -from common.constants.view.tasks import status - - -class DownloadAndSave(QtWidgets.QDialog): - finished = QtCore.pyqtSignal(str) - - def __init__( - self, url, progress_dialog_title, progress_dialog_message, parent=None - ): - super(DownloadAndSave, self).__init__(parent) - - self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint) - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground) - - self.file_path = None - - self.filename = QtCore.QUrl(url).path() - self.suffix = QtCore.QFileInfo(self.filename).suffix() - - self.progress_dialog = Dialog( - progress_dialog_title, - progress_dialog_message, - ) - self.progress_dialog.message.setStyleSheet("font-size: 13px;") - self.progress_dialog.set_buttons_type(DialogButtonTypes.NONE) - self.progress_dialog.show_progress_bar() - self.progress_dialog.progress_bar.setValue(0) - - self.web_view = QtWebEngineWidgets.QWebEngineView() - self.web_view.page().profile().downloadRequested.connect( - self.on_download_requested - ) - - self.web_view.load(QtCore.QUrl(url)) - self.web_view.hide() - - def on_download_requested(self, download): - self.file_path, _ = QtWidgets.QFileDialog.getSaveFileName( - self, "Save File", self.filename, "*." + self.suffix - ) - - if self.file_path: - download.setDownloadFileName(self.file_path) - download.accept() - download.isFinishedChanged.connect(self.__is_download_finished) - download.receivedBytesChanged.connect( - lambda: self.__progress( - download.receivedBytes(), - download.totalBytes(), - ) - ) - download.totalBytesChanged.connect( - lambda: self.__progress( - download.receivedBytes(), - download.totalBytes(), - ) - ) - self.progress_dialog.show() - else: - self.reject() - - def __is_download_finished(self): - self.close() - self.progress_dialog.close() - self.finished.emit(self.file_path) - - def __progress(self, bytes_received, bytes_total): - if bytes_total > 0: - download_percentage = int(bytes_received * 100 / bytes_total) - self.progress_dialog.progress_bar.setValue(download_percentage) - - -class Init(QtCore.QObject): - finished = QtCore.pyqtSignal() - - def __init__(self, parent=None): - super().__init__(parent) - self.is_finsished = True - self.process = None - - def __del__(self): - if ( - hasattr(self, "process") - and self.process.state() != QtCore.QProcess.ProcessState.NotRunning - ): - self.process.kill() - self.process.waitForFinished() - - def __quit(self): - try: - self.__cleanup() - except Exception as e: - pass - if hasattr(self, "process") and self.process is not None: - self.process.kill() - - sys.exit(0) - - def __enable_network_functionality(self): - configuration = NetworkTools().configuration - if configuration.get("traceroute") is False: - configuration["traceroute"] = True - NetworkTools().configuration = configuration - - options = PacketCapture().options - if options.get("enabled") is False: - options["enabled"] = True - PacketCapture().options = options - - def __disable_network_functionality(self, dialog=None): - if dialog: - dialog.close() - - configuration = NetworkTools().configuration - if configuration.get("traceroute") is True: - configuration["traceroute"] = False - NetworkTools().configuration = configuration - - options = PacketCapture().options - if options.get("enabled") is True: - options["enabled"] = False - PacketCapture().options = options - - def __download_npcap(self, dialog=None): - if dialog: - dialog.close() - try: - url = get_npcap_installer_url() - - self.ncap_process_name = QtCore.QUrl(url).path().split("/")[-1] - - donwload_and_save = DownloadAndSave(url, NPCAP, NPCAP_DOWNLOAD) - donwload_and_save.rejected.connect(self.__disable_network_functionality) - donwload_and_save.finished.connect(self.__install_ncap) - donwload_and_save.exec() - except Exception as e: - error_dlg = ErrorView( - QtWidgets.QMessageBox.Icon.Critical, - NPCAP, - ERR_NPCAP_RELEASE_VERSION, - str(e), - ) - error_dlg.exec() - - def __install_ncap(self, file_path): - cmd = 'Powershell -Command Start-Process "{}" -Verb RunAs'.format(file_path) - try: - process = subprocess.run( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - ) - process.check_returncode() - self.__monitoring_npcap_process_installer() - except Exception as e: - self.__disable_network_functionality() - error_dlg = ErrorView( - QtWidgets.QMessageBox.Icon.Critical, - NPCAP, - NPCAP_ERROR_DURING_INSTALLATION, - str(e), - ) - error_dlg.exec() - - def __monitoring_npcap_process_installer(self): - pid = None - __is_npcap_installed = False - - for proc in psutil.process_iter(["pid", "name"]): - if proc.info["name"] == self.ncap_process_name: - pid = proc.info["pid"] - break - - if pid is not None: - try: - proc = psutil.Process(pid) - while True: - if not proc.is_running(): - __is_npcap_installed = is_npcap_installed() - break - time.sleep(1) - except psutil.NoSuchProcess as e: - raise Exception(e) - except Exception as e: - raise Exception(e) - - if __is_npcap_installed is False: - self.__disable_network_functionality() - else: - self.__enable_network_functionality() - - def __download_portable_version(self, dialog=None): - if dialog: - dialog.close() - try: - url = get_portable_download_url() - if url is None: - raise ValueError(DOWNLOAD_URL_ERROR) - donwload_and_save = DownloadAndSave( - url, FIT_NEW_VERSION_DOWNLOAD_TITLE, FIT_NEW_VERSION_DOWNLOAD_MSG - ) - donwload_and_save.finished.connect(self.__unzip_portable_zipfile) - donwload_and_save.exec() - except Exception as e: - error_dlg = ErrorView( - QtWidgets.QMessageBox.Icon.Critical, - FIT_NEW_VERSION_DOWNLOAD_TITLE, - FIT_NEW_VERSION_DOWNLOAD_ERROR, - str(e), - ) - error_dlg.exec() - - def __unzip_portable_zipfile(self, file_path): - unzip_path = os.path.splitext(file_path)[0] - try: - shutil.unpack_archive(file_path, unzip_path) - self.__execute_portable_version(unzip_path) - except Exception as e: - error_dlg = ErrorView( - QtWidgets.QMessageBox.Icon.Critical, - FIT_NEW_VERSION_DOWNLOAD_TITLE, - FIT_NEW_VERSION_UNZIP_ERROR, - str(e), - ) - error_dlg.exec() - - def __execute_portable_version(self, path): - - excutable = None - if get_platform() == "win": - excutable = os.path.join(path, "fit.exe") - - current_directory = os.getcwd() - - if excutable is not None: - # Change working directory - os.chdir(path) - cmd = 'Powershell -Command Start-Process "{}" -Verb RunAs'.format(excutable) - try: - process = subprocess.run( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - ) - process.check_returncode() - self.__quit() - except Exception as e: - # Change working directory - os.chdir(current_directory) - error_dlg = ErrorView( - QtWidgets.QMessageBox.Icon.Critical, - FIT_NEW_VERSION_DOWNLOAD_TITLE, - FIT_NEW_VERSION_EXCUTE_ERROR, - str(e), - ) - error_dlg.exec() - - else: - error_dlg = ErrorView( - QtWidgets.QMessageBox.Icon.Critical, - FIT_NEW_VERSION_DOWNLOAD_TITLE, - FIT_NEW_VERSION_EXCUTE_ERROR, - "No excutable path found", - ) - error_dlg.exec() - - def __run_fit_with_privileges(self, dialog=None): - if dialog: - dialog.close() - - loop = QtCore.QEventLoop() - QtCore.QTimer.singleShot(500, loop.quit) - loop.exec() - - self.is_finsished = False - - current_app = self.__get_current_app_path() - python_path = sys.executable - - if get_platform() == "macos": - launch_script = resolve_path( - "assets/script/mac/launch_fit_with_privileges.sh" - ) - args = [python_path, current_app] - elif get_platform() == "win": - launch_script = resolve_path( - "assets/script/win/launch_fit_with_privileges.bat" - ) - args = [python_path, current_app] - elif sys.platform == "lin": - launch_script = resolve_path( - "assets/script/lin/launch_fit_with_privileges.sh" - ) - args = [python_path, current_app] - else: - raise OSError("Sistema operativo non supportato.") - - self.process = QtCore.QProcess(self) - - self.process.started.connect(self.__on_process_started) - self.process.errorOccurred.connect(self.__on_process_error) - - self.process.start(launch_script, args) - - def __on_process_started(self): - QtCore.QTimer.singleShot(1000, self.__quit) - - def __cleanup(self): - if ( - hasattr(self, "process") - and self.process.state() != QtCore.QProcess.ProcessState.NotRunning - ): - self.process.terminate() - self.process.waitForFinished() - - def __on_process_error(self, error): - error_map = { - QtCore.QProcess.ProcessError.FailedToStart: "Failed to start the process.", - QtCore.QProcess.ProcessError.Crashed: "The process has crashed.", - QtCore.QProcess.ProcessError.Timedout: "The process timed out.", - QtCore.QProcess.ProcessError.WriteError: "Write error in the process.", - QtCore.QProcess.ProcessError.ReadError: "Read error from the process.", - QtCore.QProcess.ProcessError.UnknownError: "Unknown error.", - } - error_message = error_map.get(error, "Undefined error.") - - debug_mode = "--debug" in QtWidgets.QApplication.instance().arguments() - if debug_mode: - print(f"Error during process execution: {error_message}") - - def __get_current_app_path(self): - if getattr(sys, "frozen", False): - return os.path.abspath(sys.executable) - else: - return os.path.abspath(sys.argv[0]) - - def init_check(self): - - # Check internet connection - if check_internet_connection() is False: - error_dlg = ErrorView( - QtWidgets.QMessageBox.Icon.Critical, - CHECK_CONNETION, - ERR_INTERNET_DISCONNECTED, - "", - ) - error_dlg.message.setStyleSheet("font-size: 13px;") - error_dlg.right_button.clicked.connect(self.__quit) - - error_dlg.exec() - - # Check admin privileges - if is_admin() is False: - dialog = Dialog(USER_IS_NOT_ADMIN_TITLE, USER_IS_NOT_ADMIN_MSG) - dialog.message.setStyleSheet("font-size: 13px;") - dialog.set_buttons_type(DialogButtonTypes.QUESTION) - dialog.right_button.clicked.connect( - lambda: self.__disable_network_functionality(dialog) - ) - dialog.left_button.clicked.connect( - lambda: self.__run_fit_with_privileges(dialog) - ) - - dialog.content_box.adjustSize() - - dialog.exec() - else: - self.__enable_network_functionality() - - if get_platform() == "win": - # Check if NPCAP is installed - if is_npcap_installed() is False: - dialog = Dialog( - NPCAP, - WAR_NPCAP_NOT_INSTALLED, - ) - dialog.message.setStyleSheet("font-size: 13px;") - dialog.set_buttons_type(DialogButtonTypes.QUESTION) - dialog.right_button.clicked.connect( - lambda: self.__disable_network_functionality(dialog) - ) - dialog.left_button.clicked.connect( - lambda: self.__download_npcap(dialog) - ) - - dialog.exec() - - if is_nvidia_gpu_present(): - dialog = Dialog( - NVIDIA_GPU_PRESENT_TITLE, - NVIDIA_GPU_PRESENT_MSG, - "", - QtWidgets.QMessageBox.Icon.Warning, - ) - dialog.message.setStyleSheet("font-size: 13px;") - dialog.set_buttons_type(DialogButtonTypes.MESSAGE) - dialog.right_button.clicked.connect(lambda: dialog.close()) - dialog.text_box.addWidget( - ClickableLabelView(NVIDIA_GPU_GUIDE_URL, NVIDIA_GPU_GUIDE) - ) - - dialog.content_box.adjustSize() - - dialog.exec() - - # Check there is a new portable version of FIT - if getattr(sys, "frozen", False) and has_new_portable_version(): - dialog = Dialog( - FIT_NEW_VERSION_TITLE, - FIT_NEW_VERSION_MSG, - ) - dialog.message.setStyleSheet("font-size: 13px;") - dialog.set_buttons_type(DialogButtonTypes.QUESTION) - dialog.right_button.clicked.connect(dialog.close) - dialog.left_button.clicked.connect( - lambda: self.__download_portable_version(dialog) - ) - - dialog.exec() - if self.is_finsished: - self.finished.emit() - - def closeEvent(self, event): - if ( - hasattr(self, "process") - and self.process.state() != QtCore.QProcess.ProcessState.NotRunning - ): - self.process.terminate() - if not self.process.waitForFinished(3000): # Attendi fino a 3 secondi - self.process.kill() - event.accept() diff --git a/view/util.py b/view/util.py index 01366360..ed2e4684 100644 --- a/view/util.py +++ b/view/util.py @@ -21,10 +21,14 @@ from view.dialog import Dialog, DialogButtonTypes from view.tasks.tasks_info import TasksInfo +from controller.configurations.tabs.packetcapture.packetcapture import PacketCapture +from controller.configurations.tabs.network.networktools import NetworkTools + from common.utility import get_platform, is_cmd from common.constants import logger, details + from common.constants.view import verify_pec, verify_pdf_timestamp, case from common.constants.view.tasks import status from enum import Enum, auto @@ -298,3 +302,27 @@ def resolve_db_path(path): resolve_db_path = os.path.abspath(os.path.join(os.getcwd(), path)) return resolve_db_path + + +def enable_network_functionality(): + configuration = NetworkTools().configuration + if configuration.get("traceroute") is False: + configuration["traceroute"] = True + NetworkTools().configuration = configuration + + options = PacketCapture().options + if options.get("enabled") is False: + options["enabled"] = True + PacketCapture().options = options + + +def disable_network_functionality(): + configuration = NetworkTools().configuration + if configuration.get("traceroute") is True: + configuration["traceroute"] = False + NetworkTools().configuration = configuration + + options = PacketCapture().options + if options.get("enabled") is True: + options["enabled"] = False + PacketCapture().options = options