ActionListener 没有看到动态添加的 ArrayList 元素

问题描述 投票:0回答:1

我正在开发一个用 Java 编写的 Burp Suite 插件(我的第一个)。不会撒谎,自从我完成任何 Java 工作以来,这是一个热门时刻,所以我认为对这个问题存在根本性的误解。此外,代码目前非常混乱,因为我一直在尝试这个和尝试那个。我所做的一切都是基于这样一个前提:Java 在通过基于此处提出的问题和答案的方法传递变量时,本质上传递的是指针的等效项:Java 是“按引用传递”还是“按值传递” ?.

此插件的基本前提是,它将搜索文本的请求或响应,并允许您替换为预定义值、基于正则表达式的搜索,或动态发送请求并搜索该响应。这个插件的第一步只是一个规则集,一切都运行得很好。我一直在尝试更新插件以允许任意数量的规则并通过 ArrayList 处理规则集。这就是问题开始的地方。我已经包含了相关的代码片段,但我可能错过了一些试图将其精简为可读部分的地方。 BurpPlugin 类是 BurpSuite 的入口点。 MainWindow 包含我的 JTabbedPane,基本上是中央站。

public class BurpPlugin implements BurpExtension {
    private MontoyaApi api;

    @Override
    public void initialize(MontoyaApi api)
    {
        this.api = api;
        api.extension().setName("Burp Plugin");

        // list of tabs
        ArrayList<Tab> tabs = new ArrayList<>();

        // will need to create a new main tab that will have the tabbed top with a button for new tab
        // the rest of the window will contain replacer tabs
        Tab aTab = new Tab(this.api);

        tabs.add(firstTab);

        MainWindow mainWindow = new MainWindow(this.api, tabs);

        this.api.userInterface().registerSuiteTab("Burp Plugin", mainWindow.getTabUI());
        this.api.http().registerHttpHandler(new MyHttpHandler(this.api, tabs)); // <--- Tabs here does not get updated arraylist, only the first tab created during init.
    }
}

public class MainWindow {

    private final MontoyaApi api;
    private final Logging logging;
    private ArrayList<Tab> tabs;

    ...

    public MainWindow(MontoyaApi api, ArrayList<Tab> allTabs) {
        this.api = api;
        this.logging = api.logging();
        this.tabs = allTabs;
        logging.logToOutput("mw init: " + String.valueOf(allTabs.size()));
    }

    public Component getTabUI()
    {
        ...

        for(int i = 0; i < this.tabs.size(); i++) {
            String title = Integer.toString(i+1);
            tabPanel.addTab(title, this.tabs.get(i).getTabUI());
            this.createCloseButton(this, tabPanel, i);
        }

        this.createAddButton(this, tabPanel);

        return tabPanel;
    }

    private void createAddButton(MainWindow main, JTabbedPane tabPanel) {
        
    ...

        ActionListener listener = e -> {
            Tab newTab = new Tab(main.api);
            main.tabs.add(newTab);
            logging.logToOutput("cab: " + String.valueOf(main.tabs.size())); // <--- This counts as expected
            String title = String.valueOf(main.tabs.size());
            tabPanel.insertTab(title, null, newTab.getTabUI(), null, tabPanel.getTabCount()-1);
            // logging.logToOutput("getTabCount-1: " + String.valueOf(tabPanel.getTabCount()-1));
            // logging.logToOutput("tabs.size: " + String.valueOf(main.tabs.size()));
            main.createCloseButton(main, tabPanel, main.tabs.size()-POSTTABS);
        };

        addTab.addActionListener (listener);
        tabPanel.addTab ("addbutton", null);
        tabPanel.setTabComponentAt (tabPanel.getTabCount() - 1, pnlTab);
    }

    private JPanel getHelpSettingsPaneUI() {
        GridBagConstraints tpc = new GridBagConstraints();

        JPanel toolPanel = new JPanel();
        toolPanel.setLayout(new GridBagLayout());
        toolPanel.setBorder(BorderFactory.createTitledBorder(SETTINGS_PANE_TITLE));

        ...

        // add btnExportCfg
        btnExportCfg.addActionListener(new ExportActionListener(this.api, this));
        tpc.fill = GridBagConstraints.HORIZONTAL;
        tpc.gridwidth = 2;
        tpc.gridx = 0;
        tpc.gridy += 1;
        tpc.insets = new Insets(0, 10, 10, 10);
        toolPanel.add(btnExportCfg, tpc);

        return toolPanel;
    }
}

public class ExportActionListener implements ActionListener {

    private MontoyaApi api;
    private ArrayList<ReplacerTab> tabs;
    private MainConfig config;
    public ExportActionListener(MontoyaApi api, MainWindow main) {

        // this.tabs = tabs;
        this.api = api;
    // this.config = cfg;
        Logging logging = api.logging();

        logging.logToOutput("eal:"+String.valueOf(main.getReplacerTabs().size())); <---- This is always 1 from when it is first initialized
    }

    public void actionPerformed(ActionEvent e) {
        this.saveConfiguration(); // <--- This converts most of the items from the main window into a json config for export.
    }
}

我尝试过传递各种类,例如 MainWindow 或只是选项卡或设置静态类变量,但即使这样似乎也会遭受相同的结果,因为在导出或拦截期间仅存在 init 期间的第一个添加的规则。我不确定这是否是我对 Java 缺乏了解,因为我对它不起作用或者在 Burp 中作为插件使用是否是一个因素或两者的组合并不感到惊讶。

现在,因为我理解 Java 本质上是传递指针,所以我的期望是可以在入口点创建 ArrayList,然后在整个应用程序中传递指针。当前的问题是当使用 JTabbedPane 使用 MainWindow 中 createAddButton 方法中的内联 ActionListener 创建更多规则选项卡时。选项卡已创建并完美编号,关闭按钮将关闭相应的选项卡,并且 UI 通常按预期工作。但是,当尝试使用 MyHttpHandler 或 btnExportCfg 的 ActionListener 时,动态添加的规则选项卡均不可用,并且选项卡仅包含插件初始化期间添加的第一个选项卡。

已更新可建造

构建.gradle

plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compileOnly 'net.portswigger.burp.extensions:montoya-api:latest.release'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2'
}

test {
    useJUnitPlatform()
}

jar {
    from {
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

测试规则.java

package org.example;

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import java.util.ArrayList;

public class TestRules implements BurpExtension {

    private MontoyaApi api;

    public void initialize(MontoyaApi api)
    {
        this.api = api;
        api.extension().setName("Test Rules");

        // list of tabs
        ArrayList<Tab> tabs = new ArrayList<>();

        // will need to create a new main tab that will have the tabbed top with a button for new tab
        // the rest of the window will contain replacer tabs
        Tab firstTab = new Tab(this.api);

        tabs.add(firstTab);

        MainWindow mainWindow = new MainWindow(this.api, tabs);

        this.api.userInterface().registerSuiteTab("Test Rules", mainWindow.getTabUI());
        this.api.http().registerHttpHandler(new MyHttpHandler(this.api, tabs));
    }
}

主窗口.java

package org.example;

import burp.api.montoya.MontoyaApi;
import burp.api.montoya.logging.Logging;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

public class MainWindow {

    private final MontoyaApi api;
    private final Logging logging;
    private ArrayList<Tab> tabs;

    private final int PRETABS = 1; // num of tabs before first replacer
    private final int POSTTABS = 1; //num of tabs after last replacer

    //matchPane Controls

    private JButton btnImportCfg = new JButton("Import Config");
    private JButton btnExportCfg = new JButton("Export Config");

    public MainWindow(MontoyaApi api, ArrayList<Tab> allTabs) {
        this.api = api;
        this.logging = api.logging();
        this.tabs = allTabs;
        logging.logToOutput("mw init: " + String.valueOf(allTabs.size()));
    }

    public ArrayList<Tab> getTabs() { return this.tabs; }

    public Component getTabUI()
    {
        MainWindow that = this;

        JTabbedPane tabPanel = new JTabbedPane();

        tabPanel.addTab("help", this.getSettingsTabUI());

        for(int i = 0; i < this.tabs.size(); i++) {
            String title = Integer.toString(i+1);
            tabPanel.addTab(title, this.tabs.get(i).getTabUI());
            this.createCloseButton(this, tabPanel, i);
        }

        this.createAddButton(this, tabPanel);

        return tabPanel;
    }

    private void createCloseButton(MainWindow main, JTabbedPane tabPanel, int i) {
        String title = Integer.toString(i+1);
        JPanel pnlTab = new JPanel(new FlowLayout(FlowLayout.CENTER, 2, 2));
        pnlTab.setOpaque(false);
        JLabel lblTitle = new JLabel(title);
        lblTitle.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
        JButton btnClose = new JButton("x");
        btnClose.setBorder(null);
        btnClose.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        btnClose.setContentAreaFilled(false);
//            btnClose.setBorderPainted(false);
//            btnClose.setMargin(new Insets(2,2,2,2));

        ActionListener listener = e -> {
            // logging.logToOutput("remove i: " + String.valueOf(i));
            if (i >= 0) {
                main.tabs.remove(i);
                tabPanel.removeTabAt(i+PRETABS);
                for(int j = i; j < main.tabs.size(); j++) {
                    this.createCloseButton(main, tabPanel, j);
                }
            }
        };

        btnClose.addActionListener(listener);

        pnlTab.add(lblTitle);
        pnlTab.add(btnClose);

        tabPanel.setTabComponentAt(i+1, pnlTab);
    }

    private void createAddButton(MainWindow main, JTabbedPane tabPanel) {
        FlowLayout f = new FlowLayout(FlowLayout.CENTER, 5, 0);

        // Make a small JPanel with the layout and make it non-opaque
        JPanel pnlTab = new JPanel (f);
        pnlTab.setOpaque (false);
        // Create a JButton for adding the tabs
        JButton addTab = new JButton ("+");
        addTab.setOpaque (false); //
        addTab.setBorder (null);
        addTab.setContentAreaFilled (false);
        addTab.setFocusPainted (false);
        addTab.setFocusable (false);
        pnlTab.add (addTab);

        ActionListener listener = e -> {
            Tab newTab = new Tab(main.api);
            main.tabs.add(newTab);
            logging.logToOutput("cab: " + String.valueOf(main.tabs.size()));
            String title = String.valueOf(main.tabs.size());
            tabPanel.insertTab(title, null, newTab.getTabUI(), null, tabPanel.getTabCount()-1);
            // logging.logToOutput("getTabCount-1: " + String.valueOf(tabPanel.getTabCount()-1));
            // logging.logToOutput("tabs.size: " + String.valueOf(main.tabs.size()));
            main.createCloseButton(main, tabPanel, main.tabs.size()-POSTTABS);
        };

        addTab.addActionListener (listener);
        tabPanel.addTab ("addbutton", null);
        tabPanel.setTabComponentAt (tabPanel.getTabCount() - 1, pnlTab);
    }

    private JPanel getSettingsTabUI() {
        GridBagConstraints tpc = new GridBagConstraints();

        JPanel toolPanel = new JPanel();
        toolPanel.setLayout(new GridBagLayout());

        // add btnImportCfg
        // btnImportCfg.addActionListener(new ImportActionListener(this.api, new MainConfig(this.api, this)));
        tpc.fill = GridBagConstraints.HORIZONTAL;
        tpc.weightx = 1.0;
        tpc.gridwidth = 2;
        tpc.gridx = 0;
        tpc.gridy += 1;
        tpc.insets = new Insets(0, 10, 10, 10);
        toolPanel.add(btnImportCfg, tpc);

        // add btnExportCfg
        btnExportCfg.addActionListener(new ExportActionListener(this.api, this));
        tpc.fill = GridBagConstraints.HORIZONTAL;
        tpc.gridwidth = 2;
        tpc.gridx = 0;
        tpc.gridy += 1;
        tpc.insets = new Insets(0, 10, 10, 10);
        toolPanel.add(btnExportCfg, tpc);

        return toolPanel;
    }
}

Tab.java

package org.example;

import burp.api.montoya.MontoyaApi;

import javax.swing.*;

import java.awt.*;

public class Tab {
    private MontoyaApi api;

    //matchPane Controls
    private JCheckBox chkEnabled= new JCheckBox("Enabled");

    public Tab(MontoyaApi api)
    {
        this.api = api;

    }

    public JPanel getTabUI()
    {
        JPanel matchPanel = new JPanel();
        matchPanel.setLayout(new GridBagLayout());
        matchPanel.setBorder(BorderFactory.createTitledBorder("Stuff"));

        GridBagConstraints tpc = new GridBagConstraints();

         //add chkEnabled
         tpc.fill = GridBagConstraints.HORIZONTAL;
         tpc.weightx = 1.0;
         tpc.gridwidth = 2;
         tpc.gridx = 0;
         tpc.gridy = 0;
         tpc.insets = new Insets(0,10,20,10);
         matchPanel.add(chkEnabled, tpc);



        return matchPanel;
    }
}

MyHttpHandler.java

package org.example;

import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.Annotations;
import burp.api.montoya.http.handler.*;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.logging.Logging;
import java.util.ArrayList;

public class MyHttpHandler implements HttpHandler
{
    private final MontoyaApi api;
    private final Logging logging;
    private final ArrayList<Tab> tabs;

    public MyHttpHandler(MontoyaApi api, ArrayList<Tab> allTabs)
    {
        this.api = api;
        this.logging = api.logging();
        this.tabs = allTabs;
    }

    @Override
    public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent)
    {

        HttpRequest modifiedRequest = requestToBeSent;
        Annotations annotations = requestToBeSent.annotations();

        boolean was_modified = false;

        // for tab in this.tabs
        logging.logToOutput("handleRequest size:" + String.valueOf(this.tabs.size()));

        if (was_modified) {
            annotations = annotations.withNotes("Request was modified with Super Replacer");
        }

        return RequestToBeSentAction.continueWith(modifiedRequest, annotations);
    }

    @Override
    public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived responseReceived)
    {
        Annotations annotations = responseReceived.annotations();
        String bodyAsStr = responseReceived.bodyToString();

        boolean was_modified = false;

        logging.logToOutput("handleResponse size:" + String.valueOf(this.tabs.size()));

        if (was_modified) {
            annotations = annotations.withNotes("Request was modified with Super Replacer");
        }

        return ResponseReceivedAction.continueWith(responseReceived.withBody(bodyAsStr), annotations);
    }
}

导出ActionListener.java

package org.example;

import javax.swing.*;
import java.awt.event.*;
import java.io.FileWriter;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.ArrayList;

import burp.api.montoya.MontoyaApi;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.core.JsonProcessingException;
import burp.api.montoya.logging.Logging;

public class ExportActionListener implements ActionListener {

    private MontoyaApi api;
    private ArrayList<Tab> tabs;
    Logging logging;
    public ExportActionListener(MontoyaApi api, MainWindow main) {

        this.tabs = main.getTabs();
        this.api = api;
        this.logging = api.logging();

        logging.logToOutput("eal:"+String.valueOf(main.getTabs().size()));
    }

    public void actionPerformed(ActionEvent e) {
        logging.logToOutput("eal performed:"+String.valueOf(this.tabs.size()));
        this.saveConfiguration();
    }

    private Boolean saveConfiguration()
    {
        return true;
    }
}
java swing burp
1个回答
0
投票

因此,在发布(工作)最小构建之后,喝了一杯好喝的威士忌,并清理和构建了该项目几次。

你瞧,它也起作用了。我不知道它为什么坏了或者是什么修复了它。如果我发现了,我会更新。

© www.soinside.com 2019 - 2024. All rights reserved.