2024-08-23 22:03:31 +08:00
package hae.component ;
2024-05-06 12:56:56 +08:00
import burp.api.montoya.MontoyaApi ;
2024-11-16 18:06:49 +08:00
import burp.api.montoya.core.Registration ;
import hae.component.board.message.MessageTableModel ;
2024-05-06 12:56:56 +08:00
import hae.component.rule.Rules ;
2024-11-16 18:06:49 +08:00
import hae.instances.http.HttpMessageActiveHandler ;
import hae.instances.http.HttpMessagePassiveHandler ;
2024-05-24 15:00:49 +08:00
import hae.utils.ConfigLoader ;
import hae.utils.UIEnhancer ;
2024-05-06 12:56:56 +08:00
import javax.swing.* ;
2024-05-23 12:00:13 +08:00
import javax.swing.border.EmptyBorder ;
2024-07-23 09:21:30 +08:00
import javax.swing.border.TitledBorder ;
import javax.swing.event.DocumentEvent ;
import javax.swing.event.DocumentListener ;
2024-05-23 12:00:13 +08:00
import javax.swing.event.TableModelEvent ;
import javax.swing.event.TableModelListener ;
import javax.swing.table.DefaultTableModel ;
2024-05-06 12:56:56 +08:00
import java.awt.* ;
2024-05-23 12:00:13 +08:00
import java.awt.datatransfer.Clipboard ;
import java.awt.datatransfer.DataFlavor ;
2024-11-16 18:06:49 +08:00
import java.awt.event.* ;
2024-05-23 12:00:13 +08:00
import java.util.List ;
2024-07-23 09:21:30 +08:00
import java.util.* ;
2024-05-06 12:56:56 +08:00
public class Config extends JPanel {
private final MontoyaApi api ;
private final ConfigLoader configLoader ;
2024-11-16 18:06:49 +08:00
private final MessageTableModel messageTableModel ;
2024-05-06 12:56:56 +08:00
private final Rules rules ;
2024-11-16 18:06:49 +08:00
private Registration activeHandler ;
private Registration passiveHandler ;
public Config ( MontoyaApi api , ConfigLoader configLoader , MessageTableModel messageTableModel , Rules rules ) {
2024-05-06 12:56:56 +08:00
this . api = api ;
this . configLoader = configLoader ;
2024-11-16 18:06:49 +08:00
this . messageTableModel = messageTableModel ;
2024-05-06 12:56:56 +08:00
this . rules = rules ;
2024-11-16 18:06:49 +08:00
this . activeHandler = api . http ( ) . registerHttpHandler ( new HttpMessageActiveHandler ( api , configLoader , messageTableModel ) ) ;
2025-01-08 13:49:12 +08:00
this . passiveHandler = api . scanner ( ) . registerScanCheck ( new HttpMessagePassiveHandler ( api , configLoader , messageTableModel ) ) ;
2024-11-16 18:06:49 +08:00
2024-05-06 12:56:56 +08:00
initComponents ( ) ;
}
private void initComponents ( ) {
2024-05-23 12:00:13 +08:00
setLayout ( new BorderLayout ( ) ) ;
2024-08-12 10:34:26 +08:00
GridBagConstraints constraints = new GridBagConstraints ( ) ;
constraints . weightx = 1 . 0 ;
constraints . fill = GridBagConstraints . HORIZONTAL ;
2024-05-23 12:00:13 +08:00
JPanel ruleInfoPanel = new JPanel ( new GridBagLayout ( ) ) ;
2024-05-24 15:00:49 +08:00
ruleInfoPanel . setBorder ( new EmptyBorder ( 10 , 15 , 5 , 15 ) ) ;
2024-05-06 12:56:56 +08:00
2024-05-23 12:00:13 +08:00
JLabel ruleLabel = new JLabel ( " Path: " ) ;
JTextField pathTextField = new JTextField ( ) ;
pathTextField . setEditable ( false ) ;
pathTextField . setText ( configLoader . getRulesFilePath ( ) ) ;
JButton reloadButton = new JButton ( " Reload " ) ;
2024-12-21 15:34:45 +08:00
JButton reinitButton = new JButton ( " Reinit " ) ;
2024-05-23 12:00:13 +08:00
ruleInfoPanel . add ( ruleLabel ) ;
ruleInfoPanel . add ( pathTextField , constraints ) ;
ruleInfoPanel . add ( Box . createHorizontalStrut ( 5 ) ) ;
2024-12-21 15:34:45 +08:00
ruleInfoPanel . add ( reinitButton ) ;
2024-05-23 12:00:13 +08:00
ruleInfoPanel . add ( Box . createHorizontalStrut ( 5 ) ) ;
2024-12-21 15:34:45 +08:00
ruleInfoPanel . add ( reloadButton ) ;
2024-05-06 12:56:56 +08:00
reloadButton . addActionListener ( this : : reloadActionPerformed ) ;
2024-12-21 15:34:45 +08:00
reinitButton . addActionListener ( this : : reinitActionPerformed ) ;
2024-05-23 12:00:13 +08:00
2024-07-23 09:21:30 +08:00
constraints . gridx = 1 ;
JTabbedPane configTabbedPanel = new JTabbedPane ( ) ;
2024-11-16 18:06:49 +08:00
String [ ] settingMode = new String [ ] { " Exclude suffix " , " Block host " , " Exclude status " } ;
2024-12-21 15:34:45 +08:00
JPanel settingPanel = createConfigTablePanel ( settingMode ) ;
2024-11-16 18:06:49 +08:00
JPanel northPanel = new JPanel ( new BorderLayout ( ) ) ;
JPanel modePanel = getModePanel ( ) ;
JScrollPane modeScrollPane = new JScrollPane ( modePanel ) ;
modeScrollPane . setBorder ( new TitledBorder ( " Mode " ) ) ;
JTextField limitPanel = getLimitPanel ( ) ;
JScrollPane limitScrollPane = new JScrollPane ( limitPanel ) ;
limitScrollPane . setBorder ( new TitledBorder ( " Limit Size (MB) " ) ) ;
JSplitPane northTopPanel = new JSplitPane ( JSplitPane . HORIZONTAL_SPLIT , modeScrollPane , limitScrollPane ) ;
northTopPanel . addComponentListener ( new ComponentAdapter ( ) {
@Override
public void componentResized ( ComponentEvent e ) {
northTopPanel . setDividerLocation ( 0 . 5 ) ;
}
} ) ;
2024-07-23 09:21:30 +08:00
JPanel scopePanel = getScopePanel ( ) ;
JScrollPane scopeScrollPane = new JScrollPane ( scopePanel ) ;
scopeScrollPane . setBorder ( new TitledBorder ( " Scope " ) ) ;
2024-11-16 18:06:49 +08:00
northPanel . add ( scopeScrollPane , BorderLayout . SOUTH ) ;
northPanel . add ( northTopPanel , BorderLayout . NORTH ) ;
settingPanel . add ( northPanel , BorderLayout . NORTH ) ;
2024-07-23 09:21:30 +08:00
configTabbedPanel . add ( " Setting " , settingPanel ) ;
add ( ruleInfoPanel , BorderLayout . NORTH ) ;
add ( configTabbedPanel , BorderLayout . CENTER ) ;
}
private JPanel getScopePanel ( ) {
JPanel scopePanel = new JPanel ( ) ;
scopePanel . setLayout ( new BoxLayout ( scopePanel , BoxLayout . X_AXIS ) ) ;
2024-11-16 18:06:49 +08:00
scopePanel . setBorder ( new EmptyBorder ( 3 , 0 , 6 , 0 ) ) ;
2024-07-23 09:21:30 +08:00
String [ ] scopeInit = hae . Config . scopeOptions . split ( " \\ | " ) ;
String [ ] scopeMode = configLoader . getScope ( ) . split ( " \\ | " ) ;
for ( String scope : scopeInit ) {
JCheckBox checkBox = new JCheckBox ( scope ) ;
scopePanel . add ( checkBox ) ;
2024-11-16 18:06:49 +08:00
checkBox . addActionListener ( e - > updateScope ( checkBox ) ) ;
2024-07-23 09:21:30 +08:00
for ( String mode : scopeMode ) {
if ( scope . equals ( mode ) ) {
checkBox . setSelected ( true ) ;
}
}
2024-11-16 18:06:49 +08:00
updateScope ( checkBox ) ;
2024-07-23 09:21:30 +08:00
}
2024-11-16 18:06:49 +08:00
2024-07-23 09:21:30 +08:00
return scopePanel ;
}
2024-11-16 18:06:49 +08:00
private JPanel getModePanel ( ) {
JPanel modePanel = new JPanel ( ) ;
modePanel . setLayout ( new BoxLayout ( modePanel , BoxLayout . X_AXIS ) ) ;
JCheckBox checkBox = new JCheckBox ( " Enable active http message handler " ) ;
2025-01-08 13:49:12 +08:00
checkBox . setEnabled ( hae . Config . proVersionStatus ) ;
2024-11-16 18:06:49 +08:00
modePanel . add ( checkBox ) ;
checkBox . addActionListener ( e - > updateModeStatus ( checkBox ) ) ;
checkBox . setSelected ( configLoader . getMode ( ) ) ;
updateModeStatus ( checkBox ) ;
return modePanel ;
}
private JTextField getLimitPanel ( ) {
JTextField limitSizeTextField = new JTextField ( ) ;
limitSizeTextField . getDocument ( ) . addDocumentListener ( new DocumentListener ( ) {
@Override
public void insertUpdate ( DocumentEvent e ) {
onTextChange ( ) ;
}
@Override
public void removeUpdate ( DocumentEvent e ) {
onTextChange ( ) ;
}
@Override
public void changedUpdate ( DocumentEvent e ) {
onTextChange ( ) ;
}
private void onTextChange ( ) {
String limitSizeText = limitSizeTextField . getText ( ) ;
configLoader . setLimitSize ( limitSizeText ) ;
}
} ) ;
limitSizeTextField . setText ( configLoader . getLimitSize ( ) ) ;
return limitSizeTextField ;
}
2024-07-23 09:21:30 +08:00
private TableModelListener craeteSettingTableModelListener ( JComboBox < String > setTypeComboBox , DefaultTableModel model ) {
return new TableModelListener ( ) {
@Override
public void tableChanged ( TableModelEvent e ) {
String selected = ( String ) setTypeComboBox . getSelectedItem ( ) ;
String values = getFirstColumnDataAsString ( model ) ;
if ( selected . equals ( " Exclude suffix " ) ) {
if ( ! values . equals ( configLoader . getExcludeSuffix ( ) ) & & ! values . isEmpty ( ) ) {
configLoader . setExcludeSuffix ( values ) ;
}
}
if ( selected . equals ( " Block host " ) ) {
if ( ! values . equals ( configLoader . getBlockHost ( ) ) & & ! values . isEmpty ( ) ) {
configLoader . setBlockHost ( values ) ;
}
}
2024-08-12 10:34:26 +08:00
if ( selected . equals ( " Exclude status " ) ) {
if ( ! values . equals ( configLoader . getExcludeStatus ( ) ) & & ! values . isEmpty ( ) ) {
configLoader . setExcludeStatus ( values ) ;
}
}
2024-09-19 17:08:46 +08:00
2024-07-23 09:21:30 +08:00
}
} ;
}
private ActionListener createSettingActionListener ( JComboBox < String > setTypeComboBox , DefaultTableModel model ) {
return new ActionListener ( ) {
@Override
public void actionPerformed ( ActionEvent e ) {
String selected = ( String ) setTypeComboBox . getSelectedItem ( ) ;
model . setRowCount ( 0 ) ;
if ( selected . equals ( " Exclude suffix " ) ) {
addDataToTable ( configLoader . getExcludeSuffix ( ) . replaceAll ( " \\ | " , " \ r \ n " ) , model ) ;
}
if ( selected . equals ( " Block host " ) ) {
addDataToTable ( configLoader . getBlockHost ( ) . replaceAll ( " \\ | " , " \ r \ n " ) , model ) ;
}
2024-08-12 10:34:26 +08:00
if ( selected . equals ( " Exclude status " ) ) {
addDataToTable ( configLoader . getExcludeStatus ( ) . replaceAll ( " \\ | " , " \ r \ n " ) , model ) ;
}
2024-07-23 09:21:30 +08:00
}
} ;
}
2024-12-21 15:34:45 +08:00
private JPanel createConfigTablePanel ( String [ ] mode ) {
2024-08-12 10:34:26 +08:00
GridBagConstraints constraints = new GridBagConstraints ( ) ;
constraints . weightx = 1 . 0 ;
constraints . fill = GridBagConstraints . HORIZONTAL ;
2024-05-23 12:00:13 +08:00
JPanel settingPanel = new JPanel ( new BorderLayout ( ) ) ;
DefaultTableModel model = new DefaultTableModel ( ) ;
JTable table = new JTable ( model ) ;
model . addColumn ( " Value " ) ;
JScrollPane scrollPane = new JScrollPane ( table ) ;
JPanel buttonPanel = new JPanel ( ) ;
buttonPanel . setBorder ( new EmptyBorder ( 0 , 3 , 0 , 0 ) ) ;
GridBagLayout layout = new GridBagLayout ( ) ;
layout . rowHeights = new int [ ] { 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
layout . rowWeights = new double [ ] { 0 . 0 , 0 . 0 , 0 . 0 , 0 . 0 , 0 . 0 , 0 . 0 , Double . MIN_VALUE } ;
buttonPanel . setLayout ( layout ) ;
JPanel inputPanel = new JPanel ( new BorderLayout ( ) ) ;
JPanel inputPanelB = new JPanel ( new BorderLayout ( ) ) ;
inputPanelB . setBorder ( new EmptyBorder ( 0 , 0 , 3 , 0 ) ) ;
JButton addButton = new JButton ( " Add " ) ;
JButton removeButton = new JButton ( " Remove " ) ;
JButton pasteButton = new JButton ( " Paste " ) ;
JButton clearButton = new JButton ( " Clear " ) ;
JComboBox < String > setTypeComboBox = new JComboBox < > ( ) ;
setTypeComboBox . setModel ( new DefaultComboBoxModel < > ( mode ) ) ;
2024-12-21 15:34:45 +08:00
model . addTableModelListener ( craeteSettingTableModelListener ( setTypeComboBox , model ) ) ;
2024-11-16 18:06:49 +08:00
2024-12-21 15:34:45 +08:00
setTypeComboBox . addActionListener ( createSettingActionListener ( setTypeComboBox , model ) ) ;
2024-05-23 12:00:13 +08:00
2024-07-23 09:21:30 +08:00
setTypeComboBox . setSelectedItem ( mode [ 0 ] ) ;
2024-05-23 12:00:13 +08:00
constraints . insets = new Insets ( 0 , 0 , 3 , 0 ) ;
constraints . gridy = 0 ;
buttonPanel . add ( setTypeComboBox , constraints ) ;
constraints . gridy = 1 ;
buttonPanel . add ( addButton , constraints ) ;
constraints . gridy = 2 ;
buttonPanel . add ( removeButton , constraints ) ;
constraints . gridy = 3 ;
buttonPanel . add ( pasteButton , constraints ) ;
constraints . gridy = 4 ;
buttonPanel . add ( clearButton , constraints ) ;
2024-08-12 10:34:26 +08:00
JTextField addTextField = new JTextField ( ) ;
2024-12-21 15:34:45 +08:00
String defaultText = " Enter a new item " ;
2024-05-23 12:00:13 +08:00
UIEnhancer . setTextFieldPlaceholder ( addTextField , defaultText ) ;
inputPanelB . add ( addTextField , BorderLayout . CENTER ) ;
inputPanel . add ( scrollPane , BorderLayout . CENTER ) ;
inputPanel . add ( inputPanelB , BorderLayout . NORTH ) ;
settingPanel . add ( buttonPanel , BorderLayout . EAST ) ;
settingPanel . add ( inputPanel , BorderLayout . CENTER ) ;
2024-05-24 15:00:49 +08:00
2024-09-19 17:08:46 +08:00
addButton . addActionListener ( e - > addActionPerformed ( e , model , addTextField , setTypeComboBox . getSelectedItem ( ) . toString ( ) ) ) ;
2024-05-24 15:00:49 +08:00
addTextField . addKeyListener ( new KeyAdapter ( ) {
@Override
public void keyPressed ( KeyEvent e ) {
if ( e . getKeyCode ( ) = = KeyEvent . VK_ENTER ) {
2024-09-19 17:08:46 +08:00
addActionPerformed ( null , model , addTextField , setTypeComboBox . getSelectedItem ( ) . toString ( ) ) ;
2024-05-24 15:00:49 +08:00
}
2024-05-23 12:00:13 +08:00
}
} ) ;
pasteButton . addActionListener ( e - > {
Clipboard clipboard = Toolkit . getDefaultToolkit ( ) . getSystemClipboard ( ) ;
try {
String data = ( String ) clipboard . getData ( DataFlavor . stringFlavor ) ;
if ( data ! = null & & ! data . isEmpty ( ) ) {
addDataToTable ( data , model ) ;
}
} catch ( Exception ignored ) {
}
} ) ;
2024-05-06 12:56:56 +08:00
2024-05-23 12:00:13 +08:00
removeButton . addActionListener ( e - > {
int selectedRow = table . getSelectedRow ( ) ;
if ( selectedRow ! = - 1 ) {
model . removeRow ( selectedRow ) ;
}
} ) ;
clearButton . addActionListener ( e - > model . setRowCount ( 0 ) ) ;
JPanel settingMainPanel = new JPanel ( new BorderLayout ( ) ) ;
2024-07-23 09:21:30 +08:00
settingMainPanel . setBorder ( new EmptyBorder ( 5 , 15 , 10 , 15 ) ) ;
JScrollPane settingScroller = new JScrollPane ( settingPanel ) ;
2024-12-21 15:34:45 +08:00
settingScroller . setBorder ( new TitledBorder ( " Setting " ) ) ;
2024-07-23 09:21:30 +08:00
settingMainPanel . add ( settingScroller , BorderLayout . CENTER ) ;
2024-05-23 12:00:13 +08:00
2024-07-23 09:21:30 +08:00
return settingMainPanel ;
2024-05-23 12:00:13 +08:00
}
2024-05-24 15:00:49 +08:00
2024-05-23 12:00:13 +08:00
private String getFirstColumnDataAsString ( DefaultTableModel model ) {
StringBuilder firstColumnData = new StringBuilder ( ) ;
int numRows = model . getRowCount ( ) ;
for ( int row = 0 ; row < numRows ; row + + ) {
firstColumnData . append ( model . getValueAt ( row , 0 ) ) ;
if ( row < numRows - 1 ) {
firstColumnData . append ( " | " ) ;
}
}
return firstColumnData . toString ( ) ;
}
private void addDataToTable ( String data , DefaultTableModel model ) {
if ( ! data . isBlank ( ) ) {
String [ ] rows = data . split ( " \\ r? \\ n " ) ;
for ( String row : rows ) {
model . addRow ( new String [ ] { row } ) ;
}
deduplicateTableData ( model ) ;
}
}
private void deduplicateTableData ( DefaultTableModel model ) {
// 使用 Map 存储每一行的数据,用于去重
Set < List < Object > > rowData = new LinkedHashSet < > ( ) ;
int columnCount = model . getColumnCount ( ) ;
// 将每一行数据作为一个列表,添加到 Set 中
for ( int i = 0 ; i < model . getRowCount ( ) ; i + + ) {
List < Object > row = new ArrayList < > ( ) ;
for ( int j = 0 ; j < columnCount ; j + + ) {
row . add ( model . getValueAt ( i , j ) ) ;
}
rowData . add ( row ) ;
}
// 清除原始数据
model . setRowCount ( 0 ) ;
// 将去重后的数据添加回去
for ( List < Object > uniqueRow : rowData ) {
model . addRow ( uniqueRow . toArray ( ) ) ;
}
2024-05-06 12:56:56 +08:00
}
2024-11-16 18:06:49 +08:00
public void updateModeStatus ( JCheckBox checkBox ) {
boolean selected = checkBox . isSelected ( ) ;
configLoader . setMode ( selected ? " true " : " false " ) ;
if ( checkBox . isSelected ( ) ) {
2025-01-08 13:49:12 +08:00
if ( hae . Config . proVersionStatus & & passiveHandler . isRegistered ( ) ) {
2024-11-16 18:06:49 +08:00
passiveHandler . deregister ( ) ;
}
if ( ! activeHandler . isRegistered ( ) ) {
activeHandler = api . http ( ) . registerHttpHandler ( new HttpMessageActiveHandler ( api , configLoader , messageTableModel ) ) ;
}
} else {
2025-01-08 13:49:12 +08:00
if ( hae . Config . proVersionStatus & & ! passiveHandler . isRegistered ( ) ) {
2024-11-16 18:06:49 +08:00
passiveHandler = api . scanner ( ) . registerScanCheck ( new HttpMessagePassiveHandler ( api , configLoader , messageTableModel ) ) ;
}
if ( activeHandler . isRegistered ( ) ) {
activeHandler . deregister ( ) ;
}
}
}
2024-07-23 09:21:30 +08:00
public void updateScope ( JCheckBox checkBox ) {
String boxText = checkBox . getText ( ) ;
boolean selected = checkBox . isSelected ( ) ;
Set < String > HaEScope = new HashSet < > ( Arrays . asList ( configLoader . getScope ( ) . split ( " \\ | " ) ) ) ;
if ( selected ) {
HaEScope . add ( boxText ) ;
} else {
HaEScope . remove ( boxText ) ;
}
configLoader . setScope ( String . join ( " | " , HaEScope ) ) ;
}
2024-09-19 17:08:46 +08:00
private void addActionPerformed ( ActionEvent e , DefaultTableModel model , JTextField addTextField , String comboBoxSelected ) {
2024-05-24 15:00:49 +08:00
String addTextFieldText = addTextField . getText ( ) ;
2024-09-19 17:08:46 +08:00
if ( addTextField . getForeground ( ) . equals ( Color . BLACK ) ) {
2024-05-24 15:00:49 +08:00
addDataToTable ( addTextFieldText , model ) ;
2024-09-19 17:08:46 +08:00
addTextField . setText ( " " ) ;
addTextField . requestFocusInWindow ( ) ;
2024-05-24 15:00:49 +08:00
}
}
2024-05-06 12:56:56 +08:00
private void reloadActionPerformed ( ActionEvent e ) {
rules . reloadRuleGroup ( ) ;
}
2024-12-21 15:34:45 +08:00
private void reinitActionPerformed ( ActionEvent e ) {
int retCode = JOptionPane . showConfirmDialog ( this , " Do you want to reinitialize rules? This action will overwrite your existing rules. " , " Info " , JOptionPane . YES_NO_OPTION ) ;
if ( retCode = = JOptionPane . YES_OPTION ) {
boolean ret = configLoader . initRules ( ) ;
if ( ret ) {
rules . reloadRuleGroup ( ) ;
}
}
}
2024-05-06 12:56:56 +08:00
}