Spaces:
No application file
No application file
Upload 67 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +1 -0
- .gitignore +4 -0
- Commands.txt +1 -0
- img/account_run_win.png +0 -0
- img/account_run_win_custom_email_api.png +0 -0
- img/activated_href_business.png +0 -0
- img/activated_href_esethome.png +0 -0
- img/activated_href_protecthub.png +0 -0
- img/activation_with_account_1.png +0 -0
- img/activation_with_account_2.png +0 -0
- img/activation_with_account_3.png +0 -0
- img/activation_with_account_5.png +3 -0
- img/activation_with_account_6.png +0 -0
- img/activation_with_account_7.png +0 -0
- img/activation_with_key.png +0 -0
- img/custom_settings_menu.png +0 -0
- img/default_settings_menu.png +0 -0
- img/delete_eset_home_account.png +0 -0
- img/endpoint_key_run_win.png +0 -0
- img/endpoint_key_run_win_custom_email_api.png +0 -0
- img/installation_from_source.png +0 -0
- img/installer_permission_error.png +0 -0
- img/key_run_win.png +0 -0
- img/key_run_win_custom_email_api.png +0 -0
- img/logo_alt.png +0 -0
- img/main_menu.png +0 -0
- img/protecthub_account_run_win.png +0 -0
- img/protecthub_account_run_win_custom_email_api.png +0 -0
- img/protecthub_license_data_message.png +0 -0
- img/reinstallation_attempt.png +0 -0
- img/reset_eset_vpn.png +0 -0
- img/small_business_key_run_win.png +0 -0
- img/small_business_key_run_win_custom_email_api.png +0 -0
- img/successfully_installed.png +0 -0
- img/unbinding_protecthub_key.png +0 -0
- img/updater_available.png +0 -0
- img/updater_binary_update.png +0 -0
- img/updater_src_update.png +0 -0
- img/updater_uptodate.png +0 -0
- img/vpn_codes_message.png +0 -0
- img/vpn_codes_run_win.png +0 -0
- img/vpn_codes_run_win_custom_email_api.png +0 -0
- main.py +735 -0
- modules/EmailAPIs.py +384 -0
- modules/EsetTools.py +515 -0
- modules/MBCI.py +122 -0
- modules/ProgressBar.py +55 -0
- modules/SharedTools.py +539 -0
- modules/Updater.py +235 -0
- modules/WebDriverInstaller.py +410 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
img/activation_with_account_5.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.exe
|
| 2 |
+
*.pyc
|
| 3 |
+
*.txt
|
| 4 |
+
.DS_STORE
|
Commands.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
python .\main.py --skip-webdriver-menu --chrome --vpn-codes --email-api fakemail --custom-browser-location "C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe"
|
img/account_run_win.png
ADDED
|
img/account_run_win_custom_email_api.png
ADDED
|
img/activated_href_business.png
ADDED
|
img/activated_href_esethome.png
ADDED
|
img/activated_href_protecthub.png
ADDED
|
img/activation_with_account_1.png
ADDED
|
img/activation_with_account_2.png
ADDED
|
img/activation_with_account_3.png
ADDED
|
img/activation_with_account_5.png
ADDED
|
Git LFS Details
|
img/activation_with_account_6.png
ADDED
|
img/activation_with_account_7.png
ADDED
|
img/activation_with_key.png
ADDED
|
img/custom_settings_menu.png
ADDED
|
img/default_settings_menu.png
ADDED
|
img/delete_eset_home_account.png
ADDED
|
img/endpoint_key_run_win.png
ADDED
|
img/endpoint_key_run_win_custom_email_api.png
ADDED
|
img/installation_from_source.png
ADDED
|
img/installer_permission_error.png
ADDED
|
img/key_run_win.png
ADDED
|
img/key_run_win_custom_email_api.png
ADDED
|
img/logo_alt.png
ADDED
|
img/main_menu.png
ADDED
|
img/protecthub_account_run_win.png
ADDED
|
img/protecthub_account_run_win_custom_email_api.png
ADDED
|
img/protecthub_license_data_message.png
ADDED
|
img/reinstallation_attempt.png
ADDED
|
img/reset_eset_vpn.png
ADDED
|
img/small_business_key_run_win.png
ADDED
|
img/small_business_key_run_win_custom_email_api.png
ADDED
|
img/successfully_installed.png
ADDED
|
img/unbinding_protecthub_key.png
ADDED
|
img/updater_available.png
ADDED
|
img/updater_binary_update.png
ADDED
|
img/updater_src_update.png
ADDED
|
img/updater_uptodate.png
ADDED
|
img/vpn_codes_message.png
ADDED
|
img/vpn_codes_run_win.png
ADDED
|
img/vpn_codes_run_win_custom_email_api.png
ADDED
|
main.py
ADDED
|
@@ -0,0 +1,735 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import contextlib
|
| 2 |
+
import logging
|
| 3 |
+
import pathlib
|
| 4 |
+
import json
|
| 5 |
+
import sys
|
| 6 |
+
import io
|
| 7 |
+
|
| 8 |
+
I_AM_EXECUTABLE = (True if (getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')) else False)
|
| 9 |
+
PATH_TO_SELF = sys.executable if I_AM_EXECUTABLE else __file__
|
| 10 |
+
CONFIG_PATH = pathlib.Path(PATH_TO_SELF).parent.resolve().joinpath('eset-keygen-config.json')
|
| 11 |
+
LOG_PATH = pathlib.Path(PATH_TO_SELF).parent.resolve().joinpath('ESET-KeyGen.log')
|
| 12 |
+
SILENT_MODE = '--silent' in sys.argv
|
| 13 |
+
MBCI_MODE = len(sys.argv) == 1
|
| 14 |
+
|
| 15 |
+
def enable_logging():
|
| 16 |
+
logging.basicConfig(
|
| 17 |
+
level=logging.INFO,
|
| 18 |
+
filemode='w',
|
| 19 |
+
filename=LOG_PATH,
|
| 20 |
+
format='%(asctime)s - %(levelname)s - %(message)s'
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
if ('--disable-logging' not in sys.argv and not MBCI_MODE) or ('--disable-logging' in sys.argv and SILENT_MODE):
|
| 24 |
+
enable_logging()
|
| 25 |
+
|
| 26 |
+
from modules.EmailAPIs import *
|
| 27 |
+
|
| 28 |
+
# ---- Quick settings ----
|
| 29 |
+
VERSION = ['v1.5.5.3', 1553]
|
| 30 |
+
LOGO = f"""
|
| 31 |
+
███████╗███████╗███████╗████████╗ ██╗ ██╗███████╗██╗ ██╗ ██████╗ ███████╗███╗ ██╗
|
| 32 |
+
██╔════╝██╔════╝██╔════╝╚══██╔══╝ ██║ ██╔╝██╔════╝╚██╗ ██╔╝██╔════╝ ██╔════╝████╗ ██║
|
| 33 |
+
█████╗ ███████╗█████╗ ██║ █████╔╝ █████╗ ╚████╔╝ ██║ ███╗█████╗ ██╔██╗ ██║
|
| 34 |
+
██╔══╝ ╚════██║██╔══╝ ██║ ██╔═██╗ ██╔══╝ ╚██╔╝ ██║ ██║██╔══╝ ██║╚██╗██║
|
| 35 |
+
███████╗███████║███████╗ ██║ ██║ ██╗███████╗ ██║ ╚██████╔╝███████╗██║ ╚████║
|
| 36 |
+
╚══════╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝
|
| 37 |
+
Project Version: {VERSION[0]}
|
| 38 |
+
Project Dev: Parv Ashwani (ZARWIN)
|
| 39 |
+
Dev Website: https://zarwin.is-a.dev
|
| 40 |
+
"""
|
| 41 |
+
if '--no-logo' in sys.argv:
|
| 42 |
+
LOGO = f"ESET KeyGen {VERSION[0]} by rzc0d3r\n"
|
| 43 |
+
|
| 44 |
+
DEFAULT_PATH_TO_PROXY_FILE = 'proxies.txt'
|
| 45 |
+
DEFAULT_EMAIL_API = 'guerrillamail'
|
| 46 |
+
AVAILABLE_EMAIL_APIS = ('1secmail', 'guerrillamail', 'developermail', 'mailticking', 'fakemail', 'inboxes', 'incognitomail')
|
| 47 |
+
WEB_WRAPPER_EMAIL_APIS = ('guerrillamail', 'mailticking', 'fakemail', 'inboxes', 'incognitomail')
|
| 48 |
+
EMAIL_API_CLASSES = {
|
| 49 |
+
'guerrillamail': GuerRillaMailAPI,
|
| 50 |
+
'1secmail': OneSecEmailAPI,
|
| 51 |
+
'developermail': DeveloperMailAPI,
|
| 52 |
+
'mailticking': MailTickingAPI,
|
| 53 |
+
'fakemail': FakeMailAPI,
|
| 54 |
+
'inboxes': InboxesAPI,
|
| 55 |
+
'incognitomail': IncognitoMailAPI
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
args = {
|
| 59 |
+
'auto_detect_browser': True,
|
| 60 |
+
'chrome': False,
|
| 61 |
+
'firefox': False,
|
| 62 |
+
'edge': False,
|
| 63 |
+
'safari': False,
|
| 64 |
+
|
| 65 |
+
'key': True,
|
| 66 |
+
'small_business_key': False,
|
| 67 |
+
'advanced_key': False,
|
| 68 |
+
'vpn_codes': False,
|
| 69 |
+
'account': False,
|
| 70 |
+
'protecthub_account': False,
|
| 71 |
+
'only_webdriver_update': False,
|
| 72 |
+
'update': False,
|
| 73 |
+
'reset_eset_vpn': False,
|
| 74 |
+
'install': False,
|
| 75 |
+
'return_exit_code': 0,
|
| 76 |
+
|
| 77 |
+
'skip_webdriver_menu': False,
|
| 78 |
+
'no_headless': False,
|
| 79 |
+
'custom_browser_location': '',
|
| 80 |
+
'email_api': DEFAULT_EMAIL_API,
|
| 81 |
+
'custom_email_api': False,
|
| 82 |
+
'skip_update_check': False,
|
| 83 |
+
'no_logo': False,
|
| 84 |
+
'disable_progress_bar': False,
|
| 85 |
+
'disable_output_file': False,
|
| 86 |
+
'repeat': 1,
|
| 87 |
+
'proxy_file': DEFAULT_PATH_TO_PROXY_FILE,
|
| 88 |
+
|
| 89 |
+
'silent': False,
|
| 90 |
+
'disable_logging': False
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
MBCI_BROWSERS_ARGS = ['auto-detect-browser', 'chrome', 'firefox', 'edge', 'safari']
|
| 94 |
+
MBCI_MODES_OF_OPERATION_ARGS = [
|
| 95 |
+
'key', 'small-business-key', 'advanced-key', 'vpn-codes', 'account',
|
| 96 |
+
'protecthub-account', 'only-webdriver-update', 'reset-eset-vpn', 'update', 'install'
|
| 97 |
+
]
|
| 98 |
+
MBCI_OTHER_ARGS = [
|
| 99 |
+
'skip_webdriver_menu', 'no_headless', 'custom_browser_location', 'custom_email_api',
|
| 100 |
+
'skip_update_check', 'disable_progress_bar', 'disable_output_file', 'repeat', 'disable_logging',
|
| 101 |
+
'proxy_file'
|
| 102 |
+
]
|
| 103 |
+
MBCI_ARGS = MBCI_BROWSERS_ARGS + MBCI_MODES_OF_OPERATION_ARGS + MBCI_OTHER_ARGS
|
| 104 |
+
|
| 105 |
+
from modules.WebDriverInstaller import *
|
| 106 |
+
from modules.EsetTools import EsetRegister as ER
|
| 107 |
+
from modules.EsetTools import EsetKeygen as EK
|
| 108 |
+
from modules.EsetTools import EsetVPN as EV
|
| 109 |
+
from modules.EsetTools import EsetProtectHubRegister as EPHR
|
| 110 |
+
from modules.EsetTools import EsetProtectHubKeygen as EPHK
|
| 111 |
+
from modules.EsetTools import EsetVPNResetWindows as EVRW
|
| 112 |
+
from modules.EsetTools import EsetVPNResetMacOS as EVRM
|
| 113 |
+
from modules.EsetTools import IPBlockedException
|
| 114 |
+
from modules.SharedTools import *
|
| 115 |
+
from modules.MBCI import *
|
| 116 |
+
from modules.Updater import Updater
|
| 117 |
+
|
| 118 |
+
import traceback
|
| 119 |
+
import colorama
|
| 120 |
+
import platform
|
| 121 |
+
import datetime
|
| 122 |
+
import argparse
|
| 123 |
+
import re
|
| 124 |
+
import os
|
| 125 |
+
|
| 126 |
+
PATH_TO_SELF = sys.executable if I_AM_EXECUTABLE else __file__
|
| 127 |
+
DRIVER = None
|
| 128 |
+
PROXIES = []
|
| 129 |
+
PROXIES_LEN = 0
|
| 130 |
+
PROXY_COUNTER = 1
|
| 131 |
+
PROXY_ERROR_COUNTER = 0
|
| 132 |
+
PROXY_ERROR_COUNTER_LIMIT = 3
|
| 133 |
+
CHROME_PROXY_EXTENSION_PATH = ""
|
| 134 |
+
|
| 135 |
+
class MBCIConfigManager:
|
| 136 |
+
def __init__(self, path=CONFIG_PATH):
|
| 137 |
+
self.path = path
|
| 138 |
+
|
| 139 |
+
def save(self, args):
|
| 140 |
+
config = {
|
| 141 |
+
'Browser': [key for key in MBCI_BROWSERS_ARGS if args[key.replace('-', '_')]][0],
|
| 142 |
+
'Mode of operation': [key for key in MBCI_MODES_OF_OPERATION_ARGS if args[key.replace('-', '_')]][0],
|
| 143 |
+
'Email API': args['email_api']
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
for key in MBCI_OTHER_ARGS:
|
| 147 |
+
config[key] = args[key]
|
| 148 |
+
|
| 149 |
+
json.dump(config, open(CONFIG_PATH, 'w'), indent=4)
|
| 150 |
+
|
| 151 |
+
def load(self):
|
| 152 |
+
config = json.load(open(self.path))
|
| 153 |
+
try:
|
| 154 |
+
filtered_config = {}
|
| 155 |
+
browser = config.pop('Browser')
|
| 156 |
+
mode_of_operation = config.pop('Mode of operation')
|
| 157 |
+
email_api = config.pop('Email API')
|
| 158 |
+
if browser in MBCI_BROWSERS_ARGS:
|
| 159 |
+
filtered_config[browser] = True
|
| 160 |
+
if mode_of_operation in MBCI_MODES_OF_OPERATION_ARGS:
|
| 161 |
+
filtered_config[mode_of_operation] = True
|
| 162 |
+
if email_api in AVAILABLE_EMAIL_APIS:
|
| 163 |
+
filtered_config['email_api'] = email_api
|
| 164 |
+
for key in config:
|
| 165 |
+
if key in MBCI_OTHER_ARGS:
|
| 166 |
+
filtered_config[key] = config[key]
|
| 167 |
+
return filtered_config
|
| 168 |
+
except:
|
| 169 |
+
return False
|
| 170 |
+
|
| 171 |
+
@property
|
| 172 |
+
def is_exists(self):
|
| 173 |
+
return os.path.isfile(self.path)
|
| 174 |
+
|
| 175 |
+
def RunMenu():
|
| 176 |
+
MainMenu = ViewMenu(LOGO+'\n---- Main Menu ----')
|
| 177 |
+
|
| 178 |
+
SettingMenu = ViewMenu(LOGO+'\n---- Settings Menu ----')
|
| 179 |
+
SettingMenu.add_item(
|
| 180 |
+
OptionAction(
|
| 181 |
+
args,
|
| 182 |
+
title='Browsers',
|
| 183 |
+
action='store_true',
|
| 184 |
+
args_names=MBCI_BROWSERS_ARGS,
|
| 185 |
+
default_value=[key for key in MBCI_BROWSERS_ARGS if args[key.replace('-', '_')]][0]
|
| 186 |
+
)
|
| 187 |
+
)
|
| 188 |
+
SettingMenu.add_item(
|
| 189 |
+
OptionAction(
|
| 190 |
+
args,
|
| 191 |
+
title='Modes of operation',
|
| 192 |
+
action='store_true',
|
| 193 |
+
args_names=MBCI_MODES_OF_OPERATION_ARGS,
|
| 194 |
+
default_value=[key for key in MBCI_MODES_OF_OPERATION_ARGS if args[key.replace('-', '_')]][0]
|
| 195 |
+
)
|
| 196 |
+
)
|
| 197 |
+
SettingMenu.add_item(
|
| 198 |
+
OptionAction(
|
| 199 |
+
args,
|
| 200 |
+
title='Email APIs',
|
| 201 |
+
action='choice',
|
| 202 |
+
args_names='email-api',
|
| 203 |
+
choices=AVAILABLE_EMAIL_APIS,
|
| 204 |
+
default_value=args['email_api']
|
| 205 |
+
)
|
| 206 |
+
)
|
| 207 |
+
SettingMenu.add_item(
|
| 208 |
+
OptionAction(
|
| 209 |
+
args,
|
| 210 |
+
title='--skip-webdriver-menu',
|
| 211 |
+
action='bool_switch',
|
| 212 |
+
args_names='skip-webdriver-menu'
|
| 213 |
+
)
|
| 214 |
+
)
|
| 215 |
+
SettingMenu.add_item(
|
| 216 |
+
OptionAction(
|
| 217 |
+
args,
|
| 218 |
+
title='--no-headless',
|
| 219 |
+
action='bool_switch',
|
| 220 |
+
args_names='no-headless'
|
| 221 |
+
)
|
| 222 |
+
)
|
| 223 |
+
SettingMenu.add_item(
|
| 224 |
+
OptionAction(
|
| 225 |
+
args,
|
| 226 |
+
title='--custom-browser-location',
|
| 227 |
+
action='manual_input',
|
| 228 |
+
args_names='custom-browser-location',
|
| 229 |
+
default_value=args['custom_browser_location']
|
| 230 |
+
)
|
| 231 |
+
)
|
| 232 |
+
SettingMenu.add_item(
|
| 233 |
+
OptionAction(
|
| 234 |
+
args,
|
| 235 |
+
title='--custom-email-api',
|
| 236 |
+
action='bool_switch',
|
| 237 |
+
args_names='custom-email-api'
|
| 238 |
+
)
|
| 239 |
+
)
|
| 240 |
+
SettingMenu.add_item(
|
| 241 |
+
OptionAction(
|
| 242 |
+
args,
|
| 243 |
+
title='--skip-update-check',
|
| 244 |
+
action='bool_switch',
|
| 245 |
+
args_names='skip_update_check'
|
| 246 |
+
)
|
| 247 |
+
)
|
| 248 |
+
SettingMenu.add_item(
|
| 249 |
+
OptionAction(
|
| 250 |
+
args,
|
| 251 |
+
title='--disable-progress-bar',
|
| 252 |
+
action='bool_switch',
|
| 253 |
+
args_names='disable_progress_bar'
|
| 254 |
+
)
|
| 255 |
+
)
|
| 256 |
+
SettingMenu.add_item(
|
| 257 |
+
OptionAction(
|
| 258 |
+
args,
|
| 259 |
+
title='--disable-output-file',
|
| 260 |
+
action='bool_switch',
|
| 261 |
+
args_names='disable_output_file'
|
| 262 |
+
)
|
| 263 |
+
)
|
| 264 |
+
SettingMenu.add_item(
|
| 265 |
+
OptionAction(
|
| 266 |
+
args,
|
| 267 |
+
title='--disable-logging',
|
| 268 |
+
action='bool_switch',
|
| 269 |
+
args_names='disable_logging'
|
| 270 |
+
)
|
| 271 |
+
)
|
| 272 |
+
SettingMenu.add_item(
|
| 273 |
+
OptionAction(
|
| 274 |
+
args,
|
| 275 |
+
title='--repeat',
|
| 276 |
+
action='manual_input',
|
| 277 |
+
args_names='repeat',
|
| 278 |
+
default_value=args['repeat'],
|
| 279 |
+
data_type=int
|
| 280 |
+
)
|
| 281 |
+
)
|
| 282 |
+
SettingMenu.add_item(
|
| 283 |
+
OptionAction(
|
| 284 |
+
args,
|
| 285 |
+
title='--proxy-file',
|
| 286 |
+
action='manual_input',
|
| 287 |
+
args_names='proxy-file',
|
| 288 |
+
default_value=args['proxy_file']
|
| 289 |
+
)
|
| 290 |
+
)
|
| 291 |
+
|
| 292 |
+
def exit_with_save_config():
|
| 293 |
+
MBCIConfigManager().save(args)
|
| 294 |
+
sys.exit()
|
| 295 |
+
|
| 296 |
+
SettingMenu.add_item(MenuAction('Back', SettingMenu.close))
|
| 297 |
+
MainMenu.add_item(MenuAction('Settings', SettingMenu))
|
| 298 |
+
MainMenu.add_item(MenuAction('Start', MainMenu.close))
|
| 299 |
+
MainMenu.add_item(MenuAction('Exit', exit_with_save_config))
|
| 300 |
+
MainMenu.view()
|
| 301 |
+
|
| 302 |
+
def parse_argv(sys_argv=None):
|
| 303 |
+
if '--return-exit-code' not in sys.argv and not SILENT_MODE and sys_argv is None:
|
| 304 |
+
print(LOGO)
|
| 305 |
+
if MBCI_MODE and sys_argv is None:
|
| 306 |
+
RunMenu()
|
| 307 |
+
else:
|
| 308 |
+
args_parser = argparse.ArgumentParser()
|
| 309 |
+
ENABLE_REQUIRED_ARGUMENTS = True
|
| 310 |
+
GLOBAL_OVERRIDE_ARGUMENTS = ['--reset-eset-vpn', '--update', '--install', '--return-exit-code']
|
| 311 |
+
for argv in GLOBAL_OVERRIDE_ARGUMENTS:
|
| 312 |
+
ENABLE_REQUIRED_ARGUMENTS = (argv not in sys.argv)
|
| 313 |
+
if not ENABLE_REQUIRED_ARGUMENTS:
|
| 314 |
+
break
|
| 315 |
+
|
| 316 |
+
args_browsers = args_parser.add_mutually_exclusive_group(required=ENABLE_REQUIRED_ARGUMENTS)
|
| 317 |
+
args_browsers.add_argument('--chrome', action='store_true', help='Launching the program via Google Chrome browser')
|
| 318 |
+
args_browsers.add_argument('--firefox', action='store_true', help='Launching the program via Mozilla Firefox browser')
|
| 319 |
+
args_browsers.add_argument('--edge', action='store_true', help='Launching the program via Microsoft Edge browser')
|
| 320 |
+
args_browsers.add_argument('--safari', action='store_true', help='Launching the program via Apple Safari browser')
|
| 321 |
+
args_browsers.add_argument('--auto-detect-browser', action='store_true', help='The program itself will determine which browser to use (from the list of supported browsers)')
|
| 322 |
+
|
| 323 |
+
args_modes = args_parser.add_mutually_exclusive_group(required=ENABLE_REQUIRED_ARGUMENTS)
|
| 324 |
+
args_modes.add_argument('--key', action='store_true', help='muimerP ytiruceS tramS TESE rof yek esnecil a gnitaerC'[::-1])
|
| 325 |
+
args_modes.add_argument('--small-business-key', action='store_true', help=')secived 5 - yek 1( ytiruceS ssenisuB llamS TESE rof yek esnecil a gnitaerC'[::-1])
|
| 326 |
+
args_modes.add_argument('--advanced-key', action='store_true', help=')secived 52 - yek 1( decnavdA TCETORP TESE rof yek esnecil a gnitaerC'[::-1])
|
| 327 |
+
args_modes.add_argument('--vpn-codes', action='store_true', help='yek ytiruceS ssenisuB llamS TESE 1 + NPV TESE rof sedoc 01 gnitaerC'[::-1])
|
| 328 |
+
args_modes.add_argument('--account', action='store_true', help=')noisrev lairt eerf eht etavitca ot( tnuoccA EMOH TESE a gnitaerC'[::-1])
|
| 329 |
+
args_modes.add_argument('--protecthub-account', action='store_true', help=')noisrev lairt eerf eht etavitca ot( tnuoccA buHtcetorP TESE a gnitaerC'[::-1])
|
| 330 |
+
args_modes.add_argument('--only-webdriver-update', action='store_true', help='yek esnecil dna tnuocca gnitareneg tuohtiw sresworb dna srevirdbew sllatsni/setadpU'[::-1])
|
| 331 |
+
args_modes.add_argument('--reset-eset-vpn', action='store_true', help='!!!elbaliava era taht stnemugra lla sedirrevO - )ylno SOcam & swodniW( noitacilppa NPV TESE eht ni esnecil eht teser ot gniyrT'[::-1])
|
| 332 |
+
args_modes.add_argument('--update', action='store_true', help='Switching to program update mode - Overrides all arguments that are available!!!')
|
| 333 |
+
args_modes.add_argument('--install', action='store_true', help='Installs the program and adds it to the environment variable (Windows & macOS only) - Overrides all arguments that are available!!!')
|
| 334 |
+
args_modes.add_argument('--return-exit-code', type=int, default=0, help='[For developers] Will make the program return the exit code you requested - Overrides all arguments that are available!!!')
|
| 335 |
+
|
| 336 |
+
args_parser.add_argument('--skip-webdriver-menu', action='store_true', help='Skips installation/upgrade webdrivers through the my custom wrapper (the built-in selenium-manager will be used)')
|
| 337 |
+
args_parser.add_argument('--no-headless', action='store_true', help='Shows the browser at runtime (the browser is hidden by default, but on Windows 7 this option is enabled by itself)')
|
| 338 |
+
args_parser.add_argument('--custom-browser-location', type=str, default='', help='Set path to the custom browser (to the binary file, useful when using non-standard releases, for example, Firefox Developer Edition)')
|
| 339 |
+
args_parser.add_argument('--email-api', choices=AVAILABLE_EMAIL_APIS, default=DEFAULT_EMAIL_API, help=f'Specify which api to use for mail, default - {DEFAULT_EMAIL_API}')
|
| 340 |
+
args_parser.add_argument('--custom-email-api', action='store_true', help='Allows you to manually specify any email, and all work will go through it. But you will also have to manually read inbox and do what is described in the documentation for this argument')
|
| 341 |
+
args_parser.add_argument('--skip-update-check', action='store_true', help='Skips checking for program updates')
|
| 342 |
+
args_parser.add_argument('--no-logo', action='store_true', help='Replaces ASCII-Art with plain text')
|
| 343 |
+
args_parser.add_argument('--disable-progress-bar', action='store_true', help='Disables the webdriver download progress bar')
|
| 344 |
+
args_parser.add_argument('--disable-output-file', action='store_true', help='Disables the output txt file generation')
|
| 345 |
+
args_parser.add_argument('--repeat', type=int, default=1, help='Specifies how many times to repeat generation')
|
| 346 |
+
args_parser.add_argument('--proxy-file', type=str, default=DEFAULT_PATH_TO_PROXY_FILE, help=f'Specifies the path from where the list of proxies will be read from, default - {DEFAULT_PATH_TO_PROXY_FILE}')
|
| 347 |
+
|
| 348 |
+
args_logging = args_parser.add_mutually_exclusive_group()
|
| 349 |
+
args_logging.add_argument('--silent', action='store_true', help='Disables message output, output called by the --custom-email-api argument will still be output!')
|
| 350 |
+
args_logging.add_argument('--disable-logging', action='store_true', help='Disables logging')
|
| 351 |
+
|
| 352 |
+
parsed_args = None
|
| 353 |
+
captured_stderr = io.StringIO()
|
| 354 |
+
with contextlib.redirect_stderr(captured_stderr):
|
| 355 |
+
try:
|
| 356 |
+
parsed_args = vars(args_parser.parse_args(sys_argv))
|
| 357 |
+
parsed_args['repeat'] = abs(parsed_args['repeat'])
|
| 358 |
+
if sys_argv is None:
|
| 359 |
+
logging.info(f'Parsed arguments: {parsed_args}')
|
| 360 |
+
except SystemExit:
|
| 361 |
+
captured_stderr = captured_stderr.getvalue().strip()
|
| 362 |
+
if captured_stderr != '':
|
| 363 |
+
if sys_argv is None:
|
| 364 |
+
logging.error(captured_stderr)
|
| 365 |
+
console_log(captured_stderr, silent_mode=SILENT_MODE)
|
| 366 |
+
if sys_argv is None:
|
| 367 |
+
exit_program(-1)
|
| 368 |
+
return parsed_args
|
| 369 |
+
|
| 370 |
+
def exit_program(exit_code, driver=None):
|
| 371 |
+
if MBCI_MODE and not SILENT_MODE:
|
| 372 |
+
input('\nPress Enter to exit...')
|
| 373 |
+
if driver is not None:
|
| 374 |
+
driver.quit()
|
| 375 |
+
sys.exit(exit_code)
|
| 376 |
+
|
| 377 |
+
def update():
|
| 378 |
+
Updater().updater_menu(I_AM_EXECUTABLE, PATH_TO_SELF)
|
| 379 |
+
exit_program(0)
|
| 380 |
+
|
| 381 |
+
def main(disable_exit=False):
|
| 382 |
+
global PROXY_ERROR_COUNTER_LIMIT
|
| 383 |
+
global PROXY_ERROR_COUNTER
|
| 384 |
+
global DRIVER
|
| 385 |
+
if args['return_exit_code'] != 0:
|
| 386 |
+
sys.exit(args['return_exit_code'])
|
| 387 |
+
if MBCI_MODE and not disable_exit:
|
| 388 |
+
print()
|
| 389 |
+
try:
|
| 390 |
+
if not args['update'] and not args['install'] and not args['reset_eset_vpn']:
|
| 391 |
+
if platform.release() == '7' and sys.platform.startswith('win'):
|
| 392 |
+
args['no_headless'] = True
|
| 393 |
+
elif args['advanced_key'] or args['protecthub_account']:
|
| 394 |
+
args['no_headless'] = True
|
| 395 |
+
if not args['custom_email_api']:
|
| 396 |
+
if args['email_api'] not in ['mailticking', 'fakemail', 'inboxes', 'incognitomail']:
|
| 397 |
+
raise RuntimeError('--advanced-key, --protecthub-account works ONLY if you use the --custom-email-api argument or the following Email APIs: mailticking, fakemail, inboxes!!!')
|
| 398 |
+
elif args['update']:
|
| 399 |
+
logging.info('-- Updater --')
|
| 400 |
+
console_log(f'{Fore.LIGHTMAGENTA_EX}-- Updater --{Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 401 |
+
update()
|
| 402 |
+
elif args['reset_eset_vpn']:
|
| 403 |
+
logging.info('-- Reset ESET VPN --')
|
| 404 |
+
console_log(f'{Fore.LIGHTMAGENTA_EX}-- Reset ESET VPN --{Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 405 |
+
if sys.platform.startswith('win'):
|
| 406 |
+
EVRW()
|
| 407 |
+
elif sys.platform == "darwin":
|
| 408 |
+
EVRM()
|
| 409 |
+
else:
|
| 410 |
+
logging.error('This feature is for Windows and macOS only!!!')
|
| 411 |
+
console_log('This feature is for Windows and macOS only!!!', ERROR, silent_mode=SILENT_MODE)
|
| 412 |
+
exit_program(-2)
|
| 413 |
+
elif args['install']:
|
| 414 |
+
logging.info('-- Installer --')
|
| 415 |
+
console_log(f'{Fore.LIGHTMAGENTA_EX}-- Installer --{Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 416 |
+
Installer().install()
|
| 417 |
+
exit_program(0)
|
| 418 |
+
if not args['skip_update_check'] and not args['update']:
|
| 419 |
+
try:
|
| 420 |
+
logging.info('-- Updater --')
|
| 421 |
+
console_log(f'{Fore.LIGHTMAGENTA_EX}-- Updater --{Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 422 |
+
updater = Updater()
|
| 423 |
+
latest_cloud_version = list(updater.get_releases().keys())[0]
|
| 424 |
+
latest_cloud_version_int = latest_cloud_version[1:].split('.')
|
| 425 |
+
latest_cloud_version_int = int(''.join(latest_cloud_version_int[:-1])+latest_cloud_version_int[-1][0])
|
| 426 |
+
if VERSION[1] > latest_cloud_version_int:
|
| 427 |
+
logging.warning(f'The project has an unreleased version, maybe you are using a build from the developer?')
|
| 428 |
+
console_log(f'The project has an unreleased version, maybe you are using a build from the developer?\n', WARN, True, SILENT_MODE)
|
| 429 |
+
elif latest_cloud_version_int > VERSION[1]:
|
| 430 |
+
logging.info(f'Project update is available up to version: {latest_cloud_version}')
|
| 431 |
+
if not SILENT_MODE:
|
| 432 |
+
console_log(f'Project update is available up to version: {colorama.Fore.GREEN}{latest_cloud_version}{colorama.Fore.RESET}', WARN)
|
| 433 |
+
update_now = input(f'[ {colorama.Fore.YELLOW}INPT{colorama.Fore.RESET} ] {colorama.Fore.CYAN}Do you want to update right now? (y/n): {colorama.Fore.RESET}').strip().lower()
|
| 434 |
+
if update_now == 'y':
|
| 435 |
+
update()
|
| 436 |
+
else:
|
| 437 |
+
console_log(f'The update has been ignored\n', INFO)
|
| 438 |
+
else:
|
| 439 |
+
logging.info('Project up to date!!!')
|
| 440 |
+
console_log('Project up to date!!!\n', OK, silent_mode=SILENT_MODE)
|
| 441 |
+
except Exception as e:
|
| 442 |
+
logging.error("EXC_INFO:", exc_info=True)
|
| 443 |
+
|
| 444 |
+
webdriver_path = None
|
| 445 |
+
browser_name = GOOGLE_CHROME
|
| 446 |
+
custom_browser_location = None if args['custom_browser_location'] == '' else args['custom_browser_location']
|
| 447 |
+
webdriver_installer = WebDriverInstaller(browser_name, custom_browser_location)
|
| 448 |
+
|
| 449 |
+
if args['auto_detect_browser']:
|
| 450 |
+
result = webdriver_installer.detect_installed_browser()
|
| 451 |
+
if result is not None:
|
| 452 |
+
browser_name = result[0]
|
| 453 |
+
webdriver_installer = WebDriverInstaller(browser_name, custom_browser_location)
|
| 454 |
+
else:
|
| 455 |
+
args['skip_webdriver_menu'] = True
|
| 456 |
+
else:
|
| 457 |
+
if args['chrome']:
|
| 458 |
+
browser_name = GOOGLE_CHROME
|
| 459 |
+
global CHROME_PROXY_EXTENSION_PATH
|
| 460 |
+
if PROXIES != []:
|
| 461 |
+
CHROME_PROXY_EXTENSION_PATH = ChromeProxyExtensionManager.create_extension(*PROXIES[0])
|
| 462 |
+
else:
|
| 463 |
+
CHROME_PROXY_EXTENSION_PATH = ''
|
| 464 |
+
elif args['firefox']:
|
| 465 |
+
browser_name = MOZILLA_FIREFOX
|
| 466 |
+
elif args['edge']:
|
| 467 |
+
browser_name = MICROSOFT_EDGE
|
| 468 |
+
elif args['safari']:
|
| 469 |
+
browser_name = APPLE_SAFARI
|
| 470 |
+
webdriver_installer = WebDriverInstaller(browser_name, custom_browser_location)
|
| 471 |
+
|
| 472 |
+
if browser_name == APPLE_SAFARI:
|
| 473 |
+
args['skip_webdriver_menu'] = True
|
| 474 |
+
|
| 475 |
+
if not args['skip_webdriver_menu']:
|
| 476 |
+
webdriver_path, custom_browser_location = webdriver_installer.menu(args['disable_progress_bar'])
|
| 477 |
+
if not args['only_webdriver_update']:
|
| 478 |
+
DRIVER = initSeleniumWebDriver(browser_name, webdriver_path, custom_browser_location, CHROME_PROXY_EXTENSION_PATH, (not args['no_headless']))
|
| 479 |
+
if DRIVER is None:
|
| 480 |
+
raise RuntimeError(f'{browser_name} initialization error!')
|
| 481 |
+
if PROXIES != []:
|
| 482 |
+
scheme, host, port, username, password = PROXIES[0]
|
| 483 |
+
global PROXY_COUNTER
|
| 484 |
+
if username != '' or password != '':
|
| 485 |
+
logging.info(f'[{PROXY_COUNTER}/{PROXIES_LEN}] Using proxy with authentication: {host}:{port}')
|
| 486 |
+
console_log(f'[{PROXY_COUNTER}/{PROXIES_LEN}] Using proxy with authentication: {host}:{port}', INFO, silent_mode=SILENT_MODE)
|
| 487 |
+
else:
|
| 488 |
+
logging.info(f'[{PROXY_COUNTER}/{PROXIES_LEN}] Using proxy: {host}:{port}')
|
| 489 |
+
console_log(f'[{PROXY_COUNTER}/{PROXIES_LEN}] Using proxy: {host}:{port}', INFO, silent_mode=SILENT_MODE)
|
| 490 |
+
else:
|
| 491 |
+
sys.exit(0)
|
| 492 |
+
|
| 493 |
+
logging.info(f'-- KeyGen --')
|
| 494 |
+
console_log(f'\n{Fore.LIGHTMAGENTA_EX}-- KeyGen --{Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 495 |
+
if not args['custom_email_api']:
|
| 496 |
+
logging.info(f'[{args["email_api"]}] Mail registration...')
|
| 497 |
+
console_log(f'[{args["email_api"]}] Mail registration...', INFO, silent_mode=SILENT_MODE)
|
| 498 |
+
if args['email_api'] in WEB_WRAPPER_EMAIL_APIS:
|
| 499 |
+
email_obj = EMAIL_API_CLASSES[args['email_api']](DRIVER)
|
| 500 |
+
else:
|
| 501 |
+
email_obj = EMAIL_API_CLASSES[args['email_api']]()
|
| 502 |
+
try:
|
| 503 |
+
email_obj.init()
|
| 504 |
+
if email_obj.email is not None:
|
| 505 |
+
logging.info('Mail registration completed successfully!')
|
| 506 |
+
console_log('Mail registration completed successfully!', OK, silent_mode=SILENT_MODE)
|
| 507 |
+
except:
|
| 508 |
+
pass
|
| 509 |
+
if email_obj.email is None:
|
| 510 |
+
logging.critical('Mail registration was not completed, try using a different Email API!')
|
| 511 |
+
console_log('Mail registration was not completed, try using a different Email API!\n', ERROR, silent_mode=SILENT_MODE)
|
| 512 |
+
PROXY_ERROR_COUNTER += 1
|
| 513 |
+
else:
|
| 514 |
+
email_obj = CustomEmailAPI()
|
| 515 |
+
while True:
|
| 516 |
+
email = input(f'[ {colorama.Fore.YELLOW}INPT{colorama.Fore.RESET} ] {colorama.Fore.CYAN}Enter the email address you have access to: {colorama.Fore.RESET}').strip()
|
| 517 |
+
try:
|
| 518 |
+
matched_email = re.match(r'[-a-z0-9+.]+@[a-z]+(\.[a-z]+)+', email).group()
|
| 519 |
+
if matched_email == email:
|
| 520 |
+
email_obj.email = matched_email
|
| 521 |
+
console_log('Mail has the correct syntax!', OK)
|
| 522 |
+
break
|
| 523 |
+
else:
|
| 524 |
+
raise RuntimeError
|
| 525 |
+
except:
|
| 526 |
+
console_log('Invalid email syntax!!!', ERROR)
|
| 527 |
+
|
| 528 |
+
if email_obj.email is not None:
|
| 529 |
+
e_passwd = dataGenerator(10)
|
| 530 |
+
l_key = None
|
| 531 |
+
obtained_from_site = False
|
| 532 |
+
|
| 533 |
+
if args['account'] or args['key'] or args['small_business_key'] or args['vpn_codes']:
|
| 534 |
+
ER_obj = ER(email_obj, e_passwd, DRIVER)
|
| 535 |
+
ER_obj.createAccount()
|
| 536 |
+
ER_obj.confirmAccount()
|
| 537 |
+
output_line = '\n'.join([
|
| 538 |
+
'',
|
| 539 |
+
'-------------------------------------------------',
|
| 540 |
+
'}{ :liamE tnuoccA'[::-1].format(email_obj.email),
|
| 541 |
+
'}{ :drowssaP tnuoccA'[::-1].format(e_passwd),
|
| 542 |
+
'-------------------------------------------------',
|
| 543 |
+
''
|
| 544 |
+
])
|
| 545 |
+
output_filename = 'ESET ACCOUNTS.txt'
|
| 546 |
+
if args['key'] or args['small_business_key'] or args['vpn_codes']:
|
| 547 |
+
output_filename = 'ESET KEYS.txt'
|
| 548 |
+
EK_obj = EK(email_obj, DRIVER, 'ESET HOME' if args['key'] else 'SMALL BUSINESS')
|
| 549 |
+
EK_obj.sendRequestForKey()
|
| 550 |
+
l_name, l_key, l_out_date = EK_obj.getLD()
|
| 551 |
+
output_line = '\n'.join([
|
| 552 |
+
'',
|
| 553 |
+
'-------------------------------------------------',
|
| 554 |
+
'}{ :liamE tnuoccA'[::-1].format(email_obj.email),
|
| 555 |
+
'}{ :drowssaP tnuoccA'[::-1].format(e_passwd),
|
| 556 |
+
'',
|
| 557 |
+
'}{ :emaN esneciL'[::-1].format(l_name),
|
| 558 |
+
'}{ :yeK esneciL'[::-1].format(l_key),
|
| 559 |
+
'}{ :etaD tuO esneciL'[::-1].format(l_out_date),
|
| 560 |
+
'-------------------------------------------------',
|
| 561 |
+
''
|
| 562 |
+
])
|
| 563 |
+
if args['vpn_codes']:
|
| 564 |
+
EV_obj = EV(email_obj, DRIVER, ER_obj.window_handle)
|
| 565 |
+
EV_obj.sendRequestForVPNCodes()
|
| 566 |
+
vpn_codes = EV_obj.getVPNCodes()
|
| 567 |
+
if not args['custom_email_api']:
|
| 568 |
+
vpn_codes_line = ', '.join(vpn_codes)
|
| 569 |
+
output_line = '\n'.join([
|
| 570 |
+
'',
|
| 571 |
+
'-------------------------------------------------',
|
| 572 |
+
'}{ :liamE tnuoccA'[::-1].format(email_obj.email),
|
| 573 |
+
'}{ :drowssaP tnuoccA'[::-1].format(e_passwd),
|
| 574 |
+
'',
|
| 575 |
+
'}{ :emaN esneciL'[::-1].format(l_name),
|
| 576 |
+
'}{ :yeK esneciL'[::-1].format(l_key),
|
| 577 |
+
'}{ :etaD tuO esneciL'[::-1].format(l_out_date),
|
| 578 |
+
'',
|
| 579 |
+
'}{ :sedoC NPV'[::-1].format(vpn_codes_line),
|
| 580 |
+
'-------------------------------------------------',
|
| 581 |
+
''
|
| 582 |
+
])
|
| 583 |
+
|
| 584 |
+
elif args['protecthub_account'] or args['advanced_key']:
|
| 585 |
+
EPHR_obj = EPHR(email_obj, e_passwd, DRIVER)
|
| 586 |
+
EPHR_obj.createAccount()
|
| 587 |
+
EPHR_obj.confirmAccount()
|
| 588 |
+
EPHR_obj.activateAccount()
|
| 589 |
+
output_line = '\n'.join([
|
| 590 |
+
'',
|
| 591 |
+
'---------------------------------------------------------------------',
|
| 592 |
+
'}{ :liamE tnuoccA buHtcetorP TESE'[::-1].format(email_obj.email),
|
| 593 |
+
'}{ :drowssaP tnuoccA buHtcetorP TESE'[::-1].format(e_passwd),
|
| 594 |
+
'---------------------------------------------------------------------',
|
| 595 |
+
''
|
| 596 |
+
])
|
| 597 |
+
output_filename = 'ESET ACCOUNTS.txt'
|
| 598 |
+
if args['advanced_key']:
|
| 599 |
+
output_filename = 'ESET KEYS.txt'
|
| 600 |
+
EPHK_obj = EPHK(email_obj, e_passwd, DRIVER)
|
| 601 |
+
l_name, l_key, l_out_date, obtained_from_site = EPHK_obj.getLD()
|
| 602 |
+
if l_name is not None:
|
| 603 |
+
output_line = '\n'.join([
|
| 604 |
+
'',
|
| 605 |
+
'---------------------------------------------------------------------',
|
| 606 |
+
'}{ :liamE tnuoccA buHtcetorP TESE'[::-1].format(email_obj.email),
|
| 607 |
+
'}{ :drowssaP tnuoccA buHtcetorP TESE'[::-1].format(e_passwd),
|
| 608 |
+
'',
|
| 609 |
+
'}{ :emaN esneciL'[::-1].format(l_name),
|
| 610 |
+
'}{ :yeK esneciL'[::-1].format(l_key),
|
| 611 |
+
'}{ :etaD tuO esneciL'[::-1].format(l_out_date),
|
| 612 |
+
'---------------------------------------------------------------------',
|
| 613 |
+
''
|
| 614 |
+
])
|
| 615 |
+
|
| 616 |
+
logging.info(output_line)
|
| 617 |
+
console_log(output_line, silent_mode=SILENT_MODE)
|
| 618 |
+
if not args['disable_output_file']:
|
| 619 |
+
date = datetime.datetime.now()
|
| 620 |
+
f = open(f"{str(date.day)}.{str(date.month)}.{str(date.year)} - "+output_filename, 'a')
|
| 621 |
+
f.write(output_line)
|
| 622 |
+
f.close()
|
| 623 |
+
|
| 624 |
+
if l_key is not None and args['advanced_key'] and obtained_from_site:
|
| 625 |
+
if not SILENT_MODE:
|
| 626 |
+
unbind_key = input(f'[ {colorama.Fore.YELLOW}INPT{colorama.Fore.RESET} ] {colorama.Fore.CYAN}Do you want to unbind the key from this account? (y/n): {colorama.Fore.RESET}').strip().lower()
|
| 627 |
+
if unbind_key == 'y':
|
| 628 |
+
EPHK_obj.removeLicense()
|
| 629 |
+
else:
|
| 630 |
+
EPHK_obj.removeLicense()
|
| 631 |
+
except IPBlockedException:
|
| 632 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 633 |
+
traceback_string = traceback.format_exc()
|
| 634 |
+
if PROXIES != []:
|
| 635 |
+
PROXIES.remove(PROXIES[0])
|
| 636 |
+
if PROXY_COUNTER < PROXIES_LEN:
|
| 637 |
+
PROXY_COUNTER += 1
|
| 638 |
+
console_log(traceback_string, ERROR, silent_mode=SILENT_MODE)
|
| 639 |
+
except Exception as E:
|
| 640 |
+
PROXY_ERROR_COUNTER_LIMIT += 1
|
| 641 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 642 |
+
traceback_string = traceback.format_exc()
|
| 643 |
+
if str(type(E)).find('selenium') and traceback_string.find('Stacktrace:') != -1:
|
| 644 |
+
traceback_string = traceback_string.split('Stacktrace:', 1)[0]
|
| 645 |
+
console_log(traceback_string, ERROR, silent_mode=SILENT_MODE)
|
| 646 |
+
|
| 647 |
+
if PROXIES != [] and PROXY_ERROR_COUNTER == PROXY_ERROR_COUNTER_LIMIT:
|
| 648 |
+
PROXY_ERROR_COUNTER = 0
|
| 649 |
+
PROXIES.remove(PROXIES[0])
|
| 650 |
+
if PROXY_COUNTER < PROXIES_LEN:
|
| 651 |
+
PROXY_COUNTER += 1
|
| 652 |
+
|
| 653 |
+
if globals().get('DRIVER', None) is not None:
|
| 654 |
+
DRIVER.quit()
|
| 655 |
+
if not disable_exit:
|
| 656 |
+
exit_program(0)
|
| 657 |
+
|
| 658 |
+
if __name__ == '__main__':
|
| 659 |
+
if MBCI_MODE:
|
| 660 |
+
config_manager = MBCIConfigManager()
|
| 661 |
+
if config_manager.is_exists:
|
| 662 |
+
try:
|
| 663 |
+
config_args = config_manager.load()
|
| 664 |
+
config_sys_argv = []
|
| 665 |
+
for key, value in config_args.items():
|
| 666 |
+
if isinstance(value, bool) and not value:
|
| 667 |
+
continue
|
| 668 |
+
config_sys_argv.append('--'+key.replace('_', '-'))
|
| 669 |
+
if not isinstance(value, bool):
|
| 670 |
+
config_sys_argv.append(str(value))
|
| 671 |
+
parsed_args = parse_argv(config_sys_argv)
|
| 672 |
+
if parsed_args is not None:
|
| 673 |
+
args = parsed_args
|
| 674 |
+
else:
|
| 675 |
+
raise RuntimeError
|
| 676 |
+
except:
|
| 677 |
+
console_log("\nError loading the config, check its integrity!!!", WARN)
|
| 678 |
+
input('\nPress Enter to continue...')
|
| 679 |
+
parse_argv()
|
| 680 |
+
args['repeat'] = abs(args['repeat'])
|
| 681 |
+
try:
|
| 682 |
+
config_manager.save(args)
|
| 683 |
+
except:
|
| 684 |
+
console_log("\nError saving configuration, check write access!!!", WARN)
|
| 685 |
+
input('\nPress Enter to continue...')
|
| 686 |
+
else:
|
| 687 |
+
args = parse_argv()
|
| 688 |
+
|
| 689 |
+
if args['disable_logging']:
|
| 690 |
+
logging.basicConfig(level=logging.CRITICAL+1)
|
| 691 |
+
else:
|
| 692 |
+
enable_logging()
|
| 693 |
+
|
| 694 |
+
logging.info(f'ESET-KeyGen Version: text={VERSION[0]}, index={VERSION[1]}')
|
| 695 |
+
logging.info(f'I_AM_EXECUTABLE={I_AM_EXECUTABLE}, OS={os.name}')
|
| 696 |
+
logging.info(f'sys.argv: {sys.argv}')
|
| 697 |
+
|
| 698 |
+
# Determine browser name for proxy loading
|
| 699 |
+
browser_name = None
|
| 700 |
+
if args['auto_detect_browser']:
|
| 701 |
+
result = WebDriverInstaller(None, None).detect_installed_browser()
|
| 702 |
+
if result is not None:
|
| 703 |
+
browser_name = result[0]
|
| 704 |
+
else:
|
| 705 |
+
if args['chrome']:
|
| 706 |
+
browser_name = GOOGLE_CHROME
|
| 707 |
+
elif args['firefox']:
|
| 708 |
+
browser_name = MOZILLA_FIREFOX
|
| 709 |
+
elif args['edge']:
|
| 710 |
+
browser_name = MICROSOFT_EDGE
|
| 711 |
+
elif args['safari']:
|
| 712 |
+
browser_name = APPLE_SAFARI
|
| 713 |
+
|
| 714 |
+
# Load proxies only if using Chrome and proxy file exists
|
| 715 |
+
if browser_name == GOOGLE_CHROME and os.path.exists(args['proxy_file']) and os.path.isfile(args['proxy_file']):
|
| 716 |
+
PROXIES = ChromeProxyExtensionManager.parse_proxies_from_file(args['proxy_file'])
|
| 717 |
+
PROXIES_LEN = len(PROXIES)
|
| 718 |
+
|
| 719 |
+
if args['repeat'] == 1 or args['repeat'] == 0:
|
| 720 |
+
main()
|
| 721 |
+
else:
|
| 722 |
+
args['skip_update_check'] = True
|
| 723 |
+
for i in range(args['repeat']):
|
| 724 |
+
try:
|
| 725 |
+
logging.info(f'------------ Initializing of {i+1} start ------------')
|
| 726 |
+
console_log(f'\n{Fore.MAGENTA}------------ Initializing of {Fore.YELLOW}{i+1} {Fore.MAGENTA}start ------------{Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 727 |
+
if i == 0:
|
| 728 |
+
main(disable_exit=True)
|
| 729 |
+
args['skip_webdriver_menu'] = True
|
| 730 |
+
elif i+1 == args['repeat']:
|
| 731 |
+
main()
|
| 732 |
+
else:
|
| 733 |
+
main(disable_exit=True)
|
| 734 |
+
except KeyboardInterrupt:
|
| 735 |
+
exit_program(0, DRIVER)
|
modules/EmailAPIs.py
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .SharedTools import *
|
| 2 |
+
|
| 3 |
+
from email import policy, parser
|
| 4 |
+
|
| 5 |
+
import requests
|
| 6 |
+
import time
|
| 7 |
+
|
| 8 |
+
DEFINE_PARSE_10MINUTEMAIL_INBOX_FUNCTION = """function parse_10minutemail_inbox() {
|
| 9 |
+
updatemailbox()
|
| 10 |
+
let mails = Array.from(document.getElementsByTagName('tr')).slice(1)
|
| 11 |
+
let inbox = []
|
| 12 |
+
for(let i=0; i < mails.length; i++) {
|
| 13 |
+
let id = mails[i].children[0].children[0].href
|
| 14 |
+
let from = mails[i].children[0].innerText
|
| 15 |
+
let subject = mails[i].children[1].innerText
|
| 16 |
+
inbox.push([id, from, subject]) }
|
| 17 |
+
return inbox }"""
|
| 18 |
+
PARSE_GUERRILLAMAIL_INBOX = """
|
| 19 |
+
var email_list = document.getElementById('email_list').children
|
| 20 |
+
var inbox = []
|
| 21 |
+
for(var i=0; i < email_list.length-1; i++) {
|
| 22 |
+
var mail = email_list[i].children
|
| 23 |
+
var from = mail[1].innerText
|
| 24 |
+
var subject = mail[2].innerText
|
| 25 |
+
var mail_id = mail[0].children[0].value
|
| 26 |
+
inbox.push([mail_id, from, subject])
|
| 27 |
+
}
|
| 28 |
+
return inbox
|
| 29 |
+
"""
|
| 30 |
+
GET_GUERRILLAMAIL_DOMAINS = """
|
| 31 |
+
var domains_options = document.getElementById('gm-host-select').options
|
| 32 |
+
var domains = []
|
| 33 |
+
for(var i=0; i < domains_options.length-1; i++) {
|
| 34 |
+
domains.push(domains_options[i].value)
|
| 35 |
+
}
|
| 36 |
+
return domains
|
| 37 |
+
"""
|
| 38 |
+
PARSE_MAILTICKING_INBOX = """function MailTickingParse() {
|
| 39 |
+
var inbox = []
|
| 40 |
+
var mlist = document.getElementById("message-list").children
|
| 41 |
+
for(i=0; i<mlist.length-1; i++) {
|
| 42 |
+
var mfields = mlist[i].children
|
| 43 |
+
var mail_id = mfields[0].children[0].href
|
| 44 |
+
var from = mfields[0].innerText
|
| 45 |
+
var subject = mfields[1].innerText
|
| 46 |
+
inbox.push([mail_id, from, subject])
|
| 47 |
+
}
|
| 48 |
+
return inbox;
|
| 49 |
+
}
|
| 50 |
+
return MailTickingParse()"""
|
| 51 |
+
PARSE_FAKEMAIL_INBOX = """
|
| 52 |
+
let raw_inbox = Array.from(document.getElementById('schranka').children).slice(0, -3)
|
| 53 |
+
let inbox = []
|
| 54 |
+
for(let i=0; i < raw_inbox.length; i++) {
|
| 55 |
+
let id = raw_inbox[i].dataset.href
|
| 56 |
+
let from = raw_inbox[i].children[0].children[1].tagName.toLowerCase()
|
| 57 |
+
let subject = raw_inbox[i].children[1].innerText.trim()
|
| 58 |
+
inbox.push([id, from, subject])
|
| 59 |
+
}
|
| 60 |
+
return inbox
|
| 61 |
+
"""
|
| 62 |
+
PARSE_1SECMAILPRO_INBOX = """
|
| 63 |
+
let iframes = document.getElementsByTagName('iframe')
|
| 64 |
+
let message_iframes = []
|
| 65 |
+
for (let i = 0; i < iframes.length; i++) {
|
| 66 |
+
if (iframes[i].className.search('flex') !== -1)
|
| 67 |
+
message_iframes.push(iframes[i])
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
let messages = []
|
| 71 |
+
let mailbox = document.getElementsByClassName('list')[0].children[1].children
|
| 72 |
+
for(let i = 0; i < mailbox.length; i++) {
|
| 73 |
+
let temp = mailbox[i].innerText.split('\n')
|
| 74 |
+
messages.push([temp[1].trim(), temp[2].trim(), message_iframes[i].srcdoc])
|
| 75 |
+
}
|
| 76 |
+
return messages
|
| 77 |
+
"""
|
| 78 |
+
PARSE_INCOGNITOMAIL_INBOX = """
|
| 79 |
+
let li_elements = document.getElementsByTagName('li')
|
| 80 |
+
let messages_header = []
|
| 81 |
+
for (let i = 0; i < li_elements.length; i++) {
|
| 82 |
+
let headers = li_elements[i].querySelectorAll('p')
|
| 83 |
+
try {
|
| 84 |
+
if (headers[0].title != '' && headers[1].title != '')
|
| 85 |
+
messages_header.push([headers[0], headers[0].title, headers[1].title])
|
| 86 |
+
} catch (error) { }
|
| 87 |
+
}
|
| 88 |
+
return messages_header
|
| 89 |
+
"""
|
| 90 |
+
|
| 91 |
+
class OneSecEmailAPI:
|
| 92 |
+
def __init__(self):
|
| 93 |
+
self.class_name = '1secmail'
|
| 94 |
+
self.__login = None
|
| 95 |
+
self.__domain = None
|
| 96 |
+
self.email = None
|
| 97 |
+
self.__api = 'https://www.1secmail.com/api/v1/'
|
| 98 |
+
|
| 99 |
+
def init(self):
|
| 100 |
+
url = f'{self.__api}?action=genRandomMailbox&count=1'
|
| 101 |
+
try:
|
| 102 |
+
r = requests.get(url)
|
| 103 |
+
except:
|
| 104 |
+
raise RuntimeError('SecEmailAPI: API access error!')
|
| 105 |
+
if r.status_code != 200:
|
| 106 |
+
raise RuntimeError('SecEmailAPI: API access error!')
|
| 107 |
+
self.__login, self.__domain = str(r.content, 'utf-8')[2:-2].split('@')
|
| 108 |
+
self.email = self.__login+'@'+self.__domain
|
| 109 |
+
|
| 110 |
+
def login(self, login, domain):
|
| 111 |
+
self.__login = login
|
| 112 |
+
self.__domain = domain
|
| 113 |
+
|
| 114 |
+
def read_email(self):
|
| 115 |
+
url = f'{self.__api}?action=getMessages&login={self.__login}&domain={self.__domain}'
|
| 116 |
+
print(url)
|
| 117 |
+
try:
|
| 118 |
+
r = requests.get(url)
|
| 119 |
+
except:
|
| 120 |
+
raise RuntimeError('SecEmailAPI: API access error!')
|
| 121 |
+
if r.status_code != 200:
|
| 122 |
+
raise RuntimeError('SecEmailAPI: API access error!')
|
| 123 |
+
return r.json()
|
| 124 |
+
|
| 125 |
+
def get_message(self, message_id):
|
| 126 |
+
url = f'{self.__api}?action=readMessage&login={self.__login}&domain={self.__domain}&id={message_id}'
|
| 127 |
+
print(url)
|
| 128 |
+
try:
|
| 129 |
+
r = requests.get(url)
|
| 130 |
+
except:
|
| 131 |
+
raise RuntimeError('SecEmailAPI: API access error!')
|
| 132 |
+
if r.status_code != 200:
|
| 133 |
+
raise RuntimeError('SecEmailAPI: API access error!')
|
| 134 |
+
return r.json()
|
| 135 |
+
|
| 136 |
+
class DeveloperMailAPI:
|
| 137 |
+
def __init__(self):
|
| 138 |
+
self.class_name = 'developermail'
|
| 139 |
+
self.email = None
|
| 140 |
+
self.email_name = ''
|
| 141 |
+
self.headers = {}
|
| 142 |
+
self.api_url = 'https://www.developermail.com/api/v1'
|
| 143 |
+
|
| 144 |
+
def init(self):
|
| 145 |
+
r = requests.put(f'{self.api_url}/mailbox')
|
| 146 |
+
self.email_name, token = list(r.json()['result'].values())
|
| 147 |
+
self.email = self.email_name+'@developermail.com'
|
| 148 |
+
self.headers = {'X-MailboxToken': token}
|
| 149 |
+
|
| 150 |
+
def __parse_message(self, raw_message_body):
|
| 151 |
+
message_bytes = raw_message_body.encode('utf-8')
|
| 152 |
+
msg = parser.BytesParser(policy=policy.default).parsebytes(message_bytes)
|
| 153 |
+
message_subject = msg['subject']
|
| 154 |
+
message_from = msg['from']
|
| 155 |
+
message_body = str(msg.get_payload(decode=True).decode(msg.get_content_charset())) # decoding MIME-Type to html
|
| 156 |
+
return {'subject':message_subject, 'from':message_from, 'body':message_body}
|
| 157 |
+
|
| 158 |
+
def get_messages(self):
|
| 159 |
+
# get message IDs
|
| 160 |
+
r = requests.get(
|
| 161 |
+
f'{self.api_url}/mailbox/{self.email_name}',
|
| 162 |
+
headers=self.headers
|
| 163 |
+
)
|
| 164 |
+
message_ids = r.json()['result']
|
| 165 |
+
if message_ids == []:
|
| 166 |
+
return None
|
| 167 |
+
# parse messages
|
| 168 |
+
messages = []
|
| 169 |
+
for message_id in message_ids:
|
| 170 |
+
try:
|
| 171 |
+
r = requests.get(f'{self.api_url}/mailbox/{self.email_name}/messages/{message_id}', headers=self.headers)
|
| 172 |
+
raw_message_body = r.json()['result']
|
| 173 |
+
messages.append(self.__parse_message(raw_message_body))
|
| 174 |
+
except:
|
| 175 |
+
continue
|
| 176 |
+
if messages == []:
|
| 177 |
+
messages = None
|
| 178 |
+
return messages
|
| 179 |
+
|
| 180 |
+
class GuerRillaMailAPI:
|
| 181 |
+
def __init__(self, driver: Chrome):
|
| 182 |
+
self.class_name = 'guerrillamail'
|
| 183 |
+
self.driver = driver
|
| 184 |
+
self.email = None
|
| 185 |
+
self.window_handle = None
|
| 186 |
+
|
| 187 |
+
def init(self):
|
| 188 |
+
self.driver.get('https://www.guerrillamail.com/')
|
| 189 |
+
self.window_handle = self.driver.current_window_handle
|
| 190 |
+
untilConditionExecute(self.driver, f'return {GET_EBID}("email-widget") != null')
|
| 191 |
+
self.email = self.driver.execute_script(f'return {GET_EBID}("email-widget").innerText')
|
| 192 |
+
# change to random available domain
|
| 193 |
+
self.email = self.email.split('@')[0]+'@'+random.choice(self.driver.execute_script(GET_GUERRILLAMAIL_DOMAINS))
|
| 194 |
+
|
| 195 |
+
def parse_inbox(self):
|
| 196 |
+
self.driver.switch_to.window(self.window_handle)
|
| 197 |
+
self.driver.get('https://www.guerrillamail.com/')
|
| 198 |
+
inbox = self.driver.execute_script(PARSE_GUERRILLAMAIL_INBOX)
|
| 199 |
+
return inbox
|
| 200 |
+
|
| 201 |
+
def open_mail(self, id):
|
| 202 |
+
self.driver.switch_to.window(self.window_handle)
|
| 203 |
+
self.driver.get(f'https://www.guerrillamail.com/inbox?mail_id={id}')
|
| 204 |
+
|
| 205 |
+
class MailTickingAPI:
|
| 206 |
+
def __init__(self, driver: Chrome):
|
| 207 |
+
self.class_name = 'mailticking'
|
| 208 |
+
self.driver = driver
|
| 209 |
+
self.email = None
|
| 210 |
+
self.window_handle = None
|
| 211 |
+
|
| 212 |
+
def init(self):
|
| 213 |
+
try:
|
| 214 |
+
self.driver.get('https://www.mailticking.com')
|
| 215 |
+
self.window_handle = self.driver.current_window_handle
|
| 216 |
+
untilConditionExecute(self.driver, f'return {CLICK_WITH_BOOL}({GET_EBCN}("modal-footer text-center")[1].children[0])')
|
| 217 |
+
untilConditionExecute(self.driver, f'return {GET_EBID}("active-mail") != null')
|
| 218 |
+
time.sleep(3)
|
| 219 |
+
self.email = self.driver.execute_script(f'return {GET_EBID}("active-mail").value')
|
| 220 |
+
return True
|
| 221 |
+
except:
|
| 222 |
+
raise RuntimeError("MailTickingAPI.init Error!")
|
| 223 |
+
|
| 224 |
+
def parse_inbox(self):
|
| 225 |
+
self.driver.switch_to.window(self.window_handle)
|
| 226 |
+
self.driver.get('https://www.mailticking.com')
|
| 227 |
+
try:
|
| 228 |
+
self.driver.execute_script(f'return {GET_EBID}("refresh-button")').click()
|
| 229 |
+
time.sleep(1)
|
| 230 |
+
inbox = self.driver.execute_script(PARSE_MAILTICKING_INBOX)
|
| 231 |
+
except:
|
| 232 |
+
inbox = []
|
| 233 |
+
return inbox
|
| 234 |
+
|
| 235 |
+
def open_mail(self, id):
|
| 236 |
+
self.driver.switch_to.window(self.window_handle)
|
| 237 |
+
self.driver.get(id)
|
| 238 |
+
|
| 239 |
+
class FakeMailAPI:
|
| 240 |
+
def __init__(self, driver: Chrome):
|
| 241 |
+
self.class_name = 'fakemail'
|
| 242 |
+
self.driver = driver
|
| 243 |
+
self.email = None
|
| 244 |
+
self.window_handle = None
|
| 245 |
+
|
| 246 |
+
def init(self):
|
| 247 |
+
self.driver.get('https://www.fakemail.net')
|
| 248 |
+
self.window_handle = self.driver.current_window_handle
|
| 249 |
+
untilConditionExecute(self.driver, f'return {GET_EBID}("email").innerText != null')
|
| 250 |
+
self.email = self.driver.execute_script(f'return {GET_EBID}("email").innerText')
|
| 251 |
+
|
| 252 |
+
def parse_inbox(self):
|
| 253 |
+
self.driver.switch_to.window(self.window_handle)
|
| 254 |
+
self.driver.get('https://www.fakemail.net')
|
| 255 |
+
inbox = self.driver.execute_script(PARSE_FAKEMAIL_INBOX)
|
| 256 |
+
return inbox
|
| 257 |
+
|
| 258 |
+
def open_mail(self, id):
|
| 259 |
+
self.driver.switch_to.window(self.window_handle)
|
| 260 |
+
self.driver.get(f'https://www.fakemail.net/email/id/{id}')
|
| 261 |
+
|
| 262 |
+
class InboxesAPI:
|
| 263 |
+
def __init__(self, driver: Chrome):
|
| 264 |
+
self.class_name = 'inboxes'
|
| 265 |
+
self.driver = driver
|
| 266 |
+
self.email = None
|
| 267 |
+
self.window_handle = None
|
| 268 |
+
|
| 269 |
+
def init(self):
|
| 270 |
+
self.driver.get('https://inboxes.com')
|
| 271 |
+
self.window_handle = self.driver.current_window_handle
|
| 272 |
+
button = None
|
| 273 |
+
for _ in range(DEFAULT_MAX_ITER):
|
| 274 |
+
try:
|
| 275 |
+
button = self.driver.find_element('xpath', '//button[contains(text(), "Get my first inbox!")]')
|
| 276 |
+
break
|
| 277 |
+
except:
|
| 278 |
+
pass
|
| 279 |
+
time.sleep(DEFAULT_DELAY)
|
| 280 |
+
if button is not None:
|
| 281 |
+
button.click()
|
| 282 |
+
time.sleep(1)
|
| 283 |
+
for button in self.driver.execute_script(f'return {GET_EBTN}("button")'):
|
| 284 |
+
if button.text.strip().lower() == 'choose for me':
|
| 285 |
+
button.click()
|
| 286 |
+
break
|
| 287 |
+
time.sleep(2)
|
| 288 |
+
for element in self.driver.execute_script(f'return {GET_EBTN}("span")'):
|
| 289 |
+
new_email = ''.join(element.text.split())
|
| 290 |
+
if new_email is not None:
|
| 291 |
+
new_email = re.match(r'[-a-z0-9+.]+@[a-z]+(\.[a-z]+)+', new_email)
|
| 292 |
+
if new_email is not None:
|
| 293 |
+
self.email = new_email.group()
|
| 294 |
+
break
|
| 295 |
+
|
| 296 |
+
def get_messages(self):
|
| 297 |
+
r = requests.get(f'https://inboxes.com/api/v2/inbox/{self.email}')
|
| 298 |
+
raw_inbox = r.json()['msgs']
|
| 299 |
+
messages = []
|
| 300 |
+
for message in raw_inbox:
|
| 301 |
+
r = requests.get(f'https://inboxes.com/api/v2/message/{message["uid"]}').json()
|
| 302 |
+
messages.append({
|
| 303 |
+
'from': r['ff'][0]['address'],
|
| 304 |
+
'subject': message['s'],
|
| 305 |
+
'body': r['html']
|
| 306 |
+
})
|
| 307 |
+
return messages
|
| 308 |
+
|
| 309 |
+
"""class OneSecMailProAPI:
|
| 310 |
+
def __init__(self, driver: Chrome):
|
| 311 |
+
self.class_name = '1secmailpro'
|
| 312 |
+
self.driver = driver
|
| 313 |
+
self.email = None
|
| 314 |
+
self.window_handle = None
|
| 315 |
+
|
| 316 |
+
def init(self):
|
| 317 |
+
self.driver.get("https://1secmail.pro")
|
| 318 |
+
self.window_handle = self.driver.current_window_handle
|
| 319 |
+
untilConditionExecute(self.driver, f"return {CLICK_WITH_BOOL}(document.querySelectorAll('input.block')[3])")
|
| 320 |
+
for _ in range(5):
|
| 321 |
+
if self.driver.page_source.lower().find('you have reached daily limit of maximum 5 temp mail addresses') != -1:
|
| 322 |
+
console_log('[1secmailpro]: Daily limit reached!', ERROR)
|
| 323 |
+
return False
|
| 324 |
+
time.sleep(DEFAULT_DELAY)
|
| 325 |
+
untilConditionExecute(self.driver, f"return {GET_EBID}('email_id').innerText != ''", delay=0.5, max_iter=20)
|
| 326 |
+
self.email = self.driver.execute_script(f"return {GET_EBID}('email_id').innerText")
|
| 327 |
+
|
| 328 |
+
def get_messages(self):
|
| 329 |
+
self.driver.switch_to.window(self.window_handle)
|
| 330 |
+
self.driver.get("https://1secmail.pro/mailbox")
|
| 331 |
+
for _ in range(5):
|
| 332 |
+
try:
|
| 333 |
+
messages_list = self.driver.execute_script(PARSE_1SECMAILPRO_INBOX)
|
| 334 |
+
print(messages_list)
|
| 335 |
+
if messages_list is not None:
|
| 336 |
+
messages = []
|
| 337 |
+
for message in messages_list:
|
| 338 |
+
messages.append({
|
| 339 |
+
'from': message[0],
|
| 340 |
+
'subject': message[1],
|
| 341 |
+
'body': message[2]
|
| 342 |
+
})
|
| 343 |
+
return messages
|
| 344 |
+
except Exception as E:
|
| 345 |
+
pass
|
| 346 |
+
time.sleep(DEFAULT_DELAY)"""
|
| 347 |
+
|
| 348 |
+
class IncognitoMailAPI:
|
| 349 |
+
def __init__(self, driver: Chrome):
|
| 350 |
+
self.class_name = 'incognitomail'
|
| 351 |
+
self.driver = driver
|
| 352 |
+
self.email = None
|
| 353 |
+
self.window_handle = None
|
| 354 |
+
|
| 355 |
+
def init(self):
|
| 356 |
+
self.driver.get("https://incognitomail.co/")
|
| 357 |
+
self.window_handle = self.driver.current_window_handle
|
| 358 |
+
untilConditionExecute(self.driver, f"return {GET_EBAV}('button', 'aria-label', 'Email dropdown').textContent != 'Creating...'")
|
| 359 |
+
self.email = self.driver.execute_script(f"return {GET_EBAV}('button', 'aria-label', 'Email dropdown').textContent")
|
| 360 |
+
|
| 361 |
+
def parse_inbox(self):
|
| 362 |
+
self.driver.switch_to.window(self.window_handle)
|
| 363 |
+
self.driver.get("https://incognitomail.co")
|
| 364 |
+
for _ in range(3):
|
| 365 |
+
try:
|
| 366 |
+
inbox_headers = self.driver.execute_script(PARSE_INCOGNITOMAIL_INBOX)
|
| 367 |
+
if inbox_headers != [] and inbox_headers is not None:
|
| 368 |
+
return inbox_headers
|
| 369 |
+
except Exception as E:
|
| 370 |
+
pass
|
| 371 |
+
time.sleep(DEFAULT_DELAY)
|
| 372 |
+
return []
|
| 373 |
+
|
| 374 |
+
def open_mail(self, web_element):
|
| 375 |
+
self.driver.switch_to.window(self.window_handle)
|
| 376 |
+
web_element.click()
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
class CustomEmailAPI:
|
| 380 |
+
def __init__(self):
|
| 381 |
+
self.class_name = 'custom'
|
| 382 |
+
self.email = None
|
| 383 |
+
|
| 384 |
+
WEB_WRAPPER_EMAIL_APIS_CLASSES = (GuerRillaMailAPI, MailTickingAPI, FakeMailAPI, InboxesAPI, IncognitoMailAPI)
|
modules/EsetTools.py
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .EmailAPIs import *
|
| 2 |
+
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
import subprocess
|
| 6 |
+
import colorama
|
| 7 |
+
import logging
|
| 8 |
+
import time
|
| 9 |
+
import sys
|
| 10 |
+
|
| 11 |
+
SILENT_MODE = '--silent' in sys.argv
|
| 12 |
+
|
| 13 |
+
class IPBlockedException(Exception):
|
| 14 |
+
def __init__(self, message):
|
| 15 |
+
super().__init__(message)
|
| 16 |
+
|
| 17 |
+
class EsetRegister(object):
|
| 18 |
+
def __init__(self, registered_email_obj: OneSecEmailAPI, eset_password: str, driver: Chrome):
|
| 19 |
+
self.email_obj = registered_email_obj
|
| 20 |
+
self.eset_password = eset_password
|
| 21 |
+
self.driver = driver
|
| 22 |
+
self.window_handle = None
|
| 23 |
+
|
| 24 |
+
def createAccount(self):
|
| 25 |
+
exec_js = self.driver.execute_script
|
| 26 |
+
uCE = untilConditionExecute
|
| 27 |
+
|
| 28 |
+
logging.info('[EMAIL] Register page loading...')
|
| 29 |
+
console_log('\n[EMAIL] Register page loading...', INFO, silent_mode=SILENT_MODE)
|
| 30 |
+
if isinstance(self.email_obj, WEB_WRAPPER_EMAIL_APIS_CLASSES):
|
| 31 |
+
self.driver.switch_to.new_window('tab')
|
| 32 |
+
self.window_handle = self.driver.current_window_handle
|
| 33 |
+
self.driver.get('https://login.eset.com/Register')
|
| 34 |
+
uCE(self.driver, f"return {GET_EBID}('email') != null")
|
| 35 |
+
logging.info('[EMAIL] Register page is loaded!')
|
| 36 |
+
console_log('[EMAIL] Register page is loaded!', OK, silent_mode=SILENT_MODE)
|
| 37 |
+
|
| 38 |
+
logging.info('Bypassing cookies...')
|
| 39 |
+
console_log('\nBypassing cookies...', INFO, silent_mode=SILENT_MODE)
|
| 40 |
+
if uCE(self.driver, f"return {CLICK_WITH_BOOL}({GET_EBAV}('button', 'id', 'cc-accept'))", max_iter=10, raise_exception_if_failed=False):
|
| 41 |
+
logging.info('Cookies successfully bypassed!')
|
| 42 |
+
console_log('Cookies successfully bypassed!', OK, silent_mode=SILENT_MODE)
|
| 43 |
+
time.sleep(1) # Once pressed, you have to wait a little while. If code do not do this, the site does not count the acceptance of cookies
|
| 44 |
+
else:
|
| 45 |
+
logging.info('Cookies were not bypassed (it doesn\'t affect the algorithm, I think :D)')
|
| 46 |
+
console_log("Cookies were not bypassed (it doesn't affect the algorithm, I think :D)", ERROR, silent_mode=SILENT_MODE)
|
| 47 |
+
|
| 48 |
+
exec_js(f"return {GET_EBID}('email')").send_keys(self.email_obj.email)
|
| 49 |
+
uCE(self.driver, f"return {CLICK_WITH_BOOL}({DEFINE_GET_EBAV_FUNCTION}('button', 'data-label', 'register-continue-button'))")
|
| 50 |
+
|
| 51 |
+
logging.info('[PASSWD] Register page loading...')
|
| 52 |
+
console_log('\n[PASSWD] Register page loading...', INFO, silent_mode=SILENT_MODE)
|
| 53 |
+
uCE(self.driver, f"return typeof {GET_EBAV}('button', 'data-label', 'register-create-account-button') === 'object'")
|
| 54 |
+
logging.info('[PASSWD] Register page is loaded!')
|
| 55 |
+
console_log('[PASSWD] Register page is loaded!', OK, silent_mode=SILENT_MODE)
|
| 56 |
+
exec_js(f"return {GET_EBID}('password')").send_keys(self.eset_password)
|
| 57 |
+
|
| 58 |
+
# Select Ukraine country
|
| 59 |
+
logging.info('Selecting the country...')
|
| 60 |
+
if exec_js(f"return {GET_EBCN}('select__single-value ltr-1dimb5e-singleValue')[0]").text != 'Ukraine':
|
| 61 |
+
exec_js(f"return {GET_EBCN}('select__control ltr-13cymwt-control')[0]").click()
|
| 62 |
+
for country in exec_js(f"return {GET_EBCN}('select__option ltr-uhiml7-option')"):
|
| 63 |
+
if country.text == 'Ukraine':
|
| 64 |
+
country.click()
|
| 65 |
+
logging.info('Country selected!')
|
| 66 |
+
break
|
| 67 |
+
|
| 68 |
+
uCE(self.driver, f"return {CLICK_WITH_BOOL}({DEFINE_GET_EBAV_FUNCTION}('button', 'data-label', 'register-create-account-button'))")
|
| 69 |
+
|
| 70 |
+
for _ in range(DEFAULT_MAX_ITER):
|
| 71 |
+
title = exec_js('return document.title')
|
| 72 |
+
if title == 'Service not available':
|
| 73 |
+
raise IPBlockedException('\nESET temporarily blocked your IP, try again later!!! Try to use VPN/Proxy or try to change Email API!!!')
|
| 74 |
+
url = exec_js('return document.URL')
|
| 75 |
+
if url == 'https://home.eset.com/':
|
| 76 |
+
return True
|
| 77 |
+
time.sleep(DEFAULT_DELAY)
|
| 78 |
+
raise IPBlockedException('\nESET temporarily blocked your IP, try again later!!! Try to use VPN/Proxy or try to change Email API!!!')
|
| 79 |
+
|
| 80 |
+
def confirmAccount(self):
|
| 81 |
+
uCE = untilConditionExecute
|
| 82 |
+
#uCE(self.driver, f'return {CLICK_WITH_BOOL}({GET_EBAV}("ion-button", "data-r", "account-verification-email-modal-resend-email-btn"))') # accelerating the receipt of an eset token
|
| 83 |
+
|
| 84 |
+
if isinstance(self.email_obj, CustomEmailAPI):
|
| 85 |
+
token = parseToken(self.email_obj, max_iter=100, delay=3)
|
| 86 |
+
else:
|
| 87 |
+
logging.info(f'[{self.email_obj.class_name}] ESET-HOME-Token interception...')
|
| 88 |
+
console_log(f'\n[{self.email_obj.class_name}] ESET-HOME-Token interception...', INFO, silent_mode=SILENT_MODE)
|
| 89 |
+
if isinstance(self.email_obj, WEB_WRAPPER_EMAIL_APIS_CLASSES):
|
| 90 |
+
token = parseToken(self.email_obj, self.driver, max_iter=100, delay=3)
|
| 91 |
+
self.driver.switch_to.window(self.window_handle)
|
| 92 |
+
else:
|
| 93 |
+
token = parseToken(self.email_obj, max_iter=100, delay=3) # 1secmail, developermail
|
| 94 |
+
logging.info(f'ESET-HOME-Token: {token}')
|
| 95 |
+
logging.info('Account confirmation is in progress...')
|
| 96 |
+
console_log(f'ESET-HOME-Token: {token}', OK, silent_mode=SILENT_MODE)
|
| 97 |
+
console_log('\nAccount confirmation is in progress...', INFO, silent_mode=SILENT_MODE)
|
| 98 |
+
self.driver.get(f'https://login.eset.com/link/confirmregistration?token={token}')
|
| 99 |
+
uCE(self.driver, 'return document.title === "ESET HOME"')
|
| 100 |
+
try:
|
| 101 |
+
uCE(self.driver, f'return {GET_EBCN}("verification-email_p").length === 0')
|
| 102 |
+
except:
|
| 103 |
+
self.driver.get(f'https://login.eset.com/link/confirmregistration?token={token}')
|
| 104 |
+
uCE(self.driver, 'return document.title === "ESET HOME"')
|
| 105 |
+
uCE(self.driver, f'return {GET_EBCN}("verification-email_p").length === 0')
|
| 106 |
+
logging.info('Account successfully confirmed!')
|
| 107 |
+
console_log('Account successfully confirmed!', OK, silent_mode=SILENT_MODE)
|
| 108 |
+
return True
|
| 109 |
+
|
| 110 |
+
class EsetKeygen(object):
|
| 111 |
+
def __init__(self, registered_email_obj: OneSecEmailAPI, driver: Chrome, mode='ESET HOME'):
|
| 112 |
+
self.email_obj = registered_email_obj
|
| 113 |
+
self.driver = driver
|
| 114 |
+
self.mode = mode.upper()
|
| 115 |
+
if self.mode not in ['ESET HOME', 'SMALL BUSINESS']:
|
| 116 |
+
raise RuntimeError('Undefined keygen mode!')
|
| 117 |
+
|
| 118 |
+
def sendRequestForKey(self):
|
| 119 |
+
uCE = untilConditionExecute
|
| 120 |
+
|
| 121 |
+
logging.info(f'[{self.mode}] Request sending...')
|
| 122 |
+
console_log(f'\n[{self.mode}] Request sending...', INFO, silent_mode=SILENT_MODE)
|
| 123 |
+
self.driver.get('https://home.eset.com/subscriptions/choose-trial')
|
| 124 |
+
uCE(self.driver, f"return {GET_EBAV}('button', 'data-label', 'subscription-choose-trial-ehsp-card-button') != null")
|
| 125 |
+
if self.mode == 'ESET HOME':
|
| 126 |
+
uCE(self.driver, f"return {CLICK_WITH_BOOL}({GET_EBAV}('button', 'data-label', 'subscription-choose-trial-ehsp-card-button'))")
|
| 127 |
+
elif self.mode == 'SMALL BUSINESS':
|
| 128 |
+
uCE(self.driver, f"return {CLICK_WITH_BOOL}({GET_EBAV}('button', 'data-label', 'subscription-choose-trial-esbs-card-button'))")
|
| 129 |
+
try:
|
| 130 |
+
for button in self.driver.find_elements('tag name', 'button'):
|
| 131 |
+
if button.get_attribute('innerText').strip().lower() == 'continue':
|
| 132 |
+
button.click()
|
| 133 |
+
break
|
| 134 |
+
time.sleep(0.05)
|
| 135 |
+
else:
|
| 136 |
+
raise RuntimeError('Continue button error!')
|
| 137 |
+
uCE(self.driver, f"return {CLICK_WITH_BOOL}({GET_EBAV}('button', 'data-label', 'subscription-choose-trial-esbs-card-button'))")
|
| 138 |
+
time.sleep(1)
|
| 139 |
+
for button in self.driver.find_elements('tag name', 'button'):
|
| 140 |
+
if button.get_attribute('innerText').strip().lower() == 'continue':
|
| 141 |
+
button.click()
|
| 142 |
+
break
|
| 143 |
+
time.sleep(0.05)
|
| 144 |
+
else:
|
| 145 |
+
raise RuntimeError('Continue button error!')
|
| 146 |
+
logging.info(f'[{self.mode}] Request successfully sent!')
|
| 147 |
+
console_log(f'[{self.mode}] Request successfully sent!', OK, silent_mode=SILENT_MODE)
|
| 148 |
+
except:
|
| 149 |
+
raise RuntimeError('Request sending error!!!')
|
| 150 |
+
|
| 151 |
+
def getLD(self):
|
| 152 |
+
exec_js = self.driver.execute_script
|
| 153 |
+
uCE = untilConditionExecute
|
| 154 |
+
logging.info(f'License uploads...')
|
| 155 |
+
console_log('\nLicense uploads...', INFO, silent_mode=SILENT_MODE)
|
| 156 |
+
uCE(self.driver, f"return {GET_EBAV}('div', 'data-label', 'license-detail-info') != null", raise_exception_if_failed=False)
|
| 157 |
+
if self.driver.current_url.find('detail') != -1:
|
| 158 |
+
logging.info(f'License ID: {self.driver.current_url[-11:]}')
|
| 159 |
+
console_log(f'License ID: {self.driver.current_url[-11:]}', OK, silent_mode=SILENT_MODE)
|
| 160 |
+
uCE(self.driver, f"return {GET_EBAV}('div', 'data-label', 'license-detail-product-name') != null", max_iter=10)
|
| 161 |
+
uCE(self.driver, f"return {GET_EBAV}('div', 'data-label', 'license-detail-license-model-additional-info') != null", max_iter=10)
|
| 162 |
+
uCE(self.driver, f"return {GET_EBAV}('div', 'data-label', 'license-detail-license-key') != null", max_iter=10)
|
| 163 |
+
license_name = exec_js(f"return {GET_EBAV}('div', 'data-label', 'license-detail-product-name').innerText")
|
| 164 |
+
license_out_date = exec_js(f"return {GET_EBAV}('div', 'data-label', 'license-detail-license-model-additional-info').innerText")
|
| 165 |
+
license_key = exec_js(f"return {GET_EBAV}('div', 'data-label', 'license-detail-license-key').innerText")
|
| 166 |
+
logging.info('Information successfully received!')
|
| 167 |
+
console_log('Information successfully received!', OK, silent_mode=SILENT_MODE)
|
| 168 |
+
return license_name, license_key, license_out_date
|
| 169 |
+
|
| 170 |
+
class EsetVPN(object):
|
| 171 |
+
def __init__(self, registered_email_obj: OneSecEmailAPI, driver: Chrome, EsetRegister_window_handle=None):
|
| 172 |
+
self.email_obj = registered_email_obj
|
| 173 |
+
self.driver = driver
|
| 174 |
+
self.window_handle = EsetRegister_window_handle
|
| 175 |
+
|
| 176 |
+
def sendRequestForVPNCodes(self):
|
| 177 |
+
exec_js = self.driver.execute_script
|
| 178 |
+
uCE = untilConditionExecute
|
| 179 |
+
|
| 180 |
+
logging.info('Sending a request for VPN subscriptions...')
|
| 181 |
+
console_log('\nSending a request for VPN subscriptions...', INFO, silent_mode=SILENT_MODE)
|
| 182 |
+
self.driver.get("https://home.eset.com/security-features")
|
| 183 |
+
try:
|
| 184 |
+
uCE(self.driver, f'return {CLICK_WITH_BOOL}({GET_EBAV}("button", "data-label", "security-feature-explore-button"))', max_iter=10)
|
| 185 |
+
except:
|
| 186 |
+
raise RuntimeError('Explore-feature-button error!')
|
| 187 |
+
time.sleep(0.5)
|
| 188 |
+
for profile in exec_js(f'return {GET_EBAV}("button", "data-label", "choose-profile-tile-button", -1)'): # choose Me profile
|
| 189 |
+
if profile.get_attribute("innerText").find(self.email_obj.email) != -1: # Me profile contains an email address
|
| 190 |
+
profile.click()
|
| 191 |
+
uCE(self.driver, f'return {CLICK_WITH_BOOL}({GET_EBAV}("button", "data-label", "choose-profile-continue-btn"))', max_iter=5)
|
| 192 |
+
uCE(self.driver, f'return {GET_EBAV}("ion-button", "robot", "choose-device-counter-increment-button") != null', max_iter=10)
|
| 193 |
+
for _ in range(9): # increasing 'Number of devices' (to 10)
|
| 194 |
+
exec_js(f'{GET_EBAV}("ion-button", "robot", "choose-device-counter-increment-button").click()')
|
| 195 |
+
exec_js(f'{GET_EBAV}("button", "data-label", "choose-device-count-submit-button").click()')
|
| 196 |
+
uCE(self.driver, f'return {GET_EBAV}("button", "data-label", "pwm-instructions-sent-download-button") != null', max_iter=15)
|
| 197 |
+
logging.info('Request successfully sent!')
|
| 198 |
+
console_log('Request successfully sent!', OK, silent_mode=SILENT_MODE)
|
| 199 |
+
return True
|
| 200 |
+
|
| 201 |
+
def getVPNCodes(self):
|
| 202 |
+
if isinstance(self.email_obj, CustomEmailAPI):
|
| 203 |
+
logging.warning('Wait for a message to your e-mail about instructions on how to set up the VPN!!!')
|
| 204 |
+
console_log('\nWait for a message to your e-mail about instructions on how to set up the VPN!!!', WARN, True, SILENT_MODE)
|
| 205 |
+
return None
|
| 206 |
+
else:
|
| 207 |
+
logging.info(f'[{self.email_obj.class_name}] VPN Codes interception...')
|
| 208 |
+
console_log(f'\n[{self.email_obj.class_name}] VPN Codes interception...', INFO, silent_mode=SILENT_MODE) # timeout 1.5m
|
| 209 |
+
if isinstance(self.email_obj, WEB_WRAPPER_EMAIL_APIS_CLASSES):
|
| 210 |
+
vpn_codes = parseVPNCodes(self.email_obj, self.driver, delay=2, max_iter=45)
|
| 211 |
+
self.driver.switch_to.window(self.window_handle)
|
| 212 |
+
else:
|
| 213 |
+
vpn_codes = parseVPNCodes(self.email_obj, self.driver, delay=2, max_iter=45) # 1secmail, developermail
|
| 214 |
+
logging.info('Information successfully received!')
|
| 215 |
+
console_log('Information successfully received!', OK, silent_mode=SILENT_MODE)
|
| 216 |
+
return vpn_codes
|
| 217 |
+
|
| 218 |
+
class EsetProtectHubRegister(object):
|
| 219 |
+
def __init__(self, registered_email_obj: OneSecEmailAPI, eset_password: str, driver: Chrome):
|
| 220 |
+
self.email_obj = registered_email_obj
|
| 221 |
+
self.driver = driver
|
| 222 |
+
self.eset_password = eset_password
|
| 223 |
+
self.window_handle = None
|
| 224 |
+
|
| 225 |
+
def createAccount(self):
|
| 226 |
+
exec_js = self.driver.execute_script
|
| 227 |
+
uCE = untilConditionExecute
|
| 228 |
+
# STEP 0
|
| 229 |
+
|
| 230 |
+
logging.info('Loading ESET ProtectHub Page...')
|
| 231 |
+
console_log('\nLoading ESET ProtectHub Page...', INFO, silent_mode=SILENT_MODE)
|
| 232 |
+
if isinstance(self.email_obj, WEB_WRAPPER_EMAIL_APIS_CLASSES):
|
| 233 |
+
self.driver.switch_to.new_window('tab')
|
| 234 |
+
self.window_handle = self.driver.current_window_handle
|
| 235 |
+
self.driver.get('https://protecthub.eset.com/public/registration?culture=en-US')
|
| 236 |
+
uCE(self.driver, f'return {GET_EBID}("continue") != null')
|
| 237 |
+
logging.info('Successfully!')
|
| 238 |
+
console_log('Successfully!', OK, silent_mode=SILENT_MODE)
|
| 239 |
+
|
| 240 |
+
# STEP 1
|
| 241 |
+
logging.info('Data filling...')
|
| 242 |
+
console_log('\nData filling...', INFO, silent_mode=SILENT_MODE)
|
| 243 |
+
exec_js(f'return {GET_EBID}("email-input")').send_keys(self.email_obj.email)
|
| 244 |
+
exec_js(f'return {GET_EBID}("company-name-input")').send_keys(dataGenerator(10))
|
| 245 |
+
# Select country
|
| 246 |
+
exec_js(f"return {GET_EBID}('country-select')").click()
|
| 247 |
+
selected_country = 'Ukraine'
|
| 248 |
+
logging.info('Selecting the country...')
|
| 249 |
+
for country in self.driver.find_elements('xpath', '//div[starts-with(@class, "select")]'):
|
| 250 |
+
if country.text == selected_country:
|
| 251 |
+
country.click()
|
| 252 |
+
logging.info('Country selected!')
|
| 253 |
+
break
|
| 254 |
+
exec_js(f'return {GET_EBID}("company-vat-input")').send_keys(dataGenerator(10, True))
|
| 255 |
+
exec_js(f'return {GET_EBID}("company-crn-input")').send_keys(dataGenerator(10, True))
|
| 256 |
+
logging.warning('Solve the captcha on the page manually!!!')
|
| 257 |
+
console_log(f'\n{colorama.Fore.CYAN}Solve the captcha on the page manually!!!{colorama.Fore.RESET}', INFO, False, SILENT_MODE)
|
| 258 |
+
while True: # captcha
|
| 259 |
+
try:
|
| 260 |
+
mtcaptcha_solved_token = exec_js(f'return {GET_EBCN}("mtcaptcha-verifiedtoken")[0].value')
|
| 261 |
+
if mtcaptcha_solved_token.strip() != '':
|
| 262 |
+
break
|
| 263 |
+
except Exception as E:
|
| 264 |
+
pass
|
| 265 |
+
time.sleep(1)
|
| 266 |
+
exec_js(f'return {GET_EBID}("continue").click()')
|
| 267 |
+
try:
|
| 268 |
+
uCE(self.driver, f'return {GET_EBID}("registration-email-sent").innerText === "We sent you a verification email"', max_iter=10)
|
| 269 |
+
logging.info('Successfully!')
|
| 270 |
+
console_log('Successfully!', OK, silent_mode=SILENT_MODE)
|
| 271 |
+
except:
|
| 272 |
+
raise IPBlockedException('\nESET temporarily blocked your IP, try again later!!! Try to use VPN/Proxy or try to change Email API!!!')
|
| 273 |
+
return True
|
| 274 |
+
|
| 275 |
+
def activateAccount(self):
|
| 276 |
+
exec_js = self.driver.execute_script
|
| 277 |
+
uCE = untilConditionExecute
|
| 278 |
+
|
| 279 |
+
# STEP 1
|
| 280 |
+
logging.info('Data filling...')
|
| 281 |
+
console_log('\nData filling...', INFO, silent_mode=SILENT_MODE)
|
| 282 |
+
exec_js(f'return {GET_EBID}("first-name-input")').send_keys(dataGenerator(10))
|
| 283 |
+
exec_js(f'return {GET_EBID}("last-name-input")').send_keys(dataGenerator(10))
|
| 284 |
+
exec_js(f'return {GET_EBID}("first-name-input")').send_keys(dataGenerator(10))
|
| 285 |
+
exec_js(f'return {GET_EBID}("password-input")').send_keys(self.eset_password)
|
| 286 |
+
exec_js(f'return {GET_EBID}("password-repeat-input")').send_keys(self.eset_password)
|
| 287 |
+
exec_js(f'return {GET_EBID}("continue").click()')
|
| 288 |
+
|
| 289 |
+
# STEP 2
|
| 290 |
+
uCE(self.driver, f'return {GET_EBID}("phone-input") != null')
|
| 291 |
+
exec_js(f'return {GET_EBID}("phone-input")').send_keys(dataGenerator(10, True))
|
| 292 |
+
exec_js(f'{GET_EBID}("tou-checkbox").click()')
|
| 293 |
+
time.sleep(0.3)
|
| 294 |
+
exec_js(f'return {GET_EBID}("continue").click()')
|
| 295 |
+
uCE(self.driver, f'return {GET_EBID}("activated-user-title").innerText === "Your account has been successfully activated"', max_iter=15)
|
| 296 |
+
logging.info('Successfully!')
|
| 297 |
+
console_log('Successfully!', OK, silent_mode=SILENT_MODE)
|
| 298 |
+
|
| 299 |
+
def confirmAccount(self):
|
| 300 |
+
if isinstance(self.email_obj, CustomEmailAPI):
|
| 301 |
+
token = parseToken(self.email_obj, eset_business=True, max_iter=100, delay=3)
|
| 302 |
+
else:
|
| 303 |
+
logging.info(f'[{self.email_obj.class_name}] ProtectHub-Token interception...')
|
| 304 |
+
console_log(f'\n[{self.email_obj.class_name}] ProtectHub-Token interception...', INFO, silent_mode=SILENT_MODE)
|
| 305 |
+
if isinstance(self.email_obj, WEB_WRAPPER_EMAIL_APIS_CLASSES):
|
| 306 |
+
token = parseToken(self.email_obj, self.driver, True, max_iter=100, delay=3)
|
| 307 |
+
self.driver.switch_to.window(self.window_handle)
|
| 308 |
+
else:
|
| 309 |
+
token = parseToken(self.email_obj, eset_business=True, max_iter=100, delay=3) # 1secmail
|
| 310 |
+
logging.info(f'ProtectHub-Token: {token}')
|
| 311 |
+
logging.info('Account confirmation is in progress...')
|
| 312 |
+
console_log(f'ProtectHub-Token: {token}', OK, silent_mode=SILENT_MODE)
|
| 313 |
+
console_log('\nAccount confirmation is in progress...', INFO, silent_mode=SILENT_MODE)
|
| 314 |
+
self.driver.get(f'https://protecthub.eset.com/public/activation/{token}/?culture=en-US')
|
| 315 |
+
untilConditionExecute(self.driver, f'return {GET_EBID}("first-name-input") != null')
|
| 316 |
+
logging.info('Account successfully confirmed!')
|
| 317 |
+
console_log('Account successfully confirmed!', OK, silent_mode=SILENT_MODE)
|
| 318 |
+
|
| 319 |
+
class EsetProtectHubKeygen(object):
|
| 320 |
+
def __init__(self, registered_email_obj: OneSecEmailAPI, eset_password: str, driver: Chrome):
|
| 321 |
+
self.email_obj = registered_email_obj
|
| 322 |
+
self.eset_password = eset_password
|
| 323 |
+
self.driver = driver
|
| 324 |
+
|
| 325 |
+
def getLD(self):
|
| 326 |
+
exec_js = self.driver.execute_script
|
| 327 |
+
uCE = untilConditionExecute
|
| 328 |
+
|
| 329 |
+
# Log in
|
| 330 |
+
logging.info('Logging in to the created account...')
|
| 331 |
+
console_log('\nLogging in to the created account...', INFO, silent_mode=SILENT_MODE)
|
| 332 |
+
self.driver.get('https://protecthub.eset.com')
|
| 333 |
+
uCE(self.driver, f'return {GET_EBID}("username") != null')
|
| 334 |
+
exec_js(f'return {GET_EBID}("username")').send_keys(self.email_obj.email)
|
| 335 |
+
exec_js(f'return {GET_EBID}("password")').send_keys(self.eset_password)
|
| 336 |
+
exec_js(f'return {GET_EBID}("btn-login").click()')
|
| 337 |
+
|
| 338 |
+
# Start free trial
|
| 339 |
+
uCE(self.driver, f'return {GET_EBID}("welcome-dialog-generate-trial-license") != null', delay=3)
|
| 340 |
+
logging.info('Successfully!')
|
| 341 |
+
logging.info('Sending a request for a get license...')
|
| 342 |
+
console_log('Successfully!', OK, silent_mode=SILENT_MODE)
|
| 343 |
+
console_log('\nSending a request for a get license...', INFO, silent_mode=SILENT_MODE)
|
| 344 |
+
try:
|
| 345 |
+
exec_js(f'return {GET_EBID}("welcome-dialog-generate-trial-license").click()')
|
| 346 |
+
exec_js(f'return {GET_EBID}("welcome-dialog-generate-trial-license")').click()
|
| 347 |
+
except:
|
| 348 |
+
pass
|
| 349 |
+
|
| 350 |
+
# Waiting for a response from the site
|
| 351 |
+
license_is_being_generated = False
|
| 352 |
+
for _ in range(DEFAULT_MAX_ITER):
|
| 353 |
+
try:
|
| 354 |
+
r = exec_js(f"return {GET_EBCN}('Toastify__toast-body toastBody')[0].innerText").lower()
|
| 355 |
+
if r.find('is being generated') != -1:
|
| 356 |
+
license_is_being_generated = True
|
| 357 |
+
logging.info('Request successfully sent!')
|
| 358 |
+
console_log('Request successfully sent!', OK, silent_mode=SILENT_MODE)
|
| 359 |
+
try:
|
| 360 |
+
exec_js(f'return {GET_EBID}("welcome-dialog-skip-button").click()')
|
| 361 |
+
exec_js(f'return {GET_EBID}("welcome-dialog-skip-button")').click()
|
| 362 |
+
except:
|
| 363 |
+
pass
|
| 364 |
+
break
|
| 365 |
+
except Exception as E:
|
| 366 |
+
pass
|
| 367 |
+
time.sleep(DEFAULT_DELAY)
|
| 368 |
+
|
| 369 |
+
if not license_is_being_generated:
|
| 370 |
+
raise RuntimeError('The request has not been sent!')
|
| 371 |
+
|
| 372 |
+
logging.info('Waiting for a back response...')
|
| 373 |
+
console_log('\nWaiting for a back response...', INFO, silent_mode=SILENT_MODE)
|
| 374 |
+
license_was_generated = False
|
| 375 |
+
for _ in range(DEFAULT_MAX_ITER*10): # 5m
|
| 376 |
+
try:
|
| 377 |
+
r = exec_js(f"return {GET_EBCN}('Toastify__toast-body toastBody')[0].innerText").lower()
|
| 378 |
+
if r.find('couldn\'t be generated') != -1:
|
| 379 |
+
break
|
| 380 |
+
elif r.find('was generated') != -1:
|
| 381 |
+
logging.info('Successfully!')
|
| 382 |
+
console_log('Successfully!', OK, silent_mode=SILENT_MODE)
|
| 383 |
+
license_was_generated = True
|
| 384 |
+
break
|
| 385 |
+
except Exception as E:
|
| 386 |
+
pass
|
| 387 |
+
time.sleep(DEFAULT_DELAY)
|
| 388 |
+
|
| 389 |
+
if not license_was_generated:
|
| 390 |
+
raise RuntimeError('The license cannot be generated, try again later!')
|
| 391 |
+
|
| 392 |
+
# Obtaining license data from the site
|
| 393 |
+
logging.info('[Site] License uploads...')
|
| 394 |
+
console_log('\n[Site] License uploads...', INFO, silent_mode=SILENT_MODE)
|
| 395 |
+
license_name = 'ESET PROTECT Advanced'
|
| 396 |
+
try:
|
| 397 |
+
self.driver.get('https://protecthub.eset.com/licenses')
|
| 398 |
+
uCE(self.driver, f'return {GET_EBAV}("div", "data-label", "license-list-body-cell-renderer-row-0-column-0").innerText != ""')
|
| 399 |
+
license_id = exec_js(f'{DEFINE_GET_EBAV_FUNCTION}\nreturn {GET_EBAV}("div", "data-label", "license-list-body-cell-renderer-row-0-column-0").innerText')
|
| 400 |
+
logging.info(f'License ID: {license_id}')
|
| 401 |
+
logging.info('Getting information from the license...')
|
| 402 |
+
console_log(f'License ID: {license_id}', OK, silent_mode=SILENT_MODE)
|
| 403 |
+
console_log('\nGetting information from the license...', INFO, silent_mode=SILENT_MODE)
|
| 404 |
+
self.driver.get(f'https://protecthub.eset.com/licenses/details/2/{license_id}/overview')
|
| 405 |
+
uCE(self.driver, f'return {GET_EBAV}("div", "data-label", "license-overview-validity-value") != null')
|
| 406 |
+
license_out_date = exec_js(f'{DEFINE_GET_EBAV_FUNCTION}\nreturn {GET_EBAV}("div", "data-label", "license-overview-validity-value").children[0].children[0].innerText')
|
| 407 |
+
# Obtaining license key
|
| 408 |
+
exec_js(f'{DEFINE_GET_EBAV_FUNCTION}\n{GET_EBAV}("div", "data-label", "license-overview-key-value").children[0].children[0].click()')
|
| 409 |
+
uCE(self.driver, f'return {GET_EBID}("show-license-key-auth-modal-password-input") != null')
|
| 410 |
+
exec_js(f'return {GET_EBID}("show-license-key-auth-modal-password-input")').send_keys(self.eset_password)
|
| 411 |
+
try:
|
| 412 |
+
exec_js(f'return {GET_EBID}("show-license-key-auth-modal-authenticate").click()')
|
| 413 |
+
exec_js(f'return {GET_EBID}("show-license-key-auth-modal-authenticate")').click()
|
| 414 |
+
except:
|
| 415 |
+
pass
|
| 416 |
+
for _ in range(DEFAULT_MAX_ITER):
|
| 417 |
+
try:
|
| 418 |
+
license_key = exec_js(f'return {GET_EBAV}("div", "data-label", "license-overview-key-value").children[0].textContent.trim()')
|
| 419 |
+
if license_key is not None and not license_key.startswith('XXXX-XXXX-XXXX-XXXX-XXXX'): # ignoring XXXX-XXXX-XXXX-XXXX-XXXX
|
| 420 |
+
license_key = license_key.split(' ')[0]
|
| 421 |
+
logging.info('Information successfully received!')
|
| 422 |
+
console_log('Information successfully received!', OK, silent_mode=SILENT_MODE)
|
| 423 |
+
return license_name, license_key, license_out_date, True # True - License key obtained from the site
|
| 424 |
+
except:
|
| 425 |
+
pass
|
| 426 |
+
time.sleep(DEFAULT_DELAY)
|
| 427 |
+
except Exception as E:
|
| 428 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 429 |
+
console_log('Error when obtaining a license key from the site!!!', ERROR, silent_mode=SILENT_MODE)
|
| 430 |
+
# Obtaining license data from the email
|
| 431 |
+
logging.info('[Email] License uploads...')
|
| 432 |
+
console_log('\n[Email] License uploads...', INFO, silent_mode=SILENT_MODE)
|
| 433 |
+
if self.email_obj.class_name == 'custom':
|
| 434 |
+
logging.warning('Wait for a message to your e-mail about successful key generation!!!')
|
| 435 |
+
console_log('\nWait for a message to your e-mail about successful key generation!!!', WARN, True, SILENT_MODE)
|
| 436 |
+
return None, None, None, None
|
| 437 |
+
else:
|
| 438 |
+
license_key, license_out_date, license_id = parseEPHKey(self.email_obj, self.driver, delay=5, max_iter=30) # 2.5m
|
| 439 |
+
logging.info(f'License ID: {license_id}')
|
| 440 |
+
logging.info('Getting information from the license...')
|
| 441 |
+
logging.info('Information successfully received!')
|
| 442 |
+
console_log(f'License ID: {license_id}', OK, silent_mode=SILENT_MODE)
|
| 443 |
+
console_log('\nGetting information from the license...', INFO, silent_mode=SILENT_MODE)
|
| 444 |
+
console_log('Information successfully received!', OK, silent_mode=SILENT_MODE)
|
| 445 |
+
return license_name, license_key, license_out_date, False # False - License key obtained from the email
|
| 446 |
+
|
| 447 |
+
def removeLicense(self):
|
| 448 |
+
logging.info('Deleting the key from the account, the key will still work...')
|
| 449 |
+
console_log('Deleting the key from the account, the key will still work...', INFO, silent_mode=SILENT_MODE)
|
| 450 |
+
try:
|
| 451 |
+
self.driver.execute_script(f'return {GET_EBID}("license-actions-button")').click()
|
| 452 |
+
time.sleep(1)
|
| 453 |
+
button = self.driver.find_element('xpath', '//a[.//div[text()="Remove license"]]')
|
| 454 |
+
if button is not None:
|
| 455 |
+
button.click()
|
| 456 |
+
untilConditionExecute(self.driver, f'return {CLICK_WITH_BOOL}({GET_EBID}("remove-license-dlg-remove-btn"))', max_iter=15)
|
| 457 |
+
time.sleep(2)
|
| 458 |
+
for _ in range(DEFAULT_MAX_ITER//2):
|
| 459 |
+
try:
|
| 460 |
+
self.driver.execute_script(f'return {GET_EBID}("remove-license-dlg-remove-btn")').click()
|
| 461 |
+
except:
|
| 462 |
+
pass
|
| 463 |
+
if self.driver.page_source.lower().find('to keep the solutions up to date') == -1:
|
| 464 |
+
time.sleep(1)
|
| 465 |
+
logging.info('Key successfully deleted!!!')
|
| 466 |
+
console_log('Key successfully deleted!!!', OK, silent_mode=SILENT_MODE)
|
| 467 |
+
return True
|
| 468 |
+
time.sleep(DEFAULT_DELAY)
|
| 469 |
+
except:
|
| 470 |
+
pass
|
| 471 |
+
logging.error('Failed to delete key, this error has no effect on the operation of the key!!!')
|
| 472 |
+
console_log('Failed to delete key, this error has no effect on the operation of the key!!!', ERROR, silent_mode=SILENT_MODE)
|
| 473 |
+
|
| 474 |
+
def EsetVPNResetWindows(key_path='SOFTWARE\\ESET\\ESET VPN', value_name='authHash'):
|
| 475 |
+
"""Deletes the authHash value of ESET VPN"""
|
| 476 |
+
try:
|
| 477 |
+
subprocess.check_output(['taskkill', '/f', '/im', 'esetvpn.exe'], stderr=subprocess.DEVNULL)
|
| 478 |
+
except:
|
| 479 |
+
pass
|
| 480 |
+
try:
|
| 481 |
+
import winreg
|
| 482 |
+
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_ALL_ACCESS) as key:
|
| 483 |
+
winreg.DeleteValue(key, value_name)
|
| 484 |
+
logging.info('ESET VPN has been successfully reset!!!')
|
| 485 |
+
console_log('ESET VPN has been successfully reset!!!', OK, silent_mode=SILENT_MODE)
|
| 486 |
+
except FileNotFoundError:
|
| 487 |
+
logging.error(f'The registry value or key does not exist: {key_path}\\{value_name}')
|
| 488 |
+
console_log(f'The registry value or key does not exist: {key_path}\\{value_name}', ERROR, silent_mode=SILENT_MODE)
|
| 489 |
+
except PermissionError:
|
| 490 |
+
logging.error(f'Permission denied while accessing: {key_path}\\{value_name}')
|
| 491 |
+
console_log(f'Permission denied while accessing: {key_path}\\{value_name}', ERROR, silent_mode=SILENT_MODE)
|
| 492 |
+
except Exception as e:
|
| 493 |
+
raise RuntimeError(e)
|
| 494 |
+
|
| 495 |
+
def EsetVPNResetMacOS(app_name='ESET VPN', file_name='Preferences/com.eset.ESET VPN.plist'):
|
| 496 |
+
try:
|
| 497 |
+
# Use AppleScript to quit the application
|
| 498 |
+
script = f'tell application "{app_name}" to quit'
|
| 499 |
+
subprocess.run(["osascript", "-e", script], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 500 |
+
except:
|
| 501 |
+
pass
|
| 502 |
+
try:
|
| 503 |
+
time.sleep(2)
|
| 504 |
+
# Get the full path to the file in the Library folder
|
| 505 |
+
library_path = Path.home() / "Library" / file_name
|
| 506 |
+
# Check if the file exists and remove it
|
| 507 |
+
if library_path.is_file():
|
| 508 |
+
library_path.unlink()
|
| 509 |
+
logging.info('ESET VPN has been successfully reset!!!')
|
| 510 |
+
console_log('ESET VPN has been successfully reset!!!', OK, silent_mode=SILENT_MODE)
|
| 511 |
+
else:
|
| 512 |
+
logging.error(f"File '{file_name}' does not exist!!!")
|
| 513 |
+
console_log(f"File '{file_name}' does not exist!!!", ERROR, silent_mode=SILENT_MODE)
|
| 514 |
+
except Exception as e:
|
| 515 |
+
raise RuntimeError(e)
|
modules/MBCI.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from colorama import Fore
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
def clear_console():
|
| 6 |
+
if os.name == 'nt':
|
| 7 |
+
os.system('cls')
|
| 8 |
+
else:
|
| 9 |
+
os.system('clear')
|
| 10 |
+
|
| 11 |
+
class MenuAction(object):
|
| 12 |
+
def __init__(self, title, func):
|
| 13 |
+
self.title = title
|
| 14 |
+
self.function = func
|
| 15 |
+
|
| 16 |
+
def render_title(self):
|
| 17 |
+
return self.title
|
| 18 |
+
|
| 19 |
+
def run(self):
|
| 20 |
+
if isinstance(self.function, ViewMenu):
|
| 21 |
+
self.function.view()
|
| 22 |
+
else:
|
| 23 |
+
self.function()
|
| 24 |
+
|
| 25 |
+
class OptionAction(object):
|
| 26 |
+
def __init__(self, args, title, action, args_names, choices=[], default_value=None, data_type=str, data_range=None):
|
| 27 |
+
self.args = args
|
| 28 |
+
self.title = title
|
| 29 |
+
self.action = action
|
| 30 |
+
self.value = default_value
|
| 31 |
+
self.choices = choices
|
| 32 |
+
self.args_names = args_names
|
| 33 |
+
self.data_type = data_type
|
| 34 |
+
self.data_range = data_range
|
| 35 |
+
|
| 36 |
+
def render_title(self):
|
| 37 |
+
if self.action in ['store_true', 'choice']:
|
| 38 |
+
return f'{self.title} (selected: {Fore.YELLOW}{self.value}{Fore.RESET})'
|
| 39 |
+
elif self.action == 'manual_input':
|
| 40 |
+
return f'{self.title} (saved: {Fore.YELLOW}{self.value}{Fore.RESET})'
|
| 41 |
+
elif self.action == 'bool_switch':
|
| 42 |
+
if self.args[self.args_names.replace('-', '_')]:
|
| 43 |
+
return f'{self.title} {Fore.GREEN}(enabled){Fore.RESET}'
|
| 44 |
+
return f'{self.title} {Fore.RED}(disabled){Fore.RESET}'
|
| 45 |
+
|
| 46 |
+
def run(self):
|
| 47 |
+
if self.action == 'bool_switch':
|
| 48 |
+
self.args[self.args_names.replace('-', '_')] = not self.args[self.args_names.replace('-', '_')]
|
| 49 |
+
return True
|
| 50 |
+
execution = True
|
| 51 |
+
while True:
|
| 52 |
+
clear_console()
|
| 53 |
+
print(self.title+'\n')
|
| 54 |
+
menu_items = []
|
| 55 |
+
if self.choices != []:
|
| 56 |
+
menu_items = self.choices
|
| 57 |
+
else:
|
| 58 |
+
menu_items = self.args_names
|
| 59 |
+
if self.action != 'manual_input':
|
| 60 |
+
for index in range(0, len(menu_items)):
|
| 61 |
+
menu_item = menu_items[index]
|
| 62 |
+
print(f'{index+1} - {menu_item}')
|
| 63 |
+
print()
|
| 64 |
+
try:
|
| 65 |
+
if self.action == 'manual_input':
|
| 66 |
+
while True:
|
| 67 |
+
if self.data_range is not None:
|
| 68 |
+
print('Allowed values: '+str(self.data_range)+'\n')
|
| 69 |
+
self.value = input('>>> ').strip()
|
| 70 |
+
try:
|
| 71 |
+
self.value = self.data_type(self.value)
|
| 72 |
+
if self.data_range is not None:
|
| 73 |
+
if self.value not in self.data_range:
|
| 74 |
+
raise
|
| 75 |
+
self.args[self.args_names.replace('-', '_')] = self.value # self.args_names is str
|
| 76 |
+
execution = False
|
| 77 |
+
break
|
| 78 |
+
except:
|
| 79 |
+
clear_console()
|
| 80 |
+
print(self.title+'\n')
|
| 81 |
+
if not execution:
|
| 82 |
+
break
|
| 83 |
+
index = int(input('>>> ').strip()) - 1
|
| 84 |
+
self.value = menu_items[index]
|
| 85 |
+
if index in range(0, len(menu_items)):
|
| 86 |
+
if self.action == 'store_true':
|
| 87 |
+
for args_name in self.args_names: # self.args_names is list
|
| 88 |
+
self.args[args_name.replace('-', '_')] = False
|
| 89 |
+
self.args[self.value.replace('-', '_')] = True # self.value == args_name
|
| 90 |
+
elif self.action == 'choice':
|
| 91 |
+
self.args[self.args_names.replace('-', '_')] = self.value # self.args_names is str
|
| 92 |
+
break
|
| 93 |
+
except ValueError:
|
| 94 |
+
pass
|
| 95 |
+
|
| 96 |
+
class ViewMenu(object):
|
| 97 |
+
def __init__(self, title):
|
| 98 |
+
self.title = title
|
| 99 |
+
self.items = []
|
| 100 |
+
self.execution = True
|
| 101 |
+
|
| 102 |
+
def add_item(self, menu_action_object: MenuAction):
|
| 103 |
+
self.items.append(menu_action_object)
|
| 104 |
+
|
| 105 |
+
def view(self):
|
| 106 |
+
self.execution = True
|
| 107 |
+
while self.execution:
|
| 108 |
+
clear_console()
|
| 109 |
+
print(self.title+'\n')
|
| 110 |
+
for item_index in range(0, len(self.items)):
|
| 111 |
+
item = self.items[item_index]
|
| 112 |
+
print(f'{item_index+1} - {item.render_title()}')
|
| 113 |
+
print()
|
| 114 |
+
try:
|
| 115 |
+
selected_item_index = int(input('>>> ')) - 1
|
| 116 |
+
if selected_item_index in range(0, len(self.items)):
|
| 117 |
+
self.items[selected_item_index].run()
|
| 118 |
+
except ValueError:
|
| 119 |
+
pass
|
| 120 |
+
|
| 121 |
+
def close(self):
|
| 122 |
+
self.execution = False
|
modules/ProgressBar.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from colorama import Fore, init as colorama_init
|
| 2 |
+
|
| 3 |
+
import decimal
|
| 4 |
+
import platform
|
| 5 |
+
import sys
|
| 6 |
+
|
| 7 |
+
colorama_init()
|
| 8 |
+
|
| 9 |
+
class ProgressBarStyle:
|
| 10 |
+
def __init__(self, advance_char='█', empty_advance_char='▓', progressbar_length=30):
|
| 11 |
+
self.advance_char = advance_char
|
| 12 |
+
self.empty_advance_char = empty_advance_char
|
| 13 |
+
self.progressbar_length = progressbar_length
|
| 14 |
+
|
| 15 |
+
DEFAULT_STYLE = ProgressBarStyle()
|
| 16 |
+
DEFAULT_RICH_STYLE = ProgressBarStyle(f'{Fore.GREEN}━{Fore.RESET}', f'{Fore.LIGHTBLACK_EX}━{Fore.RESET}', 41)
|
| 17 |
+
CLASSIC_STYLE = ProgressBarStyle(f'{Fore.GREEN}█{Fore.RESET}', f'{Fore.LIGHTBLACK_EX}▓{Fore.RESET}')
|
| 18 |
+
DRACULA_STYLE = ProgressBarStyle(f'{Fore.RED}█{Fore.RESET}', f'{Fore.LIGHTRED_EX}▓{Fore.RESET}')
|
| 19 |
+
GIRL_STYLE = ProgressBarStyle(f'{Fore.LIGHTMAGENTA_EX}█{Fore.RESET}', f'{Fore.MAGENTA}▓{Fore.RESET}')
|
| 20 |
+
DARK_STYLE = ProgressBarStyle(f'{Fore.LIGHTBLACK_EX}█{Fore.RESET}', ' ')
|
| 21 |
+
RAINBOW_STYLE = ProgressBarStyle(f'{Fore.RED}█{Fore.CYAN}█{Fore.YELLOW}█{Fore.GREEN}█{Fore.BLUE}█{Fore.MAGENTA}█{Fore.RESET}', '', 10)
|
| 22 |
+
|
| 23 |
+
class ProgressBar:
|
| 24 |
+
def __init__(self, total, description: str, progress_bar_style=DEFAULT_STYLE):
|
| 25 |
+
self.advance = 0
|
| 26 |
+
self.total = total
|
| 27 |
+
self.description = description
|
| 28 |
+
self.progressbar_length = progress_bar_style.progressbar_length
|
| 29 |
+
self.advance_char = progress_bar_style.advance_char
|
| 30 |
+
self.empty_advance_char = progress_bar_style.empty_advance_char
|
| 31 |
+
self.advance_char_coef = round(self.total/self.progressbar_length, 2)
|
| 32 |
+
|
| 33 |
+
@property
|
| 34 |
+
def is_finished(self):
|
| 35 |
+
return self.advance == self.total
|
| 36 |
+
|
| 37 |
+
def force_finish(self):
|
| 38 |
+
self.advance = self.total
|
| 39 |
+
|
| 40 |
+
def render(self):
|
| 41 |
+
if self.is_finished:
|
| 42 |
+
advance_char_count = self.progressbar_length
|
| 43 |
+
else:
|
| 44 |
+
advance_char_count = int(self.advance/self.advance_char_coef)
|
| 45 |
+
advance_percent = round(decimal.Decimal(self.advance/self.total), 2)*100
|
| 46 |
+
if platform.release() == '7' and sys.platform.startswith('win'): # disable rendering for windows 7 (cmd.exe does not support ASCII control characters)
|
| 47 |
+
pass
|
| 48 |
+
else:
|
| 49 |
+
print(f'{self.description}{self.advance_char*advance_char_count}{self.empty_advance_char*(self.progressbar_length-advance_char_count)} {advance_percent}%')
|
| 50 |
+
print('\033[F', end='')
|
| 51 |
+
if self.is_finished:
|
| 52 |
+
print()
|
| 53 |
+
|
| 54 |
+
def update(self, count):
|
| 55 |
+
self.advance += count
|
modules/SharedTools.py
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from selenium.webdriver import Chrome, ChromeOptions, ChromeService
|
| 2 |
+
from selenium.webdriver import Firefox, FirefoxOptions, FirefoxService
|
| 3 |
+
from selenium.webdriver import Edge, EdgeOptions, EdgeService
|
| 4 |
+
from selenium.webdriver import Safari, SafariOptions, SafariService
|
| 5 |
+
|
| 6 |
+
import subprocess
|
| 7 |
+
import traceback
|
| 8 |
+
import tempfile
|
| 9 |
+
import colorama
|
| 10 |
+
import logging
|
| 11 |
+
import pathlib
|
| 12 |
+
import random
|
| 13 |
+
import string
|
| 14 |
+
import shutil
|
| 15 |
+
import time
|
| 16 |
+
import sys
|
| 17 |
+
import os
|
| 18 |
+
import re
|
| 19 |
+
|
| 20 |
+
I_AM_EXECUTABLE = (True if (getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')) else False)
|
| 21 |
+
PATH_TO_SELF = sys.executable if I_AM_EXECUTABLE else __file__
|
| 22 |
+
SILENT_MODE = '--silent' in sys.argv
|
| 23 |
+
|
| 24 |
+
DEFAULT_MAX_ITER = 30
|
| 25 |
+
DEFAULT_DELAY = 1
|
| 26 |
+
GET_EBCN = 'document.getElementsByClassName'
|
| 27 |
+
GET_EBID = 'document.getElementById'
|
| 28 |
+
GET_EBTN = 'document.getElementsByTagName'
|
| 29 |
+
GET_EBAV = 'getElementByAttrValue'
|
| 30 |
+
CLICK_WITH_BOOL = 'clickWithBool'
|
| 31 |
+
DEFINE_GET_EBAV_FUNCTION = """
|
| 32 |
+
function getElementByAttrValue(tagName, attrName, attrValue, index=1) {
|
| 33 |
+
let eindex = 0
|
| 34 |
+
let elements = []
|
| 35 |
+
for (let element of document.getElementsByTagName(tagName)) {
|
| 36 |
+
if(element.getAttribute(attrName) === attrValue) {
|
| 37 |
+
eindex += 1
|
| 38 |
+
if (index == -1)
|
| 39 |
+
elements.push(element)
|
| 40 |
+
else if (index == eindex)
|
| 41 |
+
return element } }
|
| 42 |
+
if (index == -1)
|
| 43 |
+
return elements }"""
|
| 44 |
+
DEFINE_CLICK_WITH_BOOL_FUNCTION = """
|
| 45 |
+
function clickWithBool(object) {
|
| 46 |
+
try {
|
| 47 |
+
object.click()
|
| 48 |
+
return true }
|
| 49 |
+
catch {
|
| 50 |
+
return false } }"""
|
| 51 |
+
|
| 52 |
+
colorama.init()
|
| 53 |
+
|
| 54 |
+
class LoggerType:
|
| 55 |
+
def __init__(self, sborder, eborder, title, color, fill_text):
|
| 56 |
+
self.sborder = sborder
|
| 57 |
+
self.eborder = eborder
|
| 58 |
+
self.title = title
|
| 59 |
+
self.color = color
|
| 60 |
+
self.fill_text = fill_text
|
| 61 |
+
|
| 62 |
+
@property
|
| 63 |
+
def data(self):
|
| 64 |
+
return self.sborder + self.color + self.title + colorama.Style.RESET_ALL + self.eborder
|
| 65 |
+
|
| 66 |
+
ERROR = LoggerType('[ ', ' ]', 'FAILED', colorama.Fore.RED, True)
|
| 67 |
+
OK = LoggerType('[ ', ' ]', 'OK', colorama.Fore.GREEN, False)
|
| 68 |
+
INFO = LoggerType('[ ', ' ]', 'INFO', colorama.Fore.LIGHTBLACK_EX, True)
|
| 69 |
+
DEVINFO = LoggerType('[ ', ' ]', 'DEBUG', colorama.Fore.CYAN, True)
|
| 70 |
+
WARN = LoggerType('[ ', ' ]', 'WARN', colorama.Fore.YELLOW, False)
|
| 71 |
+
|
| 72 |
+
class Installer:
|
| 73 |
+
def __init__(self):
|
| 74 |
+
self.install_path = None
|
| 75 |
+
self.executable_path = None
|
| 76 |
+
if sys.platform.startswith('win'):
|
| 77 |
+
self.install_path = os.environ['SystemRoot']
|
| 78 |
+
self.executable_path = self.install_path + '\\esetkeygen.exe'
|
| 79 |
+
elif sys.platform == "darwin":
|
| 80 |
+
self.install_path = '/usr/local/bin'
|
| 81 |
+
self.executable_path = self.install_path + '/esetkeygen'
|
| 82 |
+
|
| 83 |
+
def check_install(self):
|
| 84 |
+
exit_code = None
|
| 85 |
+
try:
|
| 86 |
+
exit_code = subprocess.call([self.executable_path, '--return-exit-code', '999'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 87 |
+
except:
|
| 88 |
+
pass
|
| 89 |
+
return (exit_code == 999)
|
| 90 |
+
|
| 91 |
+
def install(self):
|
| 92 |
+
if self.check_install():
|
| 93 |
+
logging.info('The program is already installed!!!')
|
| 94 |
+
logging.warning(f'Location: {self.executable_path}')
|
| 95 |
+
console_log('The program is already installed!!!', OK, silent_mode=SILENT_MODE)
|
| 96 |
+
console_log(f'Location: {self.executable_path}', WARN, silent_mode=SILENT_MODE)
|
| 97 |
+
return True
|
| 98 |
+
if sys.platform.startswith('win') or sys.platform == 'darwin':
|
| 99 |
+
if I_AM_EXECUTABLE:
|
| 100 |
+
try:
|
| 101 |
+
shutil.copy2(PATH_TO_SELF, self.executable_path)
|
| 102 |
+
logging.info(f'The program was successfully installed on the path: {self.executable_path}')
|
| 103 |
+
console_log(f'The program was successfully installed on the path: {self.executable_path}', OK, silent_mode=SILENT_MODE)
|
| 104 |
+
return True
|
| 105 |
+
except PermissionError:
|
| 106 |
+
logging.error('No write access, try running the program with elevated permissions!!!')
|
| 107 |
+
console_log('No write access, try running the program with elevated permissions!!!', ERROR, silent_mode=SILENT_MODE)
|
| 108 |
+
except Exception as e:
|
| 109 |
+
raise RuntimeError(e)
|
| 110 |
+
except shutil.SameFileError:
|
| 111 |
+
logging.error('Installation is pointless from under an installed executable file!!!')
|
| 112 |
+
console_log('Installation is pointless from under an installed executable file!!!', ERROR, silent_mode=SILENT_MODE)
|
| 113 |
+
else:
|
| 114 |
+
logging.error('Installation from source is not possible!!!!')
|
| 115 |
+
console_log('Installation from source is not possible!!!!', ERROR, silent_mode=SILENT_MODE)
|
| 116 |
+
return False
|
| 117 |
+
|
| 118 |
+
class ChromeProxyExtensionManager:
|
| 119 |
+
MANIFEST = """
|
| 120 |
+
{
|
| 121 |
+
"version": "1.0.0",
|
| 122 |
+
"manifest_version": 3,
|
| 123 |
+
"name": "Chrome Proxy Manager",
|
| 124 |
+
"permissions": [
|
| 125 |
+
"proxy",
|
| 126 |
+
"tabs",
|
| 127 |
+
"unlimitedStorage",
|
| 128 |
+
"storage",
|
| 129 |
+
"webRequest",
|
| 130 |
+
"webRequestAuthProvider"
|
| 131 |
+
],
|
| 132 |
+
"background": {
|
| 133 |
+
"service_worker": "background.js"
|
| 134 |
+
},
|
| 135 |
+
"host_permissions": [
|
| 136 |
+
"<all_urls>"
|
| 137 |
+
],
|
| 138 |
+
"minimum_chrome_version":"22.0.0"
|
| 139 |
+
}
|
| 140 |
+
"""
|
| 141 |
+
|
| 142 |
+
BACKGROUND_JS = """
|
| 143 |
+
const config = {
|
| 144 |
+
mode: "fixed_servers",
|
| 145 |
+
rules: {
|
| 146 |
+
singleProxy: {
|
| 147 |
+
scheme: "%s",
|
| 148 |
+
host: "%s",
|
| 149 |
+
port: %s
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
chrome.proxy.settings.set({
|
| 154 |
+
value: config,
|
| 155 |
+
scope: 'regular'
|
| 156 |
+
}, () => {});
|
| 157 |
+
"""
|
| 158 |
+
|
| 159 |
+
BACKGROUND_AUTO_AUTH = """
|
| 160 |
+
chrome.webRequest.onAuthRequired.addListener(
|
| 161 |
+
(details, callback) => {
|
| 162 |
+
const authCredentials = {
|
| 163 |
+
username: "%s",
|
| 164 |
+
password: "%s",
|
| 165 |
+
};
|
| 166 |
+
setTimeout(() => {
|
| 167 |
+
callback({ authCredentials });
|
| 168 |
+
}, 200);
|
| 169 |
+
},
|
| 170 |
+
{ urls: ["<all_urls>"] },
|
| 171 |
+
["asyncBlocking"]
|
| 172 |
+
);
|
| 173 |
+
"""
|
| 174 |
+
|
| 175 |
+
def create_extension(scheme: string, host: string, port: int, username="", password=""):
|
| 176 |
+
if scheme == "" or host == "" or port == 0:
|
| 177 |
+
return ''
|
| 178 |
+
|
| 179 |
+
tempdir = pathlib.Path(tempfile.mkdtemp())
|
| 180 |
+
|
| 181 |
+
with open(tempdir.joinpath("manifest.json"), "x") as f:
|
| 182 |
+
f.write(ChromeProxyExtensionManager.MANIFEST)
|
| 183 |
+
with open(tempdir.joinpath("background.js"), "x") as f:
|
| 184 |
+
f.write(ChromeProxyExtensionManager.BACKGROUND_JS % (scheme, host, port))
|
| 185 |
+
|
| 186 |
+
if username != "" or password != "":
|
| 187 |
+
with open(tempdir.joinpath("background.js"), "a") as f:
|
| 188 |
+
f.write(ChromeProxyExtensionManager.BACKGROUND_AUTO_AUTH % (username, password))
|
| 189 |
+
|
| 190 |
+
return tempdir
|
| 191 |
+
|
| 192 |
+
def parse_proxies_from_file(path: str):
|
| 193 |
+
proxies = []
|
| 194 |
+
with open(path) as f:
|
| 195 |
+
try:
|
| 196 |
+
lines = f.readlines()
|
| 197 |
+
for line in lines:
|
| 198 |
+
line = line.strip()
|
| 199 |
+
if line != "":
|
| 200 |
+
proxy = line.split(':') # scheme:host:port:username:password
|
| 201 |
+
if len(proxy) == 5:
|
| 202 |
+
proxies.append(proxy)
|
| 203 |
+
except:
|
| 204 |
+
pass
|
| 205 |
+
return proxies
|
| 206 |
+
|
| 207 |
+
def console_log(text='', logger_type=None, fill_text=None, silent_mode=False):
|
| 208 |
+
if silent_mode:
|
| 209 |
+
return
|
| 210 |
+
if isinstance(logger_type, LoggerType):
|
| 211 |
+
ni = 0
|
| 212 |
+
for i in range(0, len(text)):
|
| 213 |
+
if text[i] != '\n':
|
| 214 |
+
ni = i
|
| 215 |
+
break
|
| 216 |
+
print()
|
| 217 |
+
if fill_text is None:
|
| 218 |
+
fill_text = logger_type.fill_text
|
| 219 |
+
if fill_text:
|
| 220 |
+
print(logger_type.data + ' ' + logger_type.color + text[ni:] + colorama.Style.RESET_ALL)
|
| 221 |
+
else:
|
| 222 |
+
print(logger_type.data + ' ' + text[ni:])
|
| 223 |
+
else:
|
| 224 |
+
print(text)
|
| 225 |
+
|
| 226 |
+
from .WebDriverInstaller import GOOGLE_CHROME, MICROSOFT_EDGE, MOZILLA_FIREFOX, APPLE_SAFARI
|
| 227 |
+
|
| 228 |
+
def clear_console():
|
| 229 |
+
if os.name == 'nt':
|
| 230 |
+
os.system('cls')
|
| 231 |
+
else:
|
| 232 |
+
os.system('clear')
|
| 233 |
+
|
| 234 |
+
def untilConditionExecute(driver_obj, js: str, delay=DEFAULT_DELAY, max_iter=DEFAULT_MAX_ITER, positive_result=True, raise_exception_if_failed=True, return_js_result=False):
|
| 235 |
+
driver_obj.execute_script(f'window.{GET_EBAV} = {DEFINE_GET_EBAV_FUNCTION}')
|
| 236 |
+
driver_obj.execute_script(f'window.{CLICK_WITH_BOOL} = {DEFINE_CLICK_WITH_BOOL_FUNCTION}')
|
| 237 |
+
pre_js = [
|
| 238 |
+
DEFINE_GET_EBAV_FUNCTION,
|
| 239 |
+
DEFINE_CLICK_WITH_BOOL_FUNCTION
|
| 240 |
+
]
|
| 241 |
+
js = '\n'.join(pre_js+[js])
|
| 242 |
+
for _ in range(max_iter):
|
| 243 |
+
try:
|
| 244 |
+
result = driver_obj.execute_script(js)
|
| 245 |
+
if return_js_result and result is not None:
|
| 246 |
+
return result
|
| 247 |
+
elif result == positive_result:
|
| 248 |
+
return True
|
| 249 |
+
except Exception as E:
|
| 250 |
+
pass
|
| 251 |
+
time.sleep(delay)
|
| 252 |
+
if raise_exception_if_failed:
|
| 253 |
+
raise RuntimeError('untilConditionExecute: the code did not return the desired value! TRY VPN!')
|
| 254 |
+
|
| 255 |
+
def dataGenerator(length, only_numbers=False):
|
| 256 |
+
"""generates a password by default. If only_numbers=True - phone number"""
|
| 257 |
+
data = []
|
| 258 |
+
if only_numbers: # phone number
|
| 259 |
+
data = [random.choice(string.digits) for _ in range(length)]
|
| 260 |
+
else: # password
|
| 261 |
+
length += random.randint(1, 10)
|
| 262 |
+
data = [ # 1 uppercase & lowercase letter, 1 number, 1 special character
|
| 263 |
+
random.choice(string.ascii_uppercase),
|
| 264 |
+
random.choice(string.ascii_lowercase),
|
| 265 |
+
random.choice(string.digits),
|
| 266 |
+
random.choice("""!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~""")
|
| 267 |
+
]
|
| 268 |
+
characters = string.ascii_letters + string.digits + string.punctuation
|
| 269 |
+
data += [random.choice(characters) for _ in range(length-3)]
|
| 270 |
+
random.shuffle(data)
|
| 271 |
+
return ''.join(data)
|
| 272 |
+
|
| 273 |
+
def initSeleniumWebDriver(browser_name: str, webdriver_path = None, browser_path = '', chrome_proxy_extension_path = '', headless=True):
|
| 274 |
+
if browser_path is None:
|
| 275 |
+
browser_path = ''
|
| 276 |
+
logging.info('-- Browsers Initializer --')
|
| 277 |
+
console_log(f'{colorama.Fore.LIGHTMAGENTA_EX}-- Browsers Initializer --{colorama.Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 278 |
+
if os.name == 'posix': # For Linux
|
| 279 |
+
if sys.platform.startswith('linux'):
|
| 280 |
+
logging.info(f'Initializing {browser_name} for Linux')
|
| 281 |
+
console_log(f'Initializing {browser_name} for Linux', INFO, silent_mode=SILENT_MODE)
|
| 282 |
+
elif sys.platform == "darwin":
|
| 283 |
+
logging.info(f'Initializing {browser_name} for macOS')
|
| 284 |
+
console_log(f'Initializing {browser_name} for macOS', INFO, silent_mode=SILENT_MODE)
|
| 285 |
+
elif os.name == 'nt':
|
| 286 |
+
logging.info(f'Initializing {browser_name} for Windows')
|
| 287 |
+
console_log(f'Initializing {browser_name} for Windows', INFO, silent_mode=SILENT_MODE)
|
| 288 |
+
driver_options = None
|
| 289 |
+
driver = None
|
| 290 |
+
if browser_name == GOOGLE_CHROME:
|
| 291 |
+
driver_options = ChromeOptions()
|
| 292 |
+
driver_options.page_load_strategy = "eager"
|
| 293 |
+
driver_options.binary_location = browser_path
|
| 294 |
+
driver_options.debugger_address = ''
|
| 295 |
+
driver_options.add_experimental_option('excludeSwitches', ['enable-logging'])
|
| 296 |
+
driver_options.add_argument("--log-level=3")
|
| 297 |
+
driver_options.add_argument("--lang=en-US")
|
| 298 |
+
driver_options.add_argument(f"--load-extension={chrome_proxy_extension_path}")
|
| 299 |
+
if headless:
|
| 300 |
+
driver_options.add_argument('--headless')
|
| 301 |
+
if os.name == 'posix': # For Linux
|
| 302 |
+
driver_options.add_argument('--no-sandbox')
|
| 303 |
+
driver_options.add_argument('--disable-dev-shm-usage')
|
| 304 |
+
try:
|
| 305 |
+
service = ChromeService(executable_path=webdriver_path)
|
| 306 |
+
if os.name == 'nt' and headless:
|
| 307 |
+
service.creation_flags = 0x08000000 # CREATE_NO_WINDOW (Process Creation Flags, WinBase.h) -> 'DevTools listening on' is not visible!!!
|
| 308 |
+
driver = Chrome(options=driver_options, service=service)
|
| 309 |
+
except Exception as e:
|
| 310 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 311 |
+
if traceback.format_exc().find('only supports') != -1: # Fix for downloaded chrome update
|
| 312 |
+
browser_path = traceback.format_exc().split('path')[-1].split('Stacktrace')[0].strip()
|
| 313 |
+
if 'new_chrome.exe' in os.listdir(browser_path[:-10]):
|
| 314 |
+
logging.info('Downloaded Google Chrome update is detected! Using new chrome executable file!')
|
| 315 |
+
console_log('Downloaded Google Chrome update is detected! Using new chrome executable file!', INFO, silent_mode=SILENT_MODE)
|
| 316 |
+
browser_path = browser_path[:-10]+'new_chrome.exe'
|
| 317 |
+
driver_options.binary_location = browser_path
|
| 318 |
+
driver = Chrome(options=driver_options, service=ChromeService(executable_path=webdriver_path))
|
| 319 |
+
else:
|
| 320 |
+
raise e
|
| 321 |
+
elif browser_name == MICROSOFT_EDGE:
|
| 322 |
+
driver_options = EdgeOptions()
|
| 323 |
+
driver_options.page_load_strategy = "eager"
|
| 324 |
+
driver_options.use_chromium = True
|
| 325 |
+
driver_options.binary_location = browser_path
|
| 326 |
+
driver_options.add_experimental_option('excludeSwitches', ['enable-logging'])
|
| 327 |
+
driver_options.add_argument("--log-level=3")
|
| 328 |
+
driver_options.add_argument("--lang=en-US")
|
| 329 |
+
if headless:
|
| 330 |
+
driver_options.add_argument('--headless')
|
| 331 |
+
if os.name == 'posix': # For Linux
|
| 332 |
+
driver_options.add_argument('--no-sandbox')
|
| 333 |
+
driver_options.add_argument('--disable-dev-shm-usage')
|
| 334 |
+
service = EdgeService(executable_path=webdriver_path)
|
| 335 |
+
if os.name == 'nt' and headless:
|
| 336 |
+
service.creation_flags = 0x08000000 # CREATE_NO_WINDOW (Process Creation Flags, WinBase.h) -> 'DevTools listening on' is not visible!!!
|
| 337 |
+
try:
|
| 338 |
+
driver = Edge(options=driver_options, service=service)
|
| 339 |
+
except Exception as e:
|
| 340 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 341 |
+
if traceback.format_exc().find('--user-data-dir') != -1: # Fix for probably user data directory is already in use
|
| 342 |
+
driver_options.add_argument("--user-data-dir=./edge_tmp")
|
| 343 |
+
try:
|
| 344 |
+
shutil.rmtree("edge_tmp")
|
| 345 |
+
except:
|
| 346 |
+
pass
|
| 347 |
+
os.makedirs('edge_tmp', exist_ok=True)
|
| 348 |
+
driver = Edge(options=driver_options, service=EdgeService(executable_path=webdriver_path))
|
| 349 |
+
else:
|
| 350 |
+
raise e
|
| 351 |
+
elif browser_name == MOZILLA_FIREFOX:
|
| 352 |
+
driver_options = FirefoxOptions()
|
| 353 |
+
driver_options.page_load_strategy = "eager"
|
| 354 |
+
if browser_path.strip() != '':
|
| 355 |
+
driver_options.binary_location = browser_path
|
| 356 |
+
driver_options.set_preference('intl.accept_languages', 'en-US')
|
| 357 |
+
if headless:
|
| 358 |
+
driver_options.add_argument('--headless')
|
| 359 |
+
if os.name == 'posix': # For Linux
|
| 360 |
+
driver_options.add_argument('--no-sandbox')
|
| 361 |
+
driver_options.add_argument("--disable-dev-shm-usage")
|
| 362 |
+
service = FirefoxService(executable_path=webdriver_path)
|
| 363 |
+
if os.name == 'nt' and headless:
|
| 364 |
+
service.creation_flags = 0x08000000 # CREATE_NO_WINDOW (Process Creation Flags, WinBase.h) -> 'DevTools listening on' is not visible!!!
|
| 365 |
+
# Fix for: Your firefox profile cannot be loaded. it may be missing or inaccessible
|
| 366 |
+
os.makedirs('firefox_tmp', exist_ok=True)
|
| 367 |
+
os.environ['TMPDIR'] = (os.getcwd()+'/firefox_tmp').replace('\\', '/')
|
| 368 |
+
driver = Firefox(options=driver_options, service=service)
|
| 369 |
+
elif browser_name == APPLE_SAFARI:
|
| 370 |
+
driver_options = SafariOptions()
|
| 371 |
+
try:
|
| 372 |
+
if os.name == 'nt':
|
| 373 |
+
console_log('Apple Safari is not supported on Windows!!!', ERROR)
|
| 374 |
+
return None
|
| 375 |
+
elif os.name == 'posix' and sys.platform.startswith('linux'):
|
| 376 |
+
console_log('Apple Safari is not supported on Linux!!!', ERROR)
|
| 377 |
+
return None
|
| 378 |
+
driver = Safari(options=driver_options, service=SafariService(executable_path=webdriver_path))
|
| 379 |
+
except Exception as e:
|
| 380 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 381 |
+
if traceback.format_exc().find("Allow Remote Automation") != -1:
|
| 382 |
+
console_log(traceback.format_exc().split('Message: ')[-1].strip(), ERROR)
|
| 383 |
+
else:
|
| 384 |
+
raise e
|
| 385 |
+
return driver
|
| 386 |
+
|
| 387 |
+
def parseToken(email_obj, driver=None, eset_business=False, delay=DEFAULT_DELAY, max_iter=DEFAULT_MAX_ITER):
|
| 388 |
+
activated_href = None
|
| 389 |
+
if email_obj.class_name == 'custom':
|
| 390 |
+
while True:
|
| 391 |
+
activated_href = input(f'\n[ {colorama.Fore.YELLOW}INPT{colorama.Fore.RESET} ] {colorama.Fore.CYAN}Enter the link to activate your account, it will come to the email address you provide: {colorama.Fore.RESET}').strip()
|
| 392 |
+
logging.info(f'[ INPT ] Enter the link to activate your account, it will come to the email address you provide: {activated_href}')
|
| 393 |
+
if activated_href != '':
|
| 394 |
+
if eset_business:
|
| 395 |
+
match = re.search(r'activation\/[a-zA-Z0-9-]+', activated_href)
|
| 396 |
+
else:
|
| 397 |
+
match = re.search(r'token=[a-zA-Z\d:/-]*', activated_href)
|
| 398 |
+
if match is not None:
|
| 399 |
+
if eset_business:
|
| 400 |
+
token = match.group()[11:]
|
| 401 |
+
else:
|
| 402 |
+
token = match.group()[6:]
|
| 403 |
+
if len(token) == 36:
|
| 404 |
+
return token
|
| 405 |
+
logging.error('Incorrect link syntax')
|
| 406 |
+
console_log('Incorrect link syntax', ERROR)
|
| 407 |
+
for _ in range(max_iter):
|
| 408 |
+
if email_obj.class_name == '1secmail':
|
| 409 |
+
json = email_obj.read_email()
|
| 410 |
+
if json != []:
|
| 411 |
+
for message in json:
|
| 412 |
+
if eset_business and message['subject'].find('ESET PROTECT Hub') != -1:
|
| 413 |
+
activated_href = email_obj.get_message(message['id'])['body']
|
| 414 |
+
elif message['from'].find('product.eset.com') != -1:
|
| 415 |
+
activated_href = email_obj.get_message(message['id'])['body']
|
| 416 |
+
elif email_obj.class_name in ['developermail', 'inboxes']:
|
| 417 |
+
messages = email_obj.get_messages()
|
| 418 |
+
if messages is not None:
|
| 419 |
+
for message in messages:
|
| 420 |
+
if eset_business and message['subject'].find('ESET PROTECT Hub') != -1:
|
| 421 |
+
activated_href = message['body']
|
| 422 |
+
elif message['from'].find('product.eset.com') != -1:
|
| 423 |
+
activated_href = message['body']
|
| 424 |
+
elif email_obj.class_name in ['guerrillamail', 'mailticking', 'fakemail', 'incognitomail']:
|
| 425 |
+
inbox = email_obj.parse_inbox()
|
| 426 |
+
for mail in inbox:
|
| 427 |
+
mail_id, mail_from, mail_subject = mail
|
| 428 |
+
if mail_from.find('product.eset.com') != -1 or mail_from.find('ESET HOME') != -1 or mail_subject.find('ESET PROTECT Hub') != -1:
|
| 429 |
+
email_obj.open_mail(mail_id)
|
| 430 |
+
if email_obj.class_name in ['mailticking', 'incognitomail']:
|
| 431 |
+
time.sleep(2)
|
| 432 |
+
try:
|
| 433 |
+
if email_obj.class_name == 'mailticking':
|
| 434 |
+
driver.switch_to.frame(driver.find_element('id', 'email-iframe'))
|
| 435 |
+
if eset_business:
|
| 436 |
+
activated_href = driver.find_element('xpath', "//a[starts-with(@href, 'https://protecthub.eset.com')]").get_attribute('href')
|
| 437 |
+
else:
|
| 438 |
+
activated_href = driver.find_element('xpath', "//a[starts-with(@href, 'https://login.eset.com')]").get_attribute('href')
|
| 439 |
+
driver.switch_to.default_content()
|
| 440 |
+
except:
|
| 441 |
+
pass
|
| 442 |
+
if activated_href is not None:
|
| 443 |
+
if eset_business:
|
| 444 |
+
match = re.search(r'activation\/[a-zA-Z0-9-]+', activated_href)
|
| 445 |
+
else:
|
| 446 |
+
match = re.search(r'token=[a-zA-Z\d:/-]*', activated_href)
|
| 447 |
+
if match is not None:
|
| 448 |
+
if eset_business:
|
| 449 |
+
token = match.group()[11:]
|
| 450 |
+
else:
|
| 451 |
+
token = match.group()[6:]
|
| 452 |
+
if len(token) == 36:
|
| 453 |
+
return token
|
| 454 |
+
time.sleep(delay)
|
| 455 |
+
raise RuntimeError('Token retrieval error, try again later or change the Email API!!!')
|
| 456 |
+
|
| 457 |
+
def parseEPHKey(email_obj, driver=None, delay=DEFAULT_DELAY, max_iter=DEFAULT_MAX_ITER):
|
| 458 |
+
for _ in range(max_iter):
|
| 459 |
+
license_data = None
|
| 460 |
+
if email_obj.class_name in ['developermail', 'inboxes']:
|
| 461 |
+
messages = email_obj.get_messages()
|
| 462 |
+
if messages is not None:
|
| 463 |
+
for message in messages:
|
| 464 |
+
if message['subject'].find('Thank you for purchasing') != -1:
|
| 465 |
+
license_data = message['body']
|
| 466 |
+
break
|
| 467 |
+
elif email_obj.class_name in ['mailticking', 'fakemail', 'incognitomail']:
|
| 468 |
+
inbox = email_obj.parse_inbox()
|
| 469 |
+
for mail in inbox:
|
| 470 |
+
mail_id, mail_from, mail_subject = mail
|
| 471 |
+
if mail_subject.find('Thank you for purchasing') != -1:
|
| 472 |
+
try:
|
| 473 |
+
email_obj.open_mail(mail_id)
|
| 474 |
+
time.sleep(3)
|
| 475 |
+
if email_obj.class_name == 'mailticking':
|
| 476 |
+
license_data = driver.find_element('id', 'email-iframe').srcdoc
|
| 477 |
+
else:
|
| 478 |
+
license_data = email_obj.driver.page_source
|
| 479 |
+
break
|
| 480 |
+
except:
|
| 481 |
+
pass
|
| 482 |
+
if license_data is not None:
|
| 483 |
+
license_data = str(license_data)
|
| 484 |
+
license_key = re.search(r'([A-Z0-9]){4}-([A-Z0-9]){4}-([A-Z0-9]){4}-([A-Z0-9]){4}-([A-Z0-9]){4}', license_data).group()
|
| 485 |
+
license_id = re.search(r'[A-Z0-9]{3}-[A-Z0-9]{3}-[A-Z0-9]{3}', license_data).group()
|
| 486 |
+
license_out_date = re.findall(r'\d\d.\d\d.\d\d\d\d', license_data)[-1]
|
| 487 |
+
return license_key, license_out_date, license_id
|
| 488 |
+
time.sleep(delay)
|
| 489 |
+
raise RuntimeError('ESET ProtectHub data waiting time has been exceeded!!!')
|
| 490 |
+
|
| 491 |
+
def parseVPNCodes(email_obj, driver=None, delay=DEFAULT_DELAY, max_iter=DEFAULT_MAX_ITER):
|
| 492 |
+
for _ in range(max_iter):
|
| 493 |
+
data = None
|
| 494 |
+
try:
|
| 495 |
+
if email_obj.class_name == '1secmail':
|
| 496 |
+
json = email_obj.read_email()
|
| 497 |
+
if json != []:
|
| 498 |
+
for message in json:
|
| 499 |
+
if message['subject'].find('VPN - Setup instructions') != -1:
|
| 500 |
+
data = email_obj.get_message(message['id'])['body']
|
| 501 |
+
elif email_obj.class_name in ['developermail', 'inboxes']:
|
| 502 |
+
messages = email_obj.get_messages()
|
| 503 |
+
if messages is not None:
|
| 504 |
+
for message in messages:
|
| 505 |
+
if message['subject'].find('VPN - Setup instructions') != -1:
|
| 506 |
+
data = message['body']
|
| 507 |
+
elif email_obj.class_name in ['guerrillamail', 'mailticking', 'fakemail', 'incognitomail']:
|
| 508 |
+
inbox = email_obj.parse_inbox()
|
| 509 |
+
for mail in inbox:
|
| 510 |
+
mail_id, mail_from, mail_subject = mail
|
| 511 |
+
if mail_subject.find('VPN - Setup instructions') != -1:
|
| 512 |
+
email_obj.open_mail(mail_id)
|
| 513 |
+
if email_obj.class_name == 'mailticking':
|
| 514 |
+
time.sleep(1.5)
|
| 515 |
+
try:
|
| 516 |
+
data = str(driver.find_element('id', 'email-iframe').get_attribute('srcdoc'))
|
| 517 |
+
except:
|
| 518 |
+
pass
|
| 519 |
+
elif email_obj.class_name == 'guerrillamail':
|
| 520 |
+
try:
|
| 521 |
+
data = str(driver.execute_script(f'return {GET_EBCN}("email_body")[0].innerHTML'))
|
| 522 |
+
except:
|
| 523 |
+
pass
|
| 524 |
+
elif email_obj.class_name == 'incognitomail':
|
| 525 |
+
time.sleep(1.5)
|
| 526 |
+
try:
|
| 527 |
+
data = str(driver.execute_script(f'return {GET_EBCN}("MuiBox-root joy-1v8x7dw")[0].innerHTML'))
|
| 528 |
+
except:
|
| 529 |
+
pass
|
| 530 |
+
else:
|
| 531 |
+
data = driver.page_source
|
| 532 |
+
except:
|
| 533 |
+
pass
|
| 534 |
+
if data is not None:
|
| 535 |
+
match = re.findall(r'[A-Z0-9]{10}', data)
|
| 536 |
+
if match is not None and len(match) == 10:
|
| 537 |
+
return match
|
| 538 |
+
time.sleep(delay)
|
| 539 |
+
raise RuntimeError('VPN Codes retrieval error, try again later or change the Email API!!!')
|
modules/Updater.py
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .SharedTools import console_log, INFO, OK, ERROR, WARN
|
| 2 |
+
from .ProgressBar import ProgressBar, DEFAULT_RICH_STYLE
|
| 3 |
+
|
| 4 |
+
import subprocess
|
| 5 |
+
import requests
|
| 6 |
+
import zipfile
|
| 7 |
+
import logging
|
| 8 |
+
import pathlib
|
| 9 |
+
import sys
|
| 10 |
+
import os
|
| 11 |
+
|
| 12 |
+
SILENT_MODE = '--silent' in sys.argv
|
| 13 |
+
|
| 14 |
+
WINDOWS_EXTERNAL_UPDATER = """
|
| 15 |
+
@echo off
|
| 16 |
+
|
| 17 |
+
timeout 1 >nul 2>&1
|
| 18 |
+
|
| 19 |
+
echo.
|
| 20 |
+
echo --- ESET-KeyGen External-Updater ---
|
| 21 |
+
echo.
|
| 22 |
+
|
| 23 |
+
echo !!! Make sure you are running the program with elevated permissions, else update will fail !!!
|
| 24 |
+
echo.
|
| 25 |
+
echo !!! Do not interrupt the update, if you interrupt the update, the executable file will be corrupted !!!
|
| 26 |
+
echo.
|
| 27 |
+
|
| 28 |
+
where curl >nul 2>&1
|
| 29 |
+
if %ERRORLEVEL%==0 (
|
| 30 |
+
curl -#L %1 -o %2
|
| 31 |
+
) else (
|
| 32 |
+
powershell Invoke-WebRequest -Uri %1 -OutFile %2
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
echo.
|
| 36 |
+
echo Press Enter to exit the updater ...
|
| 37 |
+
pause >nul
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
WINDOWS_EXTERNAL_UPDATER_SILENT = """
|
| 41 |
+
@echo off
|
| 42 |
+
|
| 43 |
+
timeout 1 >nul 2>&1
|
| 44 |
+
|
| 45 |
+
where curl >nul 2>&1
|
| 46 |
+
if %ERRORLEVEL%==0 (
|
| 47 |
+
curl -#L %1 -o %2 -s
|
| 48 |
+
) else (
|
| 49 |
+
powershell Invoke-WebRequest -Uri %1 -OutFile %2
|
| 50 |
+
)
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
MACOS_EXTERNAL_UPDATER = """
|
| 54 |
+
#!/bin/bash
|
| 55 |
+
|
| 56 |
+
sleep 1
|
| 57 |
+
|
| 58 |
+
echo -e '\n--- ESET-KeyGen External-Updater ---\n'
|
| 59 |
+
echo -e '!!! Make sure you are running the program with elevated permissions, else update will fail !!!\n'
|
| 60 |
+
echo -e '!!! Do not interrupt the update, if you interrupt the update, the executable file will be corrupted !!!\n'
|
| 61 |
+
|
| 62 |
+
curl -#L $1 -o $2
|
| 63 |
+
chmod 755 $2
|
| 64 |
+
echo -e "\nPress Enter to exit the updater ..."
|
| 65 |
+
|
| 66 |
+
exit
|
| 67 |
+
"""
|
| 68 |
+
|
| 69 |
+
MACOS_EXTERNAL_UPDATER_SILENT = """
|
| 70 |
+
#!/bin/bash
|
| 71 |
+
|
| 72 |
+
sleep 1
|
| 73 |
+
|
| 74 |
+
curl -#L $1 -o $2 -s
|
| 75 |
+
chmod 755 $2
|
| 76 |
+
exit
|
| 77 |
+
"""
|
| 78 |
+
|
| 79 |
+
class Updater:
|
| 80 |
+
def __init__(self, disable_logging=False):
|
| 81 |
+
self.disable_logging = disable_logging
|
| 82 |
+
if SILENT_MODE:
|
| 83 |
+
self.disable_logging = True
|
| 84 |
+
self.arch = None
|
| 85 |
+
if sys.platform.startswith('win'):
|
| 86 |
+
self.arch = 'win32'
|
| 87 |
+
if sys.maxsize > 2**32: # 64bit
|
| 88 |
+
self.arch = 'win64'
|
| 89 |
+
elif sys.platform == 'darwin':
|
| 90 |
+
self.arch = 'macos' # prefix for universal macOS builds (arm64 + x86_64)
|
| 91 |
+
#arch = 'macos_arm64'
|
| 92 |
+
#if platform.machine() == "x86_64":
|
| 93 |
+
# arch = 'macos_amd64'
|
| 94 |
+
self.releases = None
|
| 95 |
+
|
| 96 |
+
def get_releases(self, version='latest'):
|
| 97 |
+
url = 'https://api.github.com/repos/shadowcopyrz/ESET-KGEN-COPY/releases'
|
| 98 |
+
if version == 'latest':
|
| 99 |
+
url = 'https://api.github.com/repos/shadowcopyrz/ESET-KGEN-COPY/releases/latest'
|
| 100 |
+
try:
|
| 101 |
+
response = requests.get(url, timeout=5)
|
| 102 |
+
update_json = response.json()
|
| 103 |
+
try:
|
| 104 |
+
if update_json.get('message') is not None:
|
| 105 |
+
logging.error('Your IP address has been blocked. try again later or use a VPN!')
|
| 106 |
+
console_log('Your IP address has been blocked. try again later or use a VPN!', ERROR, silent_mode=self.disable_logging)
|
| 107 |
+
return None
|
| 108 |
+
except AttributeError:
|
| 109 |
+
pass
|
| 110 |
+
if version == 'latest': # when requesting the latest version, the site returns json without a list.
|
| 111 |
+
update_json = [update_json]
|
| 112 |
+
f_update_json = {}
|
| 113 |
+
for release in update_json:
|
| 114 |
+
f_update_json[release['name']] = {
|
| 115 |
+
'version': release['name'],
|
| 116 |
+
'src': release['zipball_url'],
|
| 117 |
+
'assets': {}
|
| 118 |
+
}
|
| 119 |
+
for asset in release['assets']:
|
| 120 |
+
if asset['name'] == 'src.zip':
|
| 121 |
+
f_update_json[release['name']]['src'] = asset['browser_download_url']
|
| 122 |
+
else:
|
| 123 |
+
f_update_json[release['name']]['assets'][asset['name']] = asset['browser_download_url']
|
| 124 |
+
self.releases = f_update_json
|
| 125 |
+
return f_update_json
|
| 126 |
+
except:
|
| 127 |
+
return None
|
| 128 |
+
|
| 129 |
+
def find_suitable_data(self, datatype='source_code', version='latest'): # datatype: source_code OR executable_file
|
| 130 |
+
if self.releases is None:
|
| 131 |
+
self.releases = self.get_releases(version)
|
| 132 |
+
if version == 'latest':
|
| 133 |
+
if datatype == 'source_code':
|
| 134 |
+
return self.releases[list(self.releases.keys())[0]]['src']
|
| 135 |
+
elif datatype == 'executable_file':
|
| 136 |
+
assets = self.releases[list(self.releases.keys())[0]]['assets']
|
| 137 |
+
else:
|
| 138 |
+
for release_name in self.releases:
|
| 139 |
+
if release_name == version:
|
| 140 |
+
if datatype == 'source_code':
|
| 141 |
+
return self.releases[release_name]['src']
|
| 142 |
+
elif datatype == 'executable_file':
|
| 143 |
+
assets = self.releases[release_name]['assets']
|
| 144 |
+
break
|
| 145 |
+
if datatype == 'executable_file':
|
| 146 |
+
for asset_name, asset_url in assets.items():
|
| 147 |
+
if asset_name.find(self.arch) != -1:
|
| 148 |
+
return asset_url
|
| 149 |
+
|
| 150 |
+
def download_file(self, url):
|
| 151 |
+
try:
|
| 152 |
+
response = requests.get(url, stream=True)
|
| 153 |
+
try:
|
| 154 |
+
filename = response.headers.get('content-disposition').split('filename=')[1]
|
| 155 |
+
logging.info(f'Downloading {filename}...')
|
| 156 |
+
console_log(f'Downloading {filename}...', INFO, silent_mode=self.disable_logging)
|
| 157 |
+
except:
|
| 158 |
+
pass
|
| 159 |
+
total_length = response.headers.get('content-length')
|
| 160 |
+
if total_length is None or self.disable_logging: # No content length header
|
| 161 |
+
with open(filename, 'wb') as f:
|
| 162 |
+
f.write(response.content)
|
| 163 |
+
else:
|
| 164 |
+
task = ProgressBar(int(total_length), ' ', DEFAULT_RICH_STYLE)
|
| 165 |
+
with open(filename, 'wb') as f:
|
| 166 |
+
for chunk in response.iter_content(chunk_size=8192):
|
| 167 |
+
if chunk: # filter out keep-alive new chunks
|
| 168 |
+
f.write(chunk)
|
| 169 |
+
task.update(len(chunk))
|
| 170 |
+
task.render()
|
| 171 |
+
return str(pathlib.Path(filename).resolve())
|
| 172 |
+
except Exception as e:
|
| 173 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 174 |
+
console_log(f"Error downloading file: {e}", ERROR, silent_mode=self.disable_logging)
|
| 175 |
+
return False
|
| 176 |
+
|
| 177 |
+
def extract_data(self, data_path: str, new_name=None):
|
| 178 |
+
extracted_data_path = None
|
| 179 |
+
if data_path.endswith('.zip'): # source code
|
| 180 |
+
try:
|
| 181 |
+
with zipfile.ZipFile(data_path, 'r') as zipf:
|
| 182 |
+
extracted_folder_name = zipf.filelist[0].filename[0:-1] # rzc0d3r-ESET-KeyGen-56a2c5b/ -> rzc0d3r-ESET-KeyGen-56a2c5b
|
| 183 |
+
zipf.extractall()
|
| 184 |
+
logging.info("Extraction completed successfully!")
|
| 185 |
+
console_log("Extraction completed successfully!", OK, silent_mode=self.disable_logging)
|
| 186 |
+
extracted_data_path = str(pathlib.Path(extracted_folder_name).resolve())
|
| 187 |
+
if new_name is not None:
|
| 188 |
+
os.rename(extracted_folder_name, new_name)
|
| 189 |
+
extracted_data_path = str(pathlib.Path(new_name).resolve())
|
| 190 |
+
else:
|
| 191 |
+
os.rename(extracted_folder_name, 'ESET-KeyGen-'+list(self.releases.keys())[0])
|
| 192 |
+
extracted_data_path = str(pathlib.Path('ESET-KeyGen-'+list(self.releases.keys())[0]))
|
| 193 |
+
except Exception as e:
|
| 194 |
+
logging.critical("EXC_INFO:", exc_info=True)
|
| 195 |
+
console_log(str(e), ERROR, silent_mode=self.disable_logging)
|
| 196 |
+
if not data_path.endswith('.zip'): # executable file
|
| 197 |
+
extracted_data_path = str(pathlib.Path(data_path).resolve())
|
| 198 |
+
if new_name is not None:
|
| 199 |
+
os.rename(data_path, new_name)
|
| 200 |
+
extracted_data_path = str(pathlib.Path(new_name).resolve())
|
| 201 |
+
logging.warning(f"Location of update: {extracted_data_path}")
|
| 202 |
+
console_log(f"Location of update: {extracted_data_path}", WARN, silent_mode=self.disable_logging)
|
| 203 |
+
return extracted_data_path
|
| 204 |
+
|
| 205 |
+
def updater_menu(self, i_am_executable, path_to_main_file):
|
| 206 |
+
executable_file_url = self.find_suitable_data(datatype='executable_file')
|
| 207 |
+
if i_am_executable: # run from the build [supported platform]
|
| 208 |
+
logging.info('Transferring control to an external script...')
|
| 209 |
+
if sys.platform.startswith('win'):
|
| 210 |
+
updater_path = os.environ['TEMP']+'\\updater.bat'
|
| 211 |
+
with open(updater_path, 'w') as f:
|
| 212 |
+
if SILENT_MODE:
|
| 213 |
+
f.write(WINDOWS_EXTERNAL_UPDATER_SILENT)
|
| 214 |
+
else:
|
| 215 |
+
f.write(WINDOWS_EXTERNAL_UPDATER)
|
| 216 |
+
subprocess.Popen([updater_path, executable_file_url, path_to_main_file], shell=True)
|
| 217 |
+
elif sys.platform == 'darwin':
|
| 218 |
+
updater_path = r'/tmp/updater.sh'
|
| 219 |
+
with open(updater_path, 'w') as f:
|
| 220 |
+
if SILENT_MODE:
|
| 221 |
+
f.write(MACOS_EXTERNAL_UPDATER_SILENT)
|
| 222 |
+
else:
|
| 223 |
+
f.write(MACOS_EXTERNAL_UPDATER)
|
| 224 |
+
os.chmod(updater_path, 0o755)
|
| 225 |
+
subprocess.Popen(['bash', updater_path, executable_file_url, path_to_main_file])
|
| 226 |
+
sys.exit(0)
|
| 227 |
+
elif executable_file_url is not None: # run from source [supported platform]
|
| 228 |
+
executable_file_url = self.find_suitable_data(datatype='executable_file')
|
| 229 |
+
self.extract_data(self.download_file(executable_file_url))
|
| 230 |
+
else: # run from source [unsupported platform]
|
| 231 |
+
logging.error('No suitable executable file was found for your platform!!!')
|
| 232 |
+
logging.info('Downloading the latest release source code...')
|
| 233 |
+
console_log('No suitable executable file was found for your platform!!!', ERROR, silent_mode=SILENT_MODE)
|
| 234 |
+
console_log('Downloading the latest release source code...', INFO, silent_mode=SILENT_MODE)
|
| 235 |
+
self.extract_data(self.download_file(self.find_suitable_data()))
|
modules/WebDriverInstaller.py
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GOOGLE_CHROME = 'Google Chrome'
|
| 2 |
+
MICROSOFT_EDGE = 'Microsoft Edge'
|
| 3 |
+
MOZILLA_FIREFOX = 'Mozilla Firefox'
|
| 4 |
+
APPLE_SAFARI = 'Apple Safari'
|
| 5 |
+
|
| 6 |
+
GOOGLE_CHROME_RE = r'(\d+\.\d+\.\d+\.\d+)'
|
| 7 |
+
MICROSOFT_EDGE_RE = r'(\d+\.\d+\.\d+\.\d+)'
|
| 8 |
+
MOZILLA_FIREFOX_RE = r'(\d+\.\d+\.\d+)|(\d+\.\d+)'
|
| 9 |
+
APPLE_SAFARI_RE = r'\d+.\d+.\d+'
|
| 10 |
+
|
| 11 |
+
from .SharedTools import console_log, INFO, OK, ERROR, WARN
|
| 12 |
+
from .ProgressBar import ProgressBar, DEFAULT_RICH_STYLE
|
| 13 |
+
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
from colorama import Fore, init
|
| 17 |
+
init()
|
| 18 |
+
|
| 19 |
+
import subprocess
|
| 20 |
+
import platform
|
| 21 |
+
import requests
|
| 22 |
+
import logging
|
| 23 |
+
import zipfile
|
| 24 |
+
import tarfile
|
| 25 |
+
import shutil
|
| 26 |
+
import sys
|
| 27 |
+
import re
|
| 28 |
+
import os
|
| 29 |
+
|
| 30 |
+
SILENT_MODE = '--silent' in sys.argv
|
| 31 |
+
|
| 32 |
+
class WebDriverInstaller(object):
|
| 33 |
+
def __init__(self, browser_name: str, custom_browser_location=None):
|
| 34 |
+
self.browsers_data = {
|
| 35 |
+
GOOGLE_CHROME: [self.get_chromedriver_url, 'chromedriver.exe' if sys.platform.startswith('win') else 'chromedriver', self.get_chrome_version, GOOGLE_CHROME_RE],
|
| 36 |
+
MICROSOFT_EDGE: [self.get_msedgedriver_url, 'msedgedriver.exe' if sys.platform.startswith('win') else 'msedgedriver', self.get_edge_version, MICROSOFT_EDGE_RE],
|
| 37 |
+
MOZILLA_FIREFOX: [self.get_geckodriver_url, 'geckodriver.exe' if sys.platform.startswith('win') else 'geckodriver', self.get_firefox_version, MOZILLA_FIREFOX_RE],
|
| 38 |
+
APPLE_SAFARI: []
|
| 39 |
+
}
|
| 40 |
+
self.browser_name = browser_name
|
| 41 |
+
self.custom_browser_location = custom_browser_location
|
| 42 |
+
if self.browser_name not in self.browsers_data:
|
| 43 |
+
raise RuntimeError('WebDriverInstaller: invalid browser_name!')
|
| 44 |
+
self.browser_data = self.browsers_data[self.browser_name]
|
| 45 |
+
self.platform = ['', []] # [OC name, [webdriver architectures]]
|
| 46 |
+
if sys.platform.startswith('win'):
|
| 47 |
+
self.platform[0] = 'win'
|
| 48 |
+
if sys.maxsize > 2**32:
|
| 49 |
+
self.platform[1] = ['win64', 'win32']
|
| 50 |
+
else:
|
| 51 |
+
self.platform[1] = ['win32']
|
| 52 |
+
elif sys.platform.startswith('linux'):
|
| 53 |
+
self.platform[0] = 'linux'
|
| 54 |
+
if sys.maxsize > 2**32:
|
| 55 |
+
self.platform[1].append('linux64')
|
| 56 |
+
else:
|
| 57 |
+
self.platform[1].append('linux32')
|
| 58 |
+
elif sys.platform == "darwin":
|
| 59 |
+
self.platform[0] = 'mac'
|
| 60 |
+
if self.browser_name == MOZILLA_FIREFOX:
|
| 61 |
+
self.platform[1] = ['macos']
|
| 62 |
+
elif platform.processor() == "arm":
|
| 63 |
+
self.platform[1] = ['mac-arm64', 'mac_arm64', 'mac64_m1']
|
| 64 |
+
if self.browser_name == MOZILLA_FIREFOX:
|
| 65 |
+
self.platform[1] = ['macos-aarch64']
|
| 66 |
+
elif platform.processor() == "i386":
|
| 67 |
+
self.platform[1] = ['mac64', 'mac-x64']
|
| 68 |
+
|
| 69 |
+
def get_browser_version_from_cmd(self, path: str, re_pattern: str):
|
| 70 |
+
try:
|
| 71 |
+
with subprocess.Popen([path, "--version"], stdout=subprocess.PIPE) as proc:
|
| 72 |
+
return re.search(re_pattern, proc.communicate()[0].decode("utf-8")).group()
|
| 73 |
+
except:
|
| 74 |
+
pass
|
| 75 |
+
|
| 76 |
+
def get_chrome_version(self):
|
| 77 |
+
browser_version = None
|
| 78 |
+
browser_path = None
|
| 79 |
+
if self.platform[0] == "linux":
|
| 80 |
+
if self.custom_browser_location is not None:
|
| 81 |
+
browser_version = self.get_browser_version_from_cmd(self.custom_browser_location, GOOGLE_CHROME_RE)
|
| 82 |
+
browser_path = self.custom_browser_location
|
| 83 |
+
else:
|
| 84 |
+
for executable in ["google-chrome", "google-chrome-stable", "google-chrome-beta", "google-chrome-dev", "chromium-browser", "chromium"]:
|
| 85 |
+
browser_version = self.get_browser_version_from_cmd(shutil.which(executable), GOOGLE_CHROME_RE)
|
| 86 |
+
if browser_version is not None:
|
| 87 |
+
browser_path = shutil.which(executable)
|
| 88 |
+
break
|
| 89 |
+
elif self.platform[0] == "mac":
|
| 90 |
+
if self.custom_browser_location is not None:
|
| 91 |
+
browser_version = self.get_browser_version_from_cmd(self.custom_browser_location, GOOGLE_CHROME_RE)
|
| 92 |
+
browser_path = self.custom_browser_location
|
| 93 |
+
else:
|
| 94 |
+
browser_version = self.get_browser_version_from_cmd('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', GOOGLE_CHROME_RE)
|
| 95 |
+
browser_path = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
|
| 96 |
+
elif self.platform[0] == "win":
|
| 97 |
+
paths = [
|
| 98 |
+
f'{os.environ.get("SYSTEMDRIVE")}\\Program Files\\Google\\Chrome\\Application',
|
| 99 |
+
f'{os.environ.get("SYSTEMDRIVE")}\\Program Files (x86)\\Google\\Chrome\\Application',
|
| 100 |
+
f'{os.environ.get("LOCALAPPDATA")}\\Google\\Chrome\\Application'
|
| 101 |
+
]
|
| 102 |
+
if self.custom_browser_location is not None:
|
| 103 |
+
paths = [str(Path(self.custom_browser_location).parent)]
|
| 104 |
+
for path in paths:
|
| 105 |
+
try:
|
| 106 |
+
with open(path+'\\chrome.VisualElementsManifest.xml', 'r') as f:
|
| 107 |
+
browser_version = re.search(GOOGLE_CHROME_RE, f.read()).group()
|
| 108 |
+
browser_path = path+'\\chrome.exe'
|
| 109 |
+
break
|
| 110 |
+
except:
|
| 111 |
+
pass
|
| 112 |
+
return [browser_version, browser_path]
|
| 113 |
+
|
| 114 |
+
def get_chromedriver_url(self, chrome_major_version=None):
|
| 115 |
+
if chrome_major_version is None:
|
| 116 |
+
chrome_major_version = self.get_chrome_version()[0]
|
| 117 |
+
if chrome_major_version is None:
|
| 118 |
+
return None
|
| 119 |
+
chrome_major_version = self.get_chrome_version()[0].split('.')[0]
|
| 120 |
+
if int(chrome_major_version) >= 115: # for new drivers ( [115.0.0000.0, ...] )
|
| 121 |
+
drivers_data = requests.get('https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json')
|
| 122 |
+
drivers_data = drivers_data.json()['versions'][::-1] # start with the latest version
|
| 123 |
+
for driver_data in drivers_data:
|
| 124 |
+
driver_major_version = driver_data['version'].split('.')[0] # major, _, minor, micro
|
| 125 |
+
if driver_major_version == chrome_major_version: # return latest driver version for current major chrome version
|
| 126 |
+
for driver_url in driver_data['downloads'].get('chromedriver', []):
|
| 127 |
+
if driver_url['platform'] in self.platform[1]:
|
| 128 |
+
return driver_url['url']
|
| 129 |
+
else: # for old drivers ( [..., 115.0.0000.0) )
|
| 130 |
+
latest_old_driver_version = requests.get(f'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_{chrome_major_version}')
|
| 131 |
+
if latest_old_driver_version.status_code == 200:
|
| 132 |
+
latest_old_driver_version = latest_old_driver_version.text
|
| 133 |
+
driver_url = f'https://chromedriver.storage.googleapis.com/{latest_old_driver_version}/chromedriver_'
|
| 134 |
+
for arch in self.platform[1]:
|
| 135 |
+
current_driver_url = driver_url+arch+'.zip'
|
| 136 |
+
driver_size = requests.head(current_driver_url).headers.get('x-goog-stored-content-length', None)
|
| 137 |
+
if driver_size is not None and int(driver_size) > 1024**2:
|
| 138 |
+
return current_driver_url
|
| 139 |
+
|
| 140 |
+
def get_edge_version(self):
|
| 141 |
+
browser_version = None
|
| 142 |
+
browser_path = None
|
| 143 |
+
if self.platform[0] == 'linux':
|
| 144 |
+
if self.custom_browser_location is not None:
|
| 145 |
+
browser_version = self.get_browser_version_from_cmd(self.custom_browser_location, MICROSOFT_EDGE_RE)
|
| 146 |
+
browser_path = self.custom_browser_location
|
| 147 |
+
else:
|
| 148 |
+
for executable in ['microsoft-edge']:
|
| 149 |
+
browser_version = self.get_browser_version_from_cmd(shutil.which(executable), MICROSOFT_EDGE_RE)
|
| 150 |
+
if browser_version is not None:
|
| 151 |
+
browser_path = shutil.which(executable)
|
| 152 |
+
break
|
| 153 |
+
elif self.platform[0] == "mac":
|
| 154 |
+
if self.custom_browser_location is not None:
|
| 155 |
+
browser_version = self.get_browser_version_from_cmd(self.custom_browser_location, MICROSOFT_EDGE_RE)
|
| 156 |
+
browser_path = self.custom_browser_location
|
| 157 |
+
else:
|
| 158 |
+
browser_version = self.get_browser_version_from_cmd('/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge', MICROSOFT_EDGE_RE)
|
| 159 |
+
browser_path = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'
|
| 160 |
+
elif self.platform[0] == 'win':
|
| 161 |
+
paths = [
|
| 162 |
+
f'{os.environ.get("SYSTEMDRIVE")}\\Program Files\\Microsoft\\Edge\\Application',
|
| 163 |
+
f'{os.environ.get("SYSTEMDRIVE")}\\Program Files (x86)\\Microsoft\\Edge\\Application'
|
| 164 |
+
]
|
| 165 |
+
if self.custom_browser_location is not None:
|
| 166 |
+
paths = [str(Path(self.custom_browser_location).parent)]
|
| 167 |
+
for path in paths:
|
| 168 |
+
try:
|
| 169 |
+
with open(path+'\\msedge.VisualElementsManifest.xml', 'r') as f:
|
| 170 |
+
browser_version = re.search(MICROSOFT_EDGE_RE, f.read()).group()
|
| 171 |
+
browser_path = path+'\\msedge.exe'
|
| 172 |
+
break
|
| 173 |
+
except:
|
| 174 |
+
pass
|
| 175 |
+
return [browser_version, browser_path]
|
| 176 |
+
|
| 177 |
+
def get_msedgedriver_url(self, edge_version=None):
|
| 178 |
+
archs = self.platform[1]
|
| 179 |
+
if edge_version is None:
|
| 180 |
+
edge_version, _ = self.get_edge_version()
|
| 181 |
+
major_version = edge_version.split('.')[0]
|
| 182 |
+
if self.platform[0] == 'win':
|
| 183 |
+
r = requests.get(f'https://msedgedriver.azureedge.net/LATEST_RELEASE_{major_version}_WINDOWS')
|
| 184 |
+
elif self.platform[0] == 'linux':
|
| 185 |
+
r = requests.get(f'https://msedgedriver.azureedge.net/LATEST_RELEASE_{major_version}_LINUX')
|
| 186 |
+
elif self.platform[0] == 'mac':
|
| 187 |
+
r = requests.get(f'https://msedgedriver.azureedge.net/LATEST_RELEASE_{major_version}_MACOS')
|
| 188 |
+
if r.status_code == 200:
|
| 189 |
+
webdriver_version = r.text.strip()
|
| 190 |
+
for arch in archs:
|
| 191 |
+
driver_url = f'https://msedgedriver.azureedge.net/{webdriver_version}/edgedriver_{arch}.zip'
|
| 192 |
+
driver_size = requests.head(driver_url).headers.get('Content-Length', None)
|
| 193 |
+
if driver_size is not None and int(driver_size) > 1024**2:
|
| 194 |
+
return driver_url
|
| 195 |
+
|
| 196 |
+
def get_firefox_version(self):
|
| 197 |
+
browser_version = None
|
| 198 |
+
browser_path = None
|
| 199 |
+
if self.platform[0] == 'linux':
|
| 200 |
+
if self.custom_browser_location is not None:
|
| 201 |
+
browser_version = self.get_browser_version_from_cmd(self.custom_browser_location, MOZILLA_FIREFOX_RE)
|
| 202 |
+
browser_path = self.custom_browser_location
|
| 203 |
+
else:
|
| 204 |
+
for executable in ['firefox']:
|
| 205 |
+
browser_version = self.get_browser_version_from_cmd(shutil.which(executable), MOZILLA_FIREFOX_RE)
|
| 206 |
+
if browser_version is not None:
|
| 207 |
+
browser_path = shutil.which(executable)
|
| 208 |
+
break
|
| 209 |
+
elif self.platform[0] == "mac":
|
| 210 |
+
if self.custom_browser_location is not None:
|
| 211 |
+
browser_version = self.get_browser_version_from_cmd(self.custom_browser_location, MOZILLA_FIREFOX_RE)
|
| 212 |
+
browser_path = self.custom_browser_location
|
| 213 |
+
else:
|
| 214 |
+
for path in ['/Applications/Firefox.app/Contents/MacOS/firefox', '/application/firefox.app']:
|
| 215 |
+
if browser_version is not None:
|
| 216 |
+
browser_version = self.get_browser_version_from_cmd(path, MOZILLA_FIREFOX_RE)
|
| 217 |
+
browser_path = path
|
| 218 |
+
break
|
| 219 |
+
elif self.platform[0] == 'win':
|
| 220 |
+
paths = [
|
| 221 |
+
f'{os.environ.get("SYSTEMDRIVE")}\\Program Files\\Mozilla Firefox',
|
| 222 |
+
f'{os.environ.get("SYSTEMDRIVE")}\\Program Files (x86)\\Mozilla Firefox',
|
| 223 |
+
]
|
| 224 |
+
if self.custom_browser_location is not None:
|
| 225 |
+
paths = [str(Path(self.custom_browser_location).parent)]
|
| 226 |
+
for path in paths:
|
| 227 |
+
try:
|
| 228 |
+
with open(path+'\\application.ini', 'r') as f:
|
| 229 |
+
browser_version = re.search(MOZILLA_FIREFOX_RE, f.read()).group()
|
| 230 |
+
browser_path = path+'\\firefox.exe'
|
| 231 |
+
break
|
| 232 |
+
except:
|
| 233 |
+
pass
|
| 234 |
+
return [browser_version, browser_path]
|
| 235 |
+
|
| 236 |
+
def get_geckodriver_url(self, only_version=False):
|
| 237 |
+
r = requests.get("https://api.github.com/repos/mozilla/geckodriver/releases/latest")
|
| 238 |
+
r_json = r.json()
|
| 239 |
+
api_rate_limit = (True if r_json.get('name', None) is None else False)
|
| 240 |
+
if api_rate_limit: # bypass for API rate limit exceeded for your IP
|
| 241 |
+
r = requests.head("https://github.com/mozilla/geckodriver/releases/latest", allow_redirects=True)
|
| 242 |
+
geckodriver_version = r.url.split('/')[-1][1:]
|
| 243 |
+
else:
|
| 244 |
+
geckodriver_version = r_json['name']
|
| 245 |
+
if only_version:
|
| 246 |
+
return geckodriver_version
|
| 247 |
+
if not api_rate_limit:
|
| 248 |
+
#https://github.com/mozilla/geckodriver/releases/download/v0.34.0/geckodriver-v0.34.0-macos.tar.gz
|
| 249 |
+
# note for: r_json['assets'][::-1]
|
| 250 |
+
# in the initialization of WebDriverInstaller for 64bit is also suitable for 32bit, but
|
| 251 |
+
# in the list of assets first go 32bit and it comes out that for 64bit gives a 32bit release, turning the list fixes it
|
| 252 |
+
for asset in r_json['assets'][::-1]:
|
| 253 |
+
if asset['name'].find('asc') == -1: # ignoring GPG Keys
|
| 254 |
+
asset_arch = asset['name'].split('-', 2)[-1].split('.')[0] # package architecture parsing; geckodriver-v0.34.0-win32.zip -> ['geckodriver', 'v0.34.0', 'win32.zip'] -> ['win32', 'zip'] -> win32
|
| 255 |
+
if asset_arch in self.platform[1]:
|
| 256 |
+
return asset['browser_download_url']
|
| 257 |
+
else:
|
| 258 |
+
# bypass for API rate limit exceeded for your IP
|
| 259 |
+
extension = '.zip' if self.platform[0] == 'win' else '.tar.gz'
|
| 260 |
+
for arch in self.platform[1]:
|
| 261 |
+
url = f'https://github.com/mozilla/geckodriver/releases/download/v{geckodriver_version}/geckodriver-v{geckodriver_version}-{arch}{extension}'
|
| 262 |
+
r = requests.get(url, stream=True)
|
| 263 |
+
if int(r.headers.get('Content-Length', 0)) > 1024**2:
|
| 264 |
+
return url
|
| 265 |
+
|
| 266 |
+
def get_safari_version(self):
|
| 267 |
+
if self.platform[0] == "mac":
|
| 268 |
+
cmd = ['/usr/libexec/PlistBuddy', '-c', "print :CFBundleShortVersionString", '/Applications/Safari.app/Contents/Info.plist']
|
| 269 |
+
try:
|
| 270 |
+
with subprocess.Popen(cmd, stdout=subprocess.PIPE) as proc:
|
| 271 |
+
return re.search(APPLE_SAFARI_RE, proc.communicate()[0].decode("utf-8")).group()
|
| 272 |
+
except:
|
| 273 |
+
pass
|
| 274 |
+
|
| 275 |
+
def detect_installed_browser(self):
|
| 276 |
+
for browser_name in self.browsers_data:
|
| 277 |
+
if browser_name == APPLE_SAFARI:
|
| 278 |
+
browser_version = self.get_safari_version()
|
| 279 |
+
if browser_version is not None:
|
| 280 |
+
return [APPLE_SAFARI, browser_version]
|
| 281 |
+
else:
|
| 282 |
+
browser_version, browser_path = self.browsers_data[browser_name][2]()
|
| 283 |
+
if browser_version is not None:
|
| 284 |
+
return [browser_name, browser_version, browser_path]
|
| 285 |
+
|
| 286 |
+
def download_webdriver(self, url=None, path='.', disable_progress_bar=False):
|
| 287 |
+
# init
|
| 288 |
+
webdriver_name = self.browser_data[1]
|
| 289 |
+
file_extension = '.zip'
|
| 290 |
+
if url is None:
|
| 291 |
+
url = self.browser_data[0]()
|
| 292 |
+
if url is None:
|
| 293 |
+
return None
|
| 294 |
+
if url.split('.')[-1] == 'gz':
|
| 295 |
+
file_extension = '.tar.gz'
|
| 296 |
+
# downloading
|
| 297 |
+
archive_path = str(Path(f'{path}/data{file_extension}').resolve())
|
| 298 |
+
response = requests.get(url, stream=True)
|
| 299 |
+
if not disable_progress_bar:
|
| 300 |
+
total_length = int(response.headers.get('Content-Length', 0))
|
| 301 |
+
total_length = int(response.headers.get('content-length', total_length))
|
| 302 |
+
else:
|
| 303 |
+
total_length = 0
|
| 304 |
+
if total_length == 0 or SILENT_MODE: # No content length header
|
| 305 |
+
with open(archive_path, 'wb') as f:
|
| 306 |
+
f.write(response.content)
|
| 307 |
+
else:
|
| 308 |
+
task = ProgressBar(int(total_length), ' ', DEFAULT_RICH_STYLE)
|
| 309 |
+
with open(archive_path, 'wb') as f:
|
| 310 |
+
for chunk in response.iter_content(chunk_size=8192):
|
| 311 |
+
if chunk: # filter out keep-alive new chunks
|
| 312 |
+
f.write(chunk)
|
| 313 |
+
task.update(len(chunk))
|
| 314 |
+
task.render()
|
| 315 |
+
# extracting
|
| 316 |
+
archive, info = None, []
|
| 317 |
+
if file_extension == '.zip':
|
| 318 |
+
archive = zipfile.ZipFile(archive_path)
|
| 319 |
+
archive_info = archive.infolist()
|
| 320 |
+
elif file_extension == '.tar.gz':
|
| 321 |
+
archive = tarfile.open(archive_path)
|
| 322 |
+
archive_info = archive.getnames()
|
| 323 |
+
if archive is not None:
|
| 324 |
+
for info in archive_info:
|
| 325 |
+
archive_filename, archive_filepath = None, None
|
| 326 |
+
if file_extension == '.zip':
|
| 327 |
+
archive_filename, archive_filepath = info.filename.split('/')[-1], info.filename
|
| 328 |
+
else:
|
| 329 |
+
archive_filename, archive_filepath = info.split('/')[-1], info
|
| 330 |
+
if archive_filename is not None and archive_filename == webdriver_name:
|
| 331 |
+
try:
|
| 332 |
+
archive.extract(info)
|
| 333 |
+
archive.close()
|
| 334 |
+
webdriver_path = str(Path(archive_filepath).resolve())
|
| 335 |
+
if Path(archive_filepath).resolve().parent != Path(os.getcwd()):
|
| 336 |
+
webdriver_path = shutil.copy2(str(Path(archive_filepath).resolve()), os.getcwd())
|
| 337 |
+
try:
|
| 338 |
+
shutil.rmtree(archive_filepath.split('/')[0], ignore_errors=True)
|
| 339 |
+
os.remove(archive_path)
|
| 340 |
+
except:
|
| 341 |
+
pass
|
| 342 |
+
os.chmod(webdriver_path, 0o777)
|
| 343 |
+
return webdriver_path
|
| 344 |
+
except:
|
| 345 |
+
return None
|
| 346 |
+
|
| 347 |
+
def menu(self, disable_progress_bar=False): # auto updating or installing webdrivers
|
| 348 |
+
def download():
|
| 349 |
+
driver_url = self.browser_data[0]()
|
| 350 |
+
if driver_url is not None:
|
| 351 |
+
logging.info('Found a suitable version for your system!')
|
| 352 |
+
logging.info('Downloading...')
|
| 353 |
+
console_log('\nFound a suitable version for your system!', OK, silent_mode=SILENT_MODE)
|
| 354 |
+
console_log('Downloading...', INFO, silent_mode=SILENT_MODE)
|
| 355 |
+
if self.download_webdriver(driver_url, disable_progress_bar=disable_progress_bar):
|
| 356 |
+
logging.info(f'{self.browser_name} webdriver was successfully downloaded and unzipped!')
|
| 357 |
+
console_log(f'{self.browser_name} webdriver was successfully downloaded and unzipped!\n', OK, silent_mode=SILENT_MODE)
|
| 358 |
+
return os.path.join(os.getcwd(), webdriver_name)
|
| 359 |
+
else:
|
| 360 |
+
logging.info('Error downloading or unpacking!')
|
| 361 |
+
console_log('Error downloading or unpacking!\n', ERROR, silent_mode=SILENT_MODE)
|
| 362 |
+
else:
|
| 363 |
+
logging.info('A suitable version for your system was not found!')
|
| 364 |
+
console_log('\nA suitable version for your system was not found!\n', ERROR, silent_mode=SILENT_MODE)
|
| 365 |
+
logging.info('-- WebDriver Auto-Installer --')
|
| 366 |
+
console_log(f'{Fore.LIGHTMAGENTA_EX}-- WebDriver Auto-Installer --{Fore.RESET}\n', silent_mode=SILENT_MODE)
|
| 367 |
+
browser_version, browser_path = self.browser_data[2]()
|
| 368 |
+
if browser_version is None:
|
| 369 |
+
if self.custom_browser_location is None or self.custom_browser_location == '':
|
| 370 |
+
raise RuntimeError(f'{self.browser_name} was not found in the standard catalogs!')
|
| 371 |
+
raise RuntimeError(f'{self.custom_browser_location} is not a valid executable file of {self.browser_name}!')
|
| 372 |
+
webdriver_name = self.browser_data[1]
|
| 373 |
+
current_webdriver_version = None
|
| 374 |
+
webdriver_path = None
|
| 375 |
+
if os.path.exists(webdriver_name):
|
| 376 |
+
try:
|
| 377 |
+
out = subprocess.check_output([os.path.join(os.getcwd(), webdriver_name), "--version"], stderr=subprocess.PIPE)
|
| 378 |
+
out = re.search(self.browser_data[3], out.decode('utf-8'))
|
| 379 |
+
if out is not None:
|
| 380 |
+
current_webdriver_version = out.group()
|
| 381 |
+
webdriver_path = os.path.join(os.getcwd(), webdriver_name)
|
| 382 |
+
except:
|
| 383 |
+
pass
|
| 384 |
+
logging.info(f'{self.browser_name} version: {browser_version}')
|
| 385 |
+
logging.info(f'{self.browser_name} webdriver version: {current_webdriver_version}')
|
| 386 |
+
console_log(f'{self.browser_name} version: {browser_version}', INFO, False, SILENT_MODE)
|
| 387 |
+
console_log(f'{self.browser_name} webdriver version: {current_webdriver_version}', INFO, False, SILENT_MODE)
|
| 388 |
+
if self.browser_name == MOZILLA_FIREFOX:
|
| 389 |
+
latest_geckodriver_version = self.browser_data[0](True)
|
| 390 |
+
if current_webdriver_version == latest_geckodriver_version:
|
| 391 |
+
logging.info('The webdriver has already been updated to the latest version!')
|
| 392 |
+
console_log('The webdriver has already been updated to the latest version!\n', OK, silent_mode=SILENT_MODE)
|
| 393 |
+
webdriver_path = os.path.join(os.getcwd(), webdriver_name)
|
| 394 |
+
else:
|
| 395 |
+
logging.info(f'Updating the webdriver from {current_webdriver_version} to {latest_geckodriver_version} version...')
|
| 396 |
+
console_log(f'Updating the webdriver from {current_webdriver_version} to {latest_geckodriver_version} version...', INFO, silent_mode=SILENT_MODE)
|
| 397 |
+
webdriver_path = download()
|
| 398 |
+
else:
|
| 399 |
+
if current_webdriver_version is None or (current_webdriver_version.split('.')[0] != browser_version.split('.')[0]): # major version match
|
| 400 |
+
logging.warning(f'{self.browser_name} webdriver version doesn\'t match version of the installed {self.browser_name}, trying to download...')
|
| 401 |
+
console_log(f'{self.browser_name} webdriver version doesn\'t match version of the installed {self.browser_name}, trying to download...', WARN, True, SILENT_MODE)
|
| 402 |
+
webdriver_path = download()
|
| 403 |
+
else:
|
| 404 |
+
logging.info('The webdriver has already been updated to the browser version!')
|
| 405 |
+
console_log('The webdriver has already been updated to the browser version!\n', OK, silent_mode=SILENT_MODE)
|
| 406 |
+
try:
|
| 407 |
+
os.chmod(webdriver_path, 0o755)
|
| 408 |
+
except:
|
| 409 |
+
pass
|
| 410 |
+
return [str(Path(webdriver_path).resolve()), str(Path(browser_path).resolve())]
|