From a824972ad950d86fd08e21b3ff43636a7035d4e6 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Mar 2026 01:21:25 +0000 Subject: [PATCH] Fix WPS and CLI column alignment in scan display The to_str() method used inconsistent column widths and separators that didn't match the header defined in scanner.py, causing WPS values to appear under the CLI header and client counts to overflow past the table. - Add _pad_colored() helper to pad ANSI-colored strings to exact visible widths - Use consistent 2-space separators between all columns - Match column widths (ESSID:26, BSSID:19, MFG:23, CH:4, ENCR:9, PWR:7, WPS:5, CLI:7) - Fix classic.py header to use same column order and widths as scanner.py https://claude.ai/code/session_019ijpUyTX2ZGrr1123Hteea --- wifite/model/target.py | 60 ++++++++++++++++++++++++++++++++++-------- wifite/ui/classic.py | 27 ++++++++++++++----- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/wifite/model/target.py b/wifite/model/target.py index 55cd23468..c414a36b2 100644 --- a/wifite/model/target.py +++ b/wifite/model/target.py @@ -48,6 +48,21 @@ class Target: """ _ansi_re = re.compile(r'\033\[[0-9;]*m') + def _pad_colored(self, colored_str, width, align='left'): + """Pad a colored string to a specific visible width.""" + visible = self._ansi_re.sub('', colored_str) + diff = width - len(visible) + if diff <= 0: + return colored_str + if align == 'right': + return ' ' * diff + colored_str + elif align == 'center': + left_pad = diff // 2 + right_pad = diff - left_pad + return ' ' * left_pad + colored_str + ' ' * right_pad + else: + return colored_str + ' ' * diff + def __init__(self, fields): """ Initializes & stores target info based on fields. @@ -249,7 +264,7 @@ def to_str(self, show_bssid=False, show_manufacturer=False): decloaked_char = Color.s('{P}*') if self.decloaked else ' ' essid += decloaked_char - bssid = Color.s('{D}%s{W} ' % self.bssid) if show_bssid else '' + bssid = Color.s('{D}%s{W}' % self.bssid) if show_bssid else '' if show_manufacturer: oui = ''.join(self.bssid.split(':')[:3]) self.manufacturer = Configuration.manufacturers.get(oui, "") @@ -260,7 +275,7 @@ def to_str(self, show_bssid=False, show_manufacturer=False): mfg_name = f'{mfg_name[:max_oui_len - 3]}...' else: mfg_name = mfg_name.ljust(max_oui_len) - manufacturer = Color.s('{W}%s ' % mfg_name) + manufacturer = Color.s('{W}%s' % mfg_name) else: manufacturer = '' @@ -328,21 +343,44 @@ def to_str(self, show_bssid=False, show_manufacturer=False): power = f'{pwr_bar} {Color.s("{%s}%s" % (pwr_color, str(pwr_dbm).rjust(2)))}' if self.wps == WPSState.UNLOCKED: - wps = Color.s(' {G}yes') + wps = Color.s('{G}yes') elif self.wps == WPSState.NONE: - wps = Color.s(' {D} - ') + wps = Color.s('{D}-') elif self.wps == WPSState.LOCKED: - wps = Color.s(' {R}lck') + wps = Color.s('{R}lck') elif self.wps == WPSState.UNKNOWN: - wps = Color.s(' {O} ? ') + wps = Color.s('{O}?') else: - wps = ' - ' + wps = '-' - clients = Color.s('{D} - ') if len(self.clients) > 0: - clients = Color.s('{G} %s' % str(len(self.clients))) - - result = f'{essid} {bssid}{manufacturer}{channel} {encryption_display_string} {power} {wps} {clients}' + clients = Color.s('{G}%s' % str(len(self.clients))) + else: + clients = Color.s('{D}-') + + # Column widths must match scanner.py header + COL_ESSID = 26 + COL_BSSID = 19 + COL_MFG = 23 + COL_CH = 4 + COL_ENC = 9 + COL_PWR = 7 + COL_WPS = 5 + COL_CLI = 7 + SEP = ' ' + + parts = [self._pad_colored(essid, COL_ESSID)] + if show_bssid: + parts.append(self._pad_colored(bssid, COL_BSSID)) + if show_manufacturer: + parts.append(self._pad_colored(manufacturer, COL_MFG)) + parts.append(self._pad_colored(channel, COL_CH, 'right')) + parts.append(self._pad_colored(encryption_display_string, COL_ENC)) + parts.append(self._pad_colored(power, COL_PWR, 'right')) + parts.append(self._pad_colored(wps, COL_WPS, 'center')) + parts.append(self._pad_colored(clients, COL_CLI, 'right')) + + result = SEP.join(parts) result += Color.s('{W}') return result diff --git a/wifite/ui/classic.py b/wifite/ui/classic.py index 317ebbb24..adc3d8e38 100755 --- a/wifite/ui/classic.py +++ b/wifite/ui/classic.py @@ -48,20 +48,35 @@ def display_targets(self, targets, show_bssid=False, show_manufacturer=False): Color.pl('{+} {C}Targets{W}') Color.pl('') - # Print header - header = ' NUM' + # Print header (column widths must match target.to_str()) + col_num = 5 + col_essid = 26 + col_bssid = 19 + col_mfg = 23 + col_ch = 4 + col_enc = 9 + col_pwr = 7 + col_wps = 5 + col_cli = 7 + + header = ' ' + 'NUM'.rjust(col_num) + header += ' ' + 'ESSID'.ljust(col_essid) if show_bssid: - header += ' BSSID ' + header += ' ' + 'BSSID'.ljust(col_bssid) if show_manufacturer: - header += ' MANUFACTURER ' - header += ' ESSID CH PWR ENC WPS CLIENT' + header += ' ' + 'MANUFACTURER'.ljust(col_mfg) + header += ' ' + 'CH'.rjust(col_ch) + header += ' ' + 'ENCR'.ljust(col_enc) + header += ' ' + 'PWR'.rjust(col_pwr) + header += ' ' + 'WPS'.center(col_wps) + header += ' ' + 'CLI'.rjust(col_cli) Color.pl(header) Color.pl(' ' + '-' * (len(header) - 2)) # Print targets for idx, target in enumerate(targets, start=1): target_str = target.to_str(show_bssid=show_bssid, show_manufacturer=show_manufacturer) - Color.pl(' {G}%3d{W} %s' % (idx, target_str)) + Color.pl(' {G}%s{W} %s' % (str(idx).rjust(col_num), target_str)) Color.pl('')