From 6195983c793c18fec60d57fa0d71aaac2e86218b Mon Sep 17 00:00:00 2001 From: Dariusz Koryto Date: Thu, 11 Jun 2026 00:01:01 +0200 Subject: [PATCH 1/2] refactor: fix critical NameErrors, clean up unused imports/variables, and modernize config - Fix missing 'import subprocess' in wifite/attack/wpa.py (NameError) - Fix missing 'log_error' import in wifite/util/interface_assignment.py (NameError) - Fix missing 'InterfaceManager' import in wifite/util/system_check.py (NameError) - Fix color variables in f-strings in wifite/util/wpa3_tools.py (NameError) - Restore 'import subprocess' in wifite/util/cleanup.py (needed by tests) - Remove dead code/duplicate entry-point from setup.py - Remove deprecated flake8-ignore from setup.cfg - Add psutil to dependencies (pyproject.toml + requirements.txt) - Remove sys.path.insert hacks from 16 test files - Mass cleanup of unused imports (F401), unused variables (F841), and empty f-strings (F541) across wifite/ and tests/ Test results: 617 passed, 7 failed (pre-existing/environment issues) --- pyproject.toml | 1 + requirements.txt | 1 + setup.cfg | 3 - setup.py | 5 +- tests/demo_statistics.py | 5 +- tests/test_Airmon.py | 3 - tests/test_Airodump.py | 3 - tests/test_Handshake.py | 3 - tests/test_Target.py | 1 - tests/test_adaptive_deauth_integration.py | 4 +- tests/test_attack_view_start.py | 3 +- tests/test_channel_synchronization.py | 3 +- tests/test_cleanup.py | 5 +- tests/test_client_monitor.py | 3 - tests/test_config_refactor.py | 1 - tests/test_config_restoration.py | 6 +- tests/test_eviltwin_attack_view.py | 3 +- tests/test_eviltwin_e2e.py | 21 ++--- tests/test_eviltwin_session.py | 5 +- tests/test_eviltwin_unit.py | 9 +- tests/test_exact_output.py | 3 - tests/test_hcxdump_integration.py | 3 +- tests/test_hcxdumptool.py | 3 - tests/test_improvements.py | 11 +-- tests/test_john_crack.py | 7 -- tests/test_keyboard_input.py | 1 - tests/test_large_target_optimization.py | 2 - tests/test_native_implementations.py | 5 -- tests/test_new_utilities.py | 9 +- tests/test_performance_optimizations.py | 4 - tests/test_resume_display.py | 2 - tests/test_resume_tui_display.py | 3 +- tests/test_sae_handshake.py | 6 +- tests/test_selector_manufacturer_display.py | 3 +- tests/test_session_attack_integration.py | 2 - tests/test_session_deletion.py | 2 - tests/test_session_updates.py | 2 - tests/test_session_validation.py | 2 - tests/test_system_check.py | 8 +- tests/test_target_filtering.py | 1 - tests/test_terminal_compatibility.py | 3 +- tests/test_tui_integration.py | 4 +- tests/test_ui_components.py | 1 - tests/test_wpa2_compatibility.py | 5 -- tests/test_wpa3_detection_optimization.py | 1 - tests/test_wpa3_detection_performance.py | 1 - tests/test_wpa3_detector.py | 4 - tests/test_wpa3_integration.py | 7 +- tests/test_wpa3_strategy.py | 4 - tests/test_wpa_capture_routing.py | 3 +- wifite/args.py | 1 - wifite/attack/all.py | 7 +- wifite/attack/attack_monitor.py | 3 - wifite/attack/eviltwin.py | 10 +-- wifite/attack/owe.py | 5 +- wifite/attack/pmkid.py | 13 ++- wifite/attack/pmkid_passive.py | 1 - wifite/attack/portal/__init__.py | 1 - wifite/attack/portal/credential_handler.py | 24 +++--- wifite/attack/portal/server.py | 15 ++-- wifite/attack/portal/templates.py | 10 +-- wifite/attack/wep.py | 7 +- wifite/attack/wpa.py | 23 +++-- wifite/attack/wpa3.py | 14 ++- wifite/attack/wpa3_strategy.py | 15 ++-- wifite/attack/wps.py | 3 +- wifite/config/__init__.py | 9 +- wifite/config/defaults.py | 1 - wifite/config/manufacturers.py | 3 +- wifite/config/parsers/__init__.py | 1 - wifite/config/parsers/attack_monitor.py | 1 - wifite/config/parsers/dual_interface.py | 1 - wifite/config/parsers/eviltwin.py | 1 - wifite/config/parsers/pmkid.py | 1 - wifite/config/parsers/settings.py | 7 +- wifite/config/parsers/wep.py | 1 - wifite/config/parsers/wpa.py | 1 - wifite/config/parsers/wpasec.py | 1 - wifite/config/parsers/wps.py | 1 - wifite/config/validators.py | 1 - wifite/model/attack.py | 1 - wifite/model/client.py | 1 - wifite/model/eviltwin_result.py | 3 +- wifite/model/handshake.py | 1 - wifite/model/ignored_result.py | 3 +- wifite/model/interface_info.py | 14 ++- wifite/model/pmkid_result.py | 5 +- wifite/model/result.py | 8 +- wifite/model/sae_handshake.py | 16 ++-- wifite/model/sae_result.py | 3 +- wifite/model/target.py | 3 +- wifite/model/wep_result.py | 3 +- wifite/model/wpa_result.py | 5 +- wifite/model/wps_result.py | 3 +- wifite/native/__init__.py | 3 - wifite/native/beacon.py | 6 +- wifite/native/deauth.py | 28 +++--- wifite/native/handshake.py | 16 ++-- wifite/native/interface.py | 84 +++++++++--------- wifite/native/mac.py | 41 ++++----- wifite/native/pmkid.py | 49 +++++------ wifite/native/scanner.py | 39 ++++----- wifite/native/wps.py | 17 ++-- wifite/tools/aircrack.py | 5 +- wifite/tools/aireplay.py | 3 +- wifite/tools/airmon.py | 11 ++- wifite/tools/airodump.py | 4 +- wifite/tools/bully.py | 3 +- wifite/tools/cowpatty.py | 1 - wifite/tools/dependency.py | 2 - wifite/tools/dnsmasq.py | 12 ++- wifite/tools/hashcat.py | 9 +- wifite/tools/hcxdumptool.py | 1 - wifite/tools/hostapd.py | 2 - wifite/tools/ip.py | 1 - wifite/tools/iw.py | 1 - wifite/tools/john.py | 1 - wifite/tools/macchanger.py | 6 +- wifite/tools/reaver.py | 6 +- wifite/tools/tshark.py | 7 +- wifite/tools/wash.py | 1 - wifite/tools/wlancap2wpasec.py | 2 - wifite/ui/__init__.py | 1 - wifite/ui/attack_view.py | 16 ++-- wifite/ui/classic.py | 3 +- wifite/ui/components.py | 14 ++- wifite/ui/scanner_view.py | 25 +++--- wifite/ui/selector_view.py | 12 ++- wifite/ui/tui.py | 4 +- wifite/util/adaptive_deauth.py | 4 +- wifite/util/cleanup.py | 12 ++- wifite/util/client_monitor.py | 46 +++++----- wifite/util/color.py | 3 +- wifite/util/crack.py | 5 +- wifite/util/credential_validator.py | 11 +-- wifite/util/dragonblood.py | 18 ++-- wifite/util/dragonblood_scanner.py | 1 - wifite/util/dragonblood_timing.py | 36 ++++---- wifite/util/honeypot_detector.py | 1 - wifite/util/input.py | 6 +- wifite/util/interface_assignment.py | 22 +++-- wifite/util/interface_exceptions.py | 3 +- wifite/util/interface_manager.py | 53 ++++++------ wifite/util/logger.py | 21 ++--- wifite/util/memory.py | 17 ++-- wifite/util/output.py | 3 +- wifite/util/owe.py | 16 ++-- wifite/util/owe_scanner.py | 1 - wifite/util/pmkid_monitor.py | 1 - wifite/util/process.py | 8 +- wifite/util/retry.py | 19 ++-- wifite/util/sae_crack.py | 45 +++++----- wifite/util/scanner.py | 11 +-- wifite/util/session.py | 96 ++++++++++----------- wifite/util/signal_tracker.py | 32 ++++--- wifite/util/system_check.py | 57 ++++++------ wifite/util/timer.py | 1 - wifite/util/tui_logger.py | 2 - wifite/util/wpa3.py | 29 +++---- wifite/util/wpa3_tools.py | 16 ++-- wifite/util/wpasec_uploader.py | 5 +- wifite/wifite.py | 13 ++- 162 files changed, 595 insertions(+), 906 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c18c94a8d..b7900c373 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ classifiers = [ ] dependencies = [ "chardet>=7.4.3", + "psutil>=7.0.0", "requests>=2.34.2", "rich>=15.0.0", "scapy>=2.7.1rc1; python_version < '4'", diff --git a/requirements.txt b/requirements.txt index 560dd4d84..ddde0cb14 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ # Core dependencies for wifite2 # These should match pyproject.toml [project.dependencies] chardet>=7.4.3 +psutil>=7.0.0 requests>=2.34.2 rich>=15.0.0 scapy>=2.7.1rc1; python_version < '4' diff --git a/setup.cfg b/setup.cfg index bd65b747e..ed3bf6e5d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,2 @@ [install] install_scripts=/usr/sbin - -[tool:pytest] -flake8-ignore = E201 E231 diff --git a/setup.py b/setup.py index 90b11e5bb..2e052aca5 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,6 @@ except ImportError: raise ImportError("setuptools is required to install wifite2") -from wifite.config import Configuration - with open('README.md', 'r', encoding='utf-8') as fh: long_description = fh.read() @@ -29,7 +27,7 @@ def _read_requirements(): setup( name='wifite2', - version=Configuration.version, + version='2.9.9-beta', author='kimocoder', author_email='christian@aircrack-ng.org', url='https://github.com/kimocoder/wifite2', @@ -38,7 +36,6 @@ def _read_requirements(): '': ['wordlists/*.txt'] }, license='GNU GPLv2', - scripts=['bin/wifite'], python_requires='>=3.10', install_requires=_read_requirements(), # Dev/test extras are defined once in pyproject.toml diff --git a/tests/demo_statistics.py b/tests/demo_statistics.py index 5f6090045..2443b2bbb 100644 --- a/tests/demo_statistics.py +++ b/tests/demo_statistics.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Demonstration of client monitoring and statistics tracking. @@ -31,7 +30,7 @@ def demo_client_connection(): client.credential_submitted = True client.credential_valid = True - print(f"\nAfter credential submission:") + print("\nAfter credential submission:") print(f" Credentials submitted: {client.credential_submitted}") print(f" Credentials valid: {client.credential_valid}") print(f" Connection duration: {client.connection_duration():.2f}s") @@ -59,7 +58,7 @@ def demo_attack_statistics(): # Second client connects time.sleep(0.3) stats.record_client_connect("11:22:33:44:55:66") - print(f" Client 2 connected") + print(" Client 2 connected") # First client submits wrong password time.sleep(0.5) diff --git a/tests/test_Airmon.py b/tests/test_Airmon.py index 97734c41d..01daad2a2 100644 --- a/tests/test_Airmon.py +++ b/tests/test_Airmon.py @@ -1,10 +1,7 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -import sys import unittest from wifite.tools.airmon import Airmon -sys.path.insert(0, '..') class TestAirmon(unittest.TestCase): diff --git a/tests/test_Airodump.py b/tests/test_Airodump.py index cc1f29615..eb4f03c64 100644 --- a/tests/test_Airodump.py +++ b/tests/test_Airodump.py @@ -1,11 +1,8 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -import sys from wifite.tools.airodump import Airodump import unittest -sys.path.insert(0, '..') class TestAirodump(unittest.TestCase): diff --git a/tests/test_Handshake.py b/tests/test_Handshake.py index 99d891c5d..13de54a3c 100644 --- a/tests/test_Handshake.py +++ b/tests/test_Handshake.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -import sys import unittest import pytest @@ -9,7 +7,6 @@ from wifite.model.handshake import Handshake from wifite.util.process import Process -sys.path.insert(0, '..') pytestmark = pytest.mark.timeout(30) diff --git a/tests/test_Target.py b/tests/test_Target.py index 14ecc65e3..708f3e6be 100644 --- a/tests/test_Target.py +++ b/tests/test_Target.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import unittest from wifite.tools.airodump import Airodump diff --git a/tests/test_adaptive_deauth_integration.py b/tests/test_adaptive_deauth_integration.py index 298a209c3..47f653311 100644 --- a/tests/test_adaptive_deauth_integration.py +++ b/tests/test_adaptive_deauth_integration.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Integration tests for adaptive deauth in Evil Twin attack. @@ -9,8 +8,7 @@ """ import unittest -import time -from unittest.mock import Mock, MagicMock, patch, call +from unittest.mock import Mock, patch class TestAdaptiveDeauthIntegration(unittest.TestCase): diff --git a/tests/test_attack_view_start.py b/tests/test_attack_view_start.py index 72a5fca4a..460c58d04 100644 --- a/tests/test_attack_view_start.py +++ b/tests/test_attack_view_start.py @@ -1,12 +1,11 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests to verify attack views start properly and don't conflict with scanner view. """ import unittest -from unittest.mock import Mock, MagicMock, patch +from unittest.mock import Mock class MockTarget: diff --git a/tests/test_channel_synchronization.py b/tests/test_channel_synchronization.py index 2ec17eebe..47210d4d5 100644 --- a/tests/test_channel_synchronization.py +++ b/tests/test_channel_synchronization.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for channel synchronization in dual interface WPA attacks. @@ -12,7 +11,7 @@ import unittest import sys -from unittest.mock import Mock, patch, MagicMock, call +from unittest.mock import Mock, patch, MagicMock # Mock sys.argv to prevent argparse from reading test arguments original_argv = sys.argv diff --git a/tests/test_cleanup.py b/tests/test_cleanup.py index c30f3e981..7e83f8abb 100644 --- a/tests/test_cleanup.py +++ b/tests/test_cleanup.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for cleanup utilities. @@ -8,11 +7,9 @@ import unittest import tempfile import os -from unittest.mock import Mock, patch, MagicMock +from unittest.mock import Mock, patch # Add parent directory to path -import sys -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from wifite.util.cleanup import CleanupManager, kill_orphaned_processes, check_conflicting_processes diff --git a/tests/test_client_monitor.py b/tests/test_client_monitor.py index 4ac3dfcf1..c49ba6ff5 100644 --- a/tests/test_client_monitor.py +++ b/tests/test_client_monitor.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for client monitoring and statistics tracking. @@ -7,8 +6,6 @@ import unittest import time -import tempfile -import os from wifite.util.client_monitor import ClientConnection, ClientMonitor, AttackStatistics diff --git a/tests/test_config_refactor.py b/tests/test_config_refactor.py index ae56a4ebd..5f0966e20 100644 --- a/tests/test_config_refactor.py +++ b/tests/test_config_refactor.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Tests for the refactored config package structure. Verifies that: diff --git a/tests/test_config_restoration.py b/tests/test_config_restoration.py index 448c012af..ed63c1689 100644 --- a/tests/test_config_restoration.py +++ b/tests/test_config_restoration.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for configuration restoration from session. @@ -8,8 +7,7 @@ import unittest import tempfile import shutil -import os -from unittest.mock import Mock, patch, MagicMock +from unittest.mock import Mock, patch from wifite.util.session import SessionManager, SessionState, TargetState @@ -258,7 +256,7 @@ def test_restore_with_missing_config_values(self): ) # Restore configuration - result = self.session_mgr.restore_configuration(session, self.config) + self.session_mgr.restore_configuration(session, self.config) # Original values should be preserved when not in session self.assertEqual(self.config.wordlist, original_wordlist) diff --git a/tests/test_eviltwin_attack_view.py b/tests/test_eviltwin_attack_view.py index ee163e475..d7f035414 100644 --- a/tests/test_eviltwin_attack_view.py +++ b/tests/test_eviltwin_attack_view.py @@ -1,12 +1,11 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for Evil Twin Attack View TUI integration. """ import unittest -from unittest.mock import Mock, MagicMock +from unittest.mock import Mock import time diff --git a/tests/test_eviltwin_e2e.py b/tests/test_eviltwin_e2e.py index e1cbfe230..05d3befe4 100644 --- a/tests/test_eviltwin_e2e.py +++ b/tests/test_eviltwin_e2e.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ End-to-end simulation tests for Evil Twin attack. @@ -12,12 +11,10 @@ """ import unittest -import tempfile -import shutil import os import time import sys -from unittest.mock import Mock, patch, MagicMock +from unittest.mock import Mock, patch # Mock sys.argv to prevent argparse from reading test arguments original_argv = sys.argv @@ -32,7 +29,7 @@ Configuration.eviltwin_template = 'generic' Configuration.eviltwin_deauth_interval = 5 -from wifite.attack.eviltwin import EvilTwin, AttackState +from wifite.attack.eviltwin import EvilTwin from wifite.model.target import Target from wifite.attack.portal.templates import TemplateRenderer from wifite.util.credential_validator import CredentialValidator @@ -265,7 +262,7 @@ def test_standard_alphanumeric_password(self): try: self.assertTrue(os.path.exists(config_file)) - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn('psk="Password123"', content) @@ -289,7 +286,7 @@ def test_special_characters_password(self): try: self.assertTrue(os.path.exists(config_file)) - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn(f'psk="{password}"', content) @@ -312,7 +309,7 @@ def test_unicode_password(self): try: self.assertTrue(os.path.exists(config_file)) - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() # Password should be in config @@ -329,7 +326,7 @@ def test_minimum_length_password(self): try: self.assertTrue(os.path.exists(config_file)) - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn('psk="12345678"', content) @@ -345,7 +342,7 @@ def test_maximum_length_password(self): try: self.assertTrue(os.path.exists(config_file)) - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn(f'psk="{password}"', content) @@ -361,7 +358,7 @@ def test_spaces_in_password(self): try: self.assertTrue(os.path.exists(config_file)) - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn('psk="My Password 123"', content) @@ -377,7 +374,7 @@ def test_quotes_in_password(self): try: self.assertTrue(os.path.exists(config_file)) - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() # Password should be in config (may be escaped) diff --git a/tests/test_eviltwin_session.py b/tests/test_eviltwin_session.py index 57d914273..7db826936 100644 --- a/tests/test_eviltwin_session.py +++ b/tests/test_eviltwin_session.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for Evil Twin session management integration. @@ -9,12 +8,10 @@ import tempfile import shutil import os -from unittest.mock import Mock, MagicMock +from unittest.mock import Mock from wifite.util.session import ( SessionManager, - SessionState, - TargetState, EvilTwinAttackState, EvilTwinClientState, EvilTwinCredentialAttempt diff --git a/tests/test_eviltwin_unit.py b/tests/test_eviltwin_unit.py index 586c0032c..855eaa858 100644 --- a/tests/test_eviltwin_unit.py +++ b/tests/test_eviltwin_unit.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for Evil Twin attack components. @@ -9,8 +8,6 @@ import unittest import os -import tempfile -from unittest.mock import Mock, patch, MagicMock import pytest @@ -107,7 +104,7 @@ def test_hostapd_config_file_creation(self): self.assertTrue(os.path.exists(config_file)) # Check file content - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn('interface=wlan0', content) @@ -177,7 +174,7 @@ def test_dnsmasq_config_file_creation(self): self.assertTrue(os.path.exists(dnsmasq.lease_file)) # Check config content - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn('interface=wlan0', content) @@ -340,7 +337,7 @@ def test_wpa_config_generation(self): self.assertTrue(os.path.exists(config_file)) # Check content - with open(config_file, 'r') as f: + with open(config_file) as f: content = f.read() self.assertIn('ssid="TestNetwork"', content) diff --git a/tests/test_exact_output.py b/tests/test_exact_output.py index 5ab87f452..4878ccbf3 100644 --- a/tests/test_exact_output.py +++ b/tests/test_exact_output.py @@ -1,17 +1,14 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ Tests for Airmon._parse_airmon_start() against exact airmon-ng output formats. """ import re -import sys import unittest import pytest -sys.path.insert(0, '..') from wifite.tools.airmon import Airmon diff --git a/tests/test_hcxdump_integration.py b/tests/test_hcxdump_integration.py index 9d0864112..3259fccd7 100644 --- a/tests/test_hcxdump_integration.py +++ b/tests/test_hcxdump_integration.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Integration tests for hcxdumptool-based WPA capture. @@ -13,7 +12,7 @@ import unittest import sys -from unittest.mock import Mock, patch, MagicMock +from unittest.mock import Mock, patch import pytest diff --git a/tests/test_hcxdumptool.py b/tests/test_hcxdumptool.py index 9a050e8ad..93d635d46 100644 --- a/tests/test_hcxdumptool.py +++ b/tests/test_hcxdumptool.py @@ -1,13 +1,10 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -import sys import unittest from unittest.mock import patch, MagicMock import pytest -sys.path.insert(0, '..') from wifite.tools.hcxdumptool import HcxDumpTool, HcxDumpToolPassive from wifite.config import Configuration diff --git a/tests/test_improvements.py b/tests/test_improvements.py index 5455084aa..8087047fe 100644 --- a/tests/test_improvements.py +++ b/tests/test_improvements.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for wifite2 improvements: @@ -14,11 +13,9 @@ import sys import ast import unittest -from unittest.mock import Mock, patch, MagicMock -from dataclasses import dataclass +from unittest.mock import Mock, patch # Add parent directory to path for imports -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) class TestMemoryMonitor(unittest.TestCase): @@ -26,7 +23,7 @@ class TestMemoryMonitor(unittest.TestCase): def test_memory_module_imports(self): """Test that memory module imports correctly.""" - from wifite.util.memory import MemoryMonitor, InfiniteModeMonitor + from wifite.util.memory import MemoryMonitor self.assertTrue(hasattr(MemoryMonitor, 'get_memory_usage_mb')) self.assertTrue(hasattr(MemoryMonitor, 'periodic_check')) self.assertTrue(hasattr(MemoryMonitor, 'force_cleanup')) @@ -159,7 +156,6 @@ def test_native_pmkid_availability_flag(self): def test_native_pmkid_module_import(self): """Test that native PMKID module can be imported.""" try: - from wifite.native.pmkid import ScapyPMKID, PMKIDResult imported = True except ImportError: imported = False @@ -205,7 +201,6 @@ def test_native_scanner_availability_flag(self): def test_native_scanner_module_import(self): """Test that native scanner module can be imported.""" try: - from wifite.native.scanner import NativeScanner, AccessPoint, ChannelHopper imported = True except ImportError: imported = False @@ -283,7 +278,7 @@ def _check_file_syntax(self, filepath): if not os.path.exists(filepath): return True # Skip if file doesn't exist - with open(filepath, 'r') as f: + with open(filepath) as f: source = f.read() try: diff --git a/tests/test_john_crack.py b/tests/test_john_crack.py index 00b92b205..3ea65b64b 100644 --- a/tests/test_john_crack.py +++ b/tests/test_john_crack.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ End-to-end tests for the --crack feature with john. @@ -20,11 +19,9 @@ import subprocess import tempfile import threading -import time import unittest # ── project root on path ────────────────────────────────────────────────────── -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) TESTS_DIR = os.path.dirname(__file__) FILES_DIR = os.path.join(TESTS_DIR, 'files') @@ -122,7 +119,6 @@ class TestGetFormat(unittest.TestCase): def setUp(self): # Minimal Configuration stub so imports don't fail - import types self._cfg_mod = sys.modules.get('wifite.config') def test_get_format_returns_string(self): @@ -297,7 +293,6 @@ def test_get_result_parses_cracked_line(self): ESSID:PLAINTEXT_PASSWORD:client_mac:ap_mac:...:capfile → parts[1] is the password. """ - from wifite.tools.john import JohnCracker import unittest.mock as mock # john --show output: hash has been replaced by plaintext in field [1] @@ -319,7 +314,6 @@ def test_get_result_parses_cracked_line(self): f'Expected "secretpassword", got {result!r}') def test_get_result_returns_none_on_no_crack(self): - from wifite.tools.john import JohnCracker import unittest.mock as mock jc = self._make_cracker() @@ -423,7 +417,6 @@ def test_john_has_wpapsk_capability_check(self): def test_crack_helper_excludes_john_when_not_wpapsk_capable(self): """When john lacks wpapsk, CrackHelper must NOT list it as available.""" - import unittest.mock as mock from wifite.tools.john import John if John.is_wpapsk_capable(): diff --git a/tests/test_keyboard_input.py b/tests/test_keyboard_input.py index d7702cb3b..0f0346af2 100644 --- a/tests/test_keyboard_input.py +++ b/tests/test_keyboard_input.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for wifite2 TUI keyboard input handling. diff --git a/tests/test_large_target_optimization.py b/tests/test_large_target_optimization.py index 22ab2d774..46a3e8634 100644 --- a/tests/test_large_target_optimization.py +++ b/tests/test_large_target_optimization.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for large target list optimization. @@ -7,7 +6,6 @@ """ import unittest -from unittest.mock import Mock class MockTarget: diff --git a/tests/test_native_implementations.py b/tests/test_native_implementations.py index 9714e805d..826b60e04 100644 --- a/tests/test_native_implementations.py +++ b/tests/test_native_implementations.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for native Python implementations. @@ -12,12 +11,9 @@ - NativeInterface: Interface management """ -import os -import sys import pytest # Add parent directory to path for imports -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) class TestNativeMac: @@ -422,7 +418,6 @@ def test_aireplay_native_deauth_check(self): def test_dependency_native_alternative_check(self): """Test dependency native alternative checking.""" - from wifite.tools.dependency import Dependency from wifite.tools.macchanger import Macchanger from wifite.tools.tshark import Tshark diff --git a/tests/test_new_utilities.py b/tests/test_new_utilities.py index 61dd7e5b5..74e220aa5 100644 --- a/tests/test_new_utilities.py +++ b/tests/test_new_utilities.py @@ -1,16 +1,13 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for signal tracker and retry utilities. """ import sys -import os import time # Add parent directory to path for imports -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) class TestSignalTracker: @@ -19,8 +16,7 @@ class TestSignalTracker: def test_import(self): """Test that signal_tracker module can be imported.""" from wifite.util.signal_tracker import ( - SignalSample, SignalHistory, SignalTracker, - get_signal_tracker, reset_signal_tracker + SignalSample, SignalHistory, SignalTracker ) assert SignalSample is not None assert SignalHistory is not None @@ -158,8 +154,7 @@ class TestRetryUtilities: def test_import(self): """Test that retry module can be imported.""" from wifite.util.retry import ( - RetryExhausted, exponential_backoff, linear_backoff, - constant_delay, RetryConfig, retry_with_backoff, RetryContext + RetryExhausted, exponential_backoff ) assert RetryExhausted is not None assert exponential_backoff is not None diff --git a/tests/test_performance_optimizations.py b/tests/test_performance_optimizations.py index 7bddf9938..84242b07b 100644 --- a/tests/test_performance_optimizations.py +++ b/tests/test_performance_optimizations.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for Evil Twin performance optimizations (task 13.3). @@ -9,9 +8,6 @@ import unittest import time -import tempfile -import os -from unittest.mock import Mock, patch, MagicMock class TestPortalCaching(unittest.TestCase): diff --git a/tests/test_resume_display.py b/tests/test_resume_display.py index c26b09895..0086bbc82 100644 --- a/tests/test_resume_display.py +++ b/tests/test_resume_display.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for resume information display. @@ -8,7 +7,6 @@ import unittest import tempfile import shutil -from unittest.mock import Mock, patch, call from wifite.util.session import SessionManager, SessionState, TargetState diff --git a/tests/test_resume_tui_display.py b/tests/test_resume_tui_display.py index 230e68940..9485b45de 100644 --- a/tests/test_resume_tui_display.py +++ b/tests/test_resume_tui_display.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for TUI resume display functionality. @@ -8,7 +7,7 @@ import unittest import time -from unittest.mock import Mock, MagicMock, patch +from unittest.mock import Mock from wifite.ui.scanner_view import ScannerView from wifite.ui.attack_view import AttackView, WPAAttackView, WPSAttackView from wifite.util.session import SessionState, TargetState diff --git a/tests/test_sae_handshake.py b/tests/test_sae_handshake.py index e8d124639..ef51fdbf8 100644 --- a/tests/test_sae_handshake.py +++ b/tests/test_sae_handshake.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for SAEHandshake class. @@ -8,18 +7,15 @@ """ import unittest -from unittest.mock import Mock, patch, MagicMock -import sys +from unittest.mock import Mock, patch import os import tempfile import pytest # Add parent directory to path -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from wifite.model.sae_handshake import SAEHandshake -from wifite.util.process import Process pytestmark = pytest.mark.timeout(30) diff --git a/tests/test_selector_manufacturer_display.py b/tests/test_selector_manufacturer_display.py index 3e53fc644..aba1109e5 100644 --- a/tests/test_selector_manufacturer_display.py +++ b/tests/test_selector_manufacturer_display.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Test for manufacturer display in selector view. @@ -9,7 +8,7 @@ """ import unittest -from unittest.mock import Mock, MagicMock, patch +from unittest.mock import Mock, patch class TestSelectorManufacturerDisplay(unittest.TestCase): diff --git a/tests/test_session_attack_integration.py b/tests/test_session_attack_integration.py index aa478d133..735aefb33 100644 --- a/tests/test_session_attack_integration.py +++ b/tests/test_session_attack_integration.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Integration tests for session updates during attack execution. @@ -9,7 +8,6 @@ import tempfile import os import shutil -from unittest.mock import Mock, MagicMock, patch class TestSessionAttackIntegration(unittest.TestCase): diff --git a/tests/test_session_deletion.py b/tests/test_session_deletion.py index ccff55b72..a6fbee40e 100644 --- a/tests/test_session_deletion.py +++ b/tests/test_session_deletion.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for session deletion on successful completion. @@ -9,7 +8,6 @@ import tempfile import os import shutil -from unittest.mock import Mock, MagicMock, patch class TestSessionDeletion(unittest.TestCase): diff --git a/tests/test_session_updates.py b/tests/test_session_updates.py index 4721fb6bf..5ad877863 100644 --- a/tests/test_session_updates.py +++ b/tests/test_session_updates.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for session update functionality during attack execution. @@ -9,7 +8,6 @@ import tempfile import os import shutil -from unittest.mock import Mock, MagicMock, patch class TestSessionUpdates(unittest.TestCase): diff --git a/tests/test_session_validation.py b/tests/test_session_validation.py index fe544434a..92c5c2470 100644 --- a/tests/test_session_validation.py +++ b/tests/test_session_validation.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for session loading and validation logic. @@ -10,7 +9,6 @@ import os import shutil import json -from unittest.mock import Mock, MagicMock, patch class TestSessionValidation(unittest.TestCase): diff --git a/tests/test_system_check.py b/tests/test_system_check.py index e2f59b0f6..bfe5176b1 100644 --- a/tests/test_system_check.py +++ b/tests/test_system_check.py @@ -1,15 +1,11 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Tests for the comprehensive --syscheck system check module.""" -import os -import sys import unittest -from unittest.mock import patch, MagicMock, PropertyMock +from unittest.mock import patch, MagicMock # Ensure project root is on path -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) from wifite.util.system_check import ( SystemCheck, CheckStatus, CheckResult, InterfaceCheckResult, @@ -182,7 +178,7 @@ def test_all_categories_present(self, mock_run, mock_which): mock_run.return_value = MagicMock(stdout='1.0.0', stderr='', returncode=0) results = self.checker.check_tools() - categories = set(t.category for t in results) + categories = {t.category for t in results} # Should have at least core, wps, cracking, wpa3, eviltwin self.assertIn('core', categories) self.assertIn('wps', categories) diff --git a/tests/test_target_filtering.py b/tests/test_target_filtering.py index 974c7a2d9..7317acce5 100644 --- a/tests/test_target_filtering.py +++ b/tests/test_target_filtering.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for target filtering during resume. diff --git a/tests/test_terminal_compatibility.py b/tests/test_terminal_compatibility.py index 68bb14590..4981b8413 100644 --- a/tests/test_terminal_compatibility.py +++ b/tests/test_terminal_compatibility.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Terminal compatibility tests for wifite2 TUI. @@ -8,7 +7,7 @@ import unittest import os -from unittest.mock import Mock, patch, MagicMock +from unittest.mock import Mock, patch class TestTerminalSizeHandling(unittest.TestCase): diff --git a/tests/test_tui_integration.py b/tests/test_tui_integration.py index f2f87985b..6a38b8d8a 100644 --- a/tests/test_tui_integration.py +++ b/tests/test_tui_integration.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Integration tests for wifite2 TUI views. @@ -7,8 +6,7 @@ """ import unittest -from unittest.mock import Mock, MagicMock, patch -import time +from unittest.mock import Mock class MockTarget: diff --git a/tests/test_ui_components.py b/tests/test_ui_components.py index ad755aaea..3f324219a 100644 --- a/tests/test_ui_components.py +++ b/tests/test_ui_components.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for wifite2 TUI UI components. diff --git a/tests/test_wpa2_compatibility.py b/tests/test_wpa2_compatibility.py index 3419f8fdd..0cc1f783d 100644 --- a/tests/test_wpa2_compatibility.py +++ b/tests/test_wpa2_compatibility.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Test WPA2 backward compatibility after WPA3 implementation. @@ -8,14 +7,10 @@ """ import unittest -from unittest.mock import Mock, patch, MagicMock -import sys -import os import pytest # Add parent directory to path -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from wifite.model.target import Target diff --git a/tests/test_wpa3_detection_optimization.py b/tests/test_wpa3_detection_optimization.py index 468a80598..1f56fcc14 100644 --- a/tests/test_wpa3_detection_optimization.py +++ b/tests/test_wpa3_detection_optimization.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tests for WPA3 detection optimization features. diff --git a/tests/test_wpa3_detection_performance.py b/tests/test_wpa3_detection_performance.py index 0e90437f4..54cb7318b 100644 --- a/tests/test_wpa3_detection_performance.py +++ b/tests/test_wpa3_detection_performance.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Performance benchmark for WPA3 detection optimization. diff --git a/tests/test_wpa3_detector.py b/tests/test_wpa3_detector.py index a14a59876..4ad166320 100644 --- a/tests/test_wpa3_detector.py +++ b/tests/test_wpa3_detector.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for WPA3Detector class. @@ -10,11 +9,8 @@ import unittest from unittest.mock import Mock -import sys -import os # Add parent directory to path -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from wifite.util.wpa3 import WPA3Detector, WPA3Info diff --git a/tests/test_wpa3_integration.py b/tests/test_wpa3_integration.py index 9edcc832d..14251565d 100644 --- a/tests/test_wpa3_integration.py +++ b/tests/test_wpa3_integration.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Integration tests for WPA3-SAE attack flows. @@ -9,16 +8,14 @@ """ import unittest -from unittest.mock import Mock, patch, MagicMock, call -import sys +from unittest.mock import Mock import os import pytest # Add parent directory to path -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from wifite.util.wpa3 import WPA3Detector, WPA3Info +from wifite.util.wpa3 import WPA3Detector from wifite.attack.wpa3_strategy import WPA3AttackStrategy pytestmark = pytest.mark.timeout(30) diff --git a/tests/test_wpa3_strategy.py b/tests/test_wpa3_strategy.py index 697524c17..54fc22e3a 100644 --- a/tests/test_wpa3_strategy.py +++ b/tests/test_wpa3_strategy.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for WPA3AttackStrategy class. @@ -9,11 +8,8 @@ import unittest from unittest.mock import Mock -import sys -import os # Add parent directory to path -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from wifite.attack.wpa3_strategy import WPA3AttackStrategy from wifite.util.wpa3 import WPA3Detector diff --git a/tests/test_wpa_capture_routing.py b/tests/test_wpa_capture_routing.py index 696d81129..80f6ac380 100644 --- a/tests/test_wpa_capture_routing.py +++ b/tests/test_wpa_capture_routing.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Unit tests for WPA capture method routing logic. @@ -10,7 +9,7 @@ import unittest import sys -from unittest.mock import Mock, patch, MagicMock +from unittest.mock import Mock, patch import pytest diff --git a/wifite/args.py b/wifite/args.py index 16abfad4f..8cc58267c 100644 --- a/wifite/args.py +++ b/wifite/args.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .util.color import Color diff --git a/wifite/attack/all.py b/wifite/attack/all.py index 29703d5f4..1cdb852dc 100755 --- a/wifite/attack/all.py +++ b/wifite/attack/all.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import subprocess from enum import Enum @@ -12,7 +11,7 @@ from ..config import Configuration from ..model.target import WPSState from ..util.color import Color -from ..util.logger import log_info, log_debug +from ..util.logger import log_info from ..util.wpa3_tools import WPA3ToolChecker from ..util.memory import MemoryMonitor, get_infinite_monitor @@ -48,7 +47,7 @@ def attack_multiple(cls, targets, session=None, session_mgr=None): targets_remaining = len(targets) for index, target in enumerate(targets, start=1): if Configuration.attack_max != 0 and index > Configuration.attack_max: - print(("Attacked %d targets, stopping because of the --first flag" % Configuration.attack_max)) + print("Attacked %d targets, stopping because of the --first flag" % Configuration.attack_max) break attacked_targets += 1 targets_remaining -= 1 @@ -216,7 +215,7 @@ def attack_single(cls, target, targets_remaining, session=None, session_mgr=None if result: attack_successful = True break # Attack was successful, stop other attacks. - except (OSError, IOError) as e: + except OSError as e: # File system or process errors Color.pl('\r {!} {R}System Error{W}: %s' % str(e)) continue diff --git a/wifite/attack/attack_monitor.py b/wifite/attack/attack_monitor.py index 96e8baa47..97fec36c5 100755 --- a/wifite/attack/attack_monitor.py +++ b/wifite/attack/attack_monitor.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Wireless Attack Monitoring Module @@ -13,9 +12,7 @@ from ..util.color import Color from ..tools.tshark import TsharkMonitor from ..util.process import Process -import os import time -import re # TUI imports (optional) try: diff --git a/wifite/attack/eviltwin.py b/wifite/attack/eviltwin.py index 0bd860829..357144f26 100755 --- a/wifite/attack/eviltwin.py +++ b/wifite/attack/eviltwin.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Evil Twin attack implementation for wifite2. @@ -12,7 +11,6 @@ import re import time import signal -from typing import Optional, List from enum import Enum from ..model.attack import Attack @@ -25,7 +23,6 @@ from ..util.cleanup import CleanupManager from ..util.adaptive_deauth import AdaptiveDeauthManager from ..util.process import Process -from ..tools.aireplay import Aireplay class AttackState(Enum): @@ -251,7 +248,7 @@ def _get_interface_assignment(self): # This is a fallback for when the attack is run directly import contextlib with contextlib.suppress(ImportError, AttributeError): - from ..wifite import Wifite + pass # Note: This is a fallback and may not always work # The preferred approach is to set interface_assignment before calling run() log_debug('EvilTwin', 'No interface assignment available, will use single interface mode') @@ -1472,7 +1469,6 @@ def _send_deauth(self, client_mac: str, count: int = 5): count: Number of deauth packets to send """ try: - from ..tools.aireplay import Aireplay from ..util.process import Process # Verify deauth interface is available @@ -2074,7 +2070,7 @@ def restore_state_from_session(self, state: 'EvilTwinAttackState') -> bool: True if state was restored successfully, False otherwise """ try: - from ..util.session import EvilTwinAttackState + pass # Restore configuration self.interface_ap = state.interface_ap or self.interface_ap @@ -2137,7 +2133,6 @@ def is_attack_running() -> bool: Returns: True if an attack is running, False otherwise """ - import subprocess try: # Check for hostapd processes with wifite config @@ -2168,7 +2163,6 @@ def cleanup_orphaned_processes(self) -> None: other processes that may have been left running from a previous interrupted attack. """ - import subprocess log_info('EvilTwin', 'Checking for orphaned processes') diff --git a/wifite/attack/owe.py b/wifite/attack/owe.py index 0ce53cdb3..ab89fd234 100644 --- a/wifite/attack/owe.py +++ b/wifite/attack/owe.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ OWE (Opportunistic Wireless Encryption) Attack Module @@ -35,7 +34,7 @@ class AttackOWE(Attack): """ def __init__(self, target): - super(AttackOWE, self).__init__(target) + super().__init__(target) self.success = False self.crack_result = None @@ -149,7 +148,7 @@ def _execute_transition_downgrade(self): output_file_prefix='owe_downgrade') as airodump: try: - airodump_target = self.wait_for_target(airodump) + self.wait_for_target(airodump) except Exception as e: Color.pl('{!} {R}Target not found: %s{W}' % str(e)) return False diff --git a/wifite/attack/pmkid.py b/wifite/attack/pmkid.py index 20b61d1f2..1e9377181 100755 --- a/wifite/attack/pmkid.py +++ b/wifite/attack/pmkid.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..model.attack import Attack from ..config import Configuration @@ -20,7 +19,7 @@ # Check for native PMKID availability try: - from ..native.pmkid import ScapyPMKID, PMKIDResult as NativePMKIDResult + from ..native.pmkid import ScapyPMKID NATIVE_PMKID_AVAILABLE = ScapyPMKID.is_available() except BaseException: NATIVE_PMKID_AVAILABLE = False @@ -28,7 +27,7 @@ class AttackPMKID(Attack): def __init__(self, target): - super(AttackPMKID, self).__init__(target) + super().__init__(target) self.crack_result = None self.do_airCRACK = False self.keep_capturing = None @@ -73,7 +72,7 @@ def get_existing_pmkid_file(bssid): try: log_debug('AttackPMKID', f'Checking file: {os.path.basename(pmkid_filename)}') - with open(pmkid_filename, 'r') as pmkid_handle: + with open(pmkid_filename) as pmkid_handle: pmkid_hash = pmkid_handle.read().strip() if Configuration.verbose > 2: @@ -115,7 +114,7 @@ def get_existing_pmkid_file(bssid): Color.pl('{+} {G}Found matching PMKID file: {C}%s{W}' % os.path.basename(pmkid_filename)) return pmkid_filename - except (IOError, OSError) as e: + except OSError as e: log_warning('AttackPMKID', f'Error reading {os.path.basename(pmkid_filename)}: {str(e)}') if Configuration.verbose > 2: Color.pl('{+} {R}ERROR reading {C}%s{W}: %s' % (os.path.basename(pmkid_filename), str(e))) @@ -565,7 +564,7 @@ def crack_pmkid_file(self, pmkid_file): def _handle_pmkid_crack_success(self, key, pmkid_file): # Successfully cracked. if self.view: - self.view.add_log(f"Successfully cracked PMKID!") + self.view.add_log("Successfully cracked PMKID!") self.view.add_log(f"Password: {mask_sensitive(key)}") self.view.update_progress({ 'progress': 1.0, @@ -633,7 +632,7 @@ def capture_pmkid_native(self): def on_pmkid_captured(result): log_info('AttackPMKID', f'Native capture found PMKID: {result.pmkid[:16]}...') if self.view: - self.view.add_log(f'PMKID captured!') + self.view.add_log('PMKID captured!') # Use ScapyPMKID capture result = ScapyPMKID.capture( diff --git a/wifite/attack/pmkid_passive.py b/wifite/attack/pmkid_passive.py index a3cb95794..099975bac 100755 --- a/wifite/attack/pmkid_passive.py +++ b/wifite/attack/pmkid_passive.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Passive PMKID Attack Module diff --git a/wifite/attack/portal/__init__.py b/wifite/attack/portal/__init__.py index a99dfe8e1..1e086261c 100755 --- a/wifite/attack/portal/__init__.py +++ b/wifite/attack/portal/__init__.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Captive portal for Evil Twin attacks. diff --git a/wifite/attack/portal/credential_handler.py b/wifite/attack/portal/credential_handler.py index 7b69b9cc9..38dc26da4 100755 --- a/wifite/attack/portal/credential_handler.py +++ b/wifite/attack/portal/credential_handler.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Credential submission handler for captive portal. @@ -9,10 +8,9 @@ import time import threading -from typing import Optional, Callable, Dict, List, Tuple +from collections.abc import Callable from queue import Queue, Empty, Full from dataclasses import dataclass -from datetime import datetime from ...util.logger import log_info, log_error, log_warning, log_debug @@ -36,7 +34,7 @@ class ValidationResult: submission: CredentialSubmission is_valid: bool validation_time: float - error_message: Optional[str] = None + error_message: str | None = None def __str__(self): status = 'VALID' if self.is_valid else 'INVALID' @@ -108,7 +106,7 @@ def set_submission_callback(self, callback: Callable[[CredentialSubmission], Non self.submission_callback = callback log_debug('CredentialHandler', 'Submission callback set') - def submit_credentials(self, ssid: str, password: str, client_ip: str) -> Tuple[bool, str]: + def submit_credentials(self, ssid: str, password: str, client_ip: str) -> tuple[bool, str]: """ Handle a credential submission. @@ -173,7 +171,7 @@ def submit_credentials(self, ssid: str, password: str, client_ip: str) -> Tuple[ log_error('CredentialHandler', f'Error handling submission: {e}', e) return False, 'An error occurred. Please try again.' - def check_and_record(self, ssid: str, password: str, client_ip: str) -> Tuple[bool, str]: + def check_and_record(self, ssid: str, password: str, client_ip: str) -> tuple[bool, str]: """ Gate a submission inline: validate input format and enforce per-client rate limiting, recording the attempt. @@ -205,7 +203,7 @@ def check_and_record(self, ssid: str, password: str, client_ip: str) -> Tuple[bo self._update_client_attempts(client_ip) return True, 'OK' - def _validate_input(self, ssid: str, password: str) -> Optional[str]: + def _validate_input(self, ssid: str, password: str) -> str | None: """ Validate input format. @@ -266,7 +264,7 @@ def _update_client_attempts(self, client_ip: str): self.client_attempts[client_ip] = self.client_attempts.get(client_ip, 0) + 1 self.client_last_attempt[client_ip] = time.time() - def get_next_submission(self, timeout=1) -> Optional[CredentialSubmission]: + def get_next_submission(self, timeout=1) -> CredentialSubmission | None: """ Get next submission from validation queue. @@ -284,7 +282,7 @@ def get_next_submission(self, timeout=1) -> Optional[CredentialSubmission]: def record_validation_result(self, submission: CredentialSubmission, is_valid: bool, validation_time: float, - error_message: Optional[str] = None): + error_message: str | None = None): """ Record the result of a validation attempt. @@ -325,7 +323,7 @@ def has_valid_credentials(self) -> bool: """ return len(self.valid_credentials) > 0 - def get_valid_credentials(self) -> Optional[Tuple[str, str]]: + def get_valid_credentials(self) -> tuple[str, str] | None: """ Get the first valid credentials found. @@ -336,7 +334,7 @@ def get_valid_credentials(self) -> Optional[Tuple[str, str]]: return self.valid_credentials[0] return None - def get_statistics(self) -> Dict: + def get_statistics(self) -> dict: """ Get handler statistics. @@ -365,7 +363,7 @@ def get_client_attempts(self, client_ip: str) -> int: """ return self.client_attempts.get(client_ip, 0) - def get_all_submissions(self) -> List[CredentialSubmission]: + def get_all_submissions(self) -> list[CredentialSubmission]: """ Get all submissions (pending and completed). @@ -387,7 +385,7 @@ def get_all_submissions(self) -> List[CredentialSubmission]: return submissions - def get_validation_results(self) -> List[ValidationResult]: + def get_validation_results(self) -> list[ValidationResult]: """ Get all validation results. diff --git a/wifite/attack/portal/server.py b/wifite/attack/portal/server.py index 466dd8317..72b79d6c7 100755 --- a/wifite/attack/portal/server.py +++ b/wifite/attack/portal/server.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ HTTP server for captive portal. @@ -10,10 +9,10 @@ import os import threading import time -from http.server import HTTPServer, ThreadingHTTPServer, BaseHTTPRequestHandler +from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler from urllib.parse import parse_qs, urlparse -from typing import Optional, Callable, Dict, Any -import socket +from typing import Any +from collections.abc import Callable from ...util.color import Color from ...util.logger import log_info, log_error, log_warning, log_debug @@ -613,7 +612,7 @@ def validate_portal(self, timeout=3) -> bool: log_warning('Portal', 'Validation failed: HTTP %d, form not found' % response.status) return False - except (ConnectionRefusedError, socket.timeout, OSError) as e: + except (ConnectionRefusedError, TimeoutError, OSError) as e: log_warning('Portal', 'Validation failed: cannot connect to %s:%d (%s)' % ( self.host, self.port, e)) return False @@ -655,7 +654,7 @@ def validate_dns_redirect(target_ip='192.168.100.1', timeout=3) -> bool: log_warning('Portal', 'DNS redirect validation failed - captive portal detection may not trigger') return False - def get_stats(self) -> Dict[str, Any]: + def get_stats(self) -> dict[str, Any]: """ Get server statistics. @@ -821,7 +820,7 @@ def _cache_static_files(self): log_warning('Portal', f'Failed to cache static files: {e}') self._static_cache = {} - def get_cached_template(self, template_name: str) -> Optional[str]: + def get_cached_template(self, template_name: str) -> str | None: """ Get cached template. @@ -833,7 +832,7 @@ def get_cached_template(self, template_name: str) -> Optional[str]: """ return self._template_cache.get(template_name) - def get_cached_static(self, filename: str) -> Optional[tuple]: + def get_cached_static(self, filename: str) -> tuple | None: """ Get cached static file. diff --git a/wifite/attack/portal/templates.py b/wifite/attack/portal/templates.py index 17a58ab5e..36169bfd4 100755 --- a/wifite/attack/portal/templates.py +++ b/wifite/attack/portal/templates.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Template system for captive portal. @@ -9,9 +8,8 @@ import html import os -from typing import Dict, Any, Optional -from ...util.logger import log_info, log_error, log_warning, log_debug +from ...util.logger import log_error, log_debug class TemplateRenderer: @@ -52,7 +50,7 @@ def render_login(self) -> str: template_file = os.path.join(self.templates_dir, f'{self.template_name}_login.html') if os.path.exists(template_file): - with open(template_file, 'r') as f: + with open(template_file) as f: template = f.read() log_debug('TemplateRenderer', f'Loaded template from {template_file}') else: @@ -81,7 +79,7 @@ def render_success(self) -> str: template_file = os.path.join(self.templates_dir, f'{self.template_name}_success.html') if os.path.exists(template_file): - with open(template_file, 'r') as f: + with open(template_file) as f: template = f.read() else: template = self._get_builtin_success_template() @@ -104,7 +102,7 @@ def render_error(self) -> str: template_file = os.path.join(self.templates_dir, f'{self.template_name}_error.html') if os.path.exists(template_file): - with open(template_file, 'r') as f: + with open(template_file) as f: template = f.read() else: template = self._get_builtin_error_template() diff --git a/wifite/attack/wep.py b/wifite/attack/wep.py index 7fe93d391..35bf249a7 100755 --- a/wifite/attack/wep.py +++ b/wifite/attack/wep.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import subprocess import time @@ -12,7 +11,7 @@ from ..tools.airodump import Airodump from ..tools.ip import Ip from ..util.color import Color -from ..util.logger import log_debug, log_info, log_warning +from ..util.logger import log_info from ..util.output import OutputManager @@ -24,7 +23,7 @@ class AttackWEP(Attack): fakeauth_wait = 5 # TODO: Configuration? def __init__(self, target): - super(AttackWEP, self).__init__(target) + super().__init__(target) self.crack_result = None self.success = False @@ -281,7 +280,7 @@ def run(self): self.success = False return self.success - except (OSError, IOError) as e: + except OSError as e: Color.pl('\r {!} {R}File System Error{W}: %s' % str(e)) continue except subprocess.CalledProcessError as e: diff --git a/wifite/attack/wpa.py b/wifite/attack/wpa.py index 06f1cddc7..dc38b6cb9 100755 --- a/wifite/attack/wpa.py +++ b/wifite/attack/wpa.py @@ -1,22 +1,21 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..model.attack import Attack -from ..tools.aircrack import Aircrack -from ..tools.hashcat import Hashcat, HashcatCracker, HcxDumpTool, HcxPcapngTool +from ..tools.hashcat import Hashcat, HashcatCracker, HcxPcapngTool from ..tools.airodump import Airodump from ..tools.aireplay import Aireplay from ..config import Configuration from ..util.color import Color from ..util.timer import Timer from ..util.output import OutputManager -from ..util.logger import log_debug, log_info, log_warning, log_error +from ..util.logger import log_info from ..model.handshake import Handshake from ..model.wpa_result import CrackResultWPA from ..util.wpasec_uploader import WpaSecUploader import time import os import re +import subprocess from shutil import copy from contextlib import contextmanager @@ -28,7 +27,7 @@ class AttackWPA(Attack): RETRY_DELAY_SECONDS = 2 def __init__(self, target): - super(AttackWPA, self).__init__(target) + super().__init__(target) self.clients = [] self.crack_result = None self.success = False @@ -119,7 +118,7 @@ def _attempt_interface_recovery(self): Tries to bring the interface back to a working state. """ from ..tools.airmon import Airmon - from ..util.logger import log_info, log_warning, log_error + from ..util.logger import log_info, log_error log_info('AttackWPA', 'Attempting interface recovery') Color.pl('{!} {O}Attempting interface recovery...{W}') @@ -182,7 +181,6 @@ def _run_with_retry(self, operation, operation_name: str, max_retries: int = Non max_retries = self.MAX_RETRY_ATTEMPTS self._retry_count = 0 - last_exception = None while self._retry_count < max_retries: try: @@ -193,12 +191,11 @@ def _run_with_retry(self, operation, operation_name: str, max_retries: int = Non if self._recovered_from_error and self._retry_count > 0: log_info('AttackWPA', f'{operation_name} succeeded after {self._retry_count} retry(s)') if self.view: - self.view.add_log(f'Operation succeeded after recovery') + self.view.add_log('Operation succeeded after recovery') return result except (OSError, subprocess.CalledProcessError, MemoryError) as e: - last_exception = e self._retry_count += 1 if self._retry_count < max_retries: @@ -715,7 +712,7 @@ def _capture_handshake_dual_airodump(self): max_cap_size = 50 * 1024 * 1024 # 50MB limit if file_size > max_cap_size: Color.pl('\n{!} {O}Warning: Capture file is large (%d MB), may cause memory issues{W}' % (file_size // (1024*1024))) - except (OSError, IOError): + except OSError: pass copy(cap_file, temp_file) @@ -1134,7 +1131,7 @@ def _capture_handshake_dual_hcxdump(self): Color.pl('\n{!} {O}Warning: Capture file is large (%d MB), may cause memory issues{W}' % (file_size // (1024*1024))) if self.view: self.view.add_log(f'Warning: Large capture file ({file_size // (1024*1024)} MB)') - except (OSError, IOError): + except OSError: pass # Convert pcapng to hashcat format for validation @@ -1278,7 +1275,7 @@ def _capture_handshake_single_hcxdump(self): if self.view: self.view.refresh_if_needed() self.view.update_progress({ - 'status': f'Listening for handshake [HCX]', + 'status': 'Listening for handshake [HCX]', 'metrics': { 'Mode': 'HCX (hcxdumptool)', 'Interface': Configuration.interface, @@ -1493,7 +1490,7 @@ def capture_handshake(self): max_cap_size = 50 * 1024 * 1024 # 50MB limit if file_size > max_cap_size: Color.pl('\n{!} {O}Warning: Capture file is large (%d MB), may cause memory issues{W}' % (file_size // (1024*1024))) - except (OSError, IOError): + except OSError: pass copy(cap_file, temp_file) diff --git a/wifite/attack/wpa3.py b/wifite/attack/wpa3.py index 0a616826a..bc95f8199 100755 --- a/wifite/attack/wpa3.py +++ b/wifite/attack/wpa3.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ WPA3-SAE Attack Module @@ -19,10 +18,9 @@ from ..util.logger import log_info, log_debug from ..util.timer import Timer from ..util.output import OutputManager -from ..util.wpa3 import WPA3Detector, WPA3Info +from ..util.wpa3 import WPA3Detector from ..util.wpa3_tools import WPA3ToolChecker from ..attack.wpa3_strategy import WPA3AttackStrategy -from ..model.handshake import Handshake from ..model.sae_result import CrackResultSAE from ..model.wpa_result import CrackResultWPA from contextlib import contextmanager @@ -42,7 +40,7 @@ class AttackWPA3SAE(Attack): """ def __init__(self, target): - super(AttackWPA3SAE, self).__init__(target) + super().__init__(target) self.clients = [] self.crack_result = None self.success = False @@ -626,7 +624,7 @@ def _read_probe_candidates(wordlist_path: str, max_count: int) -> list: """ candidates = [] try: - with open(wordlist_path, 'r', errors='replace') as fh: + with open(wordlist_path, errors='replace') as fh: for line in fh: word = line.rstrip('\n\r') if 8 <= len(word) <= 63: @@ -830,7 +828,6 @@ def attempt_downgrade(self): # still produce a warning. no_clients_warn_after = max(5, timeout_value // 2) deauth_timer = Timer(Configuration.wpa_deauth_timeout) - sae_detected = False deauth_attempts = 0 max_deauth_attempts = 10 no_clients_warning_shown = False @@ -874,7 +871,7 @@ def attempt_downgrade(self): airodump_target = self.wait_for_target(airodump, timeout=1) if airodump_target: self.clients = airodump_target.clients - except Exception as e: + except Exception: # Target temporarily lost, continue pass @@ -918,7 +915,6 @@ def attempt_downgrade(self): if deauth_success: deauth_attempts += 1 deauth_timer = Timer(Configuration.wpa_deauth_timeout) - sae_detected = True # Check if we've exceeded max deauth attempts if deauth_attempts >= max_deauth_attempts: @@ -950,7 +946,7 @@ def attempt_downgrade(self): return handshake else: handshake = None - except Exception as e: + except Exception: # Error checking handshake, continue handshake = None diff --git a/wifite/attack/wpa3_strategy.py b/wifite/attack/wpa3_strategy.py index 7043023da..2fcc59d51 100755 --- a/wifite/attack/wpa3_strategy.py +++ b/wifite/attack/wpa3_strategy.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ WPA3-SAE Attack Strategy Selection Module @@ -9,7 +8,7 @@ mode detection, PMF status, and Dragonblood vulnerability indicators. """ -from typing import Dict, Any, Optional +from typing import Any from wifite.util.wpa3 import WPA3Detector @@ -54,7 +53,7 @@ class WPA3AttackStrategy: } @staticmethod - def select_strategy(target, wpa3_info: Dict[str, Any]) -> Optional[str]: + def select_strategy(target, wpa3_info: dict[str, Any]) -> str | None: """ Select best attack strategy based on target capabilities. @@ -102,7 +101,7 @@ def select_strategy(target, wpa3_info: Dict[str, Any]) -> Optional[str]: return WPA3AttackStrategy.PASSIVE @staticmethod - def can_use_downgrade(wpa3_info: Dict[str, Any]) -> bool: + def can_use_downgrade(wpa3_info: dict[str, Any]) -> bool: """ Check if downgrade attack is possible. @@ -129,7 +128,7 @@ def can_use_downgrade(wpa3_info: Dict[str, Any]) -> bool: return wpa3_info.get('is_transition', False) @staticmethod - def can_use_deauth(wpa3_info: Dict[str, Any]) -> bool: + def can_use_deauth(wpa3_info: dict[str, Any]) -> bool: """ Check if deauth attacks will work (PMF not required). @@ -150,7 +149,7 @@ def can_use_deauth(wpa3_info: Dict[str, Any]) -> bool: return pmf_status != WPA3Detector.PMF_REQUIRED @staticmethod - def should_use_dragonblood(wpa3_info: Dict[str, Any]) -> bool: + def should_use_dragonblood(wpa3_info: dict[str, Any]) -> bool: """ Check if Dragonblood exploitation should be attempted. @@ -200,7 +199,7 @@ def get_strategy_explanation(strategy: str) -> str: ) @staticmethod - def get_attack_priority(wpa3_info: Dict[str, Any]) -> int: + def get_attack_priority(wpa3_info: dict[str, Any]) -> int: """ Get attack priority score for target. @@ -236,7 +235,7 @@ def get_attack_priority(wpa3_info: Dict[str, Any]) -> int: return 50 # Medium priority - standard SAE capture @staticmethod - def format_strategy_display(strategy: str, wpa3_info: Dict[str, Any]) -> str: + def format_strategy_display(strategy: str, wpa3_info: dict[str, Any]) -> str: """ Format strategy information for display to user. diff --git a/wifite/attack/wps.py b/wifite/attack/wps.py index 87481fcb6..76a554e48 100755 --- a/wifite/attack/wps.py +++ b/wifite/attack/wps.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import time @@ -18,7 +17,7 @@ def can_attack_wps(): return Reaver.exists() or Bully.exists() def __init__(self, target, pixie_dust=False, null_pin=False): - super(AttackWPS, self).__init__(target) + super().__init__(target) self.success = False self.crack_result = None self.pixie_dust = pixie_dust diff --git a/wifite/config/__init__.py b/wifite/config/__init__.py index 461d7b9ed..c573445db 100644 --- a/wifite/config/__init__.py +++ b/wifite/config/__init__.py @@ -1,8 +1,6 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import os -import re from ..util.color import Color from ..tools.macchanger import Macchanger @@ -348,11 +346,11 @@ def delete_temp(cls): try: file_path = os.path.join(cls.temp_dir, f) os.remove(file_path) - except (OSError, IOError): + except OSError: pass # Ignore errors during cleanup try: os.rmdir(cls.temp_dir) - except (OSError, IOError): + except OSError: pass # Ignore errors during cleanup @classmethod @@ -381,7 +379,6 @@ def exit_gracefully(cls): # Clean up managed interfaces try: - from ..util.interface_manager import InterfaceManager from ..util.logger import log_info, log_debug # Check if we have an interface manager instance to clean up @@ -433,4 +430,4 @@ def dump(cls): if __name__ == '__main__': Configuration.initialize(False) - print((Configuration.dump())) + print(Configuration.dump()) diff --git a/wifite/config/defaults.py b/wifite/config/defaults.py index 210f97fb2..5d0f2e012 100644 --- a/wifite/config/defaults.py +++ b/wifite/config/defaults.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Default values and initialization helpers for Configuration.""" import os diff --git a/wifite/config/manufacturers.py b/wifite/config/manufacturers.py index 46b77e9a9..31ba9356e 100644 --- a/wifite/config/manufacturers.py +++ b/wifite/config/manufacturers.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """OUI manufacturer database loading logic.""" import os @@ -17,7 +16,7 @@ def load_manufacturers(cls): mfr_file = 'ieee-oui.txt' if os.path.exists(mfr_file): cls.manufacturers = {} - with open(mfr_file, 'r', encoding='utf-8') as f: + with open(mfr_file, encoding='utf-8') as f: for line in f: if not re.match(r'^\w', line): continue diff --git a/wifite/config/parsers/__init__.py b/wifite/config/parsers/__init__.py index 400989a17..fcbc9c28d 100644 --- a/wifite/config/parsers/__init__.py +++ b/wifite/config/parsers/__init__.py @@ -1,3 +1,2 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Argument parsers for the Configuration class.""" diff --git a/wifite/config/parsers/attack_monitor.py b/wifite/config/parsers/attack_monitor.py index 8e5130b5f..c683b099f 100644 --- a/wifite/config/parsers/attack_monitor.py +++ b/wifite/config/parsers/attack_monitor.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Wireless attack monitoring argument parser.""" from ...util.color import Color diff --git a/wifite/config/parsers/dual_interface.py b/wifite/config/parsers/dual_interface.py index aee127fac..1ef4f1d7b 100644 --- a/wifite/config/parsers/dual_interface.py +++ b/wifite/config/parsers/dual_interface.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Dual interface-specific argument parser.""" from ...util.color import Color diff --git a/wifite/config/parsers/eviltwin.py b/wifite/config/parsers/eviltwin.py index 098846daa..861e6d61c 100644 --- a/wifite/config/parsers/eviltwin.py +++ b/wifite/config/parsers/eviltwin.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Evil Twin-specific argument parser and interface info helpers.""" from ...util.color import Color diff --git a/wifite/config/parsers/pmkid.py b/wifite/config/parsers/pmkid.py index 9e67a50cf..67848a16a 100644 --- a/wifite/config/parsers/pmkid.py +++ b/wifite/config/parsers/pmkid.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """PMKID-specific argument parser.""" from ...util.color import Color diff --git a/wifite/config/parsers/settings.py b/wifite/config/parsers/settings.py index 3f4b9fe78..e1d8734ba 100644 --- a/wifite/config/parsers/settings.py +++ b/wifite/config/parsers/settings.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """General settings argument parser and encryption/WEP-attack helpers.""" import os @@ -114,11 +113,11 @@ def parse_settings_args(cls, args): try: # Try UTF-8 first (strict), fall back to latin-1 which accepts all byte values try: - with open(args.ignore_essids_file, 'r', encoding='utf-8') as fh: + with open(args.ignore_essids_file, encoding='utf-8') as fh: file_essids = [line.strip() for line in fh if line.strip() and not line.startswith('#')] except UnicodeDecodeError: Color.pl('{!} {O}ignore-essids-file is not valid UTF-8, trying latin-1{W}') - with open(args.ignore_essids_file, 'r', encoding='latin-1') as fh: + with open(args.ignore_essids_file, encoding='latin-1') as fh: file_essids = [line.strip() for line in fh if line.strip() and not line.startswith('#')] if file_essids: cls.ignore_essids = list(set((cls.ignore_essids or []) + file_essids)) @@ -127,7 +126,7 @@ def parse_settings_args(cls, args): else: Color.pl('{!} {O}ignore-essids-file {R}%s{O} is empty or has only comments{W}' % args.ignore_essids_file) - except (OSError, IOError) as e: + except OSError as e: Color.pl('{!} {R}Could not read ignore-essids-file {O}%s{R}: %s{W}' % (args.ignore_essids_file, str(e))) diff --git a/wifite/config/parsers/wep.py b/wifite/config/parsers/wep.py index 461a32009..14594c961 100644 --- a/wifite/config/parsers/wep.py +++ b/wifite/config/parsers/wep.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """WEP-specific argument parser.""" from ...util.color import Color diff --git a/wifite/config/parsers/wpa.py b/wifite/config/parsers/wpa.py index 95d7c3f2c..c36cc683b 100644 --- a/wifite/config/parsers/wpa.py +++ b/wifite/config/parsers/wpa.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """WPA/WPA2/WPA3-specific argument parser.""" import os diff --git a/wifite/config/parsers/wpasec.py b/wifite/config/parsers/wpasec.py index f353f6e77..79353ad19 100644 --- a/wifite/config/parsers/wpasec.py +++ b/wifite/config/parsers/wpasec.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """WPA-SEC upload and TUI argument parsers.""" from ...util.color import Color diff --git a/wifite/config/parsers/wps.py b/wifite/config/parsers/wps.py index 8d4037871..9d84f03ad 100644 --- a/wifite/config/parsers/wps.py +++ b/wifite/config/parsers/wps.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """WPS-specific argument parser.""" from ...util.color import Color diff --git a/wifite/config/validators.py b/wifite/config/validators.py index 525194cfa..e079b5445 100644 --- a/wifite/config/validators.py +++ b/wifite/config/validators.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """Validation helpers and configuration validation routines.""" import re diff --git a/wifite/model/attack.py b/wifite/model/attack.py index fbbcf7c6d..e5641e3ea 100755 --- a/wifite/model/attack.py +++ b/wifite/model/attack.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import time from ..config import Configuration diff --git a/wifite/model/client.py b/wifite/model/client.py index 514f9425f..34ae791cb 100755 --- a/wifite/model/client.py +++ b/wifite/model/client.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- class Client: diff --git a/wifite/model/eviltwin_result.py b/wifite/model/eviltwin_result.py index 93f2d68e3..487644a6d 100755 --- a/wifite/model/eviltwin_result.py +++ b/wifite/model/eviltwin_result.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult @@ -18,7 +17,7 @@ def __init__(self, bssid, essid, key, clients_connected=0, credential_attempts=0 self.credential_attempts = credential_attempts self.validation_time = validation_time self.portal_template = portal_template - super(CrackResultEvilTwin, self).__init__() + super().__init__() def dump(self): if self.essid: diff --git a/wifite/model/handshake.py b/wifite/model/handshake.py index 1f499f36f..1b48d85ba 100755 --- a/wifite/model/handshake.py +++ b/wifite/model/handshake.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.process import Process from ..util.color import Color diff --git a/wifite/model/ignored_result.py b/wifite/model/ignored_result.py index 62560959b..ad0e25a62 100755 --- a/wifite/model/ignored_result.py +++ b/wifite/model/ignored_result.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from ..model.result import CrackResult @@ -20,7 +19,7 @@ def __init__(self, bssid, essid): self.result_type = 'IGN' self.bssid = bssid self.essid = essid - super(CrackResultIgnored, self).__init__() + super().__init__() def dump(self): if self.essid is not None: diff --git a/wifite/model/interface_info.py b/wifite/model/interface_info.py index 4b83f3ea4..bcc49ea50 100755 --- a/wifite/model/interface_info.py +++ b/wifite/model/interface_info.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Interface information data model for dual wireless device support. @@ -9,7 +8,6 @@ """ from dataclasses import dataclass -from typing import Optional, List @dataclass @@ -39,9 +37,9 @@ class InterfaceInfo: is_connected: bool # Connected to network (for managed mode) # Optional details - frequency: Optional[float] = None # Current frequency in MHz - channel: Optional[int] = None # Current channel - tx_power: Optional[int] = None # TX power in dBm + frequency: float | None = None # Current frequency in MHz + channel: int | None = None # Current channel + tx_power: int | None = None # TX power in dBm def can_be_ap(self) -> bool: @@ -186,11 +184,11 @@ class InterfaceAssignment: # Interface assignments primary: str # Primary interface name - secondary: Optional[str] = None # Secondary interface name (if any) + secondary: str | None = None # Secondary interface name (if any) # Role descriptions primary_role: str = 'primary' # Role of primary interface - secondary_role: Optional[str] = None # Role of secondary interface + secondary_role: str | None = None # Role of secondary interface def is_dual_interface(self) -> bool: """ @@ -201,7 +199,7 @@ def is_dual_interface(self) -> bool: """ return self.secondary is not None - def get_interfaces(self) -> List[str]: + def get_interfaces(self) -> list[str]: """ Get list of all assigned interfaces. diff --git a/wifite/model/pmkid_result.py b/wifite/model/pmkid_result.py index 23929fae4..36593540b 100755 --- a/wifite/model/pmkid_result.py +++ b/wifite/model/pmkid_result.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult @@ -12,7 +11,7 @@ def __init__(self, bssid, essid, pmkid_file, key): self.essid = essid self.pmkid_file = pmkid_file self.key = key - super(CrackResultPMKID, self).__init__() + super().__init__() def dump(self): if self.essid: @@ -53,4 +52,4 @@ def to_dict(self): print('\n') w.dump() w.save() - print((w.__dict__['bssid'])) + print(w.__dict__['bssid']) diff --git a/wifite/model/result.py b/wifite/model/result.py index 67fb16109..bd29ef146 100755 --- a/wifite/model/result.py +++ b/wifite/model/result.py @@ -1,10 +1,8 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*-* from ..util.color import Color from ..config import Configuration -import glob import os import re import time @@ -45,13 +43,13 @@ def save(self): name = CrackResult.cracked_file saved_results = [] if os.path.exists(name): - with open(name, 'r') as fid: + with open(name) as fid: text = fid.read() try: saved_results = loads(text) except (ValueError, TypeError) as e: Color.pl('{!} JSON parsing error in %s: %s' % (name, str(e))) - except (OSError, IOError) as e: + except OSError as e: Color.pl('{!} File access error for %s: %s' % (name, str(e))) except Exception as e: Color.pl('{!} Unexpected error loading %s: %s' % (name, str(e))) @@ -123,7 +121,7 @@ def display(cls, result_type): def load_all(cls): if not os.path.exists(cls.cracked_file): return [] - with open(cls.cracked_file, 'r') as json_file: + with open(cls.cracked_file) as json_file: try: json = loads(json_file.read()) except ValueError: diff --git a/wifite/model/sae_handshake.py b/wifite/model/sae_handshake.py index 114893417..f355a8ca8 100755 --- a/wifite/model/sae_handshake.py +++ b/wifite/model/sae_handshake.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ SAE Handshake Model @@ -13,8 +12,7 @@ from ..tools.tshark import Tshark import os -import re -from typing import Dict, Optional, List, Any +from typing import Any class SAEHandshake: @@ -32,7 +30,7 @@ class SAEHandshake: - Save handshake to file """ - def __init__(self, capfile: str, bssid: str, essid: Optional[str] = None): + def __init__(self, capfile: str, bssid: str, essid: str | None = None): """ Initialize SAEHandshake object. @@ -163,7 +161,7 @@ def _validate_with_tshark(self) -> bool: except Exception: return False - def extract_sae_data(self) -> Optional[Dict[str, Any]]: + def extract_sae_data(self) -> dict[str, Any] | None: """ Extract SAE authentication data from capture with optimized processing. @@ -230,7 +228,7 @@ def extract_sae_data(self) -> Optional[Dict[str, Any]]: except Exception: return None - def convert_to_hashcat(self, output_file: Optional[str] = None) -> Optional[str]: + def convert_to_hashcat(self, output_file: str | None = None) -> str | None: """ Convert SAE handshake to hashcat format (mode 22000). @@ -331,7 +329,7 @@ def analyze(self): else: Color.pl(' Status: {R}Incomplete or invalid SAE handshake{W}') - def extract_frame_timing(self) -> List[Dict]: + def extract_frame_timing(self) -> list[dict]: """ Extract precise timestamps for all SAE Commit/Confirm frames. @@ -346,7 +344,7 @@ def extract_frame_timing(self) -> List[Dict]: return DragonbloodTimingAttack.extract_timing_from_pcap( self.capfile, self.bssid) - def get_ap_response_times_us(self) -> List[float]: + def get_ap_response_times_us(self) -> list[float]: """ Compute AP SAE Commit response latencies from this capture. @@ -364,7 +362,7 @@ def get_ap_response_times_us(self) -> List[float]: frames, self.bssid) @staticmethod - def check_tools() -> Dict[str, bool]: + def check_tools() -> dict[str, bool]: """ Check if required tools for SAE handshake processing are available. diff --git a/wifite/model/sae_result.py b/wifite/model/sae_result.py index 39a3600ea..2a1cb6048 100755 --- a/wifite/model/sae_result.py +++ b/wifite/model/sae_result.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult @@ -14,7 +13,7 @@ def __init__(self, bssid, essid, handshake_file, key): self.essid = essid self.handshake_file = handshake_file self.key = key - super(CrackResultSAE, self).__init__() + super().__init__() def dump(self): if self.essid: diff --git a/wifite/model/target.py b/wifite/model/target.py index ba1ae95ee..14556d307 100644 --- a/wifite/model/target.py +++ b/wifite/model/target.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from ..config import Configuration @@ -465,4 +464,4 @@ def to_str(self, show_bssid=False, show_manufacturer=False): t = Target(fields) t.clients.append('asdf') t.clients.append('asdf') - print((t.to_str())) + print(t.to_str()) diff --git a/wifite/model/wep_result.py b/wifite/model/wep_result.py index 51ab4f281..131eead90 100755 --- a/wifite/model/wep_result.py +++ b/wifite/model/wep_result.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult @@ -12,7 +11,7 @@ def __init__(self, bssid, essid, hex_key, ascii_key): self.essid = essid self.hex_key = hex_key self.ascii_key = ascii_key - super(CrackResultWEP, self).__init__() + super().__init__() def dump(self): if self.essid: diff --git a/wifite/model/wpa_result.py b/wifite/model/wpa_result.py index b8eb20123..1f738cee8 100755 --- a/wifite/model/wpa_result.py +++ b/wifite/model/wpa_result.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult @@ -12,7 +11,7 @@ def __init__(self, bssid, essid, handshake_file, key): self.essid = essid self.handshake_file = handshake_file self.key = key - super(CrackResultWPA, self).__init__() + super().__init__() def dump(self): if self.essid: @@ -53,4 +52,4 @@ def to_dict(self): print('\n') w.dump() w.save() - print((w.__dict__['bssid'])) + print(w.__dict__['bssid']) diff --git a/wifite/model/wps_result.py b/wifite/model/wps_result.py index 65de08046..dcd480948 100755 --- a/wifite/model/wps_result.py +++ b/wifite/model/wps_result.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from ..util.color import Color from ..model.result import CrackResult @@ -22,7 +21,7 @@ def __init__(self, bssid, essid, pin, psk): self.essid = essid self.pin = pin self.psk = psk - super(CrackResultWPS, self).__init__() + super().__init__() def dump(self): if self.essid is not None: diff --git a/wifite/native/__init__.py b/wifite/native/__init__.py index f53fe62ea..c1cfe7ae3 100644 --- a/wifite/native/__init__.py +++ b/wifite/native/__init__.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Native Python implementations for WiFi operations. @@ -118,7 +117,6 @@ def check_native_availability() -> dict: status = {} try: - from .mac import NativeMac status['mac'] = True except Exception: status['mac'] = False @@ -142,7 +140,6 @@ def check_native_availability() -> dict: status['wps'] = False try: - from .interface import NativeInterface status['interface'] = True except Exception: status['interface'] = False diff --git a/wifite/native/beacon.py b/wifite/native/beacon.py index 5c40cc10b..34b3f55a7 100644 --- a/wifite/native/beacon.py +++ b/wifite/native/beacon.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Native beacon frame generator for creating fake APs. @@ -23,12 +22,11 @@ import time import secrets from threading import Thread, Event -from typing import Optional, List try: from scapy.all import ( RadioTap, Dot11, Dot11Beacon, Dot11Elt, Dot11ProbeResp, - sendp, sniff, conf as scapy_conf + sendp, sniff ) SCAPY_AVAILABLE = True except ImportError: @@ -62,7 +60,7 @@ class BeaconGenerator(Thread): def __init__(self, interface: str, essid: str, - bssid: Optional[str] = None, + bssid: str | None = None, channel: int = 6, encryption: str = 'WPA2', beacon_interval: int = DEFAULT_BEACON_INTERVAL, diff --git a/wifite/native/deauth.py b/wifite/native/deauth.py index 756e3de79..1d942b92f 100644 --- a/wifite/native/deauth.py +++ b/wifite/native/deauth.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Scapy-based deauthentication frame injection. @@ -35,9 +34,8 @@ """ import time -import random from threading import Thread, Event -from typing import Optional, List, Tuple, Callable +from collections.abc import Callable try: from scapy.all import ( @@ -83,11 +81,11 @@ def is_available(cls) -> bool: def deauth(cls, interface: str, bssid: str, - client_mac: Optional[str] = None, + client_mac: str | None = None, count: int = 5, reason: int = None, include_disassoc: bool = True, - verbose: bool = False) -> Tuple[bool, int]: + verbose: bool = False) -> tuple[bool, int]: """ Send deauthentication frames to a target. @@ -172,17 +170,17 @@ def deauth(cls, scapy_conf.verb = old_verbose return True, len(packets) - except Exception as e: + except Exception: return False, 0 @classmethod def deauth_with_callback(cls, interface: str, bssid: str, - client_mac: Optional[str] = None, + client_mac: str | None = None, count: int = 5, - callback: Optional[Callable[[int], None]] = None, - inter: float = 0.1) -> Tuple[bool, int]: + callback: Callable[[int], None] | None = None, + inter: float = 0.1) -> tuple[bool, int]: """ Send deauth frames with per-packet callback. @@ -239,14 +237,14 @@ def deauth_with_callback(cls, return True, packets_sent - except Exception as e: + except Exception: return False, packets_sent @classmethod def continuous(cls, interface: str, bssid: str, - client_mac: Optional[str] = None, + client_mac: str | None = None, interval: float = 0.5, burst_count: int = 5) -> 'ContinuousDeauth': """ @@ -282,7 +280,7 @@ class ContinuousDeauth(Thread): def __init__(self, interface: str, bssid: str, - client_mac: Optional[str] = None, + client_mac: str | None = None, interval: float = 0.5, burst_count: int = 5): """ @@ -323,7 +321,7 @@ def run(self): return self.start_time = time.time() - target = self.client_mac or ScapyDeauth.BROADCAST + self.client_mac or ScapyDeauth.BROADCAST while not self._stop_event.is_set(): # Check if paused @@ -413,8 +411,8 @@ def get_stats(self) -> dict: def deauth(interface: str, bssid: str, - client_mac: Optional[str] = None, - count: int = 5) -> Tuple[bool, int]: + client_mac: str | None = None, + count: int = 5) -> tuple[bool, int]: """ Convenience function: send deauth packets. diff --git a/wifite/native/handshake.py b/wifite/native/handshake.py index 8fb6cac7c..8357e8199 100644 --- a/wifite/native/handshake.py +++ b/wifite/native/handshake.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Scapy-based WPA/WPA2 handshake verification. @@ -29,7 +28,6 @@ """ import os -from typing import Optional, List, Dict, Set, Tuple from collections import defaultdict try: @@ -67,7 +65,7 @@ def is_available(cls) -> bool: @classmethod def bssids_with_handshakes(cls, capfile: str, - bssid: Optional[str] = None) -> List[str]: + bssid: str | None = None) -> list[str]: """ Find all BSSIDs with valid 4-way handshakes in a capture file. @@ -96,7 +94,7 @@ def bssids_with_handshakes(cls, return list(valid_bssids) - except Exception as e: + except Exception: return [] @classmethod @@ -117,7 +115,7 @@ def has_handshake(cls, capfile: str, bssid: str) -> bool: @classmethod def get_handshake_info(cls, capfile: str, - bssid: Optional[str] = None) -> List[Dict]: + bssid: str | None = None) -> list[dict]: """ Get detailed handshake information from capture file. @@ -156,7 +154,7 @@ def get_handshake_info(cls, @classmethod def _extract_handshakes(cls, capfile: str, - bssid_filter: Optional[str] = None) -> Dict[Tuple[str, str], Set[int]]: + bssid_filter: str | None = None) -> dict[tuple[str, str], set[int]]: """ Extract EAPOL handshake messages from capture file. @@ -312,7 +310,7 @@ def _determine_message_number(cls, ack: bool, mic: bool, install: bool, secure: return 0 @classmethod - def _is_complete_handshake(cls, messages: Set[int]) -> bool: + def _is_complete_handshake(cls, messages: set[int]) -> bool: """ Check if a set of messages forms a complete handshake. @@ -321,7 +319,7 @@ def _is_complete_handshake(cls, messages: Set[int]) -> bool: return messages == {1, 2, 3, 4} @classmethod - def get_essid(cls, capfile: str, bssid: str) -> Optional[str]: + def get_essid(cls, capfile: str, bssid: str) -> str | None: """ Extract ESSID for a BSSID from beacon/probe response frames. @@ -388,7 +386,7 @@ def has_handshake(capfile: str, bssid: str) -> bool: return ScapyHandshake.has_handshake(capfile, bssid) -def bssids_with_handshakes(capfile: str, bssid: Optional[str] = None) -> List[str]: +def bssids_with_handshakes(capfile: str, bssid: str | None = None) -> list[str]: """Get list of BSSIDs with valid handshakes.""" return ScapyHandshake.bssids_with_handshakes(capfile, bssid) diff --git a/wifite/native/interface.py b/wifite/native/interface.py index c01091be1..784bca761 100644 --- a/wifite/native/interface.py +++ b/wifite/native/interface.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Native network interface management without external tools. @@ -32,7 +31,6 @@ import socket import struct import fcntl -from typing import Optional, List, Dict, Tuple from dataclasses import dataclass @@ -40,15 +38,15 @@ class InterfaceInfo: """Container for interface information.""" name: str - mac_address: Optional[str] = None - driver: Optional[str] = None - mode: Optional[str] = None # managed, monitor, etc. + mac_address: str | None = None + driver: str | None = None + mode: str | None = None # managed, monitor, etc. is_up: bool = False is_wireless: bool = False - channel: Optional[int] = None - frequency: Optional[int] = None # MHz - tx_power: Optional[int] = None # dBm - phy: Optional[str] = None # Physical device (phy0, phy1, etc.) + channel: int | None = None + frequency: int | None = None # MHz + tx_power: int | None = None # dBm + phy: str | None = None # Physical device (phy0, phy1, etc.) class NativeInterface: @@ -112,7 +110,7 @@ class NativeInterface: } @classmethod - def list_interfaces(cls, wireless_only: bool = False) -> List[str]: + def list_interfaces(cls, wireless_only: bool = False) -> list[str]: """ List available network interfaces. @@ -139,7 +137,7 @@ def list_interfaces(cls, wireless_only: bool = False) -> List[str]: return sorted(interfaces) @classmethod - def get_info(cls, interface: str) -> Optional[InterfaceInfo]: + def get_info(cls, interface: str) -> InterfaceInfo | None: """ Get detailed information about an interface. @@ -157,16 +155,16 @@ def get_info(cls, interface: str) -> Optional[InterfaceInfo]: # MAC address try: - with open(f'{sysfs_base}/address', 'r') as f: + with open(f'{sysfs_base}/address') as f: info.mac_address = f.read().strip().upper() - except (IOError, OSError): + except OSError: pass # Driver try: driver_link = os.readlink(f'{sysfs_base}/device/driver') info.driver = os.path.basename(driver_link) - except (IOError, OSError): + except OSError: pass # Check if wireless @@ -174,16 +172,16 @@ def get_info(cls, interface: str) -> Optional[InterfaceInfo]: # Interface state try: - with open(f'{sysfs_base}/operstate', 'r') as f: + with open(f'{sysfs_base}/operstate') as f: info.is_up = f.read().strip().lower() in ('up', 'unknown') - except (IOError, OSError): + except OSError: info.is_up = cls._is_up_ioctl(interface) # PHY device try: phy_link = os.readlink(f'{sysfs_base}/phy80211') info.phy = os.path.basename(phy_link) - except (IOError, OSError): + except OSError: pass # Wireless-specific info @@ -213,7 +211,7 @@ def is_monitor(cls, interface: str) -> bool: return mode == 'monitor' if mode else False @classmethod - def up(cls, interface: str) -> Tuple[bool, str]: + def up(cls, interface: str) -> tuple[bool, str]: """ Bring interface up. @@ -226,7 +224,7 @@ def up(cls, interface: str) -> Tuple[bool, str]: return cls._set_flags(interface, add_flags=cls.IFF_UP) @classmethod - def down(cls, interface: str) -> Tuple[bool, str]: + def down(cls, interface: str) -> tuple[bool, str]: """ Bring interface down. @@ -239,12 +237,12 @@ def down(cls, interface: str) -> Tuple[bool, str]: return cls._set_flags(interface, remove_flags=cls.IFF_UP) @classmethod - def get_mac(cls, interface: str) -> Optional[str]: + def get_mac(cls, interface: str) -> str | None: """Get MAC address of interface.""" try: - with open(f'/sys/class/net/{interface}/address', 'r') as f: + with open(f'/sys/class/net/{interface}/address') as f: return f.read().strip().upper() - except (IOError, OSError): + except OSError: pass # Fallback to ioctl @@ -257,11 +255,11 @@ def get_mac(cls, interface: str) -> Optional[str]: return ':'.join(f'{b:02X}' for b in mac_bytes) finally: sock.close() - except (IOError, OSError): + except OSError: return None @classmethod - def get_channel(cls, interface: str) -> Optional[int]: + def get_channel(cls, interface: str) -> int | None: """Get current channel of wireless interface.""" freq = cls._get_frequency_ioctl(interface) if freq: @@ -280,7 +278,7 @@ def get_channel(cls, interface: str) -> Optional[int]: return None @classmethod - def set_channel(cls, interface: str, channel: int) -> Tuple[bool, str]: + def set_channel(cls, interface: str, channel: int) -> tuple[bool, str]: """ Set channel on wireless interface. @@ -311,7 +309,7 @@ def set_channel(cls, interface: str, channel: int) -> Tuple[bool, str]: return False, str(e) @classmethod - def set_mode(cls, interface: str, mode: str) -> Tuple[bool, str]: + def set_mode(cls, interface: str, mode: str) -> tuple[bool, str]: """ Set wireless interface mode. @@ -342,7 +340,7 @@ def set_mode(cls, interface: str, mode: str) -> Tuple[bool, str]: return True, f'Mode set to {mode}' finally: sock.close() - except (IOError, OSError): + except OSError: pass # Fallback to iw command @@ -356,7 +354,7 @@ def set_mode(cls, interface: str, mode: str) -> Tuple[bool, str]: return False, str(e) @classmethod - def get_mode(cls, interface: str) -> Optional[str]: + def get_mode(cls, interface: str) -> str | None: """Get current wireless mode.""" return cls._get_mode_ioctl(interface) @@ -372,11 +370,11 @@ def _is_up_ioctl(cls, interface: str) -> bool: return bool(flags & cls.IFF_UP) finally: sock.close() - except (IOError, OSError): + except OSError: return False @classmethod - def _set_flags(cls, interface: str, add_flags: int = 0, remove_flags: int = 0) -> Tuple[bool, str]: + def _set_flags(cls, interface: str, add_flags: int = 0, remove_flags: int = 0) -> tuple[bool, str]: """Set interface flags using ioctl.""" try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -397,7 +395,7 @@ def _set_flags(cls, interface: str, add_flags: int = 0, remove_flags: int = 0) - return True, 'Flags updated' finally: sock.close() - except (IOError, OSError) as e: + except OSError: pass # Fallback to ip command @@ -412,7 +410,7 @@ def _set_flags(cls, interface: str, add_flags: int = 0, remove_flags: int = 0) - return False, str(e) @classmethod - def _get_mode_ioctl(cls, interface: str) -> Optional[str]: + def _get_mode_ioctl(cls, interface: str) -> str | None: """Get wireless mode using ioctl.""" try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -424,7 +422,7 @@ def _get_mode_ioctl(cls, interface: str) -> Optional[str]: return cls.MODE_NAMES.get(mode, 'unknown') finally: sock.close() - except (IOError, OSError): + except OSError: pass # Fallback to iw command @@ -440,7 +438,7 @@ def _get_mode_ioctl(cls, interface: str) -> Optional[str]: return None @classmethod - def _get_frequency_ioctl(cls, interface: str) -> Optional[int]: + def _get_frequency_ioctl(cls, interface: str) -> int | None: """Get wireless frequency using ioctl.""" try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -466,7 +464,7 @@ def _get_frequency_ioctl(cls, interface: str) -> Optional[int]: finally: sock.close() - except (IOError, OSError): + except OSError: pass return None @@ -490,11 +488,11 @@ def _set_frequency_ioctl(cls, interface: str, freq_mhz: int) -> bool: return True finally: sock.close() - except (IOError, OSError): + except OSError: return False @classmethod - def _channel_to_freq(cls, channel: int) -> Optional[int]: + def _channel_to_freq(cls, channel: int) -> int | None: """Convert channel number to frequency in MHz.""" if channel in cls.CHANNEL_FREQ_24: return cls.CHANNEL_FREQ_24[channel] @@ -503,7 +501,7 @@ def _channel_to_freq(cls, channel: int) -> Optional[int]: return None @classmethod - def _freq_to_channel(cls, freq_mhz: int) -> Optional[int]: + def _freq_to_channel(cls, freq_mhz: int) -> int | None: """Convert frequency in MHz to channel number.""" # Search 2.4 GHz for ch, f in cls.CHANNEL_FREQ_24.items(): @@ -517,26 +515,26 @@ def _freq_to_channel(cls, freq_mhz: int) -> Optional[int]: # Convenience functions -def list_interfaces(wireless_only: bool = False) -> List[str]: +def list_interfaces(wireless_only: bool = False) -> list[str]: """List network interfaces.""" return NativeInterface.list_interfaces(wireless_only) -def get_info(interface: str) -> Optional[InterfaceInfo]: +def get_info(interface: str) -> InterfaceInfo | None: """Get interface information.""" return NativeInterface.get_info(interface) -def up(interface: str) -> Tuple[bool, str]: +def up(interface: str) -> tuple[bool, str]: """Bring interface up.""" return NativeInterface.up(interface) -def down(interface: str) -> Tuple[bool, str]: +def down(interface: str) -> tuple[bool, str]: """Bring interface down.""" return NativeInterface.down(interface) -def get_mac(interface: str) -> Optional[str]: +def get_mac(interface: str) -> str | None: """Get interface MAC address.""" return NativeInterface.get_mac(interface) diff --git a/wifite/native/mac.py b/wifite/native/mac.py index ada0c68bb..3633e49f5 100644 --- a/wifite/native/mac.py +++ b/wifite/native/mac.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Native MAC address manipulation without external tools. @@ -24,13 +23,11 @@ NativeMac.reset('wlan0') """ -import os import re import secrets import fcntl import socket import struct -from typing import Optional, Tuple from ..util.logger import log_debug @@ -83,7 +80,7 @@ class NativeMac: ] @classmethod - def get_mac(cls, interface: str) -> Optional[str]: + def get_mac(cls, interface: str) -> str | None: """ Get the current MAC address of an interface. @@ -96,11 +93,11 @@ def get_mac(cls, interface: str) -> Optional[str]: # Method 1: Try sysfs (fastest) sysfs_path = f'/sys/class/net/{interface}/address' try: - with open(sysfs_path, 'r') as f: + with open(sysfs_path) as f: mac = f.read().strip() if cls._is_valid_mac(mac): return mac.upper() - except (IOError, OSError): + except OSError: pass # Method 2: Try ioctl @@ -116,13 +113,13 @@ def get_mac(cls, interface: str) -> Optional[str]: return mac finally: sock.close() - except (IOError, OSError): + except OSError: pass return None @classmethod - def get_permanent_mac(cls, interface: str) -> Optional[str]: + def get_permanent_mac(cls, interface: str) -> str | None: """ Get the permanent (factory) MAC address of an interface. @@ -137,18 +134,18 @@ def get_permanent_mac(cls, interface: str) -> Optional[str]: # Try reading from sysfs perm_path = f'/sys/class/net/{interface}/perm_hwaddr' try: - with open(perm_path, 'r') as f: + with open(perm_path) as f: mac = f.read().strip() if cls._is_valid_mac(mac): return mac.upper() - except (IOError, OSError): + except OSError: pass # Fall back to cached original MAC return cls._original_macs.get(interface) @classmethod - def set_mac(cls, interface: str, mac: str) -> Tuple[bool, str]: + def set_mac(cls, interface: str, mac: str) -> tuple[bool, str]: """ Set the MAC address of an interface. @@ -188,7 +185,7 @@ def set_mac(cls, interface: str, mac: str) -> Tuple[bool, str]: new_mac = cls.get_mac(interface) if new_mac and new_mac.upper() == mac.upper(): return True, f'MAC address changed to {mac}' - except (IOError, OSError, PermissionError): + except (OSError, PermissionError): pass # Method 2: Try ioctl @@ -215,7 +212,7 @@ def set_mac(cls, interface: str, mac: str) -> Tuple[bool, str]: finally: sock.close() - except (IOError, OSError, PermissionError) as e: + except (OSError, PermissionError): pass # Method 3: Fall back to ip command @@ -232,7 +229,7 @@ def set_mac(cls, interface: str, mac: str) -> Tuple[bool, str]: return False, f'Failed to change MAC address on {interface}' @classmethod - def random(cls, interface: str, keep_vendor: bool = False) -> Tuple[bool, str]: + def random(cls, interface: str, keep_vendor: bool = False) -> tuple[bool, str]: """ Set a random MAC address on the interface. @@ -261,7 +258,7 @@ def random(cls, interface: str, keep_vendor: bool = False) -> Tuple[bool, str]: return False, msg @classmethod - def reset(cls, interface: str) -> Tuple[bool, str]: + def reset(cls, interface: str) -> tuple[bool, str]: """ Reset MAC address to the original/permanent value. @@ -321,31 +318,31 @@ def _is_interface_up(cls, interface: str) -> bool: return bool(flags & cls.IFF_UP) finally: sock.close() - except (IOError, OSError): + except OSError: # Fall back to sysfs try: - with open(f'/sys/class/net/{interface}/operstate', 'r') as f: + with open(f'/sys/class/net/{interface}/operstate') as f: return f.read().strip().lower() == 'up' - except (IOError, OSError): + except OSError: return False # Convenience functions for backward compatibility -def get_mac(interface: str) -> Optional[str]: +def get_mac(interface: str) -> str | None: """Get MAC address of interface.""" return NativeMac.get_mac(interface) -def set_mac(interface: str, mac: str) -> Tuple[bool, str]: +def set_mac(interface: str, mac: str) -> tuple[bool, str]: """Set MAC address of interface.""" return NativeMac.set_mac(interface, mac) -def random_mac(interface: str, keep_vendor: bool = False) -> Tuple[bool, str]: +def random_mac(interface: str, keep_vendor: bool = False) -> tuple[bool, str]: """Set random MAC address on interface.""" return NativeMac.random(interface, keep_vendor) -def reset_mac(interface: str) -> Tuple[bool, str]: +def reset_mac(interface: str) -> tuple[bool, str]: """Reset MAC to permanent/original value.""" return NativeMac.reset(interface) diff --git a/wifite/native/pmkid.py b/wifite/native/pmkid.py index 6f27ca431..1a2db7cfa 100644 --- a/wifite/native/pmkid.py +++ b/wifite/native/pmkid.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Native PMKID capture using Scapy. @@ -29,18 +28,16 @@ and has better driver compatibility. """ -import os import time import binascii from threading import Thread, Event -from typing import Optional, List, Dict, Tuple, Callable +from collections.abc import Callable from dataclasses import dataclass try: from scapy.all import ( RadioTap, Dot11, Dot11Beacon, Dot11ProbeResp, Dot11Auth, - Dot11AssoReq, Dot11AssoResp, Dot11Elt, EAPOL, Raw, - sniff, sendp, conf as scapy_conf + Dot11Elt, EAPOL, Raw, sniff, sendp ) SCAPY_AVAILABLE = True except ImportError: @@ -53,9 +50,9 @@ class PMKIDResult: bssid: str client_mac: str pmkid: str # Hex string - essid: Optional[str] = None - channel: Optional[int] = None - timestamp: Optional[float] = None + essid: str | None = None + channel: int | None = None + timestamp: float | None = None def to_hashcat_22000(self) -> str: """ @@ -128,12 +125,12 @@ def is_available(cls) -> bool: def capture(cls, interface: str, bssid: str, - essid: Optional[str] = None, - client_mac: Optional[str] = None, + essid: str | None = None, + client_mac: str | None = None, timeout: int = 30, send_auth: bool = True, - channel: Optional[int] = None, - callback: Optional[Callable[[PMKIDResult], None]] = None) -> Optional[PMKIDResult]: + channel: int | None = None, + callback: Callable[[PMKIDResult], None] | None = None) -> PMKIDResult | None: """ Capture PMKID for a specific target. @@ -272,8 +269,8 @@ def capture_thread(): def passive_scan(cls, interface: str, duration: int = 60, - bssid_filter: Optional[str] = None, - callback: Optional[Callable[[PMKIDResult], None]] = None) -> List[PMKIDResult]: + bssid_filter: str | None = None, + callback: Callable[[PMKIDResult], None] | None = None) -> list[PMKIDResult]: """ Passively scan for PMKIDs on multiple networks. @@ -366,7 +363,7 @@ def packet_handler(pkt): return results @classmethod - def _extract_pmkid(cls, pkt) -> Optional[str]: + def _extract_pmkid(cls, pkt) -> str | None: """ Extract PMKID from EAPOL-Key frame. @@ -379,7 +376,7 @@ def _extract_pmkid(cls, pkt) -> Optional[str]: PMKID as hex string, or None if not found """ try: - eapol = pkt[EAPOL] + pkt[EAPOL] # Get raw packet data after EAPOL header if pkt.haslayer(Raw): @@ -417,7 +414,7 @@ def _extract_pmkid(cls, pkt) -> Optional[str]: return None @classmethod - def _find_pmkid_in_key_data(cls, key_data: bytes) -> Optional[str]: + def _find_pmkid_in_key_data(cls, key_data: bytes) -> str | None: """ Find PMKID in Key Data field. @@ -486,7 +483,7 @@ def _find_pmkid_in_key_data(cls, key_data: bytes) -> Optional[str]: return None @classmethod - def _parse_rsn_ie_for_pmkid(cls, rsn_data: bytes) -> Optional[str]: + def _parse_rsn_ie_for_pmkid(cls, rsn_data: bytes) -> str | None: """ Parse RSN IE to find PMKID List. @@ -593,7 +590,7 @@ def _send_auth_request(cls, interface: str, bssid: str, client_mac: str): @classmethod def save_to_file(cls, - results: List[PMKIDResult], + results: list[PMKIDResult], filename: str, format: str = '22000') -> bool: """ @@ -616,7 +613,7 @@ def save_to_file(cls, line = result.to_hashcat_22000() f.write(line + '\n') return True - except (OSError, IOError): + except OSError: return False @@ -629,9 +626,9 @@ class PMKIDCapture(Thread): def __init__(self, interface: str, - channels: Optional[List[int]] = None, - bssid_filter: Optional[str] = None, - callback: Optional[Callable[[PMKIDResult], None]] = None): + channels: list[int] | None = None, + bssid_filter: str | None = None, + callback: Callable[[PMKIDResult], None] | None = None): """ Initialize PMKID capture thread. @@ -751,7 +748,7 @@ def stop(self): if self.is_alive(): self.join(timeout=2) - def get_results(self) -> List[PMKIDResult]: + def get_results(self) -> list[PMKIDResult]: """Get captured PMKIDs.""" return self.results.copy() @@ -767,12 +764,12 @@ def get_stats(self) -> dict: # Convenience functions -def capture_pmkid(interface: str, bssid: str, timeout: int = 30) -> Optional[PMKIDResult]: +def capture_pmkid(interface: str, bssid: str, timeout: int = 30) -> PMKIDResult | None: """Capture PMKID for specific target.""" return ScapyPMKID.capture(interface, bssid, timeout=timeout) -def passive_scan(interface: str, duration: int = 60) -> List[PMKIDResult]: +def passive_scan(interface: str, duration: int = 60) -> list[PMKIDResult]: """Passively scan for PMKIDs.""" return ScapyPMKID.passive_scan(interface, duration=duration) diff --git a/wifite/native/scanner.py b/wifite/native/scanner.py index c32acec86..9253dcfe4 100644 --- a/wifite/native/scanner.py +++ b/wifite/native/scanner.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Native channel hopping and scanning utilities. @@ -30,15 +29,12 @@ import time from threading import Thread, Event, Lock -from typing import Optional, List, Dict, Set, Callable +from collections.abc import Callable from dataclasses import dataclass, field -from collections import defaultdict try: from scapy.all import ( - RadioTap, Dot11, Dot11Beacon, Dot11ProbeResp, Dot11ProbeReq, - Dot11Elt, Dot11AssoReq, Dot11AssoResp, Dot11Auth, - sniff, conf as scapy_conf + RadioTap, Dot11, Dot11Elt, sniff ) SCAPY_AVAILABLE = True except ImportError: @@ -68,12 +64,12 @@ class AccessPoint: wps_locked: bool = False power: int = -100 # dBm beacons: int = 0 - clients: List[str] = field(default_factory=list) + clients: list[str] = field(default_factory=list) last_seen: float = 0 first_seen: float = 0 # Additional info - vendor: Optional[str] = None + vendor: str | None = None hidden: bool = False pmf: bool = False # Protected Management Frames (WPA3 requirement) @@ -82,9 +78,9 @@ class AccessPoint: class Client: """Represents a detected wireless client.""" mac: str - bssid: Optional[str] = None # Associated AP + bssid: str | None = None # Associated AP power: int = -100 - probes: List[str] = field(default_factory=list) + probes: list[str] = field(default_factory=list) last_seen: float = 0 first_seen: float = 0 packets: int = 0 @@ -100,7 +96,7 @@ class ChannelHopper(Thread): def __init__(self, interface: str, - channels: Optional[List[int]] = None, + channels: list[int] | None = None, interval: float = 0.5, band: str = '2.4'): """ @@ -140,7 +136,7 @@ def __init__(self, self.start_time = None # Callbacks - self._on_channel_change: Optional[Callable[[int], None]] = None + self._on_channel_change: Callable[[int], None] | None = None def run(self): """Main hopping loop.""" @@ -239,7 +235,7 @@ class NativeScanner: def __init__(self, interface: str, - channels: Optional[List[int]] = None, + channels: list[int] | None = None, band: str = '2.4', hop_interval: float = 0.5): """ @@ -257,18 +253,18 @@ def __init__(self, self.hop_interval = hop_interval # Data storage - self.access_points: Dict[str, AccessPoint] = {} - self.clients: Dict[str, Client] = {} + self.access_points: dict[str, AccessPoint] = {} + self.clients: dict[str, Client] = {} self._lock = Lock() # Components - self.hopper: Optional[ChannelHopper] = None - self._capture_thread: Optional[Thread] = None + self.hopper: ChannelHopper | None = None + self._capture_thread: Thread | None = None self._stop_event = Event() # Stats self.packets_processed = 0 - self.start_time: Optional[float] = None + self.start_time: float | None = None def start(self): """Start scanning.""" @@ -597,7 +593,6 @@ def _parse_rsn_ie(self, data: bytes) -> tuple: # Group cipher (4 bytes) if offset + 4 <= len(data): - group_cipher = data[offset:offset + 4] offset += 4 # Pairwise cipher count @@ -726,12 +721,12 @@ def _check_wps_locked(self, data: bytes) -> bool: pass return False - def get_targets(self) -> List[AccessPoint]: + def get_targets(self) -> list[AccessPoint]: """Get list of discovered access points.""" with self._lock: return list(self.access_points.values()) - def get_clients(self) -> List[Client]: + def get_clients(self) -> list[Client]: """Get list of discovered clients.""" with self._lock: return list(self.clients.values()) @@ -758,7 +753,7 @@ def create_channel_hopper(interface: str, band: str = '2.4') -> ChannelHopper: return ChannelHopper(interface, band=band) -def scan_networks(interface: str, duration: int = 30, band: str = '2.4') -> List[AccessPoint]: +def scan_networks(interface: str, duration: int = 30, band: str = '2.4') -> list[AccessPoint]: """ Scan for WiFi networks. diff --git a/wifite/native/wps.py b/wifite/native/wps.py index dd004b185..9fe8ea3ab 100644 --- a/wifite/native/wps.py +++ b/wifite/native/wps.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Scapy-based WPS (Wi-Fi Protected Setup) detection. @@ -27,8 +26,6 @@ """ import os -from typing import Optional, List, Dict, Set -from collections import defaultdict try: from scapy.all import ( @@ -100,7 +97,7 @@ def is_available(cls) -> bool: return SCAPY_AVAILABLE @classmethod - def detect_wps(cls, capfile: str) -> Dict[str, WPSInfo]: + def detect_wps(cls, capfile: str) -> dict[str, WPSInfo]: """ Detect WPS-enabled networks from capture file. @@ -155,7 +152,7 @@ def detect_wps(cls, capfile: str) -> Dict[str, WPSInfo]: return {} @classmethod - def update_targets(cls, capfile: str, targets: List) -> None: + def update_targets(cls, capfile: str, targets: list) -> None: """ Update target list with WPS information from capture. @@ -188,7 +185,7 @@ def update_targets(cls, capfile: str, targets: List) -> None: target.wps = 1 # UNLOCKED @classmethod - def _parse_wps_ie(cls, pkt, bssid: str) -> Optional[WPSInfo]: + def _parse_wps_ie(cls, pkt, bssid: str) -> WPSInfo | None: """ Parse WPS information element from packet. @@ -290,7 +287,7 @@ def _parse_wps_attributes(cls, data: bytes, info: WPSInfo) -> None: break @classmethod - def get_wps_status(cls, capfile: str, bssid: str) -> Optional[WPSInfo]: + def get_wps_status(cls, capfile: str, bssid: str) -> WPSInfo | None: """ Get WPS status for specific BSSID. @@ -305,7 +302,7 @@ def get_wps_status(cls, capfile: str, bssid: str) -> Optional[WPSInfo]: return all_wps.get(bssid.upper()) @classmethod - def is_wps_locked(cls, capfile: str, bssid: str) -> Optional[bool]: + def is_wps_locked(cls, capfile: str, bssid: str) -> bool | None: """ Check if WPS is locked for specific BSSID. @@ -323,12 +320,12 @@ def is_wps_locked(cls, capfile: str, bssid: str) -> Optional[bool]: # Convenience functions -def detect_wps(capfile: str) -> Dict[str, WPSInfo]: +def detect_wps(capfile: str) -> dict[str, WPSInfo]: """Detect WPS-enabled networks from capture file.""" return ScapyWPS.detect_wps(capfile) -def update_targets(capfile: str, targets: List) -> None: +def update_targets(capfile: str, targets: list) -> None: """Update targets with WPS information.""" return ScapyWPS.update_targets(capfile, targets) diff --git a/wifite/tools/aircrack.py b/wifite/tools/aircrack.py index 5bf1846af..d166e7d86 100644 --- a/wifite/tools/aircrack.py +++ b/wifite/tools/aircrack.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import os import re @@ -54,7 +53,7 @@ def get_key_hex_ascii(self): if not self.is_cracked(): raise Exception('Cracked file not found') - with open(self.cracked_file, 'r') as fid: + with open(self.cracked_file) as fid: hex_raw = fid.read() return self._hex_and_ascii_key(hex_raw) @@ -144,7 +143,7 @@ def crack_handshake(handshake, show_command=False, wordlist=None): if not os.path.exists(key_file): return None - with open(key_file, 'r') as fid: + with open(key_file) as fid: key = fid.read().strip() os.remove(key_file) diff --git a/wifite/tools/aireplay.py b/wifite/tools/aireplay.py index c64546468..0d54e7be7 100644 --- a/wifite/tools/aireplay.py +++ b/wifite/tools/aireplay.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration @@ -149,7 +148,7 @@ def _run_loop(self): self.stdout += lines fid.seek(0) fid.truncate() - except (OSError, IOError): + except OSError: continue if Configuration.verbose > 1 and lines.strip() != '': diff --git a/wifite/tools/airmon.py b/wifite/tools/airmon.py index fd57cee28..8648f0290 100644 --- a/wifite/tools/airmon.py +++ b/wifite/tools/airmon.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import os import re @@ -76,7 +75,7 @@ def refresh(self): def print_menu(self): """ Prints menu """ - print((AirmonIface.menu_header())) + print(AirmonIface.menu_header()) for idx, interface in enumerate(self.interfaces, start=1): Color.pl(' {G}%d{W}. %s' % (idx, interface)) @@ -146,7 +145,7 @@ def start_monitor(interface): # /sys/class/net/wlan0/type iface_type_path = os.path.join('/sys/class/net', interface, 'type') if os.path.exists(iface_type_path): - with open(iface_type_path, 'r') as f: + with open(iface_type_path) as f: iface_type = f.read().strip() if Configuration.verbose > 0: Color.pl('{D}Interface type from sysfs: %s{W}' % iface_type) @@ -226,7 +225,7 @@ def start(cls, interface): # Attempt to revert if possible, or let subsequent methods handle it except subprocess.CalledProcessError as e: Color.pl('{R}failed (ICNSS2 specific command error: %s). Trying other methods...{W}' % e.stderr.decode().strip()) - except (OSError, IOError) as e: + except OSError as e: Color.pl('{R}failed (ICNSS2 I/O error: %s). Trying other methods...{W}' % str(e)) except ValueError as e: Color.pl('{R}failed (ICNSS2 config error: %s). Trying other methods...{W}' % str(e)) @@ -407,9 +406,9 @@ def terminate_conflicting_processes(): # Checking for systemd, otherwise assume openrc if os.path.exists('/usr/lib/systemd/systemd'): - init_system = 'systemd' + pass else: - init_system = 'openrc' + pass # TODO: add support for other unorthodox init systems (maybe?) # Conflicting process IDs and names diff --git a/wifite/tools/airodump.py b/wifite/tools/airodump.py index 82ff1991a..1f1744456 100755 --- a/wifite/tools/airodump.py +++ b/wifite/tools/airodump.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .dependency import Dependency from .tshark import Tshark @@ -11,7 +10,6 @@ from ..model.client import Client from ..util.logger import log_debug, log_warning -import csv import os import time @@ -251,7 +249,7 @@ def get_targets_from_csv(csv_filename): except ImportError: encoding = 'utf-8' - with open(csv_filename, 'r', encoding=encoding, errors='ignore') as csvopen: + with open(csv_filename, encoding=encoding, errors='ignore') as csvopen: lines = [] has_null = False for line in csvopen: diff --git a/wifite/tools/bully.py b/wifite/tools/bully.py index 6dd2fad57..1542ca743 100755 --- a/wifite/tools/bully.py +++ b/wifite/tools/bully.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .dependency import Dependency from .airodump import Airodump @@ -136,7 +135,7 @@ def _run(self, airodump): self.target = self.wait_for_target(airodump) except subprocess.CalledProcessError as e: self.pattack('{R}Failed: {O}Bully command error: %s{W}' % e, newline=True) - except (OSError, IOError) as e: + except OSError as e: self.pattack('{R}Failed: {O}System I/O error: %s{W}' % e, newline=True) except ValueError as e: self.pattack('{R}Failed: {O}Invalid target data: %s{W}' % e, newline=True) diff --git a/wifite/tools/cowpatty.py b/wifite/tools/cowpatty.py index bfcbbd894..a21dfcfb3 100755 --- a/wifite/tools/cowpatty.py +++ b/wifite/tools/cowpatty.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration diff --git a/wifite/tools/dependency.py b/wifite/tools/dependency.py index b50570fbd..cdeee37a7 100644 --- a/wifite/tools/dependency.py +++ b/wifite/tools/dependency.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import os import shlex @@ -120,7 +119,6 @@ class Dependency: def _check_native_mac(cls) -> bool: """Check if native MAC manipulation is available.""" try: - from ..native.mac import NativeMac return True except ImportError: return False diff --git a/wifite/tools/dnsmasq.py b/wifite/tools/dnsmasq.py index 029b46303..fd8d99ffb 100755 --- a/wifite/tools/dnsmasq.py +++ b/wifite/tools/dnsmasq.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Dnsmasq tool wrapper for DHCP and DNS services. @@ -9,7 +8,6 @@ import os import time import tempfile -from typing import Optional, List from .dependency import Dependency from ..config import Configuration @@ -253,7 +251,7 @@ def _setup_routing(self): except Exception as e: log_warning('Dnsmasq', f'Failed to setup routing: {e}') - def _get_internet_interface(self) -> Optional[str]: + def _get_internet_interface(self) -> str | None: """ Get the interface with internet connectivity. @@ -371,7 +369,7 @@ def is_running(self) -> bool: return self.process.poll() is None - def get_leases(self) -> List[dict]: + def get_leases(self) -> list[dict]: """ Get list of DHCP leases. @@ -384,7 +382,7 @@ def get_leases(self) -> List[dict]: if not self.lease_file or not os.path.exists(self.lease_file): return leases - with open(self.lease_file, 'r') as f: + with open(self.lease_file) as f: for line in f: line = line.strip() if not line: @@ -408,7 +406,7 @@ def get_leases(self) -> List[dict]: log_debug('Dnsmasq', f'Failed to get leases: {e}') return [] - def get_connected_clients(self) -> List[str]: + def get_connected_clients(self) -> list[str]: """ Get list of connected client MAC addresses. @@ -418,7 +416,7 @@ def get_connected_clients(self) -> List[str]: leases = self.get_leases() return [lease['mac'] for lease in leases] - def get_client_info(self, mac_address: str) -> Optional[dict]: + def get_client_info(self, mac_address: str) -> dict | None: """ Get information about a specific client. diff --git a/wifite/tools/hashcat.py b/wifite/tools/hashcat.py index e4dd6b374..7a645f657 100755 --- a/wifite/tools/hashcat.py +++ b/wifite/tools/hashcat.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration @@ -7,7 +6,6 @@ from ..util.color import Color from ..util.logger import log_debug, log_info, log_warning, log_error import os -import re import threading class HashcatCracker: @@ -465,7 +463,6 @@ def generate_hash_file(handshake_obj, is_wpa3_sae, show_command=False): # Also include tshark check for WPA3 if is_wpa3_sae: - from .tshark import Tshark tshark_check_cmd = ['tshark', '-r', handshake_obj.capfile, '-Y', 'wlan.fc.type_subtype == 0x0b'] # Authentication frames tshark_process = Process(tshark_check_cmd) tshark_stdout, _ = tshark_process.get_output() @@ -493,7 +490,6 @@ def generate_hash_file(handshake_obj, is_wpa3_sae, show_command=False): Color.pl('{!} {O}Cleaned up temporary hash file after error{W}') except OSError as cleanup_err: log_debug('HcxPcapngTool', f'Failed to cleanup hash file: {str(cleanup_err)}') - pass raise @staticmethod @@ -549,7 +545,6 @@ def generate_john_file(handshake, show_command=False): Color.pl('{!} {O}Cleaned up temporary john file after error{W}') except OSError as cleanup_err: log_debug('HcxPcapngTool', f'Failed to cleanup john file: {str(cleanup_err)}') - pass raise def get_pmkid_hash(self, pcapng_file): @@ -563,7 +558,7 @@ def get_pmkid_hash(self, pcapng_file): if not os.path.exists(self.pmkid_file): return None - with open(self.pmkid_file, 'r') as f: + with open(self.pmkid_file) as f: output = f.read() # Each line looks like: # hash*bssid*station*essid @@ -628,7 +623,7 @@ def extract_all_pmkids(pcapng_file): pmkids = [] try: - with open(temp_hash_file, 'r') as f: + with open(temp_hash_file) as f: for line in f: line = line.strip() diff --git a/wifite/tools/hcxdumptool.py b/wifite/tools/hcxdumptool.py index c49f4c5dc..7676b6325 100644 --- a/wifite/tools/hcxdumptool.py +++ b/wifite/tools/hcxdumptool.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ hcxdumptool Wrapper diff --git a/wifite/tools/hostapd.py b/wifite/tools/hostapd.py index 077844bc1..60e60dd72 100755 --- a/wifite/tools/hostapd.py +++ b/wifite/tools/hostapd.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Hostapd tool wrapper for creating software access points. @@ -9,7 +8,6 @@ import os import time import tempfile -from typing import Optional from .dependency import Dependency from ..config import Configuration diff --git a/wifite/tools/ip.py b/wifite/tools/ip.py index 2c69b32f4..d13abd650 100644 --- a/wifite/tools/ip.py +++ b/wifite/tools/ip.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import re diff --git a/wifite/tools/iw.py b/wifite/tools/iw.py index 21633a295..d47b113a4 100644 --- a/wifite/tools/iw.py +++ b/wifite/tools/iw.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .dependency import Dependency diff --git a/wifite/tools/john.py b/wifite/tools/john.py index 48e4e0428..de3adf3da 100755 --- a/wifite/tools/john.py +++ b/wifite/tools/john.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration diff --git a/wifite/tools/macchanger.py b/wifite/tools/macchanger.py index 134b75ac9..3f27a1be1 100644 --- a/wifite/tools/macchanger.py +++ b/wifite/tools/macchanger.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ MAC address changer with native Python fallback. @@ -28,7 +27,6 @@ def _can_use_native(cls) -> bool: """Check if native MAC manipulation is available.""" if cls._use_native is None: try: - from ..native.mac import NativeMac cls._use_native = True except ImportError: cls._use_native = False @@ -96,7 +94,7 @@ def reset(cls): cls.is_changed = False return - except Exception as e: + except Exception: # Fall back to macchanger binary pass @@ -151,7 +149,7 @@ def random(cls, full_random=True): Color.pl('\r{+} {C}macchanger{W}: changed mac address to {C}%s{W} on {C}%s{W} (native)' % (result, iface)) return - except (OSError, RuntimeError) as e: + except (OSError, RuntimeError): # Bring interface back up if it was taken down try: Ip.up(iface) diff --git a/wifite/tools/reaver.py b/wifite/tools/reaver.py index ff0d62a2e..cb4810d38 100755 --- a/wifite/tools/reaver.py +++ b/wifite/tools/reaver.py @@ -19,7 +19,7 @@ class Reaver(Attack, Dependency): dependency_url = 'https://github.com/t6x/reaver-wps-fork-t6x' def __init__(self, target, pixie_dust=True, null_pin=False): - super(Reaver, self).__init__(target) + super().__init__(target) self.pixie_dust = pixie_dust self.null_pin = null_pin @@ -93,7 +93,7 @@ def run(self): except subprocess.CalledProcessError as e: # Reaver command failed self.pattack('{R}Failed:{O} Reaver command error: %s' % str(e), newline=True) - except (OSError, IOError) as e: + except OSError as e: # System or file errors self.pattack('{R}Failed:{O} System error: %s' % str(e), newline=True) except ValueError as e: @@ -510,7 +510,7 @@ def get_output(self): if self.output_write: self.output_write.flush() - with open(self.output_filename, 'r') as fid: + with open(self.output_filename) as fid: stdout = fid.read() if Configuration.verbose > 1: diff --git a/wifite/tools/tshark.py b/wifite/tools/tshark.py index 78c480388..95a0107db 100644 --- a/wifite/tools/tshark.py +++ b/wifite/tools/tshark.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Tshark wrapper with native Scapy fallback. @@ -279,7 +278,7 @@ def check_for_wps_and_update_targets(cls, capfile, targets): lines = p.stdout() except KeyboardInterrupt: raise - except (OSError, IOError) as e: + except OSError as e: from ..config import Configuration if Configuration.verbose > 0: from ..util.color import Color @@ -443,7 +442,7 @@ def read_frame(self): 'bssid': fields[4] if len(fields) > 4 else '', 'channel': fields[5] if len(fields) > 5 else '' } - except (OSError, IOError): + except OSError: return None def stop(self): @@ -476,4 +475,4 @@ def stop(self): if targets[0].wps != WPSState.UNLOCKED: raise ValueError(f'Expected WPSState.UNLOCKED, got {targets[0].wps}') - print((Tshark.bssids_with_handshakes(test_file, bssid=target_bssid))) + print(Tshark.bssids_with_handshakes(test_file, bssid=target_bssid)) diff --git a/wifite/tools/wash.py b/wifite/tools/wash.py index 4cd98d8ea..7b36b47d3 100755 --- a/wifite/tools/wash.py +++ b/wifite/tools/wash.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import json diff --git a/wifite/tools/wlancap2wpasec.py b/wifite/tools/wlancap2wpasec.py index 4ef3bf38e..545bb7125 100755 --- a/wifite/tools/wlancap2wpasec.py +++ b/wifite/tools/wlancap2wpasec.py @@ -1,11 +1,9 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import os import re from .dependency import Dependency from ..util.process import Process -from ..util.color import Color class Wlancap2wpasec(Dependency): diff --git a/wifite/ui/__init__.py b/wifite/ui/__init__.py index 517edf60d..c48bb5151 100755 --- a/wifite/ui/__init__.py +++ b/wifite/ui/__init__.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ UI package for wifite2 diff --git a/wifite/ui/attack_view.py b/wifite/ui/attack_view.py index 7f1a7c800..b8d0f5241 100755 --- a/wifite/ui/attack_view.py +++ b/wifite/ui/attack_view.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Attack View for wifite2 TUI. @@ -7,7 +6,7 @@ """ import time -from typing import Optional, Dict, Any +from typing import Any from rich.layout import Layout from rich.panel import Panel from rich.table import Table @@ -56,7 +55,6 @@ def start(self): def stop(self): """Stop the attack view.""" # View cleanup if needed - pass def set_attack_type(self, attack_type: str): """ @@ -68,7 +66,7 @@ def set_attack_type(self, attack_type: str): self.attack_type = attack_type self._render() - def update_progress(self, progress_data: Dict[str, Any]): + def update_progress(self, progress_data: dict[str, Any]): """ Update attack progress with new data. @@ -292,7 +290,7 @@ def _render_footer(self) -> Panel: padding=(0, 1) ) - def handle_input(self, key: str) -> Optional[str]: + def handle_input(self, key: str) -> str | None: """ Handle keyboard input during attack. @@ -488,7 +486,7 @@ def __init__(self, tui_controller, target, session=None, target_state=None): self.pixie_dust_mode = False self.locked_out = False - def update_pin_attempts(self, pins_tried: int, total_pins: int = None, current_pin: Optional[str] = None): + def update_pin_attempts(self, pins_tried: int, total_pins: int = None, current_pin: str | None = None): """ Update WPS PIN attempt progress. @@ -509,7 +507,7 @@ def update_pin_attempts(self, pins_tried: int, total_pins: int = None, current_p status = "WPS locked out - attack stopped" progress = 0.0 elif self.pixie_dust_mode: - status = f'Pixie Dust attack in progress' + status = 'Pixie Dust attack in progress' progress = 0.5 # Indeterminate for pixie dust else: status = f'Testing PINs ({self.pins_tried:,}/{self.total_pins:,})' @@ -931,7 +929,7 @@ def _update_display(self): status = "SAE handshake captured (passive mode)!" progress = 1.0 else: - status = f"Passive capture (PMF required) - waiting for clients..." + status = "Passive capture (PMF required) - waiting for clients..." progress = 0.4 elif self.attack_strategy == "dragonblood": status = "Attempting Dragonblood vulnerability exploit..." @@ -1250,7 +1248,7 @@ def _update_display(self): deauths_per_min = (self.deauths_sent / elapsed * 60) if elapsed > 0 else 0 metrics['Deauths Sent'] = f'[white]{self.deauths_sent:,}[/white] ([dim]{deauths_per_min:.1f}/min[/dim])' else: - metrics['Deauths Sent'] = f'[dim]0[/dim]' + metrics['Deauths Sent'] = '[dim]0[/dim]' # Show adaptive interval if available if 'Deauth Interval' in self.metrics: diff --git a/wifite/ui/classic.py b/wifite/ui/classic.py index adc3d8e38..91f40b3be 100755 --- a/wifite/ui/classic.py +++ b/wifite/ui/classic.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Classic text output mode for wifite2 @@ -161,7 +160,7 @@ def update_progress(self, progress_data): - metrics: Dict of attack-specific metrics """ status = progress_data.get('status', '') - progress = progress_data.get('progress', 0) + progress_data.get('progress', 0) metrics = progress_data.get('metrics', {}) # Print status diff --git a/wifite/ui/components.py b/wifite/ui/components.py index 6128416b3..d0f0132f4 100755 --- a/wifite/ui/components.py +++ b/wifite/ui/components.py @@ -1,18 +1,14 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Reusable UI components for wifite2 TUI. Provides common visual elements used across different views. """ -from typing import List, Optional from rich.panel import Panel -from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn from rich.table import Table from rich.text import Text from rich.console import Group -from rich.style import Style class SignalStrengthBar: @@ -115,7 +111,7 @@ def render( progress_percent: float, status_message: str, metrics: dict, - total_time: Optional[int] = None + total_time: int | None = None ) -> Panel: """ Render attack progress panel with status and metrics. @@ -136,9 +132,9 @@ def render( # Create header header = Text() - header.append(f"Attack: ", style="bold") + header.append("Attack: ", style="bold") header.append(f"{attack_type}\n", style="cyan") - header.append(f"Elapsed: ", style="bold") + header.append("Elapsed: ", style="bold") header.append(f"{elapsed_str}", style="white") if total_time: @@ -208,7 +204,7 @@ def __init__(self, max_entries: int = 1000): max_entries: Maximum number of log entries to keep """ self.max_entries = max_entries - self.logs: List[str] = [] + self.logs: list[str] = [] self.auto_scroll = True def add_log(self, message: str): @@ -304,7 +300,7 @@ def render(context: str = "general") -> Panel: ) @staticmethod - def _get_shortcuts(context: str) -> List[tuple]: + def _get_shortcuts(context: str) -> list[tuple]: """ Get keyboard shortcuts for the given context. diff --git a/wifite/ui/scanner_view.py b/wifite/ui/scanner_view.py index e16d7851d..446fdef7b 100755 --- a/wifite/ui/scanner_view.py +++ b/wifite/ui/scanner_view.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Scanner View for wifite2 TUI. @@ -7,7 +6,6 @@ """ import time -from typing import List, Optional from rich.layout import Layout from rich.panel import Panel from rich.table import Table @@ -35,7 +33,7 @@ def __init__(self, tui_controller, session=None): self.max_visible_targets = 50 # Limit displayed targets for performance self.session = session # Store session for resume status display - def update_targets(self, targets: List, decloaking: bool = False): + def update_targets(self, targets: list, decloaking: bool = False): """ Update target list and refresh display. @@ -100,7 +98,7 @@ def _render_header(self) -> Panel: # Add session progress info summary = self.session.get_progress_summary() - header.append(f" | Progress: ", style="white") + header.append(" | Progress: ", style="white") header.append(f"{summary['completed']}", style="green") header.append("/", style="white") header.append(f"{summary['total']}", style="cyan") @@ -113,7 +111,7 @@ def _render_header(self) -> Panel: age_str = f"{int(age_hours)}h" else: age_str = f"{int(age_hours / 24)}d" - header.append(f" | Age: ", style="white") + header.append(" | Age: ", style="white") header.append(age_str, style="yellow") else: header.append("- Scanning", style="bold yellow") @@ -121,17 +119,17 @@ def _render_header(self) -> Panel: if self.decloaking: header.append(" & decloaking", style="yellow") header.append(f" {minutes:02d}:{seconds:02d} | ", style="white") - header.append(f"Targets: ", style="white") + header.append("Targets: ", style="white") header.append(f"{len(self.targets)}", style="bold green") - header.append(f" | WEP: ", style="white") + header.append(" | WEP: ", style="white") header.append(f"{wep_count}", style="red") - header.append(f" | WPA: ", style="white") + header.append(" | WPA: ", style="white") header.append(f"{wpa_count}", style="yellow") - header.append(f" | WPA3: ", style="white") + header.append(" | WPA3: ", style="white") header.append(f"{wpa3_count}", style="magenta") - header.append(f" | WPS: ", style="white") + header.append(" | WPS: ", style="white") header.append(f"{wps_count}", style="cyan") - header.append(f" | Clients: ", style="white") + header.append(" | Clients: ", style="white") header.append(f"{client_count}", style="green") # Honeypot stats @@ -139,7 +137,7 @@ def _render_header(self) -> Panel: if Configuration.detect_honeypots: hp_count = sum(1 for t in self.targets if getattr(t, 'honeypot_score', 0) >= 50) if hp_count > 0: - header.append(f" | Honeypots: ", style="white") + header.append(" | Honeypots: ", style="white") header.append(f"{hp_count}", style="red bold") return Panel( @@ -413,7 +411,7 @@ def _render_footer(self) -> Panel: padding=(0, 1) ) - def handle_input(self, key: str) -> Optional[str]: + def handle_input(self, key: str) -> str | None: """ Handle keyboard input during scanning. @@ -450,7 +448,6 @@ def show_help(self): def stop(self): """Stop the scanner view and clean up.""" # Any cleanup needed when stopping the view - pass def _calculate_max_visible_targets(self) -> int: """ diff --git a/wifite/ui/selector_view.py b/wifite/ui/selector_view.py index b93fb47de..a6c04fbac 100755 --- a/wifite/ui/selector_view.py +++ b/wifite/ui/selector_view.py @@ -1,12 +1,10 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Selector View for wifite2 TUI. Interactive target selection interface with keyboard navigation. """ -from typing import List, Set, Optional from rich.layout import Layout from rich.panel import Panel from rich.table import Table @@ -20,7 +18,7 @@ class SelectorView: """Interactive target selection interface with keyboard navigation.""" - def __init__(self, tui_controller, targets: List): + def __init__(self, tui_controller, targets: list): """ Initialize selector view. @@ -30,13 +28,13 @@ def __init__(self, tui_controller, targets: List): """ self.tui = tui_controller self.targets = targets - self.selected: Set[int] = set() # Set of selected target indices + self.selected: set[int] = set() # Set of selected target indices self.cursor = 0 # Current cursor position self.scroll_offset = 0 # For scrolling through long lists # Dynamic max rows based on terminal height (leave room for header/footer) self.max_visible_rows = self._calculate_max_visible_rows() - def run(self) -> List: + def run(self) -> list: """ Run the interactive selector and return selected targets. @@ -74,7 +72,7 @@ def run(self) -> List: # Clean up pass - def handle_input(self, key: str) -> Optional[str]: + def handle_input(self, key: str) -> str | None: """ Handle keyboard input for navigation and selection. @@ -163,7 +161,7 @@ def _select_none(self): """Deselect all targets.""" self.selected.clear() - def get_selected_targets(self) -> List: + def get_selected_targets(self) -> list: """ Get list of selected targets. diff --git a/wifite/ui/tui.py b/wifite/ui/tui.py index cb26061d1..f419459f9 100755 --- a/wifite/ui/tui.py +++ b/wifite/ui/tui.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ TUI Controller for wifite2 using the rich library. @@ -8,7 +7,6 @@ import time import signal -from typing import Optional from rich.console import Console from rich.live import Live from ..util.tui_logger import TUILogger, log_tui_event, log_tui_error, log_tui_debug @@ -27,7 +25,7 @@ class TUIController: def __init__(self): """Initialize TUI controller with rich Console and Live display.""" self.console = Console() - self.live: Optional[Live] = None + self.live: Live | None = None self.is_running = False self.last_update = 0 self.min_update_interval = 0.05 # 50ms minimum between updates (was 100ms) diff --git a/wifite/util/adaptive_deauth.py b/wifite/util/adaptive_deauth.py index 7a08df78e..2e50f0fc8 100755 --- a/wifite/util/adaptive_deauth.py +++ b/wifite/util/adaptive_deauth.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Adaptive deauthentication manager for Evil Twin attacks. @@ -9,8 +8,7 @@ """ import time -from typing import Optional -from ..util.logger import log_info, log_debug, log_warning +from ..util.logger import log_info, log_debug class AdaptiveDeauthManager: diff --git a/wifite/util/cleanup.py b/wifite/util/cleanup.py index 4b716c6c9..ac50254b3 100755 --- a/wifite/util/cleanup.py +++ b/wifite/util/cleanup.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Cleanup utilities for Evil Twin attacks. @@ -15,7 +14,6 @@ import re import signal import subprocess -from typing import List, Optional, Tuple from .process import Process from .color import Color @@ -70,7 +68,7 @@ def register_interface(self, interface: str, original_state: dict): self.interfaces_to_restore.append((interface, original_state)) log_debug('Cleanup', f'Registered interface for cleanup: {interface}') - def register_iptables_rule(self, table: str, chain: str, rule: List[str]): + def register_iptables_rule(self, table: str, chain: str, rule: list[str]): """ Register an iptables rule for removal. @@ -221,7 +219,7 @@ def restore_all_interfaces(self): self.interfaces_to_restore = [] - def remove_iptables_rule(self, table: str, chain: str, rule: List[str]) -> bool: + def remove_iptables_rule(self, table: str, chain: str, rule: list[str]) -> bool: """ Remove an iptables rule. @@ -331,7 +329,7 @@ def cleanup_all(self, display_status: bool = True) -> bool: log_info('Cleanup', 'Cleanup completed successfully') return True - def get_errors(self) -> List[str]: + def get_errors(self) -> list[str]: """ Get list of cleanup errors. @@ -341,7 +339,7 @@ def get_errors(self) -> List[str]: return self.cleanup_errors.copy() -def kill_orphaned_processes() -> List[Tuple[str, str]]: +def kill_orphaned_processes() -> list[tuple[str, str]]: """ Find and kill orphaned processes from previous Evil Twin attacks. @@ -400,7 +398,7 @@ def kill_orphaned_processes() -> List[Tuple[str, str]]: return killed_processes -def check_conflicting_processes() -> List[Tuple[str, str]]: +def check_conflicting_processes() -> list[tuple[str, str]]: """ Check for processes that may conflict with Evil Twin attack. diff --git a/wifite/util/client_monitor.py b/wifite/util/client_monitor.py index 00ed4f0a8..717a2bca9 100755 --- a/wifite/util/client_monitor.py +++ b/wifite/util/client_monitor.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Client monitoring system for Evil Twin attacks. @@ -13,9 +12,8 @@ import time import re from threading import Thread, Lock -from typing import Dict, List, Optional, Callable +from collections.abc import Callable from dataclasses import dataclass, field -from datetime import datetime @dataclass @@ -27,7 +25,7 @@ class AttackStatistics: and attack duration. """ start_time: float = field(default_factory=time.time) - end_time: Optional[float] = None + end_time: float | None = None # Client statistics total_clients_connected: int = 0 @@ -40,9 +38,9 @@ class AttackStatistics: failed_attempts: int = 0 # Timing statistics - first_client_time: Optional[float] = None - first_credential_time: Optional[float] = None - success_time: Optional[float] = None + first_client_time: float | None = None + first_credential_time: float | None = None + success_time: float | None = None def record_client_connect(self, mac_address: str): """Record a client connection.""" @@ -93,7 +91,7 @@ def get_duration(self) -> float: end = self.end_time or time.time() return end - self.start_time - def get_time_to_first_client(self) -> Optional[float]: + def get_time_to_first_client(self) -> float | None: """ Get time until first client connected. @@ -104,7 +102,7 @@ def get_time_to_first_client(self) -> Optional[float]: return None return self.first_client_time - self.start_time - def get_time_to_first_credential(self) -> Optional[float]: + def get_time_to_first_credential(self) -> float | None: """ Get time until first credential attempt. @@ -115,7 +113,7 @@ def get_time_to_first_credential(self) -> Optional[float]: return None return self.first_credential_time - self.start_time - def get_time_to_success(self) -> Optional[float]: + def get_time_to_success(self) -> float | None: """ Get time until successful credential capture. @@ -180,12 +178,12 @@ class ClientConnection: credential submission status. """ mac_address: str - ip_address: Optional[str] = None - hostname: Optional[str] = None + ip_address: str | None = None + hostname: str | None = None connect_time: float = field(default_factory=time.time) - disconnect_time: Optional[float] = None + disconnect_time: float | None = None credential_submitted: bool = False - credential_valid: Optional[bool] = None + credential_valid: bool | None = None last_seen: float = field(default_factory=time.time) def is_connected(self) -> bool: @@ -226,13 +224,13 @@ def __init__(self, hostapd_log_path: str = None, dnsmasq_log_path: str = None): self.dnsmasq_log_path = dnsmasq_log_path # Client tracking - self.clients: Dict[str, ClientConnection] = {} + self.clients: dict[str, ClientConnection] = {} self.clients_lock = Lock() # Callbacks - self.on_client_connect: Optional[Callable[[ClientConnection], None]] = None - self.on_client_disconnect: Optional[Callable[[ClientConnection], None]] = None - self.on_client_dhcp: Optional[Callable[[ClientConnection], None]] = None + self.on_client_connect: Callable[[ClientConnection], None] | None = None + self.on_client_disconnect: Callable[[ClientConnection], None] | None = None + self.on_client_dhcp: Callable[[ClientConnection], None] | None = None # Monitoring state self.running = False @@ -273,7 +271,7 @@ def run(self): def _monitor_hostapd_log(self): """Monitor hostapd log for client events.""" try: - with open(self.hostapd_log_path, 'r') as f: + with open(self.hostapd_log_path) as f: # Seek to last position f.seek(self.hostapd_file_pos) @@ -349,7 +347,7 @@ def _parse_hostapd_line(self, line: str): def _monitor_dnsmasq_log(self): """Monitor dnsmasq log for DHCP leases.""" try: - with open(self.dnsmasq_log_path, 'r') as f: + with open(self.dnsmasq_log_path) as f: # Seek to last position f.seek(self.dnsmasq_file_pos) @@ -459,7 +457,7 @@ def _handle_client_disconnect(self, mac: str): from ..util.logger import log_error log_error('ClientMonitor', f'Error in disconnect callback: {e}', e) - def _handle_client_dhcp(self, mac: str, ip: str, hostname: Optional[str]): + def _handle_client_dhcp(self, mac: str, ip: str, hostname: str | None): """Handle DHCP lease event.""" with self.clients_lock: if mac in self.clients: @@ -499,7 +497,7 @@ def _cleanup_old_clients(self, max_age: int = 3600): for mac in to_remove: del self.clients[mac] - def get_connected_clients(self) -> List[ClientConnection]: + def get_connected_clients(self) -> list[ClientConnection]: """ Get list of currently connected clients. @@ -509,7 +507,7 @@ def get_connected_clients(self) -> List[ClientConnection]: with self.clients_lock: return [client for client in self.clients.values() if client.is_connected()] - def get_all_clients(self) -> List[ClientConnection]: + def get_all_clients(self) -> list[ClientConnection]: """ Get list of all clients (connected and disconnected). @@ -519,7 +517,7 @@ def get_all_clients(self) -> List[ClientConnection]: with self.clients_lock: return list(self.clients.values()) - def get_client(self, mac: str) -> Optional[ClientConnection]: + def get_client(self, mac: str) -> ClientConnection | None: """ Get client by MAC address. diff --git a/wifite/util/color.py b/wifite/util/color.py index b48b62e92..c3a8061ef 100755 --- a/wifite/util/color.py +++ b/wifite/util/color.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import sys @@ -132,6 +131,6 @@ def pexception(exception): if __name__ == '__main__': Color.pl('{R}Testing{G}One{C}Two{P}Three{W}Done') - print((Color.s('{C}Testing{P}String{W}'))) + print(Color.s('{C}Testing{P}String{W}')) Color.pl('{+} Good line') Color.pl('{!} Danger') diff --git a/wifite/util/crack.py b/wifite/util/crack.py index b44210211..ac4d1aa25 100755 --- a/wifite/util/crack.py +++ b/wifite/util/crack.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import os from json import loads @@ -252,7 +251,7 @@ def get_handshakes(cls): continue # Extract parts: name is first, bssid and date are last two - name = parts[0] + parts[0] date = parts[-1] bssid = parts[-2] # Everything in between is the ESSID (may contain underscores) @@ -335,7 +334,7 @@ def get_user_selection(cls, handshakes): selection = [] for choice in choices.split(','): if '-' in choice: - first, last = [int(x) for x in choice.split('-')] + first, last = (int(x) for x in choice.split('-')) for index in range(first, last + 1): selection.append(handshakes[index - 1]) elif choice.strip().lower() == 'all': diff --git a/wifite/util/credential_validator.py b/wifite/util/credential_validator.py index bbec5978a..07b3b075c 100755 --- a/wifite/util/credential_validator.py +++ b/wifite/util/credential_validator.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Credential validator for Evil Twin attacks. @@ -11,13 +10,11 @@ import time import tempfile import threading -from typing import Optional, Tuple, Dict from queue import Queue, Empty from ..tools.dependency import Dependency from ..config import Configuration from ..util.process import Process -from ..util.color import Color from ..util.logger import log_info, log_error, log_warning, log_debug @@ -115,7 +112,7 @@ def stop(self): log_info('CredentialValidator', 'Validation thread stopped') - def validate_credentials(self, ssid: str, password: str, timeout=30) -> Tuple[bool, float, Optional[str]]: + def validate_credentials(self, ssid: str, password: str, timeout=30) -> tuple[bool, float, str | None]: """ Validate credentials against the legitimate AP. @@ -376,7 +373,7 @@ def _channel_to_freq(self, channel: int) -> int: else: return 2412 # Default to channel 1 - def _check_cache(self, ssid: str, password: str) -> Optional[bool]: + def _check_cache(self, ssid: str, password: str) -> bool | None: """ Check if result is in cache. @@ -552,7 +549,7 @@ def _log_validation_attempt(self, ssid: str, password: str): f'{self.failed_attempt_count} total failures, ' f'backoff: {self.backoff_multiplier:.1f}x') - def _log_validation_result(self, ssid: str, is_valid: bool, validation_time: float, error_message: Optional[str]): + def _log_validation_result(self, ssid: str, is_valid: bool, validation_time: float, error_message: str | None): """ Log validation result with details. @@ -586,7 +583,7 @@ def _cleanup_temp_files(self): for file_path in self.temp_files[:]: self._remove_temp_file(file_path) - def get_statistics(self) -> Dict: + def get_statistics(self) -> dict: """ Get validation statistics. diff --git a/wifite/util/dragonblood.py b/wifite/util/dragonblood.py index 9be80678a..edfaa8b07 100755 --- a/wifite/util/dragonblood.py +++ b/wifite/util/dragonblood.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Dragonblood Vulnerability Detection @@ -18,7 +17,6 @@ - https://papers.mathyvanhoef.com/dragonblood.pdf """ -from typing import Dict, List, Optional from ..util.color import Color @@ -61,7 +59,7 @@ class DragonbloodDetector: } @staticmethod - def check_vulnerability(wpa3_info: Dict) -> Dict: + def check_vulnerability(wpa3_info: dict) -> dict: """ Check if a WPA3 network is potentially vulnerable to Dragonblood. @@ -149,7 +147,7 @@ def check_vulnerability(wpa3_info: Dict) -> Dict: @staticmethod def print_vulnerability_report(target_essid: str, target_bssid: str, - vulnerability_info: Dict, verbose: bool = False): + vulnerability_info: dict, verbose: bool = False): """ Print a formatted vulnerability report. @@ -203,12 +201,12 @@ def is_group_weak(group_id: int) -> bool: return group_id in DragonbloodDetector.WEAK_SAE_GROUPS @staticmethod - def get_secure_groups() -> List[int]: + def get_secure_groups() -> list[int]: """Get list of recommended secure SAE groups.""" return list(DragonbloodDetector.SECURE_SAE_GROUPS.keys()) @staticmethod - def is_timing_attack_viable(wpa3_info: Dict) -> bool: + def is_timing_attack_viable(wpa3_info: dict) -> bool: """ Check whether the Dragonblood timing attack is worth attempting. @@ -228,8 +226,8 @@ def is_timing_attack_viable(wpa3_info: Dict) -> bool: return bool(modp_vulnerable.intersection(sae_groups)) @staticmethod - def enrich_with_timing(vulnerability_info: Dict, - timing_analysis) -> Dict: + def enrich_with_timing(vulnerability_info: dict, + timing_analysis) -> dict: """ Merge timing-attack results into an existing vulnerability report. @@ -300,7 +298,7 @@ def print_timing_report(timing_analysis) -> None: (timing_analysis.confidence * 100)) @staticmethod - def scan_mode_check(targets: List) -> Dict: + def scan_mode_check(targets: list) -> dict: """ Scan multiple targets for Dragonblood vulnerabilities. @@ -339,7 +337,7 @@ def scan_mode_check(targets: List) -> Dict: return results @staticmethod - def print_scan_summary(scan_results: Dict): + def print_scan_summary(scan_results: dict): """Print summary of vulnerability scan.""" Color.pl('\n{+} {C}Dragonblood Vulnerability Scan Summary{W}') Color.pl('{+} Networks checked: {G}%d{W}' % scan_results['total_checked']) diff --git a/wifite/util/dragonblood_scanner.py b/wifite/util/dragonblood_scanner.py index 93e7af59d..dc4357d78 100755 --- a/wifite/util/dragonblood_scanner.py +++ b/wifite/util/dragonblood_scanner.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Dragonblood Scanner diff --git a/wifite/util/dragonblood_timing.py b/wifite/util/dragonblood_timing.py index aa7e80f2b..3dd6f1e00 100644 --- a/wifite/util/dragonblood_timing.py +++ b/wifite/util/dragonblood_timing.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Dragonblood Timing Attack Implementation (CVE-2019-13377) @@ -26,7 +25,6 @@ import time import tempfile import statistics -from typing import List, Dict, Optional, Tuple from dataclasses import dataclass, field from ..util.process import Process @@ -57,8 +55,8 @@ class TimingAnalysis: median_us: float = 0.0 stdev_us: float = 0.0 threshold_us: float = 0.0 # dividing line between fast/slow - fast_passwords: List[str] = field(default_factory=list) - slow_passwords: List[str] = field(default_factory=list) + fast_passwords: list[str] = field(default_factory=list) + slow_passwords: list[str] = field(default_factory=list) confidence: float = 0.0 # 0.0-1.0, how separable the two clusters are partition_ratio: float = 0.0 # fraction of passwords in the fast bucket @@ -106,17 +104,17 @@ def __init__(self, interface: str, target_bssid: str, target_essid: str, self.target_channel = target_channel self.sae_group = sae_group - self.samples: List[TimingSample] = [] - self.analysis: Optional[TimingAnalysis] = None - self._temp_files: List[str] = [] + self.samples: list[TimingSample] = [] + self.analysis: TimingAnalysis | None = None + self._temp_files: list[str] = [] # ------------------------------------------------------------------ # Public API # ------------------------------------------------------------------ - def run(self, passwords: List[str], + def run(self, passwords: list[str], num_samples: int = 3, - view=None) -> Optional[TimingAnalysis]: + view=None) -> TimingAnalysis | None: """ Run timing probes against the target AP. @@ -197,8 +195,8 @@ def run(self, passwords: List[str], return self.analysis def get_prioritised_wordlist(self, wordlist_path: str, - output_path: Optional[str] = None - ) -> Optional[str]: + output_path: str | None = None + ) -> str | None: """ Reorder a wordlist so that timing-fast candidates appear first. @@ -231,7 +229,7 @@ def get_prioritised_wordlist(self, wordlist_path: str, # First pass: separate fast and slow fast_lines = [] slow_lines = [] - with open(wordlist_path, 'r', errors='replace') as fh: + with open(wordlist_path, errors='replace') as fh: for line in fh: word = line.rstrip('\n\r') if word in fast_set: @@ -275,7 +273,7 @@ def cleanup(self): # Timing probe via wpa_supplicant # ------------------------------------------------------------------ - def _probe_password(self, password: str) -> Optional[float]: + def _probe_password(self, password: str) -> float | None: """ Send a single SAE Commit probe and measure AP response time. @@ -291,7 +289,7 @@ def _probe_password(self, password: str) -> Optional[float]: finally: self._remove_temp(config_file) - def _measure_sae_timing(self, config_file: str) -> Optional[float]: + def _measure_sae_timing(self, config_file: str) -> float | None: """ Run wpa_supplicant briefly and measure the SAE commit->response latency. @@ -392,7 +390,7 @@ def _measure_sae_timing(self, config_file: str) -> Optional[float]: return None @classmethod - def _parse_log_timestamp(cls, line: str) -> Optional[float]: + def _parse_log_timestamp(cls, line: str) -> float | None: """Parse the leading epoch timestamp wpa_supplicant emits with ``-t``. Returns the timestamp in seconds (float) or None if the line has no @@ -475,7 +473,7 @@ def _analyse(self) -> TimingAnalysis: return analysis # Compute per-password average response times - pwd_times: Dict[str, List[float]] = {} + pwd_times: dict[str, list[float]] = {} for s in self.samples: pwd_times.setdefault(s.password, []).append(s.response_time_us) pwd_avg = {p: statistics.mean(ts) for p, ts in pwd_times.items()} @@ -568,7 +566,7 @@ def print_report(self): @staticmethod def extract_timing_from_pcap(capfile: str, bssid: str - ) -> List[Dict]: + ) -> list[dict]: """ Extract SAE Commit/Confirm frame timestamps from a pcap file. @@ -631,8 +629,8 @@ def extract_timing_from_pcap(capfile: str, bssid: str return [] @staticmethod - def compute_pcap_response_times(frames: List[Dict], ap_bssid: str - ) -> List[float]: + def compute_pcap_response_times(frames: list[dict], ap_bssid: str + ) -> list[float]: """ Compute AP response latencies from extracted pcap frame pairs. diff --git a/wifite/util/honeypot_detector.py b/wifite/util/honeypot_detector.py index c1253fa52..474b1a95c 100644 --- a/wifite/util/honeypot_detector.py +++ b/wifite/util/honeypot_detector.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Honeypot / Rogue AP detector for wifite2. diff --git a/wifite/util/input.py b/wifite/util/input.py index 337018999..86ba1076e 100755 --- a/wifite/util/input.py +++ b/wifite/util/input.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Keyboard input handling for wifite2 TUI. @@ -10,7 +9,6 @@ import select import termios import tty -from typing import Optional class KeyboardInput: @@ -33,7 +31,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings) return False - def get_key(self, timeout: float = 0.0) -> Optional[str]: + def get_key(self, timeout: float = 0.0) -> str | None: """ Get a single keypress with optional timeout. @@ -149,7 +147,7 @@ def has_input(timeout: float = 0.0) -> bool: return bool(ready) @staticmethod - def read_line(timeout: float = 0.0) -> Optional[str]: + def read_line(timeout: float = 0.0) -> str | None: """ Read a line of input with optional timeout. diff --git a/wifite/util/interface_assignment.py b/wifite/util/interface_assignment.py index b9e2f3422..db0a236d1 100755 --- a/wifite/util/interface_assignment.py +++ b/wifite/util/interface_assignment.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Interface assignment strategy for dual wireless device support. @@ -8,10 +7,9 @@ selecting the best interfaces based on capabilities and preferences. """ -from typing import List, Optional, Tuple, Dict from ..model.interface_info import InterfaceInfo, InterfaceAssignment -from ..util.logger import log_info, log_debug, log_warning +from ..util.logger import log_info, log_debug, log_warning, log_error class InterfaceAssignmentStrategy: @@ -44,7 +42,7 @@ class InterfaceAssignmentStrategy: ] @staticmethod - def assign_for_evil_twin(interfaces: List[InterfaceInfo]) -> Optional[InterfaceAssignment]: + def assign_for_evil_twin(interfaces: list[InterfaceInfo]) -> InterfaceAssignment | None: """ Assign interfaces for Evil Twin attack. @@ -162,7 +160,7 @@ def assign_for_evil_twin(interfaces: List[InterfaceInfo]) -> Optional[InterfaceA # Task 11.2: Log fallback to single interface if applicable log_info('InterfaceAssignment', 'Falling back to single interface mode') log_info('InterfaceAssignment', - f'Rationale: Insufficient interfaces for dual mode (need 1 AP-capable + 1 additional monitor-capable)') + 'Rationale: Insufficient interfaces for dual mode (need 1 AP-capable + 1 additional monitor-capable)') # Select best AP-capable interface ap_interface = InterfaceAssignmentStrategy._select_best_ap_interface(ap_capable) @@ -195,7 +193,7 @@ def assign_for_evil_twin(interfaces: List[InterfaceInfo]) -> Optional[InterfaceA ) @staticmethod - def assign_for_wpa(interfaces: List[InterfaceInfo]) -> Optional[InterfaceAssignment]: + def assign_for_wpa(interfaces: list[InterfaceInfo]) -> InterfaceAssignment | None: """ Assign interfaces for WPA handshake capture attack. @@ -315,7 +313,7 @@ def assign_for_wpa(interfaces: List[InterfaceInfo]) -> Optional[InterfaceAssignm # Task 11.2: Log fallback to single interface if applicable log_info('InterfaceAssignment', 'Falling back to single interface mode') log_info('InterfaceAssignment', - f'Rationale: Insufficient interfaces for dual mode (need 2 monitor-capable)') + 'Rationale: Insufficient interfaces for dual mode (need 2 monitor-capable)') # Select best monitor-capable interface monitor_interface = InterfaceAssignmentStrategy._select_best_monitor_interface( @@ -350,7 +348,7 @@ def assign_for_wpa(interfaces: List[InterfaceInfo]) -> Optional[InterfaceAssignm ) @staticmethod - def assign_for_wps(interfaces: List[InterfaceInfo]) -> Optional[InterfaceAssignment]: + def assign_for_wps(interfaces: list[InterfaceInfo]) -> InterfaceAssignment | None: """ Assign interfaces for WPS attack. @@ -440,7 +438,7 @@ def assign_for_wps(interfaces: List[InterfaceInfo]) -> Optional[InterfaceAssignm return assignment @staticmethod - def _select_best_ap_interface(candidates: List[InterfaceInfo]) -> InterfaceInfo: + def _select_best_ap_interface(candidates: list[InterfaceInfo]) -> InterfaceInfo: """ Select the best interface for AP mode from candidates. @@ -504,7 +502,7 @@ def _select_best_ap_interface(candidates: List[InterfaceInfo]) -> InterfaceInfo: return best_interface @staticmethod - def _select_best_monitor_interface(candidates: List[InterfaceInfo]) -> InterfaceInfo: + def _select_best_monitor_interface(candidates: list[InterfaceInfo]) -> InterfaceInfo: """ Select the best interface for monitor mode from candidates. @@ -569,7 +567,7 @@ def _select_best_monitor_interface(candidates: List[InterfaceInfo]) -> Interface @staticmethod def validate_dual_interface_setup(primary: InterfaceInfo, - secondary: InterfaceInfo) -> Tuple[bool, str]: + secondary: InterfaceInfo) -> tuple[bool, str]: """ Validate that two interfaces can work together in dual interface mode. @@ -630,7 +628,7 @@ def validate_dual_interface_setup(primary: InterfaceInfo, return True, '' @staticmethod - def get_assignment_recommendations(interfaces: List[InterfaceInfo]) -> Dict[str, Optional[InterfaceAssignment]]: + def get_assignment_recommendations(interfaces: list[InterfaceInfo]) -> dict[str, InterfaceAssignment | None]: """ Get recommended interface assignments for all attack types. diff --git a/wifite/util/interface_exceptions.py b/wifite/util/interface_exceptions.py index 6a3955b8d..7fdbb9e9a 100755 --- a/wifite/util/interface_exceptions.py +++ b/wifite/util/interface_exceptions.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Custom exception classes for interface-related errors. @@ -55,7 +54,7 @@ def __init__(self, interface_name: str = None, message: str = None): """ if message is None: if interface_name: - message = f"Interface not found or not available" + message = "Interface not found or not available" else: message = "No wireless interfaces found on system" diff --git a/wifite/util/interface_manager.py b/wifite/util/interface_manager.py index a6895b087..c9b92c914 100755 --- a/wifite/util/interface_manager.py +++ b/wifite/util/interface_manager.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Network interface management for Evil Twin attacks. @@ -10,7 +9,6 @@ import os import re -from typing import Optional, List, Tuple, Dict from dataclasses import dataclass from ..tools.iw import Iw @@ -34,8 +32,8 @@ class InterfaceState: name: str # Interface name original_mode: str # Original mode (managed, monitor, AP, etc.) original_up: bool # Whether interface was originally up - original_mac: Optional[str] # Original MAC address - original_channel: Optional[int] # Original channel + original_mac: str | None # Original MAC address + original_channel: int | None # Original channel current_mode: str # Current mode current_up: bool # Current up/down state managed_by_wifite: bool = True # Whether wifite is managing this interface @@ -135,16 +133,16 @@ class InterfaceManager: def __init__(self): # Track interface states for cleanup (interface_name -> InterfaceState) - self.interface_states: Dict[str, InterfaceState] = {} + self.interface_states: dict[str, InterfaceState] = {} # Track assigned IP addresses (interface_name -> ip_address) - self.assigned_ips: Dict[str, str] = {} + self.assigned_ips: dict[str, str] = {} # Legacy compatibility - maps to interface_states self.managed_interfaces = {} # Deprecated, kept for compatibility @staticmethod - def _execute_verbose(command: List[str], description: str = None) -> Optional[str]: + def _execute_verbose(command: list[str], description: str = None) -> str | None: """ Execute a command with verbose logging support. @@ -236,8 +234,8 @@ def _save_interface_state(self, interface: str) -> bool: log_error('InterfaceManager', f'Failed to save state for {interface}: {e}', e) return False - def _update_interface_state(self, interface: str, mode: Optional[str] = None, - up: Optional[bool] = None) -> bool: + def _update_interface_state(self, interface: str, mode: str | None = None, + up: bool | None = None) -> bool: """ Update the tracked state of an interface after making changes. @@ -292,7 +290,7 @@ def is_managed(self, interface: str) -> bool: return interface in self.interface_states and \ self.interface_states[interface].managed_by_wifite - def get_managed_interfaces(self) -> List[str]: + def get_managed_interfaces(self) -> list[str]: """ Get list of all interfaces currently managed by wifite. @@ -495,8 +493,8 @@ def set_interface_channel(self, interface: str, channel: int) -> bool: log_error('InterfaceManager', f'Configuration result: FAILED - Could not set {interface} to channel {channel}: {e}', e) return False - def configure_interface(self, interface: str, mode: Optional[str] = None, - channel: Optional[int] = None, up: Optional[bool] = None) -> bool: + def configure_interface(self, interface: str, mode: str | None = None, + channel: int | None = None, up: bool | None = None) -> bool: """ Configure multiple aspects of an interface at once. @@ -552,7 +550,7 @@ def configure_interface(self, interface: str, mode: Optional[str] = None, return False @staticmethod - def get_wireless_interfaces() -> List[str]: + def get_wireless_interfaces() -> list[str]: """ Get list of all wireless interfaces. @@ -585,7 +583,7 @@ def get_wireless_interfaces() -> List[str]: return [] @staticmethod - def get_ap_capable_interfaces() -> List[InterfaceCapabilities]: + def get_ap_capable_interfaces() -> list[InterfaceCapabilities]: """ Get list of interfaces that support AP mode. @@ -771,12 +769,12 @@ def restore_interface_mode(self, interface: str) -> bool: # Don't restore to AP mode (security consideration) if original_mode == 'AP': original_mode = 'managed' - log_debug('InterfaceManager', f'Changing AP mode to managed for safety') + log_debug('InterfaceManager', 'Changing AP mode to managed for safety') # Don't restore to unknown mode (invalid) if original_mode == 'unknown': original_mode = 'managed' - log_debug('InterfaceManager', f'Changing unknown mode to managed for safety') + log_debug('InterfaceManager', 'Changing unknown mode to managed for safety') # Set mode return self.set_interface_mode(interface, original_mode) @@ -858,7 +856,7 @@ def restore_interface(self, interface: str) -> bool: # Task 11.4: Log detailed error information and recovery attempts log_error('InterfaceManager', f'Error during cleanup: Failed to bring {interface} down', e) log_warning('InterfaceManager', f'System error: {str(e)}') - log_info('InterfaceManager', f'Recovery attempt: Continuing with restoration despite error') + log_info('InterfaceManager', 'Recovery attempt: Continuing with restoration despite error') recovery_attempts.append(f'bring_down: {str(e)}') success = False @@ -871,7 +869,7 @@ def restore_interface(self, interface: str) -> bool: # Task 11.4: Log detailed error information log_warning('InterfaceManager', f'Error during cleanup: Failed to flush IP addresses on {interface}', e) log_warning('InterfaceManager', f'System error: {str(e)}') - log_info('InterfaceManager', f'Recovery attempt: Continuing (non-critical error)') + log_info('InterfaceManager', 'Recovery attempt: Continuing (non-critical error)') recovery_attempts.append(f'flush_ip: {str(e)}') # Not critical, continue @@ -879,11 +877,11 @@ def restore_interface(self, interface: str) -> bool: original_mode = state.original_mode if original_mode == 'AP': original_mode = 'managed' # Don't restore to AP mode - log_info('InterfaceManager', f'Security measure: Changing AP mode to managed for safety') + log_info('InterfaceManager', 'Security measure: Changing AP mode to managed for safety') if original_mode == 'unknown': original_mode = 'managed' # Don't restore to unknown mode - log_info('InterfaceManager', f'Safety measure: Changing unknown mode to managed') + log_info('InterfaceManager', 'Safety measure: Changing unknown mode to managed') try: log_info('InterfaceManager', f'Cleanup step: Restoring {interface} to {original_mode} mode') @@ -924,7 +922,7 @@ def restore_interface(self, interface: str) -> bool: # Task 11.4: Log detailed error information and recovery attempts log_error('InterfaceManager', f'Error during cleanup: Failed to restore mode for {interface}', e) log_warning('InterfaceManager', f'System error: {str(e)}') - log_info('InterfaceManager', f'Recovery attempt: Trying to set to managed mode as fallback') + log_info('InterfaceManager', 'Recovery attempt: Trying to set to managed mode as fallback') recovery_attempts.append(f'restore_mode: {str(e)}') # Try fallback to managed mode @@ -1091,7 +1089,7 @@ def cleanup_all(self) -> int: return success_count @staticmethod - def select_ap_interface(preferred=None) -> Optional[str]: + def select_ap_interface(preferred=None) -> str | None: """ Select an interface for AP mode. @@ -1370,7 +1368,7 @@ def _is_interface_connected(interface: str) -> bool: return False @staticmethod - def _get_interface_frequency(interface: str) -> Optional[float]: + def _get_interface_frequency(interface: str) -> float | None: """ Get current frequency of interface in MHz. @@ -1391,7 +1389,7 @@ def _get_interface_frequency(interface: str) -> Optional[float]: return None @staticmethod - def _get_interface_channel(interface: str) -> Optional[int]: + def _get_interface_channel(interface: str) -> int | None: """ Get current channel of interface. @@ -1412,7 +1410,7 @@ def _get_interface_channel(interface: str) -> Optional[int]: return None @staticmethod - def _get_interface_tx_power(interface: str) -> Optional[int]: + def _get_interface_tx_power(interface: str) -> int | None: """ Get TX power of interface in dBm. @@ -1548,7 +1546,6 @@ def test_monitor_mode(interface: str) -> bool: True if monitor mode can be enabled, False otherwise """ from ..tools.ip import Ip - from ..tools.iw import Iw import time try: @@ -1653,7 +1650,7 @@ def check_injection_support(interface: str) -> bool: return True @staticmethod - def get_available_interfaces() -> List[InterfaceInfo]: + def get_available_interfaces() -> list[InterfaceInfo]: """ Get all available wireless interfaces with their capabilities. @@ -1783,7 +1780,7 @@ def get_available_interfaces() -> List[InterfaceInfo]: return interfaces @staticmethod - def _get_interface_info(interface: str) -> Optional[InterfaceInfo]: + def _get_interface_info(interface: str) -> InterfaceInfo | None: """ Get comprehensive information about an interface. diff --git a/wifite/util/logger.py b/wifite/util/logger.py index 9ec3e6656..9030c3dbc 100755 --- a/wifite/util/logger.py +++ b/wifite/util/logger.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Centralized logging utility for wifite2. @@ -8,10 +7,8 @@ import os import sys -import time import traceback from datetime import datetime -from typing import Optional class Logger: @@ -48,7 +45,7 @@ def get_instance(cls): return cls._instance @classmethod - def initialize(cls, log_file: Optional[str] = None, verbose: int = 0, enabled: bool = True): + def initialize(cls, log_file: str | None = None, verbose: int = 0, enabled: bool = True): """ Initialize the logger with configuration. @@ -85,7 +82,7 @@ def initialize(cls, log_file: Optional[str] = None, verbose: int = 0, enabled: b f.write(f"\n{'='*80}\n") f.write(f"Wifite2 Log - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(f"{'='*80}\n") - except (OSError, IOError) as e: + except OSError as e: print(f"Warning: Could not create log file {log_file}: {e}", file=sys.stderr) cls._log_file = None @@ -211,7 +208,7 @@ def _write_to_file(cls, formatted_message: str): try: with open(cls._log_file, 'a') as f: f.write(formatted_message + '\n') - except (OSError, IOError) as e: + except OSError as e: # Can't log to file, print to stderr as fallback print(f"Log file write error: {e}", file=sys.stderr) @@ -252,7 +249,7 @@ def warning(cls, module: str, message: str): print(formatted, file=sys.stderr) @classmethod - def error(cls, module: str, message: str, exc: Optional[Exception] = None): + def error(cls, module: str, message: str, exc: Exception | None = None): """ Log error message with optional exception. @@ -283,11 +280,11 @@ def error(cls, module: str, message: str, exc: Optional[Exception] = None): f.write(" Traceback:\n") for line in traceback.format_tb(exc.__traceback__): f.write(f" {line}") - except (OSError, IOError): + except OSError: pass @classmethod - def critical(cls, module: str, message: str, exc: Optional[Exception] = None): + def critical(cls, module: str, message: str, exc: Exception | None = None): """ Log critical error message. @@ -312,7 +309,7 @@ def critical(cls, module: str, message: str, exc: Optional[Exception] = None): with open(cls._log_file, 'a') as f: f.write(" Traceback:\n") traceback.print_exc(file=f) - except (OSError, IOError): + except OSError: pass # Print traceback to stderr if verbose @@ -352,12 +349,12 @@ def log_warning(module: str, message: str): Logger.warning(module, message) -def log_error(module: str, message: str, exc: Optional[Exception] = None): +def log_error(module: str, message: str, exc: Exception | None = None): """Log error message.""" Logger.error(module, message, exc) -def log_critical(module: str, message: str, exc: Optional[Exception] = None): +def log_critical(module: str, message: str, exc: Exception | None = None): """Log critical error.""" Logger.critical(module, message, exc) diff --git a/wifite/util/memory.py b/wifite/util/memory.py index 4138012f9..9226df197 100755 --- a/wifite/util/memory.py +++ b/wifite/util/memory.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Memory monitoring and cleanup utilities for wifite2. @@ -12,7 +11,7 @@ import os import time import threading -from typing import Optional, Dict, Any +from typing import Any from ..config import Configuration @@ -62,13 +61,13 @@ def get_memory_usage_mb(cls) -> float: try: # Fallback to /proc on Linux - with open(f'/proc/{os.getpid()}/status', 'r') as f: + with open(f'/proc/{os.getpid()}/status') as f: for line in f: if line.startswith('VmRSS:'): # VmRSS is in kB kb = int(line.split()[1]) return kb / 1024 - except (FileNotFoundError, IOError, ValueError): + except (FileNotFoundError, OSError, ValueError): pass return -1 @@ -85,7 +84,7 @@ def get_open_fd_count(cls) -> int: proc_fd_dir = f'/proc/{os.getpid()}/fd' if os.path.exists(proc_fd_dir): return len(os.listdir(proc_fd_dir)) - except (OSError, IOError): + except OSError: pass return -1 @@ -104,7 +103,7 @@ def get_fd_limit(cls) -> tuple: return (-1, -1) @classmethod - def check_memory_status(cls) -> Dict[str, Any]: + def check_memory_status(cls) -> dict[str, Any]: """ Check current memory and resource status. @@ -306,7 +305,7 @@ def force_cleanup(cls): cls._aggressive_cleanup() @classmethod - def get_stats(cls) -> Dict[str, Any]: + def get_stats(cls) -> dict[str, Any]: """ Get cleanup statistics. @@ -351,7 +350,7 @@ def on_target_complete(self): if self.targets_attacked % 10 == 0: MemoryMonitor.force_cleanup() - def get_session_stats(self) -> Dict[str, Any]: + def get_session_stats(self) -> dict[str, Any]: """Get session statistics.""" elapsed = time.time() - self.start_time memory_stats = MemoryMonitor.get_stats() @@ -365,7 +364,7 @@ def get_session_stats(self) -> Dict[str, Any]: # Global infinite mode monitor instance -_infinite_monitor: Optional[InfiniteModeMonitor] = None +_infinite_monitor: InfiniteModeMonitor | None = None def get_infinite_monitor() -> InfiniteModeMonitor: diff --git a/wifite/util/output.py b/wifite/util/output.py index 3e60ba811..914e381e0 100755 --- a/wifite/util/output.py +++ b/wifite/util/output.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Output abstraction layer for wifite2 @@ -66,7 +65,7 @@ def initialize(cls, mode='auto'): else: # classic cls._mode = 'classic' return False - except Exception as e: + except Exception: # Any unexpected error - fall back to classic mode cls._mode = 'classic' cls._controller = None diff --git a/wifite/util/owe.py b/wifite/util/owe.py index 5c92e8775..1a572e73a 100755 --- a/wifite/util/owe.py +++ b/wifite/util/owe.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ OWE (Opportunistic Wireless Encryption) Detection and Analysis @@ -22,7 +21,6 @@ - Wi-Fi Alliance Enhanced Open specification """ -from typing import Dict, List, Optional, Tuple from ..util.color import Color @@ -40,7 +38,7 @@ class OWEDetector: OWE_AKM = 18 @staticmethod - def detect_owe_capability(target) -> Optional[Dict]: + def detect_owe_capability(target) -> dict | None: """ Detect if a target supports OWE. @@ -93,7 +91,7 @@ def detect_owe_capability(target) -> Optional[Dict]: return owe_info if owe_info['owe_enabled'] else None @staticmethod - def find_transition_pairs(targets: List) -> List[Tuple]: + def find_transition_pairs(targets: list) -> list[tuple]: """ Find OWE transition mode pairs (OWE + Open networks). @@ -127,7 +125,7 @@ def find_transition_pairs(targets: List) -> List[Tuple]: return transition_pairs @staticmethod - def _assess_transition_pair(owe_target, open_target) -> Optional[str]: + def _assess_transition_pair(owe_target, open_target) -> str | None: """ Assess if two networks form an OWE transition pair. @@ -190,7 +188,7 @@ def _assess_transition_pair(owe_target, open_target) -> Optional[str]: return None @staticmethod - def print_owe_info(target, owe_info: Dict, verbose: bool = False): + def print_owe_info(target, owe_info: dict, verbose: bool = False): """ Print OWE network information. @@ -233,7 +231,7 @@ def print_owe_info(target, owe_info: Dict, verbose: bool = False): Color.pl(' {W}Encryption:{W} Automatic per-session keys') @staticmethod - def print_transition_pairs(pairs: List[Tuple], verbose: bool = False): + def print_transition_pairs(pairs: list[tuple], verbose: bool = False): """ Print detected OWE transition mode pairs. @@ -274,7 +272,7 @@ def print_transition_pairs(pairs: List[Tuple], verbose: bool = False): Color.pl(' {G}•{W} Monitor for rogue Open APs mimicking OWE networks') @staticmethod - def scan_owe_vulnerabilities(targets: List) -> Dict: + def scan_owe_vulnerabilities(targets: list) -> dict: """ Scan targets for OWE vulnerabilities. @@ -310,7 +308,7 @@ def scan_owe_vulnerabilities(targets: List) -> Dict: return results @staticmethod - def print_scan_summary(results: Dict): + def print_scan_summary(results: dict): """Print OWE vulnerability scan summary.""" Color.pl('\n{+} {C}OWE Vulnerability Scan Summary{W}') Color.pl('{+} OWE networks found: {G}%d{W}' % len(results['owe_networks'])) diff --git a/wifite/util/owe_scanner.py b/wifite/util/owe_scanner.py index f6c9b2ccf..09946a7d7 100755 --- a/wifite/util/owe_scanner.py +++ b/wifite/util/owe_scanner.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ OWE Vulnerability Scanner diff --git a/wifite/util/pmkid_monitor.py b/wifite/util/pmkid_monitor.py index 485cf8bc4..83f0f9dc5 100755 --- a/wifite/util/pmkid_monitor.py +++ b/wifite/util/pmkid_monitor.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Passive PMKID monitoring thread. diff --git a/wifite/util/process.py b/wifite/util/process.py index ce3f30da8..3302edbcf 100755 --- a/wifite/util/process.py +++ b/wifite/util/process.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import contextlib import re @@ -253,7 +252,7 @@ def __init__(self, command, devnull=False, stdout=PIPE, stderr=PIPE, cwd=None, b log_info('Process', f'Process created successfully (PID: {self.pid.pid})') except OSError as e: if e.errno == 24: # Too many open files - log_error('Process', f'Too many open files (errno 24), triggering emergency cleanup', e) + log_error('Process', 'Too many open files (errno 24), triggering emergency cleanup', e) if Configuration.verbose > 0: Color.pl('{!} {O}Too many open files, triggering emergency cleanup{W}') ProcessManager().cleanup_all() @@ -385,7 +384,6 @@ def cleanup(self): self.interrupt() except (OSError, ValueError) as e: log_debug('Process', f'Error interrupting process: {str(e)}') - pass # Ensure all descriptors closed streams_closed = 0 @@ -396,7 +394,6 @@ def cleanup(self): streams_closed += 1 except (OSError, ValueError) as e: log_debug('Process', f'Error closing stream: {str(e)}') - pass if streams_closed > 0: log_debug('Process', f'Closed {streams_closed} stream(s)') @@ -409,7 +406,6 @@ def cleanup(self): devnull_closed += 1 except (OSError, ValueError) as e: log_debug('Process', f'Error closing devnull handle: {str(e)}') - pass self._devnull_handles = [] if devnull_closed > 0: @@ -419,7 +415,6 @@ def cleanup(self): self._manager.unregister_process(self) except (OSError, ValueError) as e: log_debug('Process', f'Error unregistering process: {str(e)}') - pass # Detach the weakref finalizer — cleanup already done above if hasattr(self, '_finalizer'): @@ -556,7 +551,6 @@ def check_fd_limit(): return True except Exception as e: log_debug('Process', f'Error checking FD limit: {str(e)}') - pass return False diff --git a/wifite/util/retry.py b/wifite/util/retry.py index 55f0a1c6f..fa8e49f49 100755 --- a/wifite/util/retry.py +++ b/wifite/util/retry.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Retry logic with exponential backoff for network operations. @@ -12,13 +11,13 @@ import secrets _sysrng = secrets.SystemRandom() from functools import wraps -from typing import Callable, Optional, Tuple, Type, Union, Any +from collections.abc import Callable class RetryExhausted(Exception): """Raised when all retry attempts are exhausted.""" - def __init__(self, message: str, last_exception: Optional[Exception] = None, + def __init__(self, message: str, last_exception: Exception | None = None, attempts: int = 0): super().__init__(message) self.last_exception = last_exception @@ -89,9 +88,9 @@ class RetryConfig: def __init__(self, max_attempts: int = 3, backoff_func: Callable[[int], float] = None, - retry_exceptions: Tuple[Type[Exception], ...] = (Exception,), - on_retry: Optional[Callable[[int, Exception], None]] = None, - on_failure: Optional[Callable[[int, Exception], None]] = None): + retry_exceptions: tuple[type[Exception], ...] = (Exception,), + on_retry: Callable[[int, Exception], None] | None = None, + on_failure: Callable[[int, Exception], None] | None = None): """ Initialize retry configuration. @@ -109,10 +108,10 @@ def __init__(self, self.on_failure = on_failure -def retry_with_backoff(config: Optional[RetryConfig] = None, +def retry_with_backoff(config: RetryConfig | None = None, max_attempts: int = 3, backoff_func: Callable[[int], float] = None, - retry_exceptions: Tuple[Type[Exception], ...] = (Exception,)): + retry_exceptions: tuple[type[Exception], ...] = (Exception,)): """ Decorator to retry a function with backoff on failure. @@ -194,13 +193,13 @@ class RetryContext: def __init__(self, max_attempts: int = 3, backoff_func: Callable[[int], float] = None, - on_retry: Optional[Callable[[int, Exception], None]] = None): + on_retry: Callable[[int, Exception], None] | None = None): self.max_attempts = max_attempts self.backoff_func = backoff_func or exponential_backoff self.on_retry = on_retry self.attempt = 0 - self.last_exception: Optional[Exception] = None + self.last_exception: Exception | None = None self.succeeded = False def __enter__(self): diff --git a/wifite/util/sae_crack.py b/wifite/util/sae_crack.py index a42014601..3666f972c 100755 --- a/wifite/util/sae_crack.py +++ b/wifite/util/sae_crack.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ SAE Cracking Module @@ -9,13 +8,11 @@ """ import os -import re import time -from typing import Optional, Dict, Any, List from ..config import Configuration from ..model.sae_handshake import SAEHandshake -from ..tools.hashcat import Hashcat, HashcatCracker, HcxPcapngTool +from ..tools.hashcat import Hashcat, HashcatCracker from ..util.color import Color from ..util.process import Process @@ -35,7 +32,7 @@ class SAECracker: # Hashcat mode for WPA3-SAE HASHCAT_MODE = '22000' - def __init__(self, sae_handshake: SAEHandshake, wordlist: Optional[str] = None): + def __init__(self, sae_handshake: SAEHandshake, wordlist: str | None = None): """ Initialize SAE cracker. @@ -51,12 +48,12 @@ def __init__(self, sae_handshake: SAEHandshake, wordlist: Optional[str] = None): @staticmethod def crack_sae_handshake( sae_handshake: SAEHandshake, - wordlist: Optional[str] = None, - rules: Optional[str] = None, - mask: Optional[str] = None, + wordlist: str | None = None, + rules: str | None = None, + mask: str | None = None, show_command: bool = False, verbose: bool = True - ) -> Optional[str]: + ) -> str | None: """ Crack a SAE handshake using hashcat mode 22000. @@ -130,7 +127,7 @@ def _prepare_hash_file(self) -> bool: Color.pl('{!} {R}Error preparing hash file:{W} %s' % str(e)) return False - def _crack_with_wordlist(self, show_command: bool = False, verbose: bool = True) -> Optional[str]: + def _crack_with_wordlist(self, show_command: bool = False, verbose: bool = True) -> str | None: """ Crack SAE handshake using dictionary attack. @@ -164,7 +161,7 @@ def _crack_with_wordlist(self, show_command: bool = False, verbose: bool = True) return key - def _crack_with_rules(self, rules: str, show_command: bool = False, verbose: bool = True) -> Optional[str]: + def _crack_with_rules(self, rules: str, show_command: bool = False, verbose: bool = True) -> str | None: """ Crack SAE handshake using rule-based attack. @@ -196,7 +193,7 @@ def _crack_with_rules(self, rules: str, show_command: bool = False, verbose: boo return key - def _crack_with_mask(self, mask: str, show_command: bool = False, verbose: bool = True) -> Optional[str]: + def _crack_with_mask(self, mask: str, show_command: bool = False, verbose: bool = True) -> str | None: """ Crack SAE handshake using mask attack. @@ -226,12 +223,12 @@ def _crack_with_mask(self, mask: str, show_command: bool = False, verbose: bool def _run_hashcat( self, attack_mode: str, - wordlist: Optional[str] = None, - rules: Optional[str] = None, - mask: Optional[str] = None, + wordlist: str | None = None, + rules: str | None = None, + mask: str | None = None, show_command: bool = False, verbose: bool = True - ) -> Optional[str]: + ) -> str | None: """ Run hashcat and return the cracked password, or None. @@ -255,7 +252,7 @@ def _run_dictionary_with_progress( wordlist: str, show_command: bool = False, verbose: bool = True, - ) -> Optional[str]: + ) -> str | None: """Dictionary crack using HashcatCracker with live STATUS streaming.""" with HashcatCracker(self.hash_file, wordlist, mode=self.HASHCAT_MODE) as cracker: cracker.start(show_command=show_command) @@ -280,11 +277,11 @@ def _run_dictionary_with_progress( def _run_hashcat_oneshot( self, attack_mode: str, - wordlist: Optional[str] = None, - rules: Optional[str] = None, - mask: Optional[str] = None, + wordlist: str | None = None, + rules: str | None = None, + mask: str | None = None, show_command: bool = False, - ) -> Optional[str]: + ) -> str | None: """Plain blocking hashcat run — for rules/mask paths only.""" command = [ 'hashcat', @@ -310,7 +307,7 @@ def _run_hashcat_oneshot( stdout, stderr = proc.get_output() return self._parse_cracked_password(stdout, stderr) - def _check_pot_file(self, show_command: bool = False) -> Optional[str]: + def _check_pot_file(self, show_command: bool = False) -> str | None: """ Check if password is already in hashcat pot file. @@ -335,7 +332,7 @@ def _check_pot_file(self, show_command: bool = False) -> Optional[str]: return self._parse_cracked_password(stdout, '') - def _parse_cracked_password(self, stdout: str, stderr: str) -> Optional[str]: + def _parse_cracked_password(self, stdout: str, stderr: str) -> str | None: """ Parse cracked password from hashcat output. @@ -373,7 +370,7 @@ def _parse_cracked_password(self, stdout: str, stderr: str) -> Optional[str]: return None @staticmethod - def check_dependencies() -> Dict[str, bool]: + def check_dependencies() -> dict[str, bool]: """ Check if required tools for SAE cracking are available. diff --git a/wifite/util/scanner.py b/wifite/util/scanner.py index fd59410b5..5b6a25b4a 100755 --- a/wifite/util/scanner.py +++ b/wifite/util/scanner.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- from time import sleep, time @@ -7,11 +6,10 @@ from ..tools.airodump import Airodump from ..util.color import Color from ..util.output import OutputManager -from shlex import quote as shlex_quote # Check for native scanner availability try: - from ..native.scanner import NativeScanner, AccessPoint as NativeAP, is_available as native_scanner_available + from ..native.scanner import NativeScanner, is_available as native_scanner_available NATIVE_SCANNER_AVAILABLE = native_scanner_available() except (ImportError, Exception): NATIVE_SCANNER_AVAILABLE = False @@ -410,8 +408,7 @@ def _find_targets_native(self, max_scan_time): Returns: True if scan completed successfully """ - from ..util.logger import log_info, log_debug, log_warning - from ..model.target import Target + from ..util.logger import log_info, log_warning log_info('Scanner', 'Starting native scanner') @@ -739,7 +736,7 @@ def _prompt_user_for_targets_classic(self): break if '-' in choice: # User selected a range - (lower, upper) = [int(x) - 1 for x in choice.split('-')] + (lower, upper) = (int(x) - 1 for x in choice.split('-')) for i in range(lower, min(len(self.targets), upper + 1)): chosen_targets.append(self.targets[i]) elif choice.isdigit(): @@ -762,7 +759,7 @@ def _prompt_user_for_targets_classic(self): s = Scanner() s.find_targets() targets = s.select_targets() - except (OSError, IOError) as e: + except OSError as e: Color.pl('\r {!} {R}Scanner I/O Error{W}: %s' % str(e)) Configuration.exit_gracefully() except subprocess.CalledProcessError as e: diff --git a/wifite/util/session.py b/wifite/util/session.py index d6eec2deb..9bb986aad 100755 --- a/wifite/util/session.py +++ b/wifite/util/session.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Session management for wifite2. @@ -11,7 +10,7 @@ import json import time from dataclasses import dataclass, field, asdict -from typing import List, Dict, Any, Optional +from typing import Any from datetime import datetime @@ -32,19 +31,19 @@ class EvilTwinClientState: """Represents a client connection in an Evil Twin attack session.""" mac_address: str - ip_address: Optional[str] = None - hostname: Optional[str] = None + ip_address: str | None = None + hostname: str | None = None connect_time: float = 0.0 - disconnect_time: Optional[float] = None + disconnect_time: float | None = None credential_submitted: bool = False - credential_valid: Optional[bool] = None + credential_valid: bool | None = None - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """Convert to dictionary for JSON serialization.""" return asdict(self) @classmethod - def from_dict(cls, data: Dict[str, Any]) -> 'EvilTwinClientState': + def from_dict(cls, data: dict[str, Any]) -> 'EvilTwinClientState': """Create EvilTwinClientState from dictionary.""" return cls(**data) @@ -58,12 +57,12 @@ class EvilTwinCredentialAttempt: success: bool timestamp: float - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """Convert to dictionary for JSON serialization.""" return asdict(self) @classmethod - def from_dict(cls, data: Dict[str, Any]) -> 'EvilTwinCredentialAttempt': + def from_dict(cls, data: dict[str, Any]) -> 'EvilTwinCredentialAttempt': """Create EvilTwinCredentialAttempt from dictionary.""" return cls(**data) @@ -79,21 +78,21 @@ class EvilTwinAttackState: """Represents the complete state of an Evil Twin attack for session persistence.""" # Attack configuration - interface_ap: Optional[str] = None - interface_deauth: Optional[str] = None + interface_ap: str | None = None + interface_deauth: str | None = None portal_template: str = 'generic' deauth_interval: int = 5 # Attack progress attack_phase: str = "initializing" # initializing, running, validating, completed, failed - start_time: Optional[float] = None - setup_time: Optional[float] = None + start_time: float | None = None + setup_time: float | None = None # Client tracking - clients: List[EvilTwinClientState] = field(default_factory=list) + clients: list[EvilTwinClientState] = field(default_factory=list) # Credential attempts - credential_attempts: List[EvilTwinCredentialAttempt] = field(default_factory=list) + credential_attempts: list[EvilTwinCredentialAttempt] = field(default_factory=list) # Statistics total_clients_connected: int = 0 @@ -101,10 +100,10 @@ class EvilTwinAttackState: successful_validations: int = 0 # Result (if successful) - captured_password: Optional[str] = None + captured_password: str | None = None validation_time: float = 0.0 - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """Convert to dictionary for JSON serialization.""" return { 'interface_ap': self.interface_ap, @@ -132,7 +131,7 @@ def clear_credentials(self): attempt.clear_password() @classmethod - def from_dict(cls, data: Dict[str, Any]) -> 'EvilTwinAttackState': + def from_dict(cls, data: dict[str, Any]) -> 'EvilTwinAttackState': """Create EvilTwinAttackState from dictionary.""" clients = [EvilTwinClientState.from_dict(c) for c in data.get('clients', [])] attempts = [EvilTwinCredentialAttempt.from_dict(a) for a in data.get('credential_attempts', [])] @@ -160,17 +159,17 @@ class TargetState: """Represents the state of a single target in a session.""" bssid: str - essid: Optional[str] + essid: str | None channel: int encryption: str power: int wps: bool status: str = "pending" # pending, in_progress, completed, failed attempts: int = 0 - last_attempt: Optional[float] = None + last_attempt: float | None = None # Evil Twin specific fields - evil_twin_state: Optional[Dict[str, Any]] = None # Evil Twin attack state + evil_twin_state: dict[str, Any] | None = None # Evil Twin attack state @classmethod def from_target(cls, target) -> 'TargetState': @@ -193,12 +192,12 @@ def from_target(cls, target) -> 'TargetState': evil_twin_state=None ) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """Convert to dictionary for JSON serialization.""" return asdict(self) @classmethod - def from_dict(cls, data: Dict[str, Any]) -> 'TargetState': + def from_dict(cls, data: dict[str, Any]) -> 'TargetState': """Create TargetState from dictionary.""" # Handle evil_twin_state deserialization evil_twin_data = data.get('evil_twin_state') @@ -214,13 +213,13 @@ class SessionState: session_id: str created_at: float updated_at: float - config: Dict[str, Any] - targets: List[TargetState] = field(default_factory=list) - completed_targets: List[str] = field(default_factory=list) # BSSIDs - failed_targets: Dict[str, str] = field(default_factory=dict) # BSSID -> reason + config: dict[str, Any] + targets: list[TargetState] = field(default_factory=list) + completed_targets: list[str] = field(default_factory=list) # BSSIDs + failed_targets: dict[str, str] = field(default_factory=dict) # BSSID -> reason current_target_index: int = 0 - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """Serialize to dictionary for JSON storage.""" return { 'session_id': self.session_id, @@ -234,7 +233,7 @@ def to_dict(self) -> Dict[str, Any]: } @classmethod - def from_dict(cls, data: Dict[str, Any]) -> 'SessionState': + def from_dict(cls, data: dict[str, Any]) -> 'SessionState': """Deserialize from dictionary.""" targets = [TargetState.from_dict(t) for t in data.get('targets', [])] return cls( @@ -248,7 +247,7 @@ def from_dict(cls, data: Dict[str, Any]) -> 'SessionState': current_target_index=data.get('current_target_index', 0) ) - def get_progress_summary(self) -> Dict[str, Any]: + def get_progress_summary(self) -> dict[str, Any]: """Get summary of session progress.""" total = len(self.targets) completed = len(self.completed_targets) @@ -305,7 +304,7 @@ def _get_session_path(self, session_id: str) -> str: raise ValueError(f'Session ID resolves outside session directory: {session_id!r}') return path - def create_session(self, targets: List, config) -> SessionState: + def create_session(self, targets: list, config) -> SessionState: """ Create a new session from targets and configuration. @@ -430,7 +429,7 @@ def save_session(self, session: SessionState) -> None: pass # Re-raise with detailed context - raise IOError(f'Failed to save session {session.session_id}: {str(e)}') from e + raise OSError(f'Failed to save session {session.session_id}: {str(e)}') from e def load_session(self, session_id: str = None) -> SessionState: """ @@ -463,11 +462,11 @@ def load_session(self, session_id: str = None) -> SessionState: self._validate_file_permissions(session_path) try: - with open(session_path, 'r') as f: + with open(session_path) as f: data = json.load(f) except json.JSONDecodeError as e: raise ValueError(f"Corrupted session file (invalid JSON): {e}") - except (OSError, IOError) as e: + except OSError as e: raise ValueError(f"Cannot read session file: {e}") # Validate session data structure @@ -513,7 +512,7 @@ def _validate_file_permissions(self, session_path: str) -> None: # If we can't check permissions, continue anyway pass - def _validate_session_data(self, data: Dict[str, Any], session_id: str) -> None: + def _validate_session_data(self, data: dict[str, Any], session_id: str) -> None: """ Validate session data structure and content. @@ -584,7 +583,7 @@ def _validate_session_data(self, data: Dict[str, Any], session_id: str) -> None: if not isinstance(data['failed_targets'], dict): raise ValueError("failed_targets must be a dictionary") - def list_sessions(self) -> List[Dict[str, Any]]: + def list_sessions(self) -> list[dict[str, Any]]: """ List all available sessions with metadata. @@ -603,7 +602,7 @@ def list_sessions(self) -> List[Dict[str, Any]]: session_path = os.path.join(self.session_dir, filename) try: - with open(session_path, 'r') as f: + with open(session_path) as f: data = json.load(f) session_state = SessionState.from_dict(data) @@ -702,7 +701,7 @@ def mark_target_failed(self, session: SessionState, bssid: str, reason: str) -> def get_remaining_targets( self, session: SessionState, include_failed: bool = False - ) -> List[TargetState]: + ) -> list[TargetState]: """ Get list of targets that still need to be attacked. @@ -750,7 +749,7 @@ def save_evil_twin_state(self, session: SessionState, bssid: str, evil_twin_stat target.evil_twin_state = evil_twin_state.to_dict() break - def load_evil_twin_state(self, session: SessionState, bssid: str) -> Optional[EvilTwinAttackState]: + def load_evil_twin_state(self, session: SessionState, bssid: str) -> EvilTwinAttackState | None: """ Load Evil Twin attack state for a specific target. @@ -779,7 +778,7 @@ def clear_evil_twin_state(self, session: SessionState, bssid: str) -> None: target.evil_twin_state = None break - def handle_partial_evil_twin_completion(self, session: SessionState, bssid: str) -> Dict[str, Any]: + def handle_partial_evil_twin_completion(self, session: SessionState, bssid: str) -> dict[str, Any]: """ Handle partial completion of Evil Twin attack. @@ -845,7 +844,7 @@ def handle_partial_evil_twin_completion(self, session: SessionState, bssid: str) 'attack_phase': evil_twin_state.attack_phase } - def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, Any]: + def restore_configuration(self, session: SessionState, config_obj) -> dict[str, Any]: """ Restore attack parameters from session to Configuration object. @@ -865,7 +864,6 @@ def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, - 'interface_changed': Boolean indicating if interface was changed - 'conflicts': List of conflicting flags that were overridden """ - from ..util.color import Color warnings = [] conflicts = [] @@ -932,7 +930,7 @@ def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, if saved_wordlist: if current_wordlist and current_wordlist != saved_wordlist: conflicts.append( - f"--wordlist: command-line value overridden by session value" + "--wordlist: command-line value overridden by session value" ) config_obj.wordlist = saved_wordlist @@ -942,7 +940,7 @@ def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, current_timeout = getattr(config_obj, 'wpa_attack_timeout', 500) if current_timeout != saved_timeout and current_timeout != 500: conflicts.append( - f"--wpa-attack-timeout: command-line value overridden by session value" + "--wpa-attack-timeout: command-line value overridden by session value" ) config_obj.wpa_attack_timeout = saved_timeout @@ -987,7 +985,7 @@ def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, current_use_tui = getattr(config_obj, 'use_tui', True) if current_use_tui != saved_use_tui: conflicts.append( - f"UI mode: command-line value overridden by session value" + "UI mode: command-line value overridden by session value" ) config_obj.use_tui = saved_use_tui @@ -1002,7 +1000,7 @@ def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, current_dual_enabled = getattr(config_obj, 'dual_interface_enabled', False) if current_dual_enabled != saved_dual_enabled: conflicts.append( - f"--dual-interface: command-line value overridden by session value" + "--dual-interface: command-line value overridden by session value" ) config_obj.dual_interface_enabled = saved_dual_enabled @@ -1030,7 +1028,7 @@ def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, current_primary = getattr(config_obj, 'interface_primary', None) if current_primary and current_primary != saved_primary: conflicts.append( - f"--interface-primary: command-line value overridden by session value" + "--interface-primary: command-line value overridden by session value" ) config_obj.interface_primary = saved_primary except (FileNotFoundError, OSError, Exception): @@ -1063,7 +1061,7 @@ def restore_configuration(self, session: SessionState, config_obj) -> Dict[str, current_secondary = getattr(config_obj, 'interface_secondary', None) if current_secondary and current_secondary != saved_secondary: conflicts.append( - f"--interface-secondary: command-line value overridden by session value" + "--interface-secondary: command-line value overridden by session value" ) config_obj.interface_secondary = saved_secondary except (FileNotFoundError, OSError, Exception): diff --git a/wifite/util/signal_tracker.py b/wifite/util/signal_tracker.py index 7bc56ebcd..37304e260 100755 --- a/wifite/util/signal_tracker.py +++ b/wifite/util/signal_tracker.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Signal strength history tracking and analysis. @@ -8,7 +7,6 @@ providing trend analysis for attack optimization. """ -from typing import Dict, List, Optional, Tuple from dataclasses import dataclass, field from collections import deque import time @@ -47,33 +45,33 @@ def add_sample(self, power: int) -> None: self.samples.append(SignalSample(time.time(), power)) @property - def current(self) -> Optional[int]: + def current(self) -> int | None: """Get most recent signal strength.""" return self.samples[-1].power if self.samples else None @property - def average(self) -> Optional[float]: + def average(self) -> float | None: """Calculate average signal strength.""" if not self.samples: return None return sum(s.power for s in self.samples) / len(self.samples) @property - def max_power(self) -> Optional[int]: + def max_power(self) -> int | None: """Get maximum signal strength seen.""" if not self.samples: return None return max(s.power for s in self.samples) @property - def min_power(self) -> Optional[int]: + def min_power(self) -> int | None: """Get minimum signal strength seen.""" if not self.samples: return None return min(s.power for s in self.samples) @property - def variance(self) -> Optional[float]: + def variance(self) -> float | None: """Calculate signal variance (stability indicator).""" if len(self.samples) < 2: return None @@ -119,7 +117,7 @@ def is_stable(self, threshold: float = 5.0) -> bool: var = self.variance return var is not None and var < threshold - def get_optimal_window(self, window_seconds: int = 10) -> Optional[Tuple[float, float]]: + def get_optimal_window(self, window_seconds: int = 10) -> tuple[float, float] | None: """ Find the time window with best average signal. @@ -158,8 +156,8 @@ class SignalTracker: def __init__(self, max_samples: int = 60): self.max_samples = max_samples - self.aps: Dict[str, SignalHistory] = {} - self.clients: Dict[str, SignalHistory] = {} + self.aps: dict[str, SignalHistory] = {} + self.clients: dict[str, SignalHistory] = {} def update_ap(self, bssid: str, power: int) -> None: """Update signal strength for an AP.""" @@ -173,16 +171,16 @@ def update_client(self, mac: str, power: int) -> None: self.clients[mac] = SignalHistory(mac, self.max_samples) self.clients[mac].add_sample(power) - def get_ap_history(self, bssid: str) -> Optional[SignalHistory]: + def get_ap_history(self, bssid: str) -> SignalHistory | None: """Get signal history for an AP.""" return self.aps.get(bssid) - def get_client_history(self, mac: str) -> Optional[SignalHistory]: + def get_client_history(self, mac: str) -> SignalHistory | None: """Get signal history for a client.""" return self.clients.get(mac) def get_best_targets(self, min_power: int = -70, - require_stable: bool = False) -> List[str]: + require_stable: bool = False) -> list[str]: """ Get list of APs with good, stable signal. @@ -207,7 +205,7 @@ def get_best_targets(self, min_power: int = -70, candidates.sort(key=lambda x: x[1], reverse=True) return [bssid for bssid, _ in candidates] - def get_active_clients(self, max_age_seconds: int = 30) -> List[str]: + def get_active_clients(self, max_age_seconds: int = 30) -> list[str]: """ Get list of clients that have been seen recently. @@ -230,7 +228,7 @@ def get_active_clients(self, max_age_seconds: int = 30) -> List[str]: def should_attack_now(self, bssid: str, min_power: int = -75, - prefer_stable: bool = True) -> Tuple[bool, str]: + prefer_stable: bool = True) -> tuple[bool, str]: """ Determine if now is a good time to attack a target. @@ -303,7 +301,7 @@ def cleanup_stale(self, max_age_seconds: int = 300) -> int: return removed - def get_summary(self) -> Dict: + def get_summary(self) -> dict: """Get summary statistics for all tracked entities.""" ap_summary = {} for bssid, history in self.aps.items(): @@ -335,7 +333,7 @@ def get_summary(self) -> Dict: # Global signal tracker instance -_global_tracker: Optional[SignalTracker] = None +_global_tracker: SignalTracker | None = None def get_signal_tracker() -> SignalTracker: diff --git a/wifite/util/system_check.py b/wifite/util/system_check.py index 8205b9dc6..d2711b18c 100755 --- a/wifite/util/system_check.py +++ b/wifite/util/system_check.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Comprehensive system check for wifite2. @@ -21,7 +20,6 @@ import re import subprocess import shutil -from typing import Optional, List, Dict, Tuple from dataclasses import dataclass, field from enum import Enum @@ -41,8 +39,8 @@ class CheckResult: name: str status: CheckStatus message: str - details: Optional[str] = None - fix_hint: Optional[str] = None + details: str | None = None + fix_hint: str | None = None @dataclass @@ -58,11 +56,11 @@ class InterfaceCheckResult: supports_monitor: bool = False supports_ap: bool = False supports_injection: bool = False - monitor_tested: Optional[bool] = None # None = not tested + monitor_tested: bool | None = None # None = not tested bands_24ghz: bool = False bands_5ghz: bool = False - channels_24: List[int] = field(default_factory=list) - channels_5: List[int] = field(default_factory=list) + channels_24: list[int] = field(default_factory=list) + channels_5: list[int] = field(default_factory=list) @dataclass @@ -70,13 +68,13 @@ class ToolCheckResult: """Result of a tool dependency check.""" name: str found: bool - path: Optional[str] = None - version: Optional[str] = None - min_version: Optional[str] = None + path: str | None = None + version: str | None = None + min_version: str | None = None version_ok: bool = True required: bool = False category: str = 'misc' - native_alt: Optional[str] = None # Description of native alternative + native_alt: str | None = None # Description of native alternative class SystemCheck: @@ -95,16 +93,16 @@ def __init__(self, verbose: int = 0, run_smoke_test: bool = False): """ self.verbose = verbose self.run_smoke_test = run_smoke_test - self.tool_results: List[ToolCheckResult] = [] - self.interface_results: List[InterfaceCheckResult] = [] - self.env_results: List[CheckResult] = [] - self.attack_readiness: Dict[str, CheckStatus] = {} + self.tool_results: list[ToolCheckResult] = [] + self.interface_results: list[InterfaceCheckResult] = [] + self.env_results: list[CheckResult] = [] + self.attack_readiness: dict[str, CheckStatus] = {} # ================================================================ # Environment Checks # ================================================================ - def check_environment(self) -> List[CheckResult]: + def check_environment(self) -> list[CheckResult]: """Check OS, kernel, and runtime environment.""" results = [] @@ -213,7 +211,7 @@ def check_environment(self) -> List[CheckResult]: # Tool / Dependency Checks # ================================================================ - def check_tools(self) -> List[ToolCheckResult]: + def check_tools(self) -> list[ToolCheckResult]: """Check all tool dependencies with versions.""" from ..tools.dependency import Dependency @@ -280,7 +278,7 @@ def check_tools(self) -> List[ToolCheckResult]: self.tool_results = results return results - def _get_tool_version(self, name: str) -> Optional[str]: + def _get_tool_version(self, name: str) -> str | None: """Try to get version string for a tool.""" if name == 'airmon-ng': if shutil.which(name): @@ -337,7 +335,7 @@ def _get_tool_version(self, name: str) -> Optional[str]: # Interface Checks # ================================================================ - def check_interfaces(self) -> List[InterfaceCheckResult]: + def check_interfaces(self) -> list[InterfaceCheckResult]: """Check all wireless interfaces and their capabilities.""" results = [] @@ -374,12 +372,13 @@ def check_interfaces(self) -> List[InterfaceCheckResult]: try: driver_link = os.readlink(f'/sys/class/net/{iface}/device/driver') result.driver = os.path.basename(driver_link) - except (OSError, IOError): + except OSError: pass # Chipset (from airmon or driver map) try: from ..tools.airmon import Airmon + from ..util.interface_manager import InterfaceManager info = Airmon.get_iface_info(iface) if info and info.chipset: result.chipset = info.chipset @@ -390,9 +389,9 @@ def check_interfaces(self) -> List[InterfaceCheckResult]: # MAC address try: - with open(f'/sys/class/net/{iface}/address', 'r') as f: + with open(f'/sys/class/net/{iface}/address') as f: result.mac = f.read().strip().upper() - except (IOError, OSError): + except OSError: pass # Current mode @@ -412,9 +411,9 @@ def check_interfaces(self) -> List[InterfaceCheckResult]: # Interface up/down try: - with open(f'/sys/class/net/{iface}/operstate', 'r') as f: + with open(f'/sys/class/net/{iface}/operstate') as f: result.is_up = f.read().strip().lower() in ('up', 'unknown') - except (IOError, OSError): + except OSError: pass # Supported modes and bands from iw phy info @@ -539,7 +538,7 @@ def _smoke_test_monitor(self, iface: str) -> bool: # Attack Readiness Assessment # ================================================================ - def assess_attack_readiness(self) -> Dict[str, CheckStatus]: + def assess_attack_readiness(self) -> dict[str, CheckStatus]: """Determine which attack types are available based on checks.""" readiness = {} @@ -774,15 +773,15 @@ def _render_interfaces(self): # Smoke test result if iface.monitor_tested is not None: if iface.monitor_tested: - Color.pl(f' Monitor test: {{G}}PASS{{W}} (entered and exited monitor mode)') + Color.pl(' Monitor test: {G}PASS{W} (entered and exited monitor mode)') else: - Color.pl(f' Monitor test: {{R}}FAIL{{W}} (could not enter monitor mode)') + Color.pl(' Monitor test: {R}FAIL{W} (could not enter monitor mode)') # Driver warnings if iface.driver in ('iwlwifi',): - Color.pl(f' {{O}}⚠ Intel driver — no packet injection support{{W}}') + Color.pl(' {O}⚠ Intel driver — no packet injection support{W}') if iface.driver in ('brcmfmac',): - Color.pl(f' {{O}}⚠ Broadcom FullMAC — limited injection support{{W}}') + Color.pl(' {O}⚠ Broadcom FullMAC — limited injection support{W}') Color.pl('') # Blank line between interfaces diff --git a/wifite/util/timer.py b/wifite/util/timer.py index 6358a6088..21274aece 100755 --- a/wifite/util/timer.py +++ b/wifite/util/timer.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import time diff --git a/wifite/util/tui_logger.py b/wifite/util/tui_logger.py index 94f2e6792..c3ecc1144 100755 --- a/wifite/util/tui_logger.py +++ b/wifite/util/tui_logger.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ TUI logging and debugging utilities for wifite2. @@ -8,7 +7,6 @@ import os import stat -import time from datetime import datetime diff --git a/wifite/util/wpa3.py b/wifite/util/wpa3.py index 53bca6e65..0cb67c93b 100755 --- a/wifite/util/wpa3.py +++ b/wifite/util/wpa3.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ WPA3-SAE Detection and Classification Module @@ -10,7 +9,7 @@ """ import os -from typing import Dict, List, Any, Optional +from typing import Any class WPA3Detector: @@ -43,7 +42,7 @@ class WPA3Detector: @staticmethod def detect_wpa3_capability(target, use_cache: bool = True, - capfile: Optional[str] = None) -> Dict[str, Any]: + capfile: str | None = None) -> dict[str, Any]: """ Detect WPA3 capability from target beacon/probe response. @@ -90,7 +89,7 @@ def detect_wpa3_capability(target, use_cache: bool = True, pmf_status = WPA3Detector.PMF_OPTIONAL else: pmf_status = WPA3Detector.PMF_REQUIRED - sae_groups: List[int] = [WPA3Detector.DEFAULT_SAE_GROUP] + sae_groups: list[int] = [WPA3Detector.DEFAULT_SAE_GROUP] # Precise layer: parse real RSN/SAE data from a capture if we have one bssid = getattr(target, 'bssid', None) @@ -116,7 +115,7 @@ def detect_wpa3_capability(target, use_cache: bool = True, } @staticmethod - def _parse_rsn_from_capture(capfile: str, bssid: str) -> Optional[Dict[str, Any]]: + def _parse_rsn_from_capture(capfile: str, bssid: str) -> dict[str, Any] | None: """ Parse precise WPA3 details from a pcap/pcapng capture via tshark. @@ -143,7 +142,7 @@ def _parse_rsn_from_capture(capfile: str, bssid: str) -> Optional[Dict[str, Any] return result @staticmethod - def _parse_pmf_from_beacon(capfile: str, bssid: str) -> Optional[str]: + def _parse_pmf_from_beacon(capfile: str, bssid: str) -> str | None: """ Extract PMF status from the RSN IE in a beacon frame. @@ -173,7 +172,7 @@ def _parse_pmf_from_beacon(capfile: str, bssid: str) -> Optional[str]: return None @staticmethod - def _parse_sae_groups_from_commits(capfile: str, bssid: str) -> List[int]: + def _parse_sae_groups_from_commits(capfile: str, bssid: str) -> list[int]: """ Extract SAE groups actually observed in SAE Commit frames. @@ -297,9 +296,9 @@ def probe_sae_groups_active( bssid: str, essid: str, channel: int, - groups_to_probe: Optional[List[int]] = None, + groups_to_probe: list[int] | None = None, per_group_timeout: int = 8, - ) -> Dict[int, str]: + ) -> dict[int, str]: """ Actively probe an AP to discover which SAE groups it accepts. @@ -345,7 +344,7 @@ def probe_sae_groups_active( if groups_to_probe is None: groups_to_probe = list(WPA3Detector.DEFAULT_PROBE_GROUPS) - results: Dict[int, str] = {} + results: dict[int, str] = {} for group in groups_to_probe: status = WPA3Detector._probe_single_sae_group( interface, bssid, essid, channel, group, per_group_timeout) @@ -487,7 +486,7 @@ def check_pmf_status(target) -> str: return wpa3_info['pmf_status'] @staticmethod - def get_supported_sae_groups(target) -> List[int]: + def get_supported_sae_groups(target) -> list[int]: """ Extract supported SAE groups from target information. @@ -580,7 +579,7 @@ def _has_wpa2(target) -> bool: return False @staticmethod - def _check_dragonblood_vulnerability(sae_groups: List[int], has_wpa3: bool) -> bool: + def _check_dragonblood_vulnerability(sae_groups: list[int], has_wpa3: bool) -> bool: """ Check for known Dragonblood vulnerability indicators. @@ -615,7 +614,7 @@ class WPA3Info: def __init__(self, has_wpa3: bool = False, has_wpa2: bool = False, is_transition: bool = False, pmf_status: str = WPA3Detector.PMF_DISABLED, - sae_groups: Optional[List[int]] = None, + sae_groups: list[int] | None = None, dragonblood_vulnerable: bool = False): """ Initialize WPA3Info object. @@ -648,7 +647,7 @@ def get(self, key: str, default=None): """ return getattr(self, key, default) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """ Serialize WPA3Info to dictionary for storage. @@ -665,7 +664,7 @@ def to_dict(self) -> Dict[str, Any]: } @classmethod - def from_dict(cls, data: Dict[str, Any]) -> 'WPA3Info': + def from_dict(cls, data: dict[str, Any]) -> 'WPA3Info': """ Deserialize WPA3Info from dictionary. diff --git a/wifite/util/wpa3_tools.py b/wifite/util/wpa3_tools.py index e74678385..1b710fede 100755 --- a/wifite/util/wpa3_tools.py +++ b/wifite/util/wpa3_tools.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ WPA3 Tool Detection and Version Checking @@ -9,7 +8,6 @@ """ import re -from typing import Dict, Optional, Tuple, List from ..util.color import Color from ..util.process import Process @@ -48,7 +46,7 @@ class WPA3ToolChecker: } @staticmethod - def check_all_tools() -> Dict[str, Dict[str, any]]: + def check_all_tools() -> dict[str, dict[str, any]]: """ Check all WPA3-related tools. @@ -81,7 +79,7 @@ def check_all_tools() -> Dict[str, Dict[str, any]]: return results @staticmethod - def check_tool(tool_name: str, required: bool = True) -> Dict[str, any]: + def check_tool(tool_name: str, required: bool = True) -> dict[str, any]: """ Check if a specific tool is available and meets version requirements. @@ -121,7 +119,7 @@ def check_tool(tool_name: str, required: bool = True) -> Dict[str, any]: } @staticmethod - def get_tool_version(tool_name: str) -> Tuple[Optional[Tuple[int, ...]], Optional[str]]: + def get_tool_version(tool_name: str) -> tuple[tuple[int, ...] | None, str | None]: """ Get version of a tool. @@ -150,7 +148,7 @@ def get_tool_version(tool_name: str) -> Tuple[Optional[Tuple[int, ...]], Optiona return None, None @staticmethod - def _parse_version(output: str, tool_name: str) -> Tuple[Optional[Tuple[int, ...]], Optional[str]]: + def _parse_version(output: str, tool_name: str) -> tuple[tuple[int, ...] | None, str | None]: """ Parse version string from tool output. @@ -247,12 +245,12 @@ def print_tool_status(verbose: bool = True): Color.pl('\n{!} {R}Missing required tools:{W}') for tool in missing_required: url = WPA3ToolChecker.INSTALL_URLS.get(tool, 'N/A') - Color.pl(f' {tool}: {C}{url}{W}') + Color.pl(' %s: {C}%s{W}' % (tool, url)) if outdated_tools: Color.pl('\n{!} {O}Outdated tools (may cause issues):{W}') for tool, current, minimum in outdated_tools: - Color.pl(f' {tool}: {O}v{current}{W} (minimum: {C}v{minimum}{W})') + Color.pl(' %s: {O}v%s{W} (minimum: {C}v%s{W})' % (tool, current, minimum)) if all_available and not outdated_tools: Color.pl('\n{+} {G}All WPA3 tools are available and up to date!{W}') @@ -262,7 +260,7 @@ def print_tool_status(verbose: bool = True): Color.pl('\n{!} {R}WPA3 attacks will not be available until required tools are installed{W}') @staticmethod - def get_missing_tools() -> List[str]: + def get_missing_tools() -> list[str]: """ Get list of missing required tools. diff --git a/wifite/util/wpasec_uploader.py b/wifite/util/wpasec_uploader.py index cbaeb127e..5a74f7e1e 100755 --- a/wifite/util/wpasec_uploader.py +++ b/wifite/util/wpasec_uploader.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ WPA-SEC uploader utility for wifite2. @@ -486,7 +485,7 @@ def upload_capture(capfile, bssid, essid, capture_type='handshake', view=None): Color.pl('{!} {O}File preserved at: {C}%s{W}' % capfile) log_warning('WpaSecUploader', f'Failed to remove capture file: {str(e)}') if view: - view.add_log(f"Warning: Could not remove capture file") + view.add_log("Warning: Could not remove capture file") else: Color.pl('{+} {O}Capture file removed by upload tool{W}') log_info('WpaSecUploader', 'Capture file already removed by wlancap2wpasec tool') @@ -546,7 +545,7 @@ def upload_capture(capfile, bssid, essid, capture_type='handshake', view=None): Color.pl('{!} {O}Capture file preserved at: {C}%s{W}' % capfile) log_error('WpaSecUploader', f'=== Upload ERROR at {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} ===') log_error('WpaSecUploader', f'Target: {essid} ({bssid})') - log_error('WpaSecUploader', f'Error type: File system error (OSError)', e) + log_error('WpaSecUploader', 'Error type: File system error (OSError)', e) log_debug('WpaSecUploader', f'Capture file preserved at: {capfile}') return False except Exception as e: diff --git a/wifite/wifite.py b/wifite/wifite.py index 1906a6b9a..15eb30ccb 100644 --- a/wifite/wifite.py +++ b/wifite/wifite.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- try: from .config import Configuration @@ -87,7 +86,6 @@ def start(self): from .model.handshake import Handshake from .util.crack import CrackHelper from .util.dbupdater import DBUpdater - from .util.session import SessionManager # Handle session cleanup if Configuration.clean_sessions: @@ -260,7 +258,7 @@ def _validate_and_prepare_dual_interfaces(self): """ from .util.interface_manager import InterfaceManager from .util.color import Color - from .util.logger import log_info, log_warning + from .util.logger import log_info # Need at least 2 interfaces for dual mode if len(self.available_interfaces) < 2: @@ -483,7 +481,7 @@ def validate_interface_assignment(self): tuple: (is_valid, error_message, warnings) """ from .util.interface_assignment import InterfaceAssignmentStrategy - from .util.logger import log_warning, log_error + from .util.logger import log_warning warnings = [] @@ -782,7 +780,6 @@ def resume_session(): Color.pl('{+} Resuming attack on {C}%d{W} remaining target(s)...' % len(remaining_targets)) # Convert TargetState objects back to Target objects - from .model.target import Target targets = [] failed_conversions = [] @@ -1266,7 +1263,7 @@ def scan_and_attack(self): try: session_mgr.delete_session(session.session_id) Color.pl('{+} {G}Session completed and cleaned up{W}') - except (OSError, IOError) as e: + except OSError as e: Color.pl('{!} {O}Warning: Could not delete session file: %s{W}' % str(e)) except Exception as e: Color.pl('{!} {O}Warning: Unexpected error during session cleanup: %s{W}' % str(e)) @@ -1296,12 +1293,12 @@ def main(): import subprocess import signal as _signal - _original_sigint = _signal.getsignal(_signal.SIGINT) + _signal.getsignal(_signal.SIGINT) try: wifite = Wifite() wifite.start() - except (OSError, IOError) as e: + except OSError as e: Color.pl('\n{!} {R}System Error{W}: %s' % str(e)) Color.pl('\n{!} {R}Exiting{W}\n') except subprocess.CalledProcessError as e: From aa64206660591382f85cc9d165d1c59a3a895e5b Mon Sep 17 00:00:00 2001 From: Dariusz Koryto Date: Thu, 11 Jun 2026 00:11:40 +0200 Subject: [PATCH 2/2] fix: resolve GitHub issues #520, #477, #522 - #520: Verify OpenCL devices are actually available before using wpapsk-opencl format in john.py (not just compiled in) - #477: Uncomment --rds=3 and --enable_status=15 flags in hcxdumptool.py passive mode to prevent aggressive default behavior in hcxdumptool v7 - #522: In infinite mode, return empty target list instead of raising Exception when no targets are found, allowing scan cycle to continue --- wifite/tools/hcxdumptool.py | 6 +++--- wifite/tools/john.py | 13 ++++++++++++- wifite/util/scanner.py | 6 ++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/wifite/tools/hcxdumptool.py b/wifite/tools/hcxdumptool.py index 7676b6325..40cede949 100644 --- a/wifite/tools/hcxdumptool.py +++ b/wifite/tools/hcxdumptool.py @@ -306,9 +306,9 @@ def __enter__(self): command = [ 'hcxdumptool', '-i', self.interface, - #'--rds=3', # Passive mode with PMKID capture - '-w', self.output_file - #'--enable_status=15' # Enable all status messages + '--rds=3', # Passive mode with PMKID capture + '-w', self.output_file, + '--enable_status=15' # Enable all status messages ] # Start the process diff --git a/wifite/tools/john.py b/wifite/tools/john.py index de3adf3da..f7894b876 100755 --- a/wifite/tools/john.py +++ b/wifite/tools/john.py @@ -206,7 +206,18 @@ def _get_format(): ) combined = result.stdout + result.stderr if 'wpapsk-opencl' in combined: - return 'wpapsk-opencl' + # Verify OpenCL devices are actually available (not just compiled in) + try: + opencl_result = subprocess.run( + ['john', '--list=opencl-devices'], + capture_output=True, text=True, timeout=10 + ) + opencl_out = opencl_result.stdout + opencl_result.stderr + if 'No OpenCL-capable' not in opencl_out and \ + 'Error: No' not in opencl_out: + return 'wpapsk-opencl' + except Exception: + pass if 'wpapsk-cuda' in combined: return 'wpapsk-cuda' except Exception: diff --git a/wifite/util/scanner.py b/wifite/util/scanner.py index 5b6a25b4a..50736c5d7 100755 --- a/wifite/util/scanner.py +++ b/wifite/util/scanner.py @@ -376,6 +376,12 @@ def select_targets(self): self._diagnose_no_targets() + # In infinite mode, keep scanning instead of crashing + if Configuration.infinite_mode: + from ..util.logger import log_warning + log_warning('Scanner', 'No targets found yet in infinite mode, continuing scan cycle') + return [] + raise Exception('No targets found.' + ' You may need to wait longer,' + ' or you may have issues with your wifi card')