From 9eeadaea542ae34d8697d719e55005a3bc1bd9b4 Mon Sep 17 00:00:00 2001 From: tvroi Date: Sun, 20 Jul 2025 12:26:45 +0700 Subject: [PATCH 01/15] feat: add user tab --- gui/user_tab.py | 188 +++++++++++++++++++++++++++++++++++++++++++ helpers/initiator.py | 4 + 2 files changed, 192 insertions(+) create mode 100644 gui/user_tab.py diff --git a/gui/user_tab.py b/gui/user_tab.py new file mode 100644 index 0000000..d4225f8 --- /dev/null +++ b/gui/user_tab.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from javax.swing import JPanel +from javax.swing import JLabel +from javax.swing import JButton +from javax.swing import JTabbedPane +from javax.swing import JOptionPane +from java.awt import BorderLayout +from java.awt import FlowLayout +from java.awt import Font +from java.awt.event import ActionListener + +from gui.enforcement_detector import EnforcementDetectors +from gui.match_replace import MatchReplace + +class UserTab(): + def _init_(self, extender): + self._extender = extender + self.user_count = 0 + self.user_tabs = {} + + def draw(self): + self._extender.userPanel = JPanel(BorderLayout()) + + buttonPanel = JPanel(FlowLayout(FlowLayout.LEFT)) + + self.addUserBtn = JButton("Add User") + self.addUserBtn.addActionListener(AddUserAction(self)) + buttonPanel.add(self.addUserBtn) + + self.removeUserBtn = JButton("Remove User") + self.addUserBtn.addActionListener(RemoveUserAction(self)) + buttonPanel.add(self.removeUserBtn) + + self.duplicateUserBtn = JButton("Duplicate User") + self.duplicateUserBtn.addActionListerner(DuplicateUserAction(self)) + buttonPanel.add(self.duplicateUserBtn) + + self.userTabs = JTabbedPane() + self.add_user() + + self._extender.userPanel.add(buttonPanel, BorderLayout.NORTH) + self._extender.userPanel.add(self.userTabs, BorderLayout.CENTER) + + def add_user(self): + self.user_count += 1 + user_name = "User {}".format(self.user_count) + + userPanel = JPanel(BorderLayout()) + + headerPanel = JPanel(FlowLayout(FlowLayout.LEFT)) + headerLabel = JLabel(user_name) + headerLabel.setFont(Font("Tahoma", Font.BOLD, 16)) + headerPanel.add(headerLabel) + + userSubTabs = JTabbedPane() + + user_ed = UserEnforcementDetector(self._extender, self.user_count) + user_ed.draw() + user_ed.draw_unauthenticated() + + user_mr = UserMatchReplace(self._extender, self.user_count) + user_mr.draw() + + userSubTabs.addTab("Enforcement Detector", user_ed.EDPnl) + + userSubTabs.addTab("Match/Replace", user_mr.MRPnl) + + userPanel.add(headerPanel, BorderLayout.NORTH) + userPanel.add(userSubTabs, BorderLayout.CENTER) + + self.user_tabs[self.user_count] = { + 'panel': userPanel, + 'subtabs': userSubTabs, + 'ed_instance': user_ed, + 'mr_instance': user_mr, + 'header_label': headerLabel + } + + self.userTabs.addTab(user_name, userPanel) + + self.userTabs.setSelectedIndex(self.userTabs.getTabCount() - 1) + + def remove_user(self): + if self.userTabs.getTabCount() <= 1: + JOptionPane.showMessageDialog(None, "Cannot remove the last user!", "Warning", JOptionPane.WARNING_MESSAGE) + return + + selected_index = self.userTabs.getSelectedIndex() + if selected_index >= 0: + self.userTabs.removeTabAt(selected_index) + + + def duplicate_user(self): + selected_index = self.userTabs.getSelectedIndex() + if selected_index >= 0: + self.add_user() + + def rename_user(self): + selected_index = self.userTabs.getSelectedIndex() + if selected_index >= 0: + current_name = self.userTabs.getTitleAt(selected_index) + new_name = JOptionPane.showInputDialog(None, "Enter new name for user:", "Rename User", JOptionPane.QUESTION_MESSAGE, None, None, current_name) + + if new_name and new_name.strip(): + self.userTabs.setTitleAt(selected_index, new_name.strip()) + + for user_id, user_data in self.user_tabs.items(): + if user_data['panel'] == self.userTabs.getComponentAt(selected_index): + user_data['header_label'].setText(new_name.strip()) + break + +class UserEnforcementDetector(EnforcementDetectors): + def __init__(self, extender, user_id): + EnforcementDetectors.__init__(self, extender) + self.user_id = user_id + self.prefix = "User{}_".format(user_id) + + def draw(self): + EnforcementDetectors.draw(self) + + self.EDPnl = self._extender.EDPnl + setattr(self._extender, self.prefix + "EDPnl", self._extender.EDPnl) + setattr(self._extender, self.prefix + "EDType", self._extender.EDType) + setattr(self._extender, self.prefix + "EDText", self._extender.EDText) + setattr(self._extender, self.prefix + "EDModel", self._extender.EDModel) + setattr(self._extender, self.prefix + "EDList", self._extender.EDList) + setattr(self._extender, self.prefix + "AndOrType", self._extender.AndOrType) + + def draw_unauthenticated(self): + EnforcementDetectors.draw_unauthenticated(self) + + self.EDPnlUnauth = self._extender.EDPnlUnauth + setattr(self._extender, self.prefix + "EDPnlUnauth", self._extender.EDPnlUnauth) + setattr(self._extender, self.prefix + "EDTypeUnauth", self._extender.EDTypeUnauth) + setattr(self._extender, self.prefix + "EDTextUnauth", self._extender.EDTextUnauth) + setattr(self._extender, self.prefix + "EDModelUnauth", self._extender.EDModelUnauth) + setattr(self._extender, self.prefix + "EDListUnauth", self._extender.EDListUnauth) + setattr(self._extender, self.prefix + "AndOrTypeUnauth", self._extender.AndOrTypeUnauth) + + + +class UserMatchReplace(MatchReplace): + def __init__(self, extender, user_id): + MatchReplace.__init__(self, extender) + self.user_id = user_id + self.prefix = "User{}_".format(user_id) + + def draw(self): + MatchReplace.draw(self) + + self.MRPnl = self._extender.MRPnl + setattr(self._extender, self.prefix + "MRPnl", self._extender.MRPnl) + setattr(self._extender, self.prefix + "MRType", self._extender.MRType) + setattr(self._extender, self.prefix + "MText", self._extender.MText) + setattr(self._extender, self.prefix + "RText", self._extender.RText) + setattr(self._extender, self.prefix + "MRModel", self._extender.MRModel) + setattr(self._extender, self.prefix + "MRList", self._extender.MRList) + setattr(self._extender, self.prefix + "badProgrammerMRModel", self._extender.badProgrammerMRModel) + +class AddUserAction(ActionListener): + def __init__(self, user_tab): + self.user_tab = user_tab + + def actionPerformed(self, event): + self.user_tab.add_user() + +class RemoveUserAction(ActionListener): + def __init__(self, user_tab): + self.user_tab = user_tab + + def actionPerformed(self, event): + self.user_tab.remove_user() + +class DuplicateUserAction(ActionListener): + def __init__(self, user_tab): + self.user_tab = user_tab + + def actionPerformed(self, event): + self.user_tab.duplicate_user() + +class RenameUserAction(ActionListener): + def __init__(self, user_tab): + self.user_tab = user_tab + + def actionPerformed(self, event): + self.user_tab.rename_user() \ No newline at end of file diff --git a/helpers/initiator.py b/helpers/initiator.py index a4d0947..141f057 100644 --- a/helpers/initiator.py +++ b/helpers/initiator.py @@ -9,6 +9,7 @@ from gui.table import TableFilter from gui.export import Export from gui.menu import MenuImpl +from gui.user_tab import UserTab from java.util import ArrayList from threading import Lock @@ -54,6 +55,9 @@ def draw_all(self): cfg_tab = ConfigurationTab(self._extender) cfg_tab.draw() + user_tab = UserTab(self._extender) + user_tab.draw() + tabs = Tabs(self._extender) tabs.draw() From 58a13483721df9d2bc1024de62634d105fba844b Mon Sep 17 00:00:00 2001 From: tvroi Date: Sun, 20 Jul 2025 12:31:07 +0700 Subject: [PATCH 02/15] feat: add user tab to tabs --- gui/tabs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gui/tabs.py b/gui/tabs.py index 2094497..0b82625 100644 --- a/gui/tabs.py +++ b/gui/tabs.py @@ -174,6 +174,7 @@ def draw(self): self._extender.tabs.setMinimumSize(Dimension(1,1)) self._extender._splitpane.setRightComponent(self._extender.tabs) + self._extender.tabs.addTab("User", self._extender.userPanel) class SendRequestRepeater(ActionListener): def __init__(self, extender, callbacks, original): From 83b7958b947253092892c6f5710cc26e7cbceef5 Mon Sep 17 00:00:00 2001 From: tvroi Date: Sun, 20 Jul 2025 12:35:14 +0700 Subject: [PATCH 03/15] fix: argument issues --- gui/user_tab.py | 81 ++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/gui/user_tab.py b/gui/user_tab.py index d4225f8..7fa08a6 100644 --- a/gui/user_tab.py +++ b/gui/user_tab.py @@ -1,75 +1,76 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from javax.swing import JPanel -from javax.swing import JLabel -from javax.swing import JButton -from javax.swing import JTabbedPane -from javax.swing import JOptionPane -from java.awt import BorderLayout -from java.awt import FlowLayout -from java.awt import Font +from javax.swing import (JPanel, JLabel, JButton, JTabbedPane, JOptionPane) +from java.awt import BorderLayout, FlowLayout, Font from java.awt.event import ActionListener from gui.enforcement_detector import EnforcementDetectors from gui.match_replace import MatchReplace class UserTab(): - def _init_(self, extender): + def __init__(self, extender): self._extender = extender self.user_count = 0 self.user_tabs = {} - + def draw(self): self._extender.userPanel = JPanel(BorderLayout()) - + buttonPanel = JPanel(FlowLayout(FlowLayout.LEFT)) - + self.addUserBtn = JButton("Add User") self.addUserBtn.addActionListener(AddUserAction(self)) buttonPanel.add(self.addUserBtn) - + self.removeUserBtn = JButton("Remove User") - self.addUserBtn.addActionListener(RemoveUserAction(self)) + self.removeUserBtn.addActionListener(RemoveUserAction(self)) buttonPanel.add(self.removeUserBtn) - + self.duplicateUserBtn = JButton("Duplicate User") - self.duplicateUserBtn.addActionListerner(DuplicateUserAction(self)) + self.duplicateUserBtn.addActionListener(DuplicateUserAction(self)) buttonPanel.add(self.duplicateUserBtn) - + + self.renameUserBtn = JButton("Rename User") + self.renameUserBtn.addActionListener(RenameUserAction(self)) + buttonPanel.add(self.renameUserBtn) + self.userTabs = JTabbedPane() + self.add_user() - + self._extender.userPanel.add(buttonPanel, BorderLayout.NORTH) self._extender.userPanel.add(self.userTabs, BorderLayout.CENTER) - + def add_user(self): self.user_count += 1 user_name = "User {}".format(self.user_count) - + userPanel = JPanel(BorderLayout()) - + headerPanel = JPanel(FlowLayout(FlowLayout.LEFT)) headerLabel = JLabel(user_name) - headerLabel.setFont(Font("Tahoma", Font.BOLD, 16)) + headerLabel.setFont(Font("Tahoma", Font.BOLD, 12)) headerPanel.add(headerLabel) - + userSubTabs = JTabbedPane() - + user_ed = UserEnforcementDetector(self._extender, self.user_count) user_ed.draw() user_ed.draw_unauthenticated() - + user_mr = UserMatchReplace(self._extender, self.user_count) user_mr.draw() userSubTabs.addTab("Enforcement Detector", user_ed.EDPnl) - + + userSubTabs.addTab("Unauthentication Detector", user_ed.EDPnlUnauth) + userSubTabs.addTab("Match/Replace", user_mr.MRPnl) - + userPanel.add(headerPanel, BorderLayout.NORTH) userPanel.add(userSubTabs, BorderLayout.CENTER) - + self.user_tabs[self.user_count] = { 'panel': userPanel, 'subtabs': userSubTabs, @@ -77,11 +78,11 @@ def add_user(self): 'mr_instance': user_mr, 'header_label': headerLabel } - + self.userTabs.addTab(user_name, userPanel) - + self.userTabs.setSelectedIndex(self.userTabs.getTabCount() - 1) - + def remove_user(self): if self.userTabs.getTabCount() <= 1: JOptionPane.showMessageDialog(None, "Cannot remove the last user!", "Warning", JOptionPane.WARNING_MESSAGE) @@ -90,22 +91,20 @@ def remove_user(self): selected_index = self.userTabs.getSelectedIndex() if selected_index >= 0: self.userTabs.removeTabAt(selected_index) - - + def duplicate_user(self): selected_index = self.userTabs.getSelectedIndex() if selected_index >= 0: self.add_user() - + def rename_user(self): selected_index = self.userTabs.getSelectedIndex() if selected_index >= 0: current_name = self.userTabs.getTitleAt(selected_index) new_name = JOptionPane.showInputDialog(None, "Enter new name for user:", "Rename User", JOptionPane.QUESTION_MESSAGE, None, None, current_name) - + if new_name and new_name.strip(): self.userTabs.setTitleAt(selected_index, new_name.strip()) - for user_id, user_data in self.user_tabs.items(): if user_data['panel'] == self.userTabs.getComponentAt(selected_index): user_data['header_label'].setText(new_name.strip()) @@ -116,10 +115,10 @@ def __init__(self, extender, user_id): EnforcementDetectors.__init__(self, extender) self.user_id = user_id self.prefix = "User{}_".format(user_id) - + def draw(self): EnforcementDetectors.draw(self) - + self.EDPnl = self._extender.EDPnl setattr(self._extender, self.prefix + "EDPnl", self._extender.EDPnl) setattr(self._extender, self.prefix + "EDType", self._extender.EDType) @@ -127,10 +126,10 @@ def draw(self): setattr(self._extender, self.prefix + "EDModel", self._extender.EDModel) setattr(self._extender, self.prefix + "EDList", self._extender.EDList) setattr(self._extender, self.prefix + "AndOrType", self._extender.AndOrType) - + def draw_unauthenticated(self): EnforcementDetectors.draw_unauthenticated(self) - + self.EDPnlUnauth = self._extender.EDPnlUnauth setattr(self._extender, self.prefix + "EDPnlUnauth", self._extender.EDPnlUnauth) setattr(self._extender, self.prefix + "EDTypeUnauth", self._extender.EDTypeUnauth) @@ -139,8 +138,6 @@ def draw_unauthenticated(self): setattr(self._extender, self.prefix + "EDListUnauth", self._extender.EDListUnauth) setattr(self._extender, self.prefix + "AndOrTypeUnauth", self._extender.AndOrTypeUnauth) - - class UserMatchReplace(MatchReplace): def __init__(self, extender, user_id): MatchReplace.__init__(self, extender) From 8b54eb560b731d0ca398ffc7abf36a4f565134d5 Mon Sep 17 00:00:00 2001 From: tvroi Date: Sun, 20 Jul 2025 15:24:53 +0700 Subject: [PATCH 04/15] fix: user configuration --- gui/configuration_tab.py | 6 +- gui/user_tab.py | 169 ++++++++++++++++++++++++++++----------- 2 files changed, 126 insertions(+), 49 deletions(-) diff --git a/gui/configuration_tab.py b/gui/configuration_tab.py index 295d292..3697a0e 100644 --- a/gui/configuration_tab.py +++ b/gui/configuration_tab.py @@ -90,10 +90,10 @@ def draw(self): self._extender.filtersTabs = JTabbedPane() self._extender.filtersTabs = self._extender.filtersTabs - self._extender.filtersTabs.addTab("Enforcement Detector", self._extender.EDPnl) - self._extender.filtersTabs.addTab("Unauthentication Detector ", self._extender.EDPnlUnauth) + # self._extender.filtersTabs.addTab("Enforcement Detector", self._extender.EDPnl) + # self._extender.filtersTabs.addTab("Unauthentication Detector ", self._extender.EDPnlUnauth) self._extender.filtersTabs.addTab("Interception Filters", self._extender.filtersPnl) - self._extender.filtersTabs.addTab("Match/Replace", self._extender.MRPnl) + # self._extender.filtersTabs.addTab("Match/Replace", self._extender.MRPnl) self._extender.filtersTabs.addTab("Table Filter", self._extender.filterPnl) self._extender.filtersTabs.addTab("Save/Restore", self._extender.exportPnl) diff --git a/gui/user_tab.py b/gui/user_tab.py index 7fa08a6..91c0a7c 100644 --- a/gui/user_tab.py +++ b/gui/user_tab.py @@ -1,8 +1,14 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from javax.swing import (JPanel, JLabel, JButton, JTabbedPane, JOptionPane) -from java.awt import BorderLayout, FlowLayout, Font +from javax.swing import JPanel +from javax.swing import JLabel +from javax.swing import JButton +from javax.swing import JTabbedPane +from javax.swing import JOptionPane +from java.awt import BorderLayout +from java.awt import FlowLayout +from java.awt import Font from java.awt.event import ActionListener from gui.enforcement_detector import EnforcementDetectors @@ -13,7 +19,8 @@ def __init__(self, extender): self._extender = extender self.user_count = 0 self.user_tabs = {} - + self.user_names = [] + def draw(self): self._extender.userPanel = JPanel(BorderLayout()) @@ -45,21 +52,24 @@ def draw(self): def add_user(self): self.user_count += 1 user_name = "User {}".format(self.user_count) - + unique_user_name = self.get_unique_name(user_name) + + self.user_names.append(unique_user_name) + userPanel = JPanel(BorderLayout()) headerPanel = JPanel(FlowLayout(FlowLayout.LEFT)) - headerLabel = JLabel(user_name) + headerLabel = JLabel(unique_user_name) headerLabel.setFont(Font("Tahoma", Font.BOLD, 12)) headerPanel.add(headerLabel) userSubTabs = JTabbedPane() - user_ed = UserEnforcementDetector(self._extender, self.user_count) + user_ed = UserEnforcementDetector(self.user_count) user_ed.draw() user_ed.draw_unauthenticated() - user_mr = UserMatchReplace(self._extender, self.user_count) + user_mr = UserMatchReplace(self.user_count) user_mr.draw() userSubTabs.addTab("Enforcement Detector", user_ed.EDPnl) @@ -72,6 +82,8 @@ def add_user(self): userPanel.add(userSubTabs, BorderLayout.CENTER) self.user_tabs[self.user_count] = { + 'user_id': self.user_count, + 'user_name': unique_user_name, 'panel': userPanel, 'subtabs': userSubTabs, 'ed_instance': user_ed, @@ -79,7 +91,7 @@ def add_user(self): 'header_label': headerLabel } - self.userTabs.addTab(user_name, userPanel) + self.userTabs.addTab(unique_user_name, userPanel) self.userTabs.setSelectedIndex(self.userTabs.getTabCount() - 1) @@ -95,8 +107,57 @@ def remove_user(self): def duplicate_user(self): selected_index = self.userTabs.getSelectedIndex() if selected_index >= 0: - self.add_user() + selected_panel = self.userTabs.getComponentAt(selected_index) + source_user_data = None + + for user_id, user_data in self.user_tabs.items(): + if user_data['panel'] == selected_panel: + source_user_data = user_data + break + + if source_user_data: + self.add_user() + new_user_id = self.user_count + new_user_data = self.user_tabs[new_user_id] + + self.copy_ed_settings(source_user_data['ed_instance'], new_user_data['ed_instance']) + self.copy_mr_settings(source_user_data['mr_instance'], new_user_data['mr_instance']) + def copy_ed_settings(self, source_ed, target_ed): + target_ed.EDModel.clear() + for i in range(source_ed.EDModel.getSize()): + target_ed.EDModel.addElement(source_ed.EDModel.getElementAt(i)) + + target_ed.EDType.setSelectedIndex(source_ed.EDType.getSelectedIndex()) + target_ed.EDText.setText(source_ed.EDText.getText()) + target_ed.AndOrType.setSelectedIndex(source_ed.AndOrType.getSelectedIndex()) + + target_ed.EDModelUnauth.clear() + for i in range(source_ed.EDModelUnauth.getSize()): + target_ed.EDModelUnauth.addElement(source_ed.EDModelUnauth.getElementAt(i)) + + target_ed.EDTypeUnauth.setSelectedIndex(source_ed.EDTypeUnauth.getSelectedIndex()) + target_ed.EDTextUnauth.setText(source_ed.EDTextUnauth.getText()) + target_ed.AndOrTypeUnauth.setSelectedIndex(source_ed.AndOrTypeUnauth.getSelectedIndex()) + + def copy_mr_settings(self, source_mr, target_mr): + target_mr.MRModel.clear() + for i in range(source_mr.MRModel.getSize()): + target_mr.MRModel.addElement(source_mr.MRModel.getElementAt(i)) + + target_mr.MRType.setSelectedIndex(source_mr.MRType.getSelectedIndex()) + target_mr.MText.setText(source_mr.MText.getText()) + target_mr.RText.setText(source_mr.RText.getText()) + + target_mr.badProgrammerMRModel.clear() + for key, value in source_mr.badProgrammerMRModel.items(): + if hasattr(value, 'copy'): + target_mr.badProgrammerMRModel[key] = value.copy() + elif isinstance(value, dict): + target_mr.badProgrammerMRModel[key] = dict(value) + else: + target_mr.badProgrammerMRModel[key] = value + def rename_user(self): selected_index = self.userTabs.getSelectedIndex() if selected_index >= 0: @@ -104,57 +165,73 @@ def rename_user(self): new_name = JOptionPane.showInputDialog(None, "Enter new name for user:", "Rename User", JOptionPane.QUESTION_MESSAGE, None, None, current_name) if new_name and new_name.strip(): - self.userTabs.setTitleAt(selected_index, new_name.strip()) - for user_id, user_data in self.user_tabs.items(): + unique_name = self.get_unique_name(new_name.strip()) + + self.userTabs.setTitleAt(selected_index, unique_name) + for user_data in self.user_tabs.items(): if user_data['panel'] == self.userTabs.getComponentAt(selected_index): - user_data['header_label'].setText(new_name.strip()) + user_data['header_label'].setText(unique_name) + user_data['user_name'] = unique_name break + def get_unique_name(self, name): + if name not in self.user_names: + return name + + counter = 1 + while True: + candidate_name = "{} Copy".format(name) if counter == 1 else "{} Copy {}".format(name, counter) + + if candidate_name not in self.user_names: + return candidate_name + + counter += 1 + + if counter > 100: + return "{} Copy {}".format(name, counter) + class UserEnforcementDetector(EnforcementDetectors): - def __init__(self, extender, user_id): - EnforcementDetectors.__init__(self, extender) + def __init__(self, user_id): + self.isolated_extender = type('IsolatedExtender', (object,), {})() self.user_id = user_id - self.prefix = "User{}_".format(user_id) - + + EnforcementDetectors.__init__(self, self.isolated_extender) + def draw(self): EnforcementDetectors.draw(self) - - self.EDPnl = self._extender.EDPnl - setattr(self._extender, self.prefix + "EDPnl", self._extender.EDPnl) - setattr(self._extender, self.prefix + "EDType", self._extender.EDType) - setattr(self._extender, self.prefix + "EDText", self._extender.EDText) - setattr(self._extender, self.prefix + "EDModel", self._extender.EDModel) - setattr(self._extender, self.prefix + "EDList", self._extender.EDList) - setattr(self._extender, self.prefix + "AndOrType", self._extender.AndOrType) - + self.EDPnl = self.isolated_extender.EDPnl + self.EDType = self.isolated_extender.EDType + self.EDText = self.isolated_extender.EDText + self.EDModel = self.isolated_extender.EDModel + self.EDList = self.isolated_extender.EDList + self.AndOrType = self.isolated_extender.AndOrType + def draw_unauthenticated(self): EnforcementDetectors.draw_unauthenticated(self) - - self.EDPnlUnauth = self._extender.EDPnlUnauth - setattr(self._extender, self.prefix + "EDPnlUnauth", self._extender.EDPnlUnauth) - setattr(self._extender, self.prefix + "EDTypeUnauth", self._extender.EDTypeUnauth) - setattr(self._extender, self.prefix + "EDTextUnauth", self._extender.EDTextUnauth) - setattr(self._extender, self.prefix + "EDModelUnauth", self._extender.EDModelUnauth) - setattr(self._extender, self.prefix + "EDListUnauth", self._extender.EDListUnauth) - setattr(self._extender, self.prefix + "AndOrTypeUnauth", self._extender.AndOrTypeUnauth) + self.EDPnlUnauth = self.isolated_extender.EDPnlUnauth + self.EDTypeUnauth = self.isolated_extender.EDTypeUnauth + self.EDTextUnauth = self.isolated_extender.EDTextUnauth + self.EDModelUnauth = self.isolated_extender.EDModelUnauth + self.EDListUnauth = self.isolated_extender.EDListUnauth + self.AndOrTypeUnauth = self.isolated_extender.AndOrTypeUnauth class UserMatchReplace(MatchReplace): - def __init__(self, extender, user_id): - MatchReplace.__init__(self, extender) + def __init__(self, user_id): + self.isolated_extender = type('IsolatedExtender', (object,), {})() self.user_id = user_id - self.prefix = "User{}_".format(user_id) - + + MatchReplace.__init__(self, self.isolated_extender) + def draw(self): MatchReplace.draw(self) - - self.MRPnl = self._extender.MRPnl - setattr(self._extender, self.prefix + "MRPnl", self._extender.MRPnl) - setattr(self._extender, self.prefix + "MRType", self._extender.MRType) - setattr(self._extender, self.prefix + "MText", self._extender.MText) - setattr(self._extender, self.prefix + "RText", self._extender.RText) - setattr(self._extender, self.prefix + "MRModel", self._extender.MRModel) - setattr(self._extender, self.prefix + "MRList", self._extender.MRList) - setattr(self._extender, self.prefix + "badProgrammerMRModel", self._extender.badProgrammerMRModel) + + self.MRPnl = self.isolated_extender.MRPnl + self.MRType = self.isolated_extender.MRType + self.MText = self.isolated_extender.MText + self.RText = self.isolated_extender.RText + self.MRModel = self.isolated_extender.MRModel + self.MRList = self.isolated_extender.MRList + self.badProgrammerMRModel = self.isolated_extender.badProgrammerMRModel class AddUserAction(ActionListener): def __init__(self, user_tab): From 5af3163dd6f9e12159998417a5798d5481f7453a Mon Sep 17 00:00:00 2001 From: tvroi Date: Wed, 23 Jul 2025 19:58:17 +0700 Subject: [PATCH 05/15] feat: multi user --- authorization/authorization.py | 176 +++++++++++++++++++- gui/export.py | 252 ++++++++++++++++++++--------- gui/save_restore.py | 283 ++++++++++++++++----------------- gui/table.py | 209 ++++++++++++++++++------ gui/tabs.py | 44 ++--- gui/user_tab.py | 79 ++++++--- helpers/initiator.py | 2 + 7 files changed, 725 insertions(+), 320 deletions(-) diff --git a/authorization/authorization.py b/authorization/authorization.py index c519abe..8fbe501 100644 --- a/authorization/authorization.py +++ b/authorization/authorization.py @@ -41,7 +41,6 @@ def capture_last_authorization_header(self, messageInfo): self.lastAuthorizationHeader = authorization self.fetchAuthorizationHeaderButton.setEnabled(True) - def valid_tool(self, toolFlag): return (toolFlag == self._callbacks.TOOL_PROXY or (toolFlag == self._callbacks.TOOL_REPEATER and @@ -190,25 +189,186 @@ def handle_message(self, toolFlag, messageIsRequest, messageInfo): return if no_filters_defined(self): - checkAuthorization(self, messageInfo, - self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(), - self.doUnauthorizedRequest.isSelected()) + # checkAuthorization(self, messageInfo, + # self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(), + # self.doUnauthorizedRequest.isSelected()) + checkAuthorizationAllUsers(self, messageInfo, self.doUnauthorizedRequest.isSelected()) else: if message_passed_interception_filters(self, messageInfo): - checkAuthorization(self, messageInfo,self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(),self.doUnauthorizedRequest.isSelected()) + # checkAuthorization(self, messageInfo,self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(),self.doUnauthorizedRequest.isSelected()) + checkAuthorizationAllUsers(self, messageInfo, self.doUnauthorizedRequest.isSelected()) + +def checkAuthorizationAllUsers(self, messageInfo, checkUnauthorized=True): + # if not hasattr(self, 'userTab') or not self.userTab or len(self.userTab.user_tabs) == 0: + # checkAuthorization(self, messageInfo, self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(), checkUnauthorized) + # return + + originalHeaders = self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders() + + requestResponseUnauthorized = None + impressionUnauthorized = "Disabled" + + if checkUnauthorized: + messageUnauthorized = makeMessage(self, messageInfo, True, False) + requestResponseUnauthorized = makeRequest(self, messageInfo, messageUnauthorized) + if requestResponseUnauthorized and requestResponseUnauthorized.getResponse(): + unauthorizedResponse = requestResponseUnauthorized.getResponse() + analyzedResponseUnauthorized = self._helpers.analyzeResponse(unauthorizedResponse) + statusCodeUnauthorized = analyzedResponseUnauthorized.getHeaders()[0] + contentUnauthorized = getResponseBody(self, requestResponseUnauthorized) + + message = makeMessage(self, messageInfo, True, True) + requestResponse = makeRequest(self, messageInfo, message) + newResponse = requestResponse.getResponse() + analyzedResponse = self._helpers.analyzeResponse(newResponse) + + oldStatusCode = originalHeaders[0] + newStatusCode = analyzedResponse.getHeaders()[0] + oldContent = getResponseBody(self, messageInfo) + newContent = getResponseBody(self, requestResponse) + + EDFiltersUnauth = self.EDModelUnauth.toArray() + impressionUnauthorized = checkBypass(self, oldStatusCode, statusCodeUnauthorized, + oldContent, contentUnauthorized, + EDFiltersUnauth, requestResponseUnauthorized, + self.AndOrTypeUnauth.getSelectedItem()) + + self._lock.acquire() + + row = self._log.size() + method = self._helpers.analyzeRequest(messageInfo.getRequest()).getMethod() + original_url = self._helpers.analyzeRequest(messageInfo).getUrl() + + logEntry = LogEntry(self.currentRequestNumber, + method, + original_url, + messageInfo, + requestResponseUnauthorized if checkUnauthorized else None, + impressionUnauthorized) + + for user_id, user_data in self.userTab.user_tabs.items(): + user_name = user_data['user_name'] + ed_instance = user_data['ed_instance'] + mr_instance = user_data['mr_instance'] + + message = makeUserMessage(self, messageInfo, True, True, mr_instance) + requestResponse = makeRequest(self, messageInfo, message) + + if requestResponse and requestResponse.getResponse(): + newResponse = requestResponse.getResponse() + analyzedResponse = self._helpers.analyzeResponse(newResponse) + newStatusCode = analyzedResponse.getHeaders()[0] + oldContent = getResponseBody(self, messageInfo) + newContent = getResponseBody(self, requestResponse) + + EDFilters = ed_instance.EDModel.toArray() + impression = checkBypass(self, originalHeaders[0], newStatusCode, oldContent, newContent, + EDFilters, requestResponse, ed_instance.AndOrType.getSelectedItem()) + + savedRequestResponse = self._callbacks.saveBuffersToTempFiles(requestResponse) + logEntry.add_user_enforcement(user_id, savedRequestResponse, impression) + + self._log.add(logEntry) + SwingUtilities.invokeLater(UpdateTableEDT(self,"insert",row,row)) + self.currentRequestNumber = self.currentRequestNumber + 1 + self._lock.release() + +def makeUserMessage(self, messageInfo, removeOrNot, authorizeOrNot, mr_instance): + requestInfo = self._helpers.analyzeRequest(messageInfo) + headers = list(requestInfo.getHeaders()) + + if removeOrNot: + if hasattr(self, 'replaceString') and self.replaceString.getText(): + removeHeaders = self.replaceString.getText().split('\n') + removeHeaders = [header.split(':')[0].strip() + ':' for header in removeHeaders if ':' in header] + + headers_to_remove = [] + for header in headers[1:]: + for removeHeader in removeHeaders: + if header.lower().startswith(removeHeader.lower()): + headers_to_remove.append(header) + + for header in headers_to_remove: + if header in headers: + headers.remove(header) + + if authorizeOrNot: + for i in range(mr_instance.MRModel.getSize()): + rule_key = mr_instance.MRModel.getElementAt(i) + rule_data = mr_instance.badProgrammerMRModel.get(rule_key) + + if rule_data: + rule_type = rule_data['type'] + match_pattern = rule_data['match'] + replace_pattern = rule_data['replace'] + regex_match = rule_data.get('regexMatch') + + if rule_type == "Headers (simple string):": + modifiedHeaders = [h.replace(match_pattern, replace_pattern) for h in headers[1:]] + headers = [headers[0]] + modifiedHeaders + elif rule_type == "Headers (regex):": + if regex_match: + modifiedHeaders = [regex_match.sub(replace_pattern, h) for h in headers[1:]] + headers = [headers[0]] + modifiedHeaders + + if hasattr(self, 'replaceString') and self.replaceString.getText(): + replaceStringLines = self.replaceString.getText().split("\n") + for h in replaceStringLines: + if h.strip() and ':' in h: + headers.append(h.strip()) + + msgBody = messageInfo.getRequest()[requestInfo.getBodyOffset():] + + if authorizeOrNot and msgBody is not None: + msgBody_str = self._helpers.bytesToString(msgBody) + + for i in range(mr_instance.MRModel.getSize()): + rule_key = mr_instance.MRModel.getElementAt(i) + rule_data = mr_instance.badProgrammerMRModel.get(rule_key) + + if rule_data: + rule_type = rule_data['type'] + match_pattern = rule_data['match'] + replace_pattern = rule_data['replace'] + regex_match = rule_data.get('regexMatch') + + if rule_type == "Path (simple string):": + uriPath = headers[0].split(" ")[1] + if match_pattern in uriPath: + headers[0] = headers[0].replace(match_pattern, replace_pattern) + elif rule_type == "Path (regex):": + if regex_match: + uriPath = headers[0].split(" ")[1] + if regex_match.search(uriPath): + headers[0] = regex_match.sub(replace_pattern, headers[0]) + + elif rule_type == "Body (simple string):": + msgBody_str = msgBody_str.replace(match_pattern, replace_pattern) + elif rule_type == "Body (regex):": + if regex_match: + msgBody_str = regex_match.sub(replace_pattern, msgBody_str) + + msgBody = self._helpers.stringToBytes(msgBody_str) + + return self._helpers.buildHttpMessage(headers, msgBody) def send_request_to_autorize(self, messageInfo): if messageInfo.getResponse() is None: message = makeMessage(self, messageInfo,False,False) requestResponse = makeRequest(self, messageInfo, message) - checkAuthorization(self, requestResponse,self._helpers.analyzeResponse(requestResponse.getResponse()).getHeaders(),self.doUnauthorizedRequest.isSelected()) + # checkAuthorization(self, requestResponse,self._helpers.analyzeResponse(requestResponse.getResponse()).getHeaders(),self.doUnauthorizedRequest.isSelected()) + checkAuthorizationAllUsers(self, requestResponse, self.doUnauthorizedRequest.isSelected()) else: request = messageInfo.getRequest() response = messageInfo.getResponse() httpService = messageInfo.getHttpService() newHttpRequestResponse = IHttpRequestResponseImplementation(httpService,request,response) newHttpRequestResponsePersisted = self._callbacks.saveBuffersToTempFiles(newHttpRequestResponse) - checkAuthorization(self, newHttpRequestResponsePersisted,self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(),self.doUnauthorizedRequest.isSelected()) + + if hasattr(self, 'userTab') and self.userTab and len(self.userTab.user_tabs) > 0: + checkAuthorizationAllUsers(self, newHttpRequestResponsePersisted, self.doUnauthorizedRequest.isSelected()) + else: + checkAuthorization(self, newHttpRequestResponsePersisted, self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(), self.doUnauthorizedRequest.isSelected()) def auth_enforced_via_enforcement_detectors(self, filters, requestResponse, andOrEnforcement): response = requestResponse.getResponse() @@ -332,4 +492,6 @@ def retestAllRequests(self): self.logTable.setAutoCreateRowSorter(True) for i in range(self.tableModel.getRowCount()): logEntry = self._log.get(self.logTable.convertRowIndexToModel(i)) + logEntry._userEnforcements.clear() handle_message(self, "AUTORIZE", False, logEntry._originalrequestResponse) + diff --git a/gui/export.py b/gui/export.py index 7a7f50b..38cedf2 100644 --- a/gui/export.py +++ b/gui/export.py @@ -257,74 +257,125 @@ def exportToHTML(self): fileToSave = fileChooser.getSelectedFile() enforcementStatusFilter = self.exportES.getSelectedItem() + + header_html = "IDMethodURLOriginal lengthUnauth lengthUnauth Status" + + if hasattr(self._extender, 'userTab') and self._extender.userTab: + for user_id, user_data in self._extender.userTab.user_tabs.items(): + user_name = user_data['user_name'] + header_html += "{} Len{} Status".format(user_name, user_name) + + header_html += "" + htmlContent = """Autorize Report by Barak Tawily

Autorize Report

-
- +
IDMethodURLOriginal lengthModified lengthUnauthorized lengthAuthorization Enforcement StatusAuthorization Unauthenticated Status
""" + header_html + """ """ - unique_HTML_lines = set() # set to keep track of unique values - for i in range(0,self._log.size()): + + unique_HTML_lines = set() + for i in range(0, self._log.size()): + logEntry = self._log.get(i) + if self.removeDuplicates.isSelected(): - # line data only looks for method, url, and authorized status. Does not factor in size of request during comparision - lineData = "\t%s\t%s\t%s\t%s\n" % (self._log.get(i)._method, self._log.get(i)._url, self._log.get(i)._enfocementStatus,self._log.get(i)._enfocementStatusUnauthorized) - if lineData in unique_HTML_lines: # Skip if line is already in set + user_statuses = [] + for user_id in sorted(logEntry.get_all_users()): + user_data = logEntry.get_user_enforcement(user_id) + if user_data: + user_statuses.append(user_data['enforcementStatus']) + + lineData = "\t%s\t%s\t%s\t%s" % (logEntry._method, logEntry._url, + logEntry._enfocementStatusUnauthorized, + "\t".join(user_statuses)) + if lineData in unique_HTML_lines: continue - else: # Add line to set and continue with execution + else: unique_HTML_lines.add(lineData) - color_modified = "" - if self._log.get(i)._enfocementStatus == self.BYPASSSED_STR: - color_modified = "red" - elif self._log.get(i)._enfocementStatus == self.IS_ENFORCED_STR: - color_modified = "yellow" - elif self._log.get(i)._enfocementStatus == self.ENFORCED_STR: - color_modified = "LawnGreen" - - color_unauthorized = "" - if self._log.get(i)._enfocementStatusUnauthorized == self.BYPASSSED_STR: - color_unauthorized = "red" - elif self._log.get(i)._enfocementStatusUnauthorized == self.IS_ENFORCED_STR: - color_unauthorized = "yellow" - elif self._log.get(i)._enfocementStatusUnauthorized == self.ENFORCED_STR: - color_unauthorized = "LawnGreen" + row_html = "" % ( + logEntry._id, logEntry._method, logEntry._url, logEntry._url) + + orig_len = len(logEntry._originalrequestResponse.getResponse()) if logEntry._originalrequestResponse else 0 + row_html += "" % orig_len + + unauth_len = 0 + if logEntry._unauthorizedRequestResponse: + unauth_len = len(logEntry._unauthorizedRequestResponse.getResponse()) + + unauth_color = "" + if logEntry._enfocementStatusUnauthorized == self.BYPASSSED_STR: + unauth_color = "red" + elif logEntry._enfocementStatusUnauthorized == self.IS_ENFORCED_STR: + unauth_color = "yellow" + elif logEntry._enfocementStatusUnauthorized == self.ENFORCED_STR: + unauth_color = "LawnGreen" + + row_html += "" % (unauth_len, unauth_color, logEntry._enfocementStatusUnauthorized) + + # User data + if hasattr(self._extender, 'userTab') and self._extender.userTab: + for user_id in sorted(self._extender.userTab.user_tabs.keys()): + user_data = logEntry.get_user_enforcement(user_id) + if user_data and user_data['requestResponse']: + user_len = len(user_data['requestResponse'].getResponse()) + user_status = user_data['enforcementStatus'] + + user_color = "" + if user_status == self.BYPASSSED_STR: + user_color = "red" + elif user_status == self.IS_ENFORCED_STR: + user_color = "yellow" + elif user_status == self.ENFORCED_STR: + user_color = "LawnGreen" + + row_html += "" % (user_len, user_color, user_status) + else: + row_html += "" + + row_html += "" + + should_include = False if enforcementStatusFilter == "All Statuses": - htmlContent += "" % (self._log.get(i)._id, self._log.get(i)._method, self._log.get(i)._url, self._log.get(i)._url, len(self._log.get(i)._originalrequestResponse.getResponse()) if self._log.get(i)._originalrequestResponse is not None else 0, len(self._log.get(i)._requestResponse.getResponse()) if self._log.get(i)._requestResponse is not None else 0, len(self._log.get(i)._unauthorizedRequestResponse.getResponse()) if self._log.get(i)._unauthorizedRequestResponse is not None else 0, color_modified, self._log.get(i)._enfocementStatus, color_unauthorized, self._log.get(i)._enfocementStatusUnauthorized) + should_include = True elif enforcementStatusFilter == "As table filter": - if ((self._extender.showAuthBypassModified.isSelected() and self.BYPASSSED_STR == self._log.get(i)._enfocementStatus) or - (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and "Is enforced???" == self._log.get(i)._enfocementStatus) or - (self._extender.showAuthEnforcedModified.isSelected() and self.ENFORCED_STR == self._log.get(i)._enfocementStatus) or - (self._extender.showAuthBypassUnauthenticated.isSelected() and self.BYPASSSED_STR == self._log.get(i)._enfocementStatusUnauthorized) or - (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and "Is enforced???" == self._log.get(i)._enfocementStatusUnauthorized) or - (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self.ENFORCED_STR == self._log.get(i)._enfocementStatusUnauthorized) or - (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == self._log.get(i)._enfocementStatusUnauthorized)): - htmlContent += "" % (self._log.get(i)._id, self._log.get(i)._method, self._log.get(i)._url, self._log.get(i)._url, len(self._log.get(i)._originalrequestResponse.getResponse()) if self._log.get(i)._originalrequestResponse is not None else 0, len(self._log.get(i)._requestResponse.getResponse()) if self._log.get(i)._requestResponse is not None else 0, len(self._log.get(i)._unauthorizedRequestResponse.getResponse()) if self._log.get(i)._unauthorizedRequestResponse is not None else 0, color_modified, self._log.get(i)._enfocementStatus, color_unauthorized, self._log.get(i)._enfocementStatusUnauthorized) + if ((self._extender.showAuthBypassUnauthenticated.isSelected() and self.BYPASSSED_STR == logEntry._enfocementStatusUnauthorized) or + (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and self.IS_ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or + (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self.ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or + (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == logEntry._enfocementStatusUnauthorized)): + should_include = True + + for user_id in logEntry.get_all_users(): + user_data = logEntry.get_user_enforcement(user_id) + if user_data: + user_status = user_data['enforcementStatus'] + if ((self._extender.showAuthBypassModified.isSelected() and self.BYPASSSED_STR == user_status) or + (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and self.IS_ENFORCED_STR == user_status) or + (self._extender.showAuthEnforcedModified.isSelected() and self.ENFORCED_STR == user_status)): + should_include = True + break else: - if (enforcementStatusFilter == self._log.get(i)._enfocementStatus) or (enforcementStatusFilter == self._log.get(i)._enfocementStatusUnauthorized): - htmlContent += "" % (self._log.get(i)._id, self._log.get(i)._method, self._log.get(i)._url, self._log.get(i)._url, len(self._log.get(i)._originalrequestResponse.getResponse()) if self._log.get(i)._originalrequestResponse is not None else 0, len(self._log.get(i)._requestResponse.getResponse()) if self._log.get(i)._requestResponse is not None else 0, len(self._log.get(i)._unauthorizedRequestResponse.getResponse()) if self._log.get(i)._unauthorizedRequestResponse is not None else 0, color_modified, self._log.get(i)._enfocementStatus, color_unauthorized, self._log.get(i)._enfocementStatusUnauthorized) + if enforcementStatusFilter == logEntry._enfocementStatusUnauthorized: + should_include = True + else: + for user_id in logEntry.get_all_users(): + user_data = logEntry.get_user_enforcement(user_id) + if user_data and enforcementStatusFilter == user_data['enforcementStatus']: + should_include = True + break + + if should_include: + htmlContent += row_html htmlContent += "
%d%s%s%d%d%s%d%s0N/A
%d%s%s%d%d%d%s%s
%d%s%s%d%d%d%s%s
%d%s%s%d%d%d%s%s
" f = open(fileToSave.getAbsolutePath(), 'w') @@ -341,33 +392,86 @@ def exportToCSV(self): fileToSave = fileChooser.getSelectedFile() enforcementStatusFilter = self.exportES.getSelectedItem() - csvContent = "id\tMethod\tURL\tOriginal length\tModified length\tUnauthorized length\tAuthorization Enforcement Status\tAuthorization Unauthenticated Status\n" + + csvContent = "ID\tMethod\tURL\tOriginal Length\tUnauth Length\tUnauth Status" + + if hasattr(self._extender, 'userTab') and self._extender.userTab: + for user_id, user_data in self._extender.userTab.user_tabs.items(): + user_name = user_data['user_name'] + csvContent += "\t{} Length\t{} Status".format(user_name, user_name) + + csvContent += "\n" - unique_CVS_lines = set() + unique_CSV_lines = set() for i in range(0, self._log.size()): + logEntry = self._log.get(i) + if self.removeDuplicates.isSelected(): - # line data only looks for method, url, and authorized status. Does not factor in size of request during comparision - lineData = "\t%s\t%s\t%s\t%s\n" % (self._log.get(i)._method, self._log.get(i)._url, self._log.get(i)._enfocementStatus,self._log.get(i)._enfocementStatusUnauthorized) - if lineData in unique_CVS_lines: # Skip if line is already in set + user_statuses = [] + for user_id in sorted(logEntry.get_all_users()): + user_data = logEntry.get_user_enforcement(user_id) + if user_data: + user_statuses.append(user_data['enforcementStatus']) + + lineData = "\t%s\t%s\t%s\t%s\n" % (logEntry._method, logEntry._url, + logEntry._enfocementStatusUnauthorized, + "\t".join(user_statuses)) + if lineData in unique_CSV_lines: continue - else: # Add line to set and continue with execution - unique_CVS_lines.add(lineData) + else: + unique_CSV_lines.add(lineData) + + orig_len = len(logEntry._originalrequestResponse.getResponse()) if logEntry._originalrequestResponse else 0 + unauth_len = len(logEntry._unauthorizedRequestResponse.getResponse()) if logEntry._unauthorizedRequestResponse else 0 + + csv_row = "%d\t%s\t%s\t%d\t%d\t%s" % ( + logEntry._id, logEntry._method, logEntry._url, orig_len, unauth_len, logEntry._enfocementStatusUnauthorized) + + # User data + if hasattr(self._extender, 'userTab') and self._extender.userTab: + for user_id in sorted(self._extender.userTab.user_tabs.keys()): + user_data = logEntry.get_user_enforcement(user_id) + if user_data and user_data['requestResponse']: + user_len = len(user_data['requestResponse'].getResponse()) + user_status = user_data['enforcementStatus'] + csv_row += "\t%d\t%s" % (user_len, user_status) + else: + csv_row += "\t0\tN/A" + + csv_row += "\n" + + should_include = False if enforcementStatusFilter == "All Statuses": - csvContent += "%d\t%s\t%s\t%d\t%d\t%d\t%s\t%s\n" % (self._log.get(i)._id, self._log.get(i)._method, self._log.get(i)._url, len(self._log.get(i)._originalrequestResponse.getResponse()) if self._log.get(i)._originalrequestResponse is not None else 0, len(self._log.get(i)._requestResponse.getResponse()) if self._log.get(i)._requestResponse is not None else 0, len(self._log.get(i)._unauthorizedRequestResponse.getResponse()) if self._log.get(i)._unauthorizedRequestResponse is not None else 0, self._log.get(i)._enfocementStatus, self._log.get(i)._enfocementStatusUnauthorized) + should_include = True elif enforcementStatusFilter == "As table filter": - if ((self._extender.showAuthBypassModified.isSelected() and self.BYPASSSED_STR == self._log.get(i)._enfocementStatus) or - (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and "Is enforced???" == self._log.get(i)._enfocementStatus) or - (self._extender.showAuthEnforcedModified.isSelected() and self.ENFORCED_STR == self._log.get(i)._enfocementStatus) or - (self._extender.showAuthBypassUnauthenticated.isSelected() and self.BYPASSSED_STR == self._log.get(i)._enfocementStatusUnauthorized) or - (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and "Is enforced???" == self._log.get(i)._enfocementStatusUnauthorized) or - (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self.ENFORCED_STR == self._log.get(i)._enfocementStatusUnauthorized) or - (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == self._log.get(i)._enfocementStatusUnauthorized)): - csvContent += "%d\t%s\t%s\t%d\t%d\t%d\t%s\t%s\n" % (self._log.get(i)._id, self._log.get(i)._method, self._log.get(i)._url, len(self._log.get(i)._originalrequestResponse.getResponse()) if self._log.get(i)._originalrequestResponse is not None else 0, len(self._log.get(i)._requestResponse.getResponse()) if self._log.get(i)._requestResponse is not None else 0, len(self._log.get(i)._unauthorizedRequestResponse.getResponse()) if self._log.get(i)._unauthorizedRequestResponse is not None else 0, self._log.get(i)._enfocementStatus, self._log.get(i)._enfocementStatusUnauthorized) + if ((self._extender.showAuthBypassUnauthenticated.isSelected() and self.BYPASSSED_STR == logEntry._enfocementStatusUnauthorized) or + (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and self.IS_ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or + (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self.ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or + (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == logEntry._enfocementStatusUnauthorized)): + should_include = True + + for user_id in logEntry.get_all_users(): + user_data = logEntry.get_user_enforcement(user_id) + if user_data: + user_status = user_data['enforcementStatus'] + if ((self._extender.showAuthBypassModified.isSelected() and self.BYPASSSED_STR == user_status) or + (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and self.IS_ENFORCED_STR == user_status) or + (self._extender.showAuthEnforcedModified.isSelected() and self.ENFORCED_STR == user_status)): + should_include = True + break else: - if (enforcementStatusFilter == self._log.get(i)._enfocementStatus) or (enforcementStatusFilter == self._log.get(i)._enfocementStatusUnauthorized): - csvContent += "%d\t%s\t%s\t%d\t%d\t%d\t%s\t%s\n" % (self._log.get(i)._id, self._log.get(i)._method, self._log.get(i)._url, len(self._log.get(i)._originalrequestResponse.getResponse()) if self._log.get(i)._originalrequestResponse is not None else 0, len(self._log.get(i)._requestResponse.getResponse()) if self._log.get(i)._requestResponse is not None else 0, len(self._log.get(i)._unauthorizedRequestResponse.getResponse()) if self._log.get(i)._unauthorizedRequestResponse is not None else 0, self._log.get(i)._enfocementStatus, self._log.get(i)._enfocementStatusUnauthorized) - + if enforcementStatusFilter == logEntry._enfocementStatusUnauthorized: + should_include = True + else: + for user_id in logEntry.get_all_users(): + user_data = logEntry.get_user_enforcement(user_id) + if user_data and enforcementStatusFilter == user_data['enforcementStatus']: + should_include = True + break + + if should_include: + csvContent += csv_row f = open(fileToSave.getAbsolutePath(), 'w') f.writelines(csvContent) - f.close() + f.close() \ No newline at end of file diff --git a/gui/save_restore.py b/gui/save_restore.py index 55d2999..61c8aa2 100644 --- a/gui/save_restore.py +++ b/gui/save_restore.py @@ -55,9 +55,23 @@ def saveState(self): # Configuration tempRow = ["ReplaceString", base64.b64encode(self._extender.replaceString.getText())] csvwriter.writerow(tempRow) - - for EDFilter in self._extender.EDModel.toArray(): - tempRow = ["EDFilter", base64.b64encode(EDFilter)] + + user_configs = [] + + for user_id, user_data in self._extender.userTab.user_tabs.items(): + user_config = { + 'user_id': user_id, + 'user_name': user_data['user_name'], + 'ed_filters': list(user_data['ed_instance'].EDModel.toArray()), + 'ed_type': user_data['ed_instance'].EDType.getSelectedIndex(), + 'ed_text': user_data['ed_instance'].EDText.getText(), + 'andor_type': user_data['ed_instance'].AndOrType.getSelectedIndex(), + 'mr_rules': dict(user_data['mr_instance'].badProgrammerMRModel) + } + + user_configs.append(user_config) + + tempRow = ["UserConfigs", base64.b64encode(json.dumps(user_configs))] csvwriter.writerow(tempRow) for EDFilterUnauth in self._extender.EDModelUnauth.toArray(): @@ -68,44 +82,26 @@ def saveState(self): tempRow = ["IFFilter", base64.b64encode(IFFilter)] csvwriter.writerow(tempRow) - for t in ["AndOrType", "AndOrTypeUnauth"]: - tempRow = [t, getattr(self._extender, t).getSelectedItem()] - csvwriter.writerow(tempRow) - - for key in self._extender.badProgrammerMRModel: - d = dict(self._extender.badProgrammerMRModel[key]) - d["regexMatch"] = d["regexMatch"] is not None - tempRow = ["MatchReplace", base64.b64encode(json.dumps(d))] - csvwriter.writerow(tempRow) - d = dict((c, getattr(self._extender, c).isSelected()) for c in self._checkBoxes) tempRow = ["CheckBoxes", json.dumps(d)] csvwriter.writerow(tempRow) - isSelected = self._extender.exportPnl.getComponents()[-1].isSelected() - tempRow = ["RemoveDuplicates", json.dumps(isSelected)] - csvwriter.writerow(tempRow) - # Request/response list - for i in range(0,self._extender._log.size()): - tempRequestResponseHost = self._extender._log.get(i)._requestResponse.getHttpService().getHost() - tempRequestResponsePort = self._extender._log.get(i)._requestResponse.getHttpService().getPort() - tempRequestResponseProtocol = self._extender._log.get(i)._requestResponse.getHttpService().getProtocol() - tempRequestResponseRequest = base64.b64encode(self._extender._log.get(i)._requestResponse.getRequest()) - tempRequestResponseResponse = base64.b64encode(self._extender._log.get(i)._requestResponse.getResponse()) - - tempOriginalRequestResponseHost = self._extender._log.get(i)._originalrequestResponse.getHttpService().getHost() - tempOriginalRequestResponsePort = self._extender._log.get(i)._originalrequestResponse.getHttpService().getPort() - tempOriginalRequestResponseProtocol = self._extender._log.get(i)._originalrequestResponse.getHttpService().getProtocol() - tempOriginalRequestResponseRequest = base64.b64encode(self._extender._log.get(i)._originalrequestResponse.getRequest()) - tempOriginalRequestResponseResponse = base64.b64encode(self._extender._log.get(i)._originalrequestResponse.getResponse()) - - if self._extender._log.get(i)._unauthorizedRequestResponse is not None: - tempUnauthorizedRequestResponseHost = self._extender._log.get(i)._unauthorizedRequestResponse.getHttpService().getHost() - tempUnauthorizedRequestResponsePort = self._extender._log.get(i)._unauthorizedRequestResponse.getHttpService().getPort() - tempUnauthorizedRequestResponseProtocol = self._extender._log.get(i)._unauthorizedRequestResponse.getHttpService().getProtocol() - tempUnauthorizedRequestResponseRequest = base64.b64encode(self._extender._log.get(i)._unauthorizedRequestResponse.getRequest()) - tempUnauthorizedRequestResponseResponse = base64.b64encode(self._extender._log.get(i)._unauthorizedRequestResponse.getResponse()) + for i in range(0, self._extender._log.size()): + logEntry = self._extender._log.get(i) + + tempOriginalRequestResponseHost = logEntry._originalrequestResponse.getHttpService().getHost() + tempOriginalRequestResponsePort = logEntry._originalrequestResponse.getHttpService().getPort() + tempOriginalRequestResponseProtocol = logEntry._originalrequestResponse.getHttpService().getProtocol() + tempOriginalRequestResponseRequest = base64.b64encode(logEntry._originalrequestResponse.getRequest()) + tempOriginalRequestResponseResponse = base64.b64encode(logEntry._originalrequestResponse.getResponse()) + + if logEntry._unauthorizedRequestResponse is not None: + tempUnauthorizedRequestResponseHost = logEntry._unauthorizedRequestResponse.getHttpService().getHost() + tempUnauthorizedRequestResponsePort = logEntry._unauthorizedRequestResponse.getHttpService().getPort() + tempUnauthorizedRequestResponseProtocol = logEntry._unauthorizedRequestResponse.getHttpService().getProtocol() + tempUnauthorizedRequestResponseRequest = base64.b64encode(logEntry._unauthorizedRequestResponse.getRequest()) + tempUnauthorizedRequestResponseResponse = base64.b64encode(logEntry._unauthorizedRequestResponse.getResponse()) else: tempUnauthorizedRequestResponseHost = None tempUnauthorizedRequestResponsePort = None @@ -113,13 +109,30 @@ def saveState(self): tempUnauthorizedRequestResponseRequest = None tempUnauthorizedRequestResponseResponse = None - tempEnforcementStatus = self._extender._log.get(i)._enfocementStatus - tempEnforcementStatusUnauthorized = self._extender._log.get(i)._enfocementStatusUnauthorized - - tempRow = [tempRequestResponseHost,tempRequestResponsePort,tempRequestResponseProtocol,tempRequestResponseRequest,tempRequestResponseResponse] - tempRow.extend([tempOriginalRequestResponseHost,tempOriginalRequestResponsePort,tempOriginalRequestResponseProtocol,tempOriginalRequestResponseRequest,tempOriginalRequestResponseResponse]) - tempRow.extend([tempUnauthorizedRequestResponseHost,tempUnauthorizedRequestResponsePort,tempUnauthorizedRequestResponseProtocol,tempUnauthorizedRequestResponseRequest,tempUnauthorizedRequestResponseResponse]) - tempRow.extend([tempEnforcementStatus,tempEnforcementStatusUnauthorized]) + tempEnforcementStatusUnauthorized = logEntry._enfocementStatusUnauthorized + + user_data_json = {} + + for user_id in logEntry.get_all_users(): + user_enforcement = logEntry.get_user_enforcement(user_id) + if user_enforcement and user_enforcement['requestResponse']: + user_data_json[str(user_id)] = { + 'host': user_enforcement['requestResponse'].getHttpService().getHost(), + 'port': user_enforcement['requestResponse'].getHttpService().getPort(), + 'protocol': user_enforcement['requestResponse'].getHttpService().getProtocol(), + 'request': base64.b64encode(user_enforcement['requestResponse'].getRequest()), + 'response': base64.b64encode(user_enforcement['requestResponse'].getResponse()), + 'status': user_enforcement['enforcementStatus'] + } + + tempRow = [ + tempOriginalRequestResponseHost, tempOriginalRequestResponsePort, tempOriginalRequestResponseProtocol, + tempOriginalRequestResponseRequest, tempOriginalRequestResponseResponse, + tempUnauthorizedRequestResponseHost, tempUnauthorizedRequestResponsePort, tempUnauthorizedRequestResponseProtocol, + tempUnauthorizedRequestResponseRequest, tempUnauthorizedRequestResponseResponse, + tempEnforcementStatusUnauthorized, + base64.b64encode(json.dumps(user_data_json)) + ] csvwriter.writerow(tempRow) @@ -128,11 +141,6 @@ def restoreState(self): fileChooser = JFileChooser() fileChooser.setDialogTitle("State import file") userSelection = fileChooser.showDialog(parentFrame, "Restore") - modelMap = { - "IFFilter": self._extender.IFModel, - "EDFilter": self._extender.EDModel, - "EDFilterUnauth": self._extender.EDModelUnauth - } if userSelection == JFileChooser.APPROVE_OPTION: importFile = fileChooser.getSelectedFile() @@ -141,36 +149,41 @@ def restoreState(self): csvreader = csv.reader(csvfile, delimiter='\t', quotechar='|') + user_configs = None + for row in csvreader: # Configuration if row[0] == "ReplaceString": self._extender.replaceString.setText(base64.b64decode(row[1])) continue - if row[0] in modelMap: - f = base64.b64decode(row[1]) - if f not in modelMap[row[0]].toArray(): - modelMap[row[0]].addElement(f) - continue - - if row[0] in {"AndOrType", "AndOrTypeUnauth"}: - getattr(self._extender, row[0]).setSelectedItem(row[1]) - continue - - if row[0] == "MatchReplace": - d = json.loads(base64.b64decode(row[1])) - key = d["type"] + " " + d["match"] + "->" + d["replace"] - if key in self._extender.badProgrammerMRModel: - continue - regexMatch = None - if d["regexMatch"]: - try: - d["regexMatch"] = re.compile(d["match"]) - except re.error: - print("ERROR: Regex to restore is invalid:", d["match"]) - continue - self._extender.badProgrammerMRModel[key] = d - self._extender.MRModel.addElement(key) + if row[0] == "UserConfigs": + user_configs = json.loads(base64.b64decode(row[1])) + + # Restore user configurations + if hasattr(self._extender, 'userTab') and self._extender.userTab: + self._extender.userTab.reset_user() + + for i, config in enumerate(user_configs): + if i == 0: + user_data = list(self._extender.userTab.user_tabs.values())[0] + else: + self._extender.userTab.add_user() + user_data = list(self._extender.userTab.user_tabs.values())[-1] + + user_data['ed_instance'].EDModel.clear() + for filter in config['ed_filters']: + user_data['ed_instance'].EDModel.addElement(filter) + + user_data['ed_instance'].EDType.setSelectedIndex(config['ed_type']) + user_data['ed_instance'].EDText.setText(config['ed_text']) + user_data['ed_instance'].AndOrType.setSelectedIndex(config['andor_type']) + + user_data['mr_instance'].badProgrammerMRModel.clear() + user_data['mr_instance'].MRModel.clear() + for key, value in config['mr_rules'].items(): + user_data['mr_instance'].badProgrammerMRModel[key] = value + user_data['mr_instance'].MRModel.addElement(key) continue if row[0] == "CheckBoxes": @@ -188,74 +201,58 @@ def restoreState(self): continue # Request/response list - tempRequestResponseHost = row[0] - tempRequestResponsePort = row[1] - tempRequestResponseProtocol = row[2] - tempRequestResponseRequest = base64.b64decode(row[3]) - tempRequestResponseResponse = base64.b64decode(row[4]) - - tempRequestResponseHttpService = self._extender._helpers.buildHttpService(tempRequestResponseHost,int(tempRequestResponsePort),tempRequestResponseProtocol) - tempRequestResponse = IHttpRequestResponseImplementation(tempRequestResponseHttpService,tempRequestResponseRequest,tempRequestResponseResponse) - - tempOriginalRequestResponseHost = row[5] - tempOriginalRequestResponsePort = row[6] - tempOriginalRequestResponseProtocol = row[7] - tempOriginalRequestResponseRequest = base64.b64decode(row[8]) - tempOriginalRequestResponseResponse = base64.b64decode(row[9]) - - tempOriginalRequestResponseHttpService = self._extender._helpers.buildHttpService(tempOriginalRequestResponseHost,int(tempOriginalRequestResponsePort),tempOriginalRequestResponseProtocol) - tempOriginalRequestResponse = IHttpRequestResponseImplementation(tempOriginalRequestResponseHttpService,tempOriginalRequestResponseRequest,tempOriginalRequestResponseResponse) - - checkAuthentication = True - if row[10] != '': - tempUnauthorizedRequestResponseHost = row[10] - tempUnauthorizedRequestResponsePort = row[11] - tempUnauthorizedRequestResponseProtocol = row[12] - tempUnauthorizedRequestResponseRequest = base64.b64decode(row[13]) - tempUnauthorizedRequestResponseResponse = base64.b64decode(row[14]) - tempUnauthorizedRequestResponseHttpService = self._extender._helpers.buildHttpService(tempUnauthorizedRequestResponseHost,int(tempUnauthorizedRequestResponsePort),tempUnauthorizedRequestResponseProtocol) - tempUnauthorizedRequestResponse = IHttpRequestResponseImplementation(tempUnauthorizedRequestResponseHttpService,tempUnauthorizedRequestResponseRequest,tempUnauthorizedRequestResponseResponse) - else: - checkAuthentication = False - tempUnauthorizedRequestResponse = None - - tempEnforcementStatus = row[15] - tempEnforcementStatusUnauthorized = row[16] - - self._extender._lock.acquire() - - row = self._extender._log.size() - - if checkAuthentication: - self._extender._log.add( - LogEntry(self._extender.currentRequestNumber, - self._extender._callbacks.saveBuffersToTempFiles(tempRequestResponse), - self._extender._helpers.analyzeRequest(tempRequestResponse).getMethod(), - self._extender._helpers.analyzeRequest(tempRequestResponse).getUrl(), - self._extender._callbacks.saveBuffersToTempFiles(tempOriginalRequestResponse), - tempEnforcementStatus, - self._extender._callbacks.saveBuffersToTempFiles(tempUnauthorizedRequestResponse), - tempEnforcementStatusUnauthorized)) - else: - self._extender._log.add( - LogEntry(self._extender.currentRequestNumber, - self._extender._callbacks.saveBuffersToTempFiles(tempRequestResponse), - self._extender._helpers.analyzeRequest(tempRequestResponse).getMethod(), - self._extender._helpers.analyzeRequest(tempRequestResponse).getUrl(), - self._extender._callbacks.saveBuffersToTempFiles(tempOriginalRequestResponse), - tempEnforcementStatus,None,tempEnforcementStatusUnauthorized)) - - SwingUtilities.invokeLater(UpdateTableEDT(self._extender,"insert",row,row)) - self._extender.currentRequestNumber = self._extender.currentRequestNumber + 1 - self._extender._lock.release() - - lastRow = self._extender._log.size() - if lastRow > 0: - cookiesHeader = get_cookie_header_from_message(self._extender, self._extender._log.get(lastRow - 1)._requestResponse) - if cookiesHeader: - self._extender.lastCookiesHeader = cookiesHeader - self._extender.fetchCookiesHeaderButton.setEnabled(True) - authorizationHeader = get_authorization_header_from_message(self._extender, self._extender._log.get(lastRow - 1)._requestResponse) - if authorizationHeader: - self._extender.lastAuthorizationHeader = authorizationHeader - self._extender.fetchAuthorizationHeaderButton.setEnabled(True) + if len(row) >= 12: + tempOriginalRequestResponseHost = row[0] + tempOriginalRequestResponsePort = row[1] + tempOriginalRequestResponseProtocol = row[2] + tempOriginalRequestResponseRequest = base64.b64decode(row[3]) + tempOriginalRequestResponseResponse = base64.b64decode(row[4]) + + tempOriginalRequestResponseHttpService = self._extender._helpers.buildHttpService( + tempOriginalRequestResponseHost, int(tempOriginalRequestResponsePort), tempOriginalRequestResponseProtocol) + tempOriginalRequestResponse = IHttpRequestResponseImplementation( + tempOriginalRequestResponseHttpService, tempOriginalRequestResponseRequest, tempOriginalRequestResponseResponse) + + checkAuthentication = True + if row[5] != '': + tempUnauthorizedRequestResponseHost = row[5] + tempUnauthorizedRequestResponsePort = row[6] + tempUnauthorizedRequestResponseProtocol = row[7] + tempUnauthorizedRequestResponseRequest = base64.b64decode(row[8]) + tempUnauthorizedRequestResponseResponse = base64.b64decode(row[9]) + tempUnauthorizedRequestResponseHttpService = self._extender._helpers.buildHttpService( + tempUnauthorizedRequestResponseHost, int(tempUnauthorizedRequestResponsePort), tempUnauthorizedRequestResponseProtocol) + tempUnauthorizedRequestResponse = IHttpRequestResponseImplementation( + tempUnauthorizedRequestResponseHttpService, tempUnauthorizedRequestResponseRequest, tempUnauthorizedRequestResponseResponse) + else: + checkAuthentication = False + tempUnauthorizedRequestResponse = None + + tempEnforcementStatusUnauthorized = row[10] + + self._extender._lock.acquire() + row_index = self._extender._log.size() + + method = self._extender._helpers.analyzeRequest(tempOriginalRequestResponse).getMethod() + original_url = self._extender._helpers.analyzeRequest(tempOriginalRequestResponse).getUrl() + + logEntry = LogEntry(self._extender.currentRequestNumber, method, original_url, + self._extender._callbacks.saveBuffersToTempFiles(tempOriginalRequestResponse), + self._extender._callbacks.saveBuffersToTempFiles(tempUnauthorizedRequestResponse) if checkAuthentication else None, + tempEnforcementStatusUnauthorized) + + if len(row) > 11 and row[11]: + user_data_json = json.loads(base64.b64decode(row[11])) + for user_id_str, user_data in user_data_json.items(): + user_id = int(user_id_str) + userHttpService = self._extender._helpers.buildHttpService( + user_data['host'], int(user_data['port']), user_data['protocol']) + userRequestResponse = IHttpRequestResponseImplementation( + userHttpService, base64.b64decode(user_data['request']), base64.b64decode(user_data['response'])) + savedUserRequestResponse = self._extender._callbacks.saveBuffersToTempFiles(userRequestResponse) + logEntry.add_user_enforcement(user_id, savedUserRequestResponse, user_data['status']) + + self._extender._log.add(logEntry) + SwingUtilities.invokeLater(UpdateTableEDT(self._extender, "insert", row_index, row_index)) + self._extender.currentRequestNumber = self._extender.currentRequestNumber + 1 + self._extender._lock.release() \ No newline at end of file diff --git a/gui/table.py b/gui/table.py index a7ac4c2..d63f593 100644 --- a/gui/table.py +++ b/gui/table.py @@ -226,47 +226,94 @@ def getRowCount(self): return 0 def getColumnCount(self): - return 8 + base_columns = 6 + user_count = len(self._extender.userTab.user_tabs) if hasattr(self._extender, 'userTab') and self._extender.userTab else 0 + return base_columns + (user_count * 2) def getColumnName(self, columnIndex): - data = ['ID','Method', 'URL', 'Orig. Len', 'Modif. Len', "Unauth. Len", - "Authz. Status", "Unauth. Status"] + base_columns = ['ID', 'Method', 'URL', 'Orig. Len', 'Unauth.len', 'Unauth. Status'] + + if columnIndex < len(base_columns): + return base_columns[columnIndex] + try: - return data[columnIndex] - except IndexError: + if hasattr(self._extender, 'userTab') and self._extender.userTab: + user_index = (columnIndex - len(base_columns)) // 2 + col_type = (columnIndex - len(base_columns)) % 2 + + user_ids = sorted(self._extender.userTab.user_tabs.keys()) + + if user_index < len(user_ids): + user_id = user_ids[user_index] + user_name = self._extender.userTab.user_tabs[user_id]['user_name'] + + col_names = [ + "{} Modif. Len".format(user_name), + "{} Authz. Status".format(user_name) + ] + + return col_names[col_type] + + return "" + + except (IndexError, KeyError): return "" def getColumnClass(self, columnIndex): - data = [Integer, String, String, Integer, Integer, Integer, String, String] + base_classes = [Integer, String, String, Integer, Integer, String] + + if columnIndex < len(base_classes): + return base_classes[columnIndex] + try: - return data[columnIndex] + col_type = (columnIndex - len(base_classes)) % 2 + user_col_classes = [Integer, String] + return user_col_classes[col_type] + except IndexError: return "" def getValueAt(self, rowIndex, columnIndex): logEntry = self._extender._log.get(rowIndex) - if columnIndex == 0: + + if columnIndex == 0: # ID return logEntry._id - if columnIndex == 1: + if columnIndex == 1: # METHOD return logEntry._method - if columnIndex == 2: + if columnIndex == 2: # URL return logEntry._url.toString() - if columnIndex == 3: + if columnIndex == 3: # Original Request Length response = logEntry._originalrequestResponse.getResponse() return len(logEntry._originalrequestResponse.getResponse()) - self._extender._helpers.analyzeResponse(response).getBodyOffset() - if columnIndex == 4: - response = logEntry._requestResponse.getResponse() - return len(logEntry._requestResponse.getResponse()) - self._extender._helpers.analyzeResponse(response).getBodyOffset() - if columnIndex == 5: + if columnIndex == 4: # Unauthorized Request Length if logEntry._unauthorizedRequestResponse is not None: response = logEntry._unauthorizedRequestResponse.getResponse() return len(logEntry._unauthorizedRequestResponse.getResponse()) - self._extender._helpers.analyzeResponse(response).getBodyOffset() else: return 0 - if columnIndex == 6: - return logEntry._enfocementStatus - if columnIndex == 7: - return logEntry._enfocementStatusUnauthorized + if columnIndex == 5: + return logEntry._enfocementStatusUnauthorized + + # User columns + if hasattr(self._extender, 'userTab') and self._extender.userTab and columnIndex >= 6: + user_index = (columnIndex - 6) // 2 + col_type = (columnIndex - 6) % 2 + + user_ids = sorted(self._extender.userTab.user_tabs.keys()) + if user_index < len(user_ids): + user_id = user_ids[user_index] + user_name = self._extender.userTab.user_tabs[user_id]['user_name'] + + user_data = logEntry.get_user_enforcement(user_id) + if user_data: + if col_type == 0: # Modified Length + if user_data['requestResponse'] and user_data['requestResponse'].getResponse(): + response = user_data['requestResponse'].getResponse() + return len(response) - self._extender._helpers.analyzeResponse(response).getBodyOffset() + return 0 + elif col_type == 1: # Authorization Status + return user_data['enforcementStatus'] + return "" class TableSelectionListener(ListSelectionListener): @@ -284,15 +331,34 @@ def __init__(self, extender): self._extender.tableModel = TableModel(extender) self.setModel(self._extender.tableModel) self.addMouseListener(Mouseclick(self._extender)) - self.getColumnModel().getColumn(0).setPreferredWidth(450) self.setRowSelectionAllowed(True) + # Enables multi-row selection self.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) + self.updateColumnWidths() + + def updateColumnWidths(self): + if self.getColumnCount() > 0: + self.getColumnModel().getColumn(0).setPreferredWidth(50) + self.getColumnModel().getColumn(1).setPreferredWidth(80) + self.getColumnModel().getColumn(2).setPreferredWidth(300) + self.getColumnModel().getColumn(3).setPreferredWidth(80) + self.getColumnModel().getColumn(4).setPreferredWidth(80) + self.getColumnModel().getColumn(5).setPreferredWidth(120) + + if hasattr(self._extender, 'userTab'): + user_count = len(self._extender.userTab.user_tabs) + if user_count > 0: + col_width = 100 + + for i in range(6, self.getColumnCount()): + self.getColumnModel().getColumn(i).setPreferredWidth(col_width) def prepareRenderer(self, renderer, row, col): comp = JTable.prepareRenderer(self, renderer, row, col) value = self._extender.tableModel.getValueAt(self._extender.logTable.convertRowIndexToModel(row), col) - if col == 6 or col == 7: + + if col >= 5: if value == self._extender.BYPASSSED_STR: comp.setBackground(Color(255, 153, 153)) comp.setForeground(Color.BLACK) @@ -302,6 +368,12 @@ def prepareRenderer(self, renderer, row, col): elif value == self._extender.ENFORCED_STR: comp.setBackground(Color(204, 255, 153)) comp.setForeground(Color.BLACK) + elif value == "Disabled": + comp.setBackground(Color(211, 211, 211)) + comp.setForeground(Color.BLACK) + else: + comp.setForeground(Color.BLACK) + comp.setBackground(Color.WHITE) else: comp.setForeground(Color.BLACK) comp.setBackground(Color.WHITE) @@ -314,10 +386,29 @@ def prepareRenderer(self, renderer, row, col): return comp def changeSelection(self, row, col, toggle, extend): - # show the log entry for the selected row logEntry = self._extender._log.get(self._extender.logTable.convertRowIndexToModel(row)) - self._extender._requestViewer.setMessage(logEntry._requestResponse.getRequest(), True) - self._extender._responseViewer.setMessage(logEntry._requestResponse.getResponse(), False) + + current_user_name = "Original" + current_request_response = logEntry._originalrequestResponse + + if col >= 6 and hasattr(self._extender, 'userTab') and self._extender.userTab: + user_index = (col - 6) // 2 + user_ids = sorted(self._extender.userTab.user_tabs.keys()) + if user_index < len(user_ids): + user_id = user_ids[user_index] + user_name = self._extender.userTab.user_tabs[user_id]['user_name'] + user_data = logEntry.get_user_enforcement(user_id) + if user_data and user_data['requestResponse']: + current_user_name = user_name + current_request_response = user_data['requestResponse'] + + if col >= 4 and col < 6: # Unauthenticated columns + current_request_response = logEntry._unauthorizedRequestResponse + + current_user_name = "Unauthenticated" + + self._extender._requestViewer.setMessage(current_request_response.getRequest(), True) + self._extender._responseViewer.setMessage(current_request_response.getResponse(), False) self._extender._originalrequestViewer.setMessage(logEntry._originalrequestResponse.getRequest(), True) self._extender._originalresponseViewer.setMessage(logEntry._originalrequestResponse.getResponse(), False) @@ -330,37 +421,54 @@ def changeSelection(self, row, col, toggle, extend): self._extender._currentlyDisplayedItem = logEntry - if col == 3: + self.updateTabTitles(current_user_name) + + if col == 2: # URL column collapse(self._extender, self._extender.modified_requests_tabs) collapse(self._extender, self._extender.unauthenticated_requests_tabs) expand(self._extender, self._extender.original_requests_tabs) - elif col == 4 or col == 6: + elif col >= 6: # User columns collapse(self._extender, self._extender.original_requests_tabs) collapse(self._extender, self._extender.unauthenticated_requests_tabs) expand(self._extender, self._extender.modified_requests_tabs) - elif col == 5 or col == 7: + elif col == 4 or col == 5: # Unauth Status collapse(self._extender, self._extender.original_requests_tabs) collapse(self._extender, self._extender.modified_requests_tabs) expand(self._extender, self._extender.unauthenticated_requests_tabs) - else: - collapse(self._extender, self._extender.original_requests_tabs) - collapse(self._extender, self._extender.modified_requests_tabs) - collapse(self._extender, self._extender.unauthenticated_requests_tabs) JTable.changeSelection(self, row, col, toggle, extend) return + + def updateTabTitles(self, user_name): + if hasattr(self._extender, 'modified_requests_tabs'): + self._extender.modified_requests_tabs.setTitleAt(0, "{} Modified Request".format(user_name)) + self._extender.modified_requests_tabs.setTitleAt(1, "{} Modified Response".format(user_name)) class LogEntry: - def __init__(self, id, requestResponse, method, url, originalrequestResponse, enforcementStatus, unauthorizedRequestResponse, enforcementStatusUnauthorized): + def __init__(self, id, method, url, originalrequestResponse, unauthorizedRequestResponse=None, enforcementStatusUnauthorized="Disabled"): self._id = id - self._requestResponse = requestResponse - self._originalrequestResponse = originalrequestResponse self._method = method self._url = url - self._enfocementStatus = enforcementStatus + self._originalrequestResponse = originalrequestResponse self._unauthorizedRequestResponse = unauthorizedRequestResponse - self._enfocementStatusUnauthorized = enforcementStatusUnauthorized - return + self._enfocementStatusUnauthorized = enforcementStatusUnauthorized + + self._userEnforcements = {} + + def add_user_enforcement(self, user_id, requestResponse, enforcementStatus): + self._userEnforcements[user_id] = { + 'requestResponse': requestResponse, + 'enforcementStatus': enforcementStatus + } + + def get_user_enforcement(self, user_id): + return self._userEnforcements.get(user_id, None) + + def get_all_users(self): + return list(self._userEnforcements.keys()) + + def has_user_data(self, user_id): + return user_id in self._userEnforcements class Mouseclick(MouseAdapter): def __init__(self, extender): @@ -375,22 +483,19 @@ def __init__(self, extender): self._extender = extender def include(self, entry): - if self._extender.showAuthBypassModified.isSelected() and self._extender.BYPASSSED_STR == entry.getValue(6): - return True - elif self._extender.showAuthPotentiallyEnforcedModified.isSelected() and self._extender.IS_ENFORCED_STR == entry.getValue(6): - return True - elif self._extender.showAuthEnforcedModified.isSelected() and self._extender.ENFORCED_STR == entry.getValue(6): - return True - elif self._extender.showAuthBypassUnauthenticated.isSelected() and self._extender.BYPASSSED_STR == entry.getValue(7): - return True - elif self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and self._extender.IS_ENFORCED_STR == entry.getValue(7): - return True - elif self._extender.showAuthEnforcedUnauthenticated.isSelected() and self._extender.ENFORCED_STR == entry.getValue(7): - return True - elif self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == entry.getValue(7): + modif_status = entry.getValue(7) if entry.getValueCount() > 7 else "" + unauth_status = entry.getValue(5) if entry.getValueCount() > 5 else "" + + if (self._extender.showAuthBypassModified.isSelected() and self._extender.BYPASSSED_STR == modif_status) or \ + (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and self._extender.IS_ENFORCED_STR == modif_status) or \ + (self._extender.showAuthEnforcedModified.isSelected() and self._extender.ENFORCED_STR == modif_status) or \ + (self._extender.showAuthBypassUnauthenticated.isSelected() and self._extender.BYPASSSED_STR == unauth_status) or \ + (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and self._extender.IS_ENFORCED_STR == unauth_status) or \ + (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self._extender.ENFORCED_STR == unauth_status) or \ + (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == unauth_status): return True - else: - return False + + return False class UpdateTableEDT(Runnable): def __init__(self,extender,action,firstRow,lastRow): diff --git a/gui/tabs.py b/gui/tabs.py index 0b82625..1435a6c 100644 --- a/gui/tabs.py +++ b/gui/tabs.py @@ -52,16 +52,8 @@ def draw(self): """ self._extender.logTable = Table(self._extender) - - tableWidth = self._extender.logTable.getPreferredSize().width - self._extender.logTable.getColumn("ID").setPreferredWidth(Math.round(tableWidth / 50 * 2)) - self._extender.logTable.getColumn("Method").setPreferredWidth(Math.round(tableWidth / 50 * 3)) - self._extender.logTable.getColumn("URL").setPreferredWidth(Math.round(tableWidth / 50 * 25)) - self._extender.logTable.getColumn("Orig. Len").setPreferredWidth(Math.round(tableWidth / 50 * 4)) - self._extender.logTable.getColumn("Modif. Len").setPreferredWidth(Math.round(tableWidth / 50 * 4)) - self._extender.logTable.getColumn("Unauth. Len").setPreferredWidth(Math.round(tableWidth / 50 * 4)) - self._extender.logTable.getColumn("Authz. Status").setPreferredWidth(Math.round(tableWidth / 50 * 4)) - self._extender.logTable.getColumn("Unauth. Status").setPreferredWidth(Math.round(tableWidth / 50 * 4)) + + self.setupDynamicColumns() self._extender.tableSorter = TableRowSorter(self._extender.tableModel) rowFilter = TableRowFilter(self._extender) @@ -132,6 +124,7 @@ def draw(self): message_editor = MessageEditor(self._extender) self._extender.tabs = JTabbedPane() + self._extender._requestViewer = self._extender._callbacks.createMessageEditor(message_editor, False) self._extender._responseViewer = self._extender._callbacks.createMessageEditor(message_editor, False) @@ -147,7 +140,7 @@ def draw(self): self._extender.original_requests_tabs.addTab("Original Response", self._extender._originalresponseViewer.getComponent()) self._extender.original_requests_tabs.addTab("Expand", None) self._extender.original_requests_tabs.setSelectedIndex(0) - + self._extender.unauthenticated_requests_tabs = JTabbedPane() self._extender.unauthenticated_requests_tabs.addMouseListener(Mouseclick(self._extender)) self._extender.unauthenticated_requests_tabs.addTab("Unauthenticated Request", self._extender._unauthorizedrequestViewer.getComponent()) @@ -176,6 +169,17 @@ def draw(self): self._extender.tabs.addTab("User", self._extender.userPanel) + def setupDynamicColumns(self): + if hasattr(self._extender, 'tableModel'): + self._extender.tableModel.fireTableStructureChanged() + if hasattr(self._extender, 'logTable'): + self._extender.logTable.updateColumnWidths() + + def refreshTable(self): + if hasattr(self._extender, 'tableModel'): + self._extender.tableModel.fireTableStructureChanged() + self.setupDynamicColumns() + class SendRequestRepeater(ActionListener): def __init__(self, extender, callbacks, original): self._extender = extender @@ -229,7 +233,6 @@ def __init__(self, extender): self._extender = extender def actionPerformed(self, e): - # Its ready to delete multiple rows at a time once we can figure out how to select multiple row. rows = self._extender.logTable.getSelectedRows() if len(rows) != 0: rows = [self._extender.logTable.convertRowIndexToModel(row) for row in rows] @@ -257,13 +260,21 @@ def __init__(self, extender): self._extender = extender def getHttpService(self): - return self._extender._currentlyDisplayedItem.getHttpService() + return self._extender._currentlyDisplayedItem._originalrequestResponse.getHttpService() def getRequest(self): - return self._extender._currentlyDisplayedItem.getRequest() + if hasattr(self._extender, '_currentUserSelection'): + user_data = self._extender._currentlyDisplayedItem.get_user_enforcement(self._extender._currentUserSelection) + if user_data and user_data['requestResponse']: + return user_data['requestResponse'].getRequest() + return self._extender._currentlyDisplayedItem._originalrequestResponse.getRequest() def getResponse(self): - return self._extender._currentlyDisplayedItem.getResponse() + if hasattr(self._extender, '_currentUserSelection'): + user_data = self._extender._currentlyDisplayedItem.get_user_enforcement(self._extender._currentUserSelection) + if user_data and user_data['requestResponse']: + return user_data['requestResponse'].getResponse() + return self._extender._currentlyDisplayedItem._originalrequestResponse.getResponse() class Mouseclick(MouseAdapter): def __init__(self, extender): @@ -282,14 +293,11 @@ def __init__(self, extender, callbacks): self._callbacks = callbacks def actionPerformed(self, e): - # Get the selected row of the JTable row = self._extender.logTable.getSelectedRow() - # Get the LogEntry object for the selected row rowModelIndex = self._extender.logTable.convertRowIndexToModel(row) entry = self._extender.tableModel.getValueAt(rowModelIndex, 0) - # Get the modified request request = self._extender._currentlyDisplayedItem._requestResponse host = request.getHttpService().getHost() port = request.getHttpService().getPort() diff --git a/gui/user_tab.py b/gui/user_tab.py index 91c0a7c..f17e5e9 100644 --- a/gui/user_tab.py +++ b/gui/user_tab.py @@ -67,15 +67,12 @@ def add_user(self): user_ed = UserEnforcementDetector(self.user_count) user_ed.draw() - user_ed.draw_unauthenticated() user_mr = UserMatchReplace(self.user_count) user_mr.draw() userSubTabs.addTab("Enforcement Detector", user_ed.EDPnl) - userSubTabs.addTab("Unauthentication Detector", user_ed.EDPnlUnauth) - userSubTabs.addTab("Match/Replace", user_mr.MRPnl) userPanel.add(headerPanel, BorderLayout.NORTH) @@ -94,18 +91,48 @@ def add_user(self): self.userTabs.addTab(unique_user_name, userPanel) self.userTabs.setSelectedIndex(self.userTabs.getTabCount() - 1) - + + self.refreshTableStructure() + def remove_user(self): if self.userTabs.getTabCount() <= 1: JOptionPane.showMessageDialog(None, "Cannot remove the last user!", "Warning", JOptionPane.WARNING_MESSAGE) return selected_index = self.userTabs.getSelectedIndex() + if selected_index >= 0: - self.userTabs.removeTabAt(selected_index) - + selected_panel = self.userTabs.getComponentAt(selected_index) + + user_id_to_remove = None + user_name_to_remove = None + + for user_id, user_data in self.user_tabs.items(): + if user_data['panel'] == selected_panel: + user_id_to_remove = user_id + user_name_to_remove = user_data['user_name'] + break + + if user_id_to_remove and user_name_to_remove: + if user_name_to_remove in self.user_names: + self.user_names.remove(user_name_to_remove) + + del self.user_tabs[user_id_to_remove] + + self.userTabs.removeTabAt(selected_index) + + self.refreshTableStructure() + + def reset_user(self): + self.userTabs.removeAll() + self.user_tabs.clear() + del self.user_names[:] + self.user_count = 0 + self.add_user() + def duplicate_user(self): selected_index = self.userTabs.getSelectedIndex() + if selected_index >= 0: selected_panel = self.userTabs.getComponentAt(selected_index) source_user_data = None @@ -131,14 +158,6 @@ def copy_ed_settings(self, source_ed, target_ed): target_ed.EDType.setSelectedIndex(source_ed.EDType.getSelectedIndex()) target_ed.EDText.setText(source_ed.EDText.getText()) target_ed.AndOrType.setSelectedIndex(source_ed.AndOrType.getSelectedIndex()) - - target_ed.EDModelUnauth.clear() - for i in range(source_ed.EDModelUnauth.getSize()): - target_ed.EDModelUnauth.addElement(source_ed.EDModelUnauth.getElementAt(i)) - - target_ed.EDTypeUnauth.setSelectedIndex(source_ed.EDTypeUnauth.getSelectedIndex()) - target_ed.EDTextUnauth.setText(source_ed.EDTextUnauth.getText()) - target_ed.AndOrTypeUnauth.setSelectedIndex(source_ed.AndOrTypeUnauth.getSelectedIndex()) def copy_mr_settings(self, source_mr, target_mr): target_mr.MRModel.clear() @@ -160,20 +179,30 @@ def copy_mr_settings(self, source_mr, target_mr): def rename_user(self): selected_index = self.userTabs.getSelectedIndex() + if selected_index >= 0: current_name = self.userTabs.getTitleAt(selected_index) new_name = JOptionPane.showInputDialog(None, "Enter new name for user:", "Rename User", JOptionPane.QUESTION_MESSAGE, None, None, current_name) if new_name and new_name.strip(): + if current_name in self.user_names: + self.user_names.remove(current_name) + unique_name = self.get_unique_name(new_name.strip()) + self.user_names.append(unique_name) self.userTabs.setTitleAt(selected_index, unique_name) - for user_data in self.user_tabs.items(): - if user_data['panel'] == self.userTabs.getComponentAt(selected_index): + + selected_panel = self.userTabs.getComponentAt(selected_index) + + for user_id, user_data in self.user_tabs.items(): + if user_data['panel'] == selected_panel: user_data['header_label'].setText(unique_name) user_data['user_name'] = unique_name break + self.refreshTableStructure() + def get_unique_name(self, name): if name not in self.user_names: return name @@ -189,8 +218,15 @@ def get_unique_name(self, name): if counter > 100: return "{} Copy {}".format(name, counter) - + + def refreshTableStructure(self): + if hasattr(self._extender, 'tableModel'): + self._extender.tableModel.fireTableStructureChanged() + if hasattr(self._extender, 'logTable'): + self._extender.logTable.updateColumnWidths() + class UserEnforcementDetector(EnforcementDetectors): + def __init__(self, user_id): self.isolated_extender = type('IsolatedExtender', (object,), {})() self.user_id = user_id @@ -206,15 +242,6 @@ def draw(self): self.EDList = self.isolated_extender.EDList self.AndOrType = self.isolated_extender.AndOrType - def draw_unauthenticated(self): - EnforcementDetectors.draw_unauthenticated(self) - self.EDPnlUnauth = self.isolated_extender.EDPnlUnauth - self.EDTypeUnauth = self.isolated_extender.EDTypeUnauth - self.EDTextUnauth = self.isolated_extender.EDTextUnauth - self.EDModelUnauth = self.isolated_extender.EDModelUnauth - self.EDListUnauth = self.isolated_extender.EDListUnauth - self.AndOrTypeUnauth = self.isolated_extender.AndOrTypeUnauth - class UserMatchReplace(MatchReplace): def __init__(self, user_id): self.isolated_extender = type('IsolatedExtender', (object,), {})() diff --git a/helpers/initiator.py b/helpers/initiator.py index 141f057..115d631 100644 --- a/helpers/initiator.py +++ b/helpers/initiator.py @@ -58,6 +58,8 @@ def draw_all(self): user_tab = UserTab(self._extender) user_tab.draw() + self._extender.userTab = user_tab + tabs = Tabs(self._extender) tabs.draw() From 1f63eddab005589a16737a4f4be325ac188b4e33 Mon Sep 17 00:00:00 2001 From: tvroi Date: Thu, 24 Jul 2025 08:35:49 +0700 Subject: [PATCH 06/15] feat: enable unauth tab on configuration tab --- gui/configuration_tab.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gui/configuration_tab.py b/gui/configuration_tab.py index 3697a0e..521536d 100644 --- a/gui/configuration_tab.py +++ b/gui/configuration_tab.py @@ -90,10 +90,8 @@ def draw(self): self._extender.filtersTabs = JTabbedPane() self._extender.filtersTabs = self._extender.filtersTabs - # self._extender.filtersTabs.addTab("Enforcement Detector", self._extender.EDPnl) - # self._extender.filtersTabs.addTab("Unauthentication Detector ", self._extender.EDPnlUnauth) + self._extender.filtersTabs.addTab("Unauthentication Detector ", self._extender.EDPnlUnauth) self._extender.filtersTabs.addTab("Interception Filters", self._extender.filtersPnl) - # self._extender.filtersTabs.addTab("Match/Replace", self._extender.MRPnl) self._extender.filtersTabs.addTab("Table Filter", self._extender.filterPnl) self._extender.filtersTabs.addTab("Save/Restore", self._extender.exportPnl) @@ -386,5 +384,4 @@ def __init__(self, extender): def actionPerformed(self, e): selectedTitle = self._extender.savedHeadersTitlesCombo.getSelectedItem() headers = [x for x in self._extender.savedHeaders if x['title'] == selectedTitle] - self._extender.replaceString.setText(headers[0]['headers']) - + self._extender.replaceString.setText(headers[0]['headers']) \ No newline at end of file From b3332322e8e002bc9f2a3847fc8ae095002ab744 Mon Sep 17 00:00:00 2001 From: tvroi Date: Thu, 24 Jul 2025 08:50:58 +0700 Subject: [PATCH 07/15] fix: remove checkAuthorization --- authorization/authorization.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/authorization/authorization.py b/authorization/authorization.py index 8fbe501..2f6801d 100644 --- a/authorization/authorization.py +++ b/authorization/authorization.py @@ -198,11 +198,7 @@ def handle_message(self, toolFlag, messageIsRequest, messageInfo): # checkAuthorization(self, messageInfo,self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(),self.doUnauthorizedRequest.isSelected()) checkAuthorizationAllUsers(self, messageInfo, self.doUnauthorizedRequest.isSelected()) -def checkAuthorizationAllUsers(self, messageInfo, checkUnauthorized=True): - # if not hasattr(self, 'userTab') or not self.userTab or len(self.userTab.user_tabs) == 0: - # checkAuthorization(self, messageInfo, self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(), checkUnauthorized) - # return - +def checkAuthorizationAllUsers(self, messageInfo, checkUnauthorized=True): originalHeaders = self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders() requestResponseUnauthorized = None @@ -365,10 +361,7 @@ def send_request_to_autorize(self, messageInfo): newHttpRequestResponse = IHttpRequestResponseImplementation(httpService,request,response) newHttpRequestResponsePersisted = self._callbacks.saveBuffersToTempFiles(newHttpRequestResponse) - if hasattr(self, 'userTab') and self.userTab and len(self.userTab.user_tabs) > 0: - checkAuthorizationAllUsers(self, newHttpRequestResponsePersisted, self.doUnauthorizedRequest.isSelected()) - else: - checkAuthorization(self, newHttpRequestResponsePersisted, self._helpers.analyzeResponse(messageInfo.getResponse()).getHeaders(), self.doUnauthorizedRequest.isSelected()) + checkAuthorizationAllUsers(self, newHttpRequestResponsePersisted, self.doUnauthorizedRequest.isSelected()) def auth_enforced_via_enforcement_detectors(self, filters, requestResponse, andOrEnforcement): response = requestResponse.getResponse() From 0ffdcb0ca96aec027a556fd46bc7b6c06edd7caa Mon Sep 17 00:00:00 2001 From: tvroi Date: Thu, 24 Jul 2025 11:39:31 +0700 Subject: [PATCH 08/15] feat: table filtering --- gui/table.py | 447 ++++++++++++++++++++++++++------------------------- 1 file changed, 224 insertions(+), 223 deletions(-) diff --git a/gui/table.py b/gui/table.py index d63f593..9a2f7ff 100644 --- a/gui/table.py +++ b/gui/table.py @@ -6,14 +6,13 @@ from java.lang import Integer from java.lang import Runnable from javax.swing import JTable -from javax.swing import JLabel from javax.swing import JPanel from javax.swing import RowFilter from javax.swing import JCheckBox -from javax.swing import GroupLayout from javax.swing import ListSelectionModel from java.awt.event import MouseAdapter from java.awt.event import ItemListener +from java.awt import FlowLayout from javax.swing.table import AbstractTableModel from javax.swing.event import ListSelectionListener @@ -27,187 +26,34 @@ def draw(self): """ init show tab """ + self._extender.filterPnl = JPanel(FlowLayout(FlowLayout.LEFT)) - filterLModified = JLabel("Modified:") - filterLModified.setBounds(10, 10, 100, 30) - - filterLUnauthenticated = JLabel("Unauthenticated:") - filterLUnauthenticated.setBounds(250, 10, 100, 30) - - self._extender.showAuthBypassModified = JCheckBox(self._extender.BYPASSSED_STR) - self._extender.showAuthBypassModified.setBounds(10, 35, 200, 30) - self._extender.showAuthBypassModified.setSelected(True) - self._extender.showAuthBypassModified.addItemListener(TabTableFilter(self._extender)) - - self._extender.showAuthPotentiallyEnforcedModified = JCheckBox("Is enforced???") - self._extender.showAuthPotentiallyEnforcedModified.setBounds(10, 60, 200, 30) - self._extender.showAuthPotentiallyEnforcedModified.setSelected(True) - self._extender.showAuthPotentiallyEnforcedModified.addItemListener(TabTableFilter(self._extender)) - - self._extender.showAuthEnforcedModified = JCheckBox(self._extender.ENFORCED_STR) - self._extender.showAuthEnforcedModified.setBounds(10, 85, 200, 30) - self._extender.showAuthEnforcedModified.setSelected(True) - self._extender.showAuthEnforcedModified.addItemListener(TabTableFilter(self._extender)) - - self._extender.showAuthBypassUnauthenticated = JCheckBox(self._extender.BYPASSSED_STR) - self._extender.showAuthBypassUnauthenticated.setBounds(250, 35, 200, 30) - self._extender.showAuthBypassUnauthenticated.setSelected(True) - self._extender.showAuthBypassUnauthenticated.addItemListener(TabTableFilter(self._extender)) - - self._extender.showAuthPotentiallyEnforcedUnauthenticated = JCheckBox("Is enforced???") - self._extender.showAuthPotentiallyEnforcedUnauthenticated.setBounds(250, 60, 200, 30) - self._extender.showAuthPotentiallyEnforcedUnauthenticated.setSelected(True) - self._extender.showAuthPotentiallyEnforcedUnauthenticated.addItemListener(TabTableFilter(self._extender)) - - self._extender.showAuthEnforcedUnauthenticated = JCheckBox(self._extender.ENFORCED_STR) - self._extender.showAuthEnforcedUnauthenticated.setBounds(250, 85, 200, 30) - self._extender.showAuthEnforcedUnauthenticated.setSelected(True) - self._extender.showAuthEnforcedUnauthenticated.addItemListener(TabTableFilter(self._extender)) - - self._extender.showDisabledUnauthenticated = JCheckBox("Disabled") - self._extender.showDisabledUnauthenticated.setBounds(250, 110, 200, 30) - self._extender.showDisabledUnauthenticated.setSelected(True) - self._extender.showDisabledUnauthenticated.addItemListener(TabTableFilter(self._extender)) - - self._extender.filterPnl = JPanel() - layout = GroupLayout(self._extender.filterPnl) - self._extender.filterPnl.setLayout(layout) - layout.setAutoCreateGaps(True) - layout.setAutoCreateContainerGaps(True) - - layout.setHorizontalGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup() - .addComponent( - filterLModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthBypassModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthPotentiallyEnforcedModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthEnforcedModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - ) - .addGroup(layout.createParallelGroup() - .addComponent( - filterLUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthBypassUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthPotentiallyEnforcedUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthEnforcedUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showDisabledUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - ) - ) - - - layout.setVerticalGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent( - filterLModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - filterLUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - ) - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) - .addGroup(layout.createSequentialGroup() - .addComponent( - self._extender.showAuthBypassModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthPotentiallyEnforcedModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthEnforcedModified, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - ) - .addGroup(layout.createSequentialGroup() - .addComponent( - self._extender.showAuthBypassUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthPotentiallyEnforcedUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showAuthEnforcedUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - .addComponent( - self._extender.showDisabledUnauthenticated, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - GroupLayout.PREFERRED_SIZE, - ) - ) - ) - ) + self._extender.showBypassed = JCheckBox(self._extender.BYPASSSED_STR) + self._extender.showBypassed.setSelected(True) + self._extender.showBypassed.addItemListener(TabTableFilter(self._extender)) + + self._extender.showIsEnforced = JCheckBox("Is enforced???") + self._extender.showIsEnforced.setSelected(True) + self._extender.showIsEnforced.addItemListener(TabTableFilter(self._extender)) + + self._extender.showEnforced = JCheckBox(self._extender.ENFORCED_STR) + self._extender.showEnforced.setSelected(True) + self._extender.showEnforced.addItemListener(TabTableFilter(self._extender)) + + self._extender.filterPnl.add(self._extender.showBypassed) + self._extender.filterPnl.add(self._extender.showIsEnforced) + self._extender.filterPnl.add(self._extender.showEnforced) class TabTableFilter(ItemListener): def __init__(self, extender): self._extender = extender def itemStateChanged(self, e): - self._extender.tableSorter.sort() + if hasattr(self._extender, 'tableSorter'): + self._extender.tableSorter.sort() + + if hasattr(self._extender, 'logTable'): + self._extender.logTable.repaint() class TableModel(AbstractTableModel): def __init__(self, extender): @@ -315,6 +161,15 @@ def getValueAt(self, rowIndex, columnIndex): return user_data['enforcementStatus'] return "" + +class ColorConstants: + BLACK = Color.BLACK + WHITE = Color.WHITE + BYPASSED_BG = Color(255, 153, 153) # Light red + IS_ENFORCED_BG = Color(255, 204, 153) # Light orange + ENFORCED_BG = Color(204, 255, 153) # Light green + DISABLED_BG = Color(211, 211, 211) # Light gray + SELECTED_BG = Color(201, 215, 255) class TableSelectionListener(ListSelectionListener): """Class Responsible for the multi-row deletion""" @@ -339,52 +194,97 @@ def __init__(self, extender): def updateColumnWidths(self): if self.getColumnCount() > 0: - self.getColumnModel().getColumn(0).setPreferredWidth(50) - self.getColumnModel().getColumn(1).setPreferredWidth(80) - self.getColumnModel().getColumn(2).setPreferredWidth(300) - self.getColumnModel().getColumn(3).setPreferredWidth(80) - self.getColumnModel().getColumn(4).setPreferredWidth(80) - self.getColumnModel().getColumn(5).setPreferredWidth(120) + column_model = self.getColumnModel() + + widths = [50, 80, 300, 80, 80, 120] + for i, width in enumerate(widths): + column_model.getColumn(i).setPreferredWidth(width) - if hasattr(self._extender, 'userTab'): + if hasattr(self._extender, 'userTab') and self._extender.userTab: user_count = len(self._extender.userTab.user_tabs) - if user_count > 0: - col_width = 100 - - for i in range(6, self.getColumnCount()): - self.getColumnModel().getColumn(i).setPreferredWidth(col_width) + for i in range(6, 6 + (user_count << 1)): # Bit shift for multiply by 2 + column_model.getColumn(i).setPreferredWidth(100) def prepareRenderer(self, renderer, row, col): comp = JTable.prepareRenderer(self, renderer, row, col) - value = self._extender.tableModel.getValueAt(self._extender.logTable.convertRowIndexToModel(row), col) - - if col >= 5: - if value == self._extender.BYPASSSED_STR: - comp.setBackground(Color(255, 153, 153)) - comp.setForeground(Color.BLACK) - elif value == self._extender.IS_ENFORCED_STR: - comp.setBackground(Color(255, 204, 153)) - comp.setForeground(Color.BLACK) - elif value == self._extender.ENFORCED_STR: - comp.setBackground(Color(204, 255, 153)) - comp.setForeground(Color.BLACK) - elif value == "Disabled": - comp.setBackground(Color(211, 211, 211)) - comp.setForeground(Color.BLACK) + + if col < 4: + comp.setForeground(ColorConstants.BLACK) + comp.setBackground(ColorConstants.WHITE) + + selected_rows = self._extender.logTable.getSelectedRows() + if row in selected_rows: + comp.setBackground(ColorConstants.SELECTED_BG) + + return comp + + model_row = self._extender.logTable.convertRowIndexToModel(row) + value = self._extender.tableModel.getValueAt(model_row, col) + + comp.setForeground(Color.BLACK) + comp.setBackground(Color.WHITE) + + should_mask = False + + if col == 4: # Unauthenticated length + status_value = self._extender.tableModel.getValueAt(model_row, 5) + should_mask = not self.shouldShowStatus(status_value) + elif col == 5: # Unauthenticated status + should_mask = not self.shouldShowStatus(value) + elif col >= 6: # User columns + if col & 1: + should_mask = not self.shouldShowStatus(value) else: - comp.setForeground(Color.BLACK) - comp.setBackground(Color.WHITE) - else: - comp.setForeground(Color.BLACK) + status_col = col + 1 + if status_col < self._extender.tableModel.getColumnCount(): + status_value = self._extender.tableModel.getValueAt(model_row, status_col) + should_mask = not self.shouldShowStatus(status_value) + + if should_mask: + comp.setText("") comp.setBackground(Color.WHITE) + comp.setForeground(Color.WHITE) + elif col >= 4: + if col == 5 or (col >= 6 and col & 1): + if value == self._extender.BYPASSSED_STR: + comp.setBackground(ColorConstants.BYPASSED_BG) + elif value == self._extender.IS_ENFORCED_STR: + comp.setBackground(ColorConstants.IS_ENFORCED_BG) + elif value == self._extender.ENFORCED_STR: + comp.setBackground(ColorConstants.ENFORCED_BG) + elif value == "Disabled": + comp.setBackground(ColorConstants.DISABLED_BG) + + comp.setForeground(ColorConstants.BLACK) - selectedRows = self._extender.logTable.getSelectedRows() - if row in selectedRows: - comp.setBackground(Color(201, 215, 255)) - comp.setForeground(Color.BLACK) + selected_rows = self._extender.logTable.getSelectedRows() + + if row in selected_rows and not should_mask: + comp.setBackground(ColorConstants.SELECTED_BG) + comp.setForeground(ColorConstants.BLACK) return comp + def shouldShowStatus(self, status): + if not hasattr(self._extender, 'showBypassed'): + return True + + if (self._extender.showBypassed.isSelected() and + self._extender.showIsEnforced.isSelected() and + self._extender.showEnforced.isSelected()): + return True + + if status == "Disabled": + return True + elif self._extender.showBypassed.isSelected() and self._extender.BYPASSSED_STR == status: + return True + elif self._extender.showIsEnforced.isSelected() and self._extender.IS_ENFORCED_STR == status: + return True + elif self._extender.showEnforced.isSelected() and self._extender.ENFORCED_STR == status: + return True + + return False + def changeSelection(self, row, col, toggle, extend): logEntry = self._extender._log.get(self._extender.logTable.convertRowIndexToModel(row)) @@ -392,7 +292,7 @@ def changeSelection(self, row, col, toggle, extend): current_request_response = logEntry._originalrequestResponse if col >= 6 and hasattr(self._extender, 'userTab') and self._extender.userTab: - user_index = (col - 6) // 2 + user_index = (col - 6) >> 1 user_ids = sorted(self._extender.userTab.user_tabs.keys()) if user_index < len(user_ids): user_id = user_ids[user_index] @@ -444,6 +344,83 @@ def updateTabTitles(self, user_name): self._extender.modified_requests_tabs.setTitleAt(0, "{} Modified Request".format(user_name)) self._extender.modified_requests_tabs.setTitleAt(1, "{} Modified Response".format(user_name)) +class TableExtension: + def prepareRenderer(self, renderer, row, col): + comp = JTable.prepareRenderer(self, renderer, row, col) + + if col < 5: + comp.setForeground(ColorConstants.BLACK) + comp.setBackground(ColorConstants.WHITE) + + selected_rows = self._extender.logTable.getSelectedRows() + if row in selected_rows: + comp.setBackground(ColorConstants.SELECTED_BG) + comp.setForeground(ColorConstants.BLACK) + + return comp + + model_row = self._extender.logTable.convertRowIndexToModel(row) + value = self._extender.tableModel.getValueAt(model_row, col) + + comp.setForeground(ColorConstants.BLACK) + comp.setBackground(ColorConstants.WHITE) + should_mask = False + + if col == 5: + should_mask = not self.shouldShowStatus(value) + elif col >= 6: + if col & 1: # Odd columns are status + should_mask = not self.shouldShowStatus(value) + else: # Even columns are length + status_col = col + 1 + if status_col < self._extender.tableModel.getColumnCount(): + status_value = self._extender.tableModel.getValueAt(model_row, status_col) + should_mask = not self.shouldShowStatus(status_value) + + if should_mask: + comp.setText("") + comp.setBackground(ColorConstants.WHITE) + comp.setForeground(ColorConstants.WHITE) + else: + if col & 1 or col == 5: # Status columns + if value == self._extender.BYPASSSED_STR: + comp.setBackground(ColorConstants.BYPASSED_BG) + elif value == self._extender.IS_ENFORCED_STR: + comp.setBackground(ColorConstants.IS_ENFORCED_BG) + elif value == self._extender.ENFORCED_STR: + comp.setBackground(ColorConstants.ENFORCED_BG) + elif value == "Disabled": + comp.setBackground(ColorConstants.DISABLED_BG) + + comp.setForeground(ColorConstants.BLACK) + + selected_rows = self._extender.logTable.getSelectedRows() + if row in selected_rows and (not should_mask or col < 5): + comp.setBackground(ColorConstants.SELECTED_BG) + comp.setForeground(ColorConstants.BLACK) + + return comp + + def shouldShowStatus(self, status): + if not hasattr(self._extender, 'showBypassed'): + return True + + if (self._extender.showBypassed.isSelected() and + self._extender.showIsEnforced.isSelected() and + self._extender.showEnforced.isSelected()): + return True + + if status == "Disabled": + return True + elif self._extender.showBypassed.isSelected() and self._extender.BYPASSSED_STR == status: + return True + elif self._extender.showIsEnforced.isSelected() and self._extender.IS_ENFORCED_STR == status: + return True + elif self._extender.showEnforced.isSelected() and self._extender.ENFORCED_STR == status: + return True + + return False + class LogEntry: def __init__(self, id, method, url, originalrequestResponse, unauthorizedRequestResponse=None, enforcementStatusUnauthorized="Disabled"): self._id = id @@ -483,20 +460,45 @@ def __init__(self, extender): self._extender = extender def include(self, entry): - modif_status = entry.getValue(7) if entry.getValueCount() > 7 else "" + if (hasattr(self._extender, 'showBypassed') and + self._extender.showBypassed.isSelected() and + self._extender.showIsEnforced.isSelected() and + self._extender.showEnforced.isSelected()): + return True + unauth_status = entry.getValue(5) if entry.getValueCount() > 5 else "" - if (self._extender.showAuthBypassModified.isSelected() and self._extender.BYPASSSED_STR == modif_status) or \ - (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and self._extender.IS_ENFORCED_STR == modif_status) or \ - (self._extender.showAuthEnforcedModified.isSelected() and self._extender.ENFORCED_STR == modif_status) or \ - (self._extender.showAuthBypassUnauthenticated.isSelected() and self._extender.BYPASSSED_STR == unauth_status) or \ - (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and self._extender.IS_ENFORCED_STR == unauth_status) or \ - (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self._extender.ENFORCED_STR == unauth_status) or \ - (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == unauth_status): + if self.statusMatchesFilter(unauth_status): return True + if hasattr(self._extender, 'userTab') and self._extender.userTab: + user_count = len(self._extender.userTab.user_tabs) + + for i in range(user_count): + status_col = 7 + (i << 1) + + if status_col < entry.getValueCount(): + user_status = entry.getValue(status_col) + if self.statusMatchesFilter(user_status): + return True + return False - + + def statusMatchesFilter(self, status): + if not hasattr(self._extender, 'showBypassed'): + return True + + if self._extender.showBypassed.isSelected() and self._extender.BYPASSSED_STR == status: + return True + elif self._extender.showIsEnforced.isSelected() and self._extender.IS_ENFORCED_STR == status: + return True + elif self._extender.showEnforced.isSelected() and self._extender.ENFORCED_STR == status: + return True + elif status == "Disabled": + return True + + return False + class UpdateTableEDT(Runnable): def __init__(self,extender,action,firstRow,lastRow): self._extender=extender @@ -512,5 +514,4 @@ def run(self): elif self._action == "delete": self._extender.tableModel.fireTableRowsDeleted(self._firstRow, self._lastRow) else: - print("Invalid action in UpdateTableEDT") - + print("Invalid action in UpdateTableEDT") \ No newline at end of file From 788f46370b6d39502b8fd8566db7feb450b085ce Mon Sep 17 00:00:00 2001 From: tvroi Date: Thu, 24 Jul 2025 13:20:52 +0700 Subject: [PATCH 09/15] fix: adjust log entry --- gui/table.py | 4 ++-- gui/tabs.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gui/table.py b/gui/table.py index 9a2f7ff..3159d21 100644 --- a/gui/table.py +++ b/gui/table.py @@ -258,7 +258,7 @@ def prepareRenderer(self, renderer, row, col): comp.setForeground(ColorConstants.BLACK) selected_rows = self._extender.logTable.getSelectedRows() - + if row in selected_rows and not should_mask: comp.setBackground(ColorConstants.SELECTED_BG) comp.setForeground(ColorConstants.BLACK) @@ -422,7 +422,7 @@ def shouldShowStatus(self, status): return False class LogEntry: - def __init__(self, id, method, url, originalrequestResponse, unauthorizedRequestResponse=None, enforcementStatusUnauthorized="Disabled"): + def __init__(self, id, method, url, originalrequestResponse, unauthorizedRequestResponse, enforcementStatusUnauthorized): self._id = id self._method = method self._url = url diff --git a/gui/tabs.py b/gui/tabs.py index 1435a6c..9d1e843 100644 --- a/gui/tabs.py +++ b/gui/tabs.py @@ -293,11 +293,14 @@ def __init__(self, extender, callbacks): self._callbacks = callbacks def actionPerformed(self, e): + # Get the selected row of the JTable row = self._extender.logTable.getSelectedRow() + # Get the LogEntry object for the selected row rowModelIndex = self._extender.logTable.convertRowIndexToModel(row) entry = self._extender.tableModel.getValueAt(rowModelIndex, 0) + # Get the modified request request = self._extender._currentlyDisplayedItem._requestResponse host = request.getHttpService().getHost() port = request.getHttpService().getPort() From 6d291f0b2c8a949723ced6ce79e6acd8f75c5848 Mon Sep 17 00:00:00 2001 From: tvroi Date: Thu, 24 Jul 2025 14:44:09 +0700 Subject: [PATCH 10/15] feat: adjust to new fitler system --- gui/export.py | 171 ++++++++++++++++++++++---------------------- gui/save_restore.py | 46 +++++++----- 2 files changed, 112 insertions(+), 105 deletions(-) diff --git a/gui/export.py b/gui/export.py index 38cedf2..b7e6bcd 100644 --- a/gui/export.py +++ b/gui/export.py @@ -232,8 +232,6 @@ def draw(self): ) ) ) - - def export(self, event): if self.exportType.getSelectedItem() == "HTML": @@ -247,6 +245,45 @@ def saveStateAction(self, event): def restoreStateAction(self, event): self.save_restore.restoreState() + def shouldIncludeRow(self, logEntry, enforcementStatusFilter): + should_include = False + + if enforcementStatusFilter == "All Statuses": + should_include = True + elif enforcementStatusFilter == "As table filter": + # Check if the new filter system allows this status + if hasattr(self._extender, 'showBypassed') and hasattr(self._extender, 'showIsEnforced') and hasattr(self._extender, 'showEnforced'): + # Check unauthenticated status + unauth_status = logEntry._enfocementStatusUnauthorized + if ((self._extender.showBypassed.isSelected() and self.BYPASSSED_STR == unauth_status) or + (self._extender.showIsEnforced.isSelected() and self.IS_ENFORCED_STR == unauth_status) or + (self._extender.showEnforced.isSelected() and self.ENFORCED_STR == unauth_status) or + ("Disabled" == unauth_status)): + should_include = True + + for user_id in logEntry.get_all_users(): + user_data = logEntry.get_user_enforcement(user_id) + if user_data: + user_status = user_data['enforcementStatus'] + if ((self._extender.showBypassed.isSelected() and self.BYPASSSED_STR == user_status) or + (self._extender.showIsEnforced.isSelected() and self.IS_ENFORCED_STR == user_status) or + (self._extender.showEnforced.isSelected() and self.ENFORCED_STR == user_status)): + should_include = True + break + else: + should_include = True + else: + if enforcementStatusFilter == logEntry._enfocementStatusUnauthorized: + should_include = True + else: + for user_id in logEntry.get_all_users(): + user_data = logEntry.get_user_enforcement(user_id) + if user_data and enforcementStatusFilter == user_data['enforcementStatus']: + should_include = True + break + + return should_include + def exportToHTML(self): parentFrame = JFrame() fileChooser = JFileChooser() @@ -258,26 +295,40 @@ def exportToHTML(self): enforcementStatusFilter = self.exportES.getSelectedItem() + # Build header with user columns header_html = "IDMethodURLOriginal lengthUnauth lengthUnauth Status" if hasattr(self._extender, 'userTab') and self._extender.userTab: - for user_id, user_data in self._extender.userTab.user_tabs.items(): - user_name = user_data['user_name'] + for user_id in sorted(self._extender.userTab.user_tabs.keys()): + user_name = self._extender.userTab.user_tabs[user_id]['user_name'] header_html += "{} Len{} Status".format(user_name, user_name) header_html += "" + # Use original HTML styling from document 2 htmlContent = """Autorize Report by Barak Tawily

Autorize Report

@@ -303,6 +354,9 @@ def exportToHTML(self): else: unique_HTML_lines.add(lineData) + if not self.shouldIncludeRow(logEntry, enforcementStatusFilter): + continue + row_html = "%d%s%s" % ( logEntry._id, logEntry._method, logEntry._url, logEntry._url) @@ -344,44 +398,13 @@ def exportToHTML(self): row_html += "0N/A" row_html += "" - - should_include = False - if enforcementStatusFilter == "All Statuses": - should_include = True - elif enforcementStatusFilter == "As table filter": - if ((self._extender.showAuthBypassUnauthenticated.isSelected() and self.BYPASSSED_STR == logEntry._enfocementStatusUnauthorized) or - (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and self.IS_ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or - (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self.ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or - (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == logEntry._enfocementStatusUnauthorized)): - should_include = True - - for user_id in logEntry.get_all_users(): - user_data = logEntry.get_user_enforcement(user_id) - if user_data: - user_status = user_data['enforcementStatus'] - if ((self._extender.showAuthBypassModified.isSelected() and self.BYPASSSED_STR == user_status) or - (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and self.IS_ENFORCED_STR == user_status) or - (self._extender.showAuthEnforcedModified.isSelected() and self.ENFORCED_STR == user_status)): - should_include = True - break - else: - if enforcementStatusFilter == logEntry._enfocementStatusUnauthorized: - should_include = True - else: - for user_id in logEntry.get_all_users(): - user_data = logEntry.get_user_enforcement(user_id) - if user_data and enforcementStatusFilter == user_data['enforcementStatus']: - should_include = True - break - - if should_include: - htmlContent += row_html + htmlContent += row_html htmlContent += "" f = open(fileToSave.getAbsolutePath(), 'w') f.writelines(htmlContent) f.close() - + def exportToCSV(self): parentFrame = JFrame() fileChooser = JFileChooser() @@ -393,12 +416,12 @@ def exportToCSV(self): enforcementStatusFilter = self.exportES.getSelectedItem() - csvContent = "ID\tMethod\tURL\tOriginal Length\tUnauth Length\tUnauth Status" + csvContent = "ID,Method,URL,Original Length,Unauth Length,Unauth Status" if hasattr(self._extender, 'userTab') and self._extender.userTab: - for user_id, user_data in self._extender.userTab.user_tabs.items(): - user_name = user_data['user_name'] - csvContent += "\t{} Length\t{} Status".format(user_name, user_name) + for user_id in sorted(self._extender.userTab.user_tabs.keys()): + user_name = self._extender.userTab.user_tabs[user_id]['user_name'] + csvContent += ",{} Length,{} Status".format(user_name, user_name) csvContent += "\n" @@ -413,19 +436,24 @@ def exportToCSV(self): if user_data: user_statuses.append(user_data['enforcementStatus']) - lineData = "\t%s\t%s\t%s\t%s\n" % (logEntry._method, logEntry._url, + lineData = ",{},{},{},{}".format(logEntry._method, logEntry._url, logEntry._enfocementStatusUnauthorized, - "\t".join(user_statuses)) + ",".join(user_statuses)) if lineData in unique_CSV_lines: continue else: unique_CSV_lines.add(lineData) + if not self.shouldIncludeRow(logEntry, enforcementStatusFilter): + continue + orig_len = len(logEntry._originalrequestResponse.getResponse()) if logEntry._originalrequestResponse else 0 unauth_len = len(logEntry._unauthorizedRequestResponse.getResponse()) if logEntry._unauthorizedRequestResponse else 0 - csv_row = "%d\t%s\t%s\t%d\t%d\t%s" % ( - logEntry._id, logEntry._method, logEntry._url, orig_len, unauth_len, logEntry._enfocementStatusUnauthorized) + url_safe = '"{}"'.format(str(logEntry._url).replace('"', '""')) + + csv_row = '{},{},{},{},{},"{}"'.format( + logEntry._id, logEntry._method, url_safe, orig_len, unauth_len, logEntry._enfocementStatusUnauthorized) # User data if hasattr(self._extender, 'userTab') and self._extender.userTab: @@ -434,43 +462,12 @@ def exportToCSV(self): if user_data and user_data['requestResponse']: user_len = len(user_data['requestResponse'].getResponse()) user_status = user_data['enforcementStatus'] - csv_row += "\t%d\t%s" % (user_len, user_status) + csv_row += ',{},"{}"'.format(user_len, user_status) else: - csv_row += "\t0\tN/A" + csv_row += ',0,"N/A"' csv_row += "\n" - - should_include = False - if enforcementStatusFilter == "All Statuses": - should_include = True - elif enforcementStatusFilter == "As table filter": - if ((self._extender.showAuthBypassUnauthenticated.isSelected() and self.BYPASSSED_STR == logEntry._enfocementStatusUnauthorized) or - (self._extender.showAuthPotentiallyEnforcedUnauthenticated.isSelected() and self.IS_ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or - (self._extender.showAuthEnforcedUnauthenticated.isSelected() and self.ENFORCED_STR == logEntry._enfocementStatusUnauthorized) or - (self._extender.showDisabledUnauthenticated.isSelected() and "Disabled" == logEntry._enfocementStatusUnauthorized)): - should_include = True - - for user_id in logEntry.get_all_users(): - user_data = logEntry.get_user_enforcement(user_id) - if user_data: - user_status = user_data['enforcementStatus'] - if ((self._extender.showAuthBypassModified.isSelected() and self.BYPASSSED_STR == user_status) or - (self._extender.showAuthPotentiallyEnforcedModified.isSelected() and self.IS_ENFORCED_STR == user_status) or - (self._extender.showAuthEnforcedModified.isSelected() and self.ENFORCED_STR == user_status)): - should_include = True - break - else: - if enforcementStatusFilter == logEntry._enfocementStatusUnauthorized: - should_include = True - else: - for user_id in logEntry.get_all_users(): - user_data = logEntry.get_user_enforcement(user_id) - if user_data and enforcementStatusFilter == user_data['enforcementStatus']: - should_include = True - break - - if should_include: - csvContent += csv_row + csvContent += csv_row f = open(fileToSave.getAbsolutePath(), 'w') f.writelines(csvContent) diff --git a/gui/save_restore.py b/gui/save_restore.py index 61c8aa2..bb99c52 100644 --- a/gui/save_restore.py +++ b/gui/save_restore.py @@ -32,13 +32,9 @@ def __init__(self, extender): "interceptRequestsfromRepeater", "doUnauthorizedRequest", "replaceQueryParam", - "showAuthBypassModified", - "showAuthPotentiallyEnforcedModified", - "showAuthEnforcedModified", - "showAuthBypassUnauthenticated", - "showAuthPotentiallyEnforcedUnauthenticated", - "showAuthEnforcedUnauthenticated", - "showDisabledUnauthenticated" + "showBypassed", + "showIsEnforced", + "showEnforced" ] def saveState(self): @@ -74,15 +70,18 @@ def saveState(self): tempRow = ["UserConfigs", base64.b64encode(json.dumps(user_configs))] csvwriter.writerow(tempRow) - for EDFilterUnauth in self._extender.EDModelUnauth.toArray(): - tempRow = ["EDFilterUnauth", base64.b64encode(EDFilterUnauth)] - csvwriter.writerow(tempRow) + if hasattr(self._extender, 'EDModelUnauth'): + for EDFilterUnauth in self._extender.EDModelUnauth.toArray(): + tempRow = ["EDFilterUnauth", base64.b64encode(EDFilterUnauth)] + csvwriter.writerow(tempRow) - for IFFilter in self._extender.IFModel.toArray(): - tempRow = ["IFFilter", base64.b64encode(IFFilter)] - csvwriter.writerow(tempRow) + if hasattr(self._extender, 'IFModel'): + for IFFilter in self._extender.IFModel.toArray(): + tempRow = ["IFFilter", base64.b64encode(IFFilter)] + csvwriter.writerow(tempRow) d = dict((c, getattr(self._extender, c).isSelected()) for c in self._checkBoxes) + tempRow = ["CheckBoxes", json.dumps(d)] csvwriter.writerow(tempRow) @@ -144,6 +143,9 @@ def restoreState(self): if userSelection == JFileChooser.APPROVE_OPTION: importFile = fileChooser.getSelectedFile() + + self._extender._log.clear() + self._extender.tableModel.fireTableDataChanged() with open(importFile.getAbsolutePath(), 'r') as csvfile: @@ -186,6 +188,16 @@ def restoreState(self): user_data['mr_instance'].MRModel.addElement(key) continue + if row[0] == "EDFilterUnauth": + if hasattr(self._extender, 'EDModelUnauth'): + self._extender.EDModelUnauth.addElement(base64.b64decode(row[1])) + continue + + if row[0] == "IFFilter": + if hasattr(self._extender, 'IFModel'): + self._extender.IFModel.addElement(base64.b64decode(row[1])) + continue + if row[0] == "CheckBoxes": d = json.loads(row[1]) for k in d: @@ -201,6 +213,7 @@ def restoreState(self): continue # Request/response list + if len(row) >= 12: tempOriginalRequestResponseHost = row[0] tempOriginalRequestResponsePort = row[1] @@ -230,9 +243,6 @@ def restoreState(self): tempEnforcementStatusUnauthorized = row[10] - self._extender._lock.acquire() - row_index = self._extender._log.size() - method = self._extender._helpers.analyzeRequest(tempOriginalRequestResponse).getMethod() original_url = self._extender._helpers.analyzeRequest(tempOriginalRequestResponse).getUrl() @@ -253,6 +263,6 @@ def restoreState(self): logEntry.add_user_enforcement(user_id, savedUserRequestResponse, user_data['status']) self._extender._log.add(logEntry) - SwingUtilities.invokeLater(UpdateTableEDT(self._extender, "insert", row_index, row_index)) self._extender.currentRequestNumber = self._extender.currentRequestNumber + 1 - self._extender._lock.release() \ No newline at end of file + + self._extender.tableModel.fireTableDataChanged() \ No newline at end of file From 94c073963b4202ae3e118a20f1add661f026fe2f Mon Sep 17 00:00:00 2001 From: tvroi Date: Thu, 24 Jul 2025 14:48:18 +0700 Subject: [PATCH 11/15] fix: html issue --- gui/export.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/gui/export.py b/gui/export.py index b7e6bcd..e02ef5f 100644 --- a/gui/export.py +++ b/gui/export.py @@ -251,7 +251,6 @@ def shouldIncludeRow(self, logEntry, enforcementStatusFilter): if enforcementStatusFilter == "All Statuses": should_include = True elif enforcementStatusFilter == "As table filter": - # Check if the new filter system allows this status if hasattr(self._extender, 'showBypassed') and hasattr(self._extender, 'showIsEnforced') and hasattr(self._extender, 'showEnforced'): # Check unauthenticated status unauth_status = logEntry._enfocementStatusUnauthorized @@ -294,8 +293,7 @@ def exportToHTML(self): fileToSave = fileChooser.getSelectedFile() enforcementStatusFilter = self.exportES.getSelectedItem() - - # Build header with user columns + header_html = "IDMethodURLOriginal lengthUnauth lengthUnauth Status" if hasattr(self._extender, 'userTab') and self._extender.userTab: @@ -305,7 +303,6 @@ def exportToHTML(self): header_html += "" - # Use original HTML styling from document 2 htmlContent = """Autorize Report by Barak Tawily