diff --git a/gui/__main__.py b/gui/__main__.py index 068bf41..1b39ac9 100755 --- a/gui/__main__.py +++ b/gui/__main__.py @@ -346,6 +346,12 @@ class CustomWindow(QMainWindow): self.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground) self.setWindowTitle('HydraVeil') + + screen = QApplication.primaryScreen() + size = screen.size() + self.host_screen_width = size.width() + self.host_screen_height = size.height() + self._data = {"Profile_1": {}} self.gui_config_home = os.path.join(Constants.HV_CONFIG_HOME, 'gui') @@ -403,12 +409,14 @@ class CustomWindow(QMainWindow): connection_observer.subscribe('connecting', lambda event: self.update_status( f'[{event.subject.get("attempt_count")}/{event.subject.get("maximum_number_of_attempts")}] Performing connection attempt...')) - connection_observer.subscribe('tor_bootstrapping', lambda event: self.update_status('Establishing Tor connection...')) + connection_observer.subscribe('tor_bootstrapping', lambda event: self.update_status( + 'Establishing Tor connection...')) connection_observer.subscribe('tor_bootstrap_progressing', lambda event: self.update_status( f'Bootstrapping Tor {event.meta.get('progress'):.2f}%')) - connection_observer.subscribe('tor_bootstrapped', lambda event: self.update_status('Tor connection established.')) + connection_observer.subscribe( + 'tor_bootstrapped', lambda event: self.update_status('Tor connection established.')) self.setFixedSize(800, 570) self.central_widget = QWidget(self) @@ -4214,6 +4222,14 @@ class ScreenPage(Page): self.button_back.setVisible(True) self.title.setGeometry(585, 40, 200, 40) self.title.setText("Pick a Resolution") + self.host_screen_info = QLabel( + f"Host: {self.custom_window.host_screen_width}x{self.custom_window.host_screen_height}", self) + self.host_screen_info.setGeometry(QtCore.QRect(355, 30, 200, 30)) + self.host_screen_info.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.host_screen_info.setStyleSheet( + "color: #00ffff; font-size: 14px; font-weight: bold;") + self.host_screen_info.show() + self.display.setGeometry(QtCore.QRect(5, 50, 580, 435)) self.showing_larger_resolutions = False self.larger_resolution_buttons = [] @@ -4222,13 +4238,20 @@ class ScreenPage(Page): def create_interface_elements(self): self.buttonGroup = QButtonGroup(self) self.buttons = [] - for j, (object_type, icon_name, geometry) in enumerate([ - (QPushButton, "800x600", (595, 90, 180, 70)), - (QPushButton, "1024x760", (595, 170, 180, 70)), - (QPushButton, "1152x1080", (595, 250, 180, 70)), - (QPushButton, "1280x1024", (595, 330, 180, 70)), - (QPushButton, "1920x1080", (595, 410, 180, 70)) - ]): + resolutions = [ + ("800x600", (595, 90, 180, 70)), + ("1024x760", (595, 170, 180, 70)), + ("1152x1080", (595, 250, 180, 70)), + ("1280x1024", (595, 330, 180, 70)), + ("1920x1080", (595, 410, 180, 70)) + ] + valid_resolutions = [] + for res, geom in resolutions: + w, h = map(int, res.split('x')) + if w < self.custom_window.host_screen_width and h < self.custom_window.host_screen_height: + valid_resolutions.append((QPushButton, res, geom)) + + for j, (object_type, icon_name, geometry) in enumerate(valid_resolutions): boton = object_type(self) boton.setGeometry(*geometry) boton.setIconSize(boton.size()) @@ -4301,7 +4324,7 @@ class ScreenPage(Page): self.larger_resolutions_button.setIcon( QIcon(self.create_resolution_button_image("Standard Resolutions"))) - larger_resolutions = [ + larger_resolutions_list = [ ("2560x1600", (595, 90, 180, 70)), ("2560x1440", (595, 170, 180, 70)), ("1920x1440", (595, 250, 180, 70)), @@ -4309,7 +4332,13 @@ class ScreenPage(Page): ("2048x1152", (595, 410, 180, 70)) ] - for i, (resolution, geometry) in enumerate(larger_resolutions): + valid_larger = [] + for res, geom in larger_resolutions_list: + w, h = map(int, res.split('x')) + if w < self.custom_window.host_screen_width and h < self.custom_window.host_screen_height: + valid_larger.append((res, geom)) + + for i, (resolution, geometry) in enumerate(valid_larger): button = QPushButton(self) button.setGeometry(*geometry) button.setIconSize(button.size()) @@ -7562,6 +7591,26 @@ class Settings(Page): self.enable_fast_registration.setStyleSheet(self.get_checkbox_style()) registrations_layout.addWidget(self.enable_fast_registration) + self.dynamic_profiles_container = QWidget() + dynamic_layout = QVBoxLayout(self.dynamic_profiles_container) + dynamic_layout.setContentsMargins(20, 0, 0, 0) + + self.enable_dynamic_profiles = QCheckBox( + "Enable Dynamic Larger Profiles") + self.enable_dynamic_profiles.setStyleSheet(self.get_checkbox_style()) + dynamic_layout.addWidget(self.enable_dynamic_profiles) + + dynamic_desc = QLabel("This is for fast mode profile creation. Some users may wish to have screen sizes that are nearly as large as their host, but slightly smaller by differing amounts. This fools fingerprinters but still gives larger sizes. So for example if your host is 1200 x 800, then fast mode would offer 1150 x 750, 1100 x 700, 1050 x 650, etc.") + dynamic_desc.setWordWrap(True) + dynamic_desc.setStyleSheet( + f"color: #888888; font-size: 11px; font-style: italic; {self.font_style}") + dynamic_layout.addWidget(dynamic_desc) + + registrations_layout.addWidget(self.dynamic_profiles_container) + + self.enable_fast_registration.toggled.connect( + lambda checked: self.dynamic_profiles_container.setVisible(checked)) + layout.addWidget(registrations_group) save_button = QPushButton() @@ -7780,19 +7829,28 @@ class Settings(Page): auto_sync = registrations.get("auto_sync_enabled", False) fast_reg = registrations.get( "fast_registration_enabled", False) - if "auto_sync_enabled" not in registrations or "fast_registration_enabled" not in registrations: + dynamic_profiles = registrations.get( + "dynamic_larger_profiles", False) + if "auto_sync_enabled" not in registrations or "fast_registration_enabled" not in registrations or "dynamic_larger_profiles" not in registrations: registrations["auto_sync_enabled"] = auto_sync registrations["fast_registration_enabled"] = fast_reg + registrations["dynamic_larger_profiles"] = dynamic_profiles self.update_status._save_gui_config(config) self.enable_auto_sync.setChecked(auto_sync) self.enable_fast_registration.setChecked(fast_reg) + self.enable_dynamic_profiles.setChecked(dynamic_profiles) + self.dynamic_profiles_container.setVisible(fast_reg) else: self.enable_auto_sync.setChecked(False) self.enable_fast_registration.setChecked(False) + self.enable_dynamic_profiles.setChecked(False) + self.dynamic_profiles_container.setVisible(False) except Exception as e: logging.error(f"Error loading registration settings: {str(e)}") self.enable_auto_sync.setChecked(False) self.enable_fast_registration.setChecked(False) + self.enable_dynamic_profiles.setChecked(False) + self.dynamic_profiles_container.setVisible(False) def save_registrations_settings(self) -> None: try: @@ -7814,6 +7872,7 @@ class Settings(Page): config["registrations"]["auto_sync_enabled"] = self.enable_auto_sync.isChecked() config["registrations"]["fast_registration_enabled"] = self.enable_fast_registration.isChecked() + config["registrations"]["dynamic_larger_profiles"] = self.enable_dynamic_profiles.isChecked() self.update_status._save_gui_config(config) self.update_status.update_status("Registration settings saved") @@ -9567,6 +9626,7 @@ class FastRegistrationPage(Page): 'browser': '', 'resolution': '1024x760' } + self.res_index = 1 self.initialize_default_selections() @@ -9614,11 +9674,21 @@ class FastRegistrationPage(Page): else: self.name_hint.hide() + self.host_info_label = QLabel( + f"Host Screen: {self.update_status.host_screen_width}x{self.update_status.host_screen_height}", self) + self.host_info_label.setGeometry(415, 470, 250, 20) + self.host_info_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.host_info_label.setStyleSheet( + "color: #00ffff; font-size: 13px; font-weight: bold;") + self.host_info_label.show() + self.labels.append(self.host_info_label) + self.create_protocol_section() self.create_connection_section() self.create_location_section() - self.create_browser_section() - self.create_resolution_section() + if self.selected_values['connection'] != 'system-wide': + self.create_browser_section() + self.create_resolution_section() self.update_ui_state_for_connection() def create_protocol_section(self): @@ -9869,6 +9939,107 @@ class FastRegistrationPage(Page): next_button.setIconSize(next_button.size()) self.buttons.append(next_button) + custom_button = QPushButton("Custom", self) + custom_button.setGeometry(435, 430, 185, 30) + custom_button.setStyleSheet(""" + QPushButton { + background-color: rgba(0, 255, 255, 0.1); + color: #00ffff; + border: 1px solid #00ffff; + border-radius: 5px; + font-size: 12px; + font-weight: bold; + } + QPushButton:hover { + background-color: rgba(0, 255, 255, 0.2); + } + """) + custom_button.clicked.connect(self.show_custom_res_dialog) + custom_button.show() + self.buttons.append(custom_button) + + def show_custom_res_dialog(self): + dialog = QDialog(self) + dialog.setWindowTitle("Custom Resolution") + dialog.setFixedSize(300, 150) + dialog.setModal(True) + dialog.setStyleSheet(""" + QDialog { + background-color: #2c3e50; + border: 2px solid #00ffff; + border-radius: 10px; + } + QLabel { + color: white; + font-size: 12px; + } + QLineEdit { + background-color: #34495e; + color: white; + border: 1px solid #00ffff; + border-radius: 5px; + padding: 5px; + font-size: 12px; + } + QPushButton { + background-color: #2c3e50; + color: white; + border: 2px solid #00ffff; + border-radius: 5px; + padding: 8px; + font-size: 12px; + } + QPushButton:hover { + background-color: #34495e; + } + """) + + layout = QVBoxLayout() + input_layout = QHBoxLayout() + width_label = QLabel("Width:") + width_input = QLineEdit() + width_input.setPlaceholderText("1920") + height_label = QLabel("Height:") + height_input = QLineEdit() + height_input.setPlaceholderText("1080") + + input_layout.addWidget(width_label) + input_layout.addWidget(width_input) + input_layout.addWidget(height_label) + input_layout.addWidget(height_input) + + button_layout = QHBoxLayout() + ok_button = QPushButton("OK") + cancel_button = QPushButton("Cancel") + button_layout.addWidget(ok_button) + button_layout.addWidget(cancel_button) + + layout.addLayout(input_layout) + layout.addLayout(button_layout) + dialog.setLayout(layout) + + def validate_and_accept(): + try: + width = int(width_input.text()) + height = int(height_input.text()) + if width <= 0 or height <= 0: + return + host_w = self.update_status.host_screen_width + host_h = self.update_status.host_screen_height + if width > host_w: + width = host_w - 50 + if height > host_h: + height = host_h - 50 + self.selected_values['resolution'] = f"{width}x{height}" + self.create_interface_elements() + dialog.accept() + except ValueError: + pass + + ok_button.clicked.connect(validate_and_accept) + cancel_button.clicked.connect(dialog.reject) + dialog.exec() + def update_ui_state_for_connection(self): is_system_wide = self.selected_values['connection'] == 'system-wide' @@ -9927,11 +10098,33 @@ class FastRegistrationPage(Page): elif browsers: self.selected_values[key] = browsers[0] elif key == 'resolution': - resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', - '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] - current_index = resolutions.index(self.selected_values[key]) - previous_index = (current_index - 1) % len(resolutions) - self.selected_values[key] = resolutions[previous_index] + config = self.update_status._load_gui_config() + dynamic_enabled = config.get("registrations", {}).get( + "dynamic_larger_profiles", False) if config else False + + if dynamic_enabled: + resolutions = [] + host_w = self.update_status.host_screen_width + host_h = self.update_status.host_screen_height + for i in range(5): + resolutions.append( + f"{host_w - (50 * (i + 1))}x{host_h - (50 * (i + 1))}") + self.res_index = (self.res_index - 1) % len(resolutions) + self.selected_values[key] = resolutions[self.res_index] + else: + resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', + '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] + self.res_index = (self.res_index - 1) % len(resolutions) + choice = resolutions[self.res_index] + w, h = map(int, choice.split('x')) + host_w = self.update_status.host_screen_width + host_h = self.update_status.host_screen_height + new_w, new_h = w, h + if w > host_w: + new_w = host_w - 50 + if h > host_h: + new_h = host_h - 50 + self.selected_values[key] = f"{new_w}x{new_h}" self.create_interface_elements() @@ -9983,11 +10176,33 @@ class FastRegistrationPage(Page): elif browsers: self.selected_values[key] = browsers[0] elif key == 'resolution': - resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', - '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] - current_index = resolutions.index(self.selected_values[key]) - next_index = (current_index + 1) % len(resolutions) - self.selected_values[key] = resolutions[next_index] + config = self.update_status._load_gui_config() + dynamic_enabled = config.get("registrations", {}).get( + "dynamic_larger_profiles", False) if config else False + + if dynamic_enabled: + resolutions = [] + host_w = self.update_status.host_screen_width + host_h = self.update_status.host_screen_height + for i in range(5): + resolutions.append( + f"{host_w - (50 * (i + 1))}x{host_h - (50 * (i + 1))}") + self.res_index = (self.res_index + 1) % len(resolutions) + self.selected_values[key] = resolutions[self.res_index] + else: + resolutions = ['800x600', '1024x760', '1152x1080', '1280x1024', '1920x1080', + '2560x1440', '2560x1600', '1920x1440', '1792x1344', '2048x1152'] + self.res_index = (self.res_index + 1) % len(resolutions) + choice = resolutions[self.res_index] + w, h = map(int, choice.split('x')) + host_w = self.update_status.host_screen_width + host_h = self.update_status.host_screen_height + new_w, new_h = w, h + if w > host_w: + new_w = host_w - 50 + if h > host_h: + new_h = host_h - 50 + self.selected_values[key] = f"{new_w}x{new_h}" self.create_interface_elements()