Skip to content

Commit ab79f48

Browse files
committedDec 2, 2019
Added feature to group items within the context menu.
1 parent deb2f51 commit ab79f48

File tree

10 files changed

+156
-59
lines changed

10 files changed

+156
-59
lines changed
 

‎README.md

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ New context-menu-entries can be added using the "Add"-button. Each entry consist
1111
* **Command:** the command to be executed. You can use following placeholders:
1212
* **%S:** will be replaced with the selected text
1313
* **%F:** will be replaced with the path to a temporary file which contains the selected text
14+
* **Group:** the name of the sub-menu in which this entry will be shown. Might be empty
1415
* **Run in terminal:** defines whether a terminal-window should appear in which the configured command is executed. By default "xterm" is used as terminal-emulator. You can change the terminal-emulator in the "Miscellaneous Options" to your liking.
1516
* **Show preview:** gives you the chance to preview and change the command before executing it
1617
* **Output should replace selection:** will replace the selection with the output of the to be executed command
@@ -26,6 +27,8 @@ In addition you can add new entries via the "Custom command..."-context-menu-ent
2627

2728
![Burp-Send-To-Extension Context-Menu](images/burp-send-to-extension-context-menu-repeater.png)
2829
![Burp-Send-To-Extension Context-Menu](images/burp-send-to-extension-context-menu-target-sitemap.png)
30+
![Burp-Send-To-Extension Context-Menu Groups](images/burp-send-to-extension-context-menu-groups.png)
31+
2932

3033
## Save and load options
3134

‎burp-send-to-extension/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apply plugin: 'java'
22

33
group 'net.bytebutcher'
4-
version '0.94'
4+
version '0.95'
55

66
sourceCompatibility = 1.8
77

‎burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddDialog.form

+22-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<grid id="27dc6" binding="formPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
44
<margin top="10" left="10" bottom="10" right="10"/>
55
<constraints>
6-
<xy x="20" y="20" width="623" height="243"/>
6+
<xy x="20" y="20" width="623" height="268"/>
77
</constraints>
88
<properties/>
99
<border type="none"/>
@@ -52,7 +52,7 @@
5252
</component>
5353
<component id="af465" class="javax.swing.JCheckBox" binding="chkRunInTerminal">
5454
<constraints>
55-
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
55+
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
5656
<gridbag top="5" left="2" bottom="2" right="2" weightx="1.0" weighty="0.0"/>
5757
</constraints>
5858
<properties>
@@ -88,7 +88,7 @@
8888
</grid>
8989
<component id="1d8bf" class="javax.swing.JCheckBox" binding="chkShowPreviewPriorToExecution">
9090
<constraints>
91-
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
91+
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
9292
<gridbag top="5" left="2" bottom="2" right="2" weightx="0.0" weighty="0.0"/>
9393
</constraints>
9494
<properties>
@@ -98,7 +98,7 @@
9898
</component>
9999
<component id="512f7" class="javax.swing.JCheckBox" binding="chkOutputReplacesSelection">
100100
<constraints>
101-
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
101+
<grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
102102
<gridbag top="5" left="2" bottom="2" right="2" weightx="0.0" weighty="0.0"/>
103103
</constraints>
104104
<properties>
@@ -107,6 +107,24 @@
107107
<text value="&amp;Output should replace selection"/>
108108
</properties>
109109
</component>
110+
<component id="c7d44" class="javax.swing.JLabel">
111+
<constraints>
112+
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
113+
<gridbag top="2" left="2" bottom="2" right="10" weightx="0.0" weighty="0.0"/>
114+
</constraints>
115+
<properties>
116+
<text value="&amp;Group:"/>
117+
</properties>
118+
</component>
119+
<component id="532e8" class="javax.swing.JTextField" binding="txtGroup">
120+
<constraints>
121+
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
122+
<preferred-size width="150" height="-1"/>
123+
</grid>
124+
<gridbag top="2" left="2" bottom="2" right="2" weightx="1.0" weighty="0.0"/>
125+
</constraints>
126+
<properties/>
127+
</component>
110128
</children>
111129
</grid>
112130
<grid id="86a29" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">

‎burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddDialog.java

+38-14
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import javax.swing.*;
1111
import java.awt.*;
1212
import java.awt.event.ActionEvent;
13-
import java.util.Set;
1413

1514
public class SendToAddDialog {
1615
private JTextField txtName;
@@ -22,25 +21,27 @@ public class SendToAddDialog {
2221
private JButton btnCommandHelp;
2322
private JCheckBox chkShowPreviewPriorToExecution;
2423
private JCheckBox chkOutputReplacesSelection;
24+
private JTextField txtGroup;
2525
private final JDialog dialog;
2626

2727
private boolean success = false;
28-
private Set<String> names;
28+
private java.util.List<CommandObject> commandObjects;
2929
private AbstractAction onOkActionListener;
3030
private AbstractAction onCancelActionListener;
3131

32-
public SendToAddDialog(JFrame parent, String title, Set<String> names) {
33-
this.names = names;
32+
public SendToAddDialog(JFrame parent, String title, java.util.List<CommandObject> commandObjects) {
33+
this.commandObjects = commandObjects;
3434
this.dialog = initDialog(parent, title);
3535
initEventListener();
3636
initKeyboardShortcuts();
3737
}
3838

39-
public SendToAddDialog(JFrame parent, String title, Set<String> names, CommandObject commandObject) {
40-
this(parent, title, names);
41-
names.remove(commandObject.getName());
39+
public SendToAddDialog(JFrame parent, String title, java.util.List<CommandObject> commandObjects, CommandObject commandObject) {
40+
this(parent, title, commandObjects);
41+
commandObjects.remove(commandObject);
4242
txtName.setText(commandObject.getName());
4343
txtCommand.setText(commandObject.getCommand());
44+
txtGroup.setText(commandObject.getGroup());
4445
chkRunInTerminal.setSelected(commandObject.isRunInTerminal());
4546
chkShowPreviewPriorToExecution.setSelected(commandObject.shouldShowPreview());
4647
chkOutputReplacesSelection.setSelected(commandObject.shouldOutputReplaceSelection());
@@ -70,11 +71,11 @@ public void actionPerformed(ActionEvent e) {
7071
);
7172
return;
7273
}
73-
if (names.contains(getName())) {
74+
if (!commandObjects.stream().noneMatch(commandObject -> getName().equals(commandObject.getName()) && getGroup().equals(commandObject.getGroup()))) {
7475
DialogUtil.showErrorDialog(
7576
dialog,
76-
"Name should be unique!",
77-
"Name already exists!"
77+
"Name already exists within the specified group!",
78+
"Combination of name and group already exists!"
7879
);
7980
return;
8081
}
@@ -135,6 +136,10 @@ private String getCommand() {
135136
return txtCommand.getText();
136137
}
137138

139+
private String getGroup() {
140+
return txtGroup.getText();
141+
}
142+
138143
private boolean isRunInTerminal() {
139144
return chkRunInTerminal.isSelected();
140145
}
@@ -148,7 +153,7 @@ private boolean shouldShowPreview() {
148153
}
149154

150155
public CommandObject getCommandObject() {
151-
return new CommandObject(getName(), getCommand(), isRunInTerminal(), shouldShowPreview(), shouldOutputReplaceSelection());
156+
return new CommandObject(getName(), getCommand(), getGroup(), isRunInTerminal(), shouldShowPreview(), shouldOutputReplaceSelection());
152157
}
153158

154159
{
@@ -210,7 +215,7 @@ public CommandObject getCommandObject() {
210215
chkRunInTerminal.setDisplayedMnemonicIndex(0);
211216
gbc = new GridBagConstraints();
212217
gbc.gridx = 1;
213-
gbc.gridy = 2;
218+
gbc.gridy = 3;
214219
gbc.weightx = 1.0;
215220
gbc.anchor = GridBagConstraints.WEST;
216221
gbc.insets = new Insets(5, 2, 2, 2);
@@ -234,7 +239,7 @@ public CommandObject getCommandObject() {
234239
chkShowPreviewPriorToExecution.setDisplayedMnemonicIndex(0);
235240
gbc = new GridBagConstraints();
236241
gbc.gridx = 1;
237-
gbc.gridy = 3;
242+
gbc.gridy = 4;
238243
gbc.anchor = GridBagConstraints.WEST;
239244
gbc.insets = new Insets(5, 2, 2, 2);
240245
panel1.add(chkShowPreviewPriorToExecution, gbc);
@@ -246,10 +251,29 @@ public CommandObject getCommandObject() {
246251
chkOutputReplacesSelection.setDisplayedMnemonicIndex(0);
247252
gbc = new GridBagConstraints();
248253
gbc.gridx = 1;
249-
gbc.gridy = 4;
254+
gbc.gridy = 5;
250255
gbc.anchor = GridBagConstraints.WEST;
251256
gbc.insets = new Insets(5, 2, 2, 2);
252257
panel1.add(chkOutputReplacesSelection, gbc);
258+
final JLabel label4 = new JLabel();
259+
label4.setText("Group:");
260+
label4.setDisplayedMnemonic('G');
261+
label4.setDisplayedMnemonicIndex(0);
262+
gbc = new GridBagConstraints();
263+
gbc.gridx = 0;
264+
gbc.gridy = 2;
265+
gbc.anchor = GridBagConstraints.WEST;
266+
gbc.insets = new Insets(2, 2, 2, 10);
267+
panel1.add(label4, gbc);
268+
txtGroup = new JTextField();
269+
gbc = new GridBagConstraints();
270+
gbc.gridx = 1;
271+
gbc.gridy = 2;
272+
gbc.weightx = 1.0;
273+
gbc.anchor = GridBagConstraints.WEST;
274+
gbc.fill = GridBagConstraints.HORIZONTAL;
275+
gbc.insets = new Insets(2, 2, 2, 2);
276+
panel1.add(txtGroup, gbc);
253277
final JPanel panel3 = new JPanel();
254278
panel3.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1));
255279
formPanel.add(panel3, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));

‎burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToContextMenu.java

+36-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.bytebutcher.burpsendtoextension.gui;
22

33
import burp.*;
4+
import com.google.common.collect.*;
45
import net.bytebutcher.burpsendtoextension.gui.util.DialogUtil;
56
import net.bytebutcher.burpsendtoextension.models.CommandObject;
67
import net.bytebutcher.burpsendtoextension.utils.OsUtils;
@@ -88,7 +89,7 @@ public void actionPerformed(ActionEvent e) {
8889
SendToAddDialog addDialog = new SendToAddDialog(
8990
burpExtender.getParent(),
9091
"Add and run custom command...",
91-
getCommandNames(commandObjects)
92+
commandObjects
9293
);
9394
if (addDialog.run()) {
9495
CommandObject commandObject = addDialog.getCommandObject();
@@ -102,22 +103,46 @@ public void actionPerformed(ActionEvent e) {
102103
}));
103104
if (commandObjects.size() > 0) {
104105
sendToMenu.addSeparator();
106+
HashMap<String, java.util.List<CommandObject>> groupedCommandObjects = Maps.newLinkedHashMap();
107+
boolean hasEmptyGroup = false;
105108
for (final CommandObject commandObject : commandObjects) {
106-
sendToMenu.add(new JMenuItem(new AbstractAction(commandObject.getName()) {
107-
108-
@Override
109-
public void actionPerformed(ActionEvent e) {
110-
String result = runCommandObject(commandObject);
111-
if (commandObject.shouldOutputReplaceSelection() && result != null) {
112-
replaceSelectedText(result);
113-
}
114-
}
115-
}));
109+
String group = commandObject.getGroup();
110+
if (group.isEmpty()) {
111+
sendToMenu.add(newCommandMenuItem(commandObject));
112+
hasEmptyGroup = true;
113+
continue;
114+
}
115+
if (!groupedCommandObjects.containsKey(group)) {
116+
groupedCommandObjects.put(group, Lists.newArrayList());
117+
}
118+
groupedCommandObjects.get(group).add(commandObject);
119+
}
120+
if (hasEmptyGroup && !groupedCommandObjects.isEmpty()) {
121+
sendToMenu.addSeparator();
122+
}
123+
for (String group : groupedCommandObjects.keySet()) {
124+
JMenu menuItem = new JMenu(group);
125+
for (CommandObject commandObject : groupedCommandObjects.get(group)) {
126+
menuItem.add(newCommandMenuItem(commandObject));
127+
}
128+
sendToMenu.add(menuItem);
116129
}
117130
}
118131
sendToMenuBar.add(sendToMenu);
119132
}
120133

134+
private JMenuItem newCommandMenuItem(CommandObject commandObject) {
135+
return new JMenuItem(new AbstractAction(commandObject.getName()) {
136+
@Override
137+
public void actionPerformed(ActionEvent e) {
138+
String result = runCommandObject(commandObject);
139+
if (commandObject.shouldOutputReplaceSelection() && result != null) {
140+
replaceSelectedText(result);
141+
}
142+
}
143+
});
144+
}
145+
121146
private Set<String> getCommandNames(List<CommandObject> commandObjects) {
122147
Set<String> names = new HashSet<String>();
123148
for (CommandObject commandObject : commandObjects) {

‎burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTab.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public SendToTab(final BurpExtender burpExtender) {
4848
public void actionPerformed(final ActionEvent e) {
4949
new Thread(new Runnable() {
5050
public void run() {
51-
SendToAddDialog addDialog = new SendToAddDialog(getParent(), "Add \"Send to\" context menu entry", sendToTable.getNames());
51+
SendToAddDialog addDialog = new SendToAddDialog(getParent(), "Add \"Send to\" context menu entry", sendToTable.getCommandObjects());
5252
if (addDialog.run()) {
5353
sendToTableListener.onAddButtonClick(e, addDialog.getCommandObject());
5454
}
@@ -60,7 +60,7 @@ public void run() {
6060
@Override
6161
public void actionPerformed(ActionEvent e) {
6262
CommandObject selectedCommandObject = sendToTable.getSelectedCommandObject();
63-
SendToAddDialog editDialog = new SendToAddDialog(getParent(), "Edit \"Send to " + selectedCommandObject.getName() + "\" context menu entry", sendToTable.getNames(), selectedCommandObject);
63+
SendToAddDialog editDialog = new SendToAddDialog(getParent(), "Edit \"Send to " + selectedCommandObject.getName() + "\" context menu entry", sendToTable.getCommandObjects(), selectedCommandObject);
6464
if (editDialog.run()) {
6565
sendToTableListener.onEditButtonClick(e, editDialog.getCommandObject());
6666
}

0 commit comments

Comments
 (0)
Please sign in to comment.