diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 76e7cc7..02f1964 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,7 +9,7 @@ name: Java CI with Gradle on: push: - branches: [ "release", "post_release" ] + branches: [ "release", "pre_release" ] pull_request: branches: [ "release" ] diff --git a/extension/build.gradle b/extension/build.gradle index ccf2b94..c379576 100644 --- a/extension/build.gradle +++ b/extension/build.gradle @@ -4,7 +4,7 @@ plugins { group 'com.synfron.reshaper.burp' archivesBaseName = 'reshaper-for-burp' -version '2.5.2' +version '2.5.3' targetCompatibility = '21' sourceCompatibility = '21' diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java index 9163352..7c09621 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java @@ -12,7 +12,7 @@ import synfron.reshaper.burp.core.settings.Workspace; import synfron.reshaper.burp.core.settings.Workspaces; import synfron.reshaper.burp.ui.components.workspaces.WorkspaceComponent; -import synfron.reshaper.burp.ui.components.workspaces.WorkspaceNameOptionPane; +import synfron.reshaper.burp.ui.components.workspaces.WorkspaceNameComponent; import synfron.reshaper.burp.ui.models.workspaces.WorkspaceNameModel; import synfron.reshaper.burp.ui.utils.ModalPrompter; @@ -224,8 +224,20 @@ private void onDisableWorkspaces(ActionEvent actionEvent) { private void onAddNewWorkspace(ActionEvent actionEvent) { Workspace workspace = new Workspace(UUID.randomUUID(), ""); - WorkspaceNameModel model = new WorkspaceNameModel(workspace, ignored -> Workspaces.get().add(workspace)); - ModalPrompter.open(model, ignored -> WorkspaceNameOptionPane.showDialog(model), true); + WorkspaceNameModel model = new WorkspaceNameModel(workspace); + + IEventListener modelPropertyChanged = args -> { + if (args.getName().equals("dismissed") && model.isDismissed() && !model.isInvalidated()) { + Workspaces.get().add(workspace); + } + }; + model.withListener(modelPropertyChanged); + + ModalPrompter.open(model, new ModalPrompter.FormPromptArgs<>( + "Workspace", + model, + new WorkspaceNameComponent(model) + ).dataBag(modelPropertyChanged)); } private void onDefaultWorkspace(ActionEvent actionEvent) { @@ -234,7 +246,12 @@ private void onDefaultWorkspace(ActionEvent actionEvent) { private void onRename(ActionEvent actionEvent) { WorkspaceNameModel model = new WorkspaceNameModel(workspace); - ModalPrompter.open(model, ignored -> WorkspaceNameOptionPane.showDialog(model), true); + + ModalPrompter.open(model, new ModalPrompter.FormPromptArgs<>( + "Workspace", + model, + new WorkspaceNameComponent(model) + )); } private void onDelete(ActionEvent actionEvent) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/TextPromptComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/TextPromptComponent.java new file mode 100644 index 0000000..5cb4dcc --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/TextPromptComponent.java @@ -0,0 +1,55 @@ +package synfron.reshaper.burp.ui.components; + +import synfron.reshaper.burp.ui.components.shared.IFormComponent; +import synfron.reshaper.burp.ui.models.TextPromptModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; + +public class TextPromptComponent extends JPanel implements IFormComponent { + + private final TextPromptModel model; + private JTextPane inputText; + + public TextPromptComponent(TextPromptModel model) { + setLayout(new BorderLayout()); + this.model = model; + initComponent(); + } + + private void initComponent() { + add(getBody(), BorderLayout.CENTER); + } + + private Component getBody() { + JPanel container = new JPanel(new BorderLayout()); + + JScrollPane scrollPane = new JScrollPane(); + scrollPane.setBorder(new EmptyBorder(10,0,0,0)); + + inputText = IFormComponent.addUndo(new JTextPane()); + inputText.setText(model.getText()); + + inputText.getDocument().addDocumentListener(new DocumentActionListener(this::onTextChanged)); + + scrollPane.setViewportView(inputText); + + container.add(new JLabel(model.getDescription()), BorderLayout.PAGE_START); + container.add(scrollPane, BorderLayout.CENTER); + + return container; + } + + private void onTextChanged(ActionEvent actionEvent) { + model.setText(inputText.getText()); + } + + @Override + @SuppressWarnings("unchecked") + public T getComponent() { + return (T) this; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java index 8a7ef31..8a5082e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java @@ -8,8 +8,8 @@ import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.settings.Workspace; import synfron.reshaper.burp.core.utils.Log; -import synfron.reshaper.burp.ui.components.IFormComponent; -import synfron.reshaper.burp.ui.components.rules.wizard.matchreplace.MatchAndReplaceWizardOptionPane; +import synfron.reshaper.burp.ui.components.rules.wizard.matchreplace.MatchAndReplaceWizardComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.RuleModel; import synfron.reshaper.burp.ui.models.rules.wizard.matchreplace.MatchAndReplaceWizardModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -86,7 +86,11 @@ public Component getHeaderBar() { private void onAddMatchAndReplace(ActionEvent actionEvent) { try { MatchAndReplaceWizardModel model = new MatchAndReplaceWizardModel(this.model); - ModalPrompter.open(model, ignored -> MatchAndReplaceWizardOptionPane.showDialog(model), true); + ModalPrompter.open(model, new ModalPrompter.FormPromptArgs<>( + "Match & Replace", + model, + new MatchAndReplaceWizardComponent(model) + )); } catch (Exception e) { Log.get(workspace).withMessage("Failed to create rule from content menu").withException(e).logErr(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java index a62648d..30c566e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java @@ -5,7 +5,7 @@ import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.IRuleOperation; import synfron.reshaper.burp.core.settings.Workspace; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.components.workspaces.IWorkspaceDependentComponent; import synfron.reshaper.burp.ui.models.rules.RuleOperationModel; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java index 7efbaf0..3617384 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java @@ -7,7 +7,7 @@ import synfron.reshaper.burp.core.rules.IRuleOperation; import synfron.reshaper.burp.core.settings.Workspace; import synfron.reshaper.burp.core.utils.CollectionUtils; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.components.workspaces.IWorkspaceDependentComponent; import synfron.reshaper.burp.ui.components.workspaces.IWorkspaceHost; import synfron.reshaper.burp.ui.models.rules.RuleModel; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java index e653130..d1a2f16 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java @@ -5,7 +5,7 @@ import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.SetItemPlacement; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.thens.buildhttpmessage.MessageValueSetterModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/BytesGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/BytesGeneratorComponent.java index 45c48f3..3539d80 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/BytesGeneratorComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/BytesGeneratorComponent.java @@ -1,12 +1,10 @@ package synfron.reshaper.burp.ui.components.rules.thens.generate; import synfron.reshaper.burp.core.messages.Encoder; -import synfron.reshaper.burp.ui.components.IFormComponent; import synfron.reshaper.burp.ui.models.rules.thens.generate.IBytesGeneratorModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; import javax.swing.*; -import java.awt.*; import java.awt.event.ActionEvent; public class BytesGeneratorComponent extends GeneratorComponent { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/GeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/GeneratorComponent.java index 5d2058f..e994d82 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/GeneratorComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/GeneratorComponent.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.thens.generate; import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.thens.generate.IGeneratorModel; import javax.swing.*; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java index 77b166c..77475de 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java @@ -7,7 +7,7 @@ import synfron.reshaper.burp.core.rules.GetItemPlacement; import synfron.reshaper.burp.core.vars.SetListItemPlacement; import synfron.reshaper.burp.core.vars.VariableSource; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.thens.parsehttpmessage.MessageValueGetterModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/Base64TransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/Base64TransformerComponent.java index dd9f1f7..9c106f1 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/Base64TransformerComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/Base64TransformerComponent.java @@ -3,11 +3,9 @@ import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.rules.thens.entities.transform.Base64Variant; import synfron.reshaper.burp.core.rules.thens.entities.transform.EncodeTransform; -import synfron.reshaper.burp.ui.components.IFormComponent; import synfron.reshaper.burp.ui.models.rules.thens.transform.Base64TransformerModel; import javax.swing.*; -import java.awt.*; import java.awt.event.ActionEvent; public class Base64TransformerComponent extends TransformerComponent { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TransformerComponent.java index b2748d9..5f49587 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TransformerComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TransformerComponent.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.thens.transform; import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.thens.transform.TransformerModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/matchreplace/MatchAndReplaceWizardOptionPane.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/matchreplace/MatchAndReplaceWizardComponent.java similarity index 71% rename from extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/matchreplace/MatchAndReplaceWizardOptionPane.java rename to extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/matchreplace/MatchAndReplaceWizardComponent.java index 64deafe..1d7db02 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/matchreplace/MatchAndReplaceWizardOptionPane.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/matchreplace/MatchAndReplaceWizardComponent.java @@ -1,7 +1,9 @@ package synfron.reshaper.burp.ui.components.rules.wizard.matchreplace; import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.components.shared.PromptTextField; import synfron.reshaper.burp.ui.models.rules.wizard.matchreplace.MatchAndReplaceWizardModel; import synfron.reshaper.burp.ui.models.rules.wizard.matchreplace.MatchType; @@ -11,14 +13,9 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.beans.PropertyChangeEvent; -import java.util.Objects; -public class MatchAndReplaceWizardOptionPane extends JOptionPane implements IFormComponent { +public class MatchAndReplaceWizardComponent extends JPanel implements IFormComponent { - private final JPanel container; private final MatchAndReplaceWizardModel model; private JComboBox matchType; private JTextField identifier; @@ -26,46 +23,26 @@ public class MatchAndReplaceWizardOptionPane extends JOptionPane implements IFor private JLabel matchLabel; private PromptTextField replace; private JCheckBox regexMatch; + private final IEventListener modelChangedListener = this::onModelChanged; - private MatchAndReplaceWizardOptionPane(MatchAndReplaceWizardModel model) { - super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, new Object[]{ "OK", "Cancel" }, "OK"); - container = (JPanel)message; + public MatchAndReplaceWizardComponent(MatchAndReplaceWizardModel model) { this.model = model; - addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); initComponent(); - } - private void onPropertyChanged(PropertyChangeEvent event) { - if (Objects.equals(getValue(), "OK")) { - if (!model.updateRule()) { - JOptionPane.showMessageDialog(this, - String.join("\n", model.validate()), - "Validation Error", - JOptionPane.ERROR_MESSAGE); - } - } else { - model.setDismissed(true); - } + model.withListener(modelChangedListener); } - public static void showDialog(MatchAndReplaceWizardModel model) { - MatchAndReplaceWizardOptionPane optionPane = new MatchAndReplaceWizardOptionPane(model); - JDialog dialog = optionPane.createDialog("Match & Replace"); - dialog.setResizable(true); - - dialog.setModal(false); - dialog.setVisible(true); - - optionPane.container.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - dialog.pack(); - } - }); + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("invalidated") && model.isInvalidated()) { + JOptionPane.showMessageDialog(this, + String.join("\n", model.validate()), + "Validation Error", + JOptionPane.ERROR_MESSAGE); + } } private void initComponent() { - container.add(getBody(), BorderLayout.CENTER); + add(getBody(), BorderLayout.CENTER); } private Component getBody() { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java index 010c783..402c92c 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java @@ -2,7 +2,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.messages.MessageAnnotation; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.AnnotationVariableTagWizardModel; import javax.swing.*; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java index ba49df3..6c4879e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java @@ -2,7 +2,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.CookieJarVariableTagWizardModel; import javax.swing.*; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CustomVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CustomVariableTagWizardComponent.java index 79a6d67..aa3b0bf 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CustomVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CustomVariableTagWizardComponent.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.wizard.vars; import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.CustomVariableTagWizardModel; import javax.swing.*; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java index e3d2280..2abf33c 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java @@ -2,7 +2,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.messages.Encoder; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.FileVariableTagWizardModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GeneratorVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GeneratorVariableTagWizardComponent.java index 97b1935..adf038f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GeneratorVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GeneratorVariableTagWizardComponent.java @@ -2,7 +2,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.components.rules.thens.generate.*; import synfron.reshaper.burp.ui.models.rules.wizard.vars.GeneratorVariableTagWizardModel; import synfron.reshaper.burp.ui.models.rules.wizard.vars.generator.*; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MacroVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MacroVariableTagWizardComponent.java index 1789890..2ced19a 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MacroVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MacroVariableTagWizardComponent.java @@ -3,7 +3,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.MacroVariableTagWizardModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java index 2dc3255..9ce8883 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java @@ -3,7 +3,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.MessageVariableTagWizardModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java index cda34cc..f8ef2f1 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.wizard.vars; import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.SpecialVariableTagWizardModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardComponent.java new file mode 100644 index 0000000..cdb5155 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardComponent.java @@ -0,0 +1,79 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.VariableTagWizardModel; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.function.Consumer; + +public class VariableTagWizardComponent extends JPanel implements IFormComponent { + + private final VariableTagWizardModel model; + private JComboBox variableSource; + private final VariableTagWizardContainerComponent container; + private final ProtocolType protocolType; + private final Consumer fieldUpdater; + private final IEventListener modelChangedListener = this::onModelChanged; + + public VariableTagWizardComponent(VariableTagWizardModel model, ProtocolType protocolType, Consumer fieldUpdater) { + this.model = model; + container = new VariableTagWizardContainerComponent(protocolType); + this.protocolType = protocolType; + this.fieldUpdater = fieldUpdater; + initComponent(); + + model.withListener(modelChangedListener); + } + + private void initComponent() { + setLayout(new BorderLayout()); + + variableSource = createComboBox(VariableSource.getAll(protocolType)); + + variableSource.setSelectedItem(model.getVariableSource()); + + variableSource.addActionListener(this::onVariableSourceChanged); + + add(getLabeledField("Tag Type", variableSource), BorderLayout.PAGE_START); + add(container, BorderLayout.CENTER); + + container.setModel(model.getTagModel()); + } + + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + switch (propertyChangedArgs.getName()) { + case "invalidated": { + if (model.isInvalidated()) { + JOptionPane.showMessageDialog(this, + String.join("\n", model.validate()), + "Validation Error", + JOptionPane.ERROR_MESSAGE); + } + } + case "dismissed": { + if (model.isDismissed()) { + fieldUpdater.accept(!model.isInvalidated()); + } + } + case "tagModel": { + container.setModel(model.getTagModel()); + } + } + } + + private void onVariableSourceChanged(ActionEvent actionEvent) { + model.setVariableSource((VariableSource)variableSource.getSelectedItem()); + } + + @Override + @SuppressWarnings("unchecked") + public T getComponent() { + return (T) this; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java deleted file mode 100644 index d443b74..0000000 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java +++ /dev/null @@ -1,107 +0,0 @@ -package synfron.reshaper.burp.ui.components.rules.wizard.vars; - -import synfron.reshaper.burp.core.ProtocolType; -import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.core.vars.VariableSource; -import synfron.reshaper.burp.ui.components.IFormComponent; -import synfron.reshaper.burp.ui.models.rules.wizard.vars.VariableTagWizardModel; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.beans.PropertyChangeEvent; -import java.util.Objects; - -public class VariableTagWizardOptionPane extends JOptionPane implements IFormComponent { - - private final JPanel outerContainer; - private final VariableTagWizardModel model; - private JComboBox variableSource; - private final VariableTagWizardContainerComponent container; - private JDialog currentDialog; - private final ProtocolType protocolType; - - private VariableTagWizardOptionPane(VariableTagWizardModel model, ProtocolType protocolType) { - super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, new Object[]{ "OK", "Cancel" }, "OK"); - container = new VariableTagWizardContainerComponent(protocolType); - outerContainer = (JPanel)message; - this.model = model; - this.protocolType = protocolType; - addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); - initComponent(); - - model.withListener(this::onModelChanged); - } - - private void initComponent() { - variableSource = createComboBox(VariableSource.getAll(protocolType)); - - variableSource.setSelectedItem(model.getVariableSource()); - - variableSource.addActionListener(this::onVariableSourceChanged); - - outerContainer.add(getLabeledField("Tag Type", variableSource), BorderLayout.PAGE_START); - outerContainer.add(container, BorderLayout.CENTER); - - container.setModel(model.getTagModel()); - - container.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - resize(); - } - }); - } - - private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { - switch (propertyChangedArgs.getName()) { - case "tagModel" -> { - container.setModel(model.getTagModel()); - resize(); - - } - } - } - - private void resize() { - if (currentDialog != null) { - currentDialog.pack(); - } - } - - private void onVariableSourceChanged(ActionEvent actionEvent) { - model.setVariableSource((VariableSource)variableSource.getSelectedItem()); - } - - private void onPropertyChanged(PropertyChangeEvent event) { - if (Objects.equals(getValue(), "OK")) { - if (!model.validate().isEmpty()) { - JOptionPane.showMessageDialog(this, - String.join("\n", model.validate()), - "Validation Error", - JOptionPane.ERROR_MESSAGE); - } - } else { - model.setDismissed(true); - } - } - - public static void showDialog(VariableTagWizardModel model, ProtocolType protocolType) { - VariableTagWizardOptionPane optionPane = new VariableTagWizardOptionPane(model, protocolType); - JDialog dialog = optionPane.createDialog("Variable Tag"); - optionPane.setCurrentDialog(dialog); - dialog.setVisible(true); - } - - private void setCurrentDialog(JDialog dialog) { - this.currentDialog = dialog; - } - - @Override - @SuppressWarnings("unchecked") - public T getComponent() { - return (T) this; - } -} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardOptionPane.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardComponent.java similarity index 79% rename from extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardOptionPane.java rename to extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardComponent.java index 57672d0..5b73836 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardOptionPane.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardComponent.java @@ -3,7 +3,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardItemModel; import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -12,56 +12,44 @@ import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.ActionEvent; -import java.beans.PropertyChangeEvent; -import java.util.Objects; -public class WhenWizardOptionPane extends JOptionPane implements IFormComponent { +public class WhenWizardComponent extends JPanel implements IFormComponent { - private final JPanel container; private final WhenWizardModel model; private JTextField ruleName; private JPanel whenWizardItemsComponent; private final IEventListener whenWizardItemChangedListener = this::onWhenWizardItemChanged; private JScrollPane bodyScrollPane; + private final IEventListener modelChangedListener = this::onModelChanged; - private WhenWizardOptionPane(WhenWizardModel model) { - super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, new Object[]{ "OK", "Cancel" }, "OK"); - container = (JPanel)message; + public WhenWizardComponent(WhenWizardModel model) { this.model = model; - addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); initComponent(); + + model.withListener(modelChangedListener); } - private void onPropertyChanged(PropertyChangeEvent event) { - if (Objects.equals(getValue(), "OK")) { - if (model.createRule()) { - JOptionPane.showMessageDialog(this, - "Rule created. Navigate to Reshaper to finish the rule.", - "Rule Created", - JOptionPane.INFORMATION_MESSAGE); - } else { + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("invalidated")) { + if (model.isInvalidated()) { JOptionPane.showMessageDialog(this, String.join("\n", model.validate()), "Validation Error", JOptionPane.ERROR_MESSAGE); } - } else { - model.setDismissed(true); + } else if (propertyChangedArgs.getName().equals("dismissed")) { + if (!model.isInvalidated()) { + JOptionPane.showMessageDialog(this, + "Rule created. Navigate to Reshaper to finish the rule.", + "Rule Created", + JOptionPane.INFORMATION_MESSAGE); + } } } - public static void showDialog(WhenWizardModel model) { - WhenWizardOptionPane optionPane = new WhenWizardOptionPane(model); - JDialog dialog = optionPane.createDialog("When"); - dialog.setResizable(true); - - dialog.setModal(false); - dialog.setVisible(true); - } - private void initComponent() { bodyScrollPane = getBodyScrollPane(); - container.add(bodyScrollPane, BorderLayout.CENTER); + add(bodyScrollPane, BorderLayout.CENTER); } private JScrollPane getBodyScrollPane() { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java index 7c6ddda..19919f1 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java @@ -3,7 +3,7 @@ import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardItemModel; import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardMatchType; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsOptionPane.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsComponent.java similarity index 78% rename from extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsOptionPane.java rename to extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsComponent.java index bd57f3b..229d145 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsOptionPane.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsComponent.java @@ -4,50 +4,27 @@ import synfron.reshaper.burp.core.WorkspaceTab; import synfron.reshaper.burp.core.rules.thens.ThenType; import synfron.reshaper.burp.core.rules.whens.WhenType; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.settings.HideItemsModel; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; import java.util.HashSet; -import java.util.Objects; import java.util.stream.Stream; -public class HideItemsOptionPane extends JOptionPane implements IFormComponent { +public class HideItemsComponent extends JPanel implements IFormComponent { - private final JPanel container; private final HideItemsModel model; - private HideItemsOptionPane(HideItemsModel model) { - super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, new Object[]{ "OK", "Cancel" }, "OK"); - container = (JPanel)message; + public HideItemsComponent(HideItemsModel model) { this.model = model; - addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); initComponent(); } - private void onPropertyChanged(PropertyChangeEvent event) { - if (Objects.equals(getValue(), "OK")) { - model.save(); - } else { - model.setDismissed(true); - } - } - - public static void showDialog(HideItemsModel model) { - HideItemsOptionPane optionPane = new HideItemsOptionPane(model); - JDialog dialog = optionPane.createDialog("Hide Features"); - dialog.setResizable(true); - - dialog.setModal(false); - dialog.setVisible(true); - } - private void initComponent() { - container.add(getBody(), BorderLayout.CENTER); + add(getBody(), BorderLayout.CENTER); } private void addCheckboxes(JPanel container, int maxRowLength, java.util.List items, HashSet checkedItems, ActionListener checkboxChangedListener) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java index 9cd3274..b8a9478 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java @@ -16,7 +16,7 @@ import synfron.reshaper.burp.core.utils.Log; import synfron.reshaper.burp.core.utils.TextUtils; import synfron.reshaper.burp.core.vars.Variable; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.components.workspaces.IWorkspaceDependentComponent; import synfron.reshaper.burp.ui.models.settings.HideItemsModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; @@ -116,7 +116,11 @@ private void onEnableWorkspaces(ActionEvent actionEvent) { private void onHideFeatures(ActionEvent actionEvent) { HideItemsModel model = new HideItemsModel(generalSettings); - ModalPrompter.open(model, ignored -> HideItemsOptionPane.showDialog(model), true); + ModalPrompter.open(model, new ModalPrompter.FormPromptArgs<>( + "Hide Features", + model, + new HideItemsComponent(model) + )); } private Component RightGeneralOptions() { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/shared/FormPrompt.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/shared/FormPrompt.java new file mode 100644 index 0000000..b29eafb --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/shared/FormPrompt.java @@ -0,0 +1,106 @@ +package synfron.reshaper.burp.ui.components.shared; + +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.ui.utils.IPrompterModel; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.HashMap; +import java.util.Map; + +public class FormPrompt> extends JDialog { + + private final Component formComponent; + private final T model; + private final IEventListener modelChangedListener = this::onModelChanged; + @Getter @Setter + private boolean setAutoResize; + private Map clientProperties; + private boolean autoResize = true; + + public FormPrompt(String title, T model, Component formComponent) { + super(null, title, Dialog.ModalityType.APPLICATION_MODAL); + this.formComponent = formComponent; + this.model = model; + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + setModal(false); + setLayout(new BorderLayout()); + + initComponent(); + + model.withListener(modelChangedListener); + } + + private void initComponent() { + JPanel actionBar = getActionBar(); + + JPanel container = new JPanel(new BorderLayout()); + container.setBorder(new EmptyBorder(5,5,5,5)); + container.add(formComponent, BorderLayout.CENTER); + + add(container, BorderLayout.CENTER); + add(actionBar, BorderLayout.PAGE_END); + } + + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("dismissed")) { + setVisible(!model.isDismissed()); + } else if (propertyChangedArgs.getName().equals("fieldsSize") && autoResize) { + pack(); + } + + } + + private JPanel getActionBar() { + JPanel actionBar = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + JButton submit = new JButton("OK"); + JButton cancel = new JButton("Cancel"); + + submit.addActionListener(this::onSubmit); + cancel.addActionListener(this::onCancel); + + actionBar.add(submit); + actionBar.add(cancel); + + return actionBar; + } + + private void onCancel(ActionEvent actionEvent) { + model.cancel(); + } + + private void onSubmit(ActionEvent actionEvent) { + model.submit(); + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible && autoResize) { + pack(); + } + } + + @Override + public void setSize(Dimension size) { + autoResize = false; + super.setSize(size); + } + + public Object getClientProperty(String key) { + return clientProperties != null ? clientProperties.get(key) : null; + } + + public void putClientProperty(String key, Object value) { + if (clientProperties == null) { + clientProperties = new HashMap<>(); + } + clientProperties.put(key, value); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/shared/IFormComponent.java similarity index 86% rename from extension/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java rename to extension/src/main/java/synfron/reshaper/burp/ui/components/shared/IFormComponent.java index 07003e3..465fba8 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/shared/IFormComponent.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.ui.components; +package synfron.reshaper.burp.ui.components.shared; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang3.StringUtils; @@ -6,9 +6,7 @@ import synfron.reshaper.burp.core.settings.Workspace; import synfron.reshaper.burp.core.vars.VariableTag; import synfron.reshaper.burp.ui.components.rules.RuleOperationComponent; -import synfron.reshaper.burp.ui.components.rules.wizard.vars.VariableTagWizardOptionPane; -import synfron.reshaper.burp.ui.components.shared.PromptTextField; -import synfron.reshaper.burp.ui.components.shared.TextPrompt; +import synfron.reshaper.burp.ui.components.rules.wizard.vars.VariableTagWizardComponent; import synfron.reshaper.burp.ui.components.workspaces.IWorkspaceDependentComponent; import synfron.reshaper.burp.ui.components.workspaces.IWorkspaceHost; import synfron.reshaper.burp.ui.models.rules.wizard.vars.VariableTagWizardModel; @@ -21,6 +19,7 @@ import javax.swing.undo.UndoManager; import java.awt.*; import java.awt.event.KeyEvent; +import java.util.function.Consumer; import static java.awt.Component.LEFT_ALIGNMENT; import static java.awt.Component.TOP_ALIGNMENT; @@ -169,24 +168,32 @@ private T addContextMenu(T textComponent, boolean sup private static void insertVariableTag(T textComponent, ProtocolType protocolType) { VariableTagWizardModel model = new VariableTagWizardModel(); - do { - ModalPrompter.open(model, ignored -> VariableTagWizardOptionPane.showDialog(model, protocolType), false); - } while (model.isInvalidated() && !model.isDismissed()); - if (!model.isDismissed()) { - String tag = model.getTag(); - if (StringUtils.isNotEmpty(tag)) { - int cursorPosition = textComponent.getCaretPosition(); - int insertPosition = VariableTag.getVariableTagPositions(textComponent.getText()).stream() - .noneMatch(position -> position.getLeft() < cursorPosition && cursorPosition < position.getRight()) ? - cursorPosition : - textComponent.getText().length(); - StringBuilder text = new StringBuilder(textComponent.getText()); - text.insert(insertPosition, tag); - textComponent.setText(text.toString()); - textComponent.setCaretPosition(insertPosition + tag.length()); + + Consumer fieldUpdater = valid -> { + if (valid) { + String tag = model.getTag(); + if (StringUtils.isNotEmpty(tag)) { + int cursorPosition = textComponent.getCaretPosition(); + int insertPosition = VariableTag.getVariableTagPositions(textComponent.getText()).stream() + .noneMatch(position -> position.getLeft() < cursorPosition && cursorPosition < position.getRight()) ? + cursorPosition : + textComponent.getText().length(); + StringBuilder text = new StringBuilder(textComponent.getText()); + text.insert(insertPosition, tag); + textComponent.setText(text.toString()); + textComponent.setCaretPosition(insertPosition + tag.length()); + } } - } - textComponent.requestFocus(); + textComponent.requestFocus(); + }; + + ModalPrompter.open(model, new ModalPrompter.FormPromptArgs<>( + "Variable Tag", + model, + new VariableTagWizardComponent(model, protocolType, fieldUpdater) + ).resizable(true)); + + } static T addUndo(T textComponent) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java index fa6adbd..479c5c5 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java @@ -13,7 +13,7 @@ import synfron.reshaper.burp.core.settings.Workspace; import synfron.reshaper.burp.core.utils.BurpUtils; import synfron.reshaper.burp.core.vars.VariableValueType; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import synfron.reshaper.burp.ui.models.vars.VariableModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; import synfron.reshaper.burp.ui.utils.DocumentListenerFinder; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceComponent.java index 41a0ae8..8f9b098 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceComponent.java @@ -32,7 +32,7 @@ public class WorkspaceComponent extends JPanel implements IWorkspaceHost { public WorkspaceComponent(Workspace workspace) { this.workspace = workspace; - this.uiMessageHandler = new UiMessageHandler(workspace.getMessageEvent()); + this.uiMessageHandler = new UiMessageHandler(workspace.getMessageEvent(), this); initComponents(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceNameComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceNameComponent.java new file mode 100644 index 0000000..048ecca --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceNameComponent.java @@ -0,0 +1,63 @@ +package synfron.reshaper.burp.ui.components.workspaces; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; +import synfron.reshaper.burp.ui.models.workspaces.WorkspaceNameModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; + +public class WorkspaceNameComponent extends JPanel implements IFormComponent { + + private final WorkspaceNameModel model; + private JTextField workspaceName; + private final IEventListener modelChangedListener = this::onModelChanged; + + public WorkspaceNameComponent(WorkspaceNameModel model) { + this.model = model; + initComponent(); + + model.withListener(modelChangedListener); + } + + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("invalidated") && model.isInvalidated()) { + JOptionPane.showMessageDialog(this, + String.join("\n", model.validate()), + "Validation Error", + JOptionPane.ERROR_MESSAGE); + } + } + + private void initComponent() { + add(getBody(), BorderLayout.CENTER); + } + + private Component getBody() { + JPanel container = new JPanel(new MigLayout()); + + workspaceName = createTextField(false); + + workspaceName.setText(model.getWorkspaceName()); + + workspaceName.getDocument().addDocumentListener(new DocumentActionListener(this::onWorkspaceNameChanged)); + + container.add(getLabeledField("Workspace Name *", workspaceName), "wrap");; + + return container; + } + + private void onWorkspaceNameChanged(ActionEvent actionEvent) { + model.setWorkspaceName(workspaceName.getText()); + } + + @Override + @SuppressWarnings("unchecked") + public T getComponent() { + return (T) this; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceNameOptionPane.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceNameOptionPane.java deleted file mode 100644 index a12c716..0000000 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/workspaces/WorkspaceNameOptionPane.java +++ /dev/null @@ -1,77 +0,0 @@ -package synfron.reshaper.burp.ui.components.workspaces; - -import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.ui.components.IFormComponent; -import synfron.reshaper.burp.ui.models.workspaces.WorkspaceNameModel; -import synfron.reshaper.burp.ui.utils.DocumentActionListener; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.beans.PropertyChangeEvent; -import java.util.Objects; - -public class WorkspaceNameOptionPane extends JOptionPane implements IFormComponent { - - private final JPanel container; - private final WorkspaceNameModel model; - private JTextField workspaceName; - - private WorkspaceNameOptionPane(WorkspaceNameModel model) { - super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, new Object[]{ "OK", "Cancel" }, "OK"); - container = (JPanel)message; - this.model = model; - addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); - initComponent(); - } - - private void onPropertyChanged(PropertyChangeEvent event) { - if (Objects.equals(getValue(), "OK")) { - if (!model.save()) { - JOptionPane.showMessageDialog(this, - String.join("\n", model.validate()), - "Validation Error", - JOptionPane.ERROR_MESSAGE); - } - } else { - model.setDismissed(true); - } - } - - public static void showDialog(WorkspaceNameModel model) { - WorkspaceNameOptionPane optionPane = new WorkspaceNameOptionPane(model); - JDialog dialog = optionPane.createDialog("Workspace"); - dialog.setResizable(true); - - dialog.setModal(false); - dialog.setVisible(true); - } - - private void initComponent() { - container.add(getBody(), BorderLayout.CENTER); - } - - private Component getBody() { - JPanel container = new JPanel(new MigLayout()); - - workspaceName = createTextField(false); - - workspaceName.setText(model.getWorkspaceName()); - - workspaceName.getDocument().addDocumentListener(new DocumentActionListener(this::onWorkspaceNameChanged)); - - container.add(getLabeledField("Workspace Name", workspaceName), "wrap");; - - return container; - } - - private void onWorkspaceNameChanged(ActionEvent actionEvent) { - model.setWorkspaceName(workspaceName.getText()); - } - - @Override - @SuppressWarnings("unchecked") - public T getComponent() { - return (T) this; - } -} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/TextPromptModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/TextPromptModel.java new file mode 100644 index 0000000..87d04a9 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/TextPromptModel.java @@ -0,0 +1,59 @@ +package synfron.reshaper.burp.ui.models; + +import lombok.Getter; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.ui.utils.IPrompterModel; + +@Getter +public class TextPromptModel implements IPrompterModel { + + private final String description; + private String text; + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + private boolean dismissed; + private boolean invalidated = true; + + public TextPromptModel(String description, String text) { + this.description = description; + this.text = text; + } + + public TextPromptModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setText(String text) { + this.text = text; + propertyChanged("text", text); + } + + public void setDismissed(boolean dismissed) { + this.dismissed = dismissed; + propertyChanged("dismissed", dismissed); + } + + public void setInvalidated(boolean invalidated) { + this.invalidated = invalidated; + propertyChanged("invalidated", invalidated); + } + + @Override + public boolean submit() { + setInvalidated(false); + setDismissed(true); + return true; + } + + @Override + public boolean cancel() { + setDismissed(true); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/matchreplace/MatchAndReplaceWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/matchreplace/MatchAndReplaceWizardModel.java index 55f2309..37c9c51 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/matchreplace/MatchAndReplaceWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/matchreplace/MatchAndReplaceWizardModel.java @@ -1,7 +1,6 @@ package synfron.reshaper.burp.ui.models.rules.wizard.matchreplace; import lombok.Getter; -import lombok.Setter; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.events.IEventListener; @@ -19,7 +18,6 @@ import synfron.reshaper.burp.ui.models.rules.whens.WhenMatchesTextModel; import synfron.reshaper.burp.ui.models.rules.whens.WhenModel; import synfron.reshaper.burp.ui.utils.IPrompterModel; -import synfron.reshaper.burp.ui.utils.ModalPrompter; import java.util.ArrayList; import java.util.List; @@ -31,7 +29,7 @@ public class MatchAndReplaceWizardModel implements IPrompterModel modalPrompter; - public MatchAndReplaceWizardModel(RuleModel rule) { this.rule = rule; } - public void resetPropertyChangedListener() { - propertyChangedEvent.clearListeners(); - } - private void propertyChanged(String name, Object value) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); } @@ -58,6 +48,7 @@ private void propertyChanged(String name, Object value) { public void setMatchType(MatchType matchType) { this.matchType = matchType; propertyChanged("matchType", matchType); + propertyChanged("fieldsSize", true); } public void setIdentifier(String identifier) { @@ -103,6 +94,21 @@ public void setDismissed(boolean dismissed) { propertyChanged("dismissed", dismissed); } + @Override + public boolean submit() { + if (updateRule()) { + setDismissed(true); + return true; + } + return false; + } + + @Override + public boolean cancel() { + setDismissed(true); + return true; + } + public boolean updateRule() { if (validate().isEmpty()) { boolean useContainsMatch = !regexMatch && !matchType.isRequiresRegex(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java index 3707e74..64790de 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java @@ -2,7 +2,6 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.vars.GetListItemPlacement; import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; @@ -18,9 +17,6 @@ public abstract class CustomListVariableTagWizardModel extends CustomVariableTag @Getter private String index; - @Getter - private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); - public CustomListVariableTagWizardModel(List entries) { super(entries); } @@ -28,6 +24,7 @@ public CustomListVariableTagWizardModel(List entries) { public void setItemPlacement(GetListItemPlacement itemPlacement) { this.itemPlacement = itemPlacement; propertyChanged("itemPlacement", itemPlacement); + propertyChanged("fieldsSize", true); } public void setIndex(String index) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java index 338b276..1a7c462 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.vars.VariableSource; @@ -31,6 +32,11 @@ protected void propertyChanged(String name, Object value) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); } + public CustomVariableTagWizardModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + public void setVariableName(String variableName) { this.variableName = variableName; propertyChanged("variableName", variableName); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GeneratorVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GeneratorVariableTagWizardModel.java index c2b4e28..743b1da 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GeneratorVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GeneratorVariableTagWizardModel.java @@ -1,12 +1,14 @@ package synfron.reshaper.burp.ui.models.rules.wizard.vars; import lombok.Getter; +import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.models.rules.wizard.vars.generator.*; +import javax.swing.*; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,17 +43,24 @@ public void setGenerateOption(GenerateOption generateOption) { this.generateOption = generateOption; propertyChanged("generateOption", generateOption); setGenerator(generatorMap.computeIfAbsent(this.generateOption, this::constructGeneratorModel)); + propertyChanged("fieldsSize", true); } public void setGenerator(GeneratorVariableModel generator) { this.generator = generator; propertyChanged("generator", generator); + SwingUtilities.invokeLater(() -> propertyChanged("fieldsSize", true)); } private void propertyChanged(String name, Object value) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); } + public GeneratorVariableTagWizardModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + @Override public List validate() { return generator.validate(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java index 1104d7e..328207b 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.messages.MessageValue; @@ -30,6 +31,11 @@ private void propertyChanged(String name, Object value) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); } + public MacroVariableTagWizardModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + public void setMacroItemNumber(String macroItemNumber) { this.macroItemNumber = macroItemNumber; propertyChanged("macroItemNumber", macroItemNumber); @@ -38,6 +44,7 @@ public void setMacroItemNumber(String macroItemNumber) { public void setMessageValue(MessageValue messageValue) { this.messageValue = messageValue; propertyChanged("messageValue", messageValue); + propertyChanged("fieldsSize", true); } public void setIdentifier(String identifier) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java index 81351ec..9c31368 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.messages.MessageValue; @@ -26,9 +27,15 @@ private void propertyChanged(String name, Object value) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); } + public MessageVariableTagWizardModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + public void setMessageValue(MessageValue messageValue) { this.messageValue = messageValue; propertyChanged("messageValue", messageValue); + propertyChanged("fieldsSize", true); } public void setIdentifier(String identifier) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java index 8eb1264..b8477e1 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java @@ -1,7 +1,6 @@ package synfron.reshaper.burp.ui.models.rules.wizard.vars; import lombok.Getter; -import lombok.Setter; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; @@ -9,7 +8,6 @@ import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.ui.models.rules.thens.VariableCreatorRegistry; import synfron.reshaper.burp.ui.utils.IPrompterModel; -import synfron.reshaper.burp.ui.utils.ModalPrompter; import java.util.List; import java.util.Map; @@ -28,12 +26,10 @@ public class VariableTagWizardModel implements IVariableTagWizardModel, IPrompte private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); @Getter - private boolean invalidated; + private boolean invalidated = true; @Getter private boolean dismissed; - - @Setter @Getter - private ModalPrompter modalPrompter; + private final IEventListener modelPropertyChangedListener = this::onChildModelPropertyChanged; public VariableTagWizardModel() { List variableSourceEntries = VariableCreatorRegistry.getVariableEntries(); @@ -42,32 +38,32 @@ public VariableTagWizardModel() { Map.entry(VariableSource.Event, new EventVariableTagWizardModel(variableSourceEntries)), Map.entry(VariableSource.Global, new GlobalVariableTagWizardModel(variableSourceEntries)), Map.entry(VariableSource.Session, new SessionVariableTagWizardModel(variableSourceEntries)), - Map.entry(VariableSource.EventList, new EventListVariableTagWizardModel(variableSourceEntries)), - Map.entry(VariableSource.GlobalList, new GlobalListVariableTagWizardModel(variableSourceEntries)), - Map.entry(VariableSource.SessionList, new SessionListVariableTagWizardModel(variableSourceEntries)), - Map.entry(VariableSource.Message, new MessageVariableTagWizardModel()), - Map.entry(VariableSource.Macro, new MacroVariableTagWizardModel()), + Map.entry(VariableSource.EventList, new EventListVariableTagWizardModel(variableSourceEntries).withListener(modelPropertyChangedListener)), + Map.entry(VariableSource.GlobalList, new GlobalListVariableTagWizardModel(variableSourceEntries).withListener(modelPropertyChangedListener)), + Map.entry(VariableSource.SessionList, new SessionListVariableTagWizardModel(variableSourceEntries).withListener(modelPropertyChangedListener)), + Map.entry(VariableSource.Message, new MessageVariableTagWizardModel().withListener(modelPropertyChangedListener)), + Map.entry(VariableSource.Macro, new MacroVariableTagWizardModel().withListener(modelPropertyChangedListener)), Map.entry(VariableSource.File, new FileVariableTagWizardModel()), Map.entry(VariableSource.Special, new SpecialVariableTagWizardModel()), Map.entry(VariableSource.CookieJar, new CookieJarVariableTagWizardModel()), Map.entry(VariableSource.Annotation, new AnnotationVariableTagWizardModel()), - Map.entry(VariableSource.Generator, new GeneratorVariableTagWizardModel()) + Map.entry(VariableSource.Generator, new GeneratorVariableTagWizardModel().withListener(modelPropertyChangedListener)) ); tagModel = tagModelMap.get(variableSource); } + private void onChildModelPropertyChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("fieldsSize")) { + propertyChanged(propertyChangedArgs.getName(), propertyChangedArgs.getValue()); + } + } + public VariableTagWizardModel withListener(IEventListener listener) { getPropertyChangedEvent().add(listener); return this; } - @Override - public void resetPropertyChangedListener() { - propertyChangedEvent.clearListeners(); - tagModelMap.values().forEach(item -> item.getPropertyChangedEvent().clearListeners()); - } - private void propertyChanged(String name, Object value) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); } @@ -77,6 +73,7 @@ public void setVariableSource(VariableSource variableSource) { this.tagModel = tagModelMap.get(variableSource); propertyChanged("variableSource", variableSource); propertyChanged("tagModel", tagModel); + propertyChanged("fieldsSize", true); } public void setInvalidated(boolean invalidated) { @@ -89,6 +86,23 @@ public void setDismissed(boolean dismissed) { propertyChanged("dismissed", dismissed); } + @Override + public boolean submit() { + if (validate().isEmpty()) { + setInvalidated(false); + setDismissed(true); + return true; + } + setInvalidated(true); + return false; + } + + @Override + public boolean cancel() { + setDismissed(true); + return true; + } + @Override public String getTag() { return validate().isEmpty() ? @@ -99,7 +113,6 @@ public String getTag() { @Override public List validate() { List errors = tagModel.validate(); - setInvalidated(!errors.isEmpty()); return errors; } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java index 2c195d9..75018c7 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java @@ -1,7 +1,6 @@ package synfron.reshaper.burp.ui.models.rules.wizard.whens; import lombok.Getter; -import lombok.Setter; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; @@ -14,7 +13,6 @@ import synfron.reshaper.burp.core.rules.whens.*; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.utils.IPrompterModel; -import synfron.reshaper.burp.ui.utils.ModalPrompter; import java.util.ArrayList; import java.util.LinkedList; @@ -27,21 +25,13 @@ public class WhenWizardModel implements IPrompterModel { private final List items = new ArrayList<>(); private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); - private boolean invalidated; + private boolean invalidated = true; private boolean dismissed; - @Setter - private ModalPrompter modalPrompter; - public WhenWizardModel(EventInfo eventInfo) { this.eventInfo = eventInfo; } - public void resetPropertyChangedListener() { - propertyChangedEvent.clearListeners(); - items.forEach(item -> item.getPropertyChangedEvent().clearListeners()); - } - public void setRuleName(String ruleName) { this.ruleName = ruleName; propertyChanged("ruleName", ruleName); @@ -107,6 +97,21 @@ public void setDismissed(boolean dismissed) { propertyChanged("dismissed", dismissed); } + @Override + public boolean submit() { + if (createRule()) { + setDismissed(true); + return true; + } + return false; + } + + @Override + public boolean cancel() { + setDismissed(true); + return true; + } + public boolean createRule() { if (validate().isEmpty()) { Rule rule = new Rule(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/settings/HideItemsModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/settings/HideItemsModel.java index 894e9ff..3cc8d55 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/settings/HideItemsModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/settings/HideItemsModel.java @@ -1,14 +1,12 @@ package synfron.reshaper.burp.ui.models.settings; import lombok.Getter; -import lombok.Setter; import synfron.reshaper.burp.core.WorkspaceTab; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.settings.GeneralSettings; import synfron.reshaper.burp.ui.utils.IPrompterModel; -import synfron.reshaper.burp.ui.utils.ModalPrompter; import java.util.HashSet; @@ -19,8 +17,6 @@ public class HideItemsModel implements IPrompterModel { private final HashSet hiddenWhenTypes = new HashSet<>(); private final HashSet hiddenTabs = new HashSet<>(); private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); - @Setter - private ModalPrompter modalPrompter; private boolean dismissed; public HideItemsModel(GeneralSettings generalSettings) { @@ -77,11 +73,6 @@ public boolean save() { return true; } - @Override - public void resetPropertyChangedListener() { - propertyChangedEvent.clearListeners(); - } - @Override public boolean isInvalidated() { return false; @@ -91,4 +82,19 @@ public void setDismissed(boolean dismissed) { this.dismissed = dismissed; propertyChanged("dismissed", dismissed); } + + @Override + public boolean submit() { + if (save()) { + setDismissed(true); + return true; + } + return false; + } + + @Override + public boolean cancel() { + setDismissed(true); + return true; + } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/workspaces/WorkspaceNameModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/workspaces/WorkspaceNameModel.java index 8ce24c2..d39a654 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/workspaces/WorkspaceNameModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/workspaces/WorkspaceNameModel.java @@ -1,7 +1,6 @@ package synfron.reshaper.burp.ui.models.workspaces; import lombok.Getter; -import lombok.Setter; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; @@ -9,32 +8,22 @@ import synfron.reshaper.burp.core.settings.Workspace; import synfron.reshaper.burp.core.settings.Workspaces; import synfron.reshaper.burp.ui.utils.IPrompterModel; -import synfron.reshaper.burp.ui.utils.ModalPrompter; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.Consumer; @Getter public class WorkspaceNameModel implements IPrompterModel { private final Workspace workspace; private String workspaceName; - private final Consumer onSuccess; private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); - @Setter - private ModalPrompter modalPrompter; private boolean dismissed; - private boolean invalidated; + private boolean invalidated = true; public WorkspaceNameModel(Workspace workspace) { - this(workspace, null); - } - - public WorkspaceNameModel(Workspace workspace, Consumer onSuccess) { this.workspace = workspace; this.workspaceName = workspace.getWorkspaceName(); - this.onSuccess = onSuccess; } public WorkspaceNameModel withListener(IEventListener listener) { @@ -55,10 +44,6 @@ public boolean save() { if (validate().isEmpty()) { workspace.setWorkspaceName(workspaceName); - if (onSuccess != null) { - onSuccess.accept(workspace); - } - setInvalidated(false); return true; } @@ -66,19 +51,24 @@ public boolean save() { return false; } - @Override - public void resetPropertyChangedListener() { - propertyChangedEvent.clearListeners(); + public void setDismissed(boolean dismissed) { + this.dismissed = dismissed; + propertyChanged("dismissed", dismissed); } @Override - public boolean isInvalidated() { + public boolean submit() { + if (save()) { + setDismissed(true); + return true; + } return false; } - public void setDismissed(boolean dismissed) { - this.dismissed = dismissed; - propertyChanged("dismissed", dismissed); + @Override + public boolean cancel() { + setDismissed(true); + return true; } public void setInvalidated(boolean invalidated) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java b/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java index f031fcd..ccb24c5 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java @@ -12,12 +12,11 @@ import synfron.reshaper.burp.core.settings.Workspaces; import synfron.reshaper.burp.core.utils.Log; import synfron.reshaper.burp.core.vars.Variables; -import synfron.reshaper.burp.ui.components.rules.wizard.whens.WhenWizardOptionPane; +import synfron.reshaper.burp.ui.components.rules.wizard.whens.WhenWizardComponent; import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardModel; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; import java.util.Collections; import java.util.List; @@ -26,30 +25,34 @@ public class ContextMenuHandler implements ContextMenuItemsProvider { @Override public List provideMenuItems(ContextMenuEvent event) { JMenuItem menuItem = new JMenuItem("Create Rule"); - menuItem.addActionListener(actionEvent -> onCreateHttpRule(event.selectedRequestResponses(), actionEvent)); + menuItem.addActionListener(actionEvent -> onCreateHttpRule(event.selectedRequestResponses())); return event.selectedRequestResponses().size() == 1 ? Collections.singletonList(menuItem) : Collections.emptyList(); } @Override public List provideMenuItems(WebSocketContextMenuEvent event) { JMenuItem menuItem = new JMenuItem("Create Rule"); - menuItem.addActionListener(actionEvent -> onCreateWebSocketRule(event.selectedWebSocketMessages(), actionEvent)); + menuItem.addActionListener(actionEvent -> onCreateWebSocketRule(event.selectedWebSocketMessages())); return event.selectedWebSocketMessages().size() == 1 ? Collections.singletonList(menuItem) : Collections.emptyList(); } - private void onCreateWebSocketRule(List selectedItems, ActionEvent actionEvent) { + private void onCreateWebSocketRule(List selectedItems) { WebSocketMessage webSocketMessage = selectedItems.getFirst(); openWhenWizard(new WhenWizardModel(new WebSocketEventInfo<>(Workspaces.get().getDefault(), WebSocketMessageType.Binary, WebSocketDataDirection.from(webSocketMessage.direction()), null, null, webSocketMessage.upgradeRequest(), webSocketMessage.annotations(), webSocketMessage.payload().getBytes(), new Variables()))); } - private void onCreateHttpRule(List selectedItems, ActionEvent actionEvent) { + private void onCreateHttpRule(List selectedItems) { HttpRequestResponse httpRequestResponse = selectedItems.getFirst(); openWhenWizard(new WhenWizardModel(new HttpEventInfo(Workspaces.get().getDefault(), null, null, null, httpRequestResponse.request(), httpRequestResponse.response(), httpRequestResponse.annotations(), new Variables()))); } private void openWhenWizard(WhenWizardModel model) { try { - ModalPrompter.open(model, ignored -> WhenWizardOptionPane.showDialog(model), true); + ModalPrompter.open(model, new ModalPrompter.FormPromptArgs<>( + "When", + model, + new WhenWizardComponent(model) + )); } catch (Exception e) { Log.get(Workspaces.get().getDefault()).withMessage("Failed to create rule from content menu").withException(e).logErr(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/utils/IPrompter.java b/extension/src/main/java/synfron/reshaper/burp/ui/utils/IPrompter.java deleted file mode 100644 index 53d49e4..0000000 --- a/extension/src/main/java/synfron/reshaper/burp/ui/utils/IPrompter.java +++ /dev/null @@ -1,5 +0,0 @@ -package synfron.reshaper.burp.ui.utils; - -public interface IPrompter { - void open(T model); -} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java index 437fbcd..8698ada 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java @@ -7,15 +7,13 @@ public interface IPrompterModel> { T withListener(IEventListener listener); - void resetPropertyChangedListener(); - - void setModalPrompter(ModalPrompter modalPrompter); - - ModalPrompter getModalPrompter(); - boolean isInvalidated(); boolean isDismissed(); void setDismissed(boolean dismissed); + + boolean submit(); + + boolean cancel(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/utils/ModalPrompter.java b/extension/src/main/java/synfron/reshaper/burp/ui/utils/ModalPrompter.java index 4af1b81..3dbab2a 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/utils/ModalPrompter.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/utils/ModalPrompter.java @@ -1,86 +1,109 @@ package synfron.reshaper.burp.ui.utils; -import synfron.reshaper.burp.core.events.IEventListener; -import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.ui.components.IFormComponent; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import synfron.reshaper.burp.ui.components.shared.FormPrompt; import javax.swing.*; -import javax.swing.border.EmptyBorder; import java.awt.*; +import java.lang.ref.WeakReference; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; public class ModalPrompter> { - private static final Map dialogMap = new ConcurrentHashMap<>(); - private final T model; - private final IPrompter prompter; - private final boolean reopenOnError; + private static final Map> dialogMap = new ConcurrentHashMap<>(); - private final IEventListener modelChangedListener = this::onModelChanged; + public static > void open(T model, FormPromptArgs formPromptArgs) { + FormPrompt dialog = new FormPrompt<>(formPromptArgs.title, model, formPromptArgs.formComponent); - public ModalPrompter(T model, IPrompter prompter, boolean reopenOnError) { - this.model = model; - this.prompter = prompter; - this.reopenOnError = reopenOnError; + dialog.setResizable(formPromptArgs.resizable); - model.setModalPrompter(this); - } - - private void open() { - model.resetPropertyChangedListener(); - model.withListener(modelChangedListener); - prompter.open(model); - } - - public static > void open(T model, IPrompter prompter, boolean reopenOnError) { - ModalPrompter modalPrompter = new ModalPrompter<>(model, prompter, reopenOnError); - modalPrompter.open(); - } - - private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { - if (reopenOnError && !model.isDismissed() && propertyChangedArgs.getName().equals("invalidated") && (boolean)propertyChangedArgs.getValue()) { - ModalPrompter.open(model, prompter, reopenOnError); + Point centerLocation = getCenterLocation(formPromptArgs); + if (centerLocation != null) { + dialog.setLocation( + centerLocation.x - dialog.getPreferredSize().width / 2, + centerLocation.y - dialog.getPreferredSize().height / 2 + ); } - } - public static void createTextAreaDialog(String id, String title, String description, String text, Consumer valueHandler) { - JPanel container = new JPanel(new BorderLayout()); + if (formPromptArgs.size != null) { + dialog.setSize(formPromptArgs.size); + } - JScrollPane scrollPane = new JScrollPane(); - scrollPane.setBorder(new EmptyBorder(10,0,0,0)); - JTextPane inputText = IFormComponent.addUndo(new JTextPane()); - inputText.setText(text); - scrollPane.setViewportView(inputText); - scrollPane.setPreferredSize(new Dimension(320, 160)); + if (formPromptArgs.dataBag != null) { + dialog.putClientProperty("dataBag", formPromptArgs.dataBag); + } - container.add(new JLabel(description), BorderLayout.PAGE_START); - container.add(scrollPane, BorderLayout.CENTER); + if (formPromptArgs.registrationId != null) { + dialogMap.put(formPromptArgs.registrationId, new WeakReference<>(dialog)); + } - JOptionPane optionPane = new JOptionPane(container, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, new Object[]{ "OK", "Cancel" }, "OK"); - JDialog dialog = optionPane.createDialog(title); - dialog.setResizable(true); - dialogMap.put(id, dialog); + dialog.setVisible(true); + } - optionPane.addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, event -> { - if (Objects.equals(optionPane.getValue(), "OK")) { - valueHandler.accept(inputText.getText()); - } else { - valueHandler.accept(null); + private static > Point getCenterLocation(FormPromptArgs formPromptArgs) { + Point centerLocation = null; + if (formPromptArgs.locationRelativeTo != null) { + Rectangle bounds = formPromptArgs.locationRelativeTo.getBounds(); + Point location = bounds.getLocation(); + centerLocation = new Point( + location.x + bounds.width / 2, + location.y + bounds.height / 2 + ); + } else { + Point screenCenterLocation = getScreenCenterLocation(); + if (screenCenterLocation != null) { + centerLocation = screenCenterLocation; } - dismiss(id); - }); + } + return centerLocation; + } - dialog.setModal(false); - dialog.setVisible(true); + private static Point getScreenCenterLocation() { + PointerInfo pointerInfo = MouseInfo.getPointerInfo(); + Point mouseLocation = pointerInfo.getLocation(); + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] screens = ge.getScreenDevices(); + + for (GraphicsDevice screen : screens) { + GraphicsConfiguration gc = screen.getDefaultConfiguration(); + Rectangle bounds = gc.getBounds(); + if (bounds.contains(mouseLocation)) { + Point location = bounds.getLocation(); + return new Point( + location.x + bounds.width / 2, + location.y + bounds.height / 2 + ); + } + } + return null; } public static void dismiss(String id) { - JDialog dialog = dialogMap.get(id); - if (dialog != null) { - dialog.dispose(); + WeakReference dialogRef = dialogMap.get(id); + if (dialogRef != null) { + JDialog dialog = dialogRef.get(); + if (dialog != null) { + dialog.dispose(); + } dialogMap.remove(id); } } + + @Getter + @Setter + @Accessors(fluent = true, chain = true) + @RequiredArgsConstructor + public static class FormPromptArgs> { + private final String title; + private final T model; + private final Component formComponent; + private boolean resizable; + private Dimension size; + private Component locationRelativeTo; + private String registrationId; + private Object dataBag; + } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java b/extension/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java index f6a070f..397a64e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java @@ -3,15 +3,23 @@ import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.MessageArgs; import synfron.reshaper.burp.core.events.MessageEvent; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.message.PromptRequestMessage; import synfron.reshaper.burp.core.events.message.PromptResponseMessage; +import synfron.reshaper.burp.ui.components.TextPromptComponent; +import synfron.reshaper.burp.ui.components.workspaces.WorkspaceComponent; +import synfron.reshaper.burp.ui.models.TextPromptModel; + +import java.awt.*; public class UiMessageHandler { private final MessageEvent messageEvent; + private final WorkspaceComponent workspaceComponent; private final IEventListener messageListener = this::onMessage; - public UiMessageHandler(MessageEvent messageEvent) { + public UiMessageHandler(MessageEvent messageEvent, WorkspaceComponent workspaceComponent) { this.messageEvent = messageEvent; + this.workspaceComponent = workspaceComponent; messageEvent.add(messageListener); } @@ -19,15 +27,29 @@ private void onMessage(MessageArgs messageArgs) { switch (messageArgs.getData().getMessageType()) { case PromptRequest -> { PromptRequestMessage message = (PromptRequestMessage)messageArgs.getData(); - ModalPrompter.createTextAreaDialog( - message.getMessageId(), - "Prompt", - message.getDescription(), - message.getText(), - value -> messageEvent.invoke(new MessageArgs(this, new PromptResponseMessage( + + TextPromptModel model = new TextPromptModel(message.getDescription(), message.getText()); + + IEventListener modelPropertyChanged = args -> { + if (args.getName().equals("dismissed") && model.isDismissed() && !model.isInvalidated()) { + messageEvent.invoke(new MessageArgs(this, new PromptResponseMessage( message.getMessageId(), - value - ))) + model.getText() + ))); + } + }; + model.withListener(modelPropertyChanged); + + ModalPrompter.open(model, new ModalPrompter.FormPromptArgs<>( + "Prompt", + model, + new TextPromptComponent(model) + ) + .resizable(true) + .size(new Dimension(360, 200)) + .locationRelativeTo(workspaceComponent) + .registrationId(message.getMessageId()) + .dataBag(modelPropertyChanged) ); } case PromptCancel -> ModalPrompter.dismiss(messageArgs.getData().getMessageId()); diff --git a/runner/src/main/java/synfron/reshaper/burp/runner/Api.java b/runner/src/main/java/synfron/reshaper/burp/runner/Api.java index e47cf63..60f3c59 100644 --- a/runner/src/main/java/synfron/reshaper/burp/runner/Api.java +++ b/runner/src/main/java/synfron/reshaper/burp/runner/Api.java @@ -55,7 +55,7 @@ import burp.api.montoya.websocket.WebSockets; import burp.api.montoya.websocket.extension.ExtensionWebSocketCreation; import synfron.reshaper.burp.core.utils.BurpUtils; -import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.shared.IFormComponent; import javax.swing.*; import java.awt.*;