From 4b3079733b4f25a1f2506ebc10a8d7276108a4a7 Mon Sep 17 00:00:00 2001 From: BarsTiger Date: Thu, 27 Jan 2022 19:46:10 +0200 Subject: [PATCH] GUI development --- horsygui.py | 6 +- modules/gui.py | 61 +++--------------- modules/gui_manager.py | 136 ++++++++++++++++++++++------------------- modules/liker.py | 1 + modules/unerrored.py | 24 ++++++++ modules/virustotal.py | 11 +++- uis/horsy_download.py | 55 ++--------------- uis/horsy_download.ui | 104 ++++++------------------------- 8 files changed, 143 insertions(+), 255 deletions(-) create mode 100644 modules/unerrored.py diff --git a/horsygui.py b/horsygui.py index 8ce40bb..cb95a0a 100644 --- a/horsygui.py +++ b/horsygui.py @@ -47,8 +47,8 @@ def update_app(): if app_name == "": return else: - from modules.manager import install - install(app_name, True) + from modules.gui_manager import install + install(app_name) except: return @@ -84,7 +84,7 @@ def install_app(): if app_name == "": return else: - gui.popup("Installation", str(install(app_name))) + install(app_name) except: return diff --git a/modules/gui.py b/modules/gui.py index ffec9ea..6cbc062 100644 --- a/modules/gui.py +++ b/modules/gui.py @@ -750,68 +750,25 @@ class Ui_LoginWindow(object): class Ui_DownloadWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(682, 184) - MainWindow.setMinimumSize(QtCore.QSize(682, 184)) - MainWindow.setMaximumSize(QtCore.QSize(682, 184)) + MainWindow.resize(682, 252) + MainWindow.setMinimumSize(QtCore.QSize(682, 252)) + MainWindow.setMaximumSize(QtCore.QSize(682, 252)) MainWindow.setStyleSheet("QWidget{\n" " background-color: rgb(30, 30, 30);\n" "}\n" "") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") - self.progressBar_1 = QtWidgets.QProgressBar(self.centralwidget) - self.progressBar_1.setGeometry(QtCore.QRect(30, 80, 621, 23)) - self.progressBar_1.setStyleSheet("QProgressBar { \n" - "font: 14pt;\n" - "color: rgb(200, 200, 200);\n" - "border: 2px solid grey;\n" - "text-align: center;\n" - "background-color: rgb(74, 76, 83);\n" - "}\n" - "QProgressBar::chunk {\n" - " background-color: rgb(54, 99, 197);\n" - " margin: 0.5px;\n" - "}") - self.progressBar_1.setProperty("value", 0) - self.progressBar_1.setObjectName("progressBar_1") self.logs_box = QtWidgets.QTextBrowser(self.centralwidget) - self.logs_box.setGeometry(QtCore.QRect(30, 20, 621, 41)) + self.logs_box.setGeometry(QtCore.QRect(20, 20, 641, 211)) + self.logs_box.setMinimumSize(QtCore.QSize(0, 0)) + self.logs_box.setMaximumSize(QtCore.QSize(1000, 1000)) self.logs_box.setStyleSheet("background-color: rgb(74, 76, 83);\n" "border-radius: 5px; \n" "color: rgb(242, 242, 242);") self.logs_box.setAcceptRichText(False) - self.logs_box.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) + self.logs_box.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) self.logs_box.setObjectName("logs_box") - self.progressBar_2 = QtWidgets.QProgressBar(self.centralwidget) - self.progressBar_2.setGeometry(QtCore.QRect(30, 110, 621, 23)) - self.progressBar_2.setStyleSheet("QProgressBar { \n" - "font: 14pt;\n" - "color: rgb(200, 200, 200);\n" - "border: 2px solid grey;\n" - "text-align: center;\n" - "background-color: rgb(74, 76, 83);\n" - "}\n" - "QProgressBar::chunk {\n" - " background-color: rgb(54, 99, 197);\n" - " margin: 0.5px;\n" - "}") - self.progressBar_2.setProperty("value", 0) - self.progressBar_2.setObjectName("progressBar_2") - self.progressBar_3 = QtWidgets.QProgressBar(self.centralwidget) - self.progressBar_3.setGeometry(QtCore.QRect(30, 140, 621, 23)) - self.progressBar_3.setStyleSheet("QProgressBar { \n" - " font: 14pt;\n" - " color: rgb(200, 200, 200);\n" - " border: 2px solid grey;\n" - " text-align: center;\n" - " background-color: rgb(74, 76, 83);\n" - "}\n" - "QProgressBar::chunk {\n" - " background-color: rgb(54, 99, 197);\n" - " margin: 0.5px;\n" - "}") - self.progressBar_3.setProperty("value", 0) - self.progressBar_3.setObjectName("progressBar_3") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) @@ -828,9 +785,9 @@ class Ui_DownloadWindow(object): "


")) self.logs_box.setPlaceholderText(_translate("MainWindow", "Logs")) - def popup(title, text): - QtWidgets.QMessageBox.information(QtWidgets.QMainWindow(), title, text) + + QtWidgets.QMessageBox.information(None, title, text) if __name__ == "__main__": import sys diff --git a/modules/gui_manager.py b/modules/gui_manager.py index 06adad2..dda9b28 100644 --- a/modules/gui_manager.py +++ b/modules/gui_manager.py @@ -1,31 +1,38 @@ import json import threading +import time +from modules.unerrored import run_threaded, run import requests import modules.vars as horsy_vars import os import zipfile from modules.virustotal import get_key, scan_file, get_report from horsygui import UiDownloadWindow, download_ui +from modules.gui import popup +success = 0 def install(package): + global success r = requests.get(f"{horsy_vars.protocol}{horsy_vars.server_url}/packages/json/{package}").text if r == "": + run_threaded(popup("Installation", f"Package {package} not found")) return f"Package {package} not found" try: r = json.loads(r) except: print("[red]Error with unsupported message[/]") + run_threaded(popup("Error", "Error with unsupported message")) return "Error with unsupported message" try: if r["message"] == "Internal server error": print("[red]Internal server error[/]") + run_threaded(popup("Error", "Internal server error")) return "Internal server error" except: pass try: - print(f"[green]App {r['name']} found, information loaded[/]") UiDownloadWindow.show() if not os.path.exists('{1}apps/{0}'.format(r['name'], horsy_vars.horsypath)): @@ -33,55 +40,50 @@ def install(package): download_ui.logs_box.clear() download_ui.logs_box.append(f"Downloading {r['url'].split('/')[-1]}") - success = 0 - def dl_main_file(success): + def dl_main_file(): + global success UiDownloadWindow.show() file_r = requests.get(r['url'], stream=True) chunk_size = int(int(file_r.headers['Content-Length']) / 100) + percent = 0 with open('{2}apps/{0}/{1}'.format(r['name'], r['url'].split('/')[-1], horsy_vars.horsypath), "wb") as f: for chunk in file_r.iter_content(chunk_size=chunk_size): if chunk: - download_ui.progressBar_1.setValue(download_ui.progressBar_1.value() + 1) + percent += 1 f.write(chunk) - download_ui.progressBar_1.setValue(0) - success += 1 + # download_ui.progress_box_1.setText(f"{percent}% {'|' * percent}") - threading.Thread(target=dl_main_file, args=(success,)).start() + if not get_key(): + download_ui.logs_box.append("Virustotal api key not found \n" + "You can add it by entering horsy --vt in terminal") + else: + download_ui.logs_box.append("If you want to disable scan, type horsy --vt disable in terminal") + scan_file('{2}apps/{0}/{1}'.format(r['name'], r['url'].split('/')[-1], horsy_vars.horsypath)) + analysis = get_report('{2}apps/{0}/{1}'.format(r['name'], r['url'].split('/')[-1], + horsy_vars.horsypath)) + download_ui.logs_box.append(f"Scan finished for program \nYou can see report by opening: " + f"{analysis['link']} \n" + f"{analysis['detect']['malicious']} antivirus flagged this file as malicious") - print(f"Starting virustotal scan") - if not get_key(): - print(f"[red]Virustotal api key not found[/]") - print(f"You can add it by entering [bold]horsy --vt \[your key][/] in terminal") - else: - print(f"[green]Virustotal api key found[/]") - print(f"[italic white]If you want to disable scan, type [/][bold]horsy --vt disable[/]" - f"[italic white] in terminal[/]") - scan_file('{2}apps/{0}/{1}'.format(r['name'], r['url'].split('/')[-1], horsy_vars.horsypath)) - print(f"[green]Virustotal scan finished[/]") - analysis = get_report('{2}apps/{0}/{1}'.format(r['name'], r['url'].split('/')[-1], - horsy_vars.horsypath)) - print(f"[green]You can see report by opening: [white]{analysis['link']}[/]") - print(f"{analysis['detect']['malicious']} antivirus flagged this file as malicious") + def unzip(file, where): + with zipfile.ZipFile(file, 'r') as zip_ref: + zip_ref.extractall(where) + print(f"Extracted") - print(f"[green][OK] Done[/]") + if r['url'].split('.')[-1] == 'zip': + print(f"Extracting {r['url'].split('/')[-1]}") + unzip('{2}apps/{0}/{1}'.format(r['name'], r['url'].split('/')[-1], horsy_vars.horsypath), + '{1}apps/{0}'.format(r['name'], horsy_vars.horsypath)) - def unzip(file, where): - with zipfile.ZipFile(file, 'r') as zip_ref: - zip_ref.extractall(where) - print(f"[green]Extracted[/]") + success += 1 - if r['url'].split('.')[-1] == 'zip': - print(f"Extracting {r['url'].split('/')[-1]}") - unzip('{2}apps/{0}/{1}'.format(r['name'], r['url'].split('/')[-1], horsy_vars.horsypath), - '{1}apps/{0}'.format(r['name'], horsy_vars.horsypath)) + threads = list() + threads.append(threading.Thread(target=dl_main_file)) if r['download']: - print(f"Found dependency") - # if not is_gui: - print(f"Downloading {r['download'].split('/')[-1]}") - - def dl_dep_file(success): + def dl_dep_file(): + global success download_ui.logs_box.append(f"Downloading {r['download'].split('/')[-1]}") file_r = requests.get(r['download'], stream=True) chunk_size = int(int(file_r.headers['Content-Length']) / 100) @@ -89,46 +91,52 @@ def install(package): "wb") as f: for chunk in file_r.iter_content(chunk_size=chunk_size): if chunk: - download_ui.progressBar_2.setValue(download_ui.progressBar_2.value() + 1) f.write(chunk) - download_ui.progressBar_2.setValue(0) - success += 1 + download_ui.logs_box.append(f"Starting virustotal scan for dependency") + if not get_key(): + download_ui.logs_box.append(f"Virustotal api key not found") + download_ui.logs_box.append(f"You can add it by entering horsy --vt in terminal") + else: + scan_file('{2}apps/{0}/{1}'.format(r['name'], r['download'].split('/')[-1], horsy_vars.horsypath)) + download_ui.logs_box.append(f"Virustotal scan finished for dependency") + analysis = get_report('{2}apps/{0}/{1}'.format(r['name'], r['download'].split('/')[-1], + horsy_vars.horsypath)) + download_ui.logs_box.append(f"You can see report for dependency by opening: {analysis['link']}") + download_ui.logs_box.append(f"{analysis['detect']['malicious']} " + f"antivirus flagged this file as malicious") + if analysis['detect']['malicious'] > 0: + download_ui.logs_box.append(f"Dependency can be malicious. " + f"It may run now, if this added to installation config") + download_ui.logs_box.append(f"You can disable VT check with horsy --vt disable \n" + f"or use horsy CLI to force install") + success -= 1 + return - threading.Thread(target=dl_dep_file, args=(success,)).start() + success += 1 - print(f"Starting virustotal scan") - if not get_key(): - print(f"[red]Virustotal api key not found[/]") - print(f"You can add it by entering [italic white]horsy --vt \[your key][/] in terminal") - else: - print(f"[green]Virustotal api key found[/]") - scan_file('{2}apps/{0}/{1}'.format(r['name'], r['download'].split('/')[-1], horsy_vars.horsypath)) - print(f"[green]Virustotal scan finished[/]") - analysis = get_report('{2}apps/{0}/{1}'.format(r['name'], r['download'].split('/')[-1], - horsy_vars.horsypath)) - print(f"[green]You can see report by opening: [white]{analysis['link']}[/]") - print(f"{analysis['detect']['malicious']} antivirus flagged this file as malicious") - if analysis['detect']['malicious'] > 0: - print(f"[red]Dependency can be malicious. It may run now, if this added to installation " - f"config[/]") - input("Press enter if you want continue, or ctrl+c to exit") + threads.append(threading.Thread(target=dl_dep_file)) - if r['install']: - print(f"Found install option") - threading.Thread(target=os.system, args=('{2}apps/{0}/{1}'.format(r['name'], r['install'], - horsy_vars.horsypath),)).start() - - print(f"Generating launch script") + for t in threads: + t.start() with open('{1}apps/{0}.bat'.format(r['name'], horsy_vars.horsypath), 'w') as f: f.write(f"@ECHO off\n") f.write(f"{horsy_vars.horsypath}apps/{r['name']}/{r['run']} %*\n") - return f"All done!\n You can run your app by entering {r['name']} in terminal" + def wait_for_success(): + while success != 2: + time.sleep(1) + if success == 2: + if r['install']: + download_ui.logs_box.append(f"Found install option") + threading.Thread(target=os.system, args=('{2}apps/{0}/{1}'.format(r['name'], r['install'], + horsy_vars.horsypath),)).start() + download_ui.logs_box.append(f"All done!\n You can run your app by entering {r['name']} in terminal") + return + threading.Thread(target=wait_for_success).start() except: - raise - return "Unexpected error" + pass def uninstall(package, is_gui=False): diff --git a/modules/liker.py b/modules/liker.py index e69de29..ef57f58 100644 --- a/modules/liker.py +++ b/modules/liker.py @@ -0,0 +1 @@ +print("|"*100) \ No newline at end of file diff --git a/modules/unerrored.py b/modules/unerrored.py new file mode 100644 index 0000000..85c9367 --- /dev/null +++ b/modules/unerrored.py @@ -0,0 +1,24 @@ +import threading +import subprocess +import time + + +def run(func, *args): + try: + subprocess.Popen(func, *args, shell=True) + except: + time.sleep(5) + + +def run_threaded(func, *args): + try: + threading.Thread(target=func, args=args).start() + except: + time.sleep(5) + + +def run_old(func, *args): + try: + func(args) + except: + pass diff --git a/modules/virustotal.py b/modules/virustotal.py index aff4d7b..0bcb12a 100644 --- a/modules/virustotal.py +++ b/modules/virustotal.py @@ -49,6 +49,13 @@ def get_report(filename): headers = {'x-apikey': get_key()} response = requests.get(api_url, headers=headers) analysis = dict() - analysis['detect'] = response.json()['data']['attributes']['last_analysis_stats'] - analysis['link'] = 'https://www.virustotal.com/gui/file/' + response.json()['data']['id'] + try: + analysis['detect'] = response.json()['data']['attributes']['last_analysis_stats'] + except: + analysis['detect'] = 'No data' + try: + analysis['link'] = 'https://www.virustotal.com/gui/file/' + response.json()['data']['id'] + except: + analysis['link'] = 'No data' + return analysis diff --git a/uis/horsy_download.py b/uis/horsy_download.py index 00efcb6..17f1c50 100644 --- a/uis/horsy_download.py +++ b/uis/horsy_download.py @@ -14,68 +14,25 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(682, 184) - MainWindow.setMinimumSize(QtCore.QSize(682, 184)) - MainWindow.setMaximumSize(QtCore.QSize(682, 184)) + MainWindow.resize(682, 252) + MainWindow.setMinimumSize(QtCore.QSize(682, 252)) + MainWindow.setMaximumSize(QtCore.QSize(682, 252)) MainWindow.setStyleSheet("QWidget{\n" " background-color: rgb(30, 30, 30);\n" "}\n" "") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") - self.progressBar_1 = QtWidgets.QProgressBar(self.centralwidget) - self.progressBar_1.setGeometry(QtCore.QRect(30, 80, 621, 23)) - self.progressBar_1.setStyleSheet("QProgressBar { \n" -"font: 14pt;\n" -"color: rgb(200, 200, 200);\n" -"border: 2px solid grey;\n" -"text-align: center;\n" -"background-color: rgb(74, 76, 83);\n" -"}\n" -"QProgressBar::chunk {\n" -" background-color: rgb(54, 99, 197);\n" -" margin: 0.5px;\n" -"}") - self.progressBar_1.setProperty("value", 0) - self.progressBar_1.setObjectName("progressBar_1") self.logs_box = QtWidgets.QTextBrowser(self.centralwidget) - self.logs_box.setGeometry(QtCore.QRect(30, 20, 621, 41)) + self.logs_box.setGeometry(QtCore.QRect(20, 20, 641, 211)) + self.logs_box.setMinimumSize(QtCore.QSize(0, 0)) + self.logs_box.setMaximumSize(QtCore.QSize(1000, 1000)) self.logs_box.setStyleSheet("background-color: rgb(74, 76, 83);\n" "border-radius: 5px; \n" "color: rgb(242, 242, 242);") self.logs_box.setAcceptRichText(False) self.logs_box.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) self.logs_box.setObjectName("logs_box") - self.progressBar_2 = QtWidgets.QProgressBar(self.centralwidget) - self.progressBar_2.setGeometry(QtCore.QRect(30, 110, 621, 23)) - self.progressBar_2.setStyleSheet("QProgressBar { \n" -"font: 14pt;\n" -"color: rgb(200, 200, 200);\n" -"border: 2px solid grey;\n" -"text-align: center;\n" -"background-color: rgb(74, 76, 83);\n" -"}\n" -"QProgressBar::chunk {\n" -" background-color: rgb(54, 99, 197);\n" -" margin: 0.5px;\n" -"}") - self.progressBar_2.setProperty("value", 0) - self.progressBar_2.setObjectName("progressBar_2") - self.progressBar_3 = QtWidgets.QProgressBar(self.centralwidget) - self.progressBar_3.setGeometry(QtCore.QRect(30, 140, 621, 23)) - self.progressBar_3.setStyleSheet("QProgressBar { \n" -" font: 14pt;\n" -" color: rgb(200, 200, 200);\n" -" border: 2px solid grey;\n" -" text-align: center;\n" -" background-color: rgb(74, 76, 83);\n" -"}\n" -"QProgressBar::chunk {\n" -" background-color: rgb(54, 99, 197);\n" -" margin: 0.5px;\n" -"}") - self.progressBar_3.setProperty("value", 0) - self.progressBar_3.setObjectName("progressBar_3") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) diff --git a/uis/horsy_download.ui b/uis/horsy_download.ui index 1b6ff41..fceef56 100644 --- a/uis/horsy_download.ui +++ b/uis/horsy_download.ui @@ -7,19 +7,19 @@ 0 0 682 - 184 + 252 682 - 184 + 252 682 - 184 + 252 @@ -32,41 +32,27 @@ - - - - 30 - 80 - 621 - 23 - - - - QProgressBar { -font: 14pt; -color: rgb(200, 200, 200); -border: 2px solid grey; -text-align: center; -background-color: rgb(74, 76, 83); -} -QProgressBar::chunk { - background-color: rgb(54, 99, 197); - margin: 0.5px; -} - - - 0 - - - 30 + 20 20 - 621 - 41 + 641 + 211 + + + 0 + 0 + + + + + 1000 + 1000 + + background-color: rgb(74, 76, 83); border-radius: 5px; @@ -83,64 +69,12 @@ p, li { white-space: pre-wrap; } false - Qt::NoTextInteraction + Qt::TextSelectableByMouse Logs - - - - 30 - 110 - 621 - 23 - - - - QProgressBar { -font: 14pt; -color: rgb(200, 200, 200); -border: 2px solid grey; -text-align: center; -background-color: rgb(74, 76, 83); -} -QProgressBar::chunk { - background-color: rgb(54, 99, 197); - margin: 0.5px; -} - - - 0 - - - - - - 30 - 140 - 621 - 23 - - - - QProgressBar { - font: 14pt; - color: rgb(200, 200, 200); - border: 2px solid grey; - text-align: center; - background-color: rgb(74, 76, 83); -} -QProgressBar::chunk { - background-color: rgb(54, 99, 197); - margin: 0.5px; -} - - - 0 - -