diff --git a/tests/test_cleanup.py b/tests/test_cleanup.py index c30f3e981..1cf2884ea 100644 --- a/tests/test_cleanup.py +++ b/tests/test_cleanup.py @@ -144,7 +144,7 @@ def test_get_errors(self): self.assertIn('error1', errors) self.assertIn('error2', errors) - @patch('wifite.util.cleanup.subprocess.run') + @patch('wifite.util.process.subprocess.run') def test_remove_iptables_rule(self, mock_run): """Test removing an iptables rule.""" mock_run.return_value = Mock(returncode=0) @@ -155,7 +155,7 @@ def test_remove_iptables_rule(self, mock_run): self.assertTrue(result) mock_run.assert_called_once() - @patch('wifite.util.cleanup.subprocess.run') + @patch('wifite.util.process.subprocess.run') def test_check_conflicting_processes(self, mock_run): """Test checking for conflicting processes.""" # Mock pgrep returning PIDs @@ -166,7 +166,7 @@ def test_check_conflicting_processes(self, mock_run): # Should find some processes self.assertIsInstance(conflicting, list) - @patch('wifite.util.cleanup.subprocess.run') + @patch('wifite.util.process.subprocess.run') def test_kill_orphaned_processes(self, mock_run): """Test killing orphaned processes.""" # Mock pgrep returning PIDs diff --git a/tests/test_wpa3_detection_performance.py b/tests/test_wpa3_detection_performance.py index 0e90437f4..2db6022da 100644 --- a/tests/test_wpa3_detection_performance.py +++ b/tests/test_wpa3_detection_performance.py @@ -9,7 +9,6 @@ """ import unittest -import time from wifite.model.target import Target from wifite.util.wpa3 import WPA3Detector @@ -57,104 +56,105 @@ def setUp(self): '' ] - def test_cache_performance_improvement(self): - """Benchmark cache performance improvement.""" - target = Target(self.wpa3_transition_fields) - iterations = 1000 - - # Measure time without cache (fresh detection each time) - start_time = time.time() - for _ in range(iterations): - WPA3Detector.detect_wpa3_capability(target, use_cache=False) - no_cache_time = time.time() - start_time - - # Set cache once - wpa3_info_dict = WPA3Detector.detect_wpa3_capability(target, use_cache=False) + def test_cache_short_circuits_detection(self): + """Cached detection returns the stored result without recomputing. + + Behavioural check (deterministic, not timing-based): when a target + already carries a ``wpa3_info`` cache, ``use_cache=True`` must return + that cached value verbatim, while ``use_cache=False`` must ignore the + cache and recompute from the target's encryption fields. We prove this + by seeding the cache with a sentinel that deliberately disagrees with + what the fields would produce. + """ from wifite.util.wpa3 import WPA3Info - target.wpa3_info = WPA3Info.from_dict(wpa3_info_dict) - - # Measure time with cache - start_time = time.time() - for _ in range(iterations): - WPA3Detector.detect_wpa3_capability(target, use_cache=True) - cache_time = time.time() - start_time - - # Cache should be significantly faster - speedup = no_cache_time / cache_time if cache_time > 0 else float('inf') - - print(f"\nCache Performance Benchmark ({iterations} iterations):") - print(f" Without cache: {no_cache_time:.4f}s") - print(f" With cache: {cache_time:.4f}s") - print(f" Speedup: {speedup:.2f}x") - - # Cache should be at least 2x faster - self.assertGreater(speedup, 2.0, - f"Cache speedup {speedup:.2f}x is less than expected 2x") - - def test_early_return_performance(self): - """Benchmark early return optimization for WPA2-only targets.""" - wpa2_target = Target(self.wpa2_only_fields) - wpa3_target = Target(self.wpa3_transition_fields) - iterations = 1000 - - # Measure WPA2-only detection (should be faster with early return) - start_time = time.time() - for _ in range(iterations): - WPA3Detector.detect_wpa3_capability(wpa2_target, use_cache=False) - wpa2_time = time.time() - start_time - - # Measure WPA3 detection (full processing) - start_time = time.time() - for _ in range(iterations): - WPA3Detector.detect_wpa3_capability(wpa3_target, use_cache=False) - wpa3_time = time.time() - start_time - - print(f"\nEarly Return Benchmark ({iterations} iterations):") - print(f" WPA2-only (early return): {wpa2_time:.4f}s") - print(f" WPA3 (full processing): {wpa3_time:.4f}s") - print(f" Ratio: {wpa3_time/wpa2_time:.2f}x") - - # WPA2-only should be faster or similar (early return optimization) - # Allow some variance due to system load - self.assertLessEqual(wpa2_time, wpa3_time * 1.5, - "WPA2-only detection should benefit from early return") - def test_helper_method_cache_usage(self): - """Benchmark helper methods using cache vs fresh detection.""" target = Target(self.wpa3_transition_fields) - iterations = 1000 - - # Without cache - helper methods trigger full detection - start_time = time.time() - for _ in range(iterations): - target.wpa3_info = None # Clear cache - WPA3Detector.identify_transition_mode(target) - WPA3Detector.check_pmf_status(target) - WPA3Detector.get_supported_sae_groups(target) - no_cache_time = time.time() - start_time - - # With cache - helper methods use cached data - wpa3_info_dict = WPA3Detector.detect_wpa3_capability(target, use_cache=False) + + # What a fresh (uncached) detection derives from the fields. + fresh = WPA3Detector.detect_wpa3_capability(target, use_cache=False) + self.assertTrue(fresh['has_wpa3'], + 'Fixture should detect WPA3 from the encryption fields') + + # Seed the cache with a sentinel that disagrees with the fields, so a + # cache hit is distinguishable from a recompute. + sentinel = WPA3Info.from_dict({ + 'has_wpa3': False, + 'has_wpa2': True, + 'is_transition': False, + 'pmf_status': WPA3Detector.PMF_DISABLED, + 'sae_groups': [], + 'dragonblood_vulnerable': False, + }) + target.wpa3_info = sentinel + + # Cache hit: must return the sentinel, proving detection was skipped. + cached = WPA3Detector.detect_wpa3_capability(target, use_cache=True) + self.assertEqual(cached, sentinel.to_dict(), + 'Cached path must return the stored wpa3_info verbatim') + self.assertFalse(cached['has_wpa3'], + 'Cached path must not recompute from the fields') + + # Cache bypass: must recompute and match the fresh detection. + recomputed = WPA3Detector.detect_wpa3_capability(target, use_cache=False) + self.assertEqual(recomputed, fresh, + 'use_cache=False must ignore the cache and recompute') + self.assertTrue(recomputed['has_wpa3']) + + def test_early_return_for_wpa2_only(self): + """WPA2-only targets take the early-return branch (no WPA3 work). + + Behavioural check (deterministic): a target whose fields advertise no + WPA3/SAE must short-circuit to the WPA2-only result shape, while a + WPA3 transition target must go through full detection. This exercises + the same early-return optimisation the old benchmark targeted, without + asserting on wall-clock time. + """ + wpa2 = WPA3Detector.detect_wpa3_capability( + Target(self.wpa2_only_fields), use_cache=False) + wpa3 = WPA3Detector.detect_wpa3_capability( + Target(self.wpa3_transition_fields), use_cache=False) + + # Early-return branch: WPA2-only, not transition, no SAE groups. + self.assertFalse(wpa2['has_wpa3']) + self.assertFalse(wpa2['is_transition']) + self.assertEqual(wpa2['sae_groups'], []) + self.assertFalse(wpa2['dragonblood_vulnerable']) + + # Full-detection branch still flags WPA3. + self.assertTrue(wpa3['has_wpa3']) + + def test_helper_methods_use_cache(self): + """Helper methods read cached wpa3_info instead of recomputing. + + Deterministic check: seed the cache with a sentinel that disagrees + with the target's fields, then confirm each helper returns the cached + value. Clearing the cache makes them recompute from the fields. + """ from wifite.util.wpa3 import WPA3Info - target.wpa3_info = WPA3Info.from_dict(wpa3_info_dict) - - start_time = time.time() - for _ in range(iterations): - WPA3Detector.identify_transition_mode(target) - WPA3Detector.check_pmf_status(target) - WPA3Detector.get_supported_sae_groups(target) - cache_time = time.time() - start_time - - speedup = no_cache_time / cache_time if cache_time > 0 else float('inf') - - print(f"\nHelper Method Cache Benchmark ({iterations} iterations):") - print(f" Without cache: {no_cache_time:.4f}s") - print(f" With cache: {cache_time:.4f}s") - print(f" Speedup: {speedup:.2f}x") - - # Cache should provide significant speedup - self.assertGreater(speedup, 2.0, - f"Helper method cache speedup {speedup:.2f}x is less than expected") + + target = Target(self.wpa3_transition_fields) + + sentinel = WPA3Info.from_dict({ + 'has_wpa3': True, + 'has_wpa2': True, + 'is_transition': False, # disagrees with the fields + 'pmf_status': WPA3Detector.PMF_REQUIRED, + 'sae_groups': [21], # not the default [19] + 'dragonblood_vulnerable': False, + }) + target.wpa3_info = sentinel + + # Cache hit: helpers return the sentinel's values. + self.assertEqual(WPA3Detector.identify_transition_mode(target), + sentinel.is_transition) + self.assertEqual(WPA3Detector.check_pmf_status(target), + sentinel.pmf_status) + self.assertEqual(WPA3Detector.get_supported_sae_groups(target), + sentinel.sae_groups) + + # Cache cleared: helpers recompute from the fields (transition mode). + target.wpa3_info = None + self.assertTrue(WPA3Detector.identify_transition_mode(target)) if __name__ == '__main__': diff --git a/wifite/args.py b/wifite/args.py index 16abfad4f..536a3bd9d 100644 --- a/wifite/args.py +++ b/wifite/args.py @@ -14,6 +14,11 @@ def __init__(self, configuration): # Hack: Check for -v before parsing args; # so we know which commands to display. self.verbose = '-v' in sys.argv or '-hv' in sys.argv or '-vh' in sys.argv + # Activate Kalidroid MiniTerminal output mode as early as possible (before + # any option-echo prints) so the whole run streams scrollback-friendly + # output to the Kalidroid app's MiniTerminal. + if '--kalidroid' in sys.argv: + Color.kalidroid = True self.config = configuration self.args = self.get_arguments() @@ -270,6 +275,15 @@ def _add_global_args(self, glob): help=self._verbose( 'Write debug log to {C}[path]{W} (implies {C}-vv{W} minimum verbosity)')) + glob.add_argument('--kalidroid', + action='store_true', + default=False, + dest='kalidroid', + help=self._verbose( + 'Emit {C}MiniTerminal{W}-friendly output for the {C}Kalidroid{W} app: ' + 'flatten carriage-return progress redraws into discrete lines and ' + 'skip clear-line escapes (default: {G}off{W})')) + glob.add_argument('-i', action='store', dest='interface', diff --git a/wifite/attack/all.py b/wifite/attack/all.py index 29703d5f4..b32497f33 100755 --- a/wifite/attack/all.py +++ b/wifite/attack/all.py @@ -12,7 +12,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 diff --git a/wifite/attack/attack_monitor.py b/wifite/attack/attack_monitor.py index 96e8baa47..31820efa3 100755 --- a/wifite/attack/attack_monitor.py +++ b/wifite/attack/attack_monitor.py @@ -13,9 +13,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..b0c6f2d02 100755 --- a/wifite/attack/eviltwin.py +++ b/wifite/attack/eviltwin.py @@ -12,9 +12,12 @@ import re import time import signal -from typing import Optional, List +from typing import TYPE_CHECKING from enum import Enum +if TYPE_CHECKING: + from ..util.session import EvilTwinAttackState + from ..model.attack import Attack from ..model.eviltwin_result import CrackResultEvilTwin from ..config import Configuration @@ -25,7 +28,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 +253,6 @@ 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 # 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 +1473,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 +2074,6 @@ def restore_state_from_session(self, state: 'EvilTwinAttackState') -> bool: True if state was restored successfully, False otherwise """ try: - from ..util.session import EvilTwinAttackState # Restore configuration self.interface_ap = state.interface_ap or self.interface_ap @@ -2137,7 +2136,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 +2166,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/pmkid.py b/wifite/attack/pmkid.py index 20b61d1f2..bdda1b7d1 100755 --- a/wifite/attack/pmkid.py +++ b/wifite/attack/pmkid.py @@ -20,7 +20,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 @@ -565,7 +565,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 +633,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/portal/credential_handler.py b/wifite/attack/portal/credential_handler.py index 7b69b9cc9..d17d76bc4 100755 --- a/wifite/attack/portal/credential_handler.py +++ b/wifite/attack/portal/credential_handler.py @@ -12,7 +12,6 @@ from typing import Optional, Callable, Dict, List, Tuple 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 diff --git a/wifite/attack/portal/server.py b/wifite/attack/portal/server.py index 466dd8317..86791655e 100755 --- a/wifite/attack/portal/server.py +++ b/wifite/attack/portal/server.py @@ -10,7 +10,7 @@ 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 diff --git a/wifite/attack/portal/templates.py b/wifite/attack/portal/templates.py index 17a58ab5e..8cd9a5d5a 100755 --- a/wifite/attack/portal/templates.py +++ b/wifite/attack/portal/templates.py @@ -9,9 +9,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: diff --git a/wifite/attack/wep.py b/wifite/attack/wep.py index 7fe93d391..ea4cda51b 100755 --- a/wifite/attack/wep.py +++ b/wifite/attack/wep.py @@ -12,7 +12,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 diff --git a/wifite/attack/wpa.py b/wifite/attack/wpa.py index 06f1cddc7..510878c32 100755 --- a/wifite/attack/wpa.py +++ b/wifite/attack/wpa.py @@ -2,8 +2,7 @@ # -*- 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 @@ -17,6 +16,7 @@ import time import os import re +import subprocess from shutil import copy from contextlib import contextmanager @@ -70,7 +70,6 @@ def _error_recovery_context(self, operation_name: str): Yields: None - use 'with' statement to wrap operations """ - from ..util.logger import log_error, log_warning from ..util.process import ProcessManager, Process from ..util.memory import MemoryMonitor @@ -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_info('AttackWPA', 'Attempting interface recovery') Color.pl('{!} {O}Attempting interface recovery...{W}') @@ -176,7 +175,7 @@ def _run_with_retry(self, operation, operation_name: str, max_retries: int = Non Returns: Result of operation, or None if all retries failed """ - from ..util.logger import log_info, log_warning, log_error + from ..util.logger import log_info if max_retries is None: max_retries = self.MAX_RETRY_ATTEMPTS @@ -193,7 +192,7 @@ 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 @@ -817,7 +816,7 @@ def _set_interface_channels(self): If one interface fails, logs an error but continues with the working interface. """ from ..util.process import Process - from ..util.logger import log_error, log_debug, log_info + from ..util.logger import log_info target_channel = self.target.channel capture_success = False @@ -874,7 +873,6 @@ def _verify_channel_sync(self): and logs a warning if they don't match the target channel. """ from ..util.interface_manager import InterfaceManager - from ..util.logger import log_warning, log_debug try: # Get current channel of both interfaces @@ -1230,7 +1228,7 @@ def _capture_handshake_single_hcxdump(self): Handshake object if captured, None otherwise """ from ..tools.hcxdumptool import HcxDumpTool - from ..util.logger import log_info, log_debug, log_error + from ..util.logger import log_info handshake = None @@ -1278,7 +1276,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, diff --git a/wifite/attack/wpa3.py b/wifite/attack/wpa3.py index 0a616826a..7e69cb648 100755 --- a/wifite/attack/wpa3.py +++ b/wifite/attack/wpa3.py @@ -19,7 +19,7 @@ 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 @@ -780,7 +780,6 @@ def attempt_downgrade(self): Handshake object if successful, None otherwise """ from ..tools.hcxdumptool import HcxDumpTool - from ..model.handshake import Handshake handshake = None hcxdump = None diff --git a/wifite/config/__init__.py b/wifite/config/__init__.py index 461d7b9ed..928c20411 100644 --- a/wifite/config/__init__.py +++ b/wifite/config/__init__.py @@ -21,6 +21,7 @@ class Configuration: initialized = False # Flag indicating config has been initialized verbose = 0 + kalidroid = False # --kalidroid: MiniTerminal-friendly output for the Kalidroid app version = _get_version() all_bands = None diff --git a/wifite/config/parsers/settings.py b/wifite/config/parsers/settings.py index 3f4b9fe78..5e80c188c 100644 --- a/wifite/config/parsers/settings.py +++ b/wifite/config/parsers/settings.py @@ -11,6 +11,11 @@ def parse_settings_args(cls, args): """Parses basic settings/configurations from arguments.""" + if getattr(args, 'kalidroid', False): + cls.kalidroid = True + Color.kalidroid = True # already set early in Arguments.__init__; keep in sync + Color.pl('{+} {C}option:{W} {G}Kalidroid MiniTerminal{W} output mode enabled') + if args.random_mac or args.random_mac_vendor: if args.random_mac and args.random_mac_vendor: Color.pl('{!} {O}Warning: Cannot use both --random-mac and --random-mac-vendor') diff --git a/wifite/model/result.py b/wifite/model/result.py index 67fb16109..03dca0c17 100755 --- a/wifite/model/result.py +++ b/wifite/model/result.py @@ -4,7 +4,6 @@ from ..util.color import Color from ..config import Configuration -import glob import os import re import time diff --git a/wifite/model/sae_handshake.py b/wifite/model/sae_handshake.py index 114893417..86c0273eb 100755 --- a/wifite/model/sae_handshake.py +++ b/wifite/model/sae_handshake.py @@ -13,7 +13,6 @@ from ..tools.tshark import Tshark import os -import re from typing import Dict, Optional, List, Any diff --git a/wifite/native/beacon.py b/wifite/native/beacon.py index 5c40cc10b..f47feaf86 100644 --- a/wifite/native/beacon.py +++ b/wifite/native/beacon.py @@ -23,7 +23,7 @@ import time import secrets from threading import Thread, Event -from typing import Optional, List +from typing import Optional try: from scapy.all import ( diff --git a/wifite/native/deauth.py b/wifite/native/deauth.py index 756e3de79..820145e14 100644 --- a/wifite/native/deauth.py +++ b/wifite/native/deauth.py @@ -35,9 +35,8 @@ """ import time -import random from threading import Thread, Event -from typing import Optional, List, Tuple, Callable +from typing import Optional, Tuple, Callable try: from scapy.all import ( diff --git a/wifite/native/interface.py b/wifite/native/interface.py index c01091be1..0a5d09b72 100644 --- a/wifite/native/interface.py +++ b/wifite/native/interface.py @@ -32,7 +32,7 @@ import socket import struct import fcntl -from typing import Optional, List, Dict, Tuple +from typing import Optional, List, Tuple from dataclasses import dataclass diff --git a/wifite/native/mac.py b/wifite/native/mac.py index ada0c68bb..bc19fc834 100644 --- a/wifite/native/mac.py +++ b/wifite/native/mac.py @@ -24,7 +24,6 @@ NativeMac.reset('wlan0') """ -import os import re import secrets import fcntl diff --git a/wifite/native/pmkid.py b/wifite/native/pmkid.py index 6f27ca431..a4f68cf46 100644 --- a/wifite/native/pmkid.py +++ b/wifite/native/pmkid.py @@ -29,11 +29,10 @@ 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 typing import Optional, List, Callable from dataclasses import dataclass try: diff --git a/wifite/native/scanner.py b/wifite/native/scanner.py index c32acec86..620e1021d 100644 --- a/wifite/native/scanner.py +++ b/wifite/native/scanner.py @@ -30,9 +30,8 @@ import time from threading import Thread, Event, Lock -from typing import Optional, List, Dict, Set, Callable +from typing import Optional, List, Dict, Callable from dataclasses import dataclass, field -from collections import defaultdict try: from scapy.all import ( diff --git a/wifite/native/wps.py b/wifite/native/wps.py index dd004b185..bb815cdeb 100644 --- a/wifite/native/wps.py +++ b/wifite/native/wps.py @@ -27,8 +27,7 @@ """ import os -from typing import Optional, List, Dict, Set -from collections import defaultdict +from typing import Optional, List, Dict try: from scapy.all import ( diff --git a/wifite/tools/airodump.py b/wifite/tools/airodump.py index 82ff1991a..e91e55d03 100755 --- a/wifite/tools/airodump.py +++ b/wifite/tools/airodump.py @@ -241,7 +241,6 @@ def get_targets(self, old_targets=None, apply_filter=True, target_archives=None) def get_targets_from_csv(csv_filename): """Returns list of Target objects parsed from CSV file.""" targets2 = [] - import csv # Detect encoding from first 4KB sample to avoid reading entire file twice try: diff --git a/wifite/tools/hashcat.py b/wifite/tools/hashcat.py index e4dd6b374..084b920da 100755 --- a/wifite/tools/hashcat.py +++ b/wifite/tools/hashcat.py @@ -193,7 +193,6 @@ def get_version(): if Hashcat._cached_version is not None: return Hashcat._cached_version - import re try: process = Process(['hashcat', '--version']) stdout = process.stdout() @@ -465,7 +464,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() diff --git a/wifite/tools/hostapd.py b/wifite/tools/hostapd.py index 077844bc1..04ac7d8fd 100755 --- a/wifite/tools/hostapd.py +++ b/wifite/tools/hostapd.py @@ -9,7 +9,6 @@ import os import time import tempfile -from typing import Optional from .dependency import Dependency from ..config import Configuration diff --git a/wifite/tools/wlancap2wpasec.py b/wifite/tools/wlancap2wpasec.py index 4ef3bf38e..9b83cfd23 100755 --- a/wifite/tools/wlancap2wpasec.py +++ b/wifite/tools/wlancap2wpasec.py @@ -5,7 +5,6 @@ import re from .dependency import Dependency from ..util.process import Process -from ..util.color import Color class Wlancap2wpasec(Dependency): diff --git a/wifite/ui/attack_view.py b/wifite/ui/attack_view.py index 7f1a7c800..bf72420f6 100755 --- a/wifite/ui/attack_view.py +++ b/wifite/ui/attack_view.py @@ -509,7 +509,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 +931,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 +1250,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/components.py b/wifite/ui/components.py index 6128416b3..dfd2f7cf4 100755 --- a/wifite/ui/components.py +++ b/wifite/ui/components.py @@ -8,11 +8,9 @@ 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: @@ -136,9 +134,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: diff --git a/wifite/ui/scanner_view.py b/wifite/ui/scanner_view.py index e16d7851d..7a353f20d 100755 --- a/wifite/ui/scanner_view.py +++ b/wifite/ui/scanner_view.py @@ -100,7 +100,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 +113,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 +121,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 +139,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( diff --git a/wifite/util/adaptive_deauth.py b/wifite/util/adaptive_deauth.py index 7a08df78e..99efd1781 100755 --- a/wifite/util/adaptive_deauth.py +++ b/wifite/util/adaptive_deauth.py @@ -9,8 +9,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..079b5a4a0 100755 --- a/wifite/util/cleanup.py +++ b/wifite/util/cleanup.py @@ -14,8 +14,7 @@ import os import re import signal -import subprocess -from typing import List, Optional, Tuple +from typing import List, Tuple from .process import Process from .color import Color diff --git a/wifite/util/client_monitor.py b/wifite/util/client_monitor.py index 00ed4f0a8..e7ec0c94c 100755 --- a/wifite/util/client_monitor.py +++ b/wifite/util/client_monitor.py @@ -15,7 +15,6 @@ from threading import Thread, Lock from typing import Dict, List, Optional, Callable from dataclasses import dataclass, field -from datetime import datetime @dataclass diff --git a/wifite/util/color.py b/wifite/util/color.py index b48b62e92..9ba8a073d 100755 --- a/wifite/util/color.py +++ b/wifite/util/color.py @@ -29,6 +29,19 @@ class Color: last_sameline_length = 0 + # ── Kalidroid MiniTerminal mode ─────────────────────────────────────────── + # The Kalidroid Android app streams wifite's stdout into a MiniTerminal: an + # append-only scrollback view, NOT a terminal emulator. Carriage-return + # redraws (the live attack progress lines) and clear-line escapes therefore + # render as overwritten/garbled text. When --kalidroid is set these are + # flattened into discrete, newline-terminated lines (throttled so a + # per-second timer doesn't flood the view) and the clear-line ops become + # no-ops. ANSI colours are kept — the MiniTerminal parses SGR codes. + kalidroid = False + _kalidroid_last_emit = 0.0 + _kalidroid_last_line = '' + _KALIDROID_MIN_INTERVAL = 0.4 # seconds between same-line progress emits + @staticmethod def p(text): """ @@ -36,6 +49,9 @@ def p(text): Example: Color.p('{R}This text is red. {W} This text is white') """ + if Color.kalidroid: + Color._p_kalidroid(text) + return sys.stdout.write(Color.s(text)) sys.stdout.flush() if '\r' in text: @@ -44,6 +60,34 @@ def p(text): else: Color.last_sameline_length += len(text) + @staticmethod + def _p_kalidroid(text): + """ + Same as [p] but for the Kalidroid MiniTerminal: a carriage-return + same-line update (e.g. the per-second attack progress line) is emitted + as its own newline-terminated line so the append-only scrollback stays + readable. Identical consecutive redraws and bursts faster than + [_KALIDROID_MIN_INTERVAL] are dropped so timers don't flood the view. + Plain text (no '\\r') — including the newline-terminated Color.pl prints + — passes through unchanged, so final/result lines are never throttled. + """ + if '\r' not in text: + sys.stdout.write(Color.s(text)) + sys.stdout.flush() + return + content = text[text.rfind('\r') + 1:].rstrip('\n') + if content.strip() == '': + return # bare '\r' / whitespace-only clear carries no information + import time + now = time.time() + if (content == Color._kalidroid_last_line + or now - Color._kalidroid_last_emit < Color._KALIDROID_MIN_INTERVAL): + return + Color._kalidroid_last_emit = now + Color._kalidroid_last_line = content + sys.stdout.write(Color.s(content) + '\n') + sys.stdout.flush() + @staticmethod def pl(text): """Prints text using colored format with trailing new line.""" @@ -71,6 +115,11 @@ def s(text): @staticmethod def clear_line(): + # MiniTerminal has no cursor to rewind — the '\r\r' erase would + # just append blanks. The flattened progress lines stand on their own. + if Color.kalidroid: + Color.last_sameline_length = 0 + return spaces = ' ' * Color.last_sameline_length sys.stdout.write('\r%s\r' % spaces) sys.stdout.flush() @@ -78,6 +127,9 @@ def clear_line(): @staticmethod def clear_entire_line(): + if Color.kalidroid: + Color.last_sameline_length = 0 + return import shutil columns = shutil.get_terminal_size(fallback=(80, 24)).columns Color.p('\r' + (' ' * columns) + '\r') diff --git a/wifite/util/credential_validator.py b/wifite/util/credential_validator.py index bbec5978a..b16748105 100755 --- a/wifite/util/credential_validator.py +++ b/wifite/util/credential_validator.py @@ -17,7 +17,6 @@ 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 diff --git a/wifite/util/dragonblood.py b/wifite/util/dragonblood.py index 9be80678a..8df0a675a 100755 --- a/wifite/util/dragonblood.py +++ b/wifite/util/dragonblood.py @@ -18,7 +18,7 @@ - https://papers.mathyvanhoef.com/dragonblood.pdf """ -from typing import Dict, List, Optional +from typing import Dict, List from ..util.color import Color diff --git a/wifite/util/dragonblood_timing.py b/wifite/util/dragonblood_timing.py index aa7e80f2b..a2a48cdde 100644 --- a/wifite/util/dragonblood_timing.py +++ b/wifite/util/dragonblood_timing.py @@ -26,7 +26,7 @@ import time import tempfile import statistics -from typing import List, Dict, Optional, Tuple +from typing import List, Dict, Optional from dataclasses import dataclass, field from ..util.process import Process diff --git a/wifite/util/interface_assignment.py b/wifite/util/interface_assignment.py index b9e2f3422..0275ae604 100755 --- a/wifite/util/interface_assignment.py +++ b/wifite/util/interface_assignment.py @@ -11,7 +11,7 @@ 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: @@ -162,7 +162,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) @@ -315,7 +315,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( diff --git a/wifite/util/interface_exceptions.py b/wifite/util/interface_exceptions.py index 6a3955b8d..8098eff74 100755 --- a/wifite/util/interface_exceptions.py +++ b/wifite/util/interface_exceptions.py @@ -55,7 +55,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..fbcf12789 100755 --- a/wifite/util/interface_manager.py +++ b/wifite/util/interface_manager.py @@ -10,7 +10,7 @@ import os import re -from typing import Optional, List, Tuple, Dict +from typing import Optional, List, Dict from dataclasses import dataclass from ..tools.iw import Iw @@ -771,12 +771,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 +858,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 +871,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 +879,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 +924,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 @@ -1548,7 +1548,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: diff --git a/wifite/util/logger.py b/wifite/util/logger.py index 9ec3e6656..c4ac362c3 100755 --- a/wifite/util/logger.py +++ b/wifite/util/logger.py @@ -8,7 +8,6 @@ import os import sys -import time import traceback from datetime import datetime from typing import Optional diff --git a/wifite/util/process.py b/wifite/util/process.py index ce3f30da8..aae9ce152 100755 --- a/wifite/util/process.py +++ b/wifite/util/process.py @@ -253,7 +253,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() diff --git a/wifite/util/retry.py b/wifite/util/retry.py index 55f0a1c6f..dff0baff2 100755 --- a/wifite/util/retry.py +++ b/wifite/util/retry.py @@ -12,7 +12,7 @@ import secrets _sysrng = secrets.SystemRandom() from functools import wraps -from typing import Callable, Optional, Tuple, Type, Union, Any +from typing import Callable, Optional, Tuple, Type class RetryExhausted(Exception): diff --git a/wifite/util/sae_crack.py b/wifite/util/sae_crack.py index a42014601..a9b42ea82 100755 --- a/wifite/util/sae_crack.py +++ b/wifite/util/sae_crack.py @@ -9,13 +9,12 @@ """ import os -import re import time -from typing import Optional, Dict, Any, List +from typing import Optional, Dict 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 diff --git a/wifite/util/scanner.py b/wifite/util/scanner.py index fd59410b5..1305bd559 100755 --- a/wifite/util/scanner.py +++ b/wifite/util/scanner.py @@ -7,7 +7,6 @@ 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: @@ -410,8 +409,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') diff --git a/wifite/util/session.py b/wifite/util/session.py index d6eec2deb..545daf3d7 100755 --- a/wifite/util/session.py +++ b/wifite/util/session.py @@ -865,7 +865,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 +931,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 +941,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 +986,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 +1001,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 +1029,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 +1062,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/system_check.py b/wifite/util/system_check.py index 8205b9dc6..72f458469 100755 --- a/wifite/util/system_check.py +++ b/wifite/util/system_check.py @@ -21,7 +21,7 @@ import re import subprocess import shutil -from typing import Optional, List, Dict, Tuple +from typing import Optional, List, Dict from dataclasses import dataclass, field from enum import Enum @@ -380,6 +380,7 @@ def check_interfaces(self) -> List[InterfaceCheckResult]: # Chipset (from airmon or driver map) try: from ..tools.airmon import Airmon + from .interface_manager import InterfaceManager info = Airmon.get_iface_info(iface) if info and info.chipset: result.chipset = info.chipset @@ -774,15 +775,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/tui_logger.py b/wifite/util/tui_logger.py index 94f2e6792..db38f8319 100755 --- a/wifite/util/tui_logger.py +++ b/wifite/util/tui_logger.py @@ -8,7 +8,6 @@ import os import stat -import time from datetime import datetime diff --git a/wifite/util/wpa3_tools.py b/wifite/util/wpa3_tools.py index e74678385..3b81ba990 100755 --- a/wifite/util/wpa3_tools.py +++ b/wifite/util/wpa3_tools.py @@ -247,12 +247,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(f' {tool}: {{C}}{url}{{W}}') 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(f' {tool}: {{O}}v{current}{{W}} (minimum: {{C}}v{minimum}{{W}})') if all_available and not outdated_tools: Color.pl('\n{+} {G}All WPA3 tools are available and up to date!{W}') diff --git a/wifite/util/wpasec_uploader.py b/wifite/util/wpasec_uploader.py index cbaeb127e..2c08c916a 100755 --- a/wifite/util/wpasec_uploader.py +++ b/wifite/util/wpasec_uploader.py @@ -486,7 +486,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 +546,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..2e3c9229a 100644 --- a/wifite/wifite.py +++ b/wifite/wifite.py @@ -87,7 +87,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 +259,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 +482,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 +781,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 = []